def _check_target_flavor(self, instance, flavor, block_device_info):
        new_root_gb = flavor.root_gb
        curr_root_gb = instance.root_gb

        ephemerals = driver.block_device_info_get_ephemerals(block_device_info)
        curr_eph_gb = sum(eph.get('size', 0) for eph in ephemerals)
        new_eph_gb = instance.ephemeral_gb

        if new_root_gb < curr_root_gb:
            raise exception.InstanceFaultRollback(
                exception.CannotResizeDisk(
                    reason=_("Cannot resize the root disk to a smaller size. "
                             "Current size: %(curr_root_gb)s GB. Requested "
                             "size: %(new_root_gb)s GB.") % {
                                 'curr_root_gb': curr_root_gb,
                                 'new_root_gb': new_root_gb
                             }))

        if new_eph_gb < curr_eph_gb:
            raise exception.InstanceFaultRollback(
                exception.CannotResizeDisk(
                    reason=_("Cannot resize the ephemeral disk(s) to a smaller"
                             " size. Current total ephemeral size: "
                             "%(curr_eph_gb)s GB. Requested total size: "
                             "%(new_eph_gb)s GB") % {
                                 'curr_eph_gb': curr_eph_gb,
                                 'new_eph_gb': new_eph_gb
                             }))
Beispiel #2
0
 def _check_resize_vhd(self, vhd_path, vhd_info, new_size):
     curr_size = vhd_info['VirtualSize']
     if new_size < curr_size:
         raise exception.CannotResizeDisk(
             reason=_("Cannot resize the root disk to a smaller size. "
                      "Current size: %(curr_root_gb)s GB. Requested "
                      "size: %(new_root_gb)s GB.") % {
                          'curr_root_gb': curr_size / units.Gi,
                          'new_root_gb': new_size / units.Gi})
     elif new_size > curr_size:
         self._resize_vhd(vhd_path, new_size)
Beispiel #3
0
    def _check_target_flavor(self, instance, flavor):
        new_root_gb = flavor.root_gb
        curr_root_gb = instance.flavor.root_gb

        if new_root_gb < curr_root_gb:
            raise exception.InstanceFaultRollback(
                exception.CannotResizeDisk(
                    reason=_("Cannot resize the root disk to a smaller size. "
                             "Current size: %(curr_root_gb)s GB. Requested "
                             "size: %(new_root_gb)s GB.") % {
                                 'curr_root_gb': curr_root_gb,
                                 'new_root_gb': new_root_gb}))
