Document and provide useful error message for volume-backed backup

The createBackup API does not support backing up volume-backed
instances. The error message the user gets is not useful about
why the request was invalid, and the API reference docs do not
mention the limitation. This change addresses both of those issues.

Change-Id: I04fd8ab4f8818d9d0ccccb6f6fcb34965b15b8f3
Partial-Bug: #1679314
This commit is contained in:
Matt Riedemann
2017-04-03 18:04:31 -04:00
parent 496bfb6287
commit b98d9e1d4f
3 changed files with 20 additions and 11 deletions

View File

@@ -20,6 +20,8 @@ Create Server Back Up (createBackup Action)
Creates a back up of a server. 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. Specify the ``createBackup`` action in the request body.
Policy defaults enable only users with the administrative role or the Policy defaults enable only users with the administrative role or the

View File

@@ -2788,7 +2788,8 @@ class API(base.Base):
if compute_utils.is_volume_backed_instance(context, instance): if compute_utils.is_volume_backed_instance(context, instance):
LOG.info(_LI("It's not supported to backup volume backed " LOG.info(_LI("It's not supported to backup volume backed "
"instance."), instance=instance) "instance."), instance=instance)
raise exception.InvalidRequest() raise exception.InvalidRequest(
_('Backup is not supported for volume-backed instances.'))
else: else:
image_meta = self._create_image(context, instance, image_meta = self._create_image(context, instance,
name, 'backup', name, 'backup',

View File

@@ -14,12 +14,15 @@
# under the License. # under the License.
import mock import mock
from oslo_utils import timeutils
import six
import webob import webob
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute import create_backup \ from nova.api.openstack.compute import create_backup \
as create_backup_v21 as create_backup_v21
from nova.compute import api from nova.compute import api
from nova.compute import utils as compute_utils
from nova import exception from nova import exception
from nova import test from nova import test
from nova.tests.unit.api.openstack.compute import admin_only_action_common 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) self.req, fakes.FAKE_UUID, body=body)
@mock.patch.object(common, 'check_img_metadata_properties_quota') @mock.patch.object(common, 'check_img_metadata_properties_quota')
@mock.patch.object(api.API, 'backup') @mock.patch.object(compute_utils, 'is_volume_backed_instance',
def test_backup_volume_backed_instance(self, mock_backup, return_value=True)
def test_backup_volume_backed_instance(self, mock_is_volume_backed,
mock_check_image): mock_check_image):
body = { body = {
'createBackup': { '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 instance.image_ref = None
self.mock_get.return_value = instance self.mock_get.return_value = instance
mock_backup.side_effect = exception.InvalidRequest()
self.assertRaises(webob.exc.HTTPBadRequest, ex = self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._create_backup, self.controller._create_backup,
self.req, instance['uuid'], body=body) self.req, instance['uuid'], body=body)
mock_check_image.assert_called_once_with(self.context, {}) mock_check_image.assert_called_once_with(self.context, {})
mock_backup.assert_called_once_with(self.context, instance, 'BackupMe', mock_is_volume_backed.assert_called_once_with(self.context, instance)
'daily', 3, self.assertIn('Backup is not supported for volume-backed instances',
extra_properties={}) six.text_type(ex))
class CreateBackupPolicyEnforcementv21(test.NoDBTestCase): class CreateBackupPolicyEnforcementv21(test.NoDBTestCase):