Merge "Microversion 2.42 - Fix tag attribute disappearing"

This commit is contained in:
Jenkins 2017-04-20 17:38:02 +00:00 committed by Gerrit Code Review
commit 2ed7d2b5d0
5 changed files with 289 additions and 17 deletions

View File

@ -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.41") API_MAX_VERSION = api_versions.APIVersion("2.42")

View File

@ -13,24 +13,159 @@
# under the License. # under the License.
from oslo_utils import uuidutils from oslo_utils import uuidutils
import six
from tempest.lib import exceptions
from novaclient.tests.functional import base from novaclient.tests.functional import base
class TestDeviceTaggingCLI(base.ClientTestBase): class TestBlockDeviceTaggingCLIError(base.ClientTestBase):
"""Negative test that asserts that creating a server with a tagged
block device with a specific microversion will fail.
"""
COMPUTE_API_VERSION = "2.31"
def test_boot_server_with_tagged_block_devices_with_error(self):
try:
output = self.nova('boot', params=(
'%(name)s --flavor %(flavor)s --poll '
'--nic net-id=%(net-uuid)s '
'--block-device '
'source=image,dest=volume,id=%(image)s,size=1,bootindex=0,'
'shutdown=remove,tag=bar' % {'name': uuidutils.generate_uuid(),
'flavor': self.flavor.id,
'net-uuid': self.network.id,
'image': self.image.id}))
except exceptions.CommandFailed as e:
self.assertIn("ERROR (CommandError): "
"'tag' in block device mapping is not supported "
"in API version %s." % self.COMPUTE_API_VERSION,
six.text_type(e))
else:
server_id = self._get_value_from_the_table(output, 'id')
self.client.servers.delete(server_id)
self.wait_for_resource_delete(server_id, self.client.servers)
self.fail("Booting a server with block device tag is not failed.")
class TestNICDeviceTaggingCLIError(base.ClientTestBase):
"""Negative test that asserts that creating a server with a tagged
nic with a specific microversion will fail.
"""
COMPUTE_API_VERSION = "2.31"
def test_boot_server_with_tagged_nic_devices_with_error(self):
try:
output = self.nova('boot', params=(
'%(name)s --flavor %(flavor)s --poll '
'--nic net-id=%(net-uuid)s,tag=foo '
'--block-device '
'source=image,dest=volume,id=%(image)s,size=1,bootindex=0,'
'shutdown=remove' % {'name': uuidutils.generate_uuid(),
'flavor': self.flavor.id,
'net-uuid': self.network.id,
'image': self.image.id}))
except exceptions.CommandFailed as e:
self.assertIn("Invalid nic argument", six.text_type(e))
else:
server_id = self._get_value_from_the_table(output, 'id')
self.client.servers.delete(server_id)
self.wait_for_resource_delete(server_id, self.client.servers)
self.fail("Booting a server with network interface tag "
"is not failed.")
class TestBlockDeviceTaggingCLI(base.ClientTestBase):
"""Tests that creating a server with a tagged block device will work
with the 2.32 microversion, where the feature was originally added.
"""
COMPUTE_API_VERSION = "2.32" COMPUTE_API_VERSION = "2.32"
def test_boot_server_with_tagged_devices(self): def test_boot_server_with_tagged_block_devices(self):
server_info = self.nova('boot', params=(
'%(name)s --flavor %(flavor)s --poll '
'--nic net-id=%(net-uuid)s '
'--block-device '
'source=image,dest=volume,id=%(image)s,size=1,bootindex=0,'
'shutdown=remove,tag=bar' % {'name': uuidutils.generate_uuid(),
'flavor': self.flavor.id,
'net-uuid': self.network.id,
'image': self.image.id}))
server_id = self._get_value_from_the_table(server_info, 'id')
self.client.servers.delete(server_id)
self.wait_for_resource_delete(server_id, self.client.servers)
class TestNICDeviceTaggingCLI(base.ClientTestBase):
"""Tests that creating a server with a tagged nic will work
with the 2.32 microversion, where the feature was originally added.
"""
COMPUTE_API_VERSION = "2.32"
def test_boot_server_with_tagged_nic_devices(self):
server_info = self.nova('boot', params=( server_info = self.nova('boot', params=(
'%(name)s --flavor %(flavor)s --poll ' '%(name)s --flavor %(flavor)s --poll '
'--nic net-id=%(net-uuid)s,tag=foo ' '--nic net-id=%(net-uuid)s,tag=foo '
'--block-device ' '--block-device '
'source=image,dest=volume,id=%(image)s,size=1,' 'source=image,dest=volume,id=%(image)s,size=1,bootindex=0,'
'bootindex=0,tag=bar' % {'name': uuidutils.generate_uuid(), 'shutdown=remove' % {'name': uuidutils.generate_uuid(),
'flavor': self.flavor.id, 'flavor': self.flavor.id,
'net-uuid': self.network.id, 'net-uuid': self.network.id,
'image': self.image.id})) 'image': self.image.id}))
server_id = self._get_value_from_the_table(server_info, 'id') server_id = self._get_value_from_the_table(server_info, 'id')
self.client.servers.delete(server_id) self.client.servers.delete(server_id)
self.wait_for_resource_delete(server_id, self.client.servers) self.wait_for_resource_delete(server_id, self.client.servers)
class TestDeviceTaggingCLIV233(TestBlockDeviceTaggingCLIError,
TestNICDeviceTaggingCLI):
"""Tests that in microversion 2.33, creating a server with a tagged
block device will fail, but creating a server with a tagged nic will
succeed.
"""
COMPUTE_API_VERSION = "2.33"
class TestDeviceTaggingCLIV236(TestBlockDeviceTaggingCLIError,
TestNICDeviceTaggingCLI):
"""Tests that in microversion 2.36, creating a server with a tagged
block device will fail, but creating a server with a tagged nic will
succeed. This is testing the boundary before 2.37 where nic tagging
was broken.
"""
COMPUTE_API_VERSION = "2.36"
class TestDeviceTaggingCLIV237(TestBlockDeviceTaggingCLIError,
TestNICDeviceTaggingCLIError):
"""Tests that in microversion 2.37, creating a server with either a
tagged block device or tagged nic would fail.
"""
COMPUTE_API_VERSION = "2.37"
class TestDeviceTaggingCLIV241(TestBlockDeviceTaggingCLIError,
TestNICDeviceTaggingCLIError):
"""Tests that in microversion 2.41, creating a server with either a
tagged block device or tagged nic would fail. This is testing the
boundary before 2.42 where block device tags and nic tags were fixed
for server create requests.
"""
COMPUTE_API_VERSION = "2.41"
class TestDeviceTaggingCLIV242(TestBlockDeviceTaggingCLI,
TestNICDeviceTaggingCLI):
"""Tests that in microversion 2.42 you could once again create a server
with a tagged block device or a tagged nic.
"""
COMPUTE_API_VERSION = "2.42"