Beispiel #4
0
class ServerActionsControllerTestV21(test.TestCase):
    image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
    image_base_url = 'http://*****:*****@mock.patch.object(compute_api.API, 'rebuild')
    def test_rebuild_instance_raise_auto_disk_config_exc(self, mock_rebuild):
        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        mock_rebuild.side_effect = exception.AutoDiskConfigDisabledByImage(
            image='dummy')

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_rebuild,
                          self.req, FAKE_UUID, body=body)

    def test_resize_server(self):

        body = dict(resize=dict(flavorRef="http://localhost/3"))

        self.resize_called = False

        def resize_mock(*args):
            self.resize_called = True

        self.stub_out('nova.compute.api.API.resize', resize_mock)

        self.controller._action_resize(self.req, FAKE_UUID, body=body)

        self.assertTrue(self.resize_called)

    def test_resize_server_no_flavor(self):
        body = dict(resize=dict())

        self.assertRaises(self.validation_error,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_server_no_flavor_ref(self):
        body = dict(resize=dict(flavorRef=None))

        self.assertRaises(self.validation_error,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_server_with_extra_arg(self):
        body = dict(resize=dict(favorRef="http://localhost/3",
                                extra_arg="extra_arg"))
        self.assertRaises(self.validation_error,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_server_invalid_flavor_ref(self):
        body = dict(resize=dict(flavorRef=1.2))

        self.assertRaises(self.validation_error,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_with_server_not_found(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        with mock.patch('nova.compute.api.API.get',
                        side_effect=exception.InstanceNotFound(
                            instance_id=FAKE_UUID)):
            self.assertRaises(webob.exc.HTTPNotFound,
                              self.controller._action_resize,
                              self.req, FAKE_UUID, body=body)

    def test_resize_with_image_exceptions(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        self.resize_called = 0
        image_id = 'fake_image_id'

        exceptions = [
            (exception.ImageNotAuthorized(image_id=image_id),
             webob.exc.HTTPUnauthorized),
            (exception.ImageNotFound(image_id=image_id),
             webob.exc.HTTPBadRequest),
            (exception.Invalid, webob.exc.HTTPBadRequest),
            (exception.NoValidHost(reason='Bad host'),
             webob.exc.HTTPBadRequest),
            (exception.AutoDiskConfigDisabledByImage(image=image_id),
             webob.exc.HTTPBadRequest),
        ]

        raised, expected = map(iter, zip(*exceptions))

        def _fake_resize(obj, context, instance, flavor_id):
            self.resize_called += 1
            raise next(raised)

        self.stub_out('nova.compute.api.API.resize', _fake_resize)

        for call_no in range(len(exceptions)):
            next_exception = next(expected)
            actual = self.assertRaises(next_exception,
                                       self.controller._action_resize,
                                       self.req, FAKE_UUID, body=body)
            if (isinstance(exceptions[call_no][0],
                           exception.NoValidHost)):
                self.assertEqual(actual.explanation,
                                 'No valid host was found. Bad host')
            elif (isinstance(exceptions[call_no][0],
                           exception.AutoDiskConfigDisabledByImage)):
                self.assertEqual(actual.explanation,
                                 'Requested image fake_image_id has automatic'
                                 ' disk resize disabled.')
            self.assertEqual(self.resize_called, call_no + 1)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.CannotResizeDisk(reason=''))
    def test_resize_raises_cannot_resize_disk(self, mock_resize):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.FlavorNotFound(reason='',
                                                     flavor_id='fake_id'))
    def test_resize_raises_flavor_not_found(self, mock_resize):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_with_too_many_instances(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        def fake_resize(*args, **kwargs):
            raise exception.TooManyInstances(message="TooManyInstance")

        self.stub_out('nova.compute.api.API.resize', fake_resize)

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_resize_raises_conflict_on_invalid_state(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        def fake_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                state='fake_state', method='fake_method',
                instance_uuid='fake')

        self.stub_out('nova.compute.api.API.resize', fake_resize)

        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.NoValidHost(reason=''))
    def test_resize_raises_no_valid_host(self, mock_resize):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    @mock.patch.object(compute_api.API, 'resize')
    def test_resize_instance_raise_auto_disk_config_exc(self, mock_resize):
        mock_resize.side_effect = exception.AutoDiskConfigDisabledByImage(
            image='dummy')

        body = dict(resize=dict(flavorRef="http://localhost/3"))

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.PciRequestAliasNotDefined(
                    alias='fake_name'))
    def test_resize_pci_alias_not_defined(self, mock_resize):
        # Tests that PciRequestAliasNotDefined is translated to a 400 error.
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          self.req, FAKE_UUID, body=body)

    def test_confirm_resize_server(self):
        body = dict(confirmResize=None)

        self.confirm_resize_called = False

        def cr_mock(*args):
            self.confirm_resize_called = True

        self.stub_out('nova.compute.api.API.confirm_resize', cr_mock)

        self.controller._action_confirm_resize(self.req, FAKE_UUID, body=body)

        self.assertTrue(self.confirm_resize_called)

    def test_confirm_resize_migration_not_found(self):
        body = dict(confirmResize=None)

        def confirm_resize_mock(*args):
            raise exception.MigrationNotFoundByStatus(instance_id=1,
                                                      status='finished')

        self.stub_out('nova.compute.api.API.confirm_resize',
                      confirm_resize_mock)

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_confirm_resize,
                          self.req, FAKE_UUID, body=body)

    def test_confirm_resize_raises_conflict_on_invalid_state(self):
        body = dict(confirmResize=None)

        def fake_confirm_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                state='fake_state', method='fake_method',
                instance_uuid='fake')

        self.stub_out('nova.compute.api.API.confirm_resize',
                      fake_confirm_resize)

        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_confirm_resize,
                          self.req, FAKE_UUID, body=body)

    def test_revert_resize_migration_not_found(self):
        body = dict(revertResize=None)

        def revert_resize_mock(*args):
            raise exception.MigrationNotFoundByStatus(instance_id=1,
                                                      status='finished')

        self.stub_out('nova.compute.api.API.revert_resize',
                      revert_resize_mock)

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_revert_resize,
                          self.req, FAKE_UUID, body=body)

    def test_revert_resize_server_not_found(self):
        body = dict(revertResize=None)
        with mock.patch('nova.compute.api.API.get',
                        side_effect=exception.InstanceNotFound(
                            instance_id='bad_server_id')):
            self.assertRaises(webob. exc.HTTPNotFound,
                              self.controller._action_revert_resize,
                              self.req, "bad_server_id", body=body)

    def test_revert_resize_server(self):
        body = dict(revertResize=None)

        self.revert_resize_called = False

        def revert_mock(*args):
            self.revert_resize_called = True

        self.stub_out('nova.compute.api.API.revert_resize', revert_mock)

        body = self.controller._action_revert_resize(self.req, FAKE_UUID,
                                                     body=body)

        self.assertTrue(self.revert_resize_called)

    def test_revert_resize_raises_conflict_on_invalid_state(self):
        body = dict(revertResize=None)

        def fake_revert_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                state='fake_state', method='fake_method',
                instance_uuid='fake')

        self.stub_out('nova.compute.api.API.revert_resize',
                      fake_revert_resize)

        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_revert_resize,
                          self.req, FAKE_UUID, body=body)

    def test_create_image(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
            },
        }

        response = self.controller._action_create_image(self.req, FAKE_UUID,
                                                        body=body)

        location = response.headers['Location']
        self.assertEqual(self.image_url + '123' if self.image_url else
            self.image_api.generate_image_url('123', self.context),
            location)

    def test_create_image_v2_45(self):
        """Tests the createImage server action API with the 2.45 microversion
        where there is a response body but no Location header.
        """
        body = {
            'createImage': {
                'name': 'Snapshot 1',
            },
        }
        req = fakes.HTTPRequest.blank('', version='2.45')
        response = self.controller._action_create_image(req, FAKE_UUID,
                                                        body=body)
        self.assertIsInstance(response, dict)
        self.assertEqual('123', response['image_id'])

    def test_create_image_name_too_long(self):
        long_name = 'a' * 260
        body = {
            'createImage': {
                'name': long_name,
            },
        }

        self.assertRaises(self.validation_error,
                          self.controller._action_create_image, self.req,
                          FAKE_UUID, body=body)

    def _do_test_create_volume_backed_image(
            self, extra_properties, mock_vol_create_side_effect=None):

        def _fake_id(x):
            return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)

        body = dict(createImage=dict(name='snapshot_of_volume_backed'))

        if extra_properties:
            body['createImage']['metadata'] = extra_properties

        image_service = glance.get_default_image_service()

        bdm = [dict(volume_id=_fake_id('a'),
                    volume_size=1,
                    device_name='vda',
                    delete_on_termination=False)]

        def fake_block_device_mapping_get_all_by_instance(context, inst_id,
                                                          use_slave=False):
            return [fake_block_device.FakeDbBlockDeviceDict(
                        {'volume_id': _fake_id('a'),
                         'source_type': 'snapshot',
                         'destination_type': 'volume',
                         'volume_size': 1,
                         'device_name': 'vda',
                         'snapshot_id': 1,
                         'boot_index': 0,
                         'delete_on_termination': False,
                         'no_device': None})]

        self.stub_out('nova.db.api.block_device_mapping_get_all_by_instance',
                      fake_block_device_mapping_get_all_by_instance)

        system_metadata = dict(image_kernel_id=_fake_id('b'),
                               image_ramdisk_id=_fake_id('c'),
                               image_root_device_name='/dev/vda',
                               image_block_device_mapping=str(bdm),
                               image_container_format='ami')
        instance = fakes.fake_compute_get(image_ref=uuids.fake,
                                          vm_state=vm_states.ACTIVE,
                                          root_device_name='/dev/vda',
                                          system_metadata=system_metadata)
        self.stub_out('nova.compute.api.API.get', instance)

        volume = dict(id=_fake_id('a'),
                      size=1,
                      host='fake',
                      display_description='fake')

        snapshot = dict(id=_fake_id('d'))

        with test.nested(
            mock.patch.object(
                self.controller.compute_api.volume_api, 'get_absolute_limits',
                return_value={'totalSnapshotsUsed': 0,
                              'maxTotalSnapshots': 10}),
            mock.patch.object(self.controller.compute_api.compute_rpcapi,
                'quiesce_instance',
                side_effect=exception.InstanceQuiesceNotSupported(
                    instance_id='fake', reason='test')),
            mock.patch.object(self.controller.compute_api.volume_api, 'get',
                              return_value=volume),
            mock.patch.object(self.controller.compute_api.volume_api,
                              'create_snapshot_force',
                              return_value=snapshot),
        ) as (mock_get_limits, mock_quiesce, mock_vol_get, mock_vol_create):

            if mock_vol_create_side_effect:
                mock_vol_create.side_effect = mock_vol_create_side_effect

            response = self.controller._action_create_image(self.req,
                FAKE_UUID, body=body)

            location = response.headers['Location']
            image_id = location.replace(self.image_url or
                 self.image_api.generate_image_url('', self.context),
                                        '')
            image = image_service.show(None, image_id)

            self.assertEqual(image['name'], 'snapshot_of_volume_backed')
            properties = image['properties']
            self.assertEqual(properties['kernel_id'], _fake_id('b'))
            self.assertEqual(properties['ramdisk_id'], _fake_id('c'))
            self.assertEqual(properties['root_device_name'], '/dev/vda')
            self.assertTrue(properties['bdm_v2'])
            bdms = properties['block_device_mapping']
            self.assertEqual(len(bdms), 1)
            self.assertEqual(bdms[0]['boot_index'], 0)
            self.assertEqual(bdms[0]['source_type'], 'snapshot')
            self.assertEqual(bdms[0]['destination_type'], 'volume')
            self.assertEqual(bdms[0]['snapshot_id'], snapshot['id'])
            self.assertEqual('/dev/vda', bdms[0]['device_name'])
            for fld in ('connection_info', 'id', 'instance_uuid'):
                self.assertNotIn(fld, bdms[0])
            for k in extra_properties.keys():
                self.assertEqual(properties[k], extra_properties[k])

            mock_quiesce.assert_called_once_with(mock.ANY, mock.ANY)
            mock_vol_get.assert_called_once_with(mock.ANY, volume['id'])
            mock_vol_create.assert_called_once_with(mock.ANY, volume['id'],
                                                    mock.ANY, mock.ANY)

    def test_create_volume_backed_image_no_metadata(self):
        self._do_test_create_volume_backed_image({})

    def test_create_volume_backed_image_with_metadata(self):
        self._do_test_create_volume_backed_image(dict(ImageType='Gold',
                                                      ImageVersion='2.0'))

    def test_create_volume_backed_image_cinder_over_quota(self):
        self.assertRaises(
            webob.exc.HTTPForbidden,
            self._do_test_create_volume_backed_image, {},
            mock_vol_create_side_effect=exception.OverQuota(
                overs='snapshot'))

    def _test_create_volume_backed_image_with_metadata_from_volume(
            self, extra_metadata=None):

        def _fake_id(x):
            return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)

        body = dict(createImage=dict(name='snapshot_of_volume_backed'))
        if extra_metadata:
            body['createImage']['metadata'] = extra_metadata

        image_service = glance.get_default_image_service()

        def fake_block_device_mapping_get_all_by_instance(context, inst_id,
                                                          use_slave=False):
            return [fake_block_device.FakeDbBlockDeviceDict(
                        {'volume_id': _fake_id('a'),
                         'source_type': 'snapshot',
                         'destination_type': 'volume',
                         'volume_size': 1,
                         'device_name': 'vda',
                         'snapshot_id': 1,
                         'boot_index': 0,
                         'delete_on_termination': False,
                         'no_device': None})]

        self.stub_out('nova.db.api.block_device_mapping_get_all_by_instance',
                      fake_block_device_mapping_get_all_by_instance)

        instance = fakes.fake_compute_get(
            image_ref='',
            vm_state=vm_states.ACTIVE,
            root_device_name='/dev/vda',
            system_metadata={'image_test_key1': 'test_value1',
                             'image_test_key2': 'test_value2'})
        self.stub_out('nova.compute.api.API.get', instance)

        volume = dict(id=_fake_id('a'),
                      size=1,
                      host='fake',
                      display_description='fake')

        snapshot = dict(id=_fake_id('d'))

        with test.nested(
            mock.patch.object(
                self.controller.compute_api.volume_api, 'get_absolute_limits',
                return_value={'totalSnapshotsUsed': 0,
                              'maxTotalSnapshots': 10}),
            mock.patch.object(self.controller.compute_api.compute_rpcapi,
                'quiesce_instance',
                side_effect=exception.InstanceQuiesceNotSupported(
                    instance_id='fake', reason='test')),
            mock.patch.object(self.controller.compute_api.volume_api, 'get',
                              return_value=volume),
            mock.patch.object(self.controller.compute_api.volume_api,
                              'create_snapshot_force',
                              return_value=snapshot),
        ) as (mock_get_limits, mock_quiesce, mock_vol_get, mock_vol_create):

            response = self.controller._action_create_image(self.req,
                FAKE_UUID, body=body)
            location = response.headers['Location']
            image_id = location.replace(self.image_base_url, '')
            image = image_service.show(None, image_id)

            properties = image['properties']
            self.assertEqual(properties['test_key1'], 'test_value1')
            self.assertEqual(properties['test_key2'], 'test_value2')
            if extra_metadata:
                for key, val in extra_metadata.items():
                    self.assertEqual(properties[key], val)

            mock_quiesce.assert_called_once_with(mock.ANY, mock.ANY)
            mock_vol_get.assert_called_once_with(mock.ANY, volume['id'])
            mock_vol_create.assert_called_once_with(mock.ANY, volume['id'],
                                                    mock.ANY, mock.ANY)

    def test_create_vol_backed_img_with_meta_from_vol_without_extra_meta(self):
        self._test_create_volume_backed_image_with_metadata_from_volume()

    def test_create_vol_backed_img_with_meta_from_vol_with_extra_meta(self):
        self._test_create_volume_backed_image_with_metadata_from_volume(
            extra_metadata={'a': 'b'})

    def test_create_image_with_metadata(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
                'metadata': {'key': 'asdf'},
            },
        }

        response = self.controller._action_create_image(self.req, FAKE_UUID,
                                                        body=body)

        location = response.headers['Location']
        self.assertEqual(self.image_url + '123' if self.image_url else
            self.image_api.generate_image_url('123', self.context), location)

    def test_create_image_with_too_much_metadata(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
                'metadata': {},
            },
        }
        for num in range(CONF.quota.metadata_items + 1):
            body['createImage']['metadata']['foo%i' % num] = "bar"

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller._action_create_image,
                          self.req, FAKE_UUID, body=body)

    def test_create_image_no_name(self):
        body = {
            'createImage': {},
        }

        self.assertRaises(self.validation_error,
                          self.controller._action_create_image,
                          self.req, FAKE_UUID, body=body)

    def test_create_image_blank_name(self):
        body = {
            'createImage': {
                'name': '',
            }
        }

        self.assertRaises(self.validation_error,
                          self.controller._action_create_image,
                          self.req, FAKE_UUID, body=body)

    def test_create_image_bad_metadata(self):
        body = {
            'createImage': {
                'name': 'geoff',
                'metadata': 'henry',
            },
        }

        self.assertRaises(self.validation_error,
                          self.controller._action_create_image,
                          self.req, FAKE_UUID, body=body)

    def test_create_image_raises_conflict_on_invalid_state(self):
        def snapshot(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                state='fake_state', method='fake_method',
                instance_uuid='fake')
        self.stub_out('nova.compute.api.API.snapshot', snapshot)

        body = {
            "createImage": {
                "name": "test_snapshot",
            },
        }

        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_create_image,
                          self.req, FAKE_UUID, body=body)
