diff --git a/api-ref/source/servers-admin-action.inc b/api-ref/source/servers-admin-action.inc index 1110a49104f7..d69ba6b50e49 100644 --- a/api-ref/source/servers-admin-action.inc +++ b/api-ref/source/servers-admin-action.inc @@ -20,6 +20,8 @@ Create Server Back Up (createBackup Action) Creates a back up of a server. +.. note:: This API is not supported for volume-backed instances. + Specify the ``createBackup`` action in the request body. Policy defaults enable only users with the administrative role or the diff --git a/nova/compute/api.py b/nova/compute/api.py index 60349622eab8..671e00e11de7 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -2788,7 +2788,8 @@ class API(base.Base): if compute_utils.is_volume_backed_instance(context, instance): LOG.info(_LI("It's not supported to backup volume backed " "instance."), instance=instance) - raise exception.InvalidRequest() + raise exception.InvalidRequest( + _('Backup is not supported for volume-backed instances.')) else: image_meta = self._create_image(context, instance, name, 'backup', diff --git a/nova/tests/unit/api/openstack/compute/test_create_backup.py b/nova/tests/unit/api/openstack/compute/test_create_backup.py index b40bdc64dd92..0ebb3cdd576a 100644 --- a/nova/tests/unit/api/openstack/compute/test_create_backup.py +++ b/nova/tests/unit/api/openstack/compute/test_create_backup.py @@ -14,12 +14,15 @@ # under the License. import mock +from oslo_utils import timeutils +import six import webob from nova.api.openstack import common from nova.api.openstack.compute import create_backup \ as create_backup_v21 from nova.compute import api +from nova.compute import utils as compute_utils from nova import exception from nova import test from nova.tests.unit.api.openstack.compute import admin_only_action_common @@ -334,8 +337,9 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin, self.req, fakes.FAKE_UUID, body=body) @mock.patch.object(common, 'check_img_metadata_properties_quota') - @mock.patch.object(api.API, 'backup') - def test_backup_volume_backed_instance(self, mock_backup, + @mock.patch.object(compute_utils, 'is_volume_backed_instance', + return_value=True) + def test_backup_volume_backed_instance(self, mock_is_volume_backed, mock_check_image): body = { 'createBackup': { @@ -345,18 +349,20 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin, }, } - instance = fake_instance.fake_instance_obj(self.context) + updates = {'vm_state': 'active', + 'task_state': None, + 'launched_at': timeutils.utcnow()} + instance = fake_instance.fake_instance_obj(self.context, **updates) instance.image_ref = None self.mock_get.return_value = instance - mock_backup.side_effect = exception.InvalidRequest() - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller._create_backup, - self.req, instance['uuid'], body=body) + ex = self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._create_backup, + self.req, instance['uuid'], body=body) mock_check_image.assert_called_once_with(self.context, {}) - mock_backup.assert_called_once_with(self.context, instance, 'BackupMe', - 'daily', 3, - extra_properties={}) + mock_is_volume_backed.assert_called_once_with(self.context, instance) + self.assertIn('Backup is not supported for volume-backed instances', + six.text_type(ex)) class CreateBackupPolicyEnforcementv21(test.NoDBTestCase):