diff options
Diffstat (limited to 'nova/tests/api/openstack/compute/contrib/test_admin_actions.py')
-rw-r--r-- | nova/tests/api/openstack/compute/contrib/test_admin_actions.py | 734 |
1 files changed, 0 insertions, 734 deletions
diff --git a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py deleted file mode 100644 index d801abda64..0000000000 --- a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py +++ /dev/null @@ -1,734 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# -# 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 oslo.serialization import jsonutils -from oslo.utils import timeutils -import webob - -from nova.api.openstack import common -from nova.api.openstack.compute.contrib import admin_actions as \ - admin_actions_v2 -from nova.api.openstack.compute.plugins.v3 import admin_actions as \ - admin_actions_v21 -from nova.compute import vm_states -import nova.context -from nova import exception -from nova import objects -from nova.openstack.common import uuidutils -from nova import test -from nova.tests.api.openstack import fakes -from nova.tests import fake_instance - - -class CommonMixin(object): - admin_actions = None - fake_url = None - - def _make_request(self, url, body): - req = webob.Request.blank(self.fake_url + url) - req.method = 'POST' - req.body = jsonutils.dumps(body) - req.content_type = 'application/json' - return req.get_response(self.app) - - def _stub_instance_get(self, uuid=None): - if uuid is None: - uuid = uuidutils.generate_uuid() - instance = fake_instance.fake_db_instance( - id=1, uuid=uuid, vm_state=vm_states.ACTIVE, - task_state=None, launched_at=timeutils.utcnow()) - instance = objects.Instance._from_db_object( - self.context, objects.Instance(), instance) - self.compute_api.get(self.context, uuid, expected_attrs=None, - want_objects=True).AndReturn(instance) - return instance - - def _stub_instance_get_failure(self, exc_info, uuid=None): - if uuid is None: - uuid = uuidutils.generate_uuid() - self.compute_api.get(self.context, uuid, expected_attrs=None, - want_objects=True).AndRaise(exc_info) - return uuid - - def _test_non_existing_instance(self, action, body_map=None): - uuid = uuidutils.generate_uuid() - self._stub_instance_get_failure( - exception.InstanceNotFound(instance_id=uuid), uuid=uuid) - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % uuid, - {action: body_map.get(action)}) - self.assertEqual(404, res.status_int) - # Do these here instead of tearDown because this method is called - # more than once for the same test case - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def _test_action(self, action, body=None, method=None): - if method is None: - method = action - - instance = self._stub_instance_get() - getattr(self.compute_api, method)(self.context, instance) - - self.mox.ReplayAll() - res = self._make_request('/servers/%s/action' % instance['uuid'], - {action: None}) - self.assertEqual(202, res.status_int) - # Do these here instead of tearDown because this method is called - # more than once for the same test case - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def _test_invalid_state(self, action, method=None, body_map=None, - compute_api_args_map=None): - if method is None: - method = action - if body_map is None: - body_map = {} - if compute_api_args_map is None: - compute_api_args_map = {} - - instance = self._stub_instance_get() - - args, kwargs = compute_api_args_map.get(action, ((), {})) - - getattr(self.compute_api, method)(self.context, instance, - *args, **kwargs).AndRaise( - exception.InstanceInvalidState( - attr='vm_state', instance_uuid=instance['uuid'], - state='foo', method=method)) - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % instance['uuid'], - {action: body_map.get(action)}) - self.assertEqual(409, res.status_int) - self.assertIn("Cannot \'%(action)s\' instance %(id)s" - % {'id': instance['uuid'], 'action': action}, res.body) - # Do these here instead of tearDown because this method is called - # more than once for the same test case - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def _test_locked_instance(self, action, method=None, body_map=None, - compute_api_args_map=None): - if method is None: - method = action - - instance = self._stub_instance_get() - - args, kwargs = (), {} - act = None - - if compute_api_args_map: - args, kwargs = compute_api_args_map.get(action, ((), {})) - act = body_map.get(action) - - getattr(self.compute_api, method)(self.context, instance, - *args, **kwargs).AndRaise( - exception.InstanceIsLocked(instance_uuid=instance['uuid'])) - self.mox.ReplayAll() - res = self._make_request('/servers/%s/action' % instance['uuid'], - {action: act}) - self.assertEqual(409, res.status_int) - self.assertIn('Instance %s is locked' % instance['uuid'], res.body) - # Do these here instead of tearDown because this method is called - # more than once for the same test case - self.mox.VerifyAll() - self.mox.UnsetStubs() - - -class AdminActionsTestV21(CommonMixin, test.NoDBTestCase): - admin_actions = admin_actions_v21 - fake_url = '/v2/fake' - - def setUp(self): - super(AdminActionsTestV21, self).setUp() - self.controller = self.admin_actions.AdminActionsController() - self.compute_api = self.controller.compute_api - self.context = nova.context.RequestContext('fake', 'fake') - - def _fake_controller(*args, **kwargs): - return self.controller - - self.stubs.Set(self.admin_actions, 'AdminActionsController', - _fake_controller) - - self.app = self._get_app() - self.mox.StubOutWithMock(self.compute_api, 'get') - - def _get_app(self): - return fakes.wsgi_app_v21(init_only=('servers', - 'os-admin-actions'), - fake_auth_context=self.context) - - def test_actions(self): - actions = ['resetNetwork', 'injectNetworkInfo'] - method_translations = {'resetNetwork': 'reset_network', - 'injectNetworkInfo': 'inject_network_info'} - - for action in actions: - method = method_translations.get(action) - self.mox.StubOutWithMock(self.compute_api, method or action) - self._test_action(action, method=method) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def test_actions_with_non_existed_instance(self): - actions = ['resetNetwork', 'injectNetworkInfo', 'os-resetState'] - body_map = {'os-resetState': {'state': 'active'}} - - for action in actions: - self._test_non_existing_instance(action, - body_map=body_map) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def test_actions_with_locked_instance(self): - actions = ['resetNetwork', 'injectNetworkInfo'] - method_translations = {'resetNetwork': 'reset_network', - 'injectNetworkInfo': 'inject_network_info'} - - for action in actions: - method = method_translations.get(action) - self.mox.StubOutWithMock(self.compute_api, method or action) - self._test_locked_instance(action, method=method) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - -class AdminActionsTestV2(AdminActionsTestV21): - admin_actions = admin_actions_v2 - - def setUp(self): - super(AdminActionsTestV2, self).setUp() - self.flags( - osapi_compute_extension=[ - 'nova.api.openstack.compute.contrib.select_extensions'], - osapi_compute_ext_list=['Admin_actions']) - - def _get_app(self): - return fakes.wsgi_app(init_only=('servers',), - fake_auth_context=self.context) - - def test_actions(self): - actions = ['pause', 'unpause', 'suspend', 'resume', 'migrate', - 'resetNetwork', 'injectNetworkInfo', 'lock', - 'unlock'] - method_translations = {'migrate': 'resize', - 'resetNetwork': 'reset_network', - 'injectNetworkInfo': 'inject_network_info'} - - for action in actions: - method = method_translations.get(action) - self.mox.StubOutWithMock(self.compute_api, method or action) - self._test_action(action, method=method) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def test_actions_raise_conflict_on_invalid_state(self): - actions = ['pause', 'unpause', 'suspend', 'resume', 'migrate', - 'os-migrateLive'] - method_translations = {'migrate': 'resize', - 'os-migrateLive': 'live_migrate'} - body_map = {'os-migrateLive': - {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': False}} - args_map = {'os-migrateLive': ((False, False, 'hostname'), {})} - - for action in actions: - method = method_translations.get(action) - self.mox.StubOutWithMock(self.compute_api, method or action) - self._test_invalid_state(action, method=method, body_map=body_map, - compute_api_args_map=args_map) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def test_actions_with_non_existed_instance(self): - actions = ['pause', 'unpause', 'suspend', 'resume', - 'resetNetwork', 'injectNetworkInfo', 'lock', - 'unlock', 'os-resetState', 'migrate', 'os-migrateLive'] - body_map = {'os-resetState': {'state': 'active'}, - 'os-migrateLive': - {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': False}} - for action in actions: - self._test_non_existing_instance(action, - body_map=body_map) - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def test_actions_with_locked_instance(self): - actions = ['pause', 'unpause', 'suspend', 'resume', 'migrate', - 'resetNetwork', 'injectNetworkInfo', 'os-migrateLive'] - method_translations = {'migrate': 'resize', - 'resetNetwork': 'reset_network', - 'injectNetworkInfo': 'inject_network_info', - 'os-migrateLive': 'live_migrate'} - args_map = {'os-migrateLive': ((False, False, 'hostname'), {})} - body_map = {'os-migrateLive': {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': False}} - - for action in actions: - method = method_translations.get(action) - self.mox.StubOutWithMock(self.compute_api, method or action) - self._test_locked_instance(action, method=method, - body_map=body_map, - compute_api_args_map=args_map) - - # Re-mock this. - self.mox.StubOutWithMock(self.compute_api, 'get') - - def _test_migrate_exception(self, exc_info, expected_result): - self.mox.StubOutWithMock(self.compute_api, 'resize') - instance = self._stub_instance_get() - self.compute_api.resize(self.context, instance).AndRaise(exc_info) - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % instance['uuid'], - {'migrate': None}) - self.assertEqual(expected_result, res.status_int) - - def _test_migrate_live_succeeded(self, param): - self.mox.StubOutWithMock(self.compute_api, 'live_migrate') - instance = self._stub_instance_get() - self.compute_api.live_migrate(self.context, instance, False, - False, 'hostname') - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % instance['uuid'], - {'os-migrateLive': param}) - self.assertEqual(202, res.status_int) - - def test_migrate_live_enabled(self): - param = {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': False} - self._test_migrate_live_succeeded(param) - - def test_migrate_live_enabled_with_string_param(self): - param = {'host': 'hostname', - 'block_migration': "False", - 'disk_over_commit': "False"} - self._test_migrate_live_succeeded(param) - - def test_migrate_live_missing_dict_param(self): - body = {'os-migrateLive': {'dummy': 'hostname', - 'block_migration': False, - 'disk_over_commit': False}} - res = self._make_request('/servers/FAKE/action', body) - self.assertEqual(400, res.status_int) - - def test_migrate_live_with_invalid_block_migration(self): - body = {'os-migrateLive': {'host': 'hostname', - 'block_migration': "foo", - 'disk_over_commit': False}} - res = self._make_request('/servers/FAKE/action', body) - self.assertEqual(400, res.status_int) - - def test_migrate_live_with_invalid_disk_over_commit(self): - body = {'os-migrateLive': {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': "foo"}} - res = self._make_request('/servers/FAKE/action', body) - self.assertEqual(400, res.status_int) - - def _test_migrate_live_failed_with_exception(self, fake_exc, - uuid=None): - self.mox.StubOutWithMock(self.compute_api, 'live_migrate') - - instance = self._stub_instance_get(uuid=uuid) - self.compute_api.live_migrate(self.context, instance, False, - False, 'hostname').AndRaise(fake_exc) - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % instance.uuid, - {'os-migrateLive': - {'host': 'hostname', - 'block_migration': False, - 'disk_over_commit': False}}) - self.assertEqual(400, res.status_int) - self.assertIn(unicode(fake_exc), res.body) - - def test_migrate_live_compute_service_unavailable(self): - self._test_migrate_live_failed_with_exception( - exception.ComputeServiceUnavailable(host='host')) - - def test_migrate_live_invalid_hypervisor_type(self): - self._test_migrate_live_failed_with_exception( - exception.InvalidHypervisorType()) - - def test_migrate_live_invalid_cpu_info(self): - self._test_migrate_live_failed_with_exception( - exception.InvalidCPUInfo(reason="")) - - def test_migrate_live_unable_to_migrate_to_self(self): - uuid = uuidutils.generate_uuid() - self._test_migrate_live_failed_with_exception( - exception.UnableToMigrateToSelf(instance_id=uuid, - host='host'), - uuid=uuid) - - def test_migrate_live_destination_hypervisor_too_old(self): - self._test_migrate_live_failed_with_exception( - exception.DestinationHypervisorTooOld()) - - def test_migrate_live_no_valid_host(self): - self._test_migrate_live_failed_with_exception( - exception.NoValidHost(reason='')) - - def test_migrate_live_invalid_local_storage(self): - self._test_migrate_live_failed_with_exception( - exception.InvalidLocalStorage(path='', reason='')) - - def test_migrate_live_invalid_shared_storage(self): - self._test_migrate_live_failed_with_exception( - exception.InvalidSharedStorage(path='', reason='')) - - def test_migrate_live_hypervisor_unavailable(self): - self._test_migrate_live_failed_with_exception( - exception.HypervisorUnavailable(host="")) - - def test_migrate_live_instance_not_running(self): - self._test_migrate_live_failed_with_exception( - exception.InstanceNotRunning(instance_id="")) - - def test_migrate_live_migration_pre_check_error(self): - self._test_migrate_live_failed_with_exception( - exception.MigrationPreCheckError(reason='')) - - def test_unlock_not_authorized(self): - self.mox.StubOutWithMock(self.compute_api, 'unlock') - - instance = self._stub_instance_get() - - self.compute_api.unlock(self.context, instance).AndRaise( - exception.PolicyNotAuthorized(action='unlock')) - - self.mox.ReplayAll() - - res = self._make_request('/servers/%s/action' % instance['uuid'], - {'unlock': None}) - self.assertEqual(403, res.status_int) - - -class CreateBackupTestsV2(CommonMixin, test.NoDBTestCase): - fake_url = '/v2/fake' - - def setUp(self): - super(CreateBackupTestsV2, self).setUp() - self.controller = admin_actions_v2.AdminActionsController() - self.compute_api = self.controller.compute_api - self.context = nova.context.RequestContext('fake', 'fake') - - def _fake_controller(*args, **kwargs): - return self.controller - - self.stubs.Set(admin_actions_v2, 'AdminActionsController', - _fake_controller) - - self.flags( - osapi_compute_extension=[ - 'nova.api.openstack.compute.contrib.select_extensions'], - osapi_compute_ext_list=['Admin_actions']) - - self.app = fakes.wsgi_app(init_only=('servers',), - fake_auth_context=self.context) - self.mox.StubOutWithMock(self.compute_api, 'get') - self.mox.StubOutWithMock(common, - 'check_img_metadata_properties_quota') - self.mox.StubOutWithMock(self.compute_api, - 'backup') - - def _make_url(self, uuid): - return '/servers/%s/action' % uuid - - def test_create_backup_with_metadata(self): - metadata = {'123': 'asdf'} - body = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 1, - 'metadata': metadata, - }, - } - - image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1', - properties=metadata) - - common.check_img_metadata_properties_quota(self.context, metadata) - instance = self._stub_instance_get() - self.compute_api.backup(self.context, instance, 'Backup 1', - 'daily', 1, - extra_properties=metadata).AndReturn(image) - - self.mox.ReplayAll() - - res = self._make_request(self._make_url(instance['uuid']), body=body) - self.assertEqual(202, res.status_int) - self.assertIn('fake-image-id', res.headers['Location']) - - def test_create_backup_no_name(self): - # Name is required for backups. - body = { - 'createBackup': { - 'backup_type': 'daily', - 'rotation': 1, - }, - } - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - def test_create_backup_no_rotation(self): - # Rotation is required for backup requests. - body = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - }, - } - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - def test_create_backup_negative_rotation(self): - """Rotation must be greater than or equal to zero - for backup requests - """ - body = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': -1, - }, - } - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - def test_create_backup_no_backup_type(self): - # Backup Type (daily or weekly) is required for backup requests. - body = { - 'createBackup': { - 'name': 'Backup 1', - 'rotation': 1, - }, - } - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - def test_create_backup_bad_entity(self): - body = {'createBackup': 'go'} - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - def test_create_backup_rotation_is_zero(self): - # The happy path for creating backups if rotation is zero. - body = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 0, - }, - } - - image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1', - properties={}) - common.check_img_metadata_properties_quota(self.context, {}) - instance = self._stub_instance_get() - self.compute_api.backup(self.context, instance, 'Backup 1', - 'daily', 0, - extra_properties={}).AndReturn(image) - - self.mox.ReplayAll() - - res = self._make_request(self._make_url(instance['uuid']), body=body) - self.assertEqual(202, res.status_int) - self.assertNotIn('Location', res.headers) - - def test_create_backup_rotation_is_positive(self): - # The happy path for creating backups if rotation is positive. - body = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 1, - }, - } - - image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1', - properties={}) - common.check_img_metadata_properties_quota(self.context, {}) - instance = self._stub_instance_get() - self.compute_api.backup(self.context, instance, 'Backup 1', - 'daily', 1, - extra_properties={}).AndReturn(image) - - self.mox.ReplayAll() - - res = self._make_request(self._make_url(instance['uuid']), body=body) - self.assertEqual(202, res.status_int) - self.assertIn('fake-image-id', res.headers['Location']) - - def test_create_backup_raises_conflict_on_invalid_state(self): - body_map = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 1, - }, - } - args_map = { - 'createBackup': ( - ('Backup 1', 'daily', 1), {'extra_properties': {}} - ), - } - common.check_img_metadata_properties_quota(self.context, {}) - self._test_invalid_state('createBackup', method='backup', - body_map=body_map, - compute_api_args_map=args_map) - - def test_create_backup_with_non_existed_instance(self): - body_map = { - 'createBackup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 1, - }, - } - common.check_img_metadata_properties_quota(self.context, {}) - self._test_non_existing_instance('createBackup', - body_map=body_map) - - def test_create_backup_with_invalid_createBackup(self): - body = { - 'createBackupup': { - 'name': 'Backup 1', - 'backup_type': 'daily', - 'rotation': 1, - }, - } - res = self._make_request(self._make_url('fake'), body=body) - self.assertEqual(400, res.status_int) - - -class ResetStateTestsV21(test.NoDBTestCase): - admin_act = admin_actions_v21 - bad_request = exception.ValidationError - fake_url = '/servers' - - def setUp(self): - super(ResetStateTestsV21, self).setUp() - self.uuid = uuidutils.generate_uuid() - self.admin_api = self.admin_act.AdminActionsController() - self.compute_api = self.admin_api.compute_api - - url = '%s/%s/action' % (self.fake_url, self.uuid) - self.request = self._get_request(url) - self.context = self.request.environ['nova.context'] - - def _get_request(self, url): - return fakes.HTTPRequest.blank(url) - - def test_no_state(self): - self.assertRaises(self.bad_request, - self.admin_api._reset_state, - self.request, self.uuid, - body={"os-resetState": None}) - - def test_bad_state(self): - self.assertRaises(self.bad_request, - self.admin_api._reset_state, - self.request, self.uuid, - body={"os-resetState": {"state": "spam"}}) - - def test_no_instance(self): - self.mox.StubOutWithMock(self.compute_api, 'get') - exc = exception.InstanceNotFound(instance_id='inst_ud') - self.compute_api.get(self.context, self.uuid, expected_attrs=None, - want_objects=True).AndRaise(exc) - self.mox.ReplayAll() - - self.assertRaises(webob.exc.HTTPNotFound, - self.admin_api._reset_state, - self.request, self.uuid, - body={"os-resetState": {"state": "active"}}) - - def _setup_mock(self, expected): - instance = objects.Instance() - instance.uuid = self.uuid - instance.vm_state = 'fake' - instance.task_state = 'fake' - instance.obj_reset_changes() - - self.mox.StubOutWithMock(instance, 'save') - self.mox.StubOutWithMock(self.compute_api, 'get') - - def check_state(admin_state_reset=True): - self.assertEqual(set(expected.keys()), - instance.obj_what_changed()) - for k, v in expected.items(): - self.assertEqual(v, getattr(instance, k), - "Instance.%s doesn't match" % k) - instance.obj_reset_changes() - - self.compute_api.get(self.context, instance.uuid, expected_attrs=None, - want_objects=True).AndReturn(instance) - instance.save(admin_state_reset=True).WithSideEffects(check_state) - - def test_reset_active(self): - self._setup_mock(dict(vm_state=vm_states.ACTIVE, - task_state=None)) - self.mox.ReplayAll() - - body = {"os-resetState": {"state": "active"}} - result = self.admin_api._reset_state(self.request, self.uuid, - body=body) - # NOTE: on v2.1, http status code is set as wsgi_code of API - # method instead of status_int in a response object. - if isinstance(self.admin_api, - admin_actions_v21.AdminActionsController): - status_int = self.admin_api._reset_state.wsgi_code - else: - status_int = result.status_int - self.assertEqual(202, status_int) - - def test_reset_error(self): - self._setup_mock(dict(vm_state=vm_states.ERROR, - task_state=None)) - self.mox.ReplayAll() - body = {"os-resetState": {"state": "error"}} - result = self.admin_api._reset_state(self.request, self.uuid, - body=body) - # NOTE: on v2.1, http status code is set as wsgi_code of API - # method instead of status_int in a response object. - if isinstance(self.admin_api, - admin_actions_v21.AdminActionsController): - status_int = self.admin_api._reset_state.wsgi_code - else: - status_int = result.status_int - self.assertEqual(202, status_int) - - -class ResetStateTestsV2(ResetStateTestsV21): - admin_act = admin_actions_v2 - bad_request = webob.exc.HTTPBadRequest - fake_url = '/fake/servers' |