Merge lp:~rconradharris/nova/flavor_min_filter into lp:~hudson-openstack/nova/trunk
- flavor_min_filter
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brian Waldon (community) | Approve | ||
Chris Behrens (community) | Approve | ||
Review via email: mp+76455@code.launchpad.net |
Commit message
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_
Naveed Massjouni (ironcamel) wrote : | # |
Gabe Westmaas (westmaas) wrote : | # |
> Hi Rick. Just wanted to let you know about:
> https:/
> 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!
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
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.
Chris Behrens (cbehrens) wrote : | # |
Great stuff. lgtm.
Brian Waldon (bcwaldon) wrote : | # |
Thanks a lot, Rick. This is awesome!
Preview Diff
1 | === modified file 'nova/api/ec2/admin.py' |
2 | --- nova/api/ec2/admin.py 2011-09-01 19:22:32 +0000 |
3 | +++ nova/api/ec2/admin.py 2011-09-21 23:15:31 +0000 |
4 | @@ -126,8 +126,9 @@ |
5 | |
6 | def describe_instance_types(self, context, **_kwargs): |
7 | """Returns all active instance types data (vcpus, memory, etc.)""" |
8 | - return {'instanceTypeSet': [instance_dict(v) for v in |
9 | - db.instance_type_get_all(context).values()]} |
10 | + inst_types = db.instance_type_get_all(context) |
11 | + inst_type_dicts = [instance_dict(i) for i in inst_types] |
12 | + return {'instanceTypeSet': inst_type_dicts} |
13 | |
14 | def describe_user(self, _context, name, **_kwargs): |
15 | """Returns user data, including access and secret keys.""" |
16 | |
17 | === modified file 'nova/api/openstack/flavors.py' |
18 | --- nova/api/openstack/flavors.py 2011-09-14 18:58:47 +0000 |
19 | +++ nova/api/openstack/flavors.py 2011-09-21 23:15:31 +0000 |
20 | @@ -43,11 +43,24 @@ |
21 | |
22 | def _get_flavors(self, req, is_detail=True): |
23 | """Helper function that returns a list of flavor dicts.""" |
24 | + filters = {} |
25 | + if 'minRam' in req.params: |
26 | + try: |
27 | + filters['min_memory_mb'] = int(req.params['minRam']) |
28 | + except ValueError: |
29 | + pass # ignore bogus values per spec |
30 | + |
31 | + if 'minDisk' in req.params: |
32 | + try: |
33 | + filters['min_local_gb'] = int(req.params['minDisk']) |
34 | + except ValueError: |
35 | + pass # ignore bogus values per spec |
36 | + |
37 | ctxt = req.environ['nova.context'] |
38 | - flavors = db.api.instance_type_get_all(ctxt) |
39 | + inst_types = db.api.instance_type_get_all(ctxt, filters=filters) |
40 | builder = self._get_view_builder(req) |
41 | - items = [builder.build(flavor, is_detail=is_detail) |
42 | - for flavor in flavors.values()] |
43 | + items = [builder.build(inst_type, is_detail=is_detail) |
44 | + for inst_type in inst_types] |
45 | return items |
46 | |
47 | def show(self, req, id): |
48 | |
49 | === modified file 'nova/compute/instance_types.py' |
50 | --- nova/compute/instance_types.py 2011-07-29 15:06:02 +0000 |
51 | +++ nova/compute/instance_types.py 2011-09-21 23:15:31 +0000 |
52 | @@ -91,8 +91,12 @@ |
53 | Pass true as argument if you want deleted instance types returned also. |
54 | |
55 | """ |
56 | - return db.instance_type_get_all(context.get_admin_context(), inactive) |
57 | - |
58 | + ctxt = context.get_admin_context() |
59 | + inst_types = db.instance_type_get_all(ctxt, inactive) |
60 | + inst_type_dict = {} |
61 | + for inst_type in inst_types: |
62 | + inst_type_dict[inst_type['name']] = inst_type |
63 | + return inst_type_dict |
64 | |
65 | get_all_flavors = get_all_types |
66 | |
67 | |
68 | === modified file 'nova/db/api.py' |
69 | --- nova/db/api.py 2011-09-19 22:32:45 +0000 |
70 | +++ nova/db/api.py 2011-09-21 23:15:31 +0000 |
71 | @@ -1349,9 +1349,10 @@ |
72 | return IMPL.instance_type_create(context, values) |
73 | |
74 | |
75 | -def instance_type_get_all(context, inactive=False): |
76 | +def instance_type_get_all(context, inactive=False, filters=None): |
77 | """Get all instance types.""" |
78 | - return IMPL.instance_type_get_all(context, inactive) |
79 | + return IMPL.instance_type_get_all( |
80 | + context, inactive=inactive, filters=filters) |
81 | |
82 | |
83 | def instance_type_get(context, id): |
84 | |
85 | === modified file 'nova/db/sqlalchemy/api.py' |
86 | --- nova/db/sqlalchemy/api.py 2011-09-21 21:31:32 +0000 |
87 | +++ nova/db/sqlalchemy/api.py 2011-09-21 23:15:31 +0000 |
88 | @@ -3323,27 +3323,27 @@ |
89 | |
90 | |
91 | @require_context |
92 | -def instance_type_get_all(context, inactive=False): |
93 | - """ |
94 | - Returns a dict describing all instance_types with name as key. |
95 | - """ |
96 | +def instance_type_get_all(context, inactive=False, filters=None): |
97 | + """ |
98 | + Returns all instance types. |
99 | + """ |
100 | + filters = filters or {} |
101 | session = get_session() |
102 | - if inactive: |
103 | - inst_types = session.query(models.InstanceTypes).\ |
104 | - options(joinedload('extra_specs')).\ |
105 | - order_by("name").\ |
106 | - all() |
107 | - else: |
108 | - inst_types = session.query(models.InstanceTypes).\ |
109 | - options(joinedload('extra_specs')).\ |
110 | - filter_by(deleted=False).\ |
111 | - order_by("name").\ |
112 | - all() |
113 | - inst_dict = {} |
114 | - if inst_types: |
115 | - for i in inst_types: |
116 | - inst_dict[i['name']] = _dict_with_extra_specs(i) |
117 | - return inst_dict |
118 | + partial = session.query(models.InstanceTypes)\ |
119 | + .options(joinedload('extra_specs')) |
120 | + if not inactive: |
121 | + partial = partial.filter_by(deleted=False) |
122 | + |
123 | + if 'min_memory_mb' in filters: |
124 | + partial = partial.filter( |
125 | + models.InstanceTypes.memory_mb >= filters['min_memory_mb']) |
126 | + if 'min_local_gb' in filters: |
127 | + partial = partial.filter( |
128 | + models.InstanceTypes.local_gb >= filters['min_local_gb']) |
129 | + |
130 | + inst_types = partial.order_by("name").all() |
131 | + |
132 | + return [_dict_with_extra_specs(i) for i in inst_types] |
133 | |
134 | |
135 | @require_context |
136 | |
137 | === modified file 'nova/tests/api/openstack/test_flavors.py' |
138 | --- nova/tests/api/openstack/test_flavors.py 2011-09-14 17:10:23 +0000 |
139 | +++ nova/tests/api/openstack/test_flavors.py 2011-09-21 23:15:31 +0000 |
140 | @@ -32,25 +32,43 @@ |
141 | ATOMNS = "{http://www.w3.org/2005/Atom}" |
142 | |
143 | |
144 | -def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"): |
145 | - return { |
146 | - "flavorid": str(flavorid), |
147 | - "name": name, |
148 | - "memory_mb": memory_mb, |
149 | - "local_gb": local_gb, |
150 | - } |
151 | - |
152 | - |
153 | -def return_instance_type_by_flavor_id(context, flavorid): |
154 | - return stub_flavor(flavorid, "flavor %s" % (flavorid,)) |
155 | - |
156 | - |
157 | -def return_instance_types(context, num=2): |
158 | - instance_types = {} |
159 | - for i in xrange(1, num + 1): |
160 | - name = "flavor %s" % (i,) |
161 | - instance_types[name] = stub_flavor(i, name) |
162 | - return instance_types |
163 | +FAKE_FLAVORS = { |
164 | + 'flavor 1': { |
165 | + "flavorid": '1', |
166 | + "name": 'flavor 1', |
167 | + "memory_mb": '256', |
168 | + "local_gb": '10' |
169 | + }, |
170 | + 'flavor 2': { |
171 | + "flavorid": '2', |
172 | + "name": 'flavor 2', |
173 | + "memory_mb": '512', |
174 | + "local_gb": '20' |
175 | + }, |
176 | +} |
177 | + |
178 | + |
179 | +def fake_instance_type_get_by_flavor_id(context, flavorid): |
180 | + return FAKE_FLAVORS['flavor %s' % flavorid] |
181 | + |
182 | + |
183 | +def fake_instance_type_get_all(context, inactive=False, filters=None): |
184 | + def reject_min(db_attr, filter_attr): |
185 | + return filter_attr in filters and\ |
186 | + int(flavor[db_attr]) < int(filters[filter_attr]) |
187 | + |
188 | + filters = filters or {} |
189 | + for flavor in FAKE_FLAVORS.values(): |
190 | + if reject_min('memory_mb', 'min_memory_mb'): |
191 | + continue |
192 | + elif reject_min('local_gb', 'min_local_gb'): |
193 | + continue |
194 | + |
195 | + yield flavor |
196 | + |
197 | + |
198 | +def empty_instance_type_get_all(context, inactive=False, filters=None): |
199 | + return {} |
200 | |
201 | |
202 | def return_instance_type_not_found(context, flavor_id): |
203 | @@ -63,9 +81,9 @@ |
204 | fakes.stub_out_networking(self.stubs) |
205 | fakes.stub_out_rate_limiting(self.stubs) |
206 | self.stubs.Set(nova.db.api, "instance_type_get_all", |
207 | - return_instance_types) |
208 | + fake_instance_type_get_all) |
209 | self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id", |
210 | - return_instance_type_by_flavor_id) |
211 | + fake_instance_type_get_by_flavor_id) |
212 | |
213 | def tearDown(self): |
214 | self.stubs.UnsetAll() |
215 | @@ -89,10 +107,8 @@ |
216 | self.assertEqual(flavors, expected) |
217 | |
218 | def test_get_empty_flavor_list_v1_0(self): |
219 | - def _return_empty(self): |
220 | - return {} |
221 | self.stubs.Set(nova.db.api, "instance_type_get_all", |
222 | - _return_empty) |
223 | + empty_instance_type_get_all) |
224 | |
225 | req = webob.Request.blank('/v1.0/flavors') |
226 | res = req.get_response(fakes.wsgi_app()) |
227 | @@ -120,8 +136,8 @@ |
228 | { |
229 | "id": "2", |
230 | "name": "flavor 2", |
231 | - "ram": "256", |
232 | - "disk": "10", |
233 | + "ram": "512", |
234 | + "disk": "20", |
235 | "rxtx_cap": "", |
236 | "rxtx_quota": "", |
237 | "swap": "", |
238 | @@ -131,13 +147,13 @@ |
239 | self.assertEqual(flavors, expected) |
240 | |
241 | def test_get_flavor_by_id_v1_0(self): |
242 | - req = webob.Request.blank('/v1.0/flavors/12') |
243 | + req = webob.Request.blank('/v1.0/flavors/1') |
244 | res = req.get_response(fakes.wsgi_app()) |
245 | self.assertEqual(res.status_int, 200) |
246 | flavor = json.loads(res.body)["flavor"] |
247 | expected = { |
248 | - "id": "12", |
249 | - "name": "flavor 12", |
250 | + "id": "1", |
251 | + "name": "flavor 1", |
252 | "ram": "256", |
253 | "disk": "10", |
254 | "rxtx_cap": "", |
255 | @@ -155,15 +171,15 @@ |
256 | self.assertEqual(res.status_int, 404) |
257 | |
258 | def test_get_flavor_by_id_v1_1(self): |
259 | - req = webob.Request.blank('/v1.1/fake/flavors/12') |
260 | + req = webob.Request.blank('/v1.1/fake/flavors/1') |
261 | req.environ['api.version'] = '1.1' |
262 | res = req.get_response(fakes.wsgi_app()) |
263 | self.assertEqual(res.status_int, 200) |
264 | flavor = json.loads(res.body) |
265 | expected = { |
266 | "flavor": { |
267 | - "id": "12", |
268 | - "name": "flavor 12", |
269 | + "id": "1", |
270 | + "name": "flavor 1", |
271 | "ram": "256", |
272 | "disk": "10", |
273 | "rxtx_cap": "", |
274 | @@ -173,11 +189,11 @@ |
275 | "links": [ |
276 | { |
277 | "rel": "self", |
278 | - "href": "http://localhost/v1.1/fake/flavors/12", |
279 | + "href": "http://localhost/v1.1/fake/flavors/1", |
280 | }, |
281 | { |
282 | "rel": "bookmark", |
283 | - "href": "http://localhost/fake/flavors/12", |
284 | + "href": "http://localhost/fake/flavors/1", |
285 | }, |
286 | ], |
287 | }, |
288 | @@ -255,8 +271,8 @@ |
289 | { |
290 | "id": "2", |
291 | "name": "flavor 2", |
292 | - "ram": "256", |
293 | - "disk": "10", |
294 | + "ram": "512", |
295 | + "disk": "20", |
296 | "rxtx_cap": "", |
297 | "rxtx_quota": "", |
298 | "swap": "", |
299 | @@ -277,9 +293,8 @@ |
300 | self.assertEqual(flavor, expected) |
301 | |
302 | def test_get_empty_flavor_list_v1_1(self): |
303 | - def _return_empty(self): |
304 | - return {} |
305 | - self.stubs.Set(nova.db.api, "instance_type_get_all", _return_empty) |
306 | + self.stubs.Set(nova.db.api, "instance_type_get_all", |
307 | + empty_instance_type_get_all) |
308 | |
309 | req = webob.Request.blank('/v1.1/fake/flavors') |
310 | res = req.get_response(fakes.wsgi_app()) |
311 | @@ -288,6 +303,204 @@ |
312 | expected = [] |
313 | self.assertEqual(flavors, expected) |
314 | |
315 | + def test_get_flavor_list_filter_min_ram_v1_1(self): |
316 | + """Flavor lists may be filtered by minRam""" |
317 | + req = webob.Request.blank('/v1.1/fake/flavors?minRam=512') |
318 | + req.environ['api.version'] = '1.1' |
319 | + res = req.get_response(fakes.wsgi_app()) |
320 | + self.assertEqual(res.status_int, 200) |
321 | + flavor = json.loads(res.body) |
322 | + expected = { |
323 | + "flavors": [ |
324 | + { |
325 | + "id": "2", |
326 | + "name": "flavor 2", |
327 | + "links": [ |
328 | + { |
329 | + "rel": "self", |
330 | + "href": "http://localhost/v1.1/fake/flavors/2", |
331 | + }, |
332 | + { |
333 | + "rel": "bookmark", |
334 | + "href": "http://localhost/fake/flavors/2", |
335 | + }, |
336 | + ], |
337 | + }, |
338 | + ], |
339 | + } |
340 | + self.assertEqual(flavor, expected) |
341 | + |
342 | + def test_get_flavor_list_filter_min_disk(self): |
343 | + """Flavor lists may be filtered by minRam""" |
344 | + req = webob.Request.blank('/v1.1/fake/flavors?minDisk=20') |
345 | + req.environ['api.version'] = '1.1' |
346 | + res = req.get_response(fakes.wsgi_app()) |
347 | + self.assertEqual(res.status_int, 200) |
348 | + flavor = json.loads(res.body) |
349 | + expected = { |
350 | + "flavors": [ |
351 | + { |
352 | + "id": "2", |
353 | + "name": "flavor 2", |
354 | + "links": [ |
355 | + { |
356 | + "rel": "self", |
357 | + "href": "http://localhost/v1.1/fake/flavors/2", |
358 | + }, |
359 | + { |
360 | + "rel": "bookmark", |
361 | + "href": "http://localhost/fake/flavors/2", |
362 | + }, |
363 | + ], |
364 | + }, |
365 | + ], |
366 | + } |
367 | + self.assertEqual(flavor, expected) |
368 | + |
369 | + def test_get_flavor_list_detail_min_ram_and_min_disk_v1_1(self): |
370 | + """Tests that filtering work on flavor details and that minRam and |
371 | + minDisk filters can be combined |
372 | + """ |
373 | + req = webob.Request.blank( |
374 | + '/v1.1/fake/flavors/detail?minRam=256&minDisk=20') |
375 | + req.environ['api.version'] = '1.1' |
376 | + res = req.get_response(fakes.wsgi_app()) |
377 | + self.assertEqual(res.status_int, 200) |
378 | + flavor = json.loads(res.body) |
379 | + expected = { |
380 | + "flavors": [ |
381 | + { |
382 | + "id": "2", |
383 | + "name": "flavor 2", |
384 | + "ram": "512", |
385 | + "disk": "20", |
386 | + "rxtx_cap": "", |
387 | + "rxtx_quota": "", |
388 | + "swap": "", |
389 | + "vcpus": "", |
390 | + "links": [ |
391 | + { |
392 | + "rel": "self", |
393 | + "href": "http://localhost/v1.1/fake/flavors/2", |
394 | + }, |
395 | + { |
396 | + "rel": "bookmark", |
397 | + "href": "http://localhost/fake/flavors/2", |
398 | + }, |
399 | + ], |
400 | + }, |
401 | + ], |
402 | + } |
403 | + self.assertEqual(flavor, expected) |
404 | + |
405 | + def test_get_flavor_list_detail_bogus_min_ram_v1_1(self): |
406 | + """Tests that bogus minRam filtering values are ignored""" |
407 | + req = webob.Request.blank( |
408 | + '/v1.1/fake/flavors/detail?minRam=16GB') |
409 | + req.environ['api.version'] = '1.1' |
410 | + res = req.get_response(fakes.wsgi_app()) |
411 | + self.assertEqual(res.status_int, 200) |
412 | + flavor = json.loads(res.body) |
413 | + expected = { |
414 | + "flavors": [ |
415 | + { |
416 | + "id": "1", |
417 | + "name": "flavor 1", |
418 | + "ram": "256", |
419 | + "disk": "10", |
420 | + "rxtx_cap": "", |
421 | + "rxtx_quota": "", |
422 | + "swap": "", |
423 | + "vcpus": "", |
424 | + "links": [ |
425 | + { |
426 | + "rel": "self", |
427 | + "href": "http://localhost/v1.1/fake/flavors/1", |
428 | + }, |
429 | + { |
430 | + "rel": "bookmark", |
431 | + "href": "http://localhost/fake/flavors/1", |
432 | + }, |
433 | + ], |
434 | + }, |
435 | + { |
436 | + "id": "2", |
437 | + "name": "flavor 2", |
438 | + "ram": "512", |
439 | + "disk": "20", |
440 | + "rxtx_cap": "", |
441 | + "rxtx_quota": "", |
442 | + "swap": "", |
443 | + "vcpus": "", |
444 | + "links": [ |
445 | + { |
446 | + "rel": "self", |
447 | + "href": "http://localhost/v1.1/fake/flavors/2", |
448 | + }, |
449 | + { |
450 | + "rel": "bookmark", |
451 | + "href": "http://localhost/fake/flavors/2", |
452 | + }, |
453 | + ], |
454 | + }, |
455 | + ], |
456 | + } |
457 | + self.assertEqual(flavor, expected) |
458 | + |
459 | + def test_get_flavor_list_detail_bogus_min_disk_v1_1(self): |
460 | + """Tests that bogus minDisk filtering values are ignored""" |
461 | + req = webob.Request.blank( |
462 | + '/v1.1/fake/flavors/detail?minDisk=16GB') |
463 | + req.environ['api.version'] = '1.1' |
464 | + res = req.get_response(fakes.wsgi_app()) |
465 | + self.assertEqual(res.status_int, 200) |
466 | + flavor = json.loads(res.body) |
467 | + expected = { |
468 | + "flavors": [ |
469 | + { |
470 | + "id": "1", |
471 | + "name": "flavor 1", |
472 | + "ram": "256", |
473 | + "disk": "10", |
474 | + "rxtx_cap": "", |
475 | + "rxtx_quota": "", |
476 | + "swap": "", |
477 | + "vcpus": "", |
478 | + "links": [ |
479 | + { |
480 | + "rel": "self", |
481 | + "href": "http://localhost/v1.1/fake/flavors/1", |
482 | + }, |
483 | + { |
484 | + "rel": "bookmark", |
485 | + "href": "http://localhost/fake/flavors/1", |
486 | + }, |
487 | + ], |
488 | + }, |
489 | + { |
490 | + "id": "2", |
491 | + "name": "flavor 2", |
492 | + "ram": "512", |
493 | + "disk": "20", |
494 | + "rxtx_cap": "", |
495 | + "rxtx_quota": "", |
496 | + "swap": "", |
497 | + "vcpus": "", |
498 | + "links": [ |
499 | + { |
500 | + "rel": "self", |
501 | + "href": "http://localhost/v1.1/fake/flavors/2", |
502 | + }, |
503 | + { |
504 | + "rel": "bookmark", |
505 | + "href": "http://localhost/fake/flavors/2", |
506 | + }, |
507 | + ], |
508 | + }, |
509 | + ], |
510 | + } |
511 | + self.assertEqual(flavor, expected) |
512 | + |
513 | |
514 | class FlavorsXMLSerializationTest(test.TestCase): |
515 | |
516 | |
517 | === modified file 'nova/tests/db/fakes.py' |
518 | --- nova/tests/db/fakes.py 2011-09-13 23:38:46 +0000 |
519 | +++ nova/tests/db/fakes.py 2011-09-21 23:15:31 +0000 |
520 | @@ -411,8 +411,8 @@ |
521 | 'address_v6': 'fe80::a00:3', |
522 | 'network_id': 'fake_flat'} |
523 | |
524 | - def fake_instance_type_get_all(context, inactive=0): |
525 | - return INSTANCE_TYPES |
526 | + def fake_instance_type_get_all(context, inactive=0, filters=None): |
527 | + return INSTANCE_TYPES.values() |
528 | |
529 | def fake_instance_type_get_by_name(context, name): |
530 | return INSTANCE_TYPES[name] |
531 | |
532 | === modified file 'nova/tests/test_instance_types.py' |
533 | --- nova/tests/test_instance_types.py 2011-08-24 23:03:32 +0000 |
534 | +++ nova/tests/test_instance_types.py 2011-09-21 23:15:31 +0000 |
535 | @@ -161,3 +161,40 @@ |
536 | self.assertRaises(exception.InstanceTypeNotFound, |
537 | instance_types.get_instance_type_by_name, |
538 | self._nonexistent_flavor_id()) |
539 | + |
540 | + |
541 | +class InstanceTypeFilteringTest(test.TestCase): |
542 | + """Test cases for the filter option available for instance_type_get_all""" |
543 | + def setUp(self): |
544 | + super(InstanceTypeFilteringTest, self).setUp() |
545 | + self.context = context.get_admin_context() |
546 | + |
547 | + def assertFilterResults(self, filters, expected): |
548 | + inst_types = db.api.instance_type_get_all( |
549 | + self.context, filters=filters) |
550 | + inst_names = [i['name'] for i in inst_types] |
551 | + self.assertEqual(inst_names, expected) |
552 | + |
553 | + def test_no_filters(self): |
554 | + filters = None |
555 | + expected = ['m1.large', 'm1.medium', 'm1.small', 'm1.tiny', |
556 | + 'm1.xlarge'] |
557 | + self.assertFilterResults(filters, expected) |
558 | + |
559 | + def test_min_memory_mb_filter(self): |
560 | + """Exclude tiny instance which is 512 MB""" |
561 | + filters = dict(min_memory_mb=513) |
562 | + expected = ['m1.large', 'm1.medium', 'm1.small', 'm1.xlarge'] |
563 | + self.assertFilterResults(filters, expected) |
564 | + |
565 | + def test_min_local_gb_filter(self): |
566 | + """Exclude everything but large and xlarge which have >= 80 GB""" |
567 | + filters = dict(min_local_gb=80) |
568 | + expected = ['m1.large', 'm1.xlarge'] |
569 | + self.assertFilterResults(filters, expected) |
570 | + |
571 | + def test_min_memory_mb_AND_local_gb_filter(self): |
572 | + """Exclude everything but large and xlarge which have >= 80 GB""" |
573 | + filters = dict(min_memory_mb=16384, min_local_gb=80) |
574 | + expected = ['m1.xlarge'] |
575 | + self.assertFilterResults(filters, expected) |
576 | |
577 | === modified file 'nova/tests/test_instance_types_extra_specs.py' |
578 | --- nova/tests/test_instance_types_extra_specs.py 2011-08-03 18:47:35 +0000 |
579 | +++ nova/tests/test_instance_types_extra_specs.py 2011-09-21 23:15:31 +0000 |
580 | @@ -45,7 +45,7 @@ |
581 | |
582 | def tearDown(self): |
583 | # Remove the instance type from the database |
584 | - db.api.instance_type_purge(context.get_admin_context(), "cg1.4xlarge") |
585 | + db.api.instance_type_purge(self.context, "cg1.4xlarge") |
586 | super(InstanceTypeExtraSpecsTestCase, self).tearDown() |
587 | |
588 | def test_instance_type_specs_get(self): |
589 | @@ -55,7 +55,7 @@ |
590 | xpus="2", |
591 | xpu_model="Tesla 2050") |
592 | actual_specs = db.api.instance_type_extra_specs_get( |
593 | - context.get_admin_context(), |
594 | + self.context, |
595 | self.instance_type_id) |
596 | self.assertEquals(expected_specs, actual_specs) |
597 | |
598 | @@ -64,11 +64,11 @@ |
599 | cpu_model="Nehalem", |
600 | xpu_arch="fermi", |
601 | xpus="2") |
602 | - db.api.instance_type_extra_specs_delete(context.get_admin_context(), |
603 | + db.api.instance_type_extra_specs_delete(self.context, |
604 | self.instance_type_id, |
605 | "xpu_model") |
606 | actual_specs = db.api.instance_type_extra_specs_get( |
607 | - context.get_admin_context(), |
608 | + self.context, |
609 | self.instance_type_id) |
610 | self.assertEquals(expected_specs, actual_specs) |
611 | |
612 | @@ -79,11 +79,11 @@ |
613 | xpus="2", |
614 | xpu_model="Tesla 2050") |
615 | db.api.instance_type_extra_specs_update_or_create( |
616 | - context.get_admin_context(), |
617 | + self.context, |
618 | self.instance_type_id, |
619 | dict(cpu_model="Sandy Bridge")) |
620 | actual_specs = db.api.instance_type_extra_specs_get( |
621 | - context.get_admin_context(), |
622 | + self.context, |
623 | self.instance_type_id) |
624 | self.assertEquals(expected_specs, actual_specs) |
625 | |
626 | @@ -96,18 +96,18 @@ |
627 | net_arch="ethernet", |
628 | net_mbps="10000") |
629 | db.api.instance_type_extra_specs_update_or_create( |
630 | - context.get_admin_context(), |
631 | + self.context, |
632 | self.instance_type_id, |
633 | dict(net_arch="ethernet", |
634 | net_mbps=10000)) |
635 | actual_specs = db.api.instance_type_extra_specs_get( |
636 | - context.get_admin_context(), |
637 | + self.context, |
638 | self.instance_type_id) |
639 | self.assertEquals(expected_specs, actual_specs) |
640 | |
641 | def test_instance_type_get_with_extra_specs(self): |
642 | instance_type = db.api.instance_type_get( |
643 | - context.get_admin_context(), |
644 | + self.context, |
645 | self.instance_type_id) |
646 | self.assertEquals(instance_type['extra_specs'], |
647 | dict(cpu_arch="x86_64", |
648 | @@ -116,13 +116,13 @@ |
649 | xpus="2", |
650 | xpu_model="Tesla 2050")) |
651 | instance_type = db.api.instance_type_get( |
652 | - context.get_admin_context(), |
653 | + self.context, |
654 | 5) |
655 | self.assertEquals(instance_type['extra_specs'], {}) |
656 | |
657 | def test_instance_type_get_by_name_with_extra_specs(self): |
658 | instance_type = db.api.instance_type_get_by_name( |
659 | - context.get_admin_context(), |
660 | + self.context, |
661 | "cg1.4xlarge") |
662 | self.assertEquals(instance_type['extra_specs'], |
663 | dict(cpu_arch="x86_64", |
664 | @@ -132,13 +132,13 @@ |
665 | xpu_model="Tesla 2050")) |
666 | |
667 | instance_type = db.api.instance_type_get_by_name( |
668 | - context.get_admin_context(), |
669 | + self.context, |
670 | "m1.small") |
671 | self.assertEquals(instance_type['extra_specs'], {}) |
672 | |
673 | def test_instance_type_get_by_flavor_id_with_extra_specs(self): |
674 | instance_type = db.api.instance_type_get_by_flavor_id( |
675 | - context.get_admin_context(), |
676 | + self.context, |
677 | 105) |
678 | self.assertEquals(instance_type['extra_specs'], |
679 | dict(cpu_arch="x86_64", |
680 | @@ -148,7 +148,7 @@ |
681 | xpu_model="Tesla 2050")) |
682 | |
683 | instance_type = db.api.instance_type_get_by_flavor_id( |
684 | - context.get_admin_context(), |
685 | + self.context, |
686 | 2) |
687 | self.assertEquals(instance_type['extra_specs'], {}) |
688 | |
689 | @@ -159,7 +159,12 @@ |
690 | xpus='2', |
691 | xpu_model="Tesla 2050") |
692 | |
693 | - types = db.api.instance_type_get_all(context.get_admin_context()) |
694 | - |
695 | - self.assertEquals(types['cg1.4xlarge']['extra_specs'], specs) |
696 | - self.assertEquals(types['m1.small']['extra_specs'], {}) |
697 | + types = db.api.instance_type_get_all(self.context) |
698 | + |
699 | + name2specs = {} |
700 | + for instance_type in types: |
701 | + name = instance_type['name'] |
702 | + name2specs[name] = instance_type['extra_specs'] |
703 | + |
704 | + self.assertEquals(name2specs['cg1.4xlarge'], specs) |
705 | + self.assertEquals(name2specs['m1.small'], {}) |
706 | |
707 | === modified file 'nova/tests/vmwareapi/db_fakes.py' |
708 | --- nova/tests/vmwareapi/db_fakes.py 2011-08-22 21:17:39 +0000 |
709 | +++ nova/tests/vmwareapi/db_fakes.py 2011-09-21 23:15:31 +0000 |
710 | @@ -99,8 +99,8 @@ |
711 | """Stubs out the db.instance_get_fixed_address method.""" |
712 | return '10.10.10.10' |
713 | |
714 | - def fake_instance_type_get_all(context, inactive=0): |
715 | - return INSTANCE_TYPES |
716 | + def fake_instance_type_get_all(context, inactive=0, filters=None): |
717 | + return INSTANCE_TYPES.values() |
718 | |
719 | def fake_instance_type_get_by_name(context, name): |
720 | return INSTANCE_TYPES[name] |
Hi Rick. Just wanted to let you know about: /code.launchpad .net/~rackspace -titan/ nova/minram- mindisk
https:/
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.