Merge lp:~rconradharris/nova/flavor_min_filter into lp:~hudson-openstack/nova/trunk

Proposed by Rick Harris
Status: Merged
Approved by: Brian Waldon
Approved revision: 1601
Merged at revision: 1616
Proposed branch: lp:~rconradharris/nova/flavor_min_filter
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 720 lines (+364/-90)
10 files modified
nova/api/ec2/admin.py (+3/-2)
nova/api/openstack/flavors.py (+16/-3)
nova/compute/instance_types.py (+6/-2)
nova/db/api.py (+3/-2)
nova/db/sqlalchemy/api.py (+20/-20)
nova/tests/api/openstack/test_flavors.py (+252/-39)
nova/tests/db/fakes.py (+2/-2)
nova/tests/test_instance_types.py (+37/-0)
nova/tests/test_instance_types_extra_specs.py (+23/-18)
nova/tests/vmwareapi/db_fakes.py (+2/-2)
To merge this branch: bzr merge lp:~rconradharris/nova/flavor_min_filter
Reviewer Review Type Date Requested Status
Brian Waldon (community) Approve
Chris Behrens (community) Approve
Review via email: mp+76455@code.launchpad.net

Description of the change

This patch adds flavor filtering, specifically the ability to flavor on minRam, minDisk, or both, per the 1.1 OSAPI spec.

In addition, this patch refactors instance_type_get_all to return a *list* of instance_types instead of a *dict*. This makes it more consistent with the rest of the DB API.

To post a comment you must log in.
Revision history for this message
Naveed Massjouni (ironcamel) wrote :

Hi Rick. Just wanted to let you know about:
https://code.launchpad.net/~rackspace-titan/nova/minram-mindisk
Gonna merge prop it today hopefully. Basically it adds support for minram and mindisk in the api. It displays the minram and mindisk values for GET requests. It also prevents creating instances where the chosen flavor does not meet the minram/mindisk requirements.

Revision history for this message
Gabe Westmaas (westmaas) wrote :

> Hi Rick. Just wanted to let you know about:
> https://code.launchpad.net/~rackspace-titan/nova/minram-mindisk
> Gonna merge prop it today hopefully. Basically it adds support for minram and
> mindisk in the api. It displays the minram and mindisk values for GET
> requests. It also prevents creating instances where the chosen flavor does not
> meet the minram/mindisk requirements.

Just talked to Naveed about this, sorted it out, the code is different, no one is duplicating effort, carry on!

Revision history for this message
Brian Waldon (bcwaldon) wrote :

Looking good, Rick. Can you add some OSAPI tests for the new query parameters? You've also got a little typo on line 130

review: Needs Fixing
Revision history for this message
Rick Harris (rconradharris) wrote :

> Looking good, Rick. Can you add some OSAPI tests for the new query parameters? You've also got a
> little typo on line 130

Fixed typo and added some API level tests.

Revision history for this message
Chris Behrens (cbehrens) wrote :

Great stuff. lgtm.

review: Approve
Revision history for this message
Brian Waldon (bcwaldon) wrote :