View File

@ -2880,6 +2880,7 @@ class ShellTest(utils.TestCase):
38, # doesn't require any changes in novaclient 38, # doesn't require any changes in novaclient
39, # There are no versioned wrapped shell method changes for this 39, # There are no versioned wrapped shell method changes for this
41, # There are no version-wrapped shell method changes for this. 41, # There are no version-wrapped shell method changes for this.
42, # There are no version-wrapped shell method changes for this.
]) ])
versions_supported = set(range(0, versions_supported = set(range(0,
novaclient.API_MAX_VERSION.ver_minor + 1)) novaclient.API_MAX_VERSION.ver_minor + 1))

View File

@ -106,7 +106,15 @@ def _match_image(cs, wanted_properties):
return images_matched return images_matched
def _parse_block_device_mapping_v2(args, image): def _supports_block_device_tags(cs):
if (cs.api_version == api_versions.APIVersion('2.32') or
cs.api_version >= api_versions.APIVersion('2.42')):
return True
else:
return False
def _parse_block_device_mapping_v2(cs, args, image):
bdm = [] bdm = []
if args.boot_volume: if args.boot_volume:
@ -125,6 +133,12 @@ def _parse_block_device_mapping_v2(args, image):
spec_dict = dict(v.split('=') for v in device_spec.split(',')) spec_dict = dict(v.split('=') for v in device_spec.split(','))
bdm_dict = {} bdm_dict = {}
if ('tag' in spec_dict and not _supports_block_device_tags(cs)):
raise exceptions.CommandError(
_("'tag' in block device mapping is not supported "
"in API version %(version)s.")
% {'version': cs.api_version.get_string()})
for key, value in spec_dict.items(): for key, value in spec_dict.items():
bdm_dict[CLIENT_BDM2_KEYS[key]] = value bdm_dict[CLIENT_BDM2_KEYS[key]] = value
@ -193,9 +207,25 @@ def _parse_block_device_mapping_v2(args, image):
return bdm return bdm
def _supports_nic_tags(cs):
if ((cs.api_version >= api_versions.APIVersion('2.32') and
cs.api_version <= api_versions.APIVersion('2.36')) or
cs.api_version >= api_versions.APIVersion('2.42')):
return True
else:
return False
def _parse_nics(cs, args): def _parse_nics(cs, args):
supports_auto_alloc = cs.api_version >= api_versions.APIVersion('2.37') supports_auto_alloc = cs.api_version >= api_versions.APIVersion('2.37')
if supports_auto_alloc: supports_nic_tags = _supports_nic_tags(cs)
nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "",
"port-id": "", "net-name": ""}
if supports_auto_alloc and supports_nic_tags:
# API version >= 2.42
nic_info.update({"tag": ""})
err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of " err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of "
"the form --nic <auto,none,net-id=net-uuid," "the form --nic <auto,none,net-id=net-uuid,"
"net-name=network-name,v4-fixed-ip=ip-addr," "net-name=network-name,v4-fixed-ip=ip-addr,"
@ -203,7 +233,18 @@ def _parse_nics(cs, args):
"with only one of net-id, net-name or port-id " "with only one of net-id, net-name or port-id "
"specified. Specifying a --nic of auto or none cannot " "specified. Specifying a --nic of auto or none cannot "
"be used with any other --nic value.")) "be used with any other --nic value."))
elif cs.api_version >= api_versions.APIVersion('2.32'): elif supports_auto_alloc and not supports_nic_tags:
# 2.41 >= API version >= 2.37
err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of "
"the form --nic <auto,none,net-id=net-uuid,"
"net-name=network-name,v4-fixed-ip=ip-addr,"
"v6-fixed-ip=ip-addr,port-id=port-uuid>, "
"with only one of net-id, net-name or port-id "
"specified. Specifying a --nic of auto or none cannot "
"be used with any other --nic value."))
elif not supports_auto_alloc and supports_nic_tags:
# 2.36 >= API version >= 2.32
nic_info.update({"tag": ""})
err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of " err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of "
"the form --nic <net-id=net-uuid," "the form --nic <net-id=net-uuid,"
"net-name=network-name,v4-fixed-ip=ip-addr," "net-name=network-name,v4-fixed-ip=ip-addr,"
@ -211,6 +252,7 @@ def _parse_nics(cs, args):
"with only one of net-id, net-name or port-id " "with only one of net-id, net-name or port-id "
"specified.")) "specified."))
else: else:
# API version <= 2.31
err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of " err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of "
"the form --nic <net-id=net-uuid," "the form --nic <net-id=net-uuid,"
"net-name=network-name,v4-fixed-ip=ip-addr," "net-name=network-name,v4-fixed-ip=ip-addr,"
@ -220,9 +262,6 @@ def _parse_nics(cs, args):
auto_or_none = False auto_or_none = False
nics = [] nics = []
for nic_str in args.nics: for nic_str in args.nics:
nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "",
"port-id": "", "net-name": "", "tag": ""}
for kv_str in nic_str.split(","): for kv_str in nic_str.split(","):
try: try:
# handle the special auto/none cases # handle the special auto/none cases
@ -360,7 +399,7 @@ def _boot(cs, args):
device_name, mapping = bdm.split('=', 1) device_name, mapping = bdm.split('=', 1)
block_device_mapping[device_name] = mapping block_device_mapping[device_name] = mapping
block_device_mapping_v2 = _parse_block_device_mapping_v2(args, image) block_device_mapping_v2 = _parse_block_device_mapping_v2(cs, args, image)
n_boot_args = len(list(filter( n_boot_args = len(list(filter(
bool, (image, args.boot_volume, args.snapshot)))) bool, (image, args.boot_volume, args.snapshot))))
@ -545,6 +584,7 @@ def _boot(cs, args):
action='append', action='append',
default=[], default=[],
start_version='2.32', start_version='2.32',
end_version='2.32',
help=_("Block device mapping with the keys: " help=_("Block device mapping with the keys: "
"id=UUID (image_id, snapshot_id or volume_id only if using source " "id=UUID (image_id, snapshot_id or volume_id only if using source "
"image, snapshot or volume) " "image, snapshot or volume) "
@ -568,6 +608,64 @@ def _boot(cs, args):
"for others need to be specified) and " "for others need to be specified) and "
"shutdown=shutdown behaviour (either preserve or remove, " "shutdown=shutdown behaviour (either preserve or remove, "
"for local destination set to remove).")) "for local destination set to remove)."))
@utils.arg(
'--block-device',
metavar="key1=value1[,key2=value2...]",
action='append',
default=[],
start_version='2.33',
end_version='2.41',
help=_("Block device mapping with the keys: "
"id=UUID (image_id, snapshot_id or volume_id only if using source "
"image, snapshot or volume) "
"source=source type (image, snapshot, volume or blank), "
"dest=destination type of the block device (volume or local), "
"bus=device's bus (e.g. uml, lxc, virtio, ...; if omitted, "
"hypervisor driver chooses a suitable default, "
"honoured only if device type is supplied) "
"type=device type (e.g. disk, cdrom, ...; defaults to 'disk') "
"device=name of the device (e.g. vda, xda, ...; "
"if omitted, hypervisor driver chooses suitable device "
"depending on selected bus; note the libvirt driver always "
"uses default device names), "
"size=size of the block device in MB(for swap) and in "
"GB(for other formats) "
"(if omitted, hypervisor driver calculates size), "
"format=device will be formatted (e.g. swap, ntfs, ...; optional), "
"bootindex=integer used for ordering the boot disks "
"(for image backed instances it is equal to 0, "
"for others need to be specified) and "
"shutdown=shutdown behaviour (either preserve or remove, "
"for local destination set to remove)."))
@utils.arg(
'--block-device',
metavar="key1=value1[,key2=value2...]",
action='append',
default=[],
start_version='2.42',
help=_("Block device mapping with the keys: "
"id=UUID (image_id, snapshot_id or volume_id only if using source "
"image, snapshot or volume) "
"source=source type (image, snapshot, volume or blank), "
"dest=destination type of the block device (volume or local), "
"bus=device's bus (e.g. uml, lxc, virtio, ...; if omitted, "
"hypervisor driver chooses a suitable default, "
"honoured only if device type is supplied) "
"type=device type (e.g. disk, cdrom, ...; defaults to 'disk') "
"device=name of the device (e.g. vda, xda, ...; "
"if omitted, hypervisor driver chooses suitable device "
"depending on selected bus; note the libvirt driver always "
"uses default device names), "
"size=size of the block device in MB(for swap) and in "
"GB(for other formats) "
"(if omitted, hypervisor driver calculates size), "
"format=device will be formatted (e.g. swap, ntfs, ...; optional), "
"bootindex=integer used for ordering the boot disks "
"(for image backed instances it is equal to 0, "
"for others need to be specified), "
"shutdown=shutdown behaviour (either preserve or remove, "
"for local destination set to remove) and "
"tag=device metadata tag (optional)."))
@utils.arg( @utils.arg(
'--swap', '--swap',
metavar="<swap_size>", metavar="<swap_size>",
@ -609,7 +707,7 @@ def _boot(cs, args):
@utils.arg( @utils.arg(
'--nic', '--nic',
metavar="<net-id=net-uuid,net-name=network-name,v4-fixed-ip=ip-addr," metavar="<net-id=net-uuid,net-name=network-name,v4-fixed-ip=ip-addr,"
"v6-fixed-ip=ip-addr,port-id=port-uuid>", "v6-fixed-ip=ip-addr,port-id=port-uuid,tag=tag>",
action='append', action='append',
dest='nics', dest='nics',
default=[], default=[],
@ -629,11 +727,36 @@ def _boot(cs, args):
'--nic', '--nic',
metavar="<auto,none," metavar="<auto,none,"
"net-id=net-uuid,net-name=network-name,port-id=port-uuid," "net-id=net-uuid,net-name=network-name,port-id=port-uuid,"
"v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,tag=tag>", "v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>",
action='append', action='append',
dest='nics', dest='nics',
default=[], default=[],
start_version='2.37', start_version='2.37',
end_version='2.41',
help=_("Create a NIC on the server. "
"Specify option multiple times to create multiple nics unless "
"using the special 'auto' or 'none' values. "
"auto: automatically allocate network resources if none are "
"available. This cannot be specified with any other nic value and "
"cannot be specified multiple times. "
"none: do not attach a NIC at all. This cannot be specified "
"with any other nic value and cannot be specified multiple times. "
"net-id: attach NIC to network with a specific UUID. "
"net-name: attach NIC to network with this name "
"(either port-id or net-id or net-name must be provided), "
"v4-fixed-ip: IPv4 fixed address for NIC (optional), "
"v6-fixed-ip: IPv6 fixed address for NIC (optional), "
"port-id: attach NIC to port with this UUID "
"(either port-id or net-id must be provided)."))
@utils.arg(
'--nic',
metavar="<auto,none,"
"net-id=net-uuid,net-name=network-name,port-id=port-uuid,"
"v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,tag=tag>",
action='append',
dest='nics',
default=[],
start_version='2.42',
help=_("Create a NIC on the server. " help=_("Create a NIC on the server. "
"Specify option multiple times to create multiple nics unless " "Specify option multiple times to create multiple nics unless "
"using the special 'auto' or 'none' values. " "using the special 'auto' or 'none' values. "

View File

@ -0,0 +1,13 @@
---
fixes:
- |
Microversion 2.42 is related to the following bug.
* https://bugs.launchpad.net/nova/+bug/1658571
The following options have been changed as of Microversion 2.42.
* Remove ``tag`` attribute in ``--block-device`` option
on the server boot (nova boot) between microversion 2.33 and 2.41.
* Remove ``tag`` attribute in ``--nic`` option
on the server boot (nova boot) between microversion 2.37 and 2.41.