diff --git a/doc/source/user/proxies/block_storage_v3.rst b/doc/source/user/proxies/block_storage_v3.rst index 2c830ce90..5b6eaae17 100644 --- a/doc/source/user/proxies/block_storage_v3.rst +++ b/doc/source/user/proxies/block_storage_v3.rst @@ -162,4 +162,5 @@ Transfer Operations .. autoclass:: openstack.block_storage.v3._proxy.Proxy :noindex: - :members: create_transfer, delete_transfer, find_transfer + :members: create_transfer, delete_transfer, find_transfer, + get_transfer, transfers, accept_transfer diff --git a/openstack/block_storage/v3/_proxy.py b/openstack/block_storage/v3/_proxy.py index 9524cc8cc..f076b7b8c 100644 --- a/openstack/block_storage/v3/_proxy.py +++ b/openstack/block_storage/v3/_proxy.py @@ -34,6 +34,7 @@ from openstack.block_storage.v3 import volume as _volume from openstack import exceptions from openstack.identity.v3 import project as _project from openstack import resource +from openstack import utils class Proxy(_base_proxy.BaseBlockStorageProxy): @@ -1917,6 +1918,55 @@ class Proxy(_base_proxy.BaseBlockStorageProxy): ignore_missing=ignore_missing, ) + def get_transfer(self, transfer): + """Get a single transfer + + :param transfer: The value can be the ID of a transfer or a + :class:`~openstack.block_storage.v3.transfer.Transfer` + instance. + + :returns: One :class:`~openstack.block_storage.v3.transfer.Transfer` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_transfer.Transfer, transfer) + + def transfers(self, *, details=True, all_projects=False, **query): + """Retrieve a generator of transfers + + :param bool details: When set to ``False`` no extended attributes + will be returned. The default, ``True``, will cause objects with + additional attributes to be returned. + :param bool all_projects: When set to ``True``, list transfers from + all projects. Admin-only by default. + :param kwargs query: Optional query parameters to be sent to limit + the transfers being returned. + + :returns: A generator of transfer objects. + """ + if all_projects: + query['all_projects'] = True + base_path = '/volume-transfers' + if not utils.supports_microversion(self, '3.55'): + base_path = '/os-volume-transfer' + if details: + base_path = utils.urljoin(base_path, 'detail') + return self._list(_transfer.Transfer, base_path=base_path, **query) + + def accept_transfer(self, transfer_id, auth_key): + """Accept a Transfer + + :param transfer_id: The value can be the ID of a transfer or a + :class:`~openstack.block_storage.v3.transfer.Transfer` + instance. + :param auth_key: The key to authenticate volume transfer. + + :returns: The results of Transfer creation + :rtype: :class:`~openstack.block_storage.v3.transfer.Transfer` + """ + transfer = self._get_resource(_transfer.Transfer, transfer_id) + return transfer.accept(self, auth_key=auth_key) + # ====== UTILS ====== def wait_for_status( self, diff --git a/openstack/block_storage/v3/transfer.py b/openstack/block_storage/v3/transfer.py index 27d9fd9fc..e05cb3f98 100644 --- a/openstack/block_storage/v3/transfer.py +++ b/openstack/block_storage/v3/transfer.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from openstack import exceptions from openstack import resource from openstack import utils @@ -23,6 +24,8 @@ class Transfer(resource.Resource): allow_create = True allow_delete = True allow_fetch = True + allow_list = True + allow_get = True # Properties #: UUID of the transfer. @@ -171,3 +174,30 @@ class Transfer(resource.Resource): microversion=microversion, **kwargs, ) + + def accept(self, session, *, auth_key=None): + """Accept a volume transfer. + + :param session: The session to use for making this request. + :param auth_key: The authentication key for the volume transfer. + + :return: This :class:`Transfer` instance. + """ + body = {'accept': {'auth_key': auth_key}} + + path = self.base_path + if not utils.supports_microversion(session, '3.55'): + path = '/os-volume-transfer' + + url = utils.urljoin(path, self.id, 'accept') + microversion = self._get_microversion(session, action='commit') + resp = session.post( + url, + json=body, + microversion=microversion, + ) + exceptions.raise_from_response(resp) + + transfer = Transfer() + transfer._translate_response(response=resp) + return transfer diff --git a/openstack/tests/unit/block_storage/v3/test_transfer.py b/openstack/tests/unit/block_storage/v3/test_transfer.py index 9a88d6428..4114ab30b 100644 --- a/openstack/tests/unit/block_storage/v3/test_transfer.py +++ b/openstack/tests/unit/block_storage/v3/test_transfer.py @@ -22,9 +22,11 @@ from openstack.tests.unit import base FAKE_ID = "09d18b36-9e8d-4438-a4da-3f5eff5e1130" FAKE_VOL_ID = "390de1bc-19d1-41e7-ba67-c492bb36cae5" FAKE_VOL_NAME = "test-volume" +FAKE_TRANSFER = "7d048960-7c3f-4bf0-952f-4312fdea1dec" +FAKE_AUTH_KEY = "95bc670c0068821d" TRANSFER = { - "auth_key": "95bc670c0068821d", + "auth_key": FAKE_AUTH_KEY, "created_at": "2023-06-27T08:47:23.035010", "id": FAKE_ID, "name": FAKE_VOL_NAME, @@ -97,3 +99,46 @@ class TestTransfer(base.TestCase): headers={}, params={'volume_id': FAKE_VOL_ID, 'name': FAKE_VOL_NAME}, ) + + @mock.patch( + 'openstack.utils.supports_microversion', + autospec=True, + return_value=True, + ) + @mock.patch.object(resource.Resource, '_translate_response') + def test_accept(self, mock_mv, mock_translate): + sot = transfer.Transfer() + sot.id = FAKE_TRANSFER + + sot.accept(self.sess, auth_key=FAKE_AUTH_KEY) + self.sess.post.assert_called_with( + 'volume-transfers/%s/accept' % FAKE_TRANSFER, + json={ + 'accept': { + 'auth_key': FAKE_AUTH_KEY, + } + }, + microversion="3.55", + ) + + @mock.patch( + 'openstack.utils.supports_microversion', + autospec=True, + return_value=False, + ) + @mock.patch.object(resource.Resource, '_translate_response') + def test_accept_pre_v355(self, mock_mv, mock_translate): + self.sess.default_microversion = "3.0" + sot = transfer.Transfer() + sot.id = FAKE_TRANSFER + + sot.accept(self.sess, auth_key=FAKE_AUTH_KEY) + self.sess.post.assert_called_with( + 'os-volume-transfer/%s/accept' % FAKE_TRANSFER, + json={ + 'accept': { + 'auth_key': FAKE_AUTH_KEY, + } + }, + microversion="3.0", + ) diff --git a/releasenotes/notes/add-volume-transfer-support-28bf34a243d96e1b.yaml b/releasenotes/notes/add-volume-transfer-support-28bf34a243d96e1b.yaml index ff0ed5db5..40976dcab 100644 --- a/releasenotes/notes/add-volume-transfer-support-28bf34a243d96e1b.yaml +++ b/releasenotes/notes/add-volume-transfer-support-28bf34a243d96e1b.yaml @@ -1,5 +1,5 @@ --- features: - | - Added support for volume transfer create, find - and delete. + Added support for volume transfer create, find, + delete, get, list and accept.