diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 0816b4f61..7c0d2c937 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -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.41") +API_MAX_VERSION = api_versions.APIVersion("2.42") diff --git a/novaclient/tests/functional/v2/test_device_tagging.py b/novaclient/tests/functional/v2/test_device_tagging.py index 033b43739..c19c42403 100644 --- a/novaclient/tests/functional/v2/test_device_tagging.py +++ b/novaclient/tests/functional/v2/test_device_tagging.py @@ -13,24 +13,159 @@ # under the License. from oslo_utils import uuidutils +import six +from tempest.lib import exceptions 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" - 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=( '%(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,tag=bar' % {'name': uuidutils.generate_uuid(), - 'flavor': self.flavor.id, - 'net-uuid': self.network.id, - 'image': self.image.id})) + '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})) 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 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" diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index 266b89a6e..7e1d28fca 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -2880,6 +2880,7 @@ class ShellTest(utils.TestCase): 38, # doesn't require any changes in novaclient 39, # There are no versioned 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, novaclient.API_MAX_VERSION.ver_minor + 1)) diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index dd027f977..42bf9b7f7 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -106,7 +106,15 @@ def _match_image(cs, wanted_properties): 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 = [] 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(',')) 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(): bdm_dict[CLIENT_BDM2_KEYS[key]] = value @@ -193,9 +207,25 @@ def _parse_block_device_mapping_v2(args, image): 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): 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 " "the form --nic = 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 , " + "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 " "the form --nic ", + "v6-fixed-ip=ip-addr,port-id=port-uuid,tag=tag>", action='append', dest='nics', default=[], @@ -629,11 +727,36 @@ def _boot(cs, args): '--nic', metavar="", + "v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>", action='append', dest='nics', default=[], 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="", + action='append', + dest='nics', + default=[], + start_version='2.42', help=_("Create a NIC on the server. " "Specify option multiple times to create multiple nics unless " "using the special 'auto' or 'none' values. " diff --git a/releasenotes/notes/fix-tag-attribute-disappearing-25483a80f548ef35.yaml b/releasenotes/notes/fix-tag-attribute-disappearing-25483a80f548ef35.yaml new file mode 100644 index 000000000..7f6ed29ec --- /dev/null +++ b/releasenotes/notes/fix-tag-attribute-disappearing-25483a80f548ef35.yaml @@ -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.