summaryrefslogtreecommitdiff
path: root/nova/tests/unit/objects/test_instance.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/tests/unit/objects/test_instance.py')
-rw-r--r--nova/tests/unit/objects/test_instance.py1196
1 files changed, 1196 insertions, 0 deletions
diff --git a/nova/tests/unit/objects/test_instance.py b/nova/tests/unit/objects/test_instance.py
new file mode 100644
index 0000000000..b24fd0143d
--- /dev/null
+++ b/nova/tests/unit/objects/test_instance.py
@@ -0,0 +1,1196 @@
+# Copyright 2013 IBM Corp.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import datetime
+
+import iso8601
+import mock
+import mox
+import netaddr
+from oslo.utils import timeutils
+
+from nova.cells import rpcapi as cells_rpcapi
+from nova.compute import flavors
+from nova import db
+from nova import exception
+from nova.network import model as network_model
+from nova import notifications
+from nova import objects
+from nova.objects import instance
+from nova.objects import instance_info_cache
+from nova.objects import instance_numa_topology
+from nova.objects import pci_device
+from nova.objects import security_group
+from nova import test
+from nova.tests.unit.api.openstack import fakes
+from nova.tests.unit import fake_instance
+from nova.tests.unit.objects import test_instance_fault
+from nova.tests.unit.objects import test_instance_info_cache
+from nova.tests.unit.objects import test_instance_numa_topology
+from nova.tests.unit.objects import test_instance_pci_requests
+from nova.tests.unit.objects import test_objects
+from nova.tests.unit.objects import test_security_group
+from nova import utils
+
+
+class _TestInstanceObject(object):
+ @property
+ def fake_instance(self):
+ fake_instance = fakes.stub_instance(id=2,
+ access_ipv4='1.2.3.4',
+ access_ipv6='::1')
+ fake_instance['cell_name'] = 'api!child'
+ fake_instance['scheduled_at'] = None
+ fake_instance['terminated_at'] = None
+ fake_instance['deleted_at'] = None
+ fake_instance['created_at'] = None
+ fake_instance['updated_at'] = None
+ fake_instance['launched_at'] = (
+ fake_instance['launched_at'].replace(
+ tzinfo=iso8601.iso8601.Utc(), microsecond=0))
+ fake_instance['deleted'] = False
+ fake_instance['info_cache']['instance_uuid'] = fake_instance['uuid']
+ fake_instance['security_groups'] = []
+ fake_instance['pci_devices'] = []
+ fake_instance['user_id'] = self.context.user_id
+ fake_instance['project_id'] = self.context.project_id
+ return fake_instance
+
+ def test_datetime_deserialization(self):
+ red_letter_date = timeutils.parse_isotime(
+ timeutils.isotime(datetime.datetime(1955, 11, 5)))
+ inst = instance.Instance(uuid='fake-uuid', launched_at=red_letter_date)
+ primitive = inst.obj_to_primitive()
+ expected = {'nova_object.name': 'Instance',
+ 'nova_object.namespace': 'nova',
+ 'nova_object.version': '1.16',
+ 'nova_object.data':
+ {'uuid': 'fake-uuid',
+ 'launched_at': '1955-11-05T00:00:00Z'},
+ 'nova_object.changes': ['launched_at', 'uuid']}
+ self.assertEqual(primitive, expected)
+ inst2 = instance.Instance.obj_from_primitive(primitive)
+ self.assertIsInstance(inst2.launched_at, datetime.datetime)
+ self.assertEqual(inst2.launched_at, red_letter_date)
+
+ def test_ip_deserialization(self):
+ inst = instance.Instance(uuid='fake-uuid', access_ip_v4='1.2.3.4',
+ access_ip_v6='::1')
+ primitive = inst.obj_to_primitive()
+ expected = {'nova_object.name': 'Instance',
+ 'nova_object.namespace': 'nova',
+ 'nova_object.version': '1.16',
+ 'nova_object.data':
+ {'uuid': 'fake-uuid',
+ 'access_ip_v4': '1.2.3.4',
+ 'access_ip_v6': '::1'},
+ 'nova_object.changes': ['uuid', 'access_ip_v6',
+ 'access_ip_v4']}
+ self.assertEqual(primitive, expected)
+ inst2 = instance.Instance.obj_from_primitive(primitive)
+ self.assertIsInstance(inst2.access_ip_v4, netaddr.IPAddress)
+ self.assertIsInstance(inst2.access_ip_v6, netaddr.IPAddress)
+ self.assertEqual(inst2.access_ip_v4, netaddr.IPAddress('1.2.3.4'))
+ self.assertEqual(inst2.access_ip_v6, netaddr.IPAddress('::1'))
+
+ def test_get_without_expected(self):
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ db.instance_get_by_uuid(self.context, 'uuid',
+ columns_to_join=[],
+ use_slave=False
+ ).AndReturn(self.fake_instance)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, 'uuid',
+ expected_attrs=[])
+ for attr in instance.INSTANCE_OPTIONAL_ATTRS:
+ self.assertFalse(inst.obj_attr_is_set(attr))
+ self.assertRemotes()
+
+ def test_get_with_expected(self):
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ self.mox.StubOutWithMock(db, 'instance_fault_get_by_instance_uuids')
+ self.mox.StubOutWithMock(
+ db, 'instance_extra_get_by_instance_uuid')
+
+ exp_cols = instance.INSTANCE_OPTIONAL_ATTRS[:]
+ exp_cols.remove('fault')
+ exp_cols.remove('numa_topology')
+ exp_cols.remove('pci_requests')
+
+ db.instance_get_by_uuid(
+ self.context, 'uuid',
+ columns_to_join=exp_cols,
+ use_slave=False
+ ).AndReturn(self.fake_instance)
+ fake_faults = test_instance_fault.fake_faults
+ db.instance_fault_get_by_instance_uuids(
+ self.context, [self.fake_instance['uuid']]
+ ).AndReturn(fake_faults)
+ fake_topology = test_instance_numa_topology.fake_db_topology
+ db.instance_extra_get_by_instance_uuid(
+ self.context, self.fake_instance['uuid'],
+ columns=['numa_topology']
+ ).AndReturn(fake_topology)
+ fake_requests = test_instance_pci_requests.fake_pci_requests
+ db.instance_extra_get_by_instance_uuid(
+ self.context, self.fake_instance['uuid'],
+ columns=['pci_requests']
+ ).AndReturn(fake_requests)
+
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(
+ self.context, 'uuid',
+ expected_attrs=instance.INSTANCE_OPTIONAL_ATTRS)
+ for attr in instance.INSTANCE_OPTIONAL_ATTRS:
+ self.assertTrue(inst.obj_attr_is_set(attr))
+ self.assertRemotes()
+
+ def test_get_by_id(self):
+ self.mox.StubOutWithMock(db, 'instance_get')
+ db.instance_get(self.context, 'instid',
+ columns_to_join=['info_cache',
+ 'security_groups']
+ ).AndReturn(self.fake_instance)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_id(self.context, 'instid')
+ self.assertEqual(inst.uuid, self.fake_instance['uuid'])
+ self.assertRemotes()
+
+ def test_load(self):
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ fake_uuid = self.fake_instance['uuid']
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(self.fake_instance)
+ fake_inst2 = dict(self.fake_instance,
+ system_metadata=[{'key': 'foo', 'value': 'bar'}])
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['system_metadata'],
+ use_slave=False
+ ).AndReturn(fake_inst2)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ self.assertFalse(hasattr(inst, '_system_metadata'))
+ sys_meta = inst.system_metadata
+ self.assertEqual(sys_meta, {'foo': 'bar'})
+ self.assertTrue(hasattr(inst, '_system_metadata'))
+ # Make sure we don't run load again
+ sys_meta2 = inst.system_metadata
+ self.assertEqual(sys_meta2, {'foo': 'bar'})
+ self.assertRemotes()
+
+ def test_load_invalid(self):
+ inst = instance.Instance(context=self.context, uuid='fake-uuid')
+ self.assertRaises(exception.ObjectActionError,
+ inst.obj_load_attr, 'foo')
+
+ def test_get_remote(self):
+ # isotime doesn't have microseconds and is always UTC
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ fake_instance = self.fake_instance
+ db.instance_get_by_uuid(self.context, 'fake-uuid',
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_instance)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, 'fake-uuid')
+ self.assertEqual(inst.id, fake_instance['id'])
+ self.assertEqual(inst.launched_at, fake_instance['launched_at'])
+ self.assertEqual(str(inst.access_ip_v4),
+ fake_instance['access_ip_v4'])
+ self.assertEqual(str(inst.access_ip_v6),
+ fake_instance['access_ip_v6'])
+ self.assertRemotes()
+
+ def test_refresh(self):
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ fake_uuid = self.fake_instance['uuid']
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(dict(self.fake_instance,
+ host='orig-host'))
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(dict(self.fake_instance,
+ host='new-host'))
+ self.mox.StubOutWithMock(instance_info_cache.InstanceInfoCache,
+ 'refresh')
+ instance_info_cache.InstanceInfoCache.refresh()
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ self.assertEqual(inst.host, 'orig-host')
+ inst.refresh()
+ self.assertEqual(inst.host, 'new-host')
+ self.assertRemotes()
+ self.assertEqual(set([]), inst.obj_what_changed())
+
+ def test_refresh_does_not_recurse(self):
+ inst = instance.Instance(context=self.context, uuid='fake-uuid',
+ metadata={})
+ inst_copy = instance.Instance()
+ inst_copy.uuid = inst.uuid
+ self.mox.StubOutWithMock(instance.Instance, 'get_by_uuid')
+ instance.Instance.get_by_uuid(self.context, uuid=inst.uuid,
+ expected_attrs=['metadata'],
+ use_slave=False
+ ).AndReturn(inst_copy)
+ self.mox.ReplayAll()
+ self.assertRaises(exception.OrphanedObjectError, inst.refresh)
+
+ def _save_test_helper(self, cell_type, save_kwargs):
+ """Common code for testing save() for cells/non-cells."""
+ if cell_type:
+ self.flags(enable=True, cell_type=cell_type, group='cells')
+ else:
+ self.flags(enable=False, group='cells')
+
+ old_ref = dict(self.fake_instance, host='oldhost', user_data='old',
+ vm_state='old', task_state='old')
+ fake_uuid = old_ref['uuid']
+
+ expected_updates = dict(vm_state='meow', task_state='wuff',
+ user_data='new')
+
+ new_ref = dict(old_ref, host='newhost', **expected_updates)
+ exp_vm_state = save_kwargs.get('expected_vm_state')
+ exp_task_state = save_kwargs.get('expected_task_state')
+ admin_reset = save_kwargs.get('admin_state_reset', False)
+ if exp_vm_state:
+ expected_updates['expected_vm_state'] = exp_vm_state
+ if exp_task_state:
+ if (exp_task_state == 'image_snapshot' and
+ 'instance_version' in save_kwargs and
+ save_kwargs['instance_version'] == '1.9'):
+ expected_updates['expected_task_state'] = [
+ 'image_snapshot', 'image_snapshot_pending']
+ else:
+ expected_updates['expected_task_state'] = exp_task_state
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
+ self.mox.StubOutWithMock(db, 'instance_info_cache_update')
+ cells_api_mock = self.mox.CreateMock(cells_rpcapi.CellsAPI)
+ self.mox.StubOutWithMock(cells_api_mock,
+ 'instance_update_at_top')
+ self.mox.StubOutWithMock(cells_api_mock,
+ 'instance_update_from_api')
+ self.mox.StubOutWithMock(cells_rpcapi, 'CellsAPI',
+ use_mock_anything=True)
+ self.mox.StubOutWithMock(notifications, 'send_update')
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(old_ref)
+ db.instance_update_and_get_original(
+ self.context, fake_uuid, expected_updates,
+ update_cells=False,
+ columns_to_join=['info_cache', 'security_groups',
+ 'system_metadata']
+ ).AndReturn((old_ref, new_ref))
+ if cell_type == 'api':
+ cells_rpcapi.CellsAPI().AndReturn(cells_api_mock)
+ cells_api_mock.instance_update_from_api(
+ self.context, mox.IsA(instance.Instance),
+ exp_vm_state, exp_task_state, admin_reset)
+ elif cell_type == 'compute':
+ cells_rpcapi.CellsAPI().AndReturn(cells_api_mock)
+ cells_api_mock.instance_update_at_top(self.context, new_ref)
+ notifications.send_update(self.context, mox.IgnoreArg(),
+ mox.IgnoreArg())
+
+ self.mox.ReplayAll()
+
+ inst = instance.Instance.get_by_uuid(self.context, old_ref['uuid'])
+ if 'instance_version' in save_kwargs:
+ inst.VERSION = save_kwargs.pop('instance_version')
+ self.assertEqual('old', inst.task_state)
+ self.assertEqual('old', inst.vm_state)
+ self.assertEqual('old', inst.user_data)
+ inst.vm_state = 'meow'
+ inst.task_state = 'wuff'
+ inst.user_data = 'new'
+ inst.save(**save_kwargs)
+ self.assertEqual('newhost', inst.host)
+ self.assertEqual('meow', inst.vm_state)
+ self.assertEqual('wuff', inst.task_state)
+ self.assertEqual('new', inst.user_data)
+ self.assertEqual(set([]), inst.obj_what_changed())
+
+ def test_save(self):
+ self._save_test_helper(None, {})
+
+ def test_save_in_api_cell(self):
+ self._save_test_helper('api', {})
+
+ def test_save_in_compute_cell(self):
+ self._save_test_helper('compute', {})
+
+ def test_save_exp_vm_state(self):
+ self._save_test_helper(None, {'expected_vm_state': ['meow']})
+
+ def test_save_exp_task_state(self):
+ self._save_test_helper(None, {'expected_task_state': ['meow']})
+
+ def test_save_exp_task_state_havana(self):
+ self._save_test_helper(None, {
+ 'expected_task_state': 'image_snapshot',
+ 'instance_version': '1.9'})
+
+ def test_save_exp_vm_state_api_cell(self):
+ self._save_test_helper('api', {'expected_vm_state': ['meow']})
+
+ def test_save_exp_task_state_api_cell(self):
+ self._save_test_helper('api', {'expected_task_state': ['meow']})
+
+ def test_save_exp_task_state_api_cell_admin_reset(self):
+ self._save_test_helper('api', {'admin_state_reset': True})
+
+ def test_save_rename_sends_notification(self):
+ # Tests that simply changing the 'display_name' on the instance
+ # will send a notification.
+ self.flags(enable=False, group='cells')
+ old_ref = dict(self.fake_instance, display_name='hello')
+ fake_uuid = old_ref['uuid']
+ expected_updates = dict(display_name='goodbye')
+ new_ref = dict(old_ref, **expected_updates)
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
+ self.mox.StubOutWithMock(notifications, 'send_update')
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(old_ref)
+ db.instance_update_and_get_original(
+ self.context, fake_uuid, expected_updates, update_cells=False,
+ columns_to_join=['info_cache', 'security_groups',
+ 'system_metadata']
+ ).AndReturn((old_ref, new_ref))
+ notifications.send_update(self.context, mox.IgnoreArg(),
+ mox.IgnoreArg())
+
+ self.mox.ReplayAll()
+
+ inst = instance.Instance.get_by_uuid(self.context, old_ref['uuid'],
+ use_slave=False)
+ self.assertEqual('hello', inst.display_name)
+ inst.display_name = 'goodbye'
+ inst.save()
+ self.assertEqual('goodbye', inst.display_name)
+ self.assertEqual(set([]), inst.obj_what_changed())
+
+ @mock.patch('nova.db.instance_update_and_get_original')
+ @mock.patch('nova.objects.Instance._from_db_object')
+ def test_save_does_not_refresh_pci_devices(self, mock_fdo, mock_update):
+ # NOTE(danms): This tests that we don't update the pci_devices
+ # field from the contents of the database. This is not because we
+ # don't necessarily want to, but because the way pci_devices is
+ # currently implemented it causes versioning issues. When that is
+ # resolved, this test should go away.
+ mock_update.return_value = None, None
+ inst = instance.Instance(context=self.context, id=123)
+ inst.uuid = 'foo'
+ inst.pci_devices = pci_device.PciDeviceList()
+ inst.save()
+ self.assertNotIn('pci_devices',
+ mock_fdo.call_args_list[0][1]['expected_attrs'])
+
+ def test_get_deleted(self):
+ fake_inst = dict(self.fake_instance, id=123, deleted=123)
+ 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=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ # NOTE(danms): Make sure it's actually a bool
+ self.assertEqual(inst.deleted, True)
+
+ def test_get_not_cleaned(self):
+ fake_inst = dict(self.fake_instance, id=123, cleaned=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=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ # NOTE(mikal): Make sure it's actually a bool
+ self.assertEqual(inst.cleaned, False)
+
+ def test_get_cleaned(self):
+ fake_inst = dict(self.fake_instance, id=123, cleaned=1)
+ 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=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ # NOTE(mikal): Make sure it's actually a bool
+ self.assertEqual(inst.cleaned, True)
+
+ def test_with_info_cache(self):
+ fake_inst = dict(self.fake_instance)
+ fake_uuid = fake_inst['uuid']
+ nwinfo1 = network_model.NetworkInfo.hydrate([{'address': 'foo'}])
+ nwinfo2 = network_model.NetworkInfo.hydrate([{'address': 'bar'}])
+ nwinfo1_json = nwinfo1.json()
+ nwinfo2_json = nwinfo2.json()
+ fake_inst['info_cache'] = dict(
+ test_instance_info_cache.fake_info_cache,
+ network_info=nwinfo1_json,
+ instance_uuid=fake_uuid)
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
+ self.mox.StubOutWithMock(db, 'instance_info_cache_update')
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ db.instance_info_cache_update(self.context, fake_uuid,
+ {'network_info': nwinfo2_json})
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ self.assertEqual(inst.info_cache.network_info, nwinfo1)
+ self.assertEqual(inst.info_cache.instance_uuid, fake_uuid)
+ inst.info_cache.network_info = nwinfo2
+ inst.save()
+
+ def test_with_info_cache_none(self):
+ fake_inst = dict(self.fake_instance, info_cache=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=['info_cache'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid,
+ ['info_cache'])
+ self.assertIsNone(inst.info_cache)
+
+ def test_with_security_groups(self):
+ 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(self.context, fake_uuid,
+ columns_to_join=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ db.security_group_update(self.context, 1, {'description': 'changed'}
+ ).AndReturn(fake_inst['security_groups'][0])
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, 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.assertIsInstance(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_with_empty_security_groups(self):
+ fake_inst = dict(self.fake_instance, security_groups=[])
+ 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=['info_cache',
+ 'security_groups'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid)
+ self.assertEqual(0, len(inst.security_groups))
+
+ def test_with_empty_pci_devices(self):
+ fake_inst = dict(self.fake_instance, pci_devices=[])
+ 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'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid,
+ ['pci_devices'])
+ self.assertEqual(len(inst.pci_devices), 0)
+
+ def test_with_pci_devices(self):
+ fake_inst = dict(self.fake_instance)
+ fake_uuid = fake_inst['uuid']
+ fake_inst['pci_devices'] = [
+ {'created_at': None,
+ 'updated_at': None,
+ 'deleted_at': None,
+ 'deleted': None,
+ 'id': 2,
+ 'compute_node_id': 1,
+ 'address': 'a1',
+ 'vendor_id': 'v1',
+ 'product_id': 'p1',
+ 'dev_type': 't',
+ 'status': 'allocated',
+ 'dev_id': 'i',
+ 'label': 'l',
+ 'instance_uuid': fake_uuid,
+ 'request_id': None,
+ 'extra_info': '{}'},
+ {
+ 'created_at': None,
+ 'updated_at': None,
+ 'deleted_at': None,
+ 'deleted': None,
+ 'id': 1,
+ 'compute_node_id': 1,
+ 'address': 'a',
+ 'vendor_id': 'v',
+ 'product_id': 'p',
+ 'dev_type': 't',
+ 'status': 'allocated',
+ 'dev_id': 'i',
+ 'label': 'l',
+ 'instance_uuid': fake_uuid,
+ 'request_id': None,
+ 'extra_info': '{}'},
+ ]
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=['pci_devices'],
+ use_slave=False
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid,
+ ['pci_devices'])
+ self.assertEqual(len(inst.pci_devices), 2)
+ self.assertEqual(inst.pci_devices[0].instance_uuid, fake_uuid)
+ self.assertEqual(inst.pci_devices[1].instance_uuid, fake_uuid)
+
+ def test_with_fault(self):
+ fake_inst = dict(self.fake_instance)
+ fake_uuid = fake_inst['uuid']
+ fake_faults = [dict(x, instance_uuid=fake_uuid)
+ for x in test_instance_fault.fake_faults['fake-uuid']]
+ self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
+ self.mox.StubOutWithMock(db, 'instance_fault_get_by_instance_uuids')
+ db.instance_get_by_uuid(self.context, fake_uuid,
+ columns_to_join=[],
+ use_slave=False
+ ).AndReturn(self.fake_instance)
+ db.instance_fault_get_by_instance_uuids(
+ self.context, [fake_uuid]).AndReturn({fake_uuid: fake_faults})
+ self.mox.ReplayAll()
+ inst = instance.Instance.get_by_uuid(self.context, fake_uuid,
+ expected_attrs=['fault'])
+ self.assertEqual(fake_faults[0], dict(inst.fault.items()))
+ self.assertRemotes()
+
+ def test_iteritems_with_extra_attrs(self):
+ self.stubs.Set(instance.Instance, 'name', 'foo')
+ inst = instance.Instance(uuid='fake-uuid')
+ self.assertEqual(inst.items(),
+ {'uuid': 'fake-uuid',
+ 'name': 'foo',
+ }.items())
+
+ def _test_metadata_change_tracking(self, which):
+ inst = instance.Instance(uuid='fake-uuid')
+ setattr(inst, which, {})
+ inst.obj_reset_changes()
+ getattr(inst, which)['foo'] = 'bar'
+ self.assertEqual(set([which]), inst.obj_what_changed())
+ inst.obj_reset_changes()
+ self.assertEqual(set(), inst.obj_what_changed())
+
+ def test_metadata_change_tracking(self):
+ self._test_metadata_change_tracking('metadata')
+
+ def test_system_metadata_change_tracking(self):
+ self._test_metadata_change_tracking('system_metadata')
+
+ def test_create_stubbed(self):
+ self.mox.StubOutWithMock(db, 'instance_create')
+ vals = {'host': 'foo-host',
+ 'memory_mb': 128,
+ 'system_metadata': {'foo': 'bar'}}
+ fake_inst = fake_instance.fake_db_instance(**vals)
+ db.instance_create(self.context, vals).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance(host='foo-host', memory_mb=128,
+ system_metadata={'foo': 'bar'})
+ inst.create(self.context)
+
+ def test_create(self):
+ self.mox.StubOutWithMock(db, 'instance_create')
+ db.instance_create(self.context, {}).AndReturn(self.fake_instance)
+ self.mox.ReplayAll()
+ inst = instance.Instance()
+ inst.create(self.context)
+ self.assertEqual(self.fake_instance['id'], inst.id)
+
+ def test_create_with_values(self):
+ inst1 = instance.Instance(user_id=self.context.user_id,
+ project_id=self.context.project_id,
+ host='foo-host')
+ inst1.create(self.context)
+ self.assertEqual(inst1.host, 'foo-host')
+ inst2 = instance.Instance.get_by_uuid(self.context, inst1.uuid)
+ self.assertEqual(inst2.host, 'foo-host')
+
+ def test_create_with_numa_topology(self):
+ inst = instance.Instance(uuid=self.fake_instance['uuid'],
+ numa_topology=instance_numa_topology.InstanceNUMATopology
+ .obj_from_topology(
+ test_instance_numa_topology.fake_numa_topology))
+
+ inst.create(self.context)
+ self.assertIsNotNone(inst.numa_topology)
+ got_numa_topo = (
+ instance_numa_topology.InstanceNUMATopology
+ .get_by_instance_uuid(self.context, inst.uuid))
+ self.assertEqual(inst.numa_topology.id, got_numa_topo.id)
+
+ def test_recreate_fails(self):
+ inst = instance.Instance(user_id=self.context.user_id,
+ project_id=self.context.project_id,
+ host='foo-host')
+ inst.create(self.context)
+ self.assertRaises(exception.ObjectActionError, inst.create,
+ self.context)
+
+ def test_create_with_special_things(self):
+ self.mox.StubOutWithMock(db, 'instance_create')
+ fake_inst = fake_instance.fake_db_instance()
+ db.instance_create(self.context,
+ {'host': 'foo-host',
+ 'security_groups': ['foo', 'bar'],
+ 'info_cache': {'network_info': '[]'},
+ }
+ ).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ secgroups = security_group.SecurityGroupList()
+ secgroups.objects = []
+ for name in ('foo', 'bar'):
+ secgroup = security_group.SecurityGroup()
+ secgroup.name = name
+ secgroups.objects.append(secgroup)
+ info_cache = instance_info_cache.InstanceInfoCache()
+ info_cache.network_info = network_model.NetworkInfo()
+ inst = instance.Instance(host='foo-host', security_groups=secgroups,
+ info_cache=info_cache)
+ inst.create(self.context)
+
+ def test_destroy_stubbed(self):
+ self.mox.StubOutWithMock(db, 'instance_destroy')
+ deleted_at = datetime.datetime(1955, 11, 6)
+ fake_inst = fake_instance.fake_db_instance(deleted_at=deleted_at,
+ deleted=True)
+ db.instance_destroy(self.context, 'fake-uuid',
+ constraint=None).AndReturn(fake_inst)
+ self.mox.ReplayAll()
+ inst = instance.Instance(id=1, uuid='fake-uuid', host='foo')
+ inst.destroy(self.context)
+ self.assertEqual(timeutils.normalize_time(inst.deleted_at),
+ timeutils.normalize_time(deleted_at))
+ self.assertTrue(inst.deleted)
+
+ def test_destroy(self):
+ values = {'user_id': self.context.user_id,
+ 'project_id': self.context.project_id}
+ db_inst = db.instance_create(self.context, values)
+ inst = instance.Instance(id=db_inst['id'], uuid=db_inst['uuid'])
+ inst.destroy(self.context)
+ self.assertRaises(exception.InstanceNotFound,
+ db.instance_get_by_uuid, self.context,
+ db_inst['uuid'])
+
+ def test_destroy_host_constraint(self):
+ values = {'user_id': self.context.user_id,
+ 'project_id': self.context.project_id,
+ 'host': 'foo'}
+ db_inst = db.instance_create(self.context, values)
+ inst = instance.Instance.get_by_uuid(self.context, db_inst['uuid'])
+ inst.host = None
+ self.assertRaises(exception.ObjectActionError,
+ inst.destroy)
+
+ def test_name_does_not_trigger_lazy_loads(self):
+ values = {'user_id': self.context.user_id,
+ 'project_id': self.context.project_id,
+ 'host': 'foo'}
+ db_inst = db.instance_create(self.context, values)
+ inst = instance.Instance.get_by_uuid(self.context, db_inst['uuid'])
+ self.assertFalse(inst.obj_attr_is_set('fault'))
+ self.flags(instance_name_template='foo-%(uuid)s')
+ self.assertEqual('foo-%s' % db_inst['uuid'], inst.name)
+ self.assertFalse(inst.obj_attr_is_set('fault'))
+
+ def test_from_db_object_not_overwrite_info_cache(self):
+ info_cache = instance_info_cache.InstanceInfoCache()
+ inst = instance.Instance(context=self.context,
+ info_cache=info_cache)
+ db_inst = fake_instance.fake_db_instance()
+ db_inst['info_cache'] = dict(
+ test_instance_info_cache.fake_info_cache)
+ inst._from_db_object(self.context, inst, db_inst,
+ expected_attrs=['info_cache'])
+ self.assertIs(info_cache, inst.info_cache)
+
+ def test_compat_strings(self):
+ unicode_attributes = ['user_id', 'project_id', 'image_ref',
+ 'kernel_id', 'ramdisk_id', 'hostname',
+ 'key_name', 'key_data', 'host', 'node',
+ 'user_data', 'availability_zone',
+ 'display_name', 'display_description',
+ 'launched_on', 'locked_by', 'os_type',
+ 'architecture', 'vm_mode', 'root_device_name',
+ 'default_ephemeral_device',
+ 'default_swap_device', 'config_drive',
+ 'cell_name']
+ inst = instance.Instance()
+ expected = {}
+ for key in unicode_attributes:
+ inst[key] = u'\u2603'
+ expected[key] = '?'
+ primitive = inst.obj_to_primitive(target_version='1.6')
+ self.assertEqual(expected, primitive['nova_object.data'])
+ self.assertEqual('1.6', primitive['nova_object.version'])
+
+ def test_compat_pci_devices(self):
+ inst = instance.Instance()
+ inst.pci_devices = pci_device.PciDeviceList()
+ primitive = inst.obj_to_primitive(target_version='1.5')
+ self.assertNotIn('pci_devices', primitive)
+
+ def test_compat_info_cache(self):
+ inst = instance.Instance()
+ inst.info_cache = instance_info_cache.InstanceInfoCache()
+ primitive = inst.obj_to_primitive(target_version='1.9')
+ self.assertEqual(
+ '1.4',
+ primitive['nova_object.data']['info_cache']['nova_object.version'])
+
+ @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid')
+ def test_get_with_pci_requests(self, mock_get):
+ mock_get.return_value = objects.InstancePCIRequests()
+ db_instance = db.instance_create(self.context, {
+ 'user_id': self.context.user_id,
+ 'project_id': self.context.project_id})
+ instance = objects.Instance.get_by_uuid(
+ self.context, db_instance['uuid'],
+ expected_attrs=['pci_requests'])
+ self.assertTrue(instance.obj_attr_is_set('pci_requests'))
+ self.assertIsNotNone(instance.pci_requests)
+
+ def _test_get_flavor(self, namespace):
+ prefix = '%s_' % namespace if namespace is not None else ''
+ db_inst = db.instance_create(self.context, {
+ 'user_id': self.context.user_id,
+ 'project_id': self.context.project_id,
+ 'system_metadata': flavors.save_flavor_info(
+ {}, flavors.get_default_flavor(), prefix)})
+ db_flavor = flavors.extract_flavor(db_inst, prefix)
+ inst = instance.Instance.get_by_uuid(self.context, db_inst['uuid'])
+ flavor = inst.get_flavor(namespace)
+ self.assertEqual(db_flavor['flavorid'], flavor.flavorid)
+
+ def test_get_flavor(self):
+ self._test_get_flavor(None)
+ self._test_get_flavor('foo')
+
+ def _test_set_flavor(self, namespace):
+ prefix = '%s_' % namespace if namespace is not None else ''
+ db_inst = db.instance_create(self.context, {
+ 'user_id': self.context.user_id,
+ 'project_id': self.context.project_id,
+ })
+ inst = instance.Instance.get_by_uuid(self.context, db_inst['uuid'])
+ db_flavor = flavors.get_default_flavor()
+ inst.set_flavor(db_flavor, namespace)
+ db_inst = db.instance_get(self.context, db_inst['id'])
+ self.assertEqual(
+ db_flavor['flavorid'], flavors.extract_flavor(
+ db_inst, prefix)['flavorid'])
+
+ def test_set_flavor(self):
+ self._test_set_flavor(None)
+ self._test_set_flavor('foo')
+
+ def test_delete_flavor(self):
+ namespace = 'foo'
+ prefix = '%s_' % namespace
+ db_inst = db.instance_create(self.context, {
+ 'user_id': self.context.user_id,
+ 'project_id': self.context.project_id,
+ 'system_metadata': flavors.save_flavor_info(
+ {}, flavors.get_default_flavor(), prefix)})
+ inst = instance.Instance.get_by_uuid(self.context, db_inst['uuid'])
+ inst.delete_flavor(namespace)
+ db_inst = db.instance_get(self.context, db_inst['id'])
+ self.assertEqual({}, utils.instance_sys_meta(db_inst))
+
+ def test_delete_flavor_no_namespace_fails(self):
+ inst = instance.Instance(system_metadata={})
+ self.assertRaises(KeyError, inst.delete_flavor, None)
+ self.assertRaises(KeyError, inst.delete_flavor, '')
+
+ @mock.patch.object(db, 'instance_metadata_delete')
+ def test_delete_metadata_key(self, db_delete):
+ inst = instance.Instance(context=self.context,
+ id=1, uuid='fake-uuid')
+ inst.metadata = {'foo': '1', 'bar': '2'}
+ inst.obj_reset_changes()
+ inst.delete_metadata_key('foo')
+ self.assertEqual({'bar': '2'}, inst.metadata)
+ self.assertEqual({}, inst.obj_get_changes())
+ db_delete.assert_called_once_with(self.context, inst.uuid, 'foo')
+
+ def test_reset_changes(self):
+ inst = instance.Instance()
+ inst.metadata = {'1985': 'present'}
+ inst.system_metadata = {'1955': 'past'}
+ self.assertEqual({}, inst._orig_metadata)
+ inst.obj_reset_changes(['metadata'])
+ self.assertEqual({'1985': 'present'}, inst._orig_metadata)
+ self.assertEqual({}, inst._orig_system_metadata)
+
+ def test_load_generic_calls_handler(self):
+ inst = instance.Instance(context=self.context,
+ uuid='fake-uuid')
+ with mock.patch.object(inst, '_load_generic') as mock_load:
+ def fake_load(name):
+ inst.system_metadata = {}
+
+ mock_load.side_effect = fake_load
+ inst.system_metadata
+ mock_load.assert_called_once_with('system_metadata')
+
+ def test_load_fault_calls_handler(self):
+ inst = instance.Instance(context=self.context,
+ uuid='fake-uuid')
+ with mock.patch.object(inst, '_load_fault') as mock_load:
+ def fake_load():
+ inst.fault = None
+
+ mock_load.side_effect = fake_load
+ inst.fault
+ mock_load.assert_called_once_with()
+
+ @mock.patch('nova.objects.Instance.get_by_uuid')
+ def test_load_generic(self, mock_get):
+ inst2 = instance.Instance(metadata={'foo': 'bar'})
+ mock_get.return_value = inst2
+ inst = instance.Instance(context=self.context,
+ uuid='fake-uuid')
+ inst.metadata
+ self.assertEqual({'foo': 'bar'}, inst.metadata)
+ mock_get.assert_called_once_with(self.context,
+ uuid='fake-uuid',
+ expected_attrs=['metadata'])
+ self.assertNotIn('metadata', inst.obj_what_changed())
+
+ @mock.patch('nova.db.instance_fault_get_by_instance_uuids')
+ def test_load_fault(self, mock_get):
+ fake_fault = test_instance_fault.fake_faults['fake-uuid'][0]
+ mock_get.return_value = {'fake': [fake_fault]}
+ inst = instance.Instance(context=self.context, uuid='fake')
+ fault = inst.fault
+ mock_get.assert_called_once_with(self.context, ['fake'])
+ self.assertEqual(fake_fault['id'], fault.id)
+ self.assertNotIn('metadata', inst.obj_what_changed())
+
+
+class TestInstanceObject(test_objects._LocalTest,
+ _TestInstanceObject):
+ pass
+
+
+class TestRemoteInstanceObject(test_objects._RemoteTest,
+ _TestInstanceObject):
+ pass
+
+
+class _TestInstanceListObject(object):
+ def fake_instance(self, id, updates=None):
+ fake_instance = fakes.stub_instance(id=2,
+ access_ipv4='1.2.3.4',
+ access_ipv6='::1')
+ fake_instance['scheduled_at'] = None
+ fake_instance['terminated_at'] = None
+ fake_instance['deleted_at'] = None
+ fake_instance['created_at'] = None
+ fake_instance['updated_at'] = None
+ fake_instance['launched_at'] = (
+ fake_instance['launched_at'].replace(
+ tzinfo=iso8601.iso8601.Utc(), microsecond=0))
+ fake_instance['info_cache'] = {'network_info': '[]',
+ 'instance_uuid': fake_instance['uuid']}
+ fake_instance['security_groups'] = []
+ fake_instance['deleted'] = 0
+ if updates:
+ fake_instance.update(updates)
+ return fake_instance
+
+ def test_get_all_by_filters(self):
+ fakes = [self.fake_instance(1), self.fake_instance(2)]
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_filters')
+ db.instance_get_all_by_filters(self.context, {'foo': 'bar'}, 'uuid',
+ 'asc', limit=None, marker=None,
+ columns_to_join=['metadata'],
+ use_slave=False).AndReturn(fakes)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_by_filters(
+ self.context, {'foo': 'bar'}, 'uuid', 'asc',
+ expected_attrs=['metadata'], use_slave=False)
+
+ for i in range(0, len(fakes)):
+ self.assertIsInstance(inst_list.objects[i], instance.Instance)
+ self.assertEqual(inst_list.objects[i].uuid, fakes[i]['uuid'])
+ self.assertRemotes()
+
+ def test_get_all_by_filters_works_for_cleaned(self):
+ fakes = [self.fake_instance(1),
+ self.fake_instance(2, updates={'deleted': 2,
+ 'cleaned': None})]
+ self.context.read_deleted = 'yes'
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_filters')
+ db.instance_get_all_by_filters(self.context,
+ {'deleted': True, 'cleaned': False},
+ 'uuid', 'asc', limit=None, marker=None,
+ columns_to_join=['metadata'],
+ use_slave=False).AndReturn(
+ [fakes[1]])
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_by_filters(
+ self.context, {'deleted': True, 'cleaned': False}, 'uuid', 'asc',
+ expected_attrs=['metadata'], use_slave=False)
+
+ self.assertEqual(1, len(inst_list))
+ self.assertIsInstance(inst_list.objects[0], instance.Instance)
+ self.assertEqual(inst_list.objects[0].uuid, fakes[1]['uuid'])
+ self.assertRemotes()
+
+ def test_get_by_host(self):
+ fakes = [self.fake_instance(1),
+ self.fake_instance(2)]
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_host')
+ db.instance_get_all_by_host(self.context, 'foo',
+ columns_to_join=None,
+ use_slave=False).AndReturn(fakes)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_by_host(self.context, 'foo')
+ for i in range(0, len(fakes)):
+ self.assertIsInstance(inst_list.objects[i], instance.Instance)
+ self.assertEqual(inst_list.objects[i].uuid, fakes[i]['uuid'])
+ self.assertEqual(inst_list.objects[i]._context, self.context)
+ self.assertEqual(inst_list.obj_what_changed(), set())
+ self.assertRemotes()
+
+ def test_get_by_host_and_node(self):
+ fakes = [self.fake_instance(1),
+ self.fake_instance(2)]
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_host_and_node')
+ db.instance_get_all_by_host_and_node(self.context, 'foo', 'bar'
+ ).AndReturn(fakes)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_by_host_and_node(self.context,
+ 'foo', 'bar')
+ for i in range(0, len(fakes)):
+ self.assertIsInstance(inst_list.objects[i], instance.Instance)
+ self.assertEqual(inst_list.objects[i].uuid, fakes[i]['uuid'])
+ self.assertRemotes()
+
+ def test_get_by_host_and_not_type(self):
+ fakes = [self.fake_instance(1),
+ self.fake_instance(2)]
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_host_and_not_type')
+ db.instance_get_all_by_host_and_not_type(self.context, 'foo',
+ type_id='bar').AndReturn(
+ fakes)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_by_host_and_not_type(
+ self.context, 'foo', 'bar')
+ for i in range(0, len(fakes)):
+ self.assertIsInstance(inst_list.objects[i], instance.Instance)
+ self.assertEqual(inst_list.objects[i].uuid, fakes[i]['uuid'])
+ self.assertRemotes()
+
+ def test_get_hung_in_rebooting(self):
+ fakes = [self.fake_instance(1),
+ self.fake_instance(2)]
+ dt = timeutils.isotime()
+ self.mox.StubOutWithMock(db, 'instance_get_all_hung_in_rebooting')
+ db.instance_get_all_hung_in_rebooting(self.context, dt).AndReturn(
+ fakes)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList.get_hung_in_rebooting(self.context,
+ dt)
+ for i in range(0, len(fakes)):
+ self.assertIsInstance(inst_list.objects[i], instance.Instance)
+ self.assertEqual(inst_list.objects[i].uuid, fakes[i]['uuid'])
+ self.assertRemotes()
+
+ def test_get_active_by_window_joined(self):
+ fakes = [self.fake_instance(1), self.fake_instance(2)]
+ # NOTE(mriedem): Send in a timezone-naive datetime since the
+ # InstanceList.get_active_by_window_joined method should convert it
+ # to tz-aware for the DB API call, which we'll assert with our stub.
+ dt = timeutils.utcnow()
+
+ def fake_instance_get_active_by_window_joined(context, begin, end,
+ project_id, host):
+ # make sure begin is tz-aware
+ self.assertIsNotNone(begin.utcoffset())
+ self.assertIsNone(end)
+ return fakes
+
+ with mock.patch.object(db, 'instance_get_active_by_window_joined',
+ fake_instance_get_active_by_window_joined):
+ inst_list = instance.InstanceList.get_active_by_window_joined(
+ self.context, dt)
+
+ for fake, obj in zip(fakes, inst_list.objects):
+ self.assertIsInstance(obj, instance.Instance)
+ self.assertEqual(obj.uuid, fake['uuid'])
+ self.assertRemotes()
+
+ def test_with_fault(self):
+ fake_insts = [
+ fake_instance.fake_db_instance(uuid='fake-uuid', host='host'),
+ fake_instance.fake_db_instance(uuid='fake-inst2', host='host'),
+ ]
+ fake_faults = test_instance_fault.fake_faults
+ self.mox.StubOutWithMock(db, 'instance_get_all_by_host')
+ self.mox.StubOutWithMock(db, 'instance_fault_get_by_instance_uuids')
+ db.instance_get_all_by_host(self.context, 'host',
+ columns_to_join=[],
+ use_slave=False
+ ).AndReturn(fake_insts)
+ db.instance_fault_get_by_instance_uuids(
+ self.context, [x['uuid'] for x in fake_insts]
+ ).AndReturn(fake_faults)
+ self.mox.ReplayAll()
+ instances = instance.InstanceList.get_by_host(self.context, 'host',
+ expected_attrs=['fault'],
+ use_slave=False)
+ self.assertEqual(2, len(instances))
+ self.assertEqual(fake_faults['fake-uuid'][0],
+ dict(instances[0].fault.iteritems()))
+ self.assertIsNone(instances[1].fault)
+
+ def test_fill_faults(self):
+ self.mox.StubOutWithMock(db, 'instance_fault_get_by_instance_uuids')
+
+ inst1 = instance.Instance(uuid='uuid1')
+ inst2 = instance.Instance(uuid='uuid2')
+ insts = [inst1, inst2]
+ for inst in insts:
+ inst.obj_reset_changes()
+ db_faults = {
+ 'uuid1': [{'id': 123,
+ 'instance_uuid': 'uuid1',
+ 'code': 456,
+ 'message': 'Fake message',
+ 'details': 'No details',
+ 'host': 'foo',
+ 'deleted': False,
+ 'deleted_at': None,
+ 'updated_at': None,
+ 'created_at': None,
+ }
+ ]}
+
+ db.instance_fault_get_by_instance_uuids(self.context,
+ [x.uuid for x in insts],
+ ).AndReturn(db_faults)
+ self.mox.ReplayAll()
+ inst_list = instance.InstanceList()
+ inst_list._context = self.context
+ inst_list.objects = insts
+ faulty = inst_list.fill_faults()
+ self.assertEqual(faulty, ['uuid1'])
+ self.assertEqual(inst_list[0].fault.message,
+ db_faults['uuid1'][0]['message'])
+ self.assertIsNone(inst_list[1].fault)
+ for inst in inst_list:
+ self.assertEqual(inst.obj_what_changed(), set())
+
+ def test_get_by_security_group(self):
+ fake_secgroup = dict(test_security_group.fake_secgroup)
+ fake_secgroup['instances'] = [
+ fake_instance.fake_db_instance(id=1,
+ system_metadata={'foo': 'bar'}),
+ fake_instance.fake_db_instance(id=2),
+ ]
+
+ with mock.patch.object(db, 'security_group_get') as sgg:
+ sgg.return_value = fake_secgroup
+ secgroup = security_group.SecurityGroup()
+ secgroup.id = fake_secgroup['id']
+ instances = instance.InstanceList.get_by_security_group(
+ self.context, secgroup)
+
+ self.assertEqual(2, len(instances))
+ self.assertEqual([1, 2], [x.id for x in instances])
+ self.assertTrue(instances[0].obj_attr_is_set('system_metadata'))
+ self.assertEqual({'foo': 'bar'}, instances[0].system_metadata)
+
+
+class TestInstanceListObject(test_objects._LocalTest,
+ _TestInstanceListObject):
+ pass
+
+
+class TestRemoteInstanceListObject(test_objects._RemoteTest,
+ _TestInstanceListObject):
+ pass
+
+
+class TestInstanceObjectMisc(test.NoDBTestCase):
+ def test_expected_cols(self):
+ self.stubs.Set(instance, '_INSTANCE_OPTIONAL_JOINED_FIELDS', ['bar'])
+ self.assertEqual(['bar'], instance._expected_cols(['foo', 'bar']))
+ self.assertIsNone(instance._expected_cols(None))