Servers API for the new BDM format
This patch makes the nova API aware and able to accept the new block device mapping format introduced in If30afdb59d4c4268b97d3d10270df2cc729a0c4c when booting an instance. It does so by introducing a new extension into the v2 API. There is no v3 extension as part of this patch because volume extension is going away in v3 and thus this functionality can be part of the core servers extension. This will be done in a subsequent patch. The compute API create method will still convert these back to the legacy format for the time being until the compute API will know how to take advantage of the new format. As this change adds the new API extension, marking it as DocImpact so that the changes and the API data format can be documented. blueprint: improve-block-device-handling Change-Id: I2c1b63e41deca26f727fb9ed912a55494db9c76c
This commit is contained in:
parent
84b730b70f
commit
8c3475706d
@ -64,14 +64,6 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_status/api/v1.1",
|
||||
"updated": "2011-11-03T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-extended-volumes",
|
||||
"description": "Extended Volumes support.",
|
||||
"links": [],
|
||||
"name": "ExtendedVolumes",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_volumes/api/v1.1",
|
||||
"updated": "2013-06-07T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "OS-EXT-VIF-NET",
|
||||
"description": "Adds network id parameter to the virtual interface list.",
|
||||
@ -160,6 +152,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/baremetal_nodes/api/v2",
|
||||
"updated": "2013-01-04T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-block-device-mapping-v2-boot",
|
||||
"description": "Allow boot with the new BDM data format.",
|
||||
"links": [],
|
||||
"name": "BlockDeviceMappingV2Boot",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/block_device_mapping_v2_boot/api/v2",
|
||||
"updated": "2013-07-08T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-cell-capacities",
|
||||
"description": "Adding functionality to get cell capacities.",
|
||||
@ -280,6 +280,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_services/api/v2",
|
||||
"updated": "2013-05-17T00:00:00-00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-extended-volumes",
|
||||
"description": "Extended Volumes support.",
|
||||
"links": [],
|
||||
"name": "ExtendedVolumes",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_volumes/api/v1.1",
|
||||
"updated": "2013-06-07T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-fixed-ips",
|
||||
"description": "Fixed IPs support.",
|
||||
@ -416,6 +424,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/keypairs/api/v1.1",
|
||||
"updated": "2011-08-08T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-migrations",
|
||||
"description": "Provide data on migrations.",
|
||||
"links": [],
|
||||
"name": "Migrations",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/migrations/api/v2.0",
|
||||
"updated": "2013-05-30T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-multiple-create",
|
||||
"description": "Allow multiple create in the Create Server v1.1 API.",
|
||||
@ -591,14 +607,6 @@
|
||||
"name": "Volumes",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/volumes/api/v1.1",
|
||||
"updated": "2011-03-25T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-migrations",
|
||||
"description": "Provide data on migrations.",
|
||||
"links": [],
|
||||
"name": "Migrations",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/migrations/api/v2.0",
|
||||
"updated": "2013-05-30T00:00:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -24,9 +24,6 @@
|
||||
<extension alias="OS-EXT-STS" updated="2011-11-03T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" name="ExtendedStatus">
|
||||
<description>Extended Status support.</description>
|
||||
</extension>
|
||||
<extension alias="os-extended-volumes" updated="2013-06-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/extended_volumes/api/v1.1" name="ExtendedVolumes">
|
||||
<description>Extended Volumes support.</description>
|
||||
</extension>
|
||||
<extension alias="OS-EXT-VIF-NET" updated="2013-03-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/extended-virtual-interfaces-net/api/v1.1" name="ExtendedVIFNet">
|
||||
<description>Adds network id parameter to the virtual interface list.</description>
|
||||
</extension>
|
||||
@ -66,6 +63,9 @@
|
||||
<extension alias="os-baremetal-nodes" updated="2013-01-04T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/baremetal_nodes/api/v2" name="BareMetalNodes">
|
||||
<description>Admin-only bare-metal node administration.</description>
|
||||
</extension>
|
||||
<extension alias="os-block-device-mapping-v2-boot" updated="2013-07-08T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/block_device_mapping_v2_boot/api/v2" name="BlockDeviceMappingV2Boot">
|
||||
<description>Allow boot with the new BDM data format.</description>
|
||||
</extension>
|
||||
<extension alias="os-cell-capacities" updated="2013-05-27T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/cell_capacities/api/v1.1" name="CellCapacities">
|
||||
<description>Adding functionality to get cell capacities.</description>
|
||||
</extension>
|
||||
@ -123,6 +123,9 @@
|
||||
<extension alias="os-extended-services" updated="2013-05-17T00:00:00-00:00" namespace="http://docs.openstack.org/compute/ext/extended_services/api/v2" name="ExtendedServices">
|
||||
<description>Extended services support.</description>
|
||||
</extension>
|
||||
<extension alias="os-extended-volumes" updated="2013-06-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/extended_volumes/api/v1.1" name="ExtendedVolumes">
|
||||
<description>Extended Volumes support.</description>
|
||||
</extension>
|
||||
<extension alias="os-fixed-ips" updated="2012-10-18T13:25:27-06:00" namespace="http://docs.openstack.org/compute/ext/fixed_ips/api/v2" name="FixedIPs">
|
||||
<description>Fixed IPs support.</description>
|
||||
</extension>
|
||||
@ -176,6 +179,9 @@
|
||||
<extension alias="os-keypairs" updated="2011-08-08T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/keypairs/api/v1.1" name="Keypairs">
|
||||
<description>Keypair Support.</description>
|
||||
</extension>
|
||||
<extension alias="os-migrations" updated="2013-05-30T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/migrations/api/v2.0" name="Migrations">
|
||||
<description>Provide data on migrations.</description>
|
||||
</extension>
|
||||
<extension alias="os-multiple-create" updated="2012-08-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/multiplecreate/api/v1.1" name="MultipleCreate">
|
||||
<description>Allow multiple create in the Create Server v1.1 API.</description>
|
||||
</extension>
|
||||
@ -242,8 +248,4 @@
|
||||
<extension alias="os-volumes" updated="2011-03-25T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes">
|
||||
<description>Volumes support.</description>
|
||||
</extension>
|
||||
<extension alias="os-migrations" updated="2013-05-30T00:00:00+00:00"
|
||||
namespace="http://docs.openstack.org/compute/ext/migrations/api/v2.0" name="Migrations">
|
||||
<description>Provide data on migrations.</description>
|
||||
</extension>
|
||||
</extensions>
|
||||
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavorRef" : "http://openstack.example.com/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"block_device_mapping_v2": [
|
||||
{
|
||||
"device_name": "/dev/sdb1",
|
||||
"source_type": "blank",
|
||||
"destination_type": "local",
|
||||
"delete_on_termination": "True",
|
||||
"guest_format": "swap",
|
||||
"boot_index": "-1"
|
||||
},
|
||||
{
|
||||
"device_name": "/dev/sda1",
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"uuid": "fake-volume-id-1",
|
||||
"boot_index": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b" flavorRef="http://openstack.example.com/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
<block_device_mapping_v2>
|
||||
<mapping device_name="/dev/sdb1" source_type="blank" destination_type="local" delete_on_termination="True" guest_format="swap" boot_index="-1"></mapping>
|
||||
<mapping device_name="/dev/sda1" source_type="volume" destination_type="volume" uuid="fake-volume-id-1" boot_index="0"></mapping>
|
||||
</block_device_mapping_v2>
|
||||
</server>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "N4x7wFX6iN8D",
|
||||
"id": "babd1af0-4fc6-4529-b32f-aad69811ccf5",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/openstack/servers/babd1af0-4fc6-4529-b32f-aad69811ccf5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/servers/babd1af0-4fc6-4529-b32f-aad69811ccf5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="fdbce07b-097e-4ab1-8141-b1c847861aa1" adminPass="zA62GVkFvN74">
|
||||
<metadata/>
|
||||
<atom:link href="http://openstack.example.com/v2/openstack/servers/fdbce07b-097e-4ab1-8141-b1c847861aa1" rel="self"/>
|
||||
<atom:link href="http://openstack.example.com/openstack/servers/fdbce07b-097e-4ab1-8141-b1c847861aa1" rel="bookmark"/>
|
||||
</server>
|
@ -0,0 +1,23 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
|
||||
|
||||
class Block_device_mapping_v2_boot(extensions.ExtensionDescriptor):
|
||||
"""Allow boot with the new BDM data format."""
|
||||
|
||||
name = "BlockDeviceMappingV2Boot"
|
||||
alias = "os-block-device-mapping-v2-boot"
|
||||
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||
"block_device_mapping_v2_boot/api/v2")
|
||||
updated = "2013-07-08T00:00:00+00:00"
|
@ -27,6 +27,7 @@ from nova.api.openstack.compute import ips
|
||||
from nova.api.openstack.compute.views import servers as views_servers
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api.openstack import xmlutil
|
||||
from nova import block_device
|
||||
from nova import compute
|
||||
from nova.compute import flavors
|
||||
from nova import exception
|
||||
@ -219,6 +220,11 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
|
||||
if block_device_mapping is not None:
|
||||
server["block_device_mapping"] = block_device_mapping
|
||||
|
||||
block_device_mapping_v2 = self._extract_block_device_mapping_v2(
|
||||
server_node)
|
||||
if block_device_mapping_v2 is not None:
|
||||
server["block_device_mapping_v2"] = block_device_mapping_v2
|
||||
|
||||
# NOTE(vish): Support this incorrect version because it was in the code
|
||||
# base for a while and we don't want to accidentally break
|
||||
# anyone that might be using it.
|
||||
@ -261,6 +267,21 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
|
||||
else:
|
||||
return None
|
||||
|
||||
def _extract_block_device_mapping_v2(self, server_node):
|
||||
"""Marshal the new block_device_mappings."""
|
||||
node = self.find_first_child_named(server_node,
|
||||
"block_device_mapping_v2")
|
||||
if node:
|
||||
block_device_mapping = []
|
||||
for child in self.extract_elements(node):
|
||||
if child.nodeName != "mapping":
|
||||
continue
|
||||
block_device_mapping.append(
|
||||
dict((attr, child.getAttribute(attr))
|
||||
for attr in block_device.bdm_new_api_fields
|
||||
if child.getAttribute(attr)))
|
||||
return block_device_mapping
|
||||
|
||||
def _extract_scheduler_hints(self, server_node):
|
||||
"""Marshal the scheduler hints attribute of a parsed request."""
|
||||
node = self.find_first_child_named_in_namespace(server_node,
|
||||
@ -831,6 +852,8 @@ class Controller(wsgi.Controller):
|
||||
availability_zone = server_dict.get('availability_zone')
|
||||
|
||||
block_device_mapping = None
|
||||
block_device_mapping_v2 = None
|
||||
legacy_bdm = True
|
||||
if self.ext_mgr.is_loaded('os-volumes'):
|
||||
block_device_mapping = server_dict.get('block_device_mapping', [])
|
||||
for bdm in block_device_mapping:
|
||||
@ -842,6 +865,28 @@ class Controller(wsgi.Controller):
|
||||
bdm['delete_on_termination'] = strutils.bool_from_string(
|
||||
bdm['delete_on_termination'])
|
||||
|
||||
if self.ext_mgr.is_loaded('os-block-device-mapping-v2-boot'):
|
||||
# Consider the new data format for block device mapping
|
||||
block_device_mapping_v2 = server_dict.get(
|
||||
'block_device_mapping_v2', [])
|
||||
# NOTE (ndipanov): Disable usage of both legacy and new
|
||||
# block device format in the same request
|
||||
if block_device_mapping and block_device_mapping_v2:
|
||||
expl = _('Using different block_device_mapping syntaxes '
|
||||
'is not allowed in the same request.')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
# Assume legacy format
|
||||
legacy_bdm = not bool(block_device_mapping_v2)
|
||||
|
||||
# This will also do basic validation of block_devices
|
||||
block_device_mapping_v2 = [
|
||||
block_device.BlockDeviceDict.from_api(bdm_dict)
|
||||
for bdm_dict in block_device_mapping_v2]
|
||||
|
||||
block_device_mapping = (block_device_mapping or
|
||||
block_device_mapping_v2)
|
||||
|
||||
ret_resv_id = False
|
||||
# min_count and max_count are optional. If they exist, they may come
|
||||
# in as strings. Verify that they are valid integers and > 0.
|
||||
@ -898,7 +943,8 @@ class Controller(wsgi.Controller):
|
||||
config_drive=config_drive,
|
||||
block_device_mapping=block_device_mapping,
|
||||
auto_disk_config=auto_disk_config,
|
||||
scheduler_hints=scheduler_hints)
|
||||
scheduler_hints=scheduler_hints,
|
||||
legacy_bdm=legacy_bdm)
|
||||
except exception.QuotaError as error:
|
||||
raise exc.HTTPRequestEntityTooLarge(
|
||||
explanation=error.format_message(),
|
||||
@ -1145,8 +1191,12 @@ class Controller(wsgi.Controller):
|
||||
"""
|
||||
image_ref = data['server'].get('imageRef')
|
||||
bdm = data['server'].get('block_device_mapping')
|
||||
bdm_v2 = data['server'].get('block_device_mapping_v2')
|
||||
|
||||
if not image_ref and bdm and self.ext_mgr.is_loaded('os-volumes'):
|
||||
if (not image_ref and (
|
||||
(bdm and self.ext_mgr.is_loaded('os-volumes')) or
|
||||
(bdm_v2 and
|
||||
self.ext_mgr.is_loaded('os-block-device-mapping-v2-boot')))):
|
||||
return ''
|
||||
else:
|
||||
image_href = self._image_ref_from_req_data(data)
|
||||
|
@ -54,6 +54,17 @@ bdm_db_inherited_fields = set(['created_at', 'updated_at',
|
||||
'deleted_at', 'deleted'])
|
||||
|
||||
|
||||
bdm_new_non_api_fields = set(['volume_id', 'snapshot_id',
|
||||
'image_id', 'connection_info'])
|
||||
|
||||
|
||||
bdm_new_api_only_fields = set(['uuid'])
|
||||
|
||||
|
||||
bdm_new_api_fields = ((bdm_new_fields - bdm_new_non_api_fields) |
|
||||
bdm_new_api_only_fields)
|
||||
|
||||
|
||||
class BlockDeviceDict(dict):
|
||||
"""Represents a Block Device Mapping in Nova."""
|
||||
|
||||
@ -126,6 +137,27 @@ class BlockDeviceDict(dict):
|
||||
|
||||
return cls(new_bdm, non_computable_fields)
|
||||
|
||||
@classmethod
|
||||
def from_api(cls, api_dict):
|
||||
"""Transform the API format of data to the internally used one.
|
||||
|
||||
Only validate if the source_type field makes sense.
|
||||
"""
|
||||
if not api_dict.get('no_device'):
|
||||
|
||||
source_type = api_dict.get('source_type')
|
||||
device_uuid = api_dict.get('uuid')
|
||||
|
||||
if source_type not in ('volume', 'image', 'snapshot', 'blank'):
|
||||
raise exception.InvalidBDMFormat()
|
||||
elif source_type != 'blank':
|
||||
if not device_uuid:
|
||||
raise exception.InvalidBDMFormat()
|
||||
api_dict[source_type + '_id'] = device_uuid
|
||||
|
||||
api_dict.pop('uuid', None)
|
||||
return cls(api_dict)
|
||||
|
||||
def legacy(self):
|
||||
copy_over_fields = bdm_legacy_fields - set(['virtual_name'])
|
||||
copy_over_fields |= (bdm_db_only_fields |
|
||||
|
@ -1098,7 +1098,7 @@ class API(base.Base):
|
||||
injected_files=None, admin_password=None,
|
||||
block_device_mapping=None, access_ip_v4=None,
|
||||
access_ip_v6=None, requested_networks=None, config_drive=None,
|
||||
auto_disk_config=None, scheduler_hints=None):
|
||||
auto_disk_config=None, scheduler_hints=None, legacy_bdm=True):
|
||||
"""
|
||||
Provision instances, sending instance information to the
|
||||
scheduler. The scheduler will determine where the instance(s)
|
||||
@ -1107,6 +1107,15 @@ class API(base.Base):
|
||||
Returns a tuple of (instances, reservation_id)
|
||||
"""
|
||||
|
||||
# NOTE(ndipanov): Deal with block_device_mapping format before
|
||||
# doing any work. We assume that the API class
|
||||
# will be dealing with only one version of block
|
||||
# devices whenever possible to keep the code
|
||||
# simple. Currently this is the legacy format.
|
||||
if block_device_mapping and not legacy_bdm:
|
||||
block_device_mapping = block_device.legacy_mapping(
|
||||
block_device_mapping)
|
||||
|
||||
self._check_create_policies(context, availability_zone,
|
||||
requested_networks, block_device_mapping)
|
||||
|
||||
|
@ -44,28 +44,6 @@ FAKE_UUID_D = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
|
||||
IMAGE_UUID = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
|
||||
|
||||
|
||||
def fake_compute_api_create(cls, context, instance_type, image_href, **kwargs):
|
||||
global _block_device_mapping_seen
|
||||
_block_device_mapping_seen = kwargs.get('block_device_mapping')
|
||||
|
||||
inst_type = flavors.get_flavor_by_flavor_id(2)
|
||||
resv_id = None
|
||||
return ([{'id': 1,
|
||||
'display_name': 'test_server',
|
||||
'uuid': FAKE_UUID,
|
||||
'instance_type': dict(inst_type),
|
||||
'access_ip_v4': '1.2.3.4',
|
||||
'access_ip_v6': 'fead::1234',
|
||||
'image_ref': IMAGE_UUID,
|
||||
'user_id': 'fake',
|
||||
'project_id': 'fake',
|
||||
'created_at': datetime.datetime(2010, 10, 10, 12, 0, 0),
|
||||
'updated_at': datetime.datetime(2010, 11, 11, 11, 0, 0),
|
||||
'progress': 0,
|
||||
'fixed_ips': []
|
||||
}], resv_id)
|
||||
|
||||
|
||||
def fake_get_instance(self, context, instance_id, want_objects=False):
|
||||
return {'uuid': instance_id}
|
||||
|
||||
@ -120,12 +98,40 @@ class BootFromVolumeTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BootFromVolumeTest, self).setUp()
|
||||
self.stubs.Set(compute_api.API, 'create', fake_compute_api_create)
|
||||
self.stubs.Set(compute_api.API, 'create',
|
||||
self._get_fake_compute_api_create())
|
||||
fakes.stub_out_nw_api(self.stubs)
|
||||
self._block_device_mapping_seen = None
|
||||
self._legacy_bdm_seen = True
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Volumes'])
|
||||
osapi_compute_ext_list=['Volumes', 'Block_device_mapping_v2_boot'])
|
||||
|
||||
def _get_fake_compute_api_create(self):
|
||||
def _fake_compute_api_create(cls, context, instance_type,
|
||||
image_href, **kwargs):
|
||||
self._block_device_mapping_seen = kwargs.get(
|
||||
'block_device_mapping')
|
||||
self._legacy_bdm_seen = kwargs.get('legacy_bdm')
|
||||
|
||||
inst_type = flavors.get_flavor_by_flavor_id(2)
|
||||
resv_id = None
|
||||
return ([{'id': 1,
|
||||
'display_name': 'test_server',
|
||||
'uuid': FAKE_UUID,
|
||||
'instance_type': dict(inst_type),
|
||||
'access_ip_v4': '1.2.3.4',
|
||||
'access_ip_v6': 'fead::1234',
|
||||
'image_ref': IMAGE_UUID,
|
||||
'user_id': 'fake',
|
||||
'project_id': 'fake',
|
||||
'created_at': datetime.datetime(2010, 10, 10, 12, 0, 0),
|
||||
'updated_at': datetime.datetime(2010, 11, 11, 11, 0, 0),
|
||||
'progress': 0,
|
||||
'fixed_ips': []
|
||||
}], resv_id)
|
||||
return _fake_compute_api_create
|
||||
|
||||
def test_create_root_volume(self):
|
||||
body = dict(server=dict(
|
||||
@ -138,8 +144,6 @@ class BootFromVolumeTest(test.TestCase):
|
||||
delete_on_termination=False,
|
||||
)]
|
||||
))
|
||||
global _block_device_mapping_seen
|
||||
_block_device_mapping_seen = None
|
||||
req = webob.Request.blank('/v2/fake/os-volumes_boot')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
@ -150,9 +154,40 @@ class BootFromVolumeTest(test.TestCase):
|
||||
server = jsonutils.loads(res.body)['server']
|
||||
self.assertEqual(FAKE_UUID, server['id'])
|
||||
self.assertEqual(CONF.password_length, len(server['adminPass']))
|
||||
self.assertEqual(len(_block_device_mapping_seen), 1)
|
||||
self.assertEqual(_block_device_mapping_seen[0]['volume_id'], 1)
|
||||
self.assertEqual(_block_device_mapping_seen[0]['device_name'],
|
||||
self.assertEqual(len(self._block_device_mapping_seen), 1)
|
||||
self.assertTrue(self._legacy_bdm_seen)
|
||||
self.assertEqual(self._block_device_mapping_seen[0]['volume_id'], 1)
|
||||
self.assertEqual(self._block_device_mapping_seen[0]['device_name'],
|
||||
'/dev/vda')
|
||||
|
||||
def test_create_root_volume_bdm_v2(self):
|
||||
body = dict(server=dict(
|
||||
name='test_server', imageRef=IMAGE_UUID,
|
||||
flavorRef=2, min_count=1, max_count=1,
|
||||
block_device_mapping_v2=[dict(
|
||||
source_type='volume',
|
||||
uuid=1,
|
||||
device_name='/dev/vda',
|
||||
boot_index=0,
|
||||
delete_on_termination=False,
|
||||
)]
|
||||
))
|
||||
req = webob.Request.blank('/v2/fake/os-volumes_boot')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers['content-type'] = 'application/json'
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
init_only=('os-volumes_boot', 'servers')))
|
||||
self.assertEqual(res.status_int, 202)
|
||||
server = jsonutils.loads(res.body)['server']
|
||||
self.assertEqual(FAKE_UUID, server['id'])
|
||||
self.assertEqual(CONF.password_length, len(server['adminPass']))
|
||||
self.assertEqual(len(self._block_device_mapping_seen), 1)
|
||||
self.assertFalse(self._legacy_bdm_seen)
|
||||
self.assertEqual(self._block_device_mapping_seen[0]['volume_id'], 1)
|
||||
self.assertEqual(self._block_device_mapping_seen[0]['boot_index'],
|
||||
0)
|
||||
self.assertEqual(self._block_device_mapping_seen[0]['device_name'],
|
||||
'/dev/vda')
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@ from nova.api.openstack.compute import servers
|
||||
from nova.api.openstack.compute import views
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import xmlutil
|
||||
from nova import block_device
|
||||
from nova.compute import api as compute_api
|
||||
from nova.compute import flavors
|
||||
from nova.compute import task_states
|
||||
@ -2454,6 +2455,18 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, {}, no_image=True)
|
||||
|
||||
def test_create_instance_with_bdm_v2_enabled_no_image(self):
|
||||
self.ext_mgr.extensions = {'os-block-device-mapping-v2-boot': 'fake'}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertNotIn('imageRef', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, {}, no_image=True)
|
||||
|
||||
def test_create_instance_with_volumes_enabled_and_bdms_no_image(self):
|
||||
"""
|
||||
Test that the create works if there is no image supplied but
|
||||
@ -2494,6 +2507,40 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
self._test_create_extra(params, no_image=True)
|
||||
|
||||
def test_create_instance_with_bdm_v2_enabled_and_bdms_no_image(self):
|
||||
self.ext_mgr.extensions = {
|
||||
'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm_v2 = [{
|
||||
'no_device': None,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'uuid': self.volume_id,
|
||||
'device_name': 'vda',
|
||||
'delete_on_termination': False,
|
||||
}]
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertThat(block_device.BlockDeviceDict(bdm_v2[0]),
|
||||
matchers.DictMatches(
|
||||
kwargs['block_device_mapping'][0]))
|
||||
self.assertNotIn('imageRef', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.mox.StubOutWithMock(compute_api.API, '_validate_bdm')
|
||||
self.mox.StubOutWithMock(compute_api.API, '_get_volume_image_metadata')
|
||||
|
||||
compute_api.API._validate_bdm(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(True)
|
||||
compute_api.API._get_volume_image_metadata(
|
||||
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({})
|
||||
self.mox.ReplayAll()
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
|
||||
self._test_create_extra(params, no_image=True)
|
||||
|
||||
def test_create_instance_with_volumes_disabled(self):
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
params = {'block_device_mapping': bdm}
|
||||
@ -2554,6 +2601,7 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertTrue(kwargs['legacy_bdm'])
|
||||
self.assertEqual(kwargs['block_device_mapping'], self.bdm)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
@ -2615,6 +2663,96 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm', _validate_bdm)
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_bdm_v2(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm_v2 = [{'source_type': 'volume',
|
||||
'uuid': 'fake_vol'}]
|
||||
bdm_v2_expected = [{'source_type': 'volume',
|
||||
'volume_id': 'fake_vol'}]
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertFalse(kwargs['legacy_bdm'])
|
||||
for expected, received in zip(bdm_v2_expected,
|
||||
kwargs['block_device_mapping']):
|
||||
self.assertThat(block_device.BlockDeviceDict(expected),
|
||||
matchers.DictMatches(received))
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
def _validate_bdm(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm', _validate_bdm)
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_decide_format_legacy(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm = [{'device_name': 'foo1',
|
||||
'volume_id': 'fake_vol',
|
||||
'delete_on_termination': 1}]
|
||||
|
||||
expected_legacy_flag = True
|
||||
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertEqual(kwargs['legacy_bdm'], expected_legacy_flag)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
def _validate_bdm(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm',
|
||||
_validate_bdm)
|
||||
|
||||
self._test_create_extra({})
|
||||
|
||||
params = {'block_device_mapping': bdm}
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_decide_format_new(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
|
||||
bdm_v2 = [{'source_type': 'volume',
|
||||
'device_name': 'fake_dev',
|
||||
'uuid': 'fake_vol'}]
|
||||
|
||||
old_create = compute_api.API.create
|
||||
|
||||
expected_legacy_flag = False
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertEqual(kwargs['legacy_bdm'], expected_legacy_flag)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
def _validate_bdm(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.stubs.Set(compute_api.API, '_validate_bdm',
|
||||
_validate_bdm)
|
||||
|
||||
params = {'block_device_mapping_v2': bdm_v2}
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_both_bdm_formats(self):
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake',
|
||||
'os-block-device-mapping-v2-boot': 'fake'}
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
bdm_v2 = [{'source_type': 'volume',
|
||||
'uuid': 'fake_vol'}]
|
||||
params = {'block_device_mapping': bdm,
|
||||
'block_device_mapping_v2': bdm_v2}
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, params)
|
||||
|
||||
def test_create_instance_with_user_data_enabled(self):
|
||||
self.ext_mgr.extensions = {'os-user-data': 'fake'}
|
||||
user_data = 'fake'
|
||||
|
@ -649,6 +649,10 @@ def stub_volume_get_all_by_project(self, context, search_opts=None):
|
||||
return [stub_volume_get(self, context, '1')]
|
||||
|
||||
|
||||
def stub_volume_check_attach(self, context, *args, **param):
|
||||
pass
|
||||
|
||||
|
||||
def stub_snapshot(id, **kwargs):
|
||||
snapshot = {
|
||||
'id': id,
|
||||
|
@ -160,6 +160,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/baremetal_nodes/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-block-device-mapping-v2-boot",
|
||||
"description": "%(text)s",
|
||||
"links": [],
|
||||
"name": "BlockDeviceMappingV2Boot",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/block_device_mapping_v2_boot/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-cells",
|
||||
"description": "%(text)s",
|
||||
|
@ -60,6 +60,9 @@
|
||||
<extension alias="os-baremetal-nodes" name="BareMetalNodes" namespace="http://docs.openstack.org/compute/ext/baremetal_nodes/api/v2" updated="%(timestamp)s">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-block-device-mapping-v2-boot" name="BlockDeviceMappingV2Boot" namespace="http://docs.openstack.org/compute/ext/block_device_mapping_v2_boot/api/v2" updated="%(timestamp)s">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-cells" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/cells/api/v1.1" name="Cells">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "%(host)s/openstack/images/%(image_id)s",
|
||||
"flavorRef" : "%(host)s/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"block_device_mapping_v2": [
|
||||
{
|
||||
"device_name": "/dev/sdb1",
|
||||
"source_type": "blank",
|
||||
"destination_type": "local",
|
||||
"delete_on_termination": "True",
|
||||
"guest_format": "swap",
|
||||
"boot_index": "-1"
|
||||
},
|
||||
{
|
||||
"device_name": "/dev/sda1",
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"uuid": "fake-volume-id-1",
|
||||
"boot_index": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
<block_device_mapping_v2>
|
||||
<mapping device_name="/dev/sdb1" source_type="blank" destination_type="local" delete_on_termination="True" guest_format="swap" boot_index="-1"></mapping>
|
||||
<mapping device_name="/dev/sda1" source_type="volume" destination_type="volume" uuid="fake-volume-id-1" boot_index="0"></mapping>
|
||||
</block_device_mapping_v2>
|
||||
</server>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "%(password)s",
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2/openstack/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/openstack/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
|
||||
<metadata/>
|
||||
<atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
|
||||
<atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
|
||||
</server>
|
@ -3117,6 +3117,30 @@ class BareMetalNodesXmlTest(BareMetalNodesJsonTest):
|
||||
ctype = 'xml'
|
||||
|
||||
|
||||
class BlockDeviceMappingV2BootJsonTest(ServersSampleBase):
|
||||
extension_name = ('nova.api.openstack.compute.contrib.'
|
||||
'block_device_mapping_v2_boot.'
|
||||
'Block_device_mapping_v2_boot')
|
||||
|
||||
def _get_flags(self):
|
||||
f = super(BlockDeviceMappingV2BootJsonTest, self)._get_flags()
|
||||
f['osapi_compute_extension'] = CONF.osapi_compute_extension[:]
|
||||
# We need the volumes extension as well
|
||||
f['osapi_compute_extension'].append(
|
||||
'nova.api.openstack.compute.contrib.volumes.Volumes')
|
||||
return f
|
||||
|
||||
def test_servers_post_with_bdm_v2(self):
|
||||
self.stubs.Set(cinder.API, 'get', fakes.stub_volume_get)
|
||||
self.stubs.Set(cinder.API, 'check_attach',
|
||||
fakes.stub_volume_check_attach)
|
||||
return self._post_server()
|
||||
|
||||
|
||||
class BlockDeviceMappingV2BootXmlTest(BlockDeviceMappingV2BootJsonTest):
|
||||
ctype = 'xml'
|
||||
|
||||
|
||||
class FloatingIPPoolsSampleJsonTests(ApiSampleTestBase):
|
||||
extension_name = ("nova.api.openstack.compute.contrib.floating_ip_pools."
|
||||
"Floating_ip_pools")
|
||||
|
@ -136,6 +136,37 @@ class TestBlockDeviceDict(test.TestCase):
|
||||
|
||||
BDM = block_device.BlockDeviceDict
|
||||
|
||||
self.api_mapping = [
|
||||
{'id': 1, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sdb1',
|
||||
'source_type': 'blank',
|
||||
'destination_type': 'local',
|
||||
'delete_on_termination': True,
|
||||
'guest_format': 'swap',
|
||||
'boot_index': -1},
|
||||
{'id': 2, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sdc1',
|
||||
'source_type': 'blank',
|
||||
'destination_type': 'local',
|
||||
'delete_on_termination': True,
|
||||
'boot_index': -1},
|
||||
{'id': 3, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sda1',
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'uuid': 'fake-volume-id-1',
|
||||
'boot_index': -1},
|
||||
{'id': 4, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sda2',
|
||||
'source_type': 'snapshot',
|
||||
'destination_type': 'volume',
|
||||
'uuid': 'fake-snapshot-id-1',
|
||||
'boot_index': -1},
|
||||
{'id': 5, 'instance_uuid': 'fake-instance',
|
||||
'no_device': True,
|
||||
'device_name': '/dev/vdc'},
|
||||
]
|
||||
|
||||
self.new_mapping = [
|
||||
BDM({'id': 1, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sdb1',
|
||||
@ -154,7 +185,7 @@ class TestBlockDeviceDict(test.TestCase):
|
||||
'device_name': '/dev/sda1',
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'volume_id': 'fake-folume-id-1',
|
||||
'volume_id': 'fake-volume-id-1',
|
||||
'connection_info': "{'fake': 'connection_info'}",
|
||||
'boot_index': -1}),
|
||||
BDM({'id': 4, 'instance_uuid': 'fake-instance',
|
||||
@ -181,7 +212,7 @@ class TestBlockDeviceDict(test.TestCase):
|
||||
'virtual_name': 'ephemeral0'},
|
||||
{'id': 3, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sda1',
|
||||
'volume_id': 'fake-folume-id-1',
|
||||
'volume_id': 'fake-volume-id-1',
|
||||
'connection_info': "{'fake': 'connection_info'}"},
|
||||
{'id': 4, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/sda2',
|
||||
@ -238,6 +269,15 @@ class TestBlockDeviceDict(test.TestCase):
|
||||
block_device.BlockDeviceDict.from_legacy(legacy),
|
||||
matchers.IsSubDictOf(new))
|
||||
|
||||
def test_from_api(self):
|
||||
for api, new in zip(self.api_mapping, self.new_mapping):
|
||||
new['connection_info'] = None
|
||||
if new['snapshot_id']:
|
||||
new['volume_id'] = None
|
||||
self.assertThat(
|
||||
block_device.BlockDeviceDict.from_api(api),
|
||||
matchers.IsSubDictOf(new))
|
||||
|
||||
def test_legacy(self):
|
||||
for legacy, new in zip(self.legacy_mapping, self.new_mapping):
|
||||
self.assertThat(
|
||||
|
Loading…
x
Reference in New Issue
Block a user