Merge "Device tagging API support"
This commit is contained in:
commit
5b31a0dac8
@ -1006,7 +1006,14 @@ block_device_mapping_v2:
|
||||
"source_type": "image",
|
||||
"volume_size": "25",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": true }
|
||||
"delete_on_termination": true,
|
||||
"tag": "disk1" }
|
||||
|
||||
Starting in microversion 2.32, the tag is an optional, arbitrary attribute
|
||||
that can be used to assign a tag to the block device. This tag is then
|
||||
exposed to the guest in the metadata API and the config drive and is
|
||||
associated to hardware metadata for that block device, such as bus (ex:
|
||||
SCSI), bus address (ex: 1:0:2:0), and serial.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
@ -1280,6 +1287,13 @@ device_resp:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
device_tag:
|
||||
description: |
|
||||
An arbitrary tag.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.32
|
||||
disabled_reason_body:
|
||||
description: |
|
||||
The reason for disabling a service.
|
||||
@ -2627,6 +2641,13 @@ networks:
|
||||
a network, specify the UUID of the network in the ``uuid`` attribute in a ``networks``
|
||||
object. To provision the server instance with a NIC for an already existing port,
|
||||
specify the port-id in the ``port`` attribute in a ``networks`` object.
|
||||
|
||||
Starting in microversion 2.32, it's possible to optionally assign an
|
||||
arbitrary tag to a virtual network interface, specify the tag attribute in
|
||||
the ``network`` object. An interface's tag is exposed to the guest in the
|
||||
metadata API and the config drive and is associated to hardware metadata
|
||||
for that network interface, such as bus (ex: PCI), bus address (ex:
|
||||
0000:00:02.0), and MAC address.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
|
@ -293,6 +293,7 @@ Request
|
||||
- networks.uuid: network_uuid
|
||||
- networks.port: port
|
||||
- networks.fixed_ip: fixed_ip
|
||||
- networks.tag: device_tag
|
||||
- personality: personality
|
||||
- block_device_mapping_v2: block_device_mapping_v2
|
||||
- block_device_mapping_v2.device_name: device_name
|
||||
@ -301,6 +302,7 @@ Request
|
||||
- block_device_mapping_v2.delete_on_termination: delete_on_termination
|
||||
- block_device_mapping_v2.guest_format: guest_format
|
||||
- block_device_mapping_v2.boot_index: boot_index
|
||||
- block_device_mapping_v2.tag: device_tag
|
||||
- config_drive: config_drive
|
||||
- key_name: key_name
|
||||
- os:scheduler_hints: os:scheduler_hints
|
||||
@ -312,6 +314,11 @@ Request
|
||||
.. literalinclude:: ../../doc/api_samples/servers/server-create-req.json
|
||||
:language: javascript
|
||||
|
||||
**Example Create Server (v2.32)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.32/server-create-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
|
18
doc/api_samples/servers/v2.32/server-create-req.json
Normal file
18
doc/api_samples/servers/v2.32/server-create-req.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "device-tagging-server",
|
||||
"flavorRef" : "http://openstack.example.com/flavors/1",
|
||||
"networks" : [{
|
||||
"uuid" : "ff608d40-75e9-48cb-b745-77bb55b5eaf2",
|
||||
"tag": "nic1"
|
||||
}],
|
||||
"block_device_mapping_v2": [{
|
||||
"uuid": "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"source_type": "image",
|
||||
"destination_type": "volume",
|
||||
"boot_index": 0,
|
||||
"volume_size": "1",
|
||||
"tag": "disk1"
|
||||
}]
|
||||
}
|
||||
}
|
22
doc/api_samples/servers/v2.32/server-create-resp.json
Normal file
22
doc/api_samples/servers/v2.32/server-create-resp.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "rojsEujtu7GB",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"id": "05ec6bde-40bf-47e8-ac07-89c12b2eee03",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/05ec6bde-40bf-47e8-ac07-89c12b2eee03",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/05ec6bde-40bf-47e8-ac07-89c12b2eee03",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.31",
|
||||
"version": "2.32",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.31",
|
||||
"version": "2.32",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 2.30 - Add a force flag in live-migrate request body and change the
|
||||
behaviour for the host flag by calling the scheduler.
|
||||
* 2.31 - Fix os-console-auth-tokens to work for all console types.
|
||||
* 2.32 - Add tag to networks and block_device_mapping_v2 in server boot
|
||||
request body.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -88,7 +90,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
_MIN_API_VERSION = "2.1"
|
||||
_MAX_API_VERSION = "2.31"
|
||||
_MAX_API_VERSION = "2.32"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -74,4 +74,7 @@ class BlockDeviceMapping(extensions.V21APIExtensionBase):
|
||||
create_kwargs['legacy_bdm'] = False
|
||||
|
||||
def get_server_create_schema(self, version):
|
||||
return schema_block_device_mapping.server_create
|
||||
if version == '2.32':
|
||||
return schema_block_device_mapping.server_create_v232
|
||||
else:
|
||||
return schema_block_device_mapping.server_create
|
||||
|
@ -15,6 +15,7 @@
|
||||
import copy
|
||||
|
||||
from nova.api.openstack.compute.schemas import block_device_mapping_v1
|
||||
from nova.api.openstack.compute.schemas import server_tags
|
||||
from nova.api.validation import parameter_types
|
||||
from nova.objects import fields
|
||||
|
||||
@ -71,3 +72,18 @@ server_create = {
|
||||
'items': [block_device_mapping]
|
||||
}
|
||||
}
|
||||
|
||||
block_device_mapping_v232_new_item = {
|
||||
'tag': server_tags.tag
|
||||
}
|
||||
|
||||
block_device_mapping_v232 = copy.deepcopy(block_device_mapping)
|
||||
block_device_mapping_v232['properties'].update(
|
||||
block_device_mapping_v232_new_item)
|
||||
|
||||
server_create_v232 = {
|
||||
'block_device_mapping_v2': {
|
||||
'type': 'array',
|
||||
'items': [block_device_mapping_v232]
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import copy
|
||||
|
||||
from nova.api.openstack.compute.schemas import server_tags
|
||||
from nova.api.validation import parameter_types
|
||||
|
||||
|
||||
@ -67,6 +68,12 @@ base_create_v219['properties']['server'][
|
||||
'properties']['description'] = parameter_types.description
|
||||
|
||||
|
||||
base_create_v232 = copy.deepcopy(base_create_v219)
|
||||
base_create_v232['properties']['server'][
|
||||
'properties']['networks']['items'][
|
||||
'properties']['tag'] = server_tags.tag
|
||||
|
||||
|
||||
base_update = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
|
@ -39,6 +39,7 @@ from nova import compute
|
||||
from nova.compute import flavors
|
||||
from nova.compute import utils as compute_utils
|
||||
import nova.conf
|
||||
from nova import context as nova_context
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.i18n import _LW
|
||||
@ -49,6 +50,7 @@ from nova import utils
|
||||
|
||||
ALIAS = 'servers'
|
||||
TAG_SEARCH_FILTERS = ('tags', 'tags-any', 'not-tags', 'not-tags-any')
|
||||
DEVICE_TAGGING_MIN_COMPUTE_VERSION = 14
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
@ -75,6 +77,8 @@ class ServersController(wsgi.Controller):
|
||||
schema_server_update_v219 = schema_servers.base_update_v219
|
||||
schema_server_rebuild_v219 = schema_servers.base_rebuild_v219
|
||||
|
||||
schema_server_create_v232 = schema_servers.base_create_v232
|
||||
|
||||
@staticmethod
|
||||
def _add_location(robj):
|
||||
# Just in case...
|
||||
@ -166,6 +170,9 @@ class ServersController(wsgi.Controller):
|
||||
invoke_kwds={"extension_info": self.extension_info},
|
||||
propagate_map_exceptions=True)
|
||||
if list(self.create_schema_manager):
|
||||
self.create_schema_manager.map(self._create_extension_schema,
|
||||
self.schema_server_create_v232,
|
||||
'2.32')
|
||||
self.create_schema_manager.map(self._create_extension_schema,
|
||||
self.schema_server_create_v219,
|
||||
'2.19')
|
||||
@ -386,7 +393,8 @@ class ServersController(wsgi.Controller):
|
||||
expl = _("Duplicate networks (%s) are not allowed") % net_id
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
def _get_requested_networks(self, requested_networks):
|
||||
def _get_requested_networks(self, requested_networks,
|
||||
supports_device_tagging=False):
|
||||
"""Create a list of requested networks from the networks attribute."""
|
||||
networks = []
|
||||
network_uuids = []
|
||||
@ -399,6 +407,11 @@ class ServersController(wsgi.Controller):
|
||||
request.address = network.get('fixed_ip', None)
|
||||
request.port_id = network.get('port', None)
|
||||
|
||||
request.tag = network.get('tag', None)
|
||||
if request.tag and not supports_device_tagging:
|
||||
msg = _('Network interface tags are not yet supported.')
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
if request.port_id:
|
||||
request.network_id = None
|
||||
if not utils.is_neutron():
|
||||
@ -456,7 +469,8 @@ class ServersController(wsgi.Controller):
|
||||
@extensions.expected_errors((400, 403, 409))
|
||||
@validation.schema(schema_server_create_v20, '2.0', '2.0')
|
||||
@validation.schema(schema_server_create, '2.1', '2.18')
|
||||
@validation.schema(schema_server_create_v219, '2.19')
|
||||
@validation.schema(schema_server_create_v219, '2.19', '2.31')
|
||||
@validation.schema(schema_server_create_v232, '2.32')
|
||||
def create(self, req, body):
|
||||
"""Creates a new server for a given user."""
|
||||
|
||||
@ -511,12 +525,21 @@ class ServersController(wsgi.Controller):
|
||||
if host or node:
|
||||
context.can(server_policies.SERVERS % 'create:forced_host', {})
|
||||
|
||||
min_compute_version = objects.Service.get_minimum_version(
|
||||
nova_context.get_admin_context(), 'nova-compute')
|
||||
supports_device_tagging = (min_compute_version >=
|
||||
DEVICE_TAGGING_MIN_COMPUTE_VERSION)
|
||||
|
||||
block_device_mapping = create_kwargs.get("block_device_mapping")
|
||||
# TODO(Shao He, Feng) move this policy check to os-block-device-mapping
|
||||
# extension after refactor it.
|
||||
if block_device_mapping:
|
||||
context.can(server_policies.SERVERS % 'create:attach_volume',
|
||||
target)
|
||||
for bdm in block_device_mapping:
|
||||
if bdm.get('tag', None) and not supports_device_tagging:
|
||||
msg = _('Block device tags are not yet supported.')
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
image_uuid = self._image_from_req_data(server_dict, create_kwargs)
|
||||
|
||||
@ -537,7 +560,7 @@ class ServersController(wsgi.Controller):
|
||||
|
||||
if requested_networks is not None:
|
||||
requested_networks = self._get_requested_networks(
|
||||
requested_networks)
|
||||
requested_networks, supports_device_tagging)
|
||||
|
||||
if requested_networks and len(requested_networks):
|
||||
context.can(server_policies.SERVERS % 'create:attach_network',
|
||||
|
@ -324,3 +324,14 @@ user documentation.
|
||||
|
||||
Fix os-console-auth-tokens to return connection info for all types of tokens,
|
||||
not just RDP.
|
||||
|
||||
2.32
|
||||
----
|
||||
|
||||
Adds an optional, arbitrary 'tag' item to the 'networks' item in the server
|
||||
boot request body. In addition, every item in the block_device_mapping_v2
|
||||
array can also have an optional, arbitrary 'tag' item. These tags are used to
|
||||
identify virtual device metadata, as exposed in the metadata API and on the
|
||||
config drive. For example, a network interface on the virtual PCI bus tagged
|
||||
with 'nic1' will appear in the metadata along with its bus (PCI), bus address
|
||||
(ex: 0000:00:02.0), MAC address, and tag ('nic1').
|
||||
|
@ -43,6 +43,13 @@ def main():
|
||||
logging.setup(CONF, "nova")
|
||||
utils.monkey_patch()
|
||||
objects.register_all()
|
||||
if 'osapi_compute' in CONF.enabled_apis:
|
||||
# NOTE(mriedem): This is needed for caching the nova-compute service
|
||||
# version which is looked up when a server create request is made with
|
||||
# network id of 'auto' or 'none'.
|
||||
# TODO(mriedem): Remove this in Ocata when all computes should be
|
||||
# at least Newton.
|
||||
objects.Service.enable_min_version_cache()
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
gmr.TextGuruMeditation.setup_autorun(version)
|
||||
|
@ -37,6 +37,11 @@ def main():
|
||||
logging.setup(CONF, "nova")
|
||||
utils.monkey_patch()
|
||||
objects.register_all()
|
||||
# NOTE(mriedem): This is needed for caching the nova-compute service
|
||||
# version which is looked up when a server create request is made with
|
||||
# network id of 'auto' or 'none'.
|
||||
# TODO(mriedem): Remove this in Ocata when all computes should be Newton.
|
||||
objects.Service.enable_min_version_cache()
|
||||
|
||||
gmr.TextGuruMeditation.setup_autorun(version)
|
||||
|
||||
|
@ -314,12 +314,13 @@ class WSGIService(service.Service):
|
||||
self.backdoor_port = None
|
||||
|
||||
def reset(self):
|
||||
"""Reset server greenpool size to default.
|
||||
"""Reset server greenpool size to default and service version cache.
|
||||
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
self.server.reset()
|
||||
service_obj.Service.clear_min_version_cache()
|
||||
|
||||
def _get_manager(self):
|
||||
"""Initialize a Manager object appropriate for this service.
|
||||
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "device-tagging-server",
|
||||
"flavorRef" : "%(host)s/flavors/1",
|
||||
"networks" : [{
|
||||
"uuid" : "ff608d40-75e9-48cb-b745-77bb55b5eaf2",
|
||||
"tag": "nic1"
|
||||
}],
|
||||
"block_device_mapping_v2": [{
|
||||
"uuid": "%(image_id)s",
|
||||
"source_type": "image",
|
||||
"destination_type": "volume",
|
||||
"boot_index": 0,
|
||||
"volume_size": "1",
|
||||
"tag": "disk1"
|
||||
}]
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"adminPass": "%(password)s",
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -148,6 +148,15 @@ class ServersSampleJson219Test(ServersSampleJsonTest):
|
||||
self._verify_response('server-put-resp', subs, response, 200)
|
||||
|
||||
|
||||
class ServersSampleJson232Test(ServersSampleBase):
|
||||
microversion = '2.32'
|
||||
sample_dir = 'servers'
|
||||
scenarios = [('v2_32', {'api_major_version': 'v2.1'})]
|
||||
|
||||
def test_servers_post(self):
|
||||
self._post_server(use_common_server_api_samples=False)
|
||||
|
||||
|
||||
class ServersUpdateSampleJsonTest(ServersSampleBase):
|
||||
|
||||
def test_update_server(self):
|
||||
|
@ -3440,6 +3440,100 @@ class ServersControllerCreateTestV219(ServersControllerCreateTest):
|
||||
self.req, body=self.body)
|
||||
|
||||
|
||||
class ServersControllerCreateTestV232(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(ServersControllerCreateTestV232, self).setUp()
|
||||
self.flags(use_neutron=True)
|
||||
|
||||
ext_info = extension_info.LoadedExtensionInfo()
|
||||
self.controller = servers.ServersController(extension_info=ext_info)
|
||||
|
||||
self.body = {
|
||||
'server': {
|
||||
'name': 'device-tagging-server',
|
||||
'imageRef': '6b0edabb-8cde-4684-a3f4-978960a51378',
|
||||
'flavorRef': '2',
|
||||
'networks': [{
|
||||
'uuid': 'ff608d40-75e9-48cb-b745-77bb55b5eaf2'
|
||||
}],
|
||||
'block_device_mapping_v2': [{
|
||||
'uuid': '70a599e0-31e7-49b7-b260-868f441e862b',
|
||||
'source_type': 'image',
|
||||
'destination_type': 'volume',
|
||||
'boot_index': 0,
|
||||
'volume_size': '1'
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
self.req = fakes.HTTPRequestV21.blank('/fake/servers', version='2.32')
|
||||
self.req.method = 'POST'
|
||||
self.req.headers['content-type'] = 'application/json'
|
||||
|
||||
def _create_server(self):
|
||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||
self.controller.create(self.req, body=self.body)
|
||||
|
||||
def test_create_server_no_tags_old_compute(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.Service, 'get_minimum_version',
|
||||
return_value=13),
|
||||
mock.patch.object(nova.compute.flavors, 'get_flavor_by_flavor_id',
|
||||
return_value=objects.Flavor()),
|
||||
mock.patch.object(
|
||||
compute_api.API, 'create',
|
||||
return_value=(
|
||||
[{'uuid': 'f60012d9-5ba4-4547-ab48-f94ff7e62d4e'}],
|
||||
1)),
|
||||
):
|
||||
self._create_server()
|
||||
|
||||
@mock.patch.object(objects.Service, 'get_minimum_version',
|
||||
return_value=13)
|
||||
def test_create_server_tagged_nic_old_compute_fails(self, get_min_ver):
|
||||
self.body['server']['networks'][0]['tag'] = 'foo'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self._create_server)
|
||||
|
||||
@mock.patch.object(objects.Service, 'get_minimum_version',
|
||||
return_value=13)
|
||||
def test_create_server_tagged_bdm_old_compute_fails(self, get_min_ver):
|
||||
self.body['server']['block_device_mapping_v2'][0]['tag'] = 'foo'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self._create_server)
|
||||
|
||||
def test_create_server_tagged_nic_new_compute(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.Service, 'get_minimum_version',
|
||||
return_value=14),
|
||||
mock.patch.object(nova.compute.flavors, 'get_flavor_by_flavor_id',
|
||||
return_value=objects.Flavor()),
|
||||
mock.patch.object(
|
||||
compute_api.API, 'create',
|
||||
return_value=(
|
||||
[{'uuid': 'f60012d9-5ba4-4547-ab48-f94ff7e62d4e'}],
|
||||
1)),
|
||||
):
|
||||
self.body['server']['networks'][0]['tag'] = 'foo'
|
||||
self._create_server()
|
||||
|
||||
def test_create_server_tagged_bdm_new_compute(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.Service, 'get_minimum_version',
|
||||
return_value=14),
|
||||
mock.patch.object(nova.compute.flavors, 'get_flavor_by_flavor_id',
|
||||
return_value=objects.Flavor()),
|
||||
mock.patch.object(
|
||||
compute_api.API, 'create',
|
||||
return_value=(
|
||||
[{'uuid': 'f60012d9-5ba4-4547-ab48-f94ff7e62d4e'}],
|
||||
1)),
|
||||
mock.patch.object(self.req, 'cache_db_instances'),
|
||||
mock.patch.object(self.controller, '_add_location',
|
||||
return_value=None)
|
||||
):
|
||||
self.body['server']['block_device_mapping_v2'][0]['tag'] = 'foo'
|
||||
self._create_server()
|
||||
|
||||
|
||||
class ServersControllerCreateTestWithMock(test.TestCase):
|
||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
flavor_ref = 'http://localhost/123/flavors/3'
|
||||
@ -4129,7 +4223,7 @@ class FakeExt(extensions.V21APIExtensionBase):
|
||||
pass
|
||||
|
||||
def fake_schema_extension_point(self, version):
|
||||
if version == '2.1' or version == '2.19':
|
||||
if version in ('2.1', '2.19', '2.32'):
|
||||
return self.fake_schema
|
||||
elif version == '2.0':
|
||||
return {}
|
||||
|
@ -22,10 +22,12 @@ from nova import test
|
||||
|
||||
# required because otherwise oslo early parse_args dies
|
||||
@mock.patch.object(config, 'parse_args', new=lambda *args, **kwargs: None)
|
||||
# required so we don't set the global service version cache
|
||||
@mock.patch('nova.objects.Service.enable_min_version_cache')
|
||||
class TestNovaAPI(test.NoDBTestCase):
|
||||
|
||||
@mock.patch('nova.service.process_launcher')
|
||||
def test_with_ec2(self, launcher):
|
||||
def test_with_ec2(self, launcher, version_cache):
|
||||
"""Ensure that we don't explode if enabled_apis is wrong.
|
||||
|
||||
If the end user hasn't updated their config, an ec2 entry
|
||||
@ -40,8 +42,9 @@ class TestNovaAPI(test.NoDBTestCase):
|
||||
# collide on ports.
|
||||
self.flags(osapi_compute_listen_port=0)
|
||||
api.main()
|
||||
version_cache.assert_called_once_with()
|
||||
|
||||
def test_continues_on_failure(self):
|
||||
def test_continues_on_failure(self, version_cache):
|
||||
count = [1, 2]
|
||||
|
||||
fake_server = mock.MagicMock()
|
||||
@ -65,9 +68,10 @@ class TestNovaAPI(test.NoDBTestCase):
|
||||
launcher = mock_service.process_launcher.return_value
|
||||
launcher.launch_service.assert_called_once_with(
|
||||
fake_server, workers=123)
|
||||
self.assertFalse(version_cache.called)
|
||||
|
||||
@mock.patch('sys.exit')
|
||||
def test_fails_if_none_started(self, mock_exit):
|
||||
def test_fails_if_none_started(self, mock_exit, version_cache):
|
||||
mock_exit.side_effect = test.TestingException
|
||||
self.flags(enabled_apis=[])
|
||||
with mock.patch.object(api, 'service') as mock_service:
|
||||
@ -75,9 +79,10 @@ class TestNovaAPI(test.NoDBTestCase):
|
||||
mock_exit.assert_called_once_with(1)
|
||||
launcher = mock_service.process_launcher.return_value
|
||||
self.assertFalse(launcher.wait.called)
|
||||
self.assertFalse(version_cache.called)
|
||||
|
||||
@mock.patch('sys.exit')
|
||||
def test_fails_if_all_failed(self, mock_exit):
|
||||
def test_fails_if_all_failed(self, mock_exit, version_cache):
|
||||
mock_exit.side_effect = test.TestingException
|
||||
self.flags(enabled_apis=['foo', 'bar'])
|
||||
with mock.patch.object(api, 'service') as mock_service:
|
||||
@ -87,3 +92,4 @@ class TestNovaAPI(test.NoDBTestCase):
|
||||
mock_exit.assert_called_once_with(1)
|
||||
launcher = mock_service.process_launcher.return_value
|
||||
self.assertFalse(launcher.wait.called)
|
||||
self.assertFalse(version_cache.called)
|
||||
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The 2.32 microverison adds support for virtual device
|
||||
role tagging. Device role tagging is an answer to the
|
||||
question 'Which device is which, inside the guest?' When
|
||||
booting an instance, an optional arbitrary 'tag'
|
||||
parameter can be set on virtual network interfaces
|
||||
and/or block device mappings. This tag is exposed to the
|
||||
instance through the metadata API and on the config
|
||||
drive. Each tagged virtual network interface is listed
|
||||
along with information about the virtual hardware, such
|
||||
as bus type (ex: PCI), bus address (ex: 0000:00:02.0),
|
||||
and MAC address. For tagged block devices, the exposed
|
||||
hardware metadata includes the bus (ex: SCSI), bus
|
||||
address (ex: 1:0:2:0) and serial number.
|
||||
issues:
|
||||
- When using virtual device role tagging, the metadata on
|
||||
the config drive lags behind the metadata obtained from
|
||||
the metadata API. For example, if a tagged virtual
|
||||
network interface is detached from the instance, its tag
|
||||
remains in the metadata on the config drive. This is due
|
||||
to the nature of the config drive, which, once written,
|
||||
cannot be easily updated by Nova.
|
Loading…
x
Reference in New Issue
Block a user