summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/cli/command-objects/volume-backup.rst198
-rw-r--r--doc/source/cli/commands.rst2
-rw-r--r--doc/source/cli/data/cinder.csv4
-rw-r--r--openstackclient/tests/unit/volume/v2/fakes.py29
-rw-r--r--openstackclient/tests/unit/volume/v2/test_backup_record.py114
-rw-r--r--openstackclient/volume/v2/backup_record.py82
-rw-r--r--releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml15
-rw-r--r--setup.cfg3
8 files changed, 250 insertions, 197 deletions
diff --git a/doc/source/cli/command-objects/volume-backup.rst b/doc/source/cli/command-objects/volume-backup.rst
index 585f47d4..632e215e 100644
--- a/doc/source/cli/command-objects/volume-backup.rst
+++ b/doc/source/cli/command-objects/volume-backup.rst
@@ -2,200 +2,8 @@
volume backup
=============
-Block Storage v1, v2
+Volume v1, v2
-volume backup create
---------------------
+.. autoprogram-cliff:: openstack.volume.v2
+ :command: volume backup *
-Create new volume backup
-
-.. program:: volume backup create
-.. code:: bash
-
- openstack volume backup create
- [--container <container>]
- [--name <name>]
- [--description <description>]
- [--snapshot <snapshot>]
- [--force]
- [--incremental]
- <volume>
-
-.. option:: --container <container>
-
- Optional backup container name
-
-.. option:: --name <name>
-
- Name of the backup
-
-.. option:: --description <description>
-
- Description of the backup
-
-.. option:: --snapshot <snapshot>
-
- Snapshot to backup (name or ID)
-
- *Volume version 2 only*
-
-.. option:: --force
-
- Allow to back up an in-use volume
-
- *Volume version 2 only*
-
-.. option:: --incremental
-
- Perform an incremental backup
-
- *Volume version 2 only*
-
-.. _volume_backup_create-backup:
-.. describe:: <volume>
-
- Volume to backup (name or ID)
-
-volume backup delete
---------------------
-
-Delete volume backup(s)
-
-.. program:: volume backup delete
-.. code:: bash
-
- openstack volume backup delete
- [--force]
- <backup> [<backup> ...]
-
-.. option:: --force
-
- Allow delete in state other than error or available
-
- *Volume version 2 only*
-
-.. _volume_backup_delete-backup:
-.. describe:: <backup>
-
- Backup(s) to delete (name or ID)
-
-volume backup list
-------------------
-
-List volume backups
-
-.. program:: volume backup list
-.. code:: bash
-
- openstack volume backup list
- [--long]
- [--name <name>]
- [--status <status>]
- [--volume <volume>]
- [--marker <volume-backup>]
- [--limit <num-backups>]
- [--all-projects]
-
-.. _volume_backup_list-backup:
-.. option:: --long
-
- List additional fields in output
-
-.. option:: --name <name>
-
- Filters results by the backup name
-
-.. option:: --status <status>
-
- Filters results by the backup status
- ('creating', 'available', 'deleting', 'error', 'restoring' or 'error_restoring')
-
-.. option:: --volume <volume>
-
- Filters results by the volume which they backup (name or ID)"
-
-.. option:: --marker <volume-backup>
-
- The last backup of the previous page (name or ID)
-
- *Volume version 2 only*
-
-.. option:: --limit <num-backups>
-
- Maximum number of backups to display
-
- *Volume version 2 only*
-
-.. option:: --all-projects
-
- Include all projects (admin only)
-
-volume backup restore
----------------------
-
-Restore volume backup
-
-.. program:: volume backup restore
-.. code:: bash
-
- openstack volume backup restore
- <backup>
- <volume>
-
-.. _volume_backup_restore-backup:
-.. describe:: <backup>
-
- Backup to restore (name or ID)
-
-.. describe:: <volume>
-
- Volume to restore to (name or ID)
-
-volume backup set
------------------
-
-Set volume backup properties
-
-.. program:: volume backup set
-.. code:: bash
-
- openstack volume backup set
- [--name <name>]
- [--description <description>]
- [--state <state>]
- <backup>
-
-.. option:: --name <name>
-
- New backup name
-
-.. option:: --description <description>
-
- New backup description
-
-.. option:: --state <state>
-
- New backup state ("available" or "error") (admin only)
- (This option simply changes the state of the backup in the database with
- no regard to actual status, exercise caution when using)
-
-.. _backup_set-volume-backup:
-.. describe:: <backup>
-
- Backup to modify (name or ID)
-
-volume backup show
-------------------
-
-Display volume backup details
-
-.. program:: volume backup show
-.. code:: bash
-
- openstack volume backup show
- <backup>
-
-.. _volume_backup_show-backup:
-.. describe:: <backup>
-
- Backup to display (name or ID)
diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst
index d7c91240..cdd5e63c 100644
--- a/doc/source/cli/commands.rst
+++ b/doc/source/cli/commands.rst
@@ -158,6 +158,8 @@ referring to both Compute and Volume quotas.
* ``volume backup``: (**Volume**) backup for volumes
* ``volume backend capability``: (**volume**) volume backend storage capabilities
* ``volume backend pool``: (**volume**) volume backend storage pools
+* ``volume backup record``: (**Volume**) volume record that can be imported or exported
+* ``volume backend``: (**volume**) volume backend storage
* ``volume host``: (**Volume**) the physical computer for volumes
* ``volume qos``: (**Volume**) quality-of-service (QoS) specification for volumes
* ``volume snapshot``: (**Volume**) a point-in-time copy of a volume
diff --git a/doc/source/cli/data/cinder.csv b/doc/source/cli/data/cinder.csv
index cc8ef2d9..22fb84cf 100644
--- a/doc/source/cli/data/cinder.csv
+++ b/doc/source/cli/data/cinder.csv
@@ -2,8 +2,8 @@ absolute-limits,limits show --absolute,Lists absolute limits for a user.
availability-zone-list,availability zone list --volume,Lists all availability zones.
backup-create,volume backup create,Creates a volume backup.
backup-delete,volume backup delete,Removes a backup.
-backup-export,volume backup export,Export backup metadata record.
-backup-import,volume backup import,Import backup metadata record.
+backup-export,volume backup record export,Export backup metadata record.
+backup-import,volume backup record import,Import backup metadata record.
backup-list,volume backup list,Lists all backups.
backup-reset-state,volume backup set --state,Explicitly updates the backup state.
backup-restore,volume backup restore,Restores a backup.
diff --git a/openstackclient/tests/unit/volume/v2/fakes.py b/openstackclient/tests/unit/volume/v2/fakes.py
index 59b08d0b..c245cbf6 100644
--- a/openstackclient/tests/unit/volume/v2/fakes.py
+++ b/openstackclient/tests/unit/volume/v2/fakes.py
@@ -596,6 +596,35 @@ class FakeBackup(object):
return mock.Mock(side_effect=backups)
+ @staticmethod
+ def create_backup_record():
+ """Gets a fake backup record for a given backup.
+
+ :return: An "exported" backup record.
+ """
+
+ return {
+ 'backup_service': 'cinder.backup.drivers.swift.SwiftBackupDriver',
+ 'backup_url': 'eyJzdGF0dXMiOiAiYXZh',
+ }
+
+ @staticmethod
+ def import_backup_record():
+ """Creates a fake backup record import response from a backup.
+
+ :return: The fake backup object that was encoded.
+ """
+ return {
+ 'backup': {
+ 'id': 'backup.id',
+ 'name': 'backup.name',
+ 'links': [
+ {'href': 'link1', 'rel': 'self'},
+ {'href': 'link2', 'rel': 'bookmark'},
+ ],
+ },
+ }
+
class FakeConsistencyGroup(object):
"""Fake one or more consistency group."""
diff --git a/openstackclient/tests/unit/volume/v2/test_backup_record.py b/openstackclient/tests/unit/volume/v2/test_backup_record.py
new file mode 100644
index 00000000..0e24174c
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_backup_record.py
@@ -0,0 +1,114 @@
+#
+# 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 openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import backup_record
+
+
+class TestBackupRecord(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestBackupRecord, self).setUp()
+
+ self.backups_mock = self.app.client_manager.volume.backups
+ self.backups_mock.reset_mock()
+
+
+class TestBackupRecordExport(TestBackupRecord):
+
+ new_backup = volume_fakes.FakeBackup.create_one_backup(
+ attrs={'volume_id': 'a54708a2-0388-4476-a909-09579f885c25'})
+ new_record = volume_fakes.FakeBackup.create_backup_record()
+
+ def setUp(self):
+ super(TestBackupRecordExport, self).setUp()
+
+ self.backups_mock.export_record.return_value = self.new_record
+ self.backups_mock.get.return_value = self.new_backup
+
+ # Get the command object to mock
+ self.cmd = backup_record.ExportBackupRecord(self.app, None)
+
+ def test_backup_export_table(self):
+ arglist = [
+ self.new_backup.name,
+ ]
+ verifylist = [
+ ("backup", self.new_backup.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ parsed_args.formatter = 'table'
+ columns, __ = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.export_record.assert_called_with(
+ self.new_backup.id,
+ )
+
+ expected_columns = ('Backup Service', 'Metadata')
+ self.assertEqual(columns, expected_columns)
+
+ def test_backup_export_json(self):
+ arglist = [
+ self.new_backup.name,
+ ]
+ verifylist = [
+ ("backup", self.new_backup.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ parsed_args.formatter = 'json'
+ columns, __ = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.export_record.assert_called_with(
+ self.new_backup.id,
+ )
+
+ expected_columns = ('backup_service', 'backup_url')
+ self.assertEqual(columns, expected_columns)
+
+
+class TestBackupRecordImport(TestBackupRecord):
+
+ new_backup = volume_fakes.FakeBackup.create_one_backup(
+ attrs={'volume_id': 'a54708a2-0388-4476-a909-09579f885c25'})
+ new_import = volume_fakes.FakeBackup.import_backup_record()
+
+ def setUp(self):
+ super(TestBackupRecordImport, self).setUp()
+
+ self.backups_mock.import_record.return_value = self.new_import
+
+ # Get the command object to mock
+ self.cmd = backup_record.ImportBackupRecord(self.app, None)
+
+ def test_backup_import(self):
+ arglist = [
+ "cinder.backup.drivers.swift.SwiftBackupDriver",
+ "fake_backup_record_data",
+ ]
+ verifylist = [
+ ("backup_service",
+ "cinder.backup.drivers.swift.SwiftBackupDriver"),
+ ("backup_metadata", "fake_backup_record_data"),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, __ = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.import_record.assert_called_with(
+ "cinder.backup.drivers.swift.SwiftBackupDriver",
+ "fake_backup_record_data",
+ )
+ self.assertEqual(columns, ('backup',))
diff --git a/openstackclient/volume/v2/backup_record.py b/openstackclient/volume/v2/backup_record.py
new file mode 100644
index 00000000..f4918032
--- /dev/null
+++ b/openstackclient/volume/v2/backup_record.py
@@ -0,0 +1,82 @@
+#
+# 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 v2 Backup action implementations"""
+
+import logging
+
+from osc_lib.command import command
+from osc_lib import utils
+import six
+
+from openstackclient.i18n import _
+
+
+LOG = logging.getLogger(__name__)
+
+
+class ExportBackupRecord(command.ShowOne):
+ _description = _('Export volume backup details. Backup information can be '
+ 'imported into a new service instance to be able to '
+ 'restore.')
+
+ def get_parser(self, prog_name):
+ parser = super(ExportBackupRecord, self).get_parser(prog_name)
+ parser.add_argument(
+ "backup",
+ metavar="<backup>",
+ help=_("Backup to export (name or ID)")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ backup = utils.find_resource(volume_client.backups, parsed_args.backup)
+ backup_data = volume_client.backups.export_record(backup.id)
+
+ # We only want to show "friendly" display names, but also want to keep
+ # json structure compatibility with cinderclient
+ if parsed_args.formatter == 'table':
+ backup_data['Backup Service'] = backup_data.pop('backup_service')
+ backup_data['Metadata'] = backup_data.pop('backup_url')
+
+ return zip(*sorted(six.iteritems(backup_data)))
+
+
+class ImportBackupRecord(command.ShowOne):
+ _description = _('Import volume backup details. Exported backup details '
+ 'contain the metadata necessary to restore to a new or '
+ 'rebuilt service instance')
+
+ def get_parser(self, prog_name):
+ parser = super(ImportBackupRecord, self).get_parser(prog_name)
+ parser.add_argument(
+ "backup_service",
+ metavar="<backup_service>",
+ help=_("Backup service containing the backup.")
+ )
+ parser.add_argument(
+ "backup_metadata",
+ metavar="<backup_metadata>",
+ help=_("Encoded backup metadata from export.")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ backup_data = volume_client.backups.import_record(
+ parsed_args.backup_service,
+ parsed_args.backup_metadata)
+ backup_data.pop('links', None)
+ return zip(*sorted(six.iteritems(backup_data)))
diff --git a/releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml b/releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml
new file mode 100644
index 00000000..955e9971
--- /dev/null
+++ b/releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml
@@ -0,0 +1,15 @@
+---
+features:
+ - |
+ Add ``openstack volume backup record export <backup>`` command that
+ provides encrypted backup record metadata that can then be used to import
+ and restore on a different or rebuilt block storage service. Information
+ about volume backup export and import can be found in the `Cinder block
+ storage service documentation <https://docs.openstack.org/cinder/latest/admin/blockstorage-volume-backups-export-import.html>`_.
+ - |
+ Add ``openstack volume backup record import <backup_service>
+ <backup_matadata>`` command that can be used to import and restore on a
+ different or rebuilt block storage service. Information about volume backup
+ export and import can be found in the `Cinder block storage service
+ documentation <https://docs.openstack.org/cinder/latest/admin/blockstorage-volume-backups-export-import.html>`_.
+
diff --git a/setup.cfg b/setup.cfg
index 73c5fde9..818b6ef2 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -629,6 +629,9 @@ openstack.volume.v2 =
volume_backup_set = openstackclient.volume.v2.backup:SetVolumeBackup
volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup
+ volume_backup_record_export = openstackclient.volume.v2.backup_record:ExportBackupRecord
+ volume_backup_record_import = openstackclient.volume.v2.backup_record:ImportBackupRecord
+
volume_backend_capability_show = openstackclient.volume.v2.volume_backend:ShowCapability
volume_backend_pool_list = openstackclient.volume.v2.volume_backend:ListPool