Set instance.availability_zone whenever we schedule

This ensures that instance.availability_zone reflects what AZ the
instance is actually in. In the case where no AZ was requested at
boot, previously this would always be some default value, which
isn't as useful to the things that need to consider what AZ the
instance is actually in (without doing all the aggregate math to
determine it on the fly).

Related to blueprint cells-aware-api
Change-Id: I8d426f2635232ffc4b510548a905794ca88d7f99
This commit is contained in:
Dan Smith 2017-03-15 08:34:04 -07:00
parent b9d4bc94ab
commit 03b4c67b22
47 changed files with 104 additions and 69 deletions

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":"2012-10-29T13:42:11Z",
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":null,
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",
@ -71,4 +71,4 @@
},
"priority":"INFO",
"publisher_id":"nova-compute:compute"
}
}

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture": null,
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",
@ -81,4 +81,4 @@
},
"priority":"ERROR",
"publisher_id":"nova-compute:compute"
}
}

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":null,
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",
@ -71,4 +71,4 @@
},
"priority":"INFO",
"publisher_id":"nova-compute:compute"
}
}

View File

@ -62,7 +62,7 @@
"os_type": null,
"uuid": "b271fcb9-75c3-4c76-84eb-6ccad1150ece",
"locked": false,
"availability_zone": null,
"availability_zone": "nova",
"ramdisk_id": "",
"architecture": null,
"progress": 0,

View File

