diff options
| author | Dan Smith <danms@us.ibm.com> | 2013-06-17 19:03:03 -0700 |
|---|---|---|
| committer | Dan Smith <danms@us.ibm.com> | 2013-06-24 15:47:53 -0700 |
| commit | eec6ddcfaf2af215a0e041ab1b7bbcce8ebb5aad (patch) | |
| tree | f7f2344fce4f126f912a2436e7c7c629c20af7ba | |
| parent | 1792c03d81a5a72fbf881e26be235fb77236b1c2 (diff) | |
| download | nova-eec6ddcfaf2af215a0e041ab1b7bbcce8ebb5aad.tar.gz nova-eec6ddcfaf2af215a0e041ab1b7bbcce8ebb5aad.tar.xz nova-eec6ddcfaf2af215a0e041ab1b7bbcce8ebb5aad.zip | |
Add Instance.security_groups
This makes Instance load the security_groups list when it
is present in the database object.
It also refactors the way info_cache is saved, so that it
can more easily apply to security_groups as well.
Related to blueprint unified-object-model
Fixes bug 1192003
Change-Id: Ifb028e17ffef7c14557e6389a650d66ce8e9b25c
| -rw-r--r-- | nova/objects/instance.py | 31 | ||||
| -rw-r--r-- | nova/tests/api/openstack/fakes.py | 5 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute.py | 9 | ||||
| -rw-r--r-- | nova/tests/objects/test_instance.py | 37 |
4 files changed, 75 insertions, 7 deletions
diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 55e98e46e..cc61b1ed9 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -16,6 +16,7 @@ from nova import db from nova import notifications from nova.objects import base from nova.objects import instance_info_cache +from nova.objects import security_group from nova.objects import utils as obj_utils from nova import utils @@ -28,13 +29,14 @@ CONF = cfg.CONF # These are fields that can be specified as expected_attrs INSTANCE_OPTIONAL_FIELDS = ['metadata', 'system_metadata'] # These are fields that are always joined by the db right now -INSTANCE_IMPLIED_FIELDS = ['info_cache'] +INSTANCE_IMPLIED_FIELDS = ['info_cache', 'security_groups'] class Instance(base.NovaObject): # Version 1.0: Initial version # Version 1.1: Added info_cache - VERSION = '1.1' + # Version 1.2: Added security_groups + VERSION = '1.2' fields = { 'id': int, @@ -106,8 +108,10 @@ class Instance(base.NovaObject): 'system_metadata': dict, 'info_cache': obj_utils.nested_object_or_none( - instance_info_cache.InstanceInfoCache) + instance_info_cache.InstanceInfoCache), + 'security_groups': obj_utils.nested_object_or_none( + security_group.SecurityGroupList), } obj_extra_fields = ['name'] @@ -149,6 +153,8 @@ class Instance(base.NovaObject): _attr_launched_at_to_primitive = obj_utils.dt_serializer('launched_at') _attr_terminated_at_to_primitive = obj_utils.dt_serializer('terminated_at') _attr_info_cache_to_primitive = obj_utils.obj_serializer('info_cache') + _attr_security_groups_to_primitive = obj_utils.obj_serializer( + 'security_groups') _attr_scheduled_at_from_primitive = obj_utils.dt_deserializer _attr_launched_at_from_primitive = obj_utils.dt_deserializer @@ -157,6 +163,9 @@ class Instance(base.NovaObject): def _attr_info_cache_from_primitive(self, val): return base.NovaObject.obj_from_primitive(val) + def _attr_security_groups_from_primitive(self, val): + return base.NovaObject.obj_from_primitive(val) + @staticmethod def _from_db_object(context, instance, db_inst, expected_attrs=None): """Method to help with migration to objects. @@ -186,6 +195,11 @@ class Instance(base.NovaObject): instance['info_cache'] = instance_info_cache.InstanceInfoCache() instance_info_cache.InstanceInfoCache._from_db_object( context, instance['info_cache'], db_inst['info_cache']) + if db_inst['security_groups']: + instance['security_groups'] = security_group.SecurityGroupList() + security_group._make_secgroup_list(context, + instance['security_groups'], + db_inst['security_groups']) instance._context = context instance.obj_reset_changes() @@ -211,6 +225,13 @@ class Instance(base.NovaObject): return Instance._from_db_object(context, cls(), db_inst, expected_attrs) + def _save_info_cache(self, context): + self.info_cache.save(context) + + def _save_security_groups(self, context): + for secgroup in self.security_groups: + secgroup.save(context) + @base.remotable def save(self, context, expected_task_state=None): """Save updates to this instance @@ -228,7 +249,7 @@ class Instance(base.NovaObject): for field in self.fields: if (hasattr(self, base.get_attrname(field)) and isinstance(self[field], base.NovaObject)): - self[field].save(context) + getattr(self, '_save_%s' % field)(context) elif field in changes: updates[field] = self[field] if expected_task_state is not None: @@ -270,6 +291,8 @@ class Instance(base.NovaObject): extra.append('metadata') elif attrname == 'info_cache': extra.append('info_cache') + elif attrname == 'security_groups': + extra.append('security_groups') if not extra: raise Exception('Cannot load "%s" from instance' % attrname) diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index f05561ff2..a4edf9e89 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -488,7 +488,10 @@ def stub_instance(id, user_id=None, project_id=None, host=None, key_data = '' if security_groups is None: - security_groups = [{"id": 1, "name": "test"}] + security_groups = [{"id": 1, "name": "test", "description": "Foo:", + "project_id": "project", "user_id": "user", + "created_at": None, "updated_at": None, + "deleted_at": None, "deleted": False}] # ReservationID isn't sent back, hack it in there. server_name = name or "server%s" % id diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 7953f8b63..cb9498b1a 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -262,6 +262,7 @@ class BaseTestCase(test.TestCase): inst['created_at'] = timeutils.utcnow() inst['updated_at'] = timeutils.utcnow() inst['launched_at'] = timeutils.utcnow() + inst['security_groups'] = [] inst.update(params) _create_service_entries(self.context.elevated(), {'fake_zone': [inst['host']]}) @@ -275,7 +276,10 @@ class BaseTestCase(test.TestCase): def _fake_db_create(_ctxt, inst): for k, v in inst.items(): - setattr(instance, k, v) + if k == 'security_groups': + setattr(instance, k, v or None) + else: + setattr(instance, k, v) return instance self.stubs.Set(db, 'instance_create', _fake_db_create) @@ -4851,7 +4855,8 @@ class ComputeTestCase(BaseTestCase): inst = dict(fakes.stub_instance(1), deleted_at=None, created_at=None, updated_at=None, deleted=0, info_cache={'instance_uuid': 'fake-uuid', - 'network_info': None}) + 'network_info': None}, + security_groups=None) startup_instances = [inst, inst, inst] def _do_mock_calls(defer_iptables_apply): diff --git a/nova/tests/objects/test_instance.py b/nova/tests/objects/test_instance.py index 09ce70355..f5128e73f 100644 --- a/nova/tests/objects/test_instance.py +++ b/nova/tests/objects/test_instance.py @@ -20,6 +20,7 @@ from nova import context from nova import db from nova.objects import base from nova.objects import instance +from nova.objects import security_group from nova.openstack.common import timeutils from nova.tests.api.openstack import fakes from nova.tests.objects import test_objects @@ -41,6 +42,7 @@ class _TestInstanceObject(object): tzinfo=iso8601.iso8601.Utc(), microsecond=0)) fake_instance['deleted'] = False fake_instance['info_cache']['instance_uuid'] = fake_instance['uuid'] + fake_instance['security_groups'] = None return fake_instance def test_datetime_deserialization(self): @@ -213,6 +215,40 @@ class _TestInstanceObject(object): inst.info_cache.network_info = 'bar' inst.save() + def test_with_security_groups(self): + ctxt = context.get_admin_context() + fake_inst = dict(self.fake_instance) + fake_uuid = fake_inst['uuid'] + fake_inst['security_groups'] = [ + {'id': 1, 'name': 'secgroup1', 'description': 'fake-desc', + 'user_id': 'fake-user', 'project_id': 'fake_project', + 'created_at': None, 'updated_at': None, 'deleted_at': None, + 'deleted': False}, + {'id': 2, 'name': 'secgroup2', 'description': 'fake-desc', + 'user_id': 'fake-user', 'project_id': 'fake_project', + 'created_at': None, 'updated_at': None, 'deleted_at': None, + 'deleted': False}, + ] + self.mox.StubOutWithMock(db, 'instance_get_by_uuid') + self.mox.StubOutWithMock(db, 'instance_update_and_get_original') + self.mox.StubOutWithMock(db, 'security_group_update') + db.instance_get_by_uuid(ctxt, fake_uuid, []).AndReturn(fake_inst) + db.security_group_update(ctxt, 1, {'description': 'changed'} + ).AndReturn(fake_inst['security_groups'][0]) + self.mox.ReplayAll() + inst = instance.Instance.get_by_uuid(ctxt, fake_uuid) + self.assertEqual(len(inst.security_groups), 2) + for index, group in enumerate(fake_inst['security_groups']): + for key in group: + self.assertEqual(group[key], + inst.security_groups[index][key]) + self.assertTrue(isinstance(inst.security_groups[index], + security_group.SecurityGroup)) + self.assertEqual(inst.security_groups.obj_what_changed(), set()) + inst.security_groups[0].description = 'changed' + inst.save() + self.assertEqual(inst.security_groups.obj_what_changed(), set()) + def test_iteritems_with_extra_attrs(self): self.stubs.Set(instance.Instance, 'name', 'foo') inst = instance.Instance() @@ -248,6 +284,7 @@ class _TestInstanceListObject(object): tzinfo=iso8601.iso8601.Utc(), microsecond=0)) fake_instance['info_cache'] = {'network_info': 'foo', 'instance_uuid': fake_instance['uuid']} + fake_instance['security_groups'] = [] fake_instance['deleted'] = 0 if updates: fake_instance.update(updates) |
