summaryrefslogtreecommitdiffstats
path: root/nova/compute
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-04-26 22:25:52 +0000
committerGerrit Code Review <review@openstack.org>2013-04-26 22:25:52 +0000
commit7cb2163c2d3673abeaf0fa67032bfabb7bc75d0b (patch)
treeaea6f2783c421d9e445651ca71c66499b97bd9d1 /nova/compute
parent8eabf51af875d0b5d71b3a1bbec3054ebe270a7a (diff)
parent433e6885fd276aa2b78688745aec3ef50a06452a (diff)
downloadnova-7cb2163c2d3673abeaf0fa67032bfabb7bc75d0b.tar.gz
nova-7cb2163c2d3673abeaf0fa67032bfabb7bc75d0b.tar.xz
nova-7cb2163c2d3673abeaf0fa67032bfabb7bc75d0b.zip
Merge "Refactor _run_instance() to unify control flow"
Diffstat (limited to 'nova/compute')
-rwxr-xr-xnova/compute/manager.py205
1 files changed, 117 insertions, 88 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 16ea63f9f..e8f21e9ce 100755
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -836,6 +836,56 @@ class ComputeManager(manager.SchedulerDependentManager):
filter_properties, requested_networks, injected_files,
admin_password, is_first_time, node, instance):
"""Launch a new instance with specified options."""
+
+ extra_usage_info = {}
+
+ def notify(status, msg=None):
+ """Send a create.{start,end} notification."""
+ type_ = "create.%(status)s" % dict(status=status)
+ self._notify_about_instance_usage(context, instance, type_,
+ extra_usage_info=extra_usage_info)
+
+ try:
+ image_meta = self._prebuild_instance(context, instance)
+ if image_meta:
+ extra_usage_info = {"image_name": image_meta['name']}
+
+ notify("start") # notify that build is starting
+
+ instance = self._build_instance(context, request_spec,
+ filter_properties, requested_networks, injected_files,
+ admin_password, is_first_time, node, instance, image_meta)
+ notify("end") # notify that build is done
+
+ except exception.RescheduledException as e:
+ # Instance build encountered an error, and has been rescheduled.
+ pass
+
+ except exception.BuildAbortException as e:
+ # Instance build aborted due to a non-failure
+ LOG.info(e)
+
+ except Exception as e:
+ # Instance build encountered a non-recoverable error:
+ with excutils.save_and_reraise_exception():
+ self._set_instance_error_state(context, instance['uuid'])
+
+ def _prebuild_instance(self, context, instance):
+ self._check_instance_exists(context, instance)
+
+ try:
+ self._start_building(context, instance)
+ except exception.InstanceNotFound:
+ msg = _("Instance disappeared before we could start it")
+ # Quickly bail out of here
+ raise exception.BuildAbortException(instance_uuid=instance['uuid'],
+ reason=msg)
+
+ return self._check_image_size(context, instance)
+
+ def _build_instance(self, context, request_spec, filter_properties,
+ requested_networks, injected_files, admin_password, is_first_time,
+ node, instance, image_meta):
context = context.elevated()
# If quantum security groups pass requested security
@@ -845,97 +895,81 @@ class ComputeManager(manager.SchedulerDependentManager):
else:
security_groups = []
- try:
- self._check_instance_exists(context, instance)
-
- try:
- self._start_building(context, instance)
- except exception.InstanceNotFound:
- LOG.info(_("Instance disappeared before we could start it"),
- instance=instance)
- # Quickly bail out of here
- return
-
- image_meta = self._check_image_size(context, instance)
-
- if node is None:
- node = self.driver.get_available_nodes()[0]
- LOG.debug(_("No node specified, defaulting to %(node)s") %
- locals())
-
- if image_meta:
- extra_usage_info = {"image_name": image_meta['name']}
- else:
- extra_usage_info = {}
-
- self._notify_about_instance_usage(
- context, instance, "create.start",
- extra_usage_info=extra_usage_info)
+ if node is None:
+ node = self.driver.get_available_nodes()[0]
+ LOG.debug(_("No node specified, defaulting to %(node)s") %
+ locals())
- network_info = None
- bdms = self.conductor_api.block_device_mapping_get_all_by_instance(
- context, instance)
+ network_info = None
+ bdms = self.conductor_api.block_device_mapping_get_all_by_instance(
+ context, instance)
- # b64 decode the files to inject:
- injected_files_orig = injected_files
- injected_files = self._decode_files(injected_files)
+ # b64 decode the files to inject:
+ injected_files_orig = injected_files
+ injected_files = self._decode_files(injected_files)
- rt = self._get_resource_tracker(node)
- try:
- limits = filter_properties.get('limits', {})
- with rt.instance_claim(context, instance, limits):
- macs = self.driver.macs_for_instance(instance)
+ rt = self._get_resource_tracker(node)
+ try:
+ limits = filter_properties.get('limits', {})
+ with rt.instance_claim(context, instance, limits):
+ macs = self.driver.macs_for_instance(instance)
- network_info = self._allocate_network(context, instance,
- requested_networks, macs, security_groups)
+ network_info = self._allocate_network(context, instance,
+ requested_networks, macs, security_groups)
- self._instance_update(
- context, instance['uuid'],
- vm_state=vm_states.BUILDING,
- task_state=task_states.BLOCK_DEVICE_MAPPING)
+ self._instance_update(
+ context, instance['uuid'],
+ vm_state=vm_states.BUILDING,
+ task_state=task_states.BLOCK_DEVICE_MAPPING)
- block_device_info = self._prep_block_device(
- context, instance, bdms)
+ block_device_info = self._prep_block_device(
+ context, instance, bdms)
- set_access_ip = (is_first_time and
- not instance['access_ip_v4'] and
- not instance['access_ip_v6'])
+ set_access_ip = (is_first_time and
+ not instance['access_ip_v4'] and
+ not instance['access_ip_v6'])
- instance = self._spawn(context, instance, image_meta,
- network_info, block_device_info,
- injected_files, admin_password,
- set_access_ip=set_access_ip)
- except exception.InstanceNotFound:
- # the instance got deleted during the spawn
- with excutils.save_and_reraise_exception():
- try:
- self._deallocate_network(context, instance)
- except Exception:
- msg = _('Failed to dealloc network '
- 'for deleted instance')
- LOG.exception(msg, instance=instance)
- except exception.UnexpectedTaskStateError as e:
- actual_task_state = e.kwargs.get('actual', None)
- if actual_task_state == 'deleting':
- msg = _('Instance was deleted during spawn.')
- LOG.debug(msg, instance=instance)
- else:
- raise
- except Exception:
- exc_info = sys.exc_info()
- # try to re-schedule instance:
- self._reschedule_or_reraise(context, instance, exc_info,
- requested_networks, admin_password,
- injected_files_orig, is_first_time, request_spec,
- filter_properties, bdms)
+ instance = self._spawn(context, instance, image_meta,
+ network_info, block_device_info,
+ injected_files, admin_password,
+ set_access_ip=set_access_ip)
+ except exception.InstanceNotFound:
+ # the instance got deleted during the spawn
+ with excutils.save_and_reraise_exception():
+ try:
+ self._deallocate_network(context, instance)
+ except Exception:
+ msg = _('Failed to dealloc network '
+ 'for deleted instance')
+ LOG.exception(msg, instance=instance)
+ except exception.UnexpectedTaskStateError as e:
+ actual_task_state = e.kwargs.get('actual', None)
+ if actual_task_state == 'deleting':
+ msg = _('Instance was deleted during spawn.')
+ LOG.debug(msg, instance=instance)
+ raise exception.BuildAbortException(
+ instance_uuid=instance['uuid'], reason=msg)
else:
- # Spawn success:
- self._notify_about_instance_usage(context, instance,
- "create.end", network_info=network_info,
- extra_usage_info=extra_usage_info)
+ raise
except Exception:
- with excutils.save_and_reraise_exception():
- self._set_instance_error_state(context, instance['uuid'])
+ exc_info = sys.exc_info()
+ # try to re-schedule instance:
+ rescheduled = self._reschedule_or_error(context, instance,
+ exc_info, requested_networks, admin_password,
+ injected_files_orig, is_first_time, request_spec,
+ filter_properties, bdms)
+ if rescheduled:
+ # log the original build error
+ self._log_original_error(exc_info, instance['uuid'])
+ raise exception.RescheduledException(
+ instance_uuid=instance['uuid'],
+ reason=unicode(exc_info[1]))
+ else:
+ # not re-scheduling, go to error:
+ raise exc_info[0], exc_info[1], exc_info[2]
+
+ # spawn success
+ return instance
def _log_original_error(self, exc_info, instance_uuid):
type_, value, tb = exc_info
@@ -943,7 +977,7 @@ class ComputeManager(manager.SchedulerDependentManager):
traceback.format_exception(type_, value, tb),
instance_uuid=instance_uuid)
- def _reschedule_or_reraise(self, context, instance, exc_info,
+ def _reschedule_or_error(self, context, instance, exc_info,
requested_networks, admin_password, injected_files, is_first_time,
request_spec, filter_properties, bdms=None):
"""Try to re-schedule the build or re-raise the original build error to
@@ -984,12 +1018,7 @@ class ComputeManager(manager.SchedulerDependentManager):
LOG.exception(_("Error trying to reschedule"),
instance_uuid=instance_uuid)
- if rescheduled:
- # log the original build error
- self._log_original_error(exc_info, instance_uuid)
- else:
- # not re-scheduling
- raise exc_info[0], exc_info[1], exc_info[2]
+ return rescheduled
def _reschedule(self, context, request_spec, filter_properties,
instance_uuid, scheduler_method, method_args, task_state,