def _test_find_destination_retry_hypervisor_raises(self, error): self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, '_check_compatible_with_source_hypervisor') self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1")\ .AndRaise(error) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host, "host1"]}) self.task.scheduler_client.select_destinations(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( [{'host': 'host2'}]) self.task._check_compatible_with_source_hypervisor("host2") self.task._call_livem_checks_on_host("host2") self.mox.ReplayAll() self.assertEqual("host2", self.task._find_destination())
def test_find_destination_retry_exceeds_max(self): self.flags(migrate_max_retries=0) self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, '_check_compatible_with_source_hypervisor') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1")\ .AndRaise(exception.DestinationHypervisorTooOld) self.mox.ReplayAll() self.assertRaises(exception.NoValidHost, self.task._find_destination)
def test_find_destination_retry_exceeds_max(self): self.flags(migrate_max_retries=0) self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, '_check_compatible_with_source_hypervisor') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations( self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn([{ 'host': 'host1' }]) self.task._check_compatible_with_source_hypervisor("host1")\ .AndRaise(exception.DestinationHypervisorTooOld) self.mox.ReplayAll() self.assertRaises(exception.NoValidHost, self.task._find_destination)
def test_get_image_meta_with_image_id_none(self, mock_flavor_get): mock_flavor_get.return_value = objects.Flavor(extra_specs={}) self.image['properties'] = {'fake_property': 'fake_value'} inst = self.instance_obj with mock.patch.object(flavors, "extract_flavor") as mock_extract_flavor: with mock.patch.object(utils, "get_system_metadata_from_image" ) as mock_get_sys_metadata: image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, None, inst) self.assertEqual(0, self.mock_image_api.get.call_count) self.assertEqual(0, mock_extract_flavor.call_count) self.assertEqual(0, mock_get_sys_metadata.call_count) self.assertNotIn('fake_property', image_meta['properties']) # Checking mock_image_api_get is called with 0 image_id # as 0 is a valid image ID image_meta = compute_utils.get_image_metadata(self.ctx, self.mock_image_api, 0, self.instance_obj) self.assertEqual(1, self.mock_image_api.get.call_count) self.assertIn('fake_property', image_meta['properties'])
def test_find_destination_works(self): self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, '_check_compatible_with_source_hypervisor') self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations( self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn([{ 'host': 'host1' }]) self.task._check_compatible_with_source_hypervisor("host1") self.task._call_livem_checks_on_host("host1") self.mox.ReplayAll() self.assertEqual("host1", self.task._find_destination())
def _find_destination(self): # TODO(johngarbutt) this retry loop should be shared attempted_hosts = [self.source] image = None if self.instance.image_ref: image = compute_utils.get_image_metadata(self.context, self.image_api, self.instance.image_ref, self.instance) request_spec = scheduler_utils.build_request_spec( self.context, image, [self.instance]) host = None while host is None: self._check_not_over_max_retries(attempted_hosts) filter_properties = {'ignore_hosts': attempted_hosts} scheduler_utils.setup_instance_group(self.context, request_spec, filter_properties) host = self.scheduler_client.select_destinations( self.context, request_spec, filter_properties)[0]['host'] try: self._check_compatible_with_source_hypervisor(host) self._call_livem_checks_on_host(host) except exception.Invalid as e: LOG.debug("Skipping host: %(host)s because: %(e)s", { "host": host, "e": e }) attempted_hosts.append(host) host = None return host
def test_get_image_meta(self, mock_get): mock_get.return_value = objects.Flavor(extra_specs={}) image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) self.image['properties'] = 'DONTCARE' self.assertThat(self.image, matchers.DictMatches(image_meta))
def _find_destination(self): # TODO(johngarbutt) this retry loop should be shared attempted_hosts = [self.source] image = None if self.instance.image_ref: image = compute_utils.get_image_metadata(self.context, self.image_api, self.instance.image_ref, self.instance) request_spec = scheduler_utils.build_request_spec(self.context, image, [self.instance]) host = None while host is None: self._check_not_over_max_retries(attempted_hosts) filter_properties = {'ignore_hosts': attempted_hosts} scheduler_utils.setup_instance_group(self.context, request_spec, filter_properties) host = self.scheduler_client.select_destinations(self.context, request_spec, filter_properties)[0]['host'] try: self._check_compatible_with_source_hypervisor(host) self._call_livem_checks_on_host(host) except exception.Invalid as e: LOG.debug("Skipping host: %(host)s because: %(e)s", {"host": host, "e": e}) attempted_hosts.append(host) host = None return host
def _cold_migrate(self, context, instance, flavor, filter_properties, reservations, clean_shutdown): image_ref = instance.image_ref image = compute_utils.get_image_metadata(context, self.image_api, image_ref, instance) request_spec = scheduler_utils.build_request_spec(context, image, [instance], instance_type=flavor) quotas = objects.Quotas.from_reservations(context, reservations, instance=instance) try: scheduler_utils.setup_instance_group(context, request_spec, filter_properties) scheduler_utils.populate_retry(filter_properties, instance["uuid"]) hosts = self.scheduler_client.select_destinations(context, request_spec, filter_properties) host_state = hosts[0] except exception.NoValidHost as ex: vm_state = instance.vm_state if not vm_state: vm_state = vm_states.ACTIVE updates = {"vm_state": vm_state, "task_state": None} self._set_vm_state_and_notify(context, instance.uuid, "migrate_server", updates, ex, request_spec) quotas.rollback() # if the flavor IDs match, it's migrate; otherwise resize if flavor["id"] == instance["instance_type_id"]: msg = _("No valid host found for cold migrate") else: msg = _("No valid host found for resize") raise exception.NoValidHost(reason=msg) except exception.UnsupportedPolicyException as ex: with excutils.save_and_reraise_exception(): vm_state = instance.vm_state if not vm_state: vm_state = vm_states.ACTIVE updates = {"vm_state": vm_state, "task_state": None} self._set_vm_state_and_notify(context, instance.uuid, "migrate_server", updates, ex, request_spec) quotas.rollback() try: scheduler_utils.populate_filter_properties(filter_properties, host_state) # context is not serializable filter_properties.pop("context", None) (host, node) = (host_state["host"], host_state["nodename"]) self.compute_rpcapi.prep_resize( context, image, instance, flavor, host, reservations, request_spec=request_spec, filter_properties=filter_properties, node=node, clean_shutdown=clean_shutdown, ) except Exception as ex: with excutils.save_and_reraise_exception(): updates = {"vm_state": instance.vm_state, "task_state": None} self._set_vm_state_and_notify(context, instance.uuid, "migrate_server", updates, ex, request_spec) quotas.rollback()
def test_find_destination_when_runs_out_of_hosts(self): self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndRaise( exception.NoValidHost(reason="")) self.mox.ReplayAll() self.assertRaises(exception.NoValidHost, self.task._find_destination)
def test_find_destination_when_runs_out_of_hosts(self): self.mox.StubOutWithMock(compute_utils, 'get_image_metadata') self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') compute_utils.get_image_metadata(self.context, self.task.image_api, self.instance_image, self.instance).AndReturn("image") scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({}) scheduler_utils.setup_instance_group( self.context, {}, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations( self.context, mox.IgnoreArg(), mox.IgnoreArg()).AndRaise(exception.NoValidHost(reason="")) self.mox.ReplayAll() self.assertRaises(exception.NoValidHost, self.task._find_destination)
def _test_get_image_meta_exception(self, error): self.mock_image_api.get.side_effect = error image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) self.image['properties'] = 'DONTCARE' # NOTE(danms): The trip through system_metadata will stringify things for key in self.image: self.image[key] = str(self.image[key]) self.assertThat(self.image, matchers.DictMatches(image_meta))
def test_get_image_meta_no_image_system_meta(self): for k in self.instance_obj.system_metadata.keys(): if k.startswith('image_'): del self.instance_obj.system_metadata[k] with mock.patch('patron.objects.Flavor.get_by_flavor_id') as get: get.return_value = objects.Flavor(extra_specs={}) image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) self.image['properties'] = 'DONTCARE' self.assertThat(self.image, matchers.DictMatches(image_meta))
def test_get_image_meta_no_image_no_image_system_meta(self): e = exception.ImageNotFound(image_id='fake-image') self.mock_image_api.get.side_effect = e for k in self.instance_obj.system_metadata.keys(): if k.startswith('image_'): del self.instance_obj.system_metadata[k] with mock.patch('patron.objects.Flavor.get_by_flavor_id') as get: get.return_value = objects.Flavor(extra_specs={}) image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) expected = {'properties': 'DONTCARE'} self.assertThat(expected, matchers.DictMatches(image_meta))
def _cold_migrate(self, context, instance, flavor, filter_properties, reservations, clean_shutdown): image_ref = instance.image_ref image = compute_utils.get_image_metadata( context, self.image_api, image_ref, instance) request_spec = scheduler_utils.build_request_spec( context, image, [instance], instance_type=flavor) quotas = objects.Quotas.from_reservations(context, reservations, instance=instance) try: scheduler_utils.setup_instance_group(context, request_spec, filter_properties) scheduler_utils.populate_retry(filter_properties, instance['uuid']) hosts = self.scheduler_client.select_destinations( context, request_spec, filter_properties) host_state = hosts[0] except exception.NoValidHost as ex: vm_state = instance.vm_state if not vm_state: vm_state = vm_states.ACTIVE updates = {'vm_state': vm_state, 'task_state': None} self._set_vm_state_and_notify(context, instance.uuid, 'migrate_server', updates, ex, request_spec) quotas.rollback() # if the flavor IDs match, it's migrate; otherwise resize if flavor['id'] == instance['instance_type_id']: msg = _("No valid host found for cold migrate") else: msg = _("No valid host found for resize") raise exception.NoValidHost(reason=msg) except exception.UnsupportedPolicyException as ex: with excutils.save_and_reraise_exception(): vm_state = instance.vm_state if not vm_state: vm_state = vm_states.ACTIVE updates = {'vm_state': vm_state, 'task_state': None} self._set_vm_state_and_notify(context, instance.uuid, 'migrate_server', updates, ex, request_spec) quotas.rollback() try: scheduler_utils.populate_filter_properties(filter_properties, host_state) # context is not serializable filter_properties.pop('context', None) (host, node) = (host_state['host'], host_state['nodename']) self.compute_rpcapi.prep_resize( context, image, instance, flavor, host, reservations, request_spec=request_spec, filter_properties=filter_properties, node=node, clean_shutdown=clean_shutdown) except Exception as ex: with excutils.save_and_reraise_exception(): updates = {'vm_state': instance.vm_state, 'task_state': None} self._set_vm_state_and_notify(context, instance.uuid, 'migrate_server', updates, ex, request_spec) quotas.rollback()