Microversion 2.49 - Virt device tagged attach
Change-Id: I65a2d33710f85e9b8c342d6ff4c1e4cc82990b8c Implements: blueprint virt-device-tagged-attach-detach
This commit is contained in:
parent
bd0a2adefe
commit
e11a1266bb
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
||||
# when client supported the max version, and bumped sequentially, otherwise
|
||||
# the client may break due to server side new version may include some
|
||||
# backward incompatible change.
|
||||
API_MAX_VERSION = api_versions.APIVersion("2.48")
|
||||
API_MAX_VERSION = api_versions.APIVersion("2.49")
|
||||
|
@ -1457,3 +1457,29 @@ class ServersCreateImageBackupV2_45Test(utils.FixturedTestCase):
|
||||
self.assertEqual('456', sb['image_id'])
|
||||
self.assert_request_id(sb, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
|
||||
class ServersV249Test(ServersV2_37Test):
|
||||
|
||||
api_version = "2.49"
|
||||
|
||||
def test_interface_attach_with_tag(self):
|
||||
s = self.cs.servers.get(1234)
|
||||
ret = s.interface_attach('7f42712e-63fe-484c-a6df-30ae4867ff66',
|
||||
None, None, 'test_tag')
|
||||
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called(
|
||||
'POST', '/servers/1234/os-interface',
|
||||
{'interfaceAttachment':
|
||||
{'port_id': '7f42712e-63fe-484c-a6df-30ae4867ff66',
|
||||
'tag': 'test_tag'}})
|
||||
|
||||
def test_add_fixed_ip(self):
|
||||
# novaclient.v2.servers.Server.add_fixed_ip()
|
||||
# is not available after 2.44
|
||||
pass
|
||||
|
||||
def test_remove_fixed_ip(self):
|
||||
# novaclient.v2.servers.Server.remove_fixed_ip()
|
||||
# is not available after 2.44
|
||||
pass
|
||||
|
@ -2697,6 +2697,20 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('POST', '/servers/1234/os-interface',
|
||||
{'interfaceAttachment': {'port_id': 'port_id'}})
|
||||
|
||||
def test_interface_attach_with_tag_pre_v2_49(self):
|
||||
self.assertRaises(
|
||||
SystemExit, self.run_command,
|
||||
'interface-attach --port-id port_id --tag test_tag 1234',
|
||||
api_version='2.48')
|
||||
|
||||
def test_interface_attach_with_tag(self):
|
||||
self.run_command(
|
||||
'interface-attach --port-id port_id --tag test_tag 1234',
|
||||
api_version='2.49')
|
||||
self.assert_called('POST', '/servers/1234/os-interface',
|
||||
{'interfaceAttachment': {'port_id': 'port_id',
|
||||
'tag': 'test_tag'}})
|
||||
|
||||
def test_interface_detach(self):
|
||||
self.run_command('interface-detach 1234 port_id')
|
||||
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
||||
@ -2718,6 +2732,22 @@ class ShellTest(utils.TestCase):
|
||||
{'volumeAttachment':
|
||||
{'volumeId': 'Work'}})
|
||||
|
||||
def test_volume_attach_with_tag_pre_v2_49(self):
|
||||
self.assertRaises(
|
||||
SystemExit, self.run_command,
|
||||
'volume-attach --tag test_tag sample-server Work /dev/vdb',
|
||||
api_version='2.48')
|
||||
|
||||
def test_volume_attach_with_tag(self):
|
||||
self.run_command(
|
||||
'volume-attach --tag test_tag sample-server Work /dev/vdb',
|
||||
api_version='2.49')
|
||||
self.assert_called('POST', '/servers/1234/os-volume_attachments',
|
||||
{'volumeAttachment':
|
||||
{'device': '/dev/vdb',
|
||||
'volumeId': 'Work',
|
||||
'tag': 'test_tag'}})
|
||||
|
||||
def test_volume_update(self):
|
||||
self.run_command('volume-update sample-server Work Work')
|
||||
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||
|
@ -20,9 +20,11 @@ from novaclient.v2 import volumes
|
||||
|
||||
|
||||
class VolumesTest(utils.TestCase):
|
||||
api_version = "2.0"
|
||||
|
||||
def setUp(self):
|
||||
super(VolumesTest, self).setUp()
|
||||
self.cs = fakes.FakeClient(api_versions.APIVersion("2.0"))
|
||||
self.cs = fakes.FakeClient(api_versions.APIVersion(self.api_version))
|
||||
|
||||
def test_create_server_volume(self):
|
||||
v = self.cs.volumes.create_server_volume(
|
||||
@ -66,3 +68,23 @@ class VolumesTest(utils.TestCase):
|
||||
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.cs.assert_called('DELETE',
|
||||
'/servers/1234/os-volume_attachments/Work')
|
||||
|
||||
|
||||
class VolumesV249Test(VolumesTest):
|
||||
api_version = "2.49"
|
||||
|
||||
def test_create_server_volume_with_tag(self):
|
||||
v = self.cs.volumes.create_server_volume(
|
||||
server_id=1234,
|
||||
volume_id='15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
||||
device='/dev/vdb',
|
||||
tag='test_tag'
|
||||
)
|
||||
self.assert_request_id(v, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.cs.assert_called(
|
||||
'POST', '/servers/1234/os-volume_attachments',
|
||||
{'volumeAttachment': {
|
||||
'volumeId': '15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
||||
'device': '/dev/vdb',
|
||||
'tag': 'test_tag'}})
|
||||
self.assertIsInstance(v, volumes.Volume)
|
||||
|
@ -577,12 +577,21 @@ class Server(base.Resource):
|
||||
"""
|
||||
return self.manager.interface_list(self)
|
||||
|
||||
@api_versions.wraps("2.0", "2.48")
|
||||
def interface_attach(self, port_id, net_id, fixed_ip):
|
||||
"""
|
||||
Attach a network interface to an instance.
|
||||
"""
|
||||
return self.manager.interface_attach(self, port_id, net_id, fixed_ip)
|
||||
|
||||
@api_versions.wraps("2.49")
|
||||
def interface_attach(self, port_id, net_id, fixed_ip, tag=None):
|
||||
"""
|
||||
Attach a network interface to an instance with an optional tag.
|
||||
"""
|
||||
return self.manager.interface_attach(self, port_id, net_id, fixed_ip,
|
||||
tag)
|
||||
|
||||
def interface_detach(self, port_id):
|
||||
"""
|
||||
Detach a network interface from an instance.
|
||||
@ -1839,6 +1848,7 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
return self._list('/servers/%s/os-interface' % base.getid(server),
|
||||
'interfaceAttachments', obj_class=NetworkInterface)
|
||||
|
||||
@api_versions.wraps("2.0", "2.48")
|
||||
def interface_attach(self, server, port_id, net_id, fixed_ip):
|
||||
"""
|
||||
Attach a network_interface to an instance.
|
||||
@ -1859,6 +1869,35 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
return self._create('/servers/%s/os-interface' % base.getid(server),
|
||||
body, 'interfaceAttachment')
|
||||
|
||||
@api_versions.wraps("2.49")
|
||||
def interface_attach(self, server, port_id, net_id, fixed_ip, tag=None):
|
||||
"""
|
||||
Attach a network_interface to an instance.
|
||||
|
||||
:param server: The :class:`Server` (or its ID) to attach to.
|
||||
:param port_id: The port to attach.
|
||||
The port_id and net_id parameters are mutually
|
||||
exclusive.
|
||||
:param net_id: The ID of the network to attach.
|
||||
:param fixed_ip: The fixed IP addresses. If the fixed_ip is specified,
|
||||
the net_id has to be specified at the same time.
|
||||
:param tag: The tag.
|
||||
"""
|
||||
|
||||
body = {'interfaceAttachment': {}}
|
||||
if port_id:
|
||||
body['interfaceAttachment']['port_id'] = port_id
|
||||
if net_id:
|
||||
body['interfaceAttachment']['net_id'] = net_id
|
||||
if fixed_ip:
|
||||
body['interfaceAttachment']['fixed_ips'] = [
|
||||
{'ip_address': fixed_ip}]
|
||||
if tag:
|
||||
body['interfaceAttachment']['tag'] = tag
|
||||
|
||||
return self._create('/servers/%s/os-interface' % base.getid(server),
|
||||
body, 'interfaceAttachment')
|
||||
|
||||
def interface_detach(self, server, port_id):
|
||||
"""
|
||||
Detach a network_interface from an instance.
|
||||
|
@ -2339,14 +2339,25 @@ def _translate_volume_attachments_keys(collection):
|
||||
help=_('Name of the device e.g. /dev/vdb. '
|
||||
'Use "auto" for autoassign (if supported). '
|
||||
'Libvirt driver will use default device name.'))
|
||||
@utils.arg(
|
||||
'--tag',
|
||||
metavar='<tag>',
|
||||
default=None,
|
||||
help=_('Tag for the attached volume.'),
|
||||
start_version="2.49")
|
||||
def do_volume_attach(cs, args):
|
||||
"""Attach a volume to a server."""
|
||||
if args.device == 'auto':
|
||||
args.device = None
|
||||
|
||||
update_kwargs = {}
|
||||
if 'tag' in args and args.tag:
|
||||
update_kwargs['tag'] = args.tag
|
||||
|
||||
volume = cs.volumes.create_server_volume(_find_server(cs, args.server).id,
|
||||
args.volume,
|
||||
args.device)
|
||||
args.device,
|
||||
**update_kwargs)
|
||||
_print_volume(volume)
|
||||
|
||||
|
||||
@ -4376,11 +4387,23 @@ def do_interface_list(cs, args):
|
||||
metavar='<fixed_ip>',
|
||||
help=_('Requested fixed IP.'),
|
||||
default=None, dest="fixed_ip")
|
||||
@utils.arg(
|
||||
'--tag',
|
||||
metavar='<tag>',
|
||||
default=None,
|
||||
dest="tag",
|
||||
help=_('Tag for the attached interface.'),
|
||||
start_version="2.49")
|
||||
def do_interface_attach(cs, args):
|
||||
"""Attach a network interface to a server."""
|
||||
server = _find_server(cs, args.server)
|
||||
|
||||
res = server.interface_attach(args.port_id, args.net_id, args.fixed_ip)
|
||||
update_kwargs = {}
|
||||
if 'tag' in args and args.tag:
|
||||
update_kwargs['tag'] = args.tag
|
||||
|
||||
res = server.interface_attach(args.port_id, args.net_id, args.fixed_ip,
|
||||
**update_kwargs)
|
||||
if isinstance(res, dict):
|
||||
utils.print_dict(res)
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
Volume interface
|
||||
"""
|
||||
|
||||
from novaclient import api_versions
|
||||
from novaclient import base
|
||||
|
||||
|
||||
@ -37,6 +38,7 @@ class VolumeManager(base.Manager):
|
||||
"""
|
||||
resource_class = Volume
|
||||
|
||||
@api_versions.wraps("2.0", "2.48")
|
||||
def create_server_volume(self, server_id, volume_id, device=None):
|
||||
"""
|
||||
Attach a volume identified by the volume ID to the given server ID
|
||||
@ -52,6 +54,26 @@ class VolumeManager(base.Manager):
|
||||
return self._create("/servers/%s/os-volume_attachments" % server_id,
|
||||
body, "volumeAttachment")
|
||||
|
||||
@api_versions.wraps("2.49")
|
||||
def create_server_volume(self, server_id, volume_id, device=None,
|
||||
tag=None):
|
||||
"""
|
||||
Attach a volume identified by the volume ID to the given server ID
|
||||
|
||||
:param server_id: The ID of the server
|
||||
:param volume_id: The ID of the volume to attach.
|
||||
:param device: The device name (optional)
|
||||
:param tag: The tag (optional)
|
||||
:rtype: :class:`Volume`
|
||||
"""
|
||||
body = {'volumeAttachment': {'volumeId': volume_id}}
|
||||
if device is not None:
|
||||
body['volumeAttachment']['device'] = device
|
||||
if tag is not None:
|
||||
body['volumeAttachment']['tag'] = tag
|
||||
return self._create("/servers/%s/os-volume_attachments" % server_id,
|
||||
body, "volumeAttachment")
|
||||
|
||||
def update_server_volume(self, server_id, src_volid, dest_volid):
|
||||
"""
|
||||
Swaps the existing volume attachment to point to a new volume.
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added support for microversion 2.49 that enables users to
|
||||
attach tagged interfaces and volumes.
|
||||
A new ``--tag`` option is added to ``nova volume-attach`` and
|
||||
``nova interface-attach`` commands.
|
Loading…
Reference in New Issue
Block a user