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
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# 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.assertEqual('456', sb['image_id'])
|
||||||
self.assert_request_id(sb, fakes.FAKE_REQUEST_ID_LIST)
|
self.assert_request_id(sb, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
self.assert_called('POST', '/servers/1234/action')
|
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',
|
self.assert_called('POST', '/servers/1234/os-interface',
|
||||||
{'interfaceAttachment': {'port_id': 'port_id'}})
|
{'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):
|
def test_interface_detach(self):
|
||||||
self.run_command('interface-detach 1234 port_id')
|
self.run_command('interface-detach 1234 port_id')
|
||||||
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
|
||||||
@ -2718,6 +2732,22 @@ class ShellTest(utils.TestCase):
|
|||||||
{'volumeAttachment':
|
{'volumeAttachment':
|
||||||
{'volumeId': 'Work'}})
|
{'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):
|
def test_volume_update(self):
|
||||||
self.run_command('volume-update sample-server Work Work')
|
self.run_command('volume-update sample-server Work Work')
|
||||||
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
|
||||||
|
@ -20,9 +20,11 @@ from novaclient.v2 import volumes
|
|||||||
|
|
||||||
|
|
||||||
class VolumesTest(utils.TestCase):
|
class VolumesTest(utils.TestCase):
|
||||||
|
api_version = "2.0"
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(VolumesTest, self).setUp()
|
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):
|
def test_create_server_volume(self):
|
||||||
v = self.cs.volumes.create_server_volume(
|
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.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
self.cs.assert_called('DELETE',
|
self.cs.assert_called('DELETE',
|
||||||
'/servers/1234/os-volume_attachments/Work')
|
'/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)
|
return self.manager.interface_list(self)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.48")
|
||||||
def interface_attach(self, port_id, net_id, fixed_ip):
|
def interface_attach(self, port_id, net_id, fixed_ip):
|
||||||
"""
|
"""
|
||||||
Attach a network interface to an instance.
|
Attach a network interface to an instance.
|
||||||
"""
|
"""
|
||||||
return self.manager.interface_attach(self, port_id, net_id, fixed_ip)
|
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):
|
def interface_detach(self, port_id):
|
||||||
"""
|
"""
|
||||||
Detach a network interface from an instance.
|
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),
|
return self._list('/servers/%s/os-interface' % base.getid(server),
|
||||||
'interfaceAttachments', obj_class=NetworkInterface)
|
'interfaceAttachments', obj_class=NetworkInterface)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.48")
|
||||||
def interface_attach(self, server, port_id, net_id, fixed_ip):
|
def interface_attach(self, server, port_id, net_id, fixed_ip):
|
||||||
"""
|
"""
|
||||||
Attach a network_interface to an instance.
|
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),
|
return self._create('/servers/%s/os-interface' % base.getid(server),
|
||||||
body, 'interfaceAttachment')
|
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):
|
def interface_detach(self, server, port_id):
|
||||||
"""
|
"""
|
||||||
Detach a network_interface from an instance.
|
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. '
|
help=_('Name of the device e.g. /dev/vdb. '
|
||||||
'Use "auto" for autoassign (if supported). '
|
'Use "auto" for autoassign (if supported). '
|
||||||
'Libvirt driver will use default device name.'))
|
'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):
|
def do_volume_attach(cs, args):
|
||||||
"""Attach a volume to a server."""
|
"""Attach a volume to a server."""
|
||||||
if args.device == 'auto':
|
if args.device == 'auto':
|
||||||
args.device = None
|
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,
|
volume = cs.volumes.create_server_volume(_find_server(cs, args.server).id,
|
||||||
args.volume,
|
args.volume,
|
||||||
args.device)
|
args.device,
|
||||||
|
**update_kwargs)
|
||||||
_print_volume(volume)
|
_print_volume(volume)
|
||||||
|
|
||||||
|
|
||||||
@ -4376,11 +4387,23 @@ def do_interface_list(cs, args):
|
|||||||
metavar='<fixed_ip>',
|
metavar='<fixed_ip>',
|
||||||
help=_('Requested fixed IP.'),
|
help=_('Requested fixed IP.'),
|
||||||
default=None, dest="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):
|
def do_interface_attach(cs, args):
|
||||||
"""Attach a network interface to a server."""
|
"""Attach a network interface to a server."""
|
||||||
server = _find_server(cs, args.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):
|
if isinstance(res, dict):
|
||||||
utils.print_dict(res)
|
utils.print_dict(res)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
Volume interface
|
Volume interface
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from novaclient import base
|
from novaclient import base
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ class VolumeManager(base.Manager):
|
|||||||
"""
|
"""
|
||||||
resource_class = Volume
|
resource_class = Volume
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.48")
|
||||||
def create_server_volume(self, server_id, volume_id, device=None):
|
def create_server_volume(self, server_id, volume_id, device=None):
|
||||||
"""
|
"""
|
||||||
Attach a volume identified by the volume ID to the given server ID
|
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,
|
return self._create("/servers/%s/os-volume_attachments" % server_id,
|
||||||
body, "volumeAttachment")
|
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):
|
def update_server_volume(self, server_id, src_volid, dest_volid):
|
||||||
"""
|
"""
|
||||||
Swaps the existing volume attachment to point to a new volume.
|
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