diff --git a/nova/compute/api.py b/nova/compute/api.py index bd33792e3ce6..3be91d09df33 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -58,7 +58,7 @@ from nova.objects import instance_action from nova.objects import instance_info_cache from nova.objects import keypair as keypair_obj from nova.objects import migration as migration_obj -from nova.objects import security_group +from nova.objects import security_group as security_group_obj from nova.objects import service as service_obj from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ @@ -3675,7 +3675,7 @@ class SecurityGroupAPI(base.Base, security_group_base.SecurityGroupBase): def populate_security_groups(self, instance, security_groups): if not security_groups: - instance.security_groups = None - return - instance.security_groups = security_group.make_secgroup_list( + # Make sure it's an empty list and not None + security_groups = [] + instance.security_groups = security_group_obj.make_secgroup_list( security_groups) diff --git a/nova/objects/instance.py b/nova/objects/instance.py index d268a0ab503e..2062f637a759 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -59,7 +59,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject): # Version 1.5: Added cleaned # Version 1.6: Added pci_devices # Version 1.7: String attributes updated to support unicode - VERSION = '1.7' + # Version 1.8: 'security_groups' and 'pci_devices' cannot be None + VERSION = '1.8' fields = { 'id': int, @@ -138,7 +139,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject): instance_info_cache.InstanceInfoCache), 'security_groups': obj_utils.nested_object( - security_group.SecurityGroupList), + security_group.SecurityGroupList, none_ok=False), 'fault': obj_utils.nested_object( instance_fault.InstanceFault), @@ -146,7 +147,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject): 'cleaned': bool, 'pci_devices': obj_utils.nested_object( - pci_device.PciDeviceList), + pci_device.PciDeviceList, none_ok=False), } obj_extra_fields = ['name'] @@ -227,7 +228,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject): def _attr_pci_devices_from_primitive(self, val): if val is None: - return None + # Only possible in version <= 1.7 + return pci_device.PciDeviceList() return base.NovaObject.obj_from_primitive(val) @staticmethod @@ -259,12 +261,9 @@ class Instance(base.NovaPersistentObject, base.NovaObject): context, instance.uuid)) if 'pci_devices' in expected_attrs: - if db_inst['pci_devices'] is None: - pci_devices = None - else: - pci_devices = pci_device._make_pci_list( - context, pci_device.PciDeviceList(), - db_inst['pci_devices']) + pci_devices = pci_device._make_pci_list( + context, pci_device.PciDeviceList(), + db_inst['pci_devices']) instance['pci_devices'] = pci_devices # NOTE(danms): info_cache and security_groups are almost @@ -274,12 +273,11 @@ class Instance(base.NovaPersistentObject, 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 ('security_groups' in expected_attrs and - db_inst.get('security_groups') is not None): - instance['security_groups'] = security_group.SecurityGroupList() - security_group._make_secgroup_list(context, - instance['security_groups'], - db_inst['security_groups']) + if 'security_groups' in expected_attrs: + sec_groups = security_group._make_secgroup_list( + context, security_group.SecurityGroupList(), + db_inst['security_groups']) + instance['security_groups'] = sec_groups instance._context = context instance.obj_reset_changes() diff --git a/nova/objects/security_group.py b/nova/objects/security_group.py index e34781d4f527..90d3adf9898f 100644 --- a/nova/objects/security_group.py +++ b/nova/objects/security_group.py @@ -80,6 +80,11 @@ def _make_secgroup_list(context, secgroup_list, db_secgroup_list): class SecurityGroupList(base.ObjectListBase, base.NovaObject): + def __init__(self): + super(SecurityGroupList, self).__init__() + self.objects = [] + self.obj_reset_changes() + @base.remotable_classmethod def get_all(cls, context): return _make_secgroup_list(context, cls(), diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 03a56a2074d7..ae1cfe5fe513 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -6068,7 +6068,7 @@ class ComputeAPITestCase(BaseTestCase): self.assertEquals(task_states.SCHEDULING, instance['task_state']) self.assertEquals(1, instance['launch_index']) self.assertIsNotNone(instance.get('uuid')) - self.assertIsNone(instance.get('security_groups')) + self.assertEqual([], instance.security_groups.objects) def test_default_hostname_generator(self): fake_uuids = [str(uuid.uuid4()) for x in xrange(4)] diff --git a/nova/tests/fake_instance.py b/nova/tests/fake_instance.py index 48554e6e29a4..6f386f25de36 100644 --- a/nova/tests/fake_instance.py +++ b/nova/tests/fake_instance.py @@ -45,7 +45,10 @@ def fake_db_instance(**updates): 'project_id': 'fake-project', 'host': 'fake-host', 'created_at': datetime.datetime(1955, 11, 5), + 'pci_devices': [], + 'security_groups': [], } + for field, typefn in instance_obj.Instance.fields.items(): if field in db_instance: continue diff --git a/nova/tests/objects/test_instance.py b/nova/tests/objects/test_instance.py index f1833ff2d437..d5a4700b8d5c 100644 --- a/nova/tests/objects/test_instance.py +++ b/nova/tests/objects/test_instance.py @@ -51,7 +51,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 + fake_instance['security_groups'] = [] fake_instance['pci_devices'] = [] fake_instance['user_id'] = self.context.user_id fake_instance['project_id'] = self.context.project_id @@ -422,18 +422,6 @@ class _TestInstanceObject(object): ['pci_devices']) self.assertEqual(len(inst.pci_devices), 0) - def test_with_none_pci_devices(self): - fake_inst = dict(self.fake_instance, pci_devices=None) - fake_uuid = fake_inst['uuid'] - self.mox.StubOutWithMock(db, 'instance_get_by_uuid') - db.instance_get_by_uuid(self.context, fake_uuid, - columns_to_join=['pci_devices'] - ).AndReturn(fake_inst) - self.mox.ReplayAll() - inst = instance.Instance.get_by_uuid(self.context, fake_uuid, - ['pci_devices']) - self.assertEqual(None, inst.pci_devices) - def test_with_pci_devices(self): fake_inst = dict(self.fake_instance) fake_uuid = fake_inst['uuid'] diff --git a/nova/tests/pci/test_pci_manager.py b/nova/tests/pci/test_pci_manager.py index 802968f48125..6d15a7091c88 100644 --- a/nova/tests/pci/test_pci_manager.py +++ b/nova/tests/pci/test_pci_manager.py @@ -324,7 +324,7 @@ class PciGetInstanceDevs(test.TestCase): def _fake_obj_load_attr(foo, attrname): if attrname == 'pci_devices': self.load_attr_called = True - foo.pci_devices = None + foo.pci_devices = pci_device.PciDeviceList() inst = fakes.stub_instance(id='1') ctxt = context.get_admin_context() diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py index 0a37fd4c1d55..2fc081f976bd 100644 --- a/nova/tests/virt/libvirt/test_libvirt.py +++ b/nova/tests/virt/libvirt/test_libvirt.py @@ -3691,7 +3691,7 @@ class LibvirtConnTestCase(test.TestCase): def test_destroy_removes_disk(self): instance = {"name": "instancename", "id": "42", "uuid": "875a8070-d0b9-4949-8b31-104d125c9a64", - "cleaned": 0, 'info_cache': None, 'security_groups': None} + "cleaned": 0, 'info_cache': None, 'security_groups': []} self.mox.StubOutWithMock(libvirt_driver.LibvirtDriver, '_undefine_domain') @@ -3777,7 +3777,7 @@ class LibvirtConnTestCase(test.TestCase): def test_delete_instance_files(self): instance = {"name": "instancename", "id": "42", "uuid": "875a8070-d0b9-4949-8b31-104d125c9a64", - "cleaned": 0, 'info_cache': None, 'security_groups': None} + "cleaned": 0, 'info_cache': None, 'security_groups': []} self.mox.StubOutWithMock(db, 'instance_get_by_uuid') self.mox.StubOutWithMock(os.path, 'exists')