Add new compute method for building an instance
The run_instance method on the compute manager handles rescheduling of a failed build by casting back to the scheduler. In order to maintain backwards compatibility while modifying the build process to go through the conductor a new method is being added to co-ordinate building an instance. This is one part of a series of patches to build up the build_and_run_instance method. The conductor will be switched over to calling this method once it reaches a level of consistency with the current run_instance method. Part of bp query-scheduler Change-Id: I879805efa4a0a045082c02b10926e1278136b72c
This commit is contained in:
@@ -391,6 +391,7 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
self.compute_api = compute.API()
|
||||
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
|
||||
self.conductor_api = conductor.API()
|
||||
self.compute_task_api = conductor.ComputeTaskAPI()
|
||||
self.is_neutron_security_groups = (
|
||||
openstack_driver.is_neutron_security_groups())
|
||||
self.consoleauth_rpcapi = consoleauth.rpcapi.ConsoleAuthAPI()
|
||||
@@ -1398,6 +1399,67 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
block_device_mapping)
|
||||
return {'block_device_mapping': block_device_mapping}
|
||||
|
||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||
@reverts_task_state
|
||||
@wrap_instance_event
|
||||
@wrap_instance_fault
|
||||
def build_and_run_instance(self, context, instance, image, request_spec,
|
||||
filter_properties, admin_password=None,
|
||||
injected_files=None, requested_networks=None,
|
||||
security_groups=None, block_device_mapping=None,
|
||||
node=None):
|
||||
|
||||
@utils.synchronized(instance['uuid'])
|
||||
def do_build_and_run_instance(context, instance, image, request_spec,
|
||||
filter_properties, admin_password, injected_files,
|
||||
requested_networks, security_groups, block_device_mapping,
|
||||
node):
|
||||
|
||||
# b64 decode the files to inject:
|
||||
decoded_files = self._decode_files(injected_files)
|
||||
|
||||
try:
|
||||
self._build_and_run_instance(context, instance, image,
|
||||
decoded_files, admin_password)
|
||||
except exception.BuildAbortException:
|
||||
self._set_instance_error_state(context, instance['uuid'])
|
||||
except exception.RescheduledException:
|
||||
self.compute_task_api.build_instances(context, [instance],
|
||||
image, filter_properties, admin_password,
|
||||
injected_files, requested_networks, security_groups,
|
||||
block_device_mapping)
|
||||
except Exception:
|
||||
# Should not reach here.
|
||||
self._set_instance_error_state(context, instance['uuid'])
|
||||
msg = 'Unexpected build failure, not rescheduling build.'
|
||||
LOG.exception(msg, instance=instance)
|
||||
|
||||
do_build_and_run_instance(context, instance, image, request_spec,
|
||||
filter_properties, admin_password, injected_files,
|
||||
requested_networks, security_groups, block_device_mapping,
|
||||
node)
|
||||
|
||||
def _build_and_run_instance(self, context, instance, image, injected_files,
|
||||
admin_password):
|
||||
|
||||
try:
|
||||
self.driver.spawn(context, instance, image,
|
||||
injected_files, admin_password)
|
||||
except exception.InstanceNotFound:
|
||||
msg = _('Instance disappeared during build.')
|
||||
LOG.debug(msg, instance=instance)
|
||||
raise exception.BuildAbortException(instance_uuid=instance['uuid'],
|
||||
reason=msg)
|
||||
except exception.UnexpectedTaskStateError as e:
|
||||
msg = e.format_message()
|
||||
LOG.debug(msg, instance=instance)
|
||||
raise exception.BuildAbortException(instance_uuid=instance['uuid'],
|
||||
reason=msg)
|
||||
except Exception:
|
||||
LOG.exception('Instance failed to spawn', instance=instance)
|
||||
raise exception.RescheduledException(
|
||||
instance_uuid=instance['uuid'], reason='')
|
||||
|
||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||
@reverts_task_state
|
||||
@wrap_instance_event
|
||||
|
||||
@@ -614,3 +614,100 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
|
||||
{'uuid': 'fake'})
|
||||
self.assertTrue(volumes[old_volume_id]['status'], 'detaching')
|
||||
self.assertTrue(volumes[new_volume_id]['status'], 'attaching')
|
||||
|
||||
|
||||
class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(ComputeManagerBuildInstanceTestCase, self).setUp()
|
||||
self.compute = importutils.import_object(CONF.compute_manager)
|
||||
self.context = context.RequestContext('fake', 'fake')
|
||||
self.instance = fake_instance.fake_db_instance(
|
||||
vm_state=vm_states.ACTIVE)
|
||||
self.admin_pass = 'pass'
|
||||
self.injected_files = []
|
||||
self.image = {}
|
||||
|
||||
def test_build_and_run_instance_called_with_proper_args(self):
|
||||
self.mox.StubOutWithMock(self.compute, '_build_and_run_instance')
|
||||
self.compute._build_and_run_instance(self.context, self.instance,
|
||||
self.image, self.injected_files, self.admin_pass)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.compute.build_and_run_instance(self.context, self.instance,
|
||||
self.image, request_spec={}, filter_properties=[],
|
||||
injected_files=self.injected_files,
|
||||
admin_password=self.admin_pass)
|
||||
|
||||
def test_build_abort_exception(self):
|
||||
self.mox.StubOutWithMock(self.compute, '_build_and_run_instance')
|
||||
self.mox.StubOutWithMock(self.compute, '_set_instance_error_state')
|
||||
self.mox.StubOutWithMock(self.compute.compute_task_api,
|
||||
'build_instances')
|
||||
self.compute._build_and_run_instance(self.context, self.instance,
|
||||
self.image, self.injected_files, self.admin_pass).AndRaise(
|
||||
exception.BuildAbortException(reason='',
|
||||
instance_uuid=self.instance['uuid']))
|
||||
self.compute._set_instance_error_state(self.context,
|
||||
self.instance['uuid'])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.compute.build_and_run_instance(self.context, self.instance,
|
||||
self.image, request_spec={}, filter_properties=[],
|
||||
injected_files=self.injected_files,
|
||||
admin_password=self.admin_pass)
|
||||
|
||||
def test_rescheduled_exception(self):
|
||||
self.mox.StubOutWithMock(self.compute, '_build_and_run_instance')
|
||||
self.mox.StubOutWithMock(self.compute, '_set_instance_error_state')
|
||||
self.mox.StubOutWithMock(self.compute.compute_task_api,
|
||||
'build_instances')
|
||||
self.compute._build_and_run_instance(self.context, self.instance,
|
||||
self.image, self.injected_files, self.admin_pass).AndRaise(
|
||||
exception.RescheduledException(reason='',
|
||||
instance_uuid=self.instance['uuid']))
|
||||
self.compute.compute_task_api.build_instances(self.context,
|
||||
[self.instance], self.image, [], self.admin_pass,
|
||||
self.injected_files, None, None, None)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.compute.build_and_run_instance(self.context, self.instance,
|
||||
self.image, request_spec={}, filter_properties=[],
|
||||
injected_files=self.injected_files,
|
||||
admin_password=self.admin_pass)
|
||||
|
||||
def test_instance_not_found(self):
|
||||
self.mox.StubOutWithMock(self.compute.driver, 'spawn')
|
||||
self.compute.driver.spawn(self.context, self.instance, self.image,
|
||||
self.injected_files, self.admin_pass).AndRaise(
|
||||
exception.InstanceNotFound(instance_id=1))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.assertRaises(exception.BuildAbortException,
|
||||
self.compute._build_and_run_instance, self.context,
|
||||
self.instance, self.image, self.injected_files,
|
||||
self.admin_pass)
|
||||
|
||||
def test_reschedule_on_exception(self):
|
||||
self.mox.StubOutWithMock(self.compute.driver, 'spawn')
|
||||
self.compute.driver.spawn(self.context, self.instance, self.image,
|
||||
self.injected_files, self.admin_pass).AndRaise(
|
||||
test.TestingException())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.assertRaises(exception.RescheduledException,
|
||||
self.compute._build_and_run_instance, self.context,
|
||||
self.instance, self.image, self.injected_files,
|
||||
self.admin_pass)
|
||||
|
||||
def test_unexpected_task_state(self):
|
||||
self.mox.StubOutWithMock(self.compute.driver, 'spawn')
|
||||
self.compute.driver.spawn(self.context, self.instance, self.image,
|
||||
self.injected_files, self.admin_pass).AndRaise(
|
||||
exception.UnexpectedTaskStateError(expected=None,
|
||||
actual='deleting'))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.assertRaises(exception.BuildAbortException,
|
||||
self.compute._build_and_run_instance, self.context,
|
||||
self.instance, self.image, self.injected_files,
|
||||
self.admin_pass)
|
||||
|
||||
Reference in New Issue
Block a user