summaryrefslogtreecommitdiffstats
path: root/nova/compute/api.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/compute/api.py')
-rw-r--r--nova/compute/api.py71
1 files changed, 42 insertions, 29 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 1e24e8ce5..48d404148 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -110,10 +110,12 @@ RO_SECURITY_GROUPS = ['default']
SM_IMAGE_PROP_PREFIX = "image_"
-def check_instance_state(vm_state=None, task_state=(None,)):
+def check_instance_state(vm_state=None, task_state=(None,),
+ must_have_launched=True):
"""Decorator to check VM and/or task state before entry to API functions.
- If the instance is in the wrong state, the wrapper will raise an exception.
+ If the instance is in the wrong state, or has not been sucessfully started
+ at least once the wrapper will raise an exception.
"""
if vm_state is not None and not isinstance(vm_state, set):
@@ -137,6 +139,13 @@ def check_instance_state(vm_state=None, task_state=(None,)):
instance_uuid=instance['uuid'],
state=instance['task_state'],
method=f.__name__)
+ if must_have_launched and not instance['launched_at']:
+ raise exception.InstanceInvalidState(
+ attr=None,
+ not_launched=True,
+ instance_uuid=instance['uuid'],
+ state=instance['vm_state'],
+ method=f.__name__)
return f(self, context, instance, *args, **kw)
return inner
@@ -487,21 +496,20 @@ class API(base.Base):
instance['uuid'], updates)
return instance
- def _check_config_drive(self, context, config_drive):
- try:
- bool_like = strutils.bool_from_string(config_drive, strict=True)
- except ValueError:
- bool_like = False
-
- if config_drive is None:
- return None, None
- elif bool_like:
- return None, bool_like
+ def _check_config_drive(self, config_drive):
+ if config_drive:
+ try:
+ bool_val = strutils.bool_from_string(config_drive,
+ strict=True)
+ except ValueError:
+ raise exception.ConfigDriveInvalidValue(option=config_drive)
else:
- cd_image_service, config_drive_id = \
- glance.get_remote_image_service(context, config_drive)
- cd_image_service.show(context, config_drive_id)
- return config_drive_id, None
+ bool_val = False
+ # FIXME(comstud): Bug ID 1193438 filed for this. This looks silly,
+ # but this is because the config drive column is a String. False
+ # is represented by using an empty string. And for whatever
+ # reason, we rely on the DB to cast True to a String.
+ return True if bool_val else ''
def _check_requested_image(self, context, image_id, image, instance_type):
if not image:
@@ -589,8 +597,7 @@ class API(base.Base):
kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(
context, kernel_id, ramdisk_id, image)
- config_drive_id, config_drive = self._check_config_drive(
- context, config_drive)
+ config_drive = self._check_config_drive(config_drive)
if key_data is None and key_name:
key_pair = self.db.key_pair_get(context, context.user_id,
@@ -610,8 +617,7 @@ class API(base.Base):
'ramdisk_id': ramdisk_id or '',
'power_state': power_state.NOSTATE,
'vm_state': vm_states.BUILDING,
- 'config_drive_id': config_drive_id or '',
- 'config_drive': config_drive or '',
+ 'config_drive': config_drive,
'user_id': context.user_id,
'project_id': context.project_id,
'instance_type_id': instance_type['id'],
@@ -1305,7 +1311,8 @@ class API(base.Base):
# NOTE(maoy): we allow delete to be called no matter what vm_state says.
@wrap_check_policy
@check_instance_lock
- @check_instance_state(vm_state=None, task_state=None)
+ @check_instance_state(vm_state=None, task_state=None,
+ must_have_launched=True)
def soft_delete(self, context, instance):
"""Terminate an instance."""
LOG.debug(_('Going to try to soft delete instance'),
@@ -1329,7 +1336,8 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
- @check_instance_state(vm_state=None, task_state=None)
+ @check_instance_state(vm_state=None, task_state=None,
+ must_have_launched=False)
def delete(self, context, instance):
"""Terminate an instance."""
LOG.debug(_("Going to try to terminate instance"), instance=instance)
@@ -1369,7 +1377,8 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
- @check_instance_state(vm_state=[vm_states.SOFT_DELETED])
+ @check_instance_state(vm_state=[vm_states.SOFT_DELETED],
+ must_have_launched=False)
def force_delete(self, context, instance):
"""Force delete a previously deleted (but not reclaimed) instance."""
self._delete_instance(context, instance)
@@ -1790,7 +1799,8 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
- vm_states.PAUSED, vm_states.SUSPENDED],
+ vm_states.PAUSED, vm_states.SUSPENDED,
+ vm_states.ERROR],
task_state=[None, task_states.REBOOTING,
task_states.REBOOTING_HARD,
task_states.RESUMING,
@@ -1826,7 +1836,8 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
- @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
+ vm_states.ERROR],
task_state=[None])
def rebuild(self, context, instance, image_href, admin_password, **kwargs):
"""Rebuild the given instance with the provided attributes."""
@@ -2224,7 +2235,8 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
- @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED])
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
+ vm_states.ERROR])
def rescue(self, context, instance, rescue_password=None):
"""Rescue the given instance."""
@@ -3201,7 +3213,8 @@ class SecurityGroupAPI(base.Base, security_group_base.SecurityGroupBase):
def trigger_rules_refresh(self, context, id):
"""Called when a rule is added to or removed from a security_group."""
- security_group = self.db.security_group_get(context, id)
+ security_group = self.db.security_group_get(
+ context, id, columns_to_join=['instances'])
for instance in security_group['instances']:
if instance['host'] is not None:
@@ -3227,8 +3240,8 @@ class SecurityGroupAPI(base.Base, security_group_base.SecurityGroupBase):
security_groups = set()
for rule in security_group_rules:
security_group = self.db.security_group_get(
- context,
- rule['parent_group_id'])
+ context, rule['parent_group_id'],
+ columns_to_join=['instances'])
security_groups.add(security_group)
# ..then we find the instances that are members of these groups..