class ServerActionsControllerTest(test.TestCase):
    image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
    image_href = 'http://localhost/v2/fake/images/%s' % image_uuid

    def setUp(self):
        super(ServerActionsControllerTest, self).setUp()

        CONF.set_override('host', 'localhost', group='glance')
        self.stubs.Set(
            db, 'instance_get_by_uuid',
            fakes.fake_instance_get(vm_state=vm_states.ACTIVE,
                                    host='fake_host'))
        self.stubs.Set(db, 'instance_update_and_get_original',
                       instance_update_and_get_original)

        fakes.stub_out_nw_api(self.stubs)
        fakes.stub_out_compute_api_snapshot(self.stubs)
        fake.stub_out_image_service(self.stubs)
        self.flags(allow_instance_snapshots=True,
                   enable_instance_password=True)
        self.uuid = FAKE_UUID
        self.url = '/servers/%s/action' % self.uuid
        self._image_href = '155d900f-4e14-4e4c-a73d-069cbf4541e6'

        ext_info = plugins.LoadedExtensionInfo()
        self.controller = servers.ServersController(extension_info=ext_info)
        self.compute_api = self.controller.compute_api
        self.context = context.RequestContext('fake', 'fake')
        self.app = fakes.wsgi_app_v21(init_only=('servers', ),
                                      fake_auth_context=self.context)

    def _make_request(self, url, body):
        req = webob.Request.blank('/v2/fake' + 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):
        self.mox.StubOutWithMock(compute_api.API, 'get')
        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)
        instance = objects.Instance._from_db_object(self.context,
                                                    objects.Instance(),
                                                    instance)

        self.compute_api.get(self.context,
                             uuid,
                             want_objects=True,
                             expected_attrs=['pci_devices'
                                             ]).AndReturn(instance)
        return instance

    def _test_locked_instance(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(compute_api.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: body_map.get(action)})
        self.assertEqual(409, 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_actions_with_locked_instance(self):
        actions = [
            'resize', 'confirmResize', 'revertResize', 'reboot', 'rebuild'
        ]

        method_translations = {
            'confirmResize': 'confirm_resize',
            'revertResize': 'revert_resize'
        }

        body_map = {
            'resize': {
                'flavorRef': '2'
            },
            'reboot': {
                'type': 'HARD'
            },
            'rebuild': {
                'imageRef': self.image_uuid,
                'adminPass': '******'
            }
        }

        args_map = {
            'resize': (('2'), {}),
            'confirmResize': ((), {}),
            'reboot': (('HARD', ), {}),
            'rebuild': ((self.image_uuid, 'TNc53Dr8s7vw'), {})
        }

        for action in actions:
            method = method_translations.get(action)
            self.mox.StubOutWithMock(compute_api.API, method or action)
            self._test_locked_instance(action,
                                       method=method,
                                       body_map=body_map,
                                       compute_api_args_map=args_map)

    def test_reboot_hard(self):
        body = dict(reboot=dict(type="HARD"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.controller._action_reboot(req, FAKE_UUID, body)

    def test_reboot_soft(self):
        body = dict(reboot=dict(type="SOFT"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.controller._action_reboot(req, FAKE_UUID, body)

    def test_reboot_incorrect_type(self):
        body = dict(reboot=dict(type="NOT_A_TYPE"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_reboot_missing_type(self):
        body = dict(reboot=dict())
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_reboot_none(self):
        body = dict(reboot=dict(type=None))
        req = fakes.HTTPRequest.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_reboot_not_found(self):
        self.stubs.Set(db, 'instance_get_by_uuid', return_server_not_found)

        body = dict(reboot=dict(type="HARD"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller._action_reboot, req,
                          str(uuid.uuid4()), body)

    def test_reboot_raises_conflict_on_invalid_state(self):
        body = dict(reboot=dict(type="HARD"))

        def fake_reboot(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'reboot', fake_reboot)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_reboot_soft_with_soft_in_progress_raises_conflict(self):
        body = dict(reboot=dict(type="SOFT"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.stubs.Set(
            db, 'instance_get_by_uuid',
            fakes.fake_instance_get(vm_state=vm_states.ACTIVE,
                                    task_state=task_states.REBOOTING))
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_reboot_hard_with_soft_in_progress_does_not_raise(self):
        body = dict(reboot=dict(type="HARD"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.stubs.Set(
            db, 'instance_get_by_uuid',
            fakes.fake_instance_get(vm_state=vm_states.ACTIVE,
                                    task_state=task_states.REBOOTING))
        self.controller._action_reboot(req, FAKE_UUID, body)

    def test_reboot_hard_with_hard_in_progress_raises_conflict(self):
        body = dict(reboot=dict(type="HARD"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.stubs.Set(
            db, 'instance_get_by_uuid',
            fakes.fake_instance_get(vm_state=vm_states.ACTIVE,
                                    task_state=task_states.REBOOTING_HARD))
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_reboot, req, FAKE_UUID, body)

    def test_rebuild_accepted_minimum(self):
        return_server = fakes.fake_instance_get(image_ref='2',
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)
        self_href = 'http://localhost/v3/servers/%s' % FAKE_UUID

        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        robj = self.controller._action_rebuild(req, FAKE_UUID, body=body)
        body = robj.obj

        self.assertEqual(body['server']['image']['id'], '2')
        self.assertEqual(len(body['server']['adminPass']),
                         CONF.password_length)

        self.assertEqual(robj['location'], self_href)

    def test_rebuild_instance_with_image_uuid(self):
        info = dict(image_href_in_call=None)

        def rebuild(self2, context, instance, image_href, *args, **kwargs):
            info['image_href_in_call'] = image_href

        self.stubs.Set(db, 'instance_get',
                       fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
        self.stubs.Set(compute_api.API, 'rebuild', rebuild)

        body = {
            'rebuild': {
                'imageRef': self.image_uuid,
            },
        }

        req = fakes.HTTPRequestV3.blank('/v2/fake/servers/a/action')
        self.controller._action_rebuild(req, FAKE_UUID, body=body)
        self.assertEqual(info['image_href_in_call'], self.image_uuid)

    def test_rebuild_instance_with_image_href_uses_uuid(self):
        info = dict(image_href_in_call=None)

        def rebuild(self2, context, instance, image_href, *args, **kwargs):
            info['image_href_in_call'] = image_href

        self.stubs.Set(db, 'instance_get',
                       fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
        self.stubs.Set(compute_api.API, 'rebuild', rebuild)

        body = {
            'rebuild': {
                'imageRef': self.image_href,
            },
        }

        req = fakes.HTTPRequestV3.blank('/v2/fake/servers/a/action')
        self.controller._action_rebuild(req, FAKE_UUID, body=body)
        self.assertEqual(info['image_href_in_call'], self.image_uuid)

    def test_rebuild_accepted_minimum_pass_disabled(self):
        # run with enable_instance_password disabled to verify admin_password
        # is missing from response. See lp bug 921814
        self.flags(enable_instance_password=False)

        return_server = fakes.fake_instance_get(image_ref='2',
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)
        self_href = 'http://localhost/v3/servers/%s' % FAKE_UUID

        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        robj = self.controller._action_rebuild(req, FAKE_UUID, body=body)
        body = robj.obj

        self.assertEqual(body['server']['image']['id'], '2')
        self.assertNotIn("admin_password", body['server'])

        self.assertEqual(robj['location'], self_href)

    def test_rebuild_raises_conflict_on_invalid_state(self):
        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        def fake_rebuild(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'rebuild', fake_rebuild)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_accepted_with_metadata(self):
        metadata = {'new': 'metadata'}

        return_server = fakes.fake_instance_get(metadata=metadata,
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)

        body = {
            "rebuild": {
                "imageRef": self._image_href,
                "metadata": metadata,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_rebuild(req, FAKE_UUID, body=body).obj

        self.assertEqual(body['server']['metadata'], metadata)

    def test_rebuild_accepted_with_bad_metadata(self):
        body = {
            "rebuild": {
                "imageRef": self._image_href,
                "metadata": "stack",
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(exception.ValidationError,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_with_too_large_metadata(self):
        body = {
            "rebuild": {
                "imageRef": self._image_href,
                "metadata": {
                    256 * "k": "value"
                }
            }
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(exception.ValidationError,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_bad_entity(self):
        body = {
            "rebuild": {
                "imageId": self._image_href,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(exception.ValidationError,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_admin_password(self):
        return_server = fakes.fake_instance_get(image_ref='2',
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)

        body = {
            "rebuild": {
                "imageRef": self._image_href,
                "adminPass": "******",
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_rebuild(req, FAKE_UUID, body=body).obj

        self.assertEqual(body['server']['image']['id'], '2')
        self.assertEqual(body['server']['adminPass'], 'asdf')

    def test_rebuild_admin_password_pass_disabled(self):
        # run with enable_instance_password disabled to verify admin_password
        # is missing from response. See lp bug 921814
        self.flags(enable_instance_password=False)

        return_server = fakes.fake_instance_get(image_ref='2',
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)

        body = {
            "rebuild": {
                "imageRef": self._image_href,
                "admin_password": "******",
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_rebuild(req, FAKE_UUID, body=body).obj

        self.assertEqual(body['server']['image']['id'], '2')
        self.assertNotIn('adminPass', body['server'])

    def test_rebuild_server_not_found(self):
        def server_not_found(self,
                             instance_id,
                             columns_to_join=None,
                             use_slave=False):
            raise exception.InstanceNotFound(instance_id=instance_id)

        self.stubs.Set(db, 'instance_get_by_uuid', server_not_found)

        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_with_bad_image(self):
        body = {
            "rebuild": {
                "imageRef": "foo",
            },
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_when_kernel_not_exists(self):
        def return_image_meta(*args, **kwargs):
            image_meta_table = {
                '2': {
                    'id': 2,
                    'status': 'active',
                    'container_format': 'ari'
                },
                '155d900f-4e14-4e4c-a73d-069cbf4541e6': {
                    'id': 3,
                    'status': 'active',
                    'container_format': 'raw',
                    'properties': {
                        'kernel_id': 1,
                        'ramdisk_id': 2
                    }
                },
            }
            image_id = args[2]
            try:
                image_meta = image_meta_table[str(image_id)]
            except KeyError:
                raise exception.ImageNotFound(image_id=image_id)

            return image_meta

        self.stubs.Set(fake._FakeImageService, 'show', return_image_meta)
        body = {
            "rebuild": {
                "imageRef": "155d900f-4e14-4e4c-a73d-069cbf4541e6",
            },
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_rebuild_proper_kernel_ram(self):
        instance_meta = {'kernel_id': None, 'ramdisk_id': None}

        orig_get = compute_api.API.get

        def wrap_get(*args, **kwargs):
            inst = orig_get(*args, **kwargs)
            instance_meta['instance'] = inst
            return inst

        def fake_save(context, **kwargs):
            instance = instance_meta['instance']
            for key in instance_meta.keys():
                if key in instance.obj_what_changed():
                    instance_meta[key] = instance[key]

        def return_image_meta(*args, **kwargs):
            image_meta_table = {
                '1': {
                    'id': 1,
                    'status': 'active',
                    'container_format': 'aki'
                },
                '2': {
                    'id': 2,
                    'status': 'active',
                    'container_format': 'ari'
                },
                '155d900f-4e14-4e4c-a73d-069cbf4541e6': {
                    'id': 3,
                    'status': 'active',
                    'container_format': 'raw',
                    'properties': {
                        'kernel_id': 1,
                        'ramdisk_id': 2
                    }
                },
            }
            image_id = args[2]
            try:
                image_meta = image_meta_table[str(image_id)]
            except KeyError:
                raise exception.ImageNotFound(image_id=image_id)

            return image_meta

        self.stubs.Set(fake._FakeImageService, 'show', return_image_meta)
        self.stubs.Set(compute_api.API, 'get', wrap_get)
        self.stubs.Set(objects.Instance, 'save', fake_save)
        body = {
            "rebuild": {
                "imageRef": "155d900f-4e14-4e4c-a73d-069cbf4541e6",
            },
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.controller._action_rebuild(req, FAKE_UUID, body=body).obj
        self.assertEqual(instance_meta['kernel_id'], '1')
        self.assertEqual(instance_meta['ramdisk_id'], '2')

    def _test_rebuild_preserve_ephemeral(self, value=None):
        return_server = fakes.fake_instance_get(image_ref='2',
                                                vm_state=vm_states.ACTIVE,
                                                host='fake_host')
        self.stubs.Set(db, 'instance_get_by_uuid', return_server)

        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }
        if value is not None:
            body['rebuild']['preserve_ephemeral'] = value

        req = fakes.HTTPRequestV3.blank(self.url)
        context = req.environ['nova.context']

        self.mox.StubOutWithMock(compute_api.API, 'rebuild')
        if value is not None:
            compute_api.API.rebuild(context,
                                    mox.IgnoreArg(),
                                    self._image_href,
                                    mox.IgnoreArg(),
                                    preserve_ephemeral=value)
        else:
            compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
                                    mox.IgnoreArg())
        self.mox.ReplayAll()

        self.controller._action_rebuild(req, FAKE_UUID, body=body)

    def test_rebuild_preserve_ephemeral_true(self):
        self._test_rebuild_preserve_ephemeral(True)

    def test_rebuild_preserve_ephemeral_false(self):
        self._test_rebuild_preserve_ephemeral(False)

    def test_rebuild_preserve_ephemeral_default(self):
        self._test_rebuild_preserve_ephemeral()

    @mock.patch.object(
        compute_api.API,
        'rebuild',
        side_effect=exception.AutoDiskConfigDisabledByImage(image='dummy'))
    def test_rebuild_instance_raise_auto_disk_config_exc(self, mock_rebuild):
        body = {
            "rebuild": {
                "imageRef": self._image_href,
            },
        }

        req = fakes.HTTPRequest.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_rebuild,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_resize_server(self):

        body = dict(resize=dict(flavorRef="http://localhost/3"))

        self.resize_called = False

        def resize_mock(*args):
            self.resize_called = True

        self.stubs.Set(compute_api.API, 'resize', resize_mock)

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_resize(req, FAKE_UUID, body=body)

        self.assertEqual(self.resize_called, True)

    def test_resize_server_no_flavor(self):
        body = dict(resize=dict())

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(exception.ValidationError,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_resize_server_no_flavor_ref(self):
        body = dict(resize=dict(flavorRef=None))

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(exception.ValidationError,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_resize_with_server_not_found(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        self.stubs.Set(compute_api.API, 'get', return_server_not_found)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_resize_with_image_exceptions(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        self.resize_called = 0
        image_id = 'fake_image_id'

        exceptions = [
            (exception.ImageNotAuthorized(image_id=image_id),
             webob.exc.HTTPUnauthorized),
            (exception.ImageNotFound(image_id=image_id),
             webob.exc.HTTPBadRequest),
            (exception.Invalid, webob.exc.HTTPBadRequest),
            (exception.NoValidHost(reason='Bad host'),
             webob.exc.HTTPBadRequest),
            (exception.AutoDiskConfigDisabledByImage(image=image_id),
             webob.exc.HTTPBadRequest),
        ]

        raised, expected = map(iter, zip(*exceptions))

        def _fake_resize(obj, context, instance, flavor_id):
            self.resize_called += 1
            raise raised.next()

        self.stubs.Set(compute_api.API, 'resize', _fake_resize)

        for call_no in range(len(exceptions)):
            req = fakes.HTTPRequestV3.blank(self.url)
            next_exception = expected.next()
            actual = self.assertRaises(next_exception,
                                       self.controller._action_resize,
                                       req,
                                       FAKE_UUID,
                                       body=body)
            if (isinstance(exceptions[call_no][0], exception.NoValidHost)):
                self.assertEqual(actual.explanation,
                                 'No valid host was found. Bad host')
            elif (isinstance(exceptions[call_no][0],
                             exception.AutoDiskConfigDisabledByImage)):
                self.assertEqual(
                    actual.explanation,
                    'Requested image fake_image_id has automatic'
                    ' disk resize disabled.')
            self.assertEqual(self.resize_called, call_no + 1)

    def test_resize_with_too_many_instances(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        def fake_resize(*args, **kwargs):
            raise exception.TooManyInstances(message="TooManyInstance")

        self.stubs.Set(compute_api.API, 'resize', fake_resize)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.CannotResizeDisk(reason=''))
    def test_resize_raises_cannot_resize_disk(self, mock_resize):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    @mock.patch('nova.compute.api.API.resize',
                side_effect=exception.FlavorNotFound(reason='',
                                                     flavor_id='fake_id'))
    def test_resize_raises_flavor_not_found(self, mock_resize):
        body = dict(resize=dict(flavorRef="http://localhost/3"))
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_resize_raises_conflict_on_invalid_state(self):
        body = dict(resize=dict(flavorRef="http://localhost/3"))

        def fake_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'resize', fake_resize)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_resize,
                          req,
                          FAKE_UUID,
                          body=body)

    def test_confirm_resize_server(self):
        body = dict(confirmResize=None)

        self.confirm_resize_called = False

        def cr_mock(*args):
            self.confirm_resize_called = True

        self.stubs.Set(compute_api.API, 'confirm_resize', cr_mock)

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_confirm_resize(req, FAKE_UUID, body)

        self.assertEqual(self.confirm_resize_called, True)

    def test_confirm_resize_migration_not_found(self):
        body = dict(confirmResize=None)

        def confirm_resize_mock(*args):
            raise exception.MigrationNotFoundByStatus(instance_id=1,
                                                      status='finished')

        self.stubs.Set(compute_api.API, 'confirm_resize', confirm_resize_mock)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_confirm_resize, req,
                          FAKE_UUID, body)

    def test_confirm_resize_raises_conflict_on_invalid_state(self):
        body = dict(confirmResize=None)

        def fake_confirm_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'confirm_resize', fake_confirm_resize)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_confirm_resize, req,
                          FAKE_UUID, body)

    def test_revert_resize_migration_not_found(self):
        body = dict(revertResize=None)

        def revert_resize_mock(*args):
            raise exception.MigrationNotFoundByStatus(instance_id=1,
                                                      status='finished')

        self.stubs.Set(compute_api.API, 'revert_resize', revert_resize_mock)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_revert_resize, req,
                          FAKE_UUID, body)

    def test_revert_resize_server_not_found(self):
        body = dict(revertResize=None)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller._action_revert_resize, req,
                          "bad_server_id", body)

    def test_revert_resize_server(self):
        body = dict(revertResize=None)

        self.revert_resize_called = False

        def revert_mock(*args):
            self.revert_resize_called = True

        self.stubs.Set(compute_api.API, 'revert_resize', revert_mock)

        req = fakes.HTTPRequestV3.blank(self.url)
        body = self.controller._action_revert_resize(req, FAKE_UUID, body)

        self.assertEqual(self.revert_resize_called, True)

    def test_revert_resize_raises_conflict_on_invalid_state(self):
        body = dict(revertResize=None)

        def fake_revert_resize(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'revert_resize', fake_revert_resize)

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_revert_resize, req,
                          FAKE_UUID, body)

    def test_create_image(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        response = self.controller._action_create_image(req, FAKE_UUID, body)

        location = response.headers['Location']
        self.assertEqual(glance.generate_image_url('123'), location)

    def test_create_image_name_too_long(self):
        long_name = 'a' * 260
        body = {
            'createImage': {
                'name': long_name,
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def _do_test_create_volume_backed_image(self, extra_properties):
        def _fake_id(x):
            return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)

        body = dict(createImage=dict(name='snapshot_of_volume_backed'))

        if extra_properties:
            body['createImage']['metadata'] = extra_properties

        image_service = glance.get_default_image_service()

        bdm = [
            dict(volume_id=_fake_id('a'),
                 volume_size=1,
                 device_name='vda',
                 delete_on_termination=False)
        ]
        props = dict(kernel_id=_fake_id('b'),
                     ramdisk_id=_fake_id('c'),
                     root_device_name='/dev/vda',
                     block_device_mapping=bdm)
        original_image = dict(properties=props,
                              container_format='ami',
                              status='active',
                              is_public=True)

        image_service.create(None, original_image)

        def fake_block_device_mapping_get_all_by_instance(
                context, inst_id, use_slave=False):
            return [
                fake_block_device.FakeDbBlockDeviceDict({
                    'volume_id':
                    _fake_id('a'),
                    'source_type':
                    'snapshot',
                    'destination_type':
                    'volume',
                    'volume_size':
                    1,
                    'device_name':
                    'vda',
                    'snapshot_id':
                    1,
                    'boot_index':
                    0,
                    'delete_on_termination':
                    False,
                    'no_device':
                    None
                })
            ]

        self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
                       fake_block_device_mapping_get_all_by_instance)

        instance = fakes.fake_instance_get(image_ref=original_image['id'],
                                           vm_state=vm_states.ACTIVE,
                                           root_device_name='/dev/vda')
        self.stubs.Set(db, 'instance_get_by_uuid', instance)

        volume = dict(id=_fake_id('a'),
                      size=1,
                      host='fake',
                      display_description='fake')
        snapshot = dict(id=_fake_id('d'))
        self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api')
        volume_api = self.controller.compute_api.volume_api
        volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
        volume_api.create_snapshot_force(mox.IgnoreArg(), volume['id'],
                                         mox.IgnoreArg(),
                                         mox.IgnoreArg()).AndReturn(snapshot)

        self.mox.ReplayAll()

        req = fakes.HTTPRequestV3.blank(self.url)
        response = self.controller._action_create_image(req, FAKE_UUID, body)

        location = response.headers['Location']
        image_id = location.replace(glance.generate_image_url(''), '')
        image = image_service.show(None, image_id)

        self.assertEqual(image['name'], 'snapshot_of_volume_backed')
        properties = image['properties']
        self.assertEqual(properties['kernel_id'], _fake_id('b'))
        self.assertEqual(properties['ramdisk_id'], _fake_id('c'))
        self.assertEqual(properties['root_device_name'], '/dev/vda')
        self.assertEqual(properties['bdm_v2'], True)
        bdms = properties['block_device_mapping']
        self.assertEqual(len(bdms), 1)
        self.assertEqual(bdms[0]['boot_index'], 0)
        self.assertEqual(bdms[0]['source_type'], 'snapshot')
        self.assertEqual(bdms[0]['destination_type'], 'volume')
        self.assertEqual(bdms[0]['snapshot_id'], snapshot['id'])
        for fld in ('connection_info', 'id', 'instance_uuid', 'device_name'):
            self.assertNotIn(fld, bdms[0])
        for k in extra_properties.keys():
            self.assertEqual(properties[k], extra_properties[k])

    def test_create_volume_backed_image_no_metadata(self):
        self._do_test_create_volume_backed_image({})

    def test_create_volume_backed_image_with_metadata(self):
        self._do_test_create_volume_backed_image(
            dict(ImageType='Gold', ImageVersion='2.0'))

    def _test_create_volume_backed_image_with_metadata_from_volume(
            self, extra_metadata=None):
        def _fake_id(x):
            return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)

        body = dict(createImage=dict(name='snapshot_of_volume_backed'))
        if extra_metadata:
            body['createImage']['metadata'] = extra_metadata

        image_service = glance.get_default_image_service()

        def fake_block_device_mapping_get_all_by_instance(
                context, inst_id, use_slave=False):
            return [
                fake_block_device.FakeDbBlockDeviceDict({
                    'volume_id':
                    _fake_id('a'),
                    'source_type':
                    'snapshot',
                    'destination_type':
                    'volume',
                    'volume_size':
                    1,
                    'device_name':
                    'vda',
                    'snapshot_id':
                    1,
                    'boot_index':
                    0,
                    'delete_on_termination':
                    False,
                    'no_device':
                    None
                })
            ]

        self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
                       fake_block_device_mapping_get_all_by_instance)

        instance = fakes.fake_instance_get(image_ref='',
                                           vm_state=vm_states.ACTIVE,
                                           root_device_name='/dev/vda')
        self.stubs.Set(db, 'instance_get_by_uuid', instance)

        fake_metadata = {
            'test_key1': 'test_value1',
            'test_key2': 'test_value2'
        }
        volume = dict(id=_fake_id('a'),
                      size=1,
                      host='fake',
                      display_description='fake',
                      volume_image_metadata=fake_metadata)
        snapshot = dict(id=_fake_id('d'))
        self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api')
        volume_api = self.controller.compute_api.volume_api
        volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
        volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
        volume_api.create_snapshot_force(mox.IgnoreArg(), volume['id'],
                                         mox.IgnoreArg(),
                                         mox.IgnoreArg()).AndReturn(snapshot)

        req = fakes.HTTPRequestV3.blank(self.url)

        self.mox.ReplayAll()
        response = self.controller._action_create_image(req, FAKE_UUID, body)
        location = response.headers['Location']
        image_id = location.replace('http://localhost:9292/images/', '')
        image = image_service.show(None, image_id)

        properties = image['properties']
        self.assertEqual(properties['test_key1'], 'test_value1')
        self.assertEqual(properties['test_key2'], 'test_value2')
        if extra_metadata:
            for key, val in extra_metadata.items():
                self.assertEqual(properties[key], val)

    def test_create_vol_backed_img_with_meta_from_vol_without_extra_meta(self):
        self._test_create_volume_backed_image_with_metadata_from_volume()

    def test_create_vol_backed_img_with_meta_from_vol_with_extra_meta(self):
        self._test_create_volume_backed_image_with_metadata_from_volume(
            extra_metadata={'a': 'b'})

    def test_create_image_snapshots_disabled(self):
        """Don't permit a snapshot if the allow_instance_snapshots flag is
        False
        """
        self.flags(allow_instance_snapshots=False)
        body = {
            'createImage': {
                'name': 'Snapshot 1',
            },
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def test_create_image_with_metadata(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
                'metadata': {
                    'key': 'asdf'
                },
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        response = self.controller._action_create_image(req, FAKE_UUID, body)

        location = response.headers['Location']
        self.assertEqual(glance.generate_image_url('123'), location)

    def test_create_image_with_too_much_metadata(self):
        body = {
            'createImage': {
                'name': 'Snapshot 1',
                'metadata': {},
            },
        }
        for num in range(CONF.quota_metadata_items + 1):
            body['createImage']['metadata']['foo%i' % num] = "bar"

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def test_create_image_no_name(self):
        body = {
            'createImage': {},
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def test_create_image_blank_name(self):
        body = {
            'createImage': {
                'name': '',
            }
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def test_create_image_bad_metadata(self):
        body = {
            'createImage': {
                'name': 'geoff',
                'metadata': 'henry',
            },
        }
        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)

    def test_create_image_raises_conflict_on_invalid_state(self):
        def snapshot(*args, **kwargs):
            raise exception.InstanceInvalidState(attr='fake_attr',
                                                 state='fake_state',
                                                 method='fake_method',
                                                 instance_uuid='fake')

        self.stubs.Set(compute_api.API, 'snapshot', snapshot)

        body = {
            "createImage": {
                "name": "test_snapshot",
            },
        }

        req = fakes.HTTPRequestV3.blank(self.url)
        self.assertRaises(webob.exc.HTTPConflict,
                          self.controller._action_create_image, req, FAKE_UUID,
                          body)