From 4b74d73aebd48929ae3a4fc5329b63999568cdb1 Mon Sep 17 00:00:00 2001 From: Vincent Lequertier Date: Mon, 26 May 2025 17:21:57 +0200 Subject: [PATCH] Add backup export command Change-Id: I35830e1e534d609be1ce79dde7da4c8173d48a1e --- openstack/block_storage/v2/_proxy.py | 12 ++++++++++++ openstack/block_storage/v2/backup.py | 11 +++++++++++ openstack/block_storage/v3/_proxy.py | 12 ++++++++++++ openstack/block_storage/v3/backup.py | 11 +++++++++++ openstack/cloud/_block_storage.py | 15 +++++++++++++++ .../tests/unit/block_storage/v3/test_backup.py | 12 ++++++++++++ 6 files changed, 73 insertions(+) diff --git a/openstack/block_storage/v2/_proxy.py b/openstack/block_storage/v2/_proxy.py index 8af6d8e84..c7886be8f 100644 --- a/openstack/block_storage/v2/_proxy.py +++ b/openstack/block_storage/v2/_proxy.py @@ -716,6 +716,18 @@ class Proxy(proxy.Proxy): """ return self._get(_backup.Backup, backup) + def export_record(self, backup): + """Get a backup + + :param backup: The value can be the ID of a backup + or a :class:`~openstack.block_storage.v2.backup.Backup` + instance. + + :returns: The backup export record fields + """ + backup = self._get_resource(_backup.Backup, backup) + return backup.export(self) + def find_backup(self, name_or_id, ignore_missing=True, *, details=True): """Find a single backup diff --git a/openstack/block_storage/v2/backup.py b/openstack/block_storage/v2/backup.py index 4a336f593..73f30f249 100644 --- a/openstack/block_storage/v2/backup.py +++ b/openstack/block_storage/v2/backup.py @@ -164,6 +164,17 @@ class Backup(resource.Resource): exceptions.raise_from_response(resp) return resp + def export(self, session): + """Export the current backup + + :param session: openstack session + :return: The backup export record fields + """ + url = utils.urljoin(self.base_path, self.id, "export_record") + resp = session.get(url) + exceptions.raise_from_response(resp) + return resp.json() + def restore(self, session, volume_id=None, name=None): """Restore current backup to volume diff --git a/openstack/block_storage/v3/_proxy.py b/openstack/block_storage/v3/_proxy.py index f6689a842..a197f9da6 100644 --- a/openstack/block_storage/v3/_proxy.py +++ b/openstack/block_storage/v3/_proxy.py @@ -1433,6 +1433,18 @@ class Proxy(proxy.Proxy): backup = self._get_resource(_backup.Backup, backup) return backup.fetch_metadata(self) + def export_record(self, backup): + """Get a backup meatadata to export + + :param backup: The value can be the ID of a backup + or a :class:`~openstack.block_storage.v2.backup.Backup` + instance. + + :returns: The backup export record fields + """ + backup = self._get_resource(_backup.Backup, backup) + return backup.export(self) + def set_backup_metadata(self, backup, **metadata): """Update metadata for a backup diff --git a/openstack/block_storage/v3/backup.py b/openstack/block_storage/v3/backup.py index 26c45b1da..b3db77ba6 100644 --- a/openstack/block_storage/v3/backup.py +++ b/openstack/block_storage/v3/backup.py @@ -187,6 +187,17 @@ class Backup(resource.Resource, metadata.MetadataMixin): exceptions.raise_from_response(resp) return resp + def export(self, session): + """Export the current backup + + :param session: openstack session + :return: The backup export record fields + """ + url = utils.urljoin(self.base_path, self.id, "export_record") + resp = session.get(url) + exceptions.raise_from_response(resp) + return resp + def restore(self, session, volume_id=None, name=None): """Restore current backup to volume diff --git a/openstack/cloud/_block_storage.py b/openstack/cloud/_block_storage.py index 6d1df090f..0d55761bb 100644 --- a/openstack/cloud/_block_storage.py +++ b/openstack/cloud/_block_storage.py @@ -582,6 +582,21 @@ class BlockStorageCloudMixin(openstackcloud._OpenStackCloudMixin): return backup + def export_volume_backup(self, backup_id): + """Export a volume backup. + + :param backup_id: the ID of the backup. + + :returns: The backup export record fields + :raises: :class:`~openstack.exceptions.ResourceTimeout` if wait time + exceeded. + :raises: :class:`~openstack.exceptions.SDKException` on operation + error. + """ + payload = {'backup': backup_id} + + return self.block_storage.export_record(**payload) + # TODO(stephenfin): Remove 'filters' in a future major version def get_volume_backup(self, name_or_id, filters=None): """Get a volume backup by name or ID. diff --git a/openstack/tests/unit/block_storage/v3/test_backup.py b/openstack/tests/unit/block_storage/v3/test_backup.py index 1645db341..cff2e1742 100644 --- a/openstack/tests/unit/block_storage/v3/test_backup.py +++ b/openstack/tests/unit/block_storage/v3/test_backup.py @@ -147,6 +147,18 @@ class TestBackup(base.TestCase): params={}, ) + def test_export(self): + sot = backup.Backup(**BACKUP) + + create_response = mock.Mock() + create_response.status_code = 200 + create_response.json.return_value = {} + create_response.headers = {} + self.sess.get.return_value = create_response + url = f'backups/{FAKE_ID}/export_record' + sot.export(self.sess) + self.sess.get.assert_called_with(url) + def test_restore(self): sot = backup.Backup(**BACKUP)