summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
authorAmey Bhide <abhide@vmware.com>2015-06-03 15:05:18 -0700
committerAmey Bhide <abhide@vmware.com>2015-06-04 17:34:50 -0700
commit2fce8634119af42cef580f52b6b11e9c13326532 (patch)
tree19c6bf4756c2dd0311d13b9872dd0fa90a2b776f /openstackclient
parent7f658c0aca25dd705765bd28e0fa9ea504dc596b (diff)
downloadpython-openstackclient-2fce8634119af42cef580f52b6b11e9c13326532.tar.gz
Add support for volume backup v2 command
openstack backup create openstack backup list openstack backup restore Implements: blueprint volume-v2 Change-Id: I77965730065dd44f256c46bcc43c1e6a03b63145
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/tests/volume/v2/fakes.py7
-rw-r--r--openstackclient/tests/volume/v2/test_backup.py147
-rw-r--r--openstackclient/volume/v2/backup.py132
3 files changed, 285 insertions, 1 deletions
diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py
index 3eade391..d6c07b9f 100644
--- a/openstackclient/tests/volume/v2/fakes.py
+++ b/openstackclient/tests/volume/v2/fakes.py
@@ -93,6 +93,7 @@ backup_description = "fake description"
backup_object_count = None
backup_container = None
backup_size = 10
+backup_status = "error"
BACKUP = {
"id": backup_id,
@@ -101,7 +102,9 @@ BACKUP = {
"description": backup_description,
"object_count": backup_object_count,
"container": backup_container,
- "size": backup_size
+ "size": backup_size,
+ "status": backup_status,
+ "availability_zone": volume_availability_zone,
}
BACKUP_columns = tuple(sorted(BACKUP))
@@ -118,6 +121,8 @@ class FakeVolumeClient(object):
self.backups.resource_class = fakes.FakeResource(None, {})
self.volume_types = mock.Mock()
self.volume_types.resource_class = fakes.FakeResource(None, {})
+ self.restores = mock.Mock()
+ self.restores.resource_class = fakes.FakeResource(None, {})
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
diff --git a/openstackclient/tests/volume/v2/test_backup.py b/openstackclient/tests/volume/v2/test_backup.py
index e24cac3c..7af22e8a 100644
--- a/openstackclient/tests/volume/v2/test_backup.py
+++ b/openstackclient/tests/volume/v2/test_backup.py
@@ -26,6 +26,55 @@ class TestBackup(volume_fakes.TestVolume):
self.backups_mock = self.app.client_manager.volume.backups
self.backups_mock.reset_mock()
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+ self.restores_mock = self.app.client_manager.volume.restores
+ self.restores_mock.reset_mock()
+
+
+class TestBackupCreate(TestBackup):
+ def setUp(self):
+ super(TestBackupCreate, self).setUp()
+
+ self.volumes_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True
+ )
+
+ self.backups_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.BACKUP),
+ loaded=True
+ )
+ # Get the command object to test
+ self.cmd = backup.CreateBackup(self.app, None)
+
+ def test_backup_create(self):
+ arglist = [
+ volume_fakes.volume_id,
+ "--name", volume_fakes.backup_name,
+ "--description", volume_fakes.backup_description,
+ "--container", volume_fakes.backup_name
+ ]
+ verifylist = [
+ ("volume", volume_fakes.volume_id),
+ ("name", volume_fakes.backup_name),
+ ("description", volume_fakes.backup_description),
+ ("container", volume_fakes.backup_name)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.create.assert_called_with(
+ volume_fakes.volume_id,
+ container=volume_fakes.backup_name,
+ name=volume_fakes.backup_name,
+ description=volume_fakes.backup_description
+ )
+ self.assertEqual(columns, volume_fakes.BACKUP_columns)
+ self.assertEqual(data, volume_fakes.BACKUP_data)
class TestBackupShow(TestBackup):
@@ -80,3 +129,101 @@ class TestBackupDelete(TestBackup):
self.cmd.take_action(parsed_args)
self.backups_mock.delete.assert_called_with(volume_fakes.backup_id)
+
+
+class TestBackupRestore(TestBackup):
+ def setUp(self):
+ super(TestBackupRestore, self).setUp()
+
+ self.backups_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.BACKUP),
+ loaded=True
+ )
+ self.volumes_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True
+ )
+ self.restores_mock.restore.return_value = None
+ # Get the command object to mock
+ self.cmd = backup.RestoreBackup(self.app, None)
+
+ def test_backup_restore(self):
+ arglist = [
+ volume_fakes.backup_id,
+ volume_fakes.volume_id
+ ]
+ verifylist = [
+ ("backup", volume_fakes.backup_id),
+ ("volume", volume_fakes.volume_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.restores_mock.restore.assert_called_with(volume_fakes.backup_id,
+ volume_fakes.volume_id)
+
+
+class TestBackupList(TestBackup):
+ def setUp(self):
+ super(TestBackupList, self).setUp()
+
+ self.volumes_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True
+ )
+ ]
+ self.backups_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.BACKUP),
+ loaded=True
+ )
+ ]
+ # Get the command to test
+ self.cmd = backup.ListBackup(self.app, None)
+
+ def test_backup_list_without_options(self):
+ arglist = []
+ verifylist = [("long", False)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ['ID', 'Name', 'Description', 'Status', 'Size']
+ self.assertEqual(collist, columns)
+
+ datalist = ((
+ volume_fakes.backup_id,
+ volume_fakes.backup_name,
+ volume_fakes.backup_description,
+ volume_fakes.backup_status,
+ volume_fakes.backup_size
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_backup_list_with_options(self):
+ arglist = ["--long"]
+ verifylist = [("long", True)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ['ID', 'Name', 'Description', 'Status', 'Size',
+ 'Availability Zone', 'Volume', 'Container']
+ self.assertEqual(collist, columns)
+
+ datalist = ((
+ volume_fakes.backup_id,
+ volume_fakes.backup_name,
+ volume_fakes.backup_description,
+ volume_fakes.backup_status,
+ volume_fakes.backup_size,
+ volume_fakes.volume_availability_zone,
+ volume_fakes.backup_volume_id,
+ volume_fakes.backup_container
+ ),)
+ self.assertEqual(datalist, tuple(data))
diff --git a/openstackclient/volume/v2/backup.py b/openstackclient/volume/v2/backup.py
index bf2ea3a6..3525e701 100644
--- a/openstackclient/volume/v2/backup.py
+++ b/openstackclient/volume/v2/backup.py
@@ -14,15 +14,62 @@
"""Volume v2 Backup action implementations"""
+import copy
import logging
from cliff import command
+from cliff import lister
from cliff import show
import six
from openstackclient.common import utils
+class CreateBackup(show.ShowOne):
+ """Create new backup"""
+
+ log = logging.getLogger(__name__ + ".CreateBackup")
+
+ def get_parser(self, prog_name):
+ parser = super(CreateBackup, self).get_parser(prog_name)
+ parser.add_argument(
+ "volume",
+ metavar="<volume>",
+ help="Volume to backup (name or ID)"
+ )
+ parser.add_argument(
+ "--name",
+ metavar="<name>",
+ required=True,
+ help="Name of the backup"
+ )
+ parser.add_argument(
+ "--description",
+ metavar="<description>",
+ help="Description of the backup"
+ )
+ parser.add_argument(
+ "--container",
+ metavar="<container>",
+ help="Optional backup container name"
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action: (%s)", parsed_args)
+ volume_client = self.app.client_manager.volume
+ volume_id = utils.find_resource(
+ volume_client.volumes, parsed_args.volume).id
+ backup = volume_client.backups.create(
+ volume_id,
+ container=parsed_args.container,
+ name=parsed_args.name,
+ description=parsed_args.description
+ )
+ backup._info.pop("links", None)
+ return zip(*sorted(six.iteritems(backup._info)))
+
+
class DeleteBackup(command.Command):
"""Delete backup(s)"""
@@ -48,6 +95,91 @@ class DeleteBackup(command.Command):
return
+class ListBackup(lister.Lister):
+ """List backups"""
+
+ log = logging.getLogger(__name__ + ".ListBackup")
+
+ def get_parser(self, prog_name):
+ parser = super(ListBackup, self).get_parser(prog_name)
+ parser.add_argument(
+ "--long",
+ action="store_true",
+ default=False,
+ help="List additional fields in output"
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action: (%s)", parsed_args)
+
+ def _format_volume_id(volume_id):
+ """Return a volume name if available
+
+ :param volume_id: a volume ID
+ :rtype: either the volume ID or name
+ """
+
+ volume = volume_id
+ if volume_id in volume_cache.keys():
+ volume = volume_cache[volume_id].name
+ return volume
+
+ if parsed_args.long:
+ columns = ['ID', 'Name', 'Description', 'Status', 'Size',
+ 'Availability Zone', 'Volume ID', 'Container']
+ column_headers = copy.deepcopy(columns)
+ column_headers[6] = 'Volume'
+ else:
+ columns = ['ID', 'Name', 'Description', 'Status', 'Size']
+ column_headers = columns
+
+ # Cache the volume list
+ volume_cache = {}
+ try:
+ for s in self.app.client_manager.volume.volumes.list():
+ volume_cache[s.id] = s
+ except Exception:
+ # Just forget it if there's any trouble
+ pass
+
+ data = self.app.client_manager.volume.backups.list()
+
+ return (column_headers,
+ (utils.get_item_properties(
+ s, columns,
+ formatters={'Volume ID': _format_volume_id},
+ ) for s in data))
+
+
+class RestoreBackup(show.ShowOne):
+ """Restore backup"""
+
+ log = logging.getLogger(__name__ + ".RestoreBackup")
+
+ def get_parser(self, prog_name):
+ parser = super(RestoreBackup, self).get_parser(prog_name)
+ parser.add_argument(
+ "backup",
+ metavar="<backup>",
+ help="Backup to restore (ID only)"
+ )
+ parser.add_argument(
+ "volume",
+ metavar="<volume>",
+ help="Volume to restore to (name or ID)"
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action: (%s)", parsed_args)
+ volume_client = self.app.client_manager.volume
+ backup = utils.find_resource(volume_client.backups, parsed_args.backup)
+ destination_volume = utils.find_resource(volume_client.volumes,
+ parsed_args.volume)
+ return volume_client.restores.restore(backup.id, destination_volume.id)
+
+
class ShowBackup(show.ShowOne):
"""Display backup details"""