Thanks a lot, Rick. This is awesome!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'nova/api/ec2/admin.py'
--- nova/api/ec2/admin.py 2011-09-01 19:22:32 +0000
+++ nova/api/ec2/admin.py 2011-09-21 23:15:31 +0000
@@ -126,8 +126,9 @@
126126
127 def describe_instance_types(self, context, **_kwargs):127 def describe_instance_types(self, context, **_kwargs):
128 """Returns all active instance types data (vcpus, memory, etc.)"""128 """Returns all active instance types data (vcpus, memory, etc.)"""
129 return {'instanceTypeSet': [instance_dict(v) for v in129 inst_types = db.instance_type_get_all(context)
130 db.instance_type_get_all(context).values()]}130 inst_type_dicts = [instance_dict(i) for i in inst_types]
131 return {'instanceTypeSet': inst_type_dicts}
131132
132 def describe_user(self, _context, name, **_kwargs):133 def describe_user(self, _context, name, **_kwargs):
133 """Returns user data, including access and secret keys."""134 """Returns user data, including access and secret keys."""
134135
=== modified file 'nova/api/openstack/flavors.py'
--- nova/api/openstack/flavors.py 2011-09-14 18:58:47 +0000
+++ nova/api/openstack/flavors.py 2011-09-21 23:15:31 +0000
@@ -43,11 +43,24 @@
4343
44 def _get_flavors(self, req, is_detail=True):44 def _get_flavors(self, req, is_detail=True):
45 """Helper function that returns a list of flavor dicts."""45 """Helper function that returns a list of flavor dicts."""
46 filters = {}
47 if 'minRam' in req.params:
48 try:
49 filters['min_memory_mb'] = int(req.params['minRam'])
50 except ValueError:
51 pass # ignore bogus values per spec
52
53 if 'minDisk' in req.params:
54 try:
55 filters['min_local_gb'] = int(req.params['minDisk'])
56 except ValueError:
57 pass # ignore bogus values per spec
58
46 ctxt = req.environ['nova.context']59 ctxt = req.environ['nova.context']
47 flavors = db.api.instance_type_get_all(ctxt)60 inst_types = db.api.instance_type_get_all(ctxt, filters=filters)
48 builder = self._get_view_builder(req)61 builder = self._get_view_builder(req)
49 items = [builder.build(flavor, is_detail=is_detail)62 items = [builder.build(inst_type, is_detail=is_detail)
50 for flavor in flavors.values()]63 for inst_type in inst_types]
51 return items64 return items
5265
53 def show(self, req, id):66 def show(self, req, id):
5467
=== modified file 'nova/compute/instance_types.py'
--- nova/compute/instance_types.py 2011-07-29 15:06:02 +0000
+++ nova/compute/instance_types.py 2011-09-21 23:15:31 +0000
@@ -91,8 +91,12 @@
91 Pass true as argument if you want deleted instance types returned also.91 Pass true as argument if you want deleted instance types returned also.
9292
93 """93 """
94 return db.instance_type_get_all(context.get_admin_context(), inactive)94 ctxt = context.get_admin_context()
9595 inst_types = db.instance_type_get_all(ctxt, inactive)
96 inst_type_dict = {}
97 for inst_type in inst_types:
98 inst_type_dict[inst_type['name']] = inst_type
99 return inst_type_dict
96100
97get_all_flavors = get_all_types101get_all_flavors = get_all_types
98102
99103
=== modified file 'nova/db/api.py'
--- nova/db/api.py 2011-09-19 22:32:45 +0000
+++ nova/db/api.py 2011-09-21 23:15:31 +0000
@@ -1349,9 +1349,10 @@
1349 return IMPL.instance_type_create(context, values)1349 return IMPL.instance_type_create(context, values)
13501350
13511351
1352def instance_type_get_all(context, inactive=False):1352def instance_type_get_all(context, inactive=False, filters=None):
1353 """Get all instance types."""1353 """Get all instance types."""
1354 return IMPL.instance_type_get_all(context, inactive)1354 return IMPL.instance_type_get_all(
1355 context, inactive=inactive, filters=filters)
13551356
13561357
1357def instance_type_get(context, id):1358def instance_type_get(context, id):
13581359
=== modified file 'nova/db/sqlalchemy/api.py'
--- nova/db/sqlalchemy/api.py 2011-09-21 21:31:32 +0000
+++ nova/db/sqlalchemy/api.py 2011-09-21 23:15:31 +0000
@@ -3323,27 +3323,27 @@
33233323
33243324
3325@require_context3325@require_context
3326def instance_type_get_all(context, inactive=False):3326def instance_type_get_all(context, inactive=False, filters=None):
3327 """3327 """
3328 Returns a dict describing all instance_types with name as key.3328 Returns all instance types.
3329 """3329 """
3330 filters = filters or {}
3330 session = get_session()3331 session = get_session()
3331 if inactive:3332 partial = session.query(models.InstanceTypes)\
3332 inst_types = session.query(models.InstanceTypes).\3333 .options(joinedload('extra_specs'))
3333 options(joinedload('extra_specs')).\3334 if not inactive:
3334 order_by("name").\3335 partial = partial.filter_by(deleted=False)
3335 all()3336
3336 else:3337 if 'min_memory_mb' in filters:
3337 inst_types = session.query(models.InstanceTypes).\3338 partial = partial.filter(
3338 options(joinedload('extra_specs')).\3339 models.InstanceTypes.memory_mb >= filters['min_memory_mb'])
3339 filter_by(deleted=False).\3340 if 'min_local_gb' in filters:
3340 order_by("name").\3341 partial = partial.filter(
3341 all()3342 models.InstanceTypes.local_gb >= filters['min_local_gb'])
3342 inst_dict = {}3343
3343 if inst_types:3344 inst_types = partial.order_by("name").all()
3344 for i in inst_types:3345
3345 inst_dict[i['name']] = _dict_with_extra_specs(i)3346 return [_dict_with_extra_specs(i) for i in inst_types]
3346 return inst_dict
33473347
33483348
3349@require_context3349@require_context
33503350
=== modified file 'nova/tests/api/openstack/test_flavors.py'
--- nova/tests/api/openstack/test_flavors.py 2011-09-14 17:10:23 +0000
+++ nova/tests/api/openstack/test_flavors.py 2011-09-21 23:15:31 +0000
@@ -32,25 +32,43 @@
32ATOMNS = "{http://www.w3.org/2005/Atom}"32ATOMNS = "{http://www.w3.org/2005/Atom}"
3333
3434
35def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"):35FAKE_FLAVORS = {
36 return {36 'flavor 1': {
37 "flavorid": str(flavorid),37 "flavorid": '1',
38 "name": name,38 "name": 'flavor 1',
39 "memory_mb": memory_mb,39 "memory_mb": '256',
40 "local_gb": local_gb,40 "local_gb": '10'
41 }41 },
4242 'flavor 2': {
4343 "flavorid": '2',
44def return_instance_type_by_flavor_id(context, flavorid):44 "name": 'flavor 2',
45 return stub_flavor(flavorid, "flavor %s" % (flavorid,))45 "memory_mb": '512',
4646 "local_gb": '20'
4747 },
48def return_instance_types(context, num=2):48}
49 instance_types = {}49
50 for i in xrange(1, num + 1):50
51 name = "flavor %s" % (i,)51def fake_instance_type_get_by_flavor_id(context, flavorid):
52 instance_types[name] = stub_flavor(i, name)52 return FAKE_FLAVORS['flavor %s' % flavorid]
53 return instance_types53
54
55def fake_instance_type_get_all(context, inactive=False, filters=None):
56 def reject_min(db_attr, filter_attr):
57 return filter_attr in filters and\
58 int(flavor[db_attr]) < int(filters[filter_attr])
59
60 filters = filters or {}
61 for flavor in FAKE_FLAVORS.values():
62 if reject_min('memory_mb', 'min_memory_mb'):
63 continue
64 elif reject_min('local_gb', 'min_local_gb'):
65 continue
66
67 yield flavor
68
69
70def empty_instance_type_get_all(context, inactive=False, filters=None):
71 return {}
5472
5573
56def return_instance_type_not_found(context, flavor_id):74def return_instance_type_not_found(context, flavor_id):
@@ -63,9 +81,9 @@
63 fakes.stub_out_networking(self.stubs)81 fakes.stub_out_networking(self.stubs)
64 fakes.stub_out_rate_limiting(self.stubs)82 fakes.stub_out_rate_limiting(self.stubs)
65 self.stubs.Set(nova.db.api, "instance_type_get_all",83 self.stubs.Set(nova.db.api, "instance_type_get_all",
66 return_instance_types)84 fake_instance_type_get_all)
67 self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",85 self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
68 return_instance_type_by_flavor_id)86 fake_instance_type_get_by_flavor_id)
6987
70 def tearDown(self):88 def tearDown(self):
71 self.stubs.UnsetAll()89 self.stubs.UnsetAll()
@@ -89,10 +107,8 @@
89 self.assertEqual(flavors, expected)107 self.assertEqual(flavors, expected)
90108
91 def test_get_empty_flavor_list_v1_0(self):109 def test_get_empty_flavor_list_v1_0(self):
92 def _return_empty(self):
93 return {}
94 self.stubs.Set(nova.db.api, "instance_type_get_all",110 self.stubs.Set(nova.db.api, "instance_type_get_all",
95 _return_empty)111 empty_instance_type_get_all)
96112
97 req = webob.Request.blank('/v1.0/flavors')113 req = webob.Request.blank('/v1.0/flavors')
98 res = req.get_response(fakes.wsgi_app())114 res = req.get_response(fakes.wsgi_app())
@@ -120,8 +136,8 @@
120 {136 {
121 "id": "2",137 "id": "2",
122 "name": "flavor 2",138 "name": "flavor 2",
123 "ram": "256",139 "ram": "512",
124 "disk": "10",140 "disk": "20",
125 "rxtx_cap": "",141 "rxtx_cap": "",
126 "rxtx_quota": "",142 "rxtx_quota": "",
127 "swap": "",143 "swap": "",
@@ -131,13 +147,13 @@
131 self.assertEqual(flavors, expected)147 self.assertEqual(flavors, expected)
132148
133 def test_get_flavor_by_id_v1_0(self):149 def test_get_flavor_by_id_v1_0(self):
134 req = webob.Request.blank('/v1.0/flavors/12')150 req = webob.Request.blank('/v1.0/flavors/1')
135 res = req.get_response(fakes.wsgi_app())151 res = req.get_response(fakes.wsgi_app())
136 self.assertEqual(res.status_int, 200)152 self.assertEqual(res.status_int, 200)
137 flavor = json.loads(res.body)["flavor"]153 flavor = json.loads(res.body)["flavor"]
138 expected = {154 expected = {
139 "id": "12",155 "id": "1",
140 "name": "flavor 12",156 "name": "flavor 1",
141 "ram": "256",157 "ram": "256",
142 "disk": "10",158 "disk": "10",
143 "rxtx_cap": "",159 "rxtx_cap": "",
@@ -155,15 +171,15 @@
155 self.assertEqual(res.status_int, 404)171 self.assertEqual(res.status_int, 404)
156172
157 def test_get_flavor_by_id_v1_1(self):173 def test_get_flavor_by_id_v1_1(self):
158 req = webob.Request.blank('/v1.1/fake/flavors/12')174 req = webob.Request.blank('/v1.1/fake/flavors/1')
159 req.environ['api.version'] = '1.1'175 req.environ['api.version'] = '1.1'
160 res = req.get_response(fakes.wsgi_app())176 res = req.get_response(fakes.wsgi_app())
161 self.assertEqual(res.status_int, 200)177 self.assertEqual(res.status_int, 200)
162 flavor = json.loads(res.body)178 flavor = json.loads(res.body)
163 expected = {179 expected = {
164 "flavor": {180 "flavor": {
165 "id": "12",181 "id": "1",
166 "name": "flavor 12",182 "name": "flavor 1",
167 "ram": "256",183 "ram": "256",
168 "disk": "10",184 "disk": "10",
169 "rxtx_cap": "",185 "rxtx_cap": "",
@@ -173,11 +189,11 @@
173 "links": [189 "links": [
174 {190 {
175 "rel": "self",191 "rel": "self",
176 "href": "http://localhost/v1.1/fake/flavors/12",192 "href": "http://localhost/v1.1/fake/flavors/1",
177 },193 },
178 {194 {
179 "rel": "bookmark",195 "rel": "bookmark",
180 "href": "http://localhost/fake/flavors/12",196 "href": "http://localhost/fake/flavors/1",
181 },197 },
182 ],198 ],
183 },199 },
@@ -255,8 +271,8 @@
255 {271 {
256 "id": "2",272 "id": "2",
257 "name": "flavor 2",273 "name": "flavor 2",
258 "ram": "256",274 "ram": "512",
259 "disk": "10",275 "disk": "20",
260 "rxtx_cap": "",276 "rxtx_cap": "",
261 "rxtx_quota": "",277 "rxtx_quota": "",
262 "swap": "",278 "swap": "",
@@ -277,9 +293,8 @@
277 self.assertEqual(flavor, expected)293 self.assertEqual(flavor, expected)
278294
279 def test_get_empty_flavor_list_v1_1(self):295 def test_get_empty_flavor_list_v1_1(self):
280 def _return_empty(self):296 self.stubs.Set(nova.db.api, "instance_type_get_all",
281 return {}297 empty_instance_type_get_all)
282 self.stubs.Set(nova.db.api, "instance_type_get_all", _return_empty)
283298
284 req = webob.Request.blank('/v1.1/fake/flavors')299 req = webob.Request.blank('/v1.1/fake/flavors')
285 res = req.get_response(fakes.wsgi_app())300 res = req.get_response(fakes.wsgi_app())
@@ -288,6 +303,204 @@
288 expected = []303 expected = []
289 self.assertEqual(flavors, expected)304 self.assertEqual(flavors, expected)
290305
306 def test_get_flavor_list_filter_min_ram_v1_1(self):
307 """Flavor lists may be filtered by minRam"""
308 req = webob.Request.blank('/v1.1/fake/flavors?minRam=512')
309 req.environ['api.version'] = '1.1'
310 res = req.get_response(fakes.wsgi_app())
311 self.assertEqual(res.status_int, 200)
312 flavor = json.loads(res.body)
313 expected = {
314 "flavors": [
315 {
316 "id": "2",
317 "name": "flavor 2",
318 "links": [
319 {
320 "rel": "self",
321 "href": "http://localhost/v1.1/fake/flavors/2",
322 },
323 {
324 "rel": "bookmark",
325 "href": "http://localhost/fake/flavors/2",
326 },
327 ],
328 },
329 ],
330 }
331 self.assertEqual(flavor, expected)
332
333 def test_get_flavor_list_filter_min_disk(self):
334 """Flavor lists may be filtered by minRam"""
335 req = webob.Request.blank('/v1.1/fake/flavors?minDisk=20')
336 req.environ['api.version'] = '1.1'
337 res = req.get_response(fakes.wsgi_app())
338 self.assertEqual(res.status_int, 200)
339 flavor = json.loads(res.body)
340 expected = {
341 "flavors": [
342 {
343 "id": "2",
344 "name": "flavor 2",
345 "links": [
346 {
347 "rel": "self",
348 "href": "http://localhost/v1.1/fake/flavors/2",
349 },
350 {
351 "rel": "bookmark",
352 "href": "http://localhost/fake/flavors/2",
353 },
354 ],
355 },
356 ],
357 }
358 self.assertEqual(flavor, expected)
359
360 def test_get_flavor_list_detail_min_ram_and_min_disk_v1_1(self):
361 """Tests that filtering work on flavor details and that minRam and
362 minDisk filters can be combined
363 """
364 req = webob.Request.blank(
365 '/v1.1/fake/flavors/detail?minRam=256&minDisk=20')
366 req.environ['api.version'] = '1.1'
367 res = req.get_response(fakes.wsgi_app())
368 self.assertEqual(res.status_int, 200)
369 flavor = json.loads(res.body)
370 expected = {
371 "flavors": [
372 {
373 "id": "2",
374 "name": "flavor 2",
375 "ram": "512",
376 "disk": "20",
377 "rxtx_cap": "",
378 "rxtx_quota": "",
379 "swap": "",
380 "vcpus": "",
381 "links": [
382 {
383 "rel": "self",
384 "href": "http://localhost/v1.1/fake/flavors/2",
385 },
386 {
387 "rel": "bookmark",
388 "href": "http://localhost/fake/flavors/2",
389 },
390 ],
391 },
392 ],
393 }
394 self.assertEqual(flavor, expected)
395
396 def test_get_flavor_list_detail_bogus_min_ram_v1_1(self):
397 """Tests that bogus minRam filtering values are ignored"""
398 req = webob.Request.blank(
399 '/v1.1/fake/flavors/detail?minRam=16GB')
400 req.environ['api.version'] = '1.1'
401 res = req.get_response(fakes.wsgi_app())
402 self.assertEqual(res.status_int, 200)
403 flavor = json.loads(res.body)
404 expected = {
405 "flavors": [
406 {
407 "id": "1",
408 "name": "flavor 1",
409 "ram": "256",
410 "disk": "10",
411 "rxtx_cap": "",
412 "rxtx_quota": "",
413 "swap": "",
414 "vcpus": "",
415 "links": [
416 {
417 "rel": "self",
418 "href": "http://localhost/v1.1/fake/flavors/1",
419 },
420 {
421 "rel": "bookmark",
422 "href": "http://localhost/fake/flavors/1",
423 },
424 ],
425 },
426 {
427 "id": "2",
428 "name": "flavor 2",
429 "ram": "512",
430 "disk": "20",
431 "rxtx_cap": "",
432 "rxtx_quota": "",
433 "swap": "",
434 "vcpus": "",
435 "links": [
436 {
437 "rel": "self",
438 "href": "http://localhost/v1.1/fake/flavors/2",
439 },
440 {
441 "rel": "bookmark",
442 "href": "http://localhost/fake/flavors/2",
443 },
444 ],
445 },
446 ],
447 }
448 self.assertEqual(flavor, expected)
449
450 def test_get_flavor_list_detail_bogus_min_disk_v1_1(self):
451 """Tests that bogus minDisk filtering values are ignored"""
452 req = webob.Request.blank(
453 '/v1.1/fake/flavors/detail?minDisk=16GB')
454 req.environ['api.version'] = '1.1'
455 res = req.get_response(fakes.wsgi_app())
456 self.assertEqual(res.status_int, 200)
457 flavor = json.loads(res.body)
458 expected = {
459 "flavors": [
460 {
461 "id": "1",
462 "name": "flavor 1",
463 "ram": "256",
464 "disk": "10",
465 "rxtx_cap": "",
466 "rxtx_quota": "",
467 "swap": "",
468 "vcpus": "",
469 "links": [
470 {
471 "rel": "self",
472 "href": "http://localhost/v1.1/fake/flavors/1",
473 },
474 {
475 "rel": "bookmark",
476 "href": "http://localhost/fake/flavors/1",
477 },
478 ],
479 },
480 {
481 "id": "2",
482 "name": "flavor 2",
483 "ram": "512",
484 "disk": "20",
485 "rxtx_cap": "",
486 "rxtx_quota": "",
487 "swap": "",
488 "vcpus": "",
489 "links": [
490 {
491 "rel": "self",
492 "href": "http://localhost/v1.1/fake/flavors/2",
493 },
494 {
495 "rel": "bookmark",
496 "href": "http://localhost/fake/flavors/2",
497 },
498 ],
499 },
500 ],
501 }
502 self.assertEqual(flavor, expected)
503
291504
292class FlavorsXMLSerializationTest(test.TestCase):505class FlavorsXMLSerializationTest(test.TestCase):
293506
294507
=== modified file 'nova/tests/db/fakes.py'
--- nova/tests/db/fakes.py 2011-09-13 23:38:46 +0000
+++ nova/tests/db/fakes.py 2011-09-21 23:15:31 +0000
@@ -411,8 +411,8 @@
411 'address_v6': 'fe80::a00:3',411 'address_v6': 'fe80::a00:3',
412 'network_id': 'fake_flat'}412 'network_id': 'fake_flat'}
413413
414 def fake_instance_type_get_all(context, inactive=0):414 def fake_instance_type_get_all(context, inactive=0, filters=None):
415 return INSTANCE_TYPES415 return INSTANCE_TYPES.values()
416416
417 def fake_instance_type_get_by_name(context, name):417 def fake_instance_type_get_by_name(context, name):
418 return INSTANCE_TYPES[name]418 return INSTANCE_TYPES[name]
419419
=== modified file 'nova/tests/test_instance_types.py'
--- nova/tests/test_instance_types.py 2011-08-24 23:03:32 +0000
+++ nova/tests/test_instance_types.py 2011-09-21 23:15:31 +0000
@@ -161,3 +161,40 @@
161 self.assertRaises(exception.InstanceTypeNotFound,161 self.assertRaises(exception.InstanceTypeNotFound,
162 instance_types.get_instance_type_by_name,162 instance_types.get_instance_type_by_name,
163 self._nonexistent_flavor_id())163 self._nonexistent_flavor_id())
164
165
166class InstanceTypeFilteringTest(test.TestCase):
167 """Test cases for the filter option available for instance_type_get_all"""
168 def setUp(self):
169 super(InstanceTypeFilteringTest, self).setUp()
170 self.context = context.get_admin_context()
171
172 def assertFilterResults(self, filters, expected):
173 inst_types = db.api.instance_type_get_all(
174 self.context, filters=filters)
175 inst_names = [i['name'] for i in inst_types]
176 self.assertEqual(inst_names, expected)
177
178 def test_no_filters(self):
179 filters = None
180 expected = ['m1.large', 'm1.medium', 'm1.small', 'm1.tiny',
181 'm1.xlarge']
182 self.assertFilterResults(filters, expected)
183
184 def test_min_memory_mb_filter(self):
185 """Exclude tiny instance which is 512 MB"""
186 filters = dict(min_memory_mb=513)
187 expected = ['m1.large', 'm1.medium', 'm1.small', 'm1.xlarge']
188 self.assertFilterResults(filters, expected)
189
190 def test_min_local_gb_filter(self):
191 """Exclude everything but large and xlarge which have >= 80 GB"""
192 filters = dict(min_local_gb=80)
193 expected = ['m1.large', 'm1.xlarge']
194 self.assertFilterResults(filters, expected)
195
196 def test_min_memory_mb_AND_local_gb_filter(self):
197 """Exclude everything but large and xlarge which have >= 80 GB"""
198 filters = dict(min_memory_mb=16384, min_local_gb=80)
199 expected = ['m1.xlarge']
200 self.assertFilterResults(filters, expected)
164201
=== modified file 'nova/tests/test_instance_types_extra_specs.py'
--- nova/tests/test_instance_types_extra_specs.py 2011-08-03 18:47:35 +0000
+++ nova/tests/test_instance_types_extra_specs.py 2011-09-21 23:15:31 +0000
@@ -45,7 +45,7 @@
4545
46 def tearDown(self):46 def tearDown(self):
47 # Remove the instance type from the database47 # Remove the instance type from the database
48 db.api.instance_type_purge(context.get_admin_context(), "cg1.4xlarge")48 db.api.instance_type_purge(self.context, "cg1.4xlarge")
49 super(InstanceTypeExtraSpecsTestCase, self).tearDown()49 super(InstanceTypeExtraSpecsTestCase, self).tearDown()
5050
51 def test_instance_type_specs_get(self):51 def test_instance_type_specs_get(self):
@@ -55,7 +55,7 @@
55 xpus="2",55 xpus="2",
56 xpu_model="Tesla 2050")56 xpu_model="Tesla 2050")
57 actual_specs = db.api.instance_type_extra_specs_get(57 actual_specs = db.api.instance_type_extra_specs_get(
58 context.get_admin_context(),58 self.context,
59 self.instance_type_id)59 self.instance_type_id)
60 self.assertEquals(expected_specs, actual_specs)60 self.assertEquals(expected_specs, actual_specs)
6161
@@ -64,11 +64,11 @@
64 cpu_model="Nehalem",64 cpu_model="Nehalem",
65 xpu_arch="fermi",65 xpu_arch="fermi",
66 xpus="2")66 xpus="2")
67 db.api.instance_type_extra_specs_delete(context.get_admin_context(),67 db.api.instance_type_extra_specs_delete(self.context,
68 self.instance_type_id,68 self.instance_type_id,
69 "xpu_model")69 "xpu_model")
70 actual_specs = db.api.instance_type_extra_specs_get(70 actual_specs = db.api.instance_type_extra_specs_get(
71 context.get_admin_context(),71 self.context,
72 self.instance_type_id)72 self.instance_type_id)
73 self.assertEquals(expected_specs, actual_specs)73 self.assertEquals(expected_specs, actual_specs)
7474
@@ -79,11 +79,11 @@
79 xpus="2",79 xpus="2",
80 xpu_model="Tesla 2050")80 xpu_model="Tesla 2050")
81 db.api.instance_type_extra_specs_update_or_create(81 db.api.instance_type_extra_specs_update_or_create(
82 context.get_admin_context(),82 self.context,
83 self.instance_type_id,83 self.instance_type_id,
84 dict(cpu_model="Sandy Bridge"))84 dict(cpu_model="Sandy Bridge"))
85 actual_specs = db.api.instance_type_extra_specs_get(85 actual_specs = db.api.instance_type_extra_specs_get(
86 context.get_admin_context(),86 self.context,
87 self.instance_type_id)87 self.instance_type_id)
88 self.assertEquals(expected_specs, actual_specs)88 self.assertEquals(expected_specs, actual_specs)
8989
@@ -96,18 +96,18 @@
96 net_arch="ethernet",96 net_arch="ethernet",
97 net_mbps="10000")97 net_mbps="10000")
98 db.api.instance_type_extra_specs_update_or_create(98 db.api.instance_type_extra_specs_update_or_create(
99 context.get_admin_context(),99 self.context,
100 self.instance_type_id,100 self.instance_type_id,
101 dict(net_arch="ethernet",101 dict(net_arch="ethernet",
102 net_mbps=10000))102 net_mbps=10000))
103 actual_specs = db.api.instance_type_extra_specs_get(103 actual_specs = db.api.instance_type_extra_specs_get(
104 context.get_admin_context(),104 self.context,
105 self.instance_type_id)105 self.instance_type_id)
106 self.assertEquals(expected_specs, actual_specs)106 self.assertEquals(expected_specs, actual_specs)
107107
108 def test_instance_type_get_with_extra_specs(self):108 def test_instance_type_get_with_extra_specs(self):
109 instance_type = db.api.instance_type_get(109 instance_type = db.api.instance_type_get(
110 context.get_admin_context(),110 self.context,
111 self.instance_type_id)111 self.instance_type_id)
112 self.assertEquals(instance_type['extra_specs'],112 self.assertEquals(instance_type['extra_specs'],
113 dict(cpu_arch="x86_64",113 dict(cpu_arch="x86_64",
@@ -116,13 +116,13 @@
116 xpus="2",116 xpus="2",
117 xpu_model="Tesla 2050"))117 xpu_model="Tesla 2050"))
118 instance_type = db.api.instance_type_get(118 instance_type = db.api.instance_type_get(
119 context.get_admin_context(),119 self.context,
120 5)120 5)
121 self.assertEquals(instance_type['extra_specs'], {})121 self.assertEquals(instance_type['extra_specs'], {})
122122
123 def test_instance_type_get_by_name_with_extra_specs(self):123 def test_instance_type_get_by_name_with_extra_specs(self):
124 instance_type = db.api.instance_type_get_by_name(124 instance_type = db.api.instance_type_get_by_name(
125 context.get_admin_context(),125 self.context,
126 "cg1.4xlarge")126 "cg1.4xlarge")
127 self.assertEquals(instance_type['extra_specs'],127 self.assertEquals(instance_type['extra_specs'],
128 dict(cpu_arch="x86_64",128 dict(cpu_arch="x86_64",
@@ -132,13 +132,13 @@
132 xpu_model="Tesla 2050"))132 xpu_model="Tesla 2050"))
133133
134 instance_type = db.api.instance_type_get_by_name(134 instance_type = db.api.instance_type_get_by_name(
135 context.get_admin_context(),135 self.context,
136 "m1.small")136 "m1.small")
137 self.assertEquals(instance_type['extra_specs'], {})137 self.assertEquals(instance_type['extra_specs'], {})
138138
139 def test_instance_type_get_by_flavor_id_with_extra_specs(self):139 def test_instance_type_get_by_flavor_id_with_extra_specs(self):
140 instance_type = db.api.instance_type_get_by_flavor_id(140 instance_type = db.api.instance_type_get_by_flavor_id(
141 context.get_admin_context(),141 self.context,
142 105)142 105)
143 self.assertEquals(instance_type['extra_specs'],143 self.assertEquals(instance_type['extra_specs'],
144 dict(cpu_arch="x86_64",144 dict(cpu_arch="x86_64",
@@ -148,7 +148,7 @@
148 xpu_model="Tesla 2050"))148 xpu_model="Tesla 2050"))
149149
150 instance_type = db.api.instance_type_get_by_flavor_id(150 instance_type = db.api.instance_type_get_by_flavor_id(
151 context.get_admin_context(),151 self.context,
152 2)152 2)
153 self.assertEquals(instance_type['extra_specs'], {})153 self.assertEquals(instance_type['extra_specs'], {})
154154
@@ -159,7 +159,12 @@
159 xpus='2',159 xpus='2',
160 xpu_model="Tesla 2050")160 xpu_model="Tesla 2050")
161161
162 types = db.api.instance_type_get_all(context.get_admin_context())162 types = db.api.instance_type_get_all(self.context)
163163
164 self.assertEquals(types['cg1.4xlarge']['extra_specs'], specs)164 name2specs = {}
165 self.assertEquals(types['m1.small']['extra_specs'], {})165 for instance_type in types:
166 name = instance_type['name']
167 name2specs[name] = instance_type['extra_specs']
168
169 self.assertEquals(name2specs['cg1.4xlarge'], specs)
170 self.assertEquals(name2specs['m1.small'], {})
166171
=== modified file 'nova/tests/vmwareapi/db_fakes.py'
--- nova/tests/vmwareapi/db_fakes.py 2011-08-22 21:17:39 +0000
+++ nova/tests/vmwareapi/db_fakes.py 2011-09-21 23:15:31 +0000
@@ -99,8 +99,8 @@
99 """Stubs out the db.instance_get_fixed_address method."""99 """Stubs out the db.instance_get_fixed_address method."""
100 return '10.10.10.10'100 return '10.10.10.10'
101101
102 def fake_instance_type_get_all(context, inactive=0):102 def fake_instance_type_get_all(context, inactive=0, filters=None):
103 return INSTANCE_TYPES103 return INSTANCE_TYPES.values()
104104
105 def fake_instance_type_get_by_name(context, name):105 def fake_instance_type_get_by_name(context, name):
106 return INSTANCE_TYPES[name]106 return INSTANCE_TYPES[name]