summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGinnis <sean.mcginnis@gmail.com>2018-10-23 10:36:34 -0500
committerSean McGinnis <sean.mcginnis@gmail.com>2018-11-10 02:11:04 -0600
commitb90c780d2b99a91dd479bcc5f20caddcfb652f76 (patch)
tree0c172c7eb98ee2a38ae5d9bb763186603d30d481
parent097b45686e74d7f3ef086a1684e745cf83e73767 (diff)
Add volume backup import/export commands
This adds commands to import and export volume backup records so they can be imported and restored on other Cinder instances or to the original instance if the service or database has been lost and had to be rebuilt. I know this is a commonly used process by some users, so it would be good to have this functionality in osc so they do not have to switch clients. More details about the export and import process can be found here: https://docs.openstack.org/cinder/latest/admin/blockstorage-volume-backups-export-import.html Change-Id: Ic95f87b36a416a2b50cb2193fd5759ab59336975 Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
Notes
Notes (review): Code-Review+2: Steve Martinelli <s.martinelli@gmail.com> Workflow+1: Steve Martinelli <s.martinelli@gmail.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Sat, 10 Nov 2018 20:27:36 +0000 Reviewed-on: https://review.openstack.org/612735 Project: openstack/python-openstackclient Branch: refs/heads/master
-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 585f47d..632e215 100644
--- a/doc/source/cli/command-objects/volume-backup.rst
+++ b/doc/source/cli/command-objects/volume-backup.rst
@@ -2,200 +2,8 @@
2volume backup 2volume backup
3============= 3=============
4 4
5Block Storage v1, v2 5Volume v1, v2
6 6
7volume backup create 7.. autoprogram-cliff:: openstack.volume.v2
8-------------------- 8 :command: volume backup *
9 9
10Create new volume backup
11
12.. program:: volume backup create
13.. code:: bash
14
15 openstack volume backup create
16 [--container <container>]
17 [--name <name>]
18 [--description <description>]
19 [--snapshot <snapshot>]
20 [--force]
21 [--incremental]
22 <volume>
23
24.. option:: --container <container>
25
26 Optional backup container name
27
28.. option:: --name <name>
29
30 Name of the backup
31
32.. option:: --description <description>
33
34 Description of the backup
35
36.. option:: --snapshot <snapshot>
37
38 Snapshot to backup (name or ID)
39
40 *Volume version 2 only*
41
42.. option:: --force
43
44 Allow to back up an in-use volume
45
46 *Volume version 2 only*
47
48.. option:: --incremental
49
50 Perform an incremental backup
51
52 *Volume version 2 only*
53
54.. _volume_backup_create-backup:
55.. describe:: <volume>
56
57 Volume to backup (name or ID)
58
59volume backup delete
60--------------------
61
62Delete volume backup(s)
63
64.. program:: volume backup delete
65.. code:: bash
66
67 openstack volume backup delete
68 [--force]
69 <backup> [<backup> ...]
70
71.. option:: --force
72
73 Allow delete in state other than error or available
74
75 *Volume version 2 only*
76
77.. _volume_backup_delete-backup:
78.. describe:: <backup>
79
80 Backup(s) to delete (name or ID)
81
82volume backup list
83------------------
84
85List volume backups
86
87.. program:: volume backup list
88.. code:: bash
89
90 openstack volume backup list
91 [--long]
92 [--name <name>]
93 [--status <status>]
94 [--volume <volume>]
95 [--marker <volume-backup>]
96 [--limit <num-backups>]
97 [--all-projects]
98
99.. _volume_backup_list-backup:
100.. option:: --long
101
102 List additional fields in output
103
104.. option:: --name <name>
105
106 Filters results by the backup name
107
108.. option:: --status <status>
109
110 Filters results by the backup status
111 ('creating', 'available', 'deleting', 'error', 'restoring' or 'error_restoring')
112
113.. option:: --volume <volume>
114
115 Filters results by the volume which they backup (name or ID)"
116
117.. option:: --marker <volume-backup>
118
119 The last backup of the previous page (name or ID)
120
121 *Volume version 2 only*
122
123.. option:: --limit <num-backups>
124
125 Maximum number of backups to display
126
127 *Volume version 2 only*
128
129.. option:: --all-projects
130
131 Include all projects (admin only)
132
133volume backup restore
134---------------------
135
136Restore volume backup
137
138.. program:: volume backup restore
139.. code:: bash
140
141 openstack volume backup restore
142 <backup>
143 <volume>
144
145.. _volume_backup_restore-backup:
146.. describe:: <backup>
147
148 Backup to restore (name or ID)
149
150.. describe:: <volume>
151
152 Volume to restore to (name or ID)
153
154volume backup set
155-----------------
156
157Set volume backup properties
158
159.. program:: volume backup set
160.. code:: bash
161
162 openstack volume backup set
163 [--name <name>]
164 [--description <description>]
165 [--state <state>]
166 <backup>
167
168.. option:: --name <name>
169
170 New backup name
171
172.. option:: --description <description>
173
174 New backup description
175
176.. option:: --state <state>
177
178 New backup state ("available" or "error") (admin only)
179 (This option simply changes the state of the backup in the database with
180 no regard to actual status, exercise caution when using)
181
182.. _backup_set-volume-backup:
183.. describe:: <backup>
184
185 Backup to modify (name or ID)
186
187volume backup show
188------------------
189
190Display volume backup details
191
192.. program:: volume backup show
193.. code:: bash
194
195 openstack volume backup show
196 <backup>
197
198.. _volume_backup_show-backup:
199.. describe:: <backup>
200
201 Backup to display (name or ID)
diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst
index d7c9124..cdd5e63 100644
--- a/doc/source/cli/commands.rst
+++ b/doc/source/cli/commands.rst
@@ -158,6 +158,8 @@ referring to both Compute and Volume quotas.
158* ``volume backup``: (**Volume**) backup for volumes 158* ``volume backup``: (**Volume**) backup for volumes
159* ``volume backend capability``: (**volume**) volume backend storage capabilities 159* ``volume backend capability``: (**volume**) volume backend storage capabilities
160* ``volume backend pool``: (**volume**) volume backend storage pools 160* ``volume backend pool``: (**volume**) volume backend storage pools
161* ``volume backup record``: (**Volume**) volume record that can be imported or exported
162* ``volume backend``: (**volume**) volume backend storage
161* ``volume host``: (**Volume**) the physical computer for volumes 163* ``volume host``: (**Volume**) the physical computer for volumes
162* ``volume qos``: (**Volume**) quality-of-service (QoS) specification for volumes 164* ``volume qos``: (**Volume**) quality-of-service (QoS) specification for volumes
163* ``volume snapshot``: (**Volume**) a point-in-time copy of a volume 165* ``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 cc8ef2d..22fb84c 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.
2availability-zone-list,availability zone list --volume,Lists all availability zones. 2availability-zone-list,availability zone list --volume,Lists all availability zones.
3backup-create,volume backup create,Creates a volume backup. 3backup-create,volume backup create,Creates a volume backup.
4backup-delete,volume backup delete,Removes a backup. 4backup-delete,volume backup delete,Removes a backup.
5backup-export,volume backup export,Export backup metadata record. 5backup-export,volume backup record export,Export backup metadata record.
6backup-import,volume backup import,Import backup metadata record. 6backup-import,volume backup record import,Import backup metadata record.
7backup-list,volume backup list,Lists all backups. 7backup-list,volume backup list,Lists all backups.
8backup-reset-state,volume backup set --state,Explicitly updates the backup state. 8backup-reset-state,volume backup set --state,Explicitly updates the backup state.
9backup-restore,volume backup restore,Restores a backup. 9backup-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 59b08d0..c245cbf 100644
--- a/openstackclient/tests/unit/volume/v2/fakes.py
+++ b/openstackclient/tests/unit/volume/v2/fakes.py
@@ -596,6 +596,35 @@ class FakeBackup(object):
596 596
597 return mock.Mock(side_effect=backups) 597 return mock.Mock(side_effect=backups)
598 598
599 @staticmethod
600 def create_backup_record():
601 """Gets a fake backup record for a given backup.
602
603 :return: An "exported" backup record.
604 """
605
606 return {
607 'backup_service': 'cinder.backup.drivers.swift.SwiftBackupDriver',
608 'backup_url': 'eyJzdGF0dXMiOiAiYXZh',
609 }
610
611 @staticmethod
612 def import_backup_record():
613 """Creates a fake backup record import response from a backup.
614
615 :return: The fake backup object that was encoded.
616 """
617 return {
618 'backup': {
619 'id': 'backup.id',
620 'name': 'backup.name',
621 'links': [
622 {'href': 'link1', 'rel': 'self'},
623 {'href': 'link2', 'rel': 'bookmark'},
624 ],
625 },
626 }
627
599 628
600class FakeConsistencyGroup(object): 629class FakeConsistencyGroup(object):
601 """Fake one or more consistency group.""" 630 """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 0000000..0e24174
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_backup_record.py
@@ -0,0 +1,114 @@
1#
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13#
14
15from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
16from openstackclient.volume.v2 import backup_record
17
18
19class TestBackupRecord(volume_fakes.TestVolume):
20
21 def setUp(self):
22 super(TestBackupRecord, self).setUp()
23
24 self.backups_mock = self.app.client_manager.volume.backups
25 self.backups_mock.reset_mock()
26
27
28class TestBackupRecordExport(TestBackupRecord):
29
30 new_backup = volume_fakes.FakeBackup.create_one_backup(
31 attrs={'volume_id': 'a54708a2-0388-4476-a909-09579f885c25'})
32 new_record = volume_fakes.FakeBackup.create_backup_record()
33
34 def setUp(self):
35 super(TestBackupRecordExport, self).setUp()
36
37 self.backups_mock.export_record.return_value = self.new_record
38 self.backups_mock.get.return_value = self.new_backup
39
40 # Get the command object to mock
41 self.cmd = backup_record.ExportBackupRecord(self.app, None)
42
43 def test_backup_export_table(self):
44 arglist = [
45 self.new_backup.name,
46 ]
47 verifylist = [
48 ("backup", self.new_backup.name),
49 ]
50
51 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
52 parsed_args.formatter = 'table'
53 columns, __ = self.cmd.take_action(parsed_args)
54
55 self.backups_mock.export_record.assert_called_with(
56 self.new_backup.id,
57 )
58
59 expected_columns = ('Backup Service', 'Metadata')
60 self.assertEqual(columns, expected_columns)
61
62 def test_backup_export_json(self):
63 arglist = [
64 self.new_backup.name,
65 ]
66 verifylist = [
67 ("backup", self.new_backup.name),
68 ]
69
70 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
71 parsed_args.formatter = 'json'
72 columns, __ = self.cmd.take_action(parsed_args)
73
74 self.backups_mock.export_record.assert_called_with(
75 self.new_backup.id,
76 )
77
78 expected_columns = ('backup_service', 'backup_url')
79 self.assertEqual(columns, expected_columns)
80
81
82class TestBackupRecordImport(TestBackupRecord):
83
84 new_backup = volume_fakes.FakeBackup.create_one_backup(
85 attrs={'volume_id': 'a54708a2-0388-4476-a909-09579f885c25'})
86 new_import = volume_fakes.FakeBackup.import_backup_record()
87
88 def setUp(self):
89 super(TestBackupRecordImport, self).setUp()
90
91 self.backups_mock.import_record.return_value = self.new_import
92
93 # Get the command object to mock
94 self.cmd = backup_record.ImportBackupRecord(self.app, None)
95
96 def test_backup_import(self):
97 arglist = [
98 "cinder.backup.drivers.swift.SwiftBackupDriver",
99 "fake_backup_record_data",
100 ]
101 verifylist = [
102 ("backup_service",
103 "cinder.backup.drivers.swift.SwiftBackupDriver"),
104 ("backup_metadata", "fake_backup_record_data"),
105 ]
106
107 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
108 columns, __ = self.cmd.take_action(parsed_args)
109
110 self.backups_mock.import_record.assert_called_with(
111 "cinder.backup.drivers.swift.SwiftBackupDriver",
112 "fake_backup_record_data",
113 )
114 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 0000000..f491803
--- /dev/null
+++ b/openstackclient/volume/v2/backup_record.py
@@ -0,0 +1,82 @@
1#
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13#
14
15"""Volume v2 Backup action implementations"""
16
17import logging
18
19from osc_lib.command import command
20from osc_lib import utils
21import six
22
23from openstackclient.i18n import _
24
25
26LOG = logging.getLogger(__name__)
27
28
29class ExportBackupRecord(command.ShowOne):
30 _description = _('Export volume backup details. Backup information can be '
31 'imported into a new service instance to be able to '
32 'restore.')
33
34 def get_parser(self, prog_name):
35 parser = super(ExportBackupRecord, self).get_parser(prog_name)
36 parser.add_argument(
37 "backup",
38 metavar="<backup>",
39 help=_("Backup to export (name or ID)")
40 )
41 return parser
42
43 def take_action(self, parsed_args):
44 volume_client = self.app.client_manager.volume
45 backup = utils.find_resource(volume_client.backups, parsed_args.backup)
46 backup_data = volume_client.backups.export_record(backup.id)
47
48 # We only want to show "friendly" display names, but also want to keep
49 # json structure compatibility with cinderclient
50 if parsed_args.formatter == 'table':
51 backup_data['Backup Service'] = backup_data.pop('backup_service')
52 backup_data['Metadata'] = backup_data.pop('backup_url')
53
54 return zip(*sorted(six.iteritems(backup_data)))
55
56
57class ImportBackupRecord(command.ShowOne):
58 _description = _('Import volume backup details. Exported backup details '
59 'contain the metadata necessary to restore to a new or '
60 'rebuilt service instance')
61
62 def get_parser(self, prog_name):
63 parser = super(ImportBackupRecord, self).get_parser(prog_name)
64 parser.add_argument(
65 "backup_service",
66 metavar="<backup_service>",
67 help=_("Backup service containing the backup.")
68 )
69 parser.add_argument(
70 "backup_metadata",
71 metavar="<backup_metadata>",
72 help=_("Encoded backup metadata from export.")
73 )
74 return parser
75
76 def take_action(self, parsed_args):
77 volume_client = self.app.client_manager.volume
78 backup_data = volume_client.backups.import_record(
79 parsed_args.backup_service,
80 parsed_args.backup_metadata)
81 backup_data.pop('links', None)
82 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 0000000..955e997
--- /dev/null
+++ b/releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml
@@ -0,0 +1,15 @@
1---
2features:
3 - |
4 Add ``openstack volume backup record export <backup>`` command that
5 provides encrypted backup record metadata that can then be used to import
6 and restore on a different or rebuilt block storage service. Information
7 about volume backup export and import can be found in the `Cinder block
8 storage service documentation <https://docs.openstack.org/cinder/latest/admin/blockstorage-volume-backups-export-import.html>`_.
9 - |
10 Add ``openstack volume backup record import <backup_service>
11 <backup_matadata>`` command that can be used to import and restore on a
12 different or rebuilt block storage service. Information about volume backup
13 export and import can be found in the `Cinder block storage service
14 documentation <https://docs.openstack.org/cinder/latest/admin/blockstorage-volume-backups-export-import.html>`_.
15
diff --git a/setup.cfg b/setup.cfg
index 73c5fde..818b6ef 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -629,6 +629,9 @@ openstack.volume.v2 =
629 volume_backup_set = openstackclient.volume.v2.backup:SetVolumeBackup 629 volume_backup_set = openstackclient.volume.v2.backup:SetVolumeBackup
630 volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup 630 volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup
631 631
632 volume_backup_record_export = openstackclient.volume.v2.backup_record:ExportBackupRecord
633 volume_backup_record_import = openstackclient.volume.v2.backup_record:ImportBackupRecord
634
632 volume_backend_capability_show = openstackclient.volume.v2.volume_backend:ShowCapability 635 volume_backend_capability_show = openstackclient.volume.v2.volume_backend:ShowCapability
633 volume_backend_pool_list = openstackclient.volume.v2.volume_backend:ListPool 636 volume_backend_pool_list = openstackclient.volume.v2.volume_backend:ListPool
634 637