From d1f513a20845840471fd71068cb1c9d0b8b3d02e Mon Sep 17 00:00:00 2001 From: Ethan Lynn Date: Tue, 24 Jun 2014 00:09:19 +0800 Subject: [PATCH] Implement Flavor Extra-specs Key/Value Pairs Add flavor set_keys function to nova_flavor resource. Change-Id: I5d46ace4d729a2c4a1b136265b146417e7ad2812 --- contrib/nova_flavor/nova_flavor/README.md | 1 + .../nova_flavor/resources/nova_flavor.py | 23 +++++++++++++++++-- .../nova_flavor/tests/test_nova_flavor.py | 14 +++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/contrib/nova_flavor/nova_flavor/README.md b/contrib/nova_flavor/nova_flavor/README.md index 323514107c..f17a8cf9bf 100644 --- a/contrib/nova_flavor/nova_flavor/README.md +++ b/contrib/nova_flavor/nova_flavor/README.md @@ -33,6 +33,7 @@ resources: vcpus: 1 disk: 20 swap: 2 + extra_specs: {"quota:disk_read_bytes_sec": "10240000"} ``` ### Issues with the Nova Flavor plugin diff --git a/contrib/nova_flavor/nova_flavor/resources/nova_flavor.py b/contrib/nova_flavor/nova_flavor/resources/nova_flavor.py index 5d893fa6eb..db9b7cd8b9 100644 --- a/contrib/nova_flavor/nova_flavor/resources/nova_flavor.py +++ b/contrib/nova_flavor/nova_flavor/resources/nova_flavor.py @@ -37,10 +37,10 @@ class NovaFlavor(resource.Resource): PROPERTIES = ( RAM, VCPUS, DISK, SWAP, EPHEMERAL, - RXTX_FACTOR, + RXTX_FACTOR, EXTRA_SPECS, ) = ( 'ram', 'vcpus', 'disk', 'swap', 'ephemeral', - 'rxtx_factor', + 'rxtx_factor', 'extra_specs', ) properties_schema = { @@ -76,6 +76,12 @@ class NovaFlavor(resource.Resource): _('RX/TX factor.'), default=1.0 ), + EXTRA_SPECS: properties.Schema( + properties.Schema.MAP, + _('Key/Value pairs to extend the capabilities of the flavor.'), + update_allowed=True, + ), + } def __init__(self, name, json_snippet, stack): @@ -86,15 +92,28 @@ class NovaFlavor(resource.Resource): args['flavorid'] = 'auto' args['name'] = self.physical_resource_name() args['is_public'] = False + flavor_keys = args.pop(self.EXTRA_SPECS) flavor = self.nova().flavors.create(**args) self.resource_id_set(flavor.id) + if flavor_keys: + flavor.set_keys(flavor_keys) tenant = self.stack.context.tenant_id # grant access to the active project and the admin project self.nova().flavor_access.add_tenant_access(flavor, tenant) self.nova().flavor_access.add_tenant_access(flavor, 'admin') + def handle_update(self, json_snippet, tmpl_diff, prop_diff): + """Update nova flavor.""" + if self.EXTRA_SPECS in prop_diff: + flavor = self.nova().flavors.get(self.resource_id) + old_keys = flavor.get_keys() + flavor.unset_keys(old_keys) + new_keys = prop_diff.get(self.EXTRA_SPECS) + if new_keys is not None: + flavor.set_keys(new_keys) + def handle_delete(self): if self.resource_id is None: return diff --git a/contrib/nova_flavor/nova_flavor/tests/test_nova_flavor.py b/contrib/nova_flavor/nova_flavor/tests/test_nova_flavor.py index 0043883bec..8674e21c2f 100644 --- a/contrib/nova_flavor/nova_flavor/tests/test_nova_flavor.py +++ b/contrib/nova_flavor/nova_flavor/tests/test_nova_flavor.py @@ -35,6 +35,7 @@ flavor_template = { 'swap': 2, 'rxtx_factor': 1.0, 'ephemeral': 0, + 'extra_specs': {"foo": "bar"} } } } @@ -75,8 +76,21 @@ class NovaFlavorTest(HeatTestCase): value.id = flavor_id self.flavors.create.return_value = value self.my_flavor.handle_create() + value.set_keys.assert_called_once_with({"foo": "bar"}) self.assertEqual(flavor_id, self.my_flavor.resource_id) + def test_flavor_handle_update_keys(self): + value = mock.MagicMock() + self.flavors.get.return_value = value + value.get_keys.return_value = {} + + new_keys = {"new_foo": "new_bar"} + prop_diff = {'extra_specs': new_keys} + self.my_flavor.handle_update(json_snippet=None, + tmpl_diff=None, prop_diff=prop_diff) + value.unset_keys.assert_called_once_with({}) + value.set_keys.assert_called_once_with(new_keys) + def test_flavor_handle_delete(self): self.resource_id = None self.assertIsNone(self.my_flavor.handle_delete())