diff options
author | Zuul <zuul@review.openstack.org> | 2018-10-16 03:37:42 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2018-10-16 03:37:42 +0000 |
commit | f0c63de21d180994a3635d04b778923a9a2247dc (patch) | |
tree | 8cee4cef13fb2681cc1aad92a2584b2821325b47 | |
parent | 3881e0ba34cb3a088bda81ca825f844b8bbf4785 (diff) | |
parent | 4fef02de71d86c1aa0cb1ace74abd0fe19e0a1e9 (diff) | |
download | python-novaclient-f0c63de21d180994a3635d04b778923a9a2247dc.tar.gz |
Merge "Add support for microversion 2.67: BDMv2 volume_type"
-rw-r--r-- | doc/source/cli/nova.rst | 10 | ||||
-rw-r--r-- | novaclient/__init__.py | 2 | ||||
-rw-r--r-- | novaclient/tests/unit/utils.py | 2 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/test_servers.py | 45 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/test_shell.py | 73 | ||||
-rw-r--r-- | novaclient/v2/servers.py | 8 | ||||
-rw-r--r-- | novaclient/v2/shell.py | 42 | ||||
-rw-r--r-- | releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml | 10 |
8 files changed, 187 insertions, 5 deletions
diff --git a/doc/source/cli/nova.rst b/doc/source/cli/nova.rst index a8ff713c..a444c297 100644 --- a/doc/source/cli/nova.rst +++ b/doc/source/cli/nova.rst @@ -1036,9 +1036,13 @@ Boot a new server. 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). (Supported by API versions '2.42' - - '2.latest') + remove), tag=device metadata tag + (optional; supported by API versions '2.42' + - '2.latest'), and volume_type=type of volume + to create (either ID or name) when source is + `blank`, `image` or `snapshot` and dest is `volume` + (optional; supported by API versions '2.67' + - '2.latest'). ``--swap <swap_size>`` Create and attach a local swap block device of diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 49bd667d..43a8d1a9 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.66") +API_MAX_VERSION = api_versions.APIVersion("2.67") diff --git a/novaclient/tests/unit/utils.py b/novaclient/tests/unit/utils.py index 49d3631f..0050941b 100644 --- a/novaclient/tests/unit/utils.py +++ b/novaclient/tests/unit/utils.py @@ -104,7 +104,7 @@ class FixturedTestCase(testscenarios.TestWithScenarios, TestCase): if not isinstance(body, six.string_types): # json load if the input body to match against is not a string req_data = jsonutils.loads(req_data) - self.assertEqual(req_data, body) + self.assertEqual(body, req_data) class TestResponse(requests.Response): diff --git a/novaclient/tests/unit/v2/test_servers.py b/novaclient/tests/unit/v2/test_servers.py index 540968cf..427a4eff 100644 --- a/novaclient/tests/unit/v2/test_servers.py +++ b/novaclient/tests/unit/v2/test_servers.py @@ -1609,3 +1609,48 @@ class ServersV263Test(ServersV257Test): '1234', fakes.FAKE_IMAGE_UUID_1, trusted_image_certificates=['id1', 'id2']) self.assertIn('trusted_image_certificates', six.text_type(ex)) + + +class ServersV267Test(ServersV263Test): + """Tests for creating a server with a block_device_mapping_v2 entry + using volume_type for microversion 2.67. + """ + api_version = '2.67' + + def test_create_server_boot_from_volume_with_volume_type(self): + bdm = [{"volume_size": 1, + "uuid": "11111111-1111-1111-1111-111111111111", + "delete_on_termination": True, + "source_type": "snapshot", + "destination_type": "volume", + "boot_index": 0, + "volume_type": "rbd"}] + s = self.cs.servers.create( + name="bfv server", image='', flavor=1, + nics='auto', block_device_mapping_v2=bdm) + self.assert_request_id(s, fakes.FAKE_REQUEST_ID_LIST) + self.assert_called('POST', '/servers', { + 'server': { + 'flavorRef': '1', + 'imageRef': '', + 'name': 'bfv server', + 'networks': 'auto', + 'block_device_mapping_v2': bdm, + 'min_count': 1, + 'max_count': 1, + }}) + + def test_create_server_boot_from_volume_with_volume_type_pre_267(self): + self.cs.api_version = api_versions.APIVersion('2.66') + bdm = [{"volume_size": 1, + "uuid": "11111111-1111-1111-1111-111111111111", + "delete_on_termination": True, + "source_type": "snapshot", + "destination_type": "volume", + "boot_index": 0, + "volume_type": "rbd"}] + ex = self.assertRaises(ValueError, self.cs.servers.create, + name="bfv server", image='', flavor=1, + nics='none', block_device_mapping_v2=bdm) + self.assertIn("Block device volume_type is not supported before " + "microversion 2.67", six.text_type(ex)) diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index 830ce53d..216241ec 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -624,6 +624,78 @@ class ShellTest(utils.TestCase): 'size=1,format=ext4,type=disk,shutdown=foobar ' 'some-server' % FAKE_UUID_1)) + def test_boot_from_volume_with_volume_type_old_microversion(self): + ex = self.assertRaises( + exceptions.CommandError, self.run_command, + 'boot --flavor 1 --block-device id=%s,source=image,dest=volume,' + 'size=1,bootindex=0,shutdown=remove,tag=foo,volume_type=lvm ' + 'bfv-server' % FAKE_UUID_1, api_version='2.66') + self.assertIn("'volume_type' in block device mapping is not supported " + "in API version", six.text_type(ex)) + + def test_boot_from_volume_with_volume_type(self): + """Tests creating a volume-backed server from a source image and + specifying the type of volume to create with microversion 2.67. + """ + self.run_command( + 'boot --flavor 1 --block-device id=%s,source=image,dest=volume,' + 'size=1,bootindex=0,shutdown=remove,tag=foo,volume_type=lvm ' + 'bfv-server' % FAKE_UUID_1, api_version='2.67') + self.assert_called_anytime( + 'POST', '/servers', + {'server': { + 'flavorRef': '1', + 'name': 'bfv-server', + 'block_device_mapping_v2': [ + { + 'uuid': FAKE_UUID_1, + 'source_type': 'image', + 'destination_type': 'volume', + 'volume_size': '1', + 'delete_on_termination': True, + 'tag': 'foo', + 'boot_index': '0', + 'volume_type': 'lvm' + }, + ], + 'networks': 'auto', + 'imageRef': '', + 'min_count': 1, + 'max_count': 1, + }}) + + def test_boot_from_volume_without_volume_type_2_67(self): + """Tests creating a volume-backed server from a source image but + without specifying the type of volume to create with microversion 2.67. + The volume_type parameter should be omitted in the request to the + API server. + """ + self.run_command( + 'boot --flavor 1 --block-device id=%s,source=image,dest=volume,' + 'size=1,bootindex=0,shutdown=remove,tag=foo bfv-server' % + FAKE_UUID_1, api_version='2.67') + self.assert_called_anytime( + 'POST', '/servers', + {'server': { + 'flavorRef': '1', + 'name': 'bfv-server', + 'block_device_mapping_v2': [ + { + 'uuid': FAKE_UUID_1, + 'source_type': 'image', + 'destination_type': 'volume', + 'volume_size': '1', + 'delete_on_termination': True, + 'tag': 'foo', + 'boot_index': '0', + }, + ], + 'networks': 'auto', + 'imageRef': '', + 'min_count': 1, + 'max_count': 1, + }}) + def test_boot_metadata(self): self.run_command('boot --image %s --flavor 1 --meta foo=bar=pants' ' --meta spam=eggs some-server ' % FAKE_UUID_1) @@ -3913,6 +3985,7 @@ class ShellTest(utils.TestCase): 62, # There are no version-wrapped shell method changes for this. 63, # There are no version-wrapped shell method changes for this. 65, # There are no version-wrapped shell method changes for this. + 67, # 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/servers.py b/novaclient/v2/servers.py index d872fa01..e94f3567 100644 --- a/novaclient/v2/servers.py +++ b/novaclient/v2/servers.py @@ -1305,6 +1305,14 @@ class ServerManager(base.BootingManagerWithFind): raise exceptions.UnsupportedAttribute("trusted_image_certificates", "2.63") + if (block_device_mapping_v2 and + self.api_version < api_versions.APIVersion('2.67')): + for bdm in block_device_mapping_v2: + if bdm.get('volume_type'): + raise ValueError( + "Block device volume_type is not supported before " + "microversion 2.67") + boot_kwargs = dict( meta=meta, files=files, userdata=userdata, reservation_id=reservation_id, min_count=min_count, diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index ae7344bf..f6704559 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -71,6 +71,7 @@ CLIENT_BDM2_KEYS = { 'type': 'device_type', 'shutdown': 'delete_on_termination', 'tag': 'tag', + 'volume_type': 'volume_type' # added in 2.67 } @@ -145,6 +146,8 @@ def _parse_block_device_mapping_v2(cs, args, image): 'delete_on_termination': False} bdm.append(bdm_dict) + supports_volume_type = cs.api_version == api_versions.APIVersion('2.67') + for device_spec in args.block_device: spec_dict = _parse_device_spec(device_spec) bdm_dict = {} @@ -155,6 +158,12 @@ def _parse_block_device_mapping_v2(cs, args, image): "in API version %(version)s.") % {'version': cs.api_version.get_string()}) + if 'volume_type' in spec_dict and not supports_volume_type: + raise exceptions.CommandError( + _("'volume_type' 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 @@ -709,6 +718,7 @@ def _boot(cs, args): action='append', default=[], start_version='2.42', + end_version='2.66', help=_("Block device mapping with the keys: " "id=UUID (image_id, snapshot_id or volume_id only if using source " "image, snapshot or volume) " @@ -733,6 +743,38 @@ def _boot(cs, args): "for local destination set to remove) and " "tag=device metadata tag (optional).")) @utils.arg( + '--block-device', + metavar="key1=value1[,key2=value2...]", + action='append', + default=[], + start_version='2.67', + 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 " + "GiB(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), " + "volume_type=type of volume to create (either ID or name) when " + "source is blank, image or snapshot and dest is volume (optional)." + )) +@utils.arg( '--swap', metavar="<swap_size>", default=None, diff --git a/releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml b/releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml new file mode 100644 index 00000000..0c1e360a --- /dev/null +++ b/releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Support is added for the `2.67 microversion`_ which allows specifying + a ``volume_type`` with the ``--block-device`` option on the ``nova boot`` + command. The ``novaclient.v2.servers.ServerManager.create()`` method now + also supports a ``volume_type`` entry in the ``block_device_mapping_v2`` + parameter. + + .. _2.67 microversion: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id60 |