Volume.backup API attr name fixes
Creating backup requires "incremental" attribute, while GETs use "is_incremental". Fix that and add functional test for adding incremental backup. Change-Id: I9a4951132645756e81a618d84482614acf69ec39
This commit is contained in:
parent
b403c7b9c6
commit
fc3b3d09ef
@ -76,6 +76,64 @@ class Backup(resource.Resource):
|
||||
#: The UUID of the volume.
|
||||
volume_id = resource.Body("volume_id")
|
||||
|
||||
def create(self, session, prepend_key=True, base_path=None, **params):
|
||||
"""Create a remote resource based on this instance.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:type session: :class:`~keystoneauth1.adapter.Adapter`
|
||||
:param prepend_key: A boolean indicating whether the resource_key
|
||||
should be prepended in a resource creation
|
||||
request. Default to True.
|
||||
:param str base_path: Base part of the URI for creating resources, if
|
||||
different from
|
||||
:data:`~openstack.resource.Resource.base_path`.
|
||||
:param dict params: Additional params to pass.
|
||||
:return: This :class:`Resource` instance.
|
||||
:raises: :exc:`~openstack.exceptions.MethodNotSupported` if
|
||||
:data:`Resource.allow_create` is not set to ``True``.
|
||||
"""
|
||||
if not self.allow_create:
|
||||
raise exceptions.MethodNotSupported(self, "create")
|
||||
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'create')
|
||||
requires_id = (self.create_requires_id
|
||||
if self.create_requires_id is not None
|
||||
else self.create_method == 'PUT')
|
||||
|
||||
if self.create_exclude_id_from_body:
|
||||
self._body._dirty.discard("id")
|
||||
|
||||
if self.create_method == 'POST':
|
||||
request = self._prepare_request(requires_id=requires_id,
|
||||
prepend_key=prepend_key,
|
||||
base_path=base_path)
|
||||
# NOTE(gtema) this is a funny example of when attribute
|
||||
# is called "incremental" on create, "is_incremental" on get
|
||||
# and use of "alias" or "aka" is not working for such conflict,
|
||||
# since our preferred attr name is exactly "is_incremental"
|
||||
body = request.body
|
||||
if 'is_incremental' in body['backup']:
|
||||
body['backup']['incremental'] = \
|
||||
body['backup'].pop('is_incremental')
|
||||
response = session.post(request.url,
|
||||
json=request.body, headers=request.headers,
|
||||
microversion=microversion, params=params)
|
||||
else:
|
||||
# Just for safety of the implementation (since PUT removed)
|
||||
raise exceptions.ResourceFailure(
|
||||
msg="Invalid create method: %s" % self.create_method)
|
||||
|
||||
has_body = (self.has_body if self.create_returns_body is None
|
||||
else self.create_returns_body)
|
||||
self.microversion = microversion
|
||||
self._translate_response(response, has_body=has_body)
|
||||
# direct comparision to False since we need to rule out None
|
||||
if self.has_body and self.create_returns_body is False:
|
||||
# fetch the body if it's required but not returned by create
|
||||
return self.fetch(session)
|
||||
return self
|
||||
|
||||
def restore(self, session, volume_id=None, name=None):
|
||||
"""Restore current backup to volume
|
||||
|
||||
|
@ -86,6 +86,64 @@ class Backup(resource.Resource):
|
||||
#: The UUID of the volume.
|
||||
volume_id = resource.Body("volume_id")
|
||||
|
||||
def create(self, session, prepend_key=True, base_path=None, **params):
|
||||
"""Create a remote resource based on this instance.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:type session: :class:`~keystoneauth1.adapter.Adapter`
|
||||
:param prepend_key: A boolean indicating whether the resource_key
|
||||
should be prepended in a resource creation
|
||||
request. Default to True.
|
||||
:param str base_path: Base part of the URI for creating resources, if
|
||||
different from
|
||||
:data:`~openstack.resource.Resource.base_path`.
|
||||
:param dict params: Additional params to pass.
|
||||
:return: This :class:`Resource` instance.
|
||||
:raises: :exc:`~openstack.exceptions.MethodNotSupported` if
|
||||
:data:`Resource.allow_create` is not set to ``True``.
|
||||
"""
|
||||
if not self.allow_create:
|
||||
raise exceptions.MethodNotSupported(self, "create")
|
||||
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'create')
|
||||
requires_id = (self.create_requires_id
|
||||
if self.create_requires_id is not None
|
||||
else self.create_method == 'PUT')
|
||||
|
||||
if self.create_exclude_id_from_body:
|
||||
self._body._dirty.discard("id")
|
||||
|
||||
if self.create_method == 'POST':
|
||||
request = self._prepare_request(requires_id=requires_id,
|
||||
prepend_key=prepend_key,
|
||||
base_path=base_path)
|
||||
# NOTE(gtema) this is a funny example of when attribute
|
||||
# is called "incremental" on create, "is_incremental" on get
|
||||
# and use of "alias" or "aka" is not working for such conflict,
|
||||
# since our preferred attr name is exactly "is_incremental"
|
||||
body = request.body
|
||||
if 'is_incremental' in body['backup']:
|
||||
body['backup']['incremental'] = \
|
||||
body['backup'].pop('is_incremental')
|
||||
response = session.post(request.url,
|
||||
json=request.body, headers=request.headers,
|
||||
microversion=microversion, params=params)
|
||||
else:
|
||||
# Just for safety of the implementation (since PUT removed)
|
||||
raise exceptions.ResourceFailure(
|
||||
msg="Invalid create method: %s" % self.create_method)
|
||||
|
||||
has_body = (self.has_body if self.create_returns_body is None
|
||||
else self.create_returns_body)
|
||||
self.microversion = microversion
|
||||
self._translate_response(response, has_body=has_body)
|
||||
# direct comparision to False since we need to rule out None
|
||||
if self.has_body and self.create_returns_body is False:
|
||||
# fetch the body if it's required but not returned by create
|
||||
return self.fetch(session)
|
||||
return self
|
||||
|
||||
def restore(self, session, volume_id=None, name=None):
|
||||
"""Restore current backup to volume
|
||||
|
||||
|
@ -42,7 +42,8 @@ class TestBackup(base.BaseBlockStorageTest):
|
||||
|
||||
backup = self.user_cloud.block_storage.create_backup(
|
||||
name=self.BACKUP_NAME,
|
||||
volume_id=volume.id)
|
||||
volume_id=volume.id,
|
||||
is_incremental=False)
|
||||
self.user_cloud.block_storage.wait_for_status(
|
||||
backup,
|
||||
status='available',
|
||||
@ -66,3 +67,22 @@ class TestBackup(base.BaseBlockStorageTest):
|
||||
def test_get(self):
|
||||
sot = self.user_cloud.block_storage.get_backup(self.BACKUP_ID)
|
||||
self.assertEqual(self.BACKUP_NAME, sot.name)
|
||||
self.assertEqual(False, sot.is_incremental)
|
||||
|
||||
def test_create_incremental(self):
|
||||
incremental_backup = self.user_cloud.block_storage.create_backup(
|
||||
name=self.getUniqueString(),
|
||||
volume_id=self.VOLUME_ID,
|
||||
is_incremental=True)
|
||||
self.user_cloud.block_storage.wait_for_status(
|
||||
incremental_backup,
|
||||
status='available',
|
||||
failures=['error'],
|
||||
interval=5,
|
||||
wait=self._wait_for_timeout)
|
||||
self.assertEqual(True, incremental_backup.is_incremental)
|
||||
self.user_cloud.block_storage.delete_backup(
|
||||
incremental_backup.id,
|
||||
ignore_missing=False)
|
||||
self.user_cloud.block_storage.wait_for_delete(
|
||||
incremental_backup)
|
||||
|
@ -52,7 +52,7 @@ class TestBackup(base.TestCase):
|
||||
self.sess = mock.Mock(spec=adapter.Adapter)
|
||||
self.sess.get = mock.Mock()
|
||||
self.sess.post = mock.Mock(return_value=self.resp)
|
||||
self.sess.default_microversion = mock.Mock(return_value='')
|
||||
self.sess.default_microversion = None
|
||||
|
||||
def test_basic(self):
|
||||
sot = backup.Backup(BACKUP)
|
||||
@ -98,6 +98,42 @@ class TestBackup(base.TestCase):
|
||||
self.assertEqual(BACKUP["has_dependent_backups"],
|
||||
sot.has_dependent_backups)
|
||||
|
||||
def test_create_incremental(self):
|
||||
sot = backup.Backup(is_incremental=True)
|
||||
sot2 = backup.Backup(is_incremental=False)
|
||||
|
||||
create_response = mock.Mock()
|
||||
create_response.status_code = 200
|
||||
create_response.json.return_value = {}
|
||||
create_response.headers = {}
|
||||
self.sess.post.return_value = create_response
|
||||
|
||||
sot.create(self.sess)
|
||||
self.sess.post.assert_called_with(
|
||||
'/backups',
|
||||
headers={},
|
||||
json={
|
||||
'backup': {
|
||||
'incremental': True,
|
||||
}
|
||||
},
|
||||
microversion=None,
|
||||
params={}
|
||||
)
|
||||
|
||||
sot2.create(self.sess)
|
||||
self.sess.post.assert_called_with(
|
||||
'/backups',
|
||||
headers={},
|
||||
json={
|
||||
'backup': {
|
||||
'incremental': False,
|
||||
}
|
||||
},
|
||||
microversion=None,
|
||||
params={}
|
||||
)
|
||||
|
||||
def test_restore(self):
|
||||
sot = backup.Backup(**BACKUP)
|
||||
|
||||
|
@ -55,7 +55,7 @@ class TestBackup(base.TestCase):
|
||||
self.sess = mock.Mock(spec=adapter.Adapter)
|
||||
self.sess.get = mock.Mock()
|
||||
self.sess.post = mock.Mock(return_value=self.resp)
|
||||
self.sess.default_microversion = mock.Mock(return_value='')
|
||||
self.sess.default_microversion = None
|
||||
|
||||
def test_basic(self):
|
||||
sot = backup.Backup(BACKUP)
|
||||
@ -105,6 +105,42 @@ class TestBackup(base.TestCase):
|
||||
self.assertEqual(BACKUP['metadata'], sot.metadata)
|
||||
self.assertEqual(BACKUP['user_id'], sot.user_id)
|
||||
|
||||
def test_create_incremental(self):
|
||||
sot = backup.Backup(is_incremental=True)
|
||||
sot2 = backup.Backup(is_incremental=False)
|
||||
|
||||
create_response = mock.Mock()
|
||||
create_response.status_code = 200
|
||||
create_response.json.return_value = {}
|
||||
create_response.headers = {}
|
||||
self.sess.post.return_value = create_response
|
||||
|
||||
sot.create(self.sess)
|
||||
self.sess.post.assert_called_with(
|
||||
'/backups',
|
||||
headers={},
|
||||
json={
|
||||
'backup': {
|
||||
'incremental': True,
|
||||
}
|
||||
},
|
||||
microversion=None,
|
||||
params={}
|
||||
)
|
||||
|
||||
sot2.create(self.sess)
|
||||
self.sess.post.assert_called_with(
|
||||
'/backups',
|
||||
headers={},
|
||||
json={
|
||||
'backup': {
|
||||
'incremental': False,
|
||||
}
|
||||
},
|
||||
microversion=None,
|
||||
params={}
|
||||
)
|
||||
|
||||
def test_restore(self):
|
||||
sot = backup.Backup(**BACKUP)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user