Add support for microversion 2.67: BDMv2 volume_type
This adds the nova boot command and python API binding support for creating a server with block device mappings defined using a specific volume type. Depends-On: https://review.openstack.org/606398/ Depends-On: https://review.openstack.org/#/c/610349/ Part of blueprint boot-instance-specific-storage-backend Change-Id: I484ee065119b5783db212ea64efa60e87c40338c
This commit is contained in:
parent
0fdb154d9c
commit
4fef02de71
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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) "
|
||||
@ -732,6 +742,38 @@ def _boot(cs, args):
|
||||
"shutdown=shutdown behaviour (either preserve or remove, "
|
||||
"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>",
|
||||
|
10
releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml
Normal file
10
releasenotes/notes/microversion-v2_67-da6d9b12730b8562.yaml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user