summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorJohannes Erdfelt <johannes.erdfelt@rackspace.com>2011-12-13 23:34:18 +0000
committerJohannes Erdfelt <johannes.erdfelt@rackspace.com>2011-12-13 23:39:27 +0000
commit0514bc9d5e92ed0eb6671349e8ff37d7f58aab85 (patch)
tree289e3ff7cacf950ab24e072b35381bd8e8f08e6e /nova
parent67490c6b50174a89bce6719dd1b89fee8faa8ab2 (diff)
Refactor vm_state and task_state checking
This branch refactors the recently merged code for checking vm_state and task_state. The list of allowed states is merged to the method being checked, more methods are being checked and cleans up the general usage of them to be easier to read. Change-Id: If6130dbab947f7bd037e37af9827b6a7c9a193d4
Diffstat (limited to 'nova')
-rw-r--r--nova/compute/api.py156
-rw-r--r--nova/compute/state_checker.py137
-rw-r--r--nova/compute/task_states.py11
-rw-r--r--nova/compute/vm_states.py6
-rw-r--r--nova/exception.py2
-rw-r--r--nova/tests/api/ec2/test_cloud.py3
-rw-r--r--nova/tests/api/openstack/v2/test_servers.py8
-rw-r--r--nova/tests/integrated/test_servers.py16
-rw-r--r--nova/tests/test_compute.py115
9 files changed, 106 insertions, 348 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 806897bf4..385d3d682 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -19,6 +19,7 @@
"""Handles all requests relating to instances (guest vms)."""
+import functools
import novaclient
import re
import time
@@ -35,7 +36,6 @@ from nova import utils
from nova import volume
from nova.compute import instance_types
from nova.compute import power_state
-from nova.compute import state_checker
from nova.compute import task_states
from nova.compute import vm_states
from nova.scheduler import api as scheduler_api
@@ -50,42 +50,40 @@ flags.DECLARE('enable_zone_routing', 'nova.scheduler.api')
flags.DECLARE('vncproxy_topic', 'nova.vnc')
flags.DEFINE_integer('find_host_timeout', 30,
'Timeout after NN seconds when looking for a host.')
-flags.DEFINE_boolean('api_check_vm_states', True,
- 'Filter calls by vm state')
-def _is_queued_delete(instance):
- vm_state = instance["vm_state"]
- instance_uuid = instance["uuid"]
-
- if vm_state != vm_states.SOFT_DELETE:
- LOG.warn(_("Instance %(instance_uuid)s is not in a 'soft delete' "
- "state. It is currently %(vm_state)s. Action aborted.") %
- locals())
- return False
-
- return True
-
-
-class check_vm_state(object):
- """Class to wrap API functions that are sensitive to the VM state.
+def check_instance_state(vm_state=None, task_state=None):
+ """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.
- It uses state_checker to decide if the call is allowed or not.
"""
- def __init__(self, method_name):
- self.method_name = method_name
-
- def __call__(self, f):
- def _state_checker_wrap(api, context, instance, *args, **kw):
- if FLAGS.api_check_vm_states and \
- state_checker.is_blocked(self.method_name, context, instance):
- raise exception.InstanceInvalidState(\
- instance_uuid=instance['uuid'], method=self.method_name)
- else:
- return f(api, context, instance, *args, **kw)
- return _state_checker_wrap
+ if vm_state is not None and not isinstance(vm_state, set):
+ vm_state = set(vm_state)
+ if task_state is not None and not isinstance(task_state, set):
+ task_state = set(task_state)
+
+ def outer(f):
+ @functools.wraps(f)
+ def inner(self, context, instance, *args, **kw):
+ if vm_state is not None and \
+ instance['vm_state'] not in vm_state:
+ raise exception.InstanceInvalidState(
+ attr='vm_state',
+ instance_uuid=instance['uuid'],
+ state=instance['vm_state'],
+ method=f.__name__)
+ if task_state is not None and \
+ instance['task_state'] not in task_state:
+ raise exception.InstanceInvalidState(
+ attr='task_state',
+ instance_uuid=instance['uuid'],
+ state=instance['task_state'],
+ method=f.__name__)
+
+ return f(self, context, instance, *args, **kw)
+ return inner
+ return outer
class API(base.Base):
@@ -771,8 +769,8 @@ class API(base.Base):
rv = self.db.instance_update(context, instance["id"], kwargs)
return dict(rv.iteritems())
- @check_vm_state(state_checker.SOFT_DELETE)
- @scheduler_api.reroute_compute(state_checker.SOFT_DELETE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.ERROR])
+ @scheduler_api.reroute_compute("soft_delete")
def soft_delete(self, context, instance):
"""Terminate an instance."""
instance_uuid = instance["uuid"]
@@ -809,21 +807,22 @@ class API(base.Base):
else:
self.db.instance_destroy(context, instance['id'])
- @check_vm_state(state_checker.DELETE)
- @scheduler_api.reroute_compute(state_checker.DELETE)
+ # NOTE(jerdfelt): The API implies that only ACTIVE and ERROR are
+ # allowed but the EC2 API appears to allow from RESCUED and STOPPED
+ # too
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.ERROR,
+ vm_states.RESCUED, vm_states.STOPPED])
+ @scheduler_api.reroute_compute("delete")
def delete(self, context, instance):
"""Terminate an instance."""
LOG.debug(_("Going to try to terminate %s"), instance["uuid"])
self._delete(context, instance)
- @check_vm_state(state_checker.RESTORE)
- @scheduler_api.reroute_compute(state_checker.RESTORE)
+ @check_instance_state(vm_state=[vm_states.SOFT_DELETE])
+ @scheduler_api.reroute_compute("restore")
def restore(self, context, instance):
"""Restore a previously deleted (but not reclaimed) instance."""
- if not _is_queued_delete(instance):
- return
-
self.update(context,
instance,
vm_state=vm_states.ACTIVE,
@@ -838,18 +837,15 @@ class API(base.Base):
self._cast_compute_message('power_on_instance', context,
instance['uuid'], host)
- @check_vm_state(state_checker.FORCE_DELETE)
- @scheduler_api.reroute_compute(state_checker.FORCE_DELETE)
+ @check_instance_state(vm_state=[vm_states.SOFT_DELETE])
+ @scheduler_api.reroute_compute("force_delete")
def force_delete(self, context, instance):
"""Force delete a previously deleted (but not reclaimed) instance."""
-
- if not _is_queued_delete(instance):
- return
-
self._delete(context, instance)
- @check_vm_state(state_checker.STOP)
- @scheduler_api.reroute_compute(state_checker.STOP)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("stop")
def stop(self, context, instance):
"""Stop an instance."""
instance_uuid = instance["uuid"]
@@ -867,7 +863,7 @@ class API(base.Base):
self._cast_compute_message('stop_instance', context,
instance_uuid, host)
- @check_vm_state(state_checker.START)
+ @check_instance_state(vm_state=[vm_states.STOPPED])
def start(self, context, instance):
"""Start an instance."""
vm_state = instance["vm_state"]
@@ -1079,8 +1075,9 @@ class API(base.Base):
raise exception.Error(_("Unable to find host for Instance %s")
% instance_uuid)
- @check_vm_state(state_checker.BACKUP)
- @scheduler_api.reroute_compute(state_checker.BACKUP)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("backup")
def backup(self, context, instance, name, backup_type, rotation,
extra_properties=None):
"""Backup the given instance
@@ -1097,8 +1094,9 @@ class API(base.Base):
extra_properties=extra_properties)
return recv_meta
- @check_vm_state(state_checker.SNAPSHOT)
- @scheduler_api.reroute_compute(state_checker.SNAPSHOT)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("snapshot")
def snapshot(self, context, instance, name, extra_properties=None):
"""Snapshot the given instance.
@@ -1147,8 +1145,9 @@ class API(base.Base):
params=params)
return recv_meta
- @check_vm_state(state_checker.REBOOT)
- @scheduler_api.reroute_compute(state_checker.REBOOT)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("reboot")
def reboot(self, context, instance, reboot_type):
"""Reboot the given instance."""
state = {'SOFT': task_states.REBOOTING,
@@ -1162,8 +1161,9 @@ class API(base.Base):
instance['uuid'],
params={'reboot_type': reboot_type})
- @check_vm_state(state_checker.REBUILD)
- @scheduler_api.reroute_compute(state_checker.REBUILD)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("rebuild")
def rebuild(self, context, instance, image_href, admin_password,
name=None, metadata=None, files_to_inject=None):
"""Rebuild the given instance with the provided metadata."""
@@ -1194,8 +1194,9 @@ class API(base.Base):
instance["uuid"],
params=rebuild_params)
- @check_vm_state(state_checker.REVERT_RESIZE)
- @scheduler_api.reroute_compute(state_checker.REVERT_RESIZE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("revert_resize")
def revert_resize(self, context, instance):
"""Reverts a resize, deleting the 'new' instance in the process."""
context = context.elevated()
@@ -1219,8 +1220,9 @@ class API(base.Base):
self.db.migration_update(context, migration_ref['id'],
{'status': 'reverted'})
- @check_vm_state(state_checker.CONFIRM_RESIZE)
- @scheduler_api.reroute_compute(state_checker.CONFIRM_RESIZE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("confirm_resize")
def confirm_resize(self, context, instance):
"""Confirms a migration/resize and deletes the 'old' instance."""
context = context.elevated()
@@ -1246,8 +1248,9 @@ class API(base.Base):
self.db.instance_update(context, instance['uuid'],
{'host': migration_ref['dest_compute'], })
- @check_vm_state(state_checker.RESIZE)
- @scheduler_api.reroute_compute(state_checker.RESIZE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE],
+ task_state=[None])
+ @scheduler_api.reroute_compute("resize")
def resize(self, context, instance, flavor_id=None):
"""Resize (ie, migrate) a running instance.
@@ -1328,8 +1331,9 @@ class API(base.Base):
# didn't raise so this is the correct zone
self.network_api.add_network_to_project(context, project_id)
- @check_vm_state(state_checker.PAUSE)
- @scheduler_api.reroute_compute(state_checker.PAUSE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("pause")
def pause(self, context, instance):
"""Pause the given instance."""
instance_uuid = instance["uuid"]
@@ -1339,8 +1343,8 @@ class API(base.Base):
task_state=task_states.PAUSING)
self._cast_compute_message('pause_instance', context, instance_uuid)
- @check_vm_state(state_checker.UNPAUSE)
- @scheduler_api.reroute_compute(state_checker.UNPAUSE)
+ @check_instance_state(vm_state=[vm_states.PAUSED])
+ @scheduler_api.reroute_compute("unpause")
def unpause(self, context, instance):
"""Unpause the given instance."""
instance_uuid = instance["uuid"]
@@ -1377,8 +1381,9 @@ class API(base.Base):
"""Retrieve actions for the given instance."""
return self.db.instance_get_actions(context, instance['uuid'])
- @check_vm_state(state_checker.SUSPEND)
- @scheduler_api.reroute_compute(state_checker.SUSPEND)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("suspend")
def suspend(self, context, instance):
"""Suspend the given instance."""
instance_uuid = instance["uuid"]
@@ -1388,8 +1393,8 @@ class API(base.Base):
task_state=task_states.SUSPENDING)
self._cast_compute_message('suspend_instance', context, instance_uuid)
- @check_vm_state(state_checker.RESUME)
- @scheduler_api.reroute_compute(state_checker.RESUME)
+ @check_instance_state(vm_state=[vm_states.SUSPENDED])
+ @scheduler_api.reroute_compute("resume")
def resume(self, context, instance):
"""Resume the given instance."""
instance_uuid = instance["uuid"]
@@ -1399,8 +1404,9 @@ class API(base.Base):
task_state=task_states.RESUMING)
self._cast_compute_message('resume_instance', context, instance_uuid)
- @check_vm_state(state_checker.RESCUE)
- @scheduler_api.reroute_compute(state_checker.RESCUE)
+ @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
+ task_state=[None, task_states.RESIZE_VERIFY])
+ @scheduler_api.reroute_compute("rescue")
def rescue(self, context, instance, rescue_password=None):
"""Rescue the given instance."""
self.update(context,
@@ -1415,8 +1421,8 @@ class API(base.Base):
instance['uuid'],
params=rescue_params)
- @check_vm_state(state_checker.UNRESCUE)
- @scheduler_api.reroute_compute(state_checker.UNRESCUE)
+ @check_instance_state(vm_state=[vm_states.RESCUED])
+ @scheduler_api.reroute_compute("unrescue")
def unrescue(self, context, instance):
"""Unrescue the given instance."""
self.update(context,
diff --git a/nova/compute/state_checker.py b/nova/compute/state_checker.py
deleted file mode 100644
index 9dcdebe8c..000000000
--- a/nova/compute/state_checker.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2011 Justin Santa Barbara
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from nova import db
-from nova.compute import task_states as ts
-from nova.compute import vm_states as vm
-from nova import context as ctxt
-
-# Function names that run the state check before their execution:
-REBOOT = 'reboot'
-START = 'start'
-REBUILD = 'rebuild'
-STOP = 'stop'
-PAUSE = 'pause'
-BACKUP = 'backup'
-UNPAUSE = 'unpause'
-SUSPEND = 'suspend'
-RESUME = 'resume'
-RESCUE = 'rescue'
-UNRESCUE = 'unrescue'
-SNAPSHOT = 'snapshot'
-RESIZE = 'resize'
-CONFIRM_RESIZE = 'confirm_resize'
-REVERT_RESIZE = 'revert_resize'
-DELETE = 'delete'
-SOFT_DELETE = 'soft_delete'
-FORCE_DELETE = 'force_delete'
-RESTORE = 'restore'
-
-
-# Aux variables to save cpu time, used by blocker dictionaries
-all_ts_but_resize_verify = list(set(ts.get_list()) - set([ts.RESIZE_VERIFY]))
-all_vm_but_act_resc = list(set(vm.get_list()) - set([vm.ACTIVE, vm.RESCUED]))
-all_vm_but_active = list(set(vm.get_list()) - set([vm.ACTIVE]))
-
-# Call blocked if the vm task_state is found in the corresponding list
-block_for_task_state = {
- REBOOT: all_ts_but_resize_verify,
- START: all_ts_but_resize_verify,
- REBUILD: all_ts_but_resize_verify,
- PAUSE: all_ts_but_resize_verify,
- STOP: all_ts_but_resize_verify,
- UNPAUSE: all_ts_but_resize_verify,
- SUSPEND: all_ts_but_resize_verify,
- RESUME: all_ts_but_resize_verify,
- RESCUE: all_ts_but_resize_verify,
- UNRESCUE: all_ts_but_resize_verify,
- SNAPSHOT: all_ts_but_resize_verify,
- BACKUP: all_ts_but_resize_verify,
- RESIZE: all_ts_but_resize_verify,
- CONFIRM_RESIZE: all_ts_but_resize_verify,
- REVERT_RESIZE: all_ts_but_resize_verify}
-
-# Call blocked if the vm vm_state is found in the corresponding list
-block_for_vm_state = {
- REBOOT: all_vm_but_act_resc,
- START: list(set(vm.get_list()) - set([vm.STOPPED])),
- REBUILD: all_vm_but_active,
- PAUSE: all_vm_but_act_resc,
- STOP: all_vm_but_act_resc,
- UNPAUSE: list(set(vm.get_list()) - set([vm.PAUSED])),
- SUSPEND: all_vm_but_act_resc,
- RESUME: list(set(vm.get_list()) - set([vm.SUSPENDED])),
- RESCUE: list(set(vm.get_list()) - set([vm.ACTIVE, vm.STOPPED])),
- UNRESCUE: list(set(vm.get_list()) - set([vm.ACTIVE, vm.RESCUED])),
- SNAPSHOT: all_vm_but_active,
- BACKUP: all_vm_but_active,
- RESIZE: all_vm_but_active,
- CONFIRM_RESIZE: all_vm_but_active,
- REVERT_RESIZE: all_vm_but_active}
-
-# Call blocked if the combination of vm_state, power_state and task_state is
-# found in the corresponding list
-block_for_combination = {
- CONFIRM_RESIZE: [{'vm_state': vm.ACTIVE, 'task_state': None}],
- REVERT_RESIZE: [{'vm_state': vm.ACTIVE, 'task_state': None}]}
-
-
-def is_blocked(method_name, context, instance_ref):
- """
- Is the method blocked for the VM state?
-
- This method returns False if the state of the vm is found
- in the blocked dictionaries for the method.
- """
- if instance_ref['task_state'] in block_for_task_state.get(method_name, ()):
- return True
- if instance_ref['vm_state'] in block_for_vm_state.get(method_name, ()):
- return True
- if method_name in block_for_combination:
- return _is_combination_blocked(method_name, instance_ref)
- # Allow the method if not found in any list
- return False
-
-
-def _is_combination_blocked(method_name, instance_ref):
- """
- Is the method blocked according to the blocked_combination dictionary?
-
- To be blocked, all the elements
- in a dictionary need to match the vm states.
- If a value is not present in a dictionary we assume that the dictionary
- applies for any value of that particular element
- """
- for blocked_element in block_for_combination[method_name]:
- # Check power state
- if 'power_state' in blocked_element and instance_ref['power_state']\
- != blocked_element['power_state']:
- continue
- # Check vm state
- if 'vm_state' in blocked_element and instance_ref['vm_state']\
- != blocked_element['vm_state']:
- continue
- # Check task state
- if 'task_state' in blocked_element and instance_ref['task_state']\
- != blocked_element['task_state']:
- continue
- return True
- # After analyzing all the dictionaries for the method, none tells us to
- # block the function
- return False
diff --git a/nova/compute/task_states.py b/nova/compute/task_states.py
index 3765fc79c..c6016b509 100644
--- a/nova/compute/task_states.py
+++ b/nova/compute/task_states.py
@@ -60,14 +60,3 @@ UNRESCUING = 'unrescuing'
DELETING = 'deleting'
STOPPING = 'stopping'
STARTING = 'starting'
-
-
-def get_list():
- """Returns a list of all the possible task_states"""
- return [SCHEDULING, BLOCK_DEVICE_MAPPING, NETWORKING, SPAWNING,
- IMAGE_SNAPSHOT, IMAGE_BACKUP, UPDATING_PASSWORD, RESIZE_PREP,
- RESIZE_MIGRATING, RESIZE_MIGRATED, RESIZE_FINISH, RESIZE_REVERTING,
- RESIZE_CONFIRMING, RESIZE_VERIFY, REBUILDING, REBOOTING,
- REBOOTING_HARD, PAUSING, UNPAUSING, SUSPENDING, RESUMING,
- POWERING_OFF, POWERING_ON, RESCUING, UNRESCUING, DELETING,
- STOPPING, STARTING]
diff --git a/nova/compute/vm_states.py b/nova/compute/vm_states.py
index 4d3d524c5..f219bf7f4 100644
--- a/nova/compute/vm_states.py
+++ b/nova/compute/vm_states.py
@@ -38,9 +38,3 @@ MIGRATING = 'migrating'
RESIZING = 'resizing'
ERROR = 'error'
-
-
-def get_list():
- """Returns a list of all the possible vm_states"""
- return [ACTIVE, BUILDING, REBUILDING, PAUSED, SUSPENDED, RESCUED,
- DELETED, STOPPED, SOFT_DELETE, MIGRATING, RESIZING, ERROR]
diff --git a/nova/exception.py b/nova/exception.py
index d0ccfb627..345b313f7 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -251,7 +251,7 @@ class InvalidParameterValue(Invalid):
class InstanceInvalidState(Invalid):
- message = _("Instance %(instance_uuid)s in state %(state)s. Cannot "
+ message = _("Instance %(instance_uuid)s in %(attr)s %(state)s. Cannot "
"%(method)s while the instance is in this state.")
diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
index 039282147..b44bd2322 100644
--- a/nova/tests/api/ec2/test_cloud.py
+++ b/nova/tests/api/ec2/test_cloud.py
@@ -1401,6 +1401,9 @@ class CloudTestCase(test.TestCase):
'max_count': 1, }
instance_id = self._run_instance(**kwargs)
+ result = self.cloud.rescue_instance(self.context, instance_id)
+ self.assertTrue(result)
+
result = self.cloud.unrescue_instance(self.context, instance_id)
self.assertTrue(result)
diff --git a/nova/tests/api/openstack/v2/test_servers.py b/nova/tests/api/openstack/v2/test_servers.py
index 258928eae..243438ca5 100644
--- a/nova/tests/api/openstack/v2/test_servers.py
+++ b/nova/tests/api/openstack/v2/test_servers.py
@@ -1225,11 +1225,13 @@ class ServersControllerTest(test.TestCase):
self.server_delete_called = False
+ new_return_server = return_server_with_attributes(
+ vm_state=vm_states.ACTIVE)
+ self.stubs.Set(nova.db, 'instance_get', new_return_server)
+
def instance_destroy_mock(context, id):
self.server_delete_called = True
-
- self.stubs.Set(nova.db, 'instance_destroy',
- instance_destroy_mock)
+ self.stubs.Set(nova.db, 'instance_destroy', instance_destroy_mock)
self.controller.delete(req, FAKE_UUID)
diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py
index 58aca5778..556b74abe 100644
--- a/nova/tests/integrated/test_servers.py
+++ b/nova/tests/integrated/test_servers.py
@@ -162,18 +162,14 @@ class ServersTest(integrated_helpers._IntegratedTestBase):
self.assertEqual('ACTIVE', found_server['status'])
# Cannot restore unless instance is deleted
- self.api.post_server_action(created_server_id, {'restore': {}})
-
- # Check it's still active
- found_server = self.api.get_server(created_server_id)
- self.assertEqual('ACTIVE', found_server['status'])
+ self.assertRaises(client.OpenStackApiException,
+ self.api.post_server_action, created_server_id,
+ {'restore': {}})
# Cannot forceDelete unless instance is deleted
- self.api.post_server_action(created_server_id, {'forceDelete': {}})
-
- # Check it's still active
- found_server = self.api.get_server(created_server_id)
- self.assertEqual('ACTIVE', found_server['status'])
+ self.assertRaises(client.OpenStackApiException,
+ self.api.post_server_action, created_server_id,
+ {'forceDelete': {}})
# Delete the server
self.api.delete_server(created_server_id)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 1e5cc8ee9..0527ff456 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -29,7 +29,6 @@ from nova import compute
from nova.compute import instance_types
from nova.compute import manager as compute_manager
from nova.compute import power_state
-from nova.compute import state_checker
from nova.compute import task_states
from nova.compute import vm_states
from nova import context
@@ -135,6 +134,7 @@ class BaseTestCase(test.TestCase):
params = {}
inst = {}
+ inst['vm_state'] = vm_states.ACTIVE
inst['image_ref'] = 1
inst['reservation_id'] = 'r-fakeres'
inst['launch_time'] = '10'
@@ -1243,108 +1243,6 @@ class ComputeAPITestCase(BaseTestCase):
'properties': {'kernel_id': 1, 'ramdisk_id': 1},
}
- def test_check_vm_state_filtered_function(self):
- """Test the check_vm_state mechanism for filtered functions.
-
- Checks that the filtered_function is correctly filtered
- in the right states only for the api_check_vm_states flag set to True.
-
- Note that the filtered_function takes the same number of arguments
- than the real functions that are decorated in the compute api.
- """
- @compute.api.check_vm_state('filtered_function')
- def filtered_function(api, context, instance_ref):
- LOG.debug("filtered_function executed")
- return True
-
- def filtered_assume_right_state(instance_ref):
- self.flags(api_check_vm_states=True)
- self.assertTrue(filtered_function(self.compute_api,
- self.context, instance_ref))
-
- def filtered_assume_wrong_state(instance_ref):
- self.flags(api_check_vm_states=True)
- self.assertRaises(exception.InstanceInvalidState,
- filtered_function, self.compute_api,
- self.context, instance_ref)
- self.flags(api_check_vm_states=False)
- self.assertTrue(filtered_function(self.compute_api,
- self.context, instance_ref))
-
- # check that the filtered_function is correctly filtered
- self._execute_allowed_and_blocked('filtered_function',
- filtered_assume_right_state,
- filtered_assume_wrong_state)
-
- def test_check_vm_state_non_filtered_function(self):
- """Test the check_vm_state mechanism for non filtered functions.
-
- Checks that if a function that is decorated with the check_vm_state
- but it is not defined in any blocked dictionary, it will always
- be executed
- """
- @compute.api.check_vm_state('non_filtered_function')
- def non_filtered_function(api, context, instance_ref):
- LOG.debug("non_filtered_function executed")
- return True
-
- def non_filtered_assume_executed(instance_ref):
- self.flags(api_check_vm_states=True)
- self.assertTrue(non_filtered_function(self.compute_api,
- self.context, instance_ref))
-
- # check that the non_filtered_function is never filtered
- self._execute_allowed_and_blocked('non_filtered_function',
- non_filtered_assume_executed,
- non_filtered_assume_executed)
-
- def _execute_allowed_and_blocked(self, func_name, f_allowed, f_blocked):
- """Execute f_allowed and f_blocked functions for all the scenarios.
-
- Get an allowed vm_state, a blocked vm_state, an allowed task_state,
- and a blocked task_state for the function defined by func_name to be
- executed. Then it executes the function f_allowed or f_blocked
- accordingly, passing as parameter a new instance id. Theses functions
- have to run the func_name function and assert the expected result
- """
-
- # define blocked and allowed states
- blocked_tsk = task_states.SCHEDULING
- ok_task = task_states.NETWORKING
- blocked_vm = vm_states.BUILDING
- ok_vm = vm_states.RESCUED
- blocked_comb = {'power_state': power_state.RUNNING,
- 'vm_state': vm_states.ACTIVE, 'task_state': None}
- ok_comb = {'power_state': power_state.RUNNING,
- 'vm_state': vm_states.PAUSED, 'task_state': None}
-
- # To guarantee a 100% test coverage we create fake lists.
- fake_block_for_task_state = {'filtered_function': [blocked_tsk]}
-
- fake_block_for_vm_state = {'filtered_function': [blocked_vm]}
-
- fake_block_for_combination = {'filtered_function': [blocked_comb]}
-
- self.stubs.Set(nova.compute.state_checker, 'block_for_task_state',
- fake_block_for_task_state)
- self.stubs.Set(nova.compute.state_checker, 'block_for_vm_state',
- fake_block_for_vm_state)
- self.stubs.Set(nova.compute.state_checker, 'block_for_combination',
- fake_block_for_combination)
-
- i_ref = self._create_fake_instance(params={'task_state': blocked_tsk})
- f_blocked(i_ref)
- i_ref = self._create_fake_instance(params={'task_state': ok_task})
- f_allowed(i_ref)
- i_ref = self._create_fake_instance(params={'vm_state': blocked_vm})
- f_blocked(i_ref)
- i_ref = self._create_fake_instance(params={'vm_state': ok_vm})
- f_allowed(i_ref)
- i_ref = self._create_fake_instance(params=blocked_comb)
- f_blocked(i_ref)
- i_ref = self._create_fake_instance(params=ok_comb)
- f_allowed(i_ref)
-
def test_create_with_too_little_ram(self):
"""Test an instance type with too little memory"""
@@ -1646,6 +1544,10 @@ class ComputeAPITestCase(BaseTestCase):
self.assertEqual(instance['task_state'], None)
self.compute.pause_instance(self.context, instance_uuid)
+ # set the state that the instance gets when pause finishes
+ db.instance_update(self.context, instance['uuid'],
+ {'vm_state': vm_states.PAUSED})
+ instance = db.instance_get_by_uuid(self.context, instance['uuid'])
self.compute_api.unpause(self.context, instance)
@@ -1845,7 +1747,6 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance_uuid)
def test_resize_confirm_through_api(self):
- """Ensure invalid flavors raise"""
instance = self._create_fake_instance()
context = self.context.elevated()
self.compute.run_instance(self.context, instance['uuid'])
@@ -1866,7 +1767,6 @@ class ComputeAPITestCase(BaseTestCase):
self.compute.terminate_instance(context, instance['uuid'])
def test_resize_revert_through_api(self):
- """Ensure invalid flavors raise"""
instance = self._create_fake_instance()
context = self.context.elevated()
instance = db.instance_get_by_uuid(context, instance['uuid'])
@@ -1878,6 +1778,11 @@ class ComputeAPITestCase(BaseTestCase):
migration_ref = db.migration_create(context,
{'instance_uuid': instance['uuid'],
'status': 'finished'})
+ # set the state that the instance gets when resize finishes
+ db.instance_update(self.context, instance['uuid'],
+ {'task_state': task_states.RESIZE_VERIFY,
+ 'vm_state': vm_states.ACTIVE})
+ instance = db.instance_get_by_uuid(context, instance['uuid'])
self.compute_api.revert_resize(context, instance)
self.compute.terminate_instance(context, instance['uuid'])