Transfer snapshots with volumes

This patch will support to transfer volumes with or without
snapshots in new V3 api after mircoversion 3.55.

Change-Id: I61a84b5abf386a4073baea57d8820c8fd762ae03
Depends-On: https://review.openstack.org/533564/
Implements: blueprint transfer-snps-with-vols
This commit is contained in:
wanghao 2018-06-23 15:48:43 +08:00 committed by Jay S. Bryant
parent 8f933a9a34
commit a554faa653
6 changed files with 224 additions and 2 deletions

View File

@ -630,6 +630,45 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
def get_resource_filters(self, **kw):
return 200, {}, {'resource_filters': []}
def get_volume_transfers_detail(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
transfer2 = 'f625ec3e-13dd-4498-a22a-50afd534cc41'
return (200, {},
{'transfers': [
fake_v2._stub_transfer_full(transfer1, base_uri,
tenant_id),
fake_v2._stub_transfer_full(transfer2, base_uri,
tenant_id)]})
def get_volume_transfers_5678(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
return (200, {},
{'transfer':
fake_v2._stub_transfer_full(transfer1, base_uri, tenant_id)})
def delete_volume_transfers_5678(self, **kw):
return (202, {}, None)
def post_volume_transfers(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
return (202, {},
{'transfer': fake_v2._stub_transfer(transfer1, base_uri,
tenant_id)})
def post_volume_transfers_5678_accept(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
return (200, {},
{'transfer': fake_v2._stub_transfer(transfer1, base_uri,
tenant_id)})
def fake_request_get():
versions = {'versions': [{'id': 'v1.0',

View File

@ -1299,3 +1299,12 @@ class ShellTest(utils.TestCase):
'service_id': 1}
self.assert_called('POST', '/workers/cleanup', body=expected)
def test_create_transfer(self):
self.run_command('--os-volume-api-version 3.55 transfer-create '
'--no-snapshots 1234')
expected = {'transfer': {'volume_id': 1234,
'name': None,
'no_snapshots': True
}}
self.assert_called('POST', '/volume-transfers', body=expected)

View File

@ -0,0 +1,67 @@
# Copyright 2018 FiberHome Telecommunication Technologies CO.,LTD
# All Rights Reserved.
#
# 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 cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
cs = fakes.FakeClient()
class VolumeTransfersTest(utils.TestCase):
def test_create(self):
vol = cs.transfers.create('1234')
cs.assert_called('POST', '/volume-transfers',
body={'transfer': {'volume_id': '1234', 'name': None,
'no_snapshots': False}})
self._assert_request_id(vol)
def test_create_without_snapshots(self):
vol = cs.transfers.create('1234', no_snapshots=True)
cs.assert_called('POST', '/volume-transfers',
body={'transfer': {'volume_id': '1234', 'name': None,
'no_snapshots': True}})
self._assert_request_id(vol)
def test_get(self):
transfer_id = '5678'
vol = cs.transfers.get(transfer_id)
cs.assert_called('GET', '/volume-transfers/%s' % transfer_id)
self._assert_request_id(vol)
def test_list(self):
lst = cs.transfers.list()
cs.assert_called('GET', '/volume-transfers/detail')
self._assert_request_id(lst)
def test_delete(self):
b = cs.transfers.list()[0]
vol = b.delete()
cs.assert_called('DELETE', '/volume-transfers/5678')
self._assert_request_id(vol)
vol = cs.transfers.delete('5678')
self._assert_request_id(vol)
cs.assert_called('DELETE', '/volume-transfers/5678')
vol = cs.transfers.delete(b)
cs.assert_called('DELETE', '/volume-transfers/5678')
self._assert_request_id(vol)
def test_accept(self):
transfer_id = '5678'
auth_key = '12345'
vol = cs.transfers.accept(transfer_id, auth_key)
cs.assert_called('POST', '/volume-transfers/%s/accept' % transfer_id)
self._assert_request_id(vol)

View File

@ -2375,7 +2375,7 @@ def do_backup_create(cs, args):
kwargs = {}
if getattr(args, 'metadata', None):
kwargs['metadata'] = shell_utils.extract_metadata(args)
kwargs['metadata'] = shell_utils.extract_metadata(args)
az = getattr(args, 'availability_zone', None)
if az:
kwargs['availability_zone'] = az
@ -2396,3 +2396,38 @@ def do_backup_create(cs, args):
info.pop('links')
utils.print_dict(info)
@utils.arg('volume', metavar='<volume>',
help='Name or ID of volume to transfer.')
@utils.arg('--name',
metavar='<name>',
default=None,
help='Transfer name. Default=None.')
@utils.arg('--display-name',
help=argparse.SUPPRESS)
@utils.arg('--no-snapshots',
action='store_true',
help='Allows or disallows transfer volumes without snapshots. '
'Default=False.',
start_version='3.55',
default=False)
def do_transfer_create(cs, args):
"""Creates a volume transfer."""
if args.display_name is not None:
args.name = args.display_name
kwargs = {}
no_snapshots = getattr(args, 'no_snapshots', None)
if no_snapshots is not None:
kwargs['no_snapshots'] = no_snapshots
volume = utils.find_volume(cs, args.volume)
transfer = cs.transfers.create(volume.id,
args.name,
**kwargs)
info = dict()
info.update(transfer._info)
info.pop('links', None)
utils.print_dict(info)

View File

@ -17,4 +17,70 @@
Volume transfer interface (v3 extension).
"""
from cinderclient.v2.volume_transfers import * # flake8: noqa
from cinderclient import api_versions
from cinderclient import base
from cinderclient import utils
from cinderclient.v2 import volume_transfers
VolumeTransfer = volume_transfers.VolumeTransfer
class VolumeTransferManager(volume_transfers.VolumeTransferManager):
@api_versions.wraps("3.55")
def create(self, volume_id, name=None, no_snapshots=False):
"""Creates a volume transfer.
:param volume_id: The ID of the volume to transfer.
:param name: The name of the transfer.
:param no_snapshots: Transfer volumes without snapshots.
:rtype: :class:`VolumeTransfer`
"""
body = {'transfer': {'volume_id': volume_id,
'name': name,
'no_snapshots': no_snapshots}}
return self._create('/volume-transfers', body, 'transfer')
@api_versions.wraps("3.55")
def accept(self, transfer_id, auth_key):
"""Accept a volume transfer.
:param transfer_id: The ID of the transfer to accept.
:param auth_key: The auth_key of the transfer.
:rtype: :class:`VolumeTransfer`
"""
body = {'accept': {'auth_key': auth_key}}
return self._create('/volume-transfers/%s/accept' % transfer_id,
body, 'transfer')
@api_versions.wraps("3.55")
def get(self, transfer_id):
"""Show details of a volume transfer.
:param transfer_id: The ID of the volume transfer to display.
:rtype: :class:`VolumeTransfer`
"""
return self._get("/volume-transfers/%s" % transfer_id, "transfer")
@api_versions.wraps("3.55")
def list(self, detailed=True, search_opts=None):
"""Get a list of all volume transfer.
:rtype: list of :class:`VolumeTransfer`
"""
query_string = utils.build_query_param(search_opts)
detail = ""
if detailed:
detail = "/detail"
return self._list("/volume-transfers%s%s" % (detail, query_string),
"transfers")
@api_versions.wraps("3.55")
def delete(self, transfer_id):
"""Delete a volume transfer.
:param transfer_id: The :class:`VolumeTransfer` to delete.
"""
return self._delete("/volume-transfers/%s" % base.getid(transfer_id))

View File

@ -0,0 +1,6 @@
---
features:
- |
Starting with microversion 3.55, the volume transfer command now has the
ability to exclude a volume's snapshots when transferring a volume to another
project. The new command format is `cinder transfer-create --no-snapshots`.