Add support for volume backups
Implements support for the volume backup api added to cinder in https://review.openstack.org/19468. This is a resubmit of the expired change https://review.openstack.org/25299 with the following changes: * Added unit tests for backups (v1 and v2) * Changed references in backup code to display_name and display_description to name and description respectively * Removed links from backup-show output * Added object_count to _translate_backup_keys * Removed unneccesary items from _translate_backup_keys * Fixed backups docstrings including removing references to swift. Adds backup-create, backup-delete, backup-list, backup-restore and backup-show to both the v1 and v2 clients, since the volume backup extension is available via both APIs. Change-Id: I197384f1c2fd2af641d207a5f4dba0dfbc5c681a
This commit is contained in:
parent
80d0f74c81
commit
cc8dd55264
@ -5,6 +5,8 @@ from cinderclient.v1 import quotas
|
||||
from cinderclient.v1 import volumes
|
||||
from cinderclient.v1 import volume_snapshots
|
||||
from cinderclient.v1 import volume_types
|
||||
from cinderclient.v1 import volume_backups
|
||||
from cinderclient.v1 import volume_backups_restore
|
||||
|
||||
|
||||
class Client(object):
|
||||
@ -41,6 +43,8 @@ class Client(object):
|
||||
self.volume_types = volume_types.VolumeTypeManager(self)
|
||||
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
||||
self.quotas = quotas.QuotaSetManager(self)
|
||||
self.backups = volume_backups.VolumeBackupManager(self)
|
||||
self.restores = volume_backups_restore.VolumeBackupRestoreManager(self)
|
||||
|
||||
# Add in any extensions...
|
||||
if extensions:
|
||||
|
@ -66,6 +66,11 @@ def _find_volume_snapshot(cs, snapshot):
|
||||
return utils.find_resource(cs.volume_snapshots, snapshot)
|
||||
|
||||
|
||||
def _find_backup(cs, backup):
|
||||
"""Get a backup by ID."""
|
||||
return utils.find_resource(cs.backups, backup)
|
||||
|
||||
|
||||
def _print_volume(volume):
|
||||
utils.print_dict(volume._info)
|
||||
|
||||
@ -74,8 +79,7 @@ def _print_volume_snapshot(snapshot):
|
||||
utils.print_dict(snapshot._info)
|
||||
|
||||
|
||||
def _translate_volume_keys(collection):
|
||||
convert = [('displayName', 'display_name'), ('volumeType', 'volume_type')]
|
||||
def _translate_keys(collection, convert):
|
||||
for item in collection:
|
||||
keys = item.__dict__.keys()
|
||||
for from_key, to_key in convert:
|
||||
@ -83,13 +87,14 @@ def _translate_volume_keys(collection):
|
||||
setattr(item, to_key, item._info[from_key])
|
||||
|
||||
|
||||
def _translate_volume_keys(collection):
|
||||
convert = [('displayName', 'display_name'), ('volumeType', 'volume_type')]
|
||||
_translate_keys(collection, convert)
|
||||
|
||||
|
||||
def _translate_volume_snapshot_keys(collection):
|
||||
convert = [('displayName', 'display_name'), ('volumeId', 'volume_id')]
|
||||
for item in collection:
|
||||
keys = item.__dict__.keys()
|
||||
for from_key, to_key in convert:
|
||||
if from_key in keys and to_key not in keys:
|
||||
setattr(item, to_key, item._info[from_key])
|
||||
_translate_keys(collection, convert)
|
||||
|
||||
|
||||
def _extract_metadata(args):
|
||||
@ -648,3 +653,67 @@ def do_upload_to_image(cs, args):
|
||||
args.image_name,
|
||||
args.container_format,
|
||||
args.disk_format)
|
||||
|
||||
|
||||
@utils.arg('volume', metavar='<volume>',
|
||||
help='ID of the volume to backup.')
|
||||
@utils.arg('--container', metavar='<container>',
|
||||
help='Optional Backup container name. (Default=None)',
|
||||
default=None)
|
||||
@utils.arg('--display-name', metavar='<display-name>',
|
||||
help='Optional backup name. (Default=None)',
|
||||
default=None)
|
||||
@utils.arg('--display-description', metavar='<display-description>',
|
||||
help='Optional backup description. (Default=None)',
|
||||
default=None)
|
||||
@utils.service_type('volume')
|
||||
def do_backup_create(cs, args):
|
||||
"""Creates a backup."""
|
||||
cs.backups.create(args.volume,
|
||||
args.container,
|
||||
args.display_name,
|
||||
args.display_description)
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>', help='ID of the backup.')
|
||||
@utils.service_type('volume')
|
||||
def do_backup_show(cs, args):
|
||||
"""Show details about a backup."""
|
||||
backup = _find_backup(cs, args.backup)
|
||||
info = dict()
|
||||
info.update(backup._info)
|
||||
|
||||
if 'links' in info:
|
||||
info.pop('links')
|
||||
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volume')
|
||||
def do_backup_list(cs, args):
|
||||
"""List all the backups."""
|
||||
backups = cs.backups.list()
|
||||
columns = ['ID', 'Volume ID', 'Status', 'Name', 'Size', 'Object Count',
|
||||
'Container']
|
||||
utils.print_list(backups, columns)
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>',
|
||||
help='ID of the backup to delete.')
|
||||
@utils.service_type('volume')
|
||||
def do_backup_delete(cs, args):
|
||||
"""Remove a backup."""
|
||||
backup = _find_backup(cs, args.backup)
|
||||
backup.delete()
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>',
|
||||
help='ID of the backup to restore.')
|
||||
@utils.arg('--volume-id', metavar='<volume-id>',
|
||||
help='Optional ID of the volume to restore to.',
|
||||
default=None)
|
||||
@utils.service_type('volume')
|
||||
def do_backup_restore(cs, args):
|
||||
"""Restore a backup."""
|
||||
cs.restores.restore(args.backup,
|
||||
args.volume_id)
|
||||
|
76
cinderclient/v1/volume_backups.py
Normal file
76
cinderclient/v1/volume_backups.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Volume Backups interface (1.1 extension).
|
||||
"""
|
||||
|
||||
from cinderclient import base
|
||||
|
||||
|
||||
class VolumeBackup(base.Resource):
|
||||
"""A volume backup is a block level backup of a volume."""
|
||||
def __repr__(self):
|
||||
return "<VolumeBackup: %s>" % self.id
|
||||
|
||||
def delete(self):
|
||||
"""Delete this volume backup."""
|
||||
return self.manager.delete(self)
|
||||
|
||||
|
||||
class VolumeBackupManager(base.ManagerWithFind):
|
||||
"""Manage :class:`VolumeBackup` resources."""
|
||||
resource_class = VolumeBackup
|
||||
|
||||
def create(self, volume_id, container=None,
|
||||
name=None, description=None):
|
||||
"""Create a volume backup.
|
||||
|
||||
:param volume_id: The ID of the volume to backup.
|
||||
:param container: The name of the backup service container.
|
||||
:param name: The name of the backup.
|
||||
:param description: The description of the backup.
|
||||
:rtype: :class:`VolumeBackup`
|
||||
"""
|
||||
body = {'backup': {'volume_id': volume_id,
|
||||
'container': container,
|
||||
'name': name,
|
||||
'description': description}}
|
||||
return self._create('/backups', body, 'backup')
|
||||
|
||||
def get(self, backup_id):
|
||||
"""Show details of a volume backup.
|
||||
|
||||
:param backup_id: The ID of the backup to display.
|
||||
:rtype: :class:`VolumeBackup`
|
||||
"""
|
||||
return self._get("/backups/%s" % backup_id, "backup")
|
||||
|
||||
def list(self, detailed=True):
|
||||
"""Get a list of all volume backups.
|
||||
|
||||
:rtype: list of :class:`VolumeBackup`
|
||||
"""
|
||||
if detailed is True:
|
||||
return self._list("/backups/detail", "backups")
|
||||
else:
|
||||
return self._list("/backups", "backups")
|
||||
|
||||
def delete(self, backup):
|
||||
"""Delete a volume backup.
|
||||
|
||||
:param backup: The :class:`VolumeBackup` to delete.
|
||||
"""
|
||||
self._delete("/backups/%s" % base.getid(backup))
|
43
cinderclient/v1/volume_backups_restore.py
Normal file
43
cinderclient/v1/volume_backups_restore.py
Normal file
@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Volume Backups Restore interface (1.1 extension).
|
||||
|
||||
This is part of the Volume Backups interface.
|
||||
"""
|
||||
|
||||
from cinderclient import base
|
||||
|
||||
|
||||
class VolumeBackupsRestore(base.Resource):
|
||||
"""A Volume Backups Restore represents a restore operation."""
|
||||
def __repr__(self):
|
||||
return "<VolumeBackupsRestore: %s>" % self.id
|
||||
|
||||
|
||||
class VolumeBackupRestoreManager(base.ManagerWithFind):
|
||||
"""Manage :class:`VolumeBackupsRestore` resources."""
|
||||
resource_class = VolumeBackupsRestore
|
||||
|
||||
def restore(self, backup_id, volume_id=None):
|
||||
"""Restore a backup to a volume.
|
||||
|
||||
:param backup_id: The ID of the backup to restore.
|
||||
:param volume_id: The ID of the volume to restore the backup to.
|
||||
:rtype: :class:`Restore`
|
||||
"""
|
||||
body = {'restore': {'volume_id': volume_id}}
|
||||
return self._create("/backups/%s/restore" % backup_id,
|
||||
body, "restore")
|
@ -5,6 +5,8 @@ from cinderclient.v2 import quotas
|
||||
from cinderclient.v2 import volumes
|
||||
from cinderclient.v2 import volume_snapshots
|
||||
from cinderclient.v2 import volume_types
|
||||
from cinderclient.v2 import volume_backups
|
||||
from cinderclient.v2 import volume_backups_restore
|
||||
|
||||
|
||||
class Client(object):
|
||||
@ -39,6 +41,8 @@ class Client(object):
|
||||
self.volume_types = volume_types.VolumeTypeManager(self)
|
||||
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
||||
self.quotas = quotas.QuotaSetManager(self)
|
||||
self.backups = volume_backups.VolumeBackupManager(self)
|
||||
self.restores = volume_backups_restore.VolumeBackupRestoreManager(self)
|
||||
|
||||
# Add in any extensions...
|
||||
if extensions:
|
||||
|
@ -62,12 +62,16 @@ def _find_volume_snapshot(cs, snapshot):
|
||||
return utils.find_resource(cs.volume_snapshots, snapshot)
|
||||
|
||||
|
||||
def _find_backup(cs, backup):
|
||||
"""Get a backup by ID."""
|
||||
return utils.find_resource(cs.backups, backup)
|
||||
|
||||
|
||||
def _print_volume_snapshot(snapshot):
|
||||
utils.print_dict(snapshot._info)
|
||||
|
||||
|
||||
def _translate_volume_keys(collection):
|
||||
convert = [('volumeType', 'volume_type')]
|
||||
def _translate_keys(collection, convert):
|
||||
for item in collection:
|
||||
keys = item.__dict__.keys()
|
||||
for from_key, to_key in convert:
|
||||
@ -75,13 +79,14 @@ def _translate_volume_keys(collection):
|
||||
setattr(item, to_key, item._info[from_key])
|
||||
|
||||
|
||||
def _translate_volume_keys(collection):
|
||||
convert = [('volumeType', 'volume_type')]
|
||||
_translate_keys(collection, convert)
|
||||
|
||||
|
||||
def _translate_volume_snapshot_keys(collection):
|
||||
convert = [('volumeId', 'volume_id')]
|
||||
for item in collection:
|
||||
keys = item.__dict__.keys()
|
||||
for from_key, to_key in convert:
|
||||
if from_key in keys and to_key not in keys:
|
||||
setattr(item, to_key, item._info[from_key])
|
||||
_translate_keys(collection, convert)
|
||||
|
||||
|
||||
def _extract_metadata(args):
|
||||
@ -703,3 +708,78 @@ def do_upload_to_image(cs, args):
|
||||
args.image_name,
|
||||
args.container_format,
|
||||
args.disk_format)
|
||||
|
||||
|
||||
@utils.arg('volume', metavar='<volume>',
|
||||
help='ID of the volume to backup.')
|
||||
@utils.arg('--container', metavar='<container>',
|
||||
help='Optional backup container name. (Default=None)',
|
||||
default=None)
|
||||
@utils.arg('--display-name',
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--name', metavar='<name>',
|
||||
help='Optional backup name. (Default=None)',
|
||||
default=None)
|
||||
@utils.arg('--display-description',
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--description',
|
||||
metavar='<description>',
|
||||
default=None,
|
||||
help='Options backup description (Default=None)')
|
||||
@utils.service_type('volume')
|
||||
def do_backup_create(cs, args):
|
||||
"""Creates a backup."""
|
||||
if args.display_name is not None:
|
||||
args.name = args.display_name
|
||||
|
||||
if args.display_description is not None:
|
||||
args.description = args.display_description
|
||||
|
||||
cs.backups.create(args.volume,
|
||||
args.container,
|
||||
args.name,
|
||||
args.description)
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>', help='ID of the backup.')
|
||||
@utils.service_type('volume')
|
||||
def do_backup_show(cs, args):
|
||||
"""Show details about a backup."""
|
||||
backup = _find_backup(cs, args.backup)
|
||||
info = dict()
|
||||
info.update(backup._info)
|
||||
|
||||
if 'links' in info:
|
||||
info.pop('links')
|
||||
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volume')
|
||||
def do_backup_list(cs, args):
|
||||
"""List all the backups."""
|
||||
backups = cs.backups.list()
|
||||
columns = ['ID', 'Volume ID', 'Status', 'Name', 'Size', 'Object Count',
|
||||
'Container']
|
||||
utils.print_list(backups, columns)
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>',
|
||||
help='ID of the backup to delete.')
|
||||
@utils.service_type('volume')
|
||||
def do_backup_delete(cs, args):
|
||||
"""Remove a backup."""
|
||||
backup = _find_backup(cs, args.backup)
|
||||
backup.delete()
|
||||
|
||||
|
||||
@utils.arg('backup', metavar='<backup>',
|
||||
help='ID of the backup to restore.')
|
||||
@utils.arg('--volume-id', metavar='<volume-id>',
|
||||
help='Optional ID of the volume to restore to.',
|
||||
default=None)
|
||||
@utils.service_type('volume')
|
||||
def do_backup_restore(cs, args):
|
||||
"""Restore a backup."""
|
||||
cs.restores.restore(args.backup,
|
||||
args.volume_id)
|
||||
|
76
cinderclient/v2/volume_backups.py
Normal file
76
cinderclient/v2/volume_backups.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Volume Backups interface (1.1 extension).
|
||||
"""
|
||||
|
||||
from cinderclient import base
|
||||
|
||||
|
||||
class VolumeBackup(base.Resource):
|
||||
"""A volume backup is a block level backup of a volume."""
|
||||
def __repr__(self):
|
||||
return "<VolumeBackup: %s>" % self.id
|
||||
|
||||
def delete(self):
|
||||
"""Delete this volume backup."""
|
||||
return self.manager.delete(self)
|
||||
|
||||
|
||||
class VolumeBackupManager(base.ManagerWithFind):
|
||||
"""Manage :class:`VolumeBackup` resources."""
|
||||
resource_class = VolumeBackup
|
||||
|
||||
def create(self, volume_id, container=None,
|
||||
name=None, description=None):
|
||||
"""Create a volume backup.
|
||||
|
||||
:param volume_id: The ID of the volume to backup.
|
||||
:param container: The name of the backup service container.
|
||||
:param name: The name of the backup.
|
||||
:param description: The description of the backup.
|
||||
:rtype: :class:`VolumeBackup`
|
||||
"""
|
||||
body = {'backup': {'volume_id': volume_id,
|
||||
'container': container,
|
||||
'name': name,
|
||||
'description': description}}
|
||||
return self._create('/backups', body, 'backup')
|
||||
|
||||
def get(self, backup_id):
|
||||
"""Show details of a volume backup.
|
||||
|
||||
:param backup_id: The ID of the backup to display.
|
||||
:rtype: :class:`VolumeBackup`
|
||||
"""
|
||||
return self._get("/backups/%s" % backup_id, "backup")
|
||||
|
||||
def list(self, detailed=True):
|
||||
"""Get a list of all volume backups.
|
||||
|
||||
:rtype: list of :class:`VolumeBackup`
|
||||
"""
|
||||
if detailed is True:
|
||||
return self._list("/backups/detail", "backups")
|
||||
else:
|
||||
return self._list("/backups", "backups")
|
||||
|
||||
def delete(self, backup):
|
||||
"""Delete a volume backup.
|
||||
|
||||
:param backup: The :class:`VolumeBackup` to delete.
|
||||
"""
|
||||
self._delete("/backups/%s" % base.getid(backup))
|
43
cinderclient/v2/volume_backups_restore.py
Normal file
43
cinderclient/v2/volume_backups_restore.py
Normal file
@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Volume Backups Restore interface (1.1 extension).
|
||||
|
||||
This is part of the Volume Backups interface.
|
||||
"""
|
||||
|
||||
from cinderclient import base
|
||||
|
||||
|
||||
class VolumeBackupsRestore(base.Resource):
|
||||
"""A Volume Backups Restore represents a restore operation."""
|
||||
def __repr__(self):
|
||||
return "<VolumeBackupsRestore: %s>" % self.id
|
||||
|
||||
|
||||
class VolumeBackupRestoreManager(base.ManagerWithFind):
|
||||
"""Manage :class:`VolumeBackupsRestore` resources."""
|
||||
resource_class = VolumeBackupsRestore
|
||||
|
||||
def restore(self, backup_id, volume_id=None):
|
||||
"""Restore a backup to a volume.
|
||||
|
||||
:param backup_id: The ID of the backup to restore.
|
||||
:param volume_id: The ID of the volume to restore the backup to.
|
||||
:rtype: :class:`Restore`
|
||||
"""
|
||||
body = {'restore': {'volume_id': volume_id}}
|
||||
return self._create("/backups/%s/restore" % backup_id,
|
||||
body, "restore")
|
@ -57,6 +57,60 @@ def _stub_snapshot(**kwargs):
|
||||
return snapshot
|
||||
|
||||
|
||||
def _self_href(base_uri, tenant_id, backup_id):
|
||||
return '%s/v1/%s/backups/%s' % (base_uri, tenant_id, backup_id)
|
||||
|
||||
|
||||
def _bookmark_href(base_uri, tenant_id, backup_id):
|
||||
return '%s/%s/backups/%s' % (base_uri, tenant_id, backup_id)
|
||||
|
||||
|
||||
def _stub_backup_full(id, base_uri, tenant_id):
|
||||
return {
|
||||
'id': id,
|
||||
'name': 'backup',
|
||||
'description': 'nightly backup',
|
||||
'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b',
|
||||
'container': 'volumebackups',
|
||||
'object_count': 220,
|
||||
'size': 10,
|
||||
'availability_zone': 'az1',
|
||||
'created_at': '2013-04-12T08:16:37.000000',
|
||||
'status': 'available',
|
||||
'links': [
|
||||
{
|
||||
'href': _self_href(base_uri, tenant_id, id),
|
||||
'rel': 'self'
|
||||
},
|
||||
{
|
||||
'href': _bookmark_href(base_uri, tenant_id, id),
|
||||
'rel': 'bookmark'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _stub_backup(id, base_uri, tenant_id):
|
||||
return {
|
||||
'id': id,
|
||||
'name': 'backup',
|
||||
'links': [
|
||||
{
|
||||
'href': _self_href(base_uri, tenant_id, id),
|
||||
'rel': 'self'
|
||||
},
|
||||
{
|
||||
'href': _bookmark_href(base_uri, tenant_id, id),
|
||||
'rel': 'bookmark'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _stub_restore():
|
||||
return {'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b'}
|
||||
|
||||
|
||||
class FakeClient(fakes.FakeClient, client.Client):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -313,3 +367,38 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
},
|
||||
]
|
||||
return (200, {}, {"extensions": exts, })
|
||||
|
||||
#
|
||||
# VolumeBackups
|
||||
#
|
||||
|
||||
def get_backups_76a17945_3c6f_435c_975b_b5685db10b62(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
return (200, {},
|
||||
{'backup': _stub_backup_full(backup1, base_uri, tenant_id)})
|
||||
|
||||
def get_backups_detail(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
backup2 = 'd09534c6-08b8-4441-9e87-8976f3a8f699'
|
||||
return (200, {},
|
||||
{'backups': [
|
||||
_stub_backup_full(backup1, base_uri, tenant_id),
|
||||
_stub_backup_full(backup2, base_uri, tenant_id)]})
|
||||
|
||||
def delete_backups_76a17945_3c6f_435c_975b_b5685db10b62(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def post_backups(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
return (202, {},
|
||||
{'backup': _stub_backup(backup1, base_uri, tenant_id)})
|
||||
|
||||
def post_backups_76a17945_3c6f_435c_975b_b5685db10b62_restore(self, **kw):
|
||||
return (200, {},
|
||||
{'restore': _stub_restore()})
|
||||
|
53
tests/v1/test_volume_backups.py
Normal file
53
tests/v1/test_volume_backups.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 tests import utils
|
||||
from tests.v1 import fakes
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
|
||||
|
||||
class VolumeBackupsTest(utils.TestCase):
|
||||
|
||||
def test_create(self):
|
||||
cs.backups.create('2b695faf-b963-40c8-8464-274008fbcef4')
|
||||
cs.assert_called('POST', '/backups')
|
||||
|
||||
def test_get(self):
|
||||
backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
cs.backups.get(backup_id)
|
||||
cs.assert_called('GET', '/backups/%s' % backup_id)
|
||||
|
||||
def test_list(self):
|
||||
cs.backups.list()
|
||||
cs.assert_called('GET', '/backups/detail')
|
||||
|
||||
def test_delete(self):
|
||||
b = cs.backups.list()[0]
|
||||
b.delete()
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.backups.delete('76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.backups.delete(b)
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
|
||||
def test_restore(self):
|
||||
backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
cs.restores.restore(backup_id)
|
||||
cs.assert_called('POST', '/backups/%s/restore' % backup_id)
|
@ -64,6 +64,60 @@ def _stub_snapshot(**kwargs):
|
||||
return snapshot
|
||||
|
||||
|
||||
def _self_href(base_uri, tenant_id, backup_id):
|
||||
return '%s/v2/%s/backups/%s' % (base_uri, tenant_id, backup_id)
|
||||
|
||||
|
||||
def _bookmark_href(base_uri, tenant_id, backup_id):
|
||||
return '%s/%s/backups/%s' % (base_uri, tenant_id, backup_id)
|
||||
|
||||
|
||||
def _stub_backup_full(id, base_uri, tenant_id):
|
||||
return {
|
||||
'id': id,
|
||||
'name': 'backup',
|
||||
'description': 'nightly backup',
|
||||
'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b',
|
||||
'container': 'volumebackups',
|
||||
'object_count': 220,
|
||||
'size': 10,
|
||||
'availability_zone': 'az1',
|
||||
'created_at': '2013-04-12T08:16:37.000000',
|
||||
'status': 'available',
|
||||
'links': [
|
||||
{
|
||||
'href': _self_href(base_uri, tenant_id, id),
|
||||
'rel': 'self'
|
||||
},
|
||||
{
|
||||
'href': _bookmark_href(base_uri, tenant_id, id),
|
||||
'rel': 'bookmark'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _stub_backup(id, base_uri, tenant_id):
|
||||
return {
|
||||
'id': id,
|
||||
'name': 'backup',
|
||||
'links': [
|
||||
{
|
||||
'href': _self_href(base_uri, tenant_id, id),
|
||||
'rel': 'self'
|
||||
},
|
||||
{
|
||||
'href': _bookmark_href(base_uri, tenant_id, id),
|
||||
'rel': 'bookmark'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _stub_restore():
|
||||
return {'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b'}
|
||||
|
||||
|
||||
class FakeClient(fakes.FakeClient, client.Client):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -320,3 +374,38 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
},
|
||||
]
|
||||
return (200, {}, {"extensions": exts, })
|
||||
|
||||
#
|
||||
# VolumeBackups
|
||||
#
|
||||
|
||||
def get_backups_76a17945_3c6f_435c_975b_b5685db10b62(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
return (200, {},
|
||||
{'backup': _stub_backup_full(backup1, base_uri, tenant_id)})
|
||||
|
||||
def get_backups_detail(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
backup2 = 'd09534c6-08b8-4441-9e87-8976f3a8f699'
|
||||
return (200, {},
|
||||
{'backups': [
|
||||
_stub_backup_full(backup1, base_uri, tenant_id),
|
||||
_stub_backup_full(backup2, base_uri, tenant_id)]})
|
||||
|
||||
def delete_backups_76a17945_3c6f_435c_975b_b5685db10b62(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def post_backups(self, **kw):
|
||||
base_uri = 'http://localhost:8776'
|
||||
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
|
||||
backup1 = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
return (202, {},
|
||||
{'backup': _stub_backup(backup1, base_uri, tenant_id)})
|
||||
|
||||
def post_backups_76a17945_3c6f_435c_975b_b5685db10b62_restore(self, **kw):
|
||||
return (200, {},
|
||||
{'restore': _stub_restore()})
|
||||
|
53
tests/v2/test_volume_backups.py
Normal file
53
tests/v2/test_volume_backups.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 tests import utils
|
||||
from tests.v2 import fakes
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
|
||||
|
||||
class VolumeBackupsTest(utils.TestCase):
|
||||
|
||||
def test_create(self):
|
||||
cs.backups.create('2b695faf-b963-40c8-8464-274008fbcef4')
|
||||
cs.assert_called('POST', '/backups')
|
||||
|
||||
def test_get(self):
|
||||
backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
cs.backups.get(backup_id)
|
||||
cs.assert_called('GET', '/backups/%s' % backup_id)
|
||||
|
||||
def test_list(self):
|
||||
cs.backups.list()
|
||||
cs.assert_called('GET', '/backups/detail')
|
||||
|
||||
def test_delete(self):
|
||||
b = cs.backups.list()[0]
|
||||
b.delete()
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.backups.delete('76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
cs.backups.delete(b)
|
||||
cs.assert_called('DELETE',
|
||||
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
|
||||
|
||||
def test_restore(self):
|
||||
backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
|
||||
cs.restores.restore(backup_id)
|
||||
cs.assert_called('POST', '/backups/%s/restore' % backup_id)
|
Loading…
Reference in New Issue
Block a user