@ -4,7 +4,7 @@
"nova_object.name": "InstanceActionPayload",
"nova_object.data": {
"state": "active",
"availability_zone": null,
"availability_zone": "nova",
"kernel_id": "",
"host_name": "some-server",
"progress": 0,

View File

@ -64,7 +64,7 @@
}
],
"tenant_id": "6f70656e737461636b20342065766572",
"availability_zone": null,
"availability_zone": "nova",
"host": "compute",
"image_uuid": "a2459075-d96c-40d5-893e-577ff92e721c",
"state": "active",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -3,7 +3,7 @@
"payload":{
"nova_object.data":{
"architecture":"x86_64",
"availability_zone":null,
"availability_zone": "nova",
"created_at":"2012-10-29T13:42:11Z",
"deleted_at":null,
"display_name":"some-server",

View File

@ -11,7 +11,7 @@
"nova_object.namespace": "nova",
"nova_object.version": "1.0"
},
"availability_zone": null,
"availability_zone": "nova",
"bandwidth": [],
"created_at": "2012-10-29T13:42:11Z",
"deleted_at": null,

View File

@ -3,7 +3,7 @@
"payload": {
"nova_object.data": {
"architecture": "x86_64",
"availability_zone": null,
"availability_zone": "nova",
"created_at": "2012-10-29T13:42:11Z",
"deleted_at": null,
"display_name": "some-server",

View File

@ -3,7 +3,7 @@
"payload": {
"nova_object.data": {
"architecture": "x86_64",
"availability_zone": null,
"availability_zone": "nova",
"created_at": "2012-10-29T13:42:11Z",
"deleted_at": null,
"display_name": "some-server",

View File

@ -3,7 +3,7 @@
"payload": {
"nova_object.data": {
"architecture": "x86_64",
"availability_zone": null,
"availability_zone": "nova",
"created_at": "2012-10-29T13:42:11Z",
"deleted_at": null,
"display_name": "some-server",

View File

@ -25,6 +25,7 @@ from oslo_utils import excutils
from oslo_utils import versionutils
import six
from nova import availability_zones
from nova.compute import instance_actions
from nova.compute import rpcapi as compute_rpcapi
from nova.compute import task_states
@ -575,8 +576,13 @@ class ComputeTaskManager(base.Base):
return
for (instance, host) in six.moves.zip(instances, hosts):
instance.availability_zone = (
availability_zones.get_host_availability_zone(context,
host['host']))
try:
instance.refresh()
# NOTE(danms): This saves the az change above, refreshes our
# instance, and tells us if it has been deleted underneath us
instance.save()
except (exception.InstanceNotFound,
exception.InstanceInfoCacheNotFound):
LOG.debug('Instance deleted during build', instance=instance)
@ -698,6 +704,9 @@ class ComputeTaskManager(base.Base):
scheduler_utils.populate_filter_properties(
filter_properties, host_state)
(host, node) = (host_state['host'], host_state['nodename'])
instance.availability_zone = (
availability_zones.get_host_availability_zone(
context, host))
self.compute_rpcapi.unshelve_instance(
context, instance, host, image=image,
filter_properties=filter_properties, node=node)
@ -790,6 +799,10 @@ class ComputeTaskManager(base.Base):
compute_utils.notify_about_instance_usage(
self.notifier, context, instance, "rebuild.scheduled")
instance.availability_zone = (
availability_zones.get_host_availability_zone(
context, host))
self.compute_rpcapi.rebuild_instance(context,
instance=instance,
new_pass=new_pass,
@ -947,6 +960,9 @@ class ComputeTaskManager(base.Base):
'was already deleted.', instance=instance)
continue
else:
instance.availability_zone = (
availability_zones.get_host_availability_zone(
context, host['host']))
with obj_target_cell(instance, cell):
instance.create()

View File

@ -12,6 +12,7 @@
from oslo_serialization import jsonutils
from nova import availability_zones
from nova.conductor.tasks import base
from nova import objects
from nova.scheduler import utils as scheduler_utils
@ -67,6 +68,10 @@ class MigrationTask(base.TaskBase):
(host, node) = (host_state['host'], host_state['nodename'])
self.instance.availability_zone = (
availability_zones.get_host_availability_zone(
self.context, host))
# FIXME(sbauza): Serialize/Unserialize the legacy dict because of
# oslo.messaging #1529084 to transform datetime values into strings.
# tl;dr: datetimes in dicts are not accepted as correct values by the

View File

@ -54,14 +54,17 @@ class MigrationTaskTestCase(test.NoDBTestCase):
compute_rpcapi.ComputeAPI(),
scheduler_client.SchedulerClient())
@mock.patch('nova.availability_zones.get_host_availability_zone')
@mock.patch.object(objects.RequestSpec, 'from_components')
@mock.patch.object(scheduler_utils, 'setup_instance_group')
@mock.patch.object(scheduler_client.SchedulerClient, 'select_destinations')
@mock.patch.object(compute_rpcapi.ComputeAPI, 'prep_resize')
@mock.patch.object(objects.Quotas, 'from_reservations')
def test_execute(self, quotas_mock, prep_resize_mock,
sel_dest_mock, sig_mock, request_spec_from_components):
sel_dest_mock, sig_mock, request_spec_from_components,
az_mock):
sel_dest_mock.return_value = self.hosts
az_mock.return_value = 'myaz'
task = self._generate_task()
request_spec_from_components.return_value = self.request_spec
legacy_request_spec = self.request_spec.to_legacy_request_spec_dict()
@ -74,7 +77,7 @@ class MigrationTaskTestCase(test.NoDBTestCase):
self.context, self.instance.uuid, self.request_spec.image,
task.flavor, self.instance.numa_topology,
self.instance.pci_requests, expected_props, None,
self.instance.availability_zone)
None)
quotas_mock.assert_called_once_with(self.context, self.reservations,
instance=self.instance)
sig_mock.assert_called_once_with(self.context, legacy_request_spec,
@ -88,6 +91,7 @@ class MigrationTaskTestCase(test.NoDBTestCase):
filter_properties=self.filter_properties,
node=self.hosts[0]['nodename'], clean_shutdown=self.clean_shutdown)
self.assertFalse(quotas_mock.return_value.rollback.called)
az_mock.assert_called_once_with(self.context, 'host1')
def test_rollback(self):
task = self._generate_task()

View File

@ -379,8 +379,9 @@ class _BaseTaskTestCase(object):
def test_cold_migrate_forced_shutdown(self):
self._test_cold_migrate(clean_shutdown=False)
@mock.patch('nova.objects.Instance.refresh')
def test_build_instances(self, mock_refresh):
@mock.patch('nova.availability_zones.get_host_availability_zone')
@mock.patch('nova.objects.Instance.save')
def test_build_instances(self, mock_save, mock_getaz):
instance_type = flavors.get_default_flavor()
# NOTE(danms): Avoid datetime timezone issues with converted flavors
instance_type.created_at = None
@ -455,6 +456,8 @@ class _BaseTaskTestCase(object):
# build_instances() is a cast, we need to wait for it to complete
self.useFixture(cast_as_call.CastAsCall(self.stubs))
mock_getaz.return_value = 'myaz'
self.conductor.build_instances(self.context,
instances=instances,
image={'fake_data': 'should_pass_silently'},
@ -465,6 +468,9 @@ class _BaseTaskTestCase(object):
security_groups='security_groups',
block_device_mapping='block_device_mapping',
legacy_bdm=False)
mock_getaz.assert_has_calls([
mock.call(self.context, 'host1'),
mock.call(self.context, 'host2')])
@mock.patch.object(scheduler_utils, 'build_request_spec')
@mock.patch.object(scheduler_utils, 'setup_instance_group')
@ -608,7 +614,7 @@ class _BaseTaskTestCase(object):
state_mock.assert_has_calls(set_state_calls)
cleanup_mock.assert_has_calls(cleanup_network_calls)
@mock.patch.object(objects.Instance, 'refresh')
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid',
side_effect=exc.InstanceMappingNotFound(uuid='fake'))
@mock.patch.object(objects.HostMapping, 'get_by_host')
@ -618,7 +624,7 @@ class _BaseTaskTestCase(object):
'_set_vm_state_and_notify')
def test_build_instances_no_instance_mapping(self, _mock_set_state,
mock_select_dests, mock_get_by_host, mock_get_inst_map_by_uuid,
_mock_refresh):
_mock_save):
mock_select_dests.return_value = [
{'host': 'host1', 'nodename': 'node1', 'limits': []},
@ -649,7 +655,7 @@ class _BaseTaskTestCase(object):
mock.call(self.context, instances[1].uuid)])
self.assertFalse(mock_get_by_host.called)
@mock.patch.object(objects.Instance, 'refresh')
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(objects.HostMapping, 'get_by_host',
side_effect=exc.HostMappingNotFound(name='fake'))
@ -659,7 +665,7 @@ class _BaseTaskTestCase(object):
'_set_vm_state_and_notify')
def test_build_instances_no_host_mapping(self, _mock_set_state,
mock_select_dests, mock_get_by_host, mock_get_inst_map_by_uuid,
_mock_refresh):
_mock_save):
mock_select_dests.return_value = [
{'host': 'host1', 'nodename': 'node1', 'limits': []},
@ -698,7 +704,7 @@ class _BaseTaskTestCase(object):
mock_get_by_host.assert_has_calls([mock.call(self.context, 'host1'),
mock.call(self.context, 'host2')])
@mock.patch.object(objects.Instance, 'refresh')
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(objects.HostMapping, 'get_by_host')
@mock.patch.object(scheduler_client.SchedulerClient,
@ -707,7 +713,7 @@ class _BaseTaskTestCase(object):
'_set_vm_state_and_notify')
def test_build_instances_update_instance_mapping(self, _mock_set_state,
mock_select_dests, mock_get_by_host, mock_get_inst_map_by_uuid,
_mock_refresh):
_mock_save):
mock_select_dests.return_value = [
{'host': 'host1', 'nodename': 'node1', 'limits': []},
@ -751,7 +757,7 @@ class _BaseTaskTestCase(object):
mock_get_by_host.assert_has_calls([mock.call(self.context, 'host1'),
mock.call(self.context, 'host2')])
@mock.patch.object(objects.Instance, 'refresh', new=mock.MagicMock())
@mock.patch.object(objects.Instance, 'save', new=mock.MagicMock())
@mock.patch.object(objects.BuildRequest, 'get_by_instance_uuid')
@mock.patch.object(scheduler_client.SchedulerClient,
'select_destinations')
@ -796,7 +802,7 @@ class _BaseTaskTestCase(object):
for build_req in build_req_mocks:
build_req.destroy.assert_called_once_with()
@mock.patch.object(objects.Instance, 'refresh', new=mock.MagicMock())
@mock.patch.object(objects.Instance, 'save', new=mock.MagicMock())
@mock.patch.object(objects.BuildRequest, 'get_by_instance_uuid',
side_effect=exc.BuildRequestNotFound(uuid='fake'))
@mock.patch.object(scheduler_client.SchedulerClient,
@ -839,7 +845,7 @@ class _BaseTaskTestCase(object):
do_test()
@mock.patch.object(objects.Service, 'get_minimum_version', return_value=12)
@mock.patch.object(objects.Instance, 'refresh', new=mock.MagicMock())
@mock.patch.object(objects.Instance, 'save', new=mock.MagicMock())
@mock.patch.object(objects.BuildRequest, 'get_by_instance_uuid',
side_effect=exc.BuildRequestNotFound(uuid='fake'))
@mock.patch.object(scheduler_client.SchedulerClient,
@ -886,7 +892,7 @@ class _BaseTaskTestCase(object):
mock_service_version.assert_called_once_with(self.context,
'nova-osapi_compute')
@mock.patch.object(objects.Instance, 'refresh', new=mock.MagicMock())
@mock.patch.object(objects.Instance, 'save', new=mock.MagicMock())
@mock.patch.object(scheduler_client.SchedulerClient,
'select_destinations')
@mock.patch.object(conductor_manager.ComputeTaskManager,
@ -1432,13 +1438,16 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
objects=[bdm])
self.params = params
@mock.patch('nova.availability_zones.get_host_availability_zone')
@mock.patch('nova.compute.rpcapi.ComputeAPI.build_and_run_instance')
@mock.patch('nova.scheduler.rpcapi.SchedulerAPI.select_destinations')
def test_schedule_and_build_instances(self, select_destinations,
build_and_run_instance):
build_and_run_instance,
get_az):
select_destinations.return_value = [{'host': 'fake-host',
'nodename': 'fake-nodename',
'limits': None}]
get_az.return_value = 'myaz'
params = self.params
details = {}
@ -1453,6 +1462,7 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
build_and_run_instance.side_effect = _build_and_run_instance
self.conductor.schedule_and_build_instances(**params)
self.assertTrue(build_and_run_instance.called)
get_az.assert_called_once_with(mock.ANY, 'fake-host')
instance_uuid = details['instance'].uuid
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
@ -2227,8 +2237,8 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
def test_build_instances_instance_not_found(self):
instances = [fake_instance.fake_instance_obj(self.context)
for i in range(2)]
self.mox.StubOutWithMock(instances[0], 'refresh')
self.mox.StubOutWithMock(instances[1], 'refresh')
self.mox.StubOutWithMock(instances[0], 'save')
self.mox.StubOutWithMock(instances[1], 'save')
image = {'fake-data': 'should_pass_silently'}
spec = {'fake': 'specs',
'instance_properties': instances[0]}
@ -2244,9 +2254,9 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
spec, filter_properties).AndReturn(
[{'host': 'host1', 'nodename': 'node1', 'limits': []},
{'host': 'host2', 'nodename': 'node2', 'limits': []}])
instances[0].refresh().AndRaise(
instances[0].save().AndRaise(
exc.InstanceNotFound(instance_id=instances[0].uuid))
instances[1].refresh()
instances[1].save()
self.conductor_manager.compute_rpcapi.build_and_run_instance(
self.context, instance=instances[1], host='host2',
image={'fake-data': 'should_pass_silently'}, request_spec=spec,
@ -2289,16 +2299,16 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
'instance_properties': instances[0]}
build_request_spec.return_value = spec
with test.nested(
mock.patch.object(instances[0], 'refresh',
mock.patch.object(instances[0], 'save',
side_effect=exc.InstanceInfoCacheNotFound(
instance_uuid=instances[0].uuid)),
mock.patch.object(instances[1], 'refresh'),
mock.patch.object(instances[1], 'save'),
mock.patch.object(objects.RequestSpec, 'from_primitives'),
mock.patch.object(self.conductor_manager.scheduler_client,
'select_destinations', return_value=destinations),
mock.patch.object(self.conductor_manager.compute_rpcapi,
'build_and_run_instance')
) as (inst1_refresh, inst2_refresh, from_primitives,
) as (inst1_save, inst2_save, from_primitives,
select_destinations,
build_and_run_instance):