Merge "Support tag instances when boot(4/4)"
This commit is contained in:
commit
430ec6504b
@ -4970,6 +4970,28 @@ server_status:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
server_tags_create:
|
||||
description: |
|
||||
A list of tags. Tags have the following restrictions:
|
||||
|
||||
- Tag is a Unicode bytestring no longer than 60 characters.
|
||||
|
||||
- Tag is a non-empty string.
|
||||
|
||||
- Tags are case sensitive.
|
||||
|
||||
- '/' is not allowed to be in a tag name
|
||||
|
||||
- Comma is not allowed to be in a tag name in order to simplify
|
||||
requests that specify lists of tags
|
||||
|
||||
- All other characters are allowed to be in a tag name
|
||||
|
||||
- Each server can have up to 50 tags.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
min_version: 2.52
|
||||
server_usages:
|
||||
description: |
|
||||
A list of the server usage objects.
|
||||
|
@ -333,6 +333,7 @@ Request
|
||||
- os:scheduler_hints: os:scheduler_hints
|
||||
- OS-DCF:diskConfig: OS-DCF:diskConfig
|
||||
- description: server_description
|
||||
- tags: server_tags_create
|
||||
|
||||
**Example Create Server**
|
||||
|
||||
|
31
doc/api_samples/servers/v2.52/server-create-req.json
Normal file
31
doc/api_samples/servers/v2.52/server-create-req.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"server" : {
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavorRef" : "http://openstack.example.com/flavors/1",
|
||||
"availability_zone": "nova",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality": [
|
||||
{
|
||||
"path": "/etc/banner.txt",
|
||||
"contents": "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"user_data" : "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
|
||||
"networks": "auto",
|
||||
"tags": ["tag1", "tag2"]
|
||||
},
|
||||
"OS-SCH-HNT:scheduler_hints": {
|
||||
"same_host": "48e6a9f6-30af-47e0-bc04-acaed113bb4e"
|
||||
}
|
||||
}
|
22
doc/api_samples/servers/v2.52/server-create-resp.json
Normal file
22
doc/api_samples/servers/v2.52/server-create-resp.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"adminPass": "S5wqy9sPYUvU",
|
||||
"id": "97108291-2fd7-4dc2-a909-eaae0306a6a9",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/97108291-2fd7-4dc2-a909-eaae0306a6a9",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/97108291-2fd7-4dc2-a909-eaae0306a6a9",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
94
doc/api_samples/servers/v2.52/server-get-resp.json
Normal file
94
doc/api_samples/servers/v2.52/server-get-resp.json
Normal file
@ -0,0 +1,94 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:host": "compute",
|
||||
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
|
||||
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
|
||||
"OS-EXT-SRV-ATTR:kernel_id": "",
|
||||
"OS-EXT-SRV-ATTR:launch_index": 0,
|
||||
"OS-EXT-SRV-ATTR:ramdisk_id": "",
|
||||
"OS-EXT-SRV-ATTR:reservation_id": "r-ov3q80zj",
|
||||
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
|
||||
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"OS-SRV-USG:launched_at": "2017-02-14T19:23:59.895661",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"addr": "192.168.0.3",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"config_drive": "",
|
||||
"created": "2017-02-14T19:23:58Z",
|
||||
"description": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
|
||||
"host_status": "UP",
|
||||
"id": "9168b536-cd40-4630-b43f-b259807c6e87",
|
||||
"image": {
|
||||
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_name": null,
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{
|
||||
"delete_on_termination": false,
|
||||
"id": "volume_id1"
|
||||
},
|
||||
{
|
||||
"delete_on_termination": false,
|
||||
"id": "volume_id2"
|
||||
}
|
||||
],
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"tags": ["tag1", "tag2"],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"updated": "2017-02-14T19:24:00Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
96
doc/api_samples/servers/v2.52/servers-details-resp.json
Normal file
96
doc/api_samples/servers/v2.52/servers-details-resp.json
Normal file
@ -0,0 +1,96 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:host": "compute",
|
||||
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
|
||||
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
|
||||
"OS-EXT-SRV-ATTR:kernel_id": "",
|
||||
"OS-EXT-SRV-ATTR:launch_index": 0,
|
||||
"OS-EXT-SRV-ATTR:ramdisk_id": "",
|
||||
"OS-EXT-SRV-ATTR:reservation_id": "r-iffothgx",
|
||||
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
|
||||
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"OS-SRV-USG:launched_at": "2017-02-14T19:24:43.891568",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"addr": "192.168.0.3",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"config_drive": "",
|
||||
"created": "2017-02-14T19:24:42Z",
|
||||
"description": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
|
||||
"host_status": "UP",
|
||||
"id": "764e369e-a874-4401-b7ce-43e4760888da",
|
||||
"image": {
|
||||
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_name": null,
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/764e369e-a874-4401-b7ce-43e4760888da",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/764e369e-a874-4401-b7ce-43e4760888da",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{
|
||||
"delete_on_termination": false,
|
||||
"id": "volume_id1"
|
||||
},
|
||||
{
|
||||
"delete_on_termination": false,
|
||||
"id": "volume_id2"
|
||||
}
|
||||
],
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"tags": ["tag1", "tag2"],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"updated": "2017-02-14T19:24:43Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
]
|
||||
}
|
18
doc/api_samples/servers/v2.52/servers-list-resp.json
Normal file
18
doc/api_samples/servers/v2.52/servers-list-resp.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"id": "6e3a87e6-a133-452e-86e1-a31291c1b1c8",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "new-server-test"
|
||||
}
|
||||
]
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.51",
|
||||
"version": "2.52",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.51",
|
||||
"version": "2.52",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 2.51 - Adds new event name to external-events (volume-extended). Also,
|
||||
non-admins can see instance action event details except for the
|
||||
traceback field.
|
||||
* 2.52 - Adds support for applying tags when creating a server.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -131,7 +132,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.51"
|
||||
_MAX_API_VERSION = "2.52"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
# Almost all proxy APIs which related to network, images and baremetal
|
||||
|
@ -227,6 +227,17 @@ user documentation.
|
||||
A user can create, update, delete or check existence of simple string tags
|
||||
for servers by the os-server-tags plugin.
|
||||
|
||||
Tags have the following schema restrictions:
|
||||
|
||||
* Tag is a Unicode bytestring no longer than 60 characters.
|
||||
* Tag is a non-empty string.
|
||||
* Tags are case sensitive.
|
||||
* '/' is not allowed to be in a tag name
|
||||
* Comma is not allowed to be in a tag name in order to simplify requests that
|
||||
specify lists of tags
|
||||
* All other characters are allowed to be in a tag name
|
||||
* Each server can have up to 50 tags.
|
||||
|
||||
The resource point for these operations is /servers/<server_id>/tags
|
||||
|
||||
A user can add a single tag to the server by sending PUT request to the
|
||||
@ -610,3 +621,9 @@ user documentation.
|
||||
useful for API users to monitor when a volume extend operation completes
|
||||
for the given server instance. By default only users with the administrator
|
||||
role will be able to see event ``traceback`` details.
|
||||
|
||||
2.52
|
||||
----
|
||||
|
||||
Adds support for applying tags when creating a server. The tag schema is
|
||||
the same as in the `2.26`_ microversion.
|
||||
|
@ -16,7 +16,7 @@ import copy
|
||||
|
||||
from nova.api.validation import parameter_types
|
||||
from nova.api.validation.parameter_types import multi_params
|
||||
|
||||
from nova.objects import instance
|
||||
|
||||
base_create = {
|
||||
'type': 'object',
|
||||
@ -129,6 +129,16 @@ base_create_v242['properties']['server']['properties']['networks'] = {
|
||||
]}
|
||||
|
||||
|
||||
# 2.52 builds on 2.42 and makes the following changes:
|
||||
# Allowing adding tags to instances when booting
|
||||
base_create_v252 = copy.deepcopy(base_create_v242)
|
||||
base_create_v252['properties']['server']['properties']['tags'] = {
|
||||
"type": "array",
|
||||
"items": parameter_types.tag,
|
||||
"maxItems": instance.MAX_TAG_COUNT
|
||||
}
|
||||
|
||||
|
||||
base_update = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
|
@ -83,6 +83,7 @@ class ServersController(wsgi.Controller):
|
||||
schema_server_create_v232 = schema_servers.base_create_v232
|
||||
schema_server_create_v237 = schema_servers.base_create_v237
|
||||
schema_server_create_v242 = schema_servers.base_create_v242
|
||||
schema_server_create_v252 = schema_servers.base_create_v252
|
||||
|
||||
# NOTE(alex_xu): Please do not add more items into this list. This list
|
||||
# should be removed in the future.
|
||||
@ -135,6 +136,7 @@ class ServersController(wsgi.Controller):
|
||||
|
||||
# TODO(alex_xu): The final goal is that merging all of
|
||||
# extended json-schema into server main json-schema.
|
||||
self._create_schema(self.schema_server_create_v252, '2.52')
|
||||
self._create_schema(self.schema_server_create_v242, '2.42')
|
||||
self._create_schema(self.schema_server_create_v237, '2.37')
|
||||
self._create_schema(self.schema_server_create_v232, '2.32')
|
||||
@ -446,7 +448,8 @@ class ServersController(wsgi.Controller):
|
||||
@validation.schema(schema_server_create_v219, '2.19', '2.31')
|
||||
@validation.schema(schema_server_create_v232, '2.32', '2.36')
|
||||
@validation.schema(schema_server_create_v237, '2.37', '2.41')
|
||||
@validation.schema(schema_server_create_v242, '2.42')
|
||||
@validation.schema(schema_server_create_v242, '2.42', '2.51')
|
||||
@validation.schema(schema_server_create_v252, '2.52')
|
||||
def create(self, req, body):
|
||||
"""Creates a new server for a given user."""
|
||||
context = req.environ['nova.context']
|
||||
@ -467,6 +470,9 @@ class ServersController(wsgi.Controller):
|
||||
|
||||
availability_zone = create_kwargs.pop("availability_zone", None)
|
||||
|
||||
if api_version_request.is_supported(req, min_version='2.52'):
|
||||
create_kwargs['tags'] = server_dict.get('tags')
|
||||
|
||||
helpers.translate_attributes(helpers.CREATE,
|
||||
server_dict, create_kwargs)
|
||||
|
||||
|
@ -986,7 +986,7 @@ class API(base.Base):
|
||||
max_count, base_options, boot_meta, security_groups,
|
||||
block_device_mapping, shutdown_terminate,
|
||||
instance_group, check_server_group_quota, filter_properties,
|
||||
key_pair):
|
||||
key_pair, tags):
|
||||
# Reserve quotas
|
||||
num_instances, quotas = self._check_num_instances_quota(
|
||||
context, instance_type, min_count, max_count)
|
||||
@ -1027,11 +1027,13 @@ class API(base.Base):
|
||||
block_device_mapping = (
|
||||
self._bdm_validate_set_size_and_instance(context,
|
||||
instance, instance_type, block_device_mapping))
|
||||
instance_tags = self._transform_tags(tags, instance.uuid)
|
||||
|
||||
build_request = objects.BuildRequest(context,
|
||||
instance=instance, instance_uuid=instance.uuid,
|
||||
project_id=instance.project_id,
|
||||
block_device_mappings=block_device_mapping)
|
||||
block_device_mappings=block_device_mapping,
|
||||
tags=instance_tags)
|
||||
build_request.create()
|
||||
|
||||
# Create an instance_mapping. The null cell_mapping indicates
|
||||
@ -1179,7 +1181,7 @@ class API(base.Base):
|
||||
requested_networks, config_drive,
|
||||
block_device_mapping, auto_disk_config, filter_properties,
|
||||
reservation_id=None, legacy_bdm=True, shutdown_terminate=False,
|
||||
check_server_group_quota=False):
|
||||
check_server_group_quota=False, tags=None):
|
||||
"""Verify all the input parameters regardless of the provisioning
|
||||
strategy being performed and schedule the instance(s) for
|
||||
creation.
|
||||
@ -1192,6 +1194,7 @@ class API(base.Base):
|
||||
min_count = min_count or 1
|
||||
max_count = max_count or min_count
|
||||
block_device_mapping = block_device_mapping or []
|
||||
tags = tags or []
|
||||
|
||||
if image_href:
|
||||
image_id, boot_meta = self._get_image(context, image_href)
|
||||
@ -1237,11 +1240,13 @@ class API(base.Base):
|
||||
instance_group = self._get_requested_instance_group(context,
|
||||
filter_properties)
|
||||
|
||||
instances_to_build = self._provision_instances(context, instance_type,
|
||||
min_count, max_count, base_options, boot_meta, security_groups,
|
||||
block_device_mapping, shutdown_terminate,
|
||||
instance_group, check_server_group_quota, filter_properties,
|
||||
key_pair)
|
||||
tags = self._create_tag_list_obj(context, tags)
|
||||
|
||||
instances_to_build = self._provision_instances(
|
||||
context, instance_type, min_count, max_count, base_options,
|
||||
boot_meta, security_groups, block_device_mapping,
|
||||
shutdown_terminate, instance_group, check_server_group_quota,
|
||||
filter_properties, key_pair, tags)
|
||||
|
||||
instances = []
|
||||
request_specs = []
|
||||
@ -1276,7 +1281,8 @@ class API(base.Base):
|
||||
admin_password=admin_password,
|
||||
injected_files=injected_files,
|
||||
requested_networks=requested_networks,
|
||||
block_device_mapping=block_device_mapping)
|
||||
block_device_mapping=block_device_mapping,
|
||||
tags=tags)
|
||||
|
||||
return (instances, reservation_id)
|
||||
|
||||
@ -1583,6 +1589,33 @@ class API(base.Base):
|
||||
|
||||
return instance
|
||||
|
||||
def _create_tag_list_obj(self, context, tags):
|
||||
"""Create TagList objects from simple string tags.
|
||||
|
||||
:param context: security context.
|
||||
:param tags: simple string tags from API request.
|
||||
:returns: TagList object.
|
||||
"""
|
||||
tag_list = [objects.Tag(context=context, tag=t) for t in tags]
|
||||
tag_list_obj = objects.TagList(objects=tag_list)
|
||||
return tag_list_obj
|
||||
|
||||
def _transform_tags(self, tags, resource_id):
|
||||
"""Change the resource_id of the tags according to the input param.
|
||||
|
||||
Because this method can be called multiple times when more than one
|
||||
instance is booted in a single request it makes a copy of the tags
|
||||
list.
|
||||
|
||||
:param tags: TagList object.
|
||||
:param resource_id: string.
|
||||
:returns: TagList object.
|
||||
"""
|
||||
instance_tags = tags.obj_clone()
|
||||
for tag in instance_tags:
|
||||
tag.resource_id = resource_id
|
||||
return instance_tags
|
||||
|
||||
# This method remains because cellsv1 uses it in the scheduler
|
||||
def create_db_entry_for_new_instance(self, context, instance_type, image,
|
||||
instance, security_group, block_device_mapping, num_instances,
|
||||
@ -1640,7 +1673,7 @@ class API(base.Base):
|
||||
access_ip_v4=None, access_ip_v6=None, requested_networks=None,
|
||||
config_drive=None, auto_disk_config=None, scheduler_hints=None,
|
||||
legacy_bdm=True, shutdown_terminate=False,
|
||||
check_server_group_quota=False):
|
||||
check_server_group_quota=False, tags=None):
|
||||
"""Provision instances, sending instance information to the
|
||||
scheduler. The scheduler will determine where the instance(s)
|
||||
go and will handle creating the DB entries.
|
||||
@ -1679,7 +1712,8 @@ class API(base.Base):
|
||||
filter_properties=filter_properties,
|
||||
legacy_bdm=legacy_bdm,
|
||||
shutdown_terminate=shutdown_terminate,
|
||||
check_server_group_quota=check_server_group_quota)
|
||||
check_server_group_quota=check_server_group_quota,
|
||||
tags=tags)
|
||||
|
||||
def _check_auto_disk_config(self, instance=None, image=None,
|
||||
**extra_instance_updates):
|
||||
|
@ -126,11 +126,12 @@ class ComputeTaskAPI(object):
|
||||
def schedule_and_build_instances(self, context, build_requests,
|
||||
request_spec, image,
|
||||
admin_password, injected_files,
|
||||
requested_networks, block_device_mapping):
|
||||
requested_networks, block_device_mapping,
|
||||
tags=None):
|
||||
self.conductor_compute_rpcapi.schedule_and_build_instances(
|
||||
context, build_requests, request_spec, image,
|
||||
admin_password, injected_files, requested_networks,
|
||||
block_device_mapping)
|
||||
block_device_mapping, tags)
|
||||
|
||||
def unshelve_instance(self, context, instance, request_spec=None):
|
||||
self.conductor_compute_rpcapi.unshelve_instance(context,
|
||||
|
@ -295,6 +295,33 @@ class BuildRequestList(base.ObjectListBase, base.NovaObject):
|
||||
if (k not in instance.metadata or
|
||||
v != instance.metadata[k]):
|
||||
return False
|
||||
elif filter_key in (
|
||||
'tags', 'tags-any', 'not-tags', 'not-tags-any'):
|
||||
# Get the list of simple string tags first.
|
||||
tags = ([tag.tag for tag in instance.tags]
|
||||
if instance.tags else [])
|
||||
if filter_key == 'tags':
|
||||
for item in filter_val:
|
||||
if item not in tags:
|
||||
return False
|
||||
elif filter_key == 'tags-any':
|
||||
found = []
|
||||
for item in filter_val:
|
||||
if item in tags:
|
||||
found.append(item)
|
||||
if not found:
|
||||
return False
|
||||
elif filter_key == 'not-tags':
|
||||
found = []
|
||||
for item in filter_val:
|
||||
if item in tags:
|
||||
found.append(item)
|
||||
if len(found) == len(filter_val):
|
||||
return False
|
||||
elif filter_key == 'not-tags-any':
|
||||
for item in filter_val:
|
||||
if item in tags:
|
||||
return False
|
||||
elif isinstance(filter_val, (list, tuple, set, frozenset)):
|
||||
if not filter_val:
|
||||
# Special value to indicate that nothing will match.
|
||||
@ -364,10 +391,6 @@ class BuildRequestList(base.ObjectListBase, base.NovaObject):
|
||||
build_requests = cls.get_all(context)
|
||||
|
||||
# Fortunately some filters do not apply here.
|
||||
# 'tags' can not be applied at boot time so will not be set for an
|
||||
# instance here.
|
||||
# TODO(zhengzhenyu): Handle this when the API supports creating
|
||||
# servers with tags.
|
||||
# 'changes-since' works off of the updated_at field which has not yet
|
||||
# been set at the point in the boot process where build_request still
|
||||
# exists. So it can be ignored.
|
||||
@ -381,7 +404,8 @@ class BuildRequestList(base.ObjectListBase, base.NovaObject):
|
||||
exact_match_filter_names = ['project_id', 'user_id', 'image_ref',
|
||||
'vm_state', 'instance_type_id', 'uuid',
|
||||
'metadata', 'host', 'task_state',
|
||||
'system_metadata']
|
||||
'system_metadata', 'tags', 'tags-any',
|
||||
'not-tags', 'not-tags-any']
|
||||
exact_filters = {}
|
||||
regex_filters = {}
|
||||
for key, value in filters.items():
|
||||
|
@ -0,0 +1,31 @@
|
||||
{
|
||||
"server" : {
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "%(image_id)s",
|
||||
"flavorRef" : "http://openstack.example.com/flavors/1",
|
||||
"availability_zone": "nova",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality": [
|
||||
{
|
||||
"path": "/etc/banner.txt",
|
||||
"contents": "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"user_data" : "%(user_data)s",
|
||||
"networks": "auto",
|
||||
"tags": ["tag1", "tag2"]
|
||||
},
|
||||
"OS-SCH-HNT:scheduler_hints": {
|
||||
"same_host": "%(uuid)s"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "%(isotime)s",
|
||||
"description": null,
|
||||
"host_status": "UP",
|
||||
"locked": false,
|
||||
"tags": ["tag1", "tag2"],
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "%(hostid)s",
|
||||
"id": "%(id)s",
|
||||
"image": {
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(compute_endpoint)s/images/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_name": null,
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"config_drive": "%(cdrive)s",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
|
||||
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
|
||||
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
|
||||
"OS-EXT-SRV-ATTR:kernel_id": "",
|
||||
"OS-EXT-SRV-ATTR:launch_index": 0,
|
||||
"OS-EXT-SRV-ATTR:ramdisk_id": "",
|
||||
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
|
||||
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
|
||||
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{"id": "volume_id1", "delete_on_termination": false},
|
||||
{"id": "volume_id2", "delete_on_termination": false}
|
||||
],
|
||||
"OS-SRV-USG:launched_at": "%(strtime)s",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"updated": "%(isotime)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "%(isotime)s",
|
||||
"description": null,
|
||||
"host_status": "UP",
|
||||
"locked": false,
|
||||
"tags": ["tag1", "tag2"],
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "%(hostid)s",
|
||||
"id": "%(id)s",
|
||||
"image": {
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(compute_endpoint)s/images/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_name": null,
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/servers/%(id)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"config_drive": "%(cdrive)s",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
|
||||
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
|
||||
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
|
||||
"OS-EXT-SRV-ATTR:kernel_id": "",
|
||||
"OS-EXT-SRV-ATTR:launch_index": 0,
|
||||
"OS-EXT-SRV-ATTR:ramdisk_id": "",
|
||||
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
|
||||
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
|
||||
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{"id": "volume_id1", "delete_on_termination": false},
|
||||
{"id": "volume_id2", "delete_on_termination": false}
|
||||
],
|
||||
"OS-SRV-USG:launched_at": "%(strtime)s",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"updated": "%(isotime)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers/%(id)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/servers/%(id)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "new-server-test"
|
||||
}
|
||||
]
|
||||
}
|
@ -230,6 +230,12 @@ class ServersSampleJson247Test(ServersSampleJsonTest):
|
||||
self._verify_response('server-action-rebuild-resp', subs, resp, 202)
|
||||
|
||||
|
||||
class ServersSampleJson252Test(ServersSampleJsonTest):
|
||||
microversion = '2.52'
|
||||
scenarios = [('v2_52', {'api_major_version': 'v2.1'})]
|
||||
use_common_server_post = False
|
||||
|
||||
|
||||
class ServersUpdateSampleJsonTest(ServersSampleBase):
|
||||
|
||||
def test_update_server(self):
|
||||
|
@ -183,3 +183,57 @@ class ServersPreSchedulingTestCase(test.TestCase):
|
||||
|
||||
def test_instance_list_from_buildrequests_old_service(self):
|
||||
self._test_instance_list_from_buildrequests()
|
||||
|
||||
def test_instance_list_from_buildrequests_with_tags(self):
|
||||
"""Creates two servers with two tags each, where the 2nd tag (tag2)
|
||||
is the only intersection between the tags in both servers. This is
|
||||
used to test the various tags filters working in the BuildRequestList.
|
||||
"""
|
||||
self.useFixture(nova_fixtures.AllServicesCurrent())
|
||||
image_ref = fake_image.get_valid_image_id()
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'foo',
|
||||
'imageRef': image_ref,
|
||||
'flavorRef': '1',
|
||||
'networks': 'none',
|
||||
'tags': ['tag1', 'tag2']
|
||||
}
|
||||
}
|
||||
inst1 = self.api.api_post('servers', body)
|
||||
body['server']['name'] = 'bar'
|
||||
body['server']['tags'] = ['tag2', 'tag3']
|
||||
inst2 = self.api.api_post('servers', body)
|
||||
|
||||
# list servers using tags=tag1,tag2
|
||||
list_resp = self.api.api_get(
|
||||
'servers/detail?tags=tag1,tag2')
|
||||
list_resp = list_resp.body['servers']
|
||||
self.assertEqual(1, len(list_resp))
|
||||
self.assertEqual(inst1.body['server']['id'], list_resp[0]['id'])
|
||||
self.assertEqual('foo', list_resp[0]['name'])
|
||||
|
||||
# list servers using tags-any=tag1,tag3
|
||||
list_resp = self.api.api_get(
|
||||
'servers/detail?tags-any=tag1,tag3')
|
||||
list_resp = list_resp.body['servers']
|
||||
self.assertEqual(2, len(list_resp))
|
||||
# Default sort is created_at desc, so last created is first
|
||||
self.assertEqual(inst2.body['server']['id'], list_resp[0]['id'])
|
||||
self.assertEqual('bar', list_resp[0]['name'])
|
||||
self.assertEqual(inst1.body['server']['id'], list_resp[1]['id'])
|
||||
self.assertEqual('foo', list_resp[1]['name'])
|
||||
|
||||
# list servers using not-tags=tag1,tag2
|
||||
list_resp = self.api.api_get(
|
||||
'servers/detail?not-tags=tag1,tag2')
|
||||
list_resp = list_resp.body['servers']
|
||||
self.assertEqual(1, len(list_resp))
|
||||
self.assertEqual(inst2.body['server']['id'], list_resp[0]['id'])
|
||||
self.assertEqual('bar', list_resp[0]['name'])
|
||||
|
||||
# list servers using not-tags-any=tag1,tag3
|
||||
list_resp = self.api.api_get(
|
||||
'servers/detail?not-tags-any=tag1,tag3')
|
||||
list_resp = list_resp.body['servers']
|
||||
self.assertEqual(0, len(list_resp))
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import collections
|
||||
import datetime
|
||||
import ddt
|
||||
import uuid
|
||||
|
||||
import fixtures
|
||||
@ -56,6 +57,7 @@ from nova.image import glance
|
||||
from nova.network import manager
|
||||
from nova import objects
|
||||
from nova.objects import instance as instance_obj
|
||||
from nova.objects import tag
|
||||
from nova.policies import servers as server_policies
|
||||
from nova import policy
|
||||
from nova import test
|
||||
@ -3862,6 +3864,54 @@ class ServersControllerCreateTestV237(test.NoDBTestCase):
|
||||
[{'uuid': uuid}])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ServersControllerCreateTestV252(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(ServersControllerCreateTestV252, self).setUp()
|
||||
self.controller = servers.ServersController()
|
||||
|
||||
self.body = {
|
||||
'server': {
|
||||
'name': 'device-tagging-server',
|
||||
'imageRef': '6b0edabb-8cde-4684-a3f4-978960a51378',
|
||||
'flavorRef': '2',
|
||||
'networks': [{
|
||||
'uuid': 'ff608d40-75e9-48cb-b745-77bb55b5eaf2'
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
self.req = fakes.HTTPRequestV21.blank('/fake/servers', version='2.52')
|
||||
self.req.method = 'POST'
|
||||
self.req.headers['content-type'] = 'application/json'
|
||||
|
||||
def _create_server(self, tags):
|
||||
self.body['server']['tags'] = tags
|
||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||
return self.controller.create(self.req, body=self.body).obj['server']
|
||||
|
||||
def test_create_server_with_tags_pre_2_52_fails(self):
|
||||
"""Negative test to make sure you can't pass 'tags' before 2.52"""
|
||||
self.req.api_version_request = \
|
||||
api_version_request.APIVersionRequest('2.51')
|
||||
self.assertRaises(
|
||||
exception.ValidationError, self._create_server, ['tag1'])
|
||||
|
||||
@ddt.data([','],
|
||||
['/'],
|
||||
['a' * (tag.MAX_TAG_LENGTH + 1)],
|
||||
['a'] * (instance_obj.MAX_TAG_COUNT + 1),
|
||||
[''],
|
||||
[1, 2, 3],
|
||||
{'tag': 'tag'})
|
||||
def test_create_server_with_tags_incorrect_tags(self, tags):
|
||||
"""Negative test to incorrect tags are not allowed"""
|
||||
self.req.api_version_request = \
|
||||
api_version_request.APIVersionRequest('2.52')
|
||||
self.assertRaises(
|
||||
exception.ValidationError, self._create_server, tags)
|
||||
|
||||
|
||||
class ServersControllerCreateTestWithMock(test.TestCase):
|
||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
flavor_ref = 'http://localhost/123/flavors/3'
|
||||
|
@ -3711,7 +3711,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
boot_meta, security_groups, block_device_mapping,
|
||||
shutdown_terminate, instance_group,
|
||||
check_server_group_quota, filter_properties,
|
||||
None)
|
||||
None, objects.TagList())
|
||||
|
||||
do_test()
|
||||
|
||||
@ -3760,7 +3760,8 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
1, 1, mock.MagicMock(),
|
||||
{}, None,
|
||||
None, None, None, {}, None,
|
||||
fake_keypair)
|
||||
fake_keypair,
|
||||
objects.TagList())
|
||||
self.assertEqual(
|
||||
'test',
|
||||
mock_instance.return_value.keypairs.objects[0].name)
|
||||
@ -3769,7 +3770,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
1, 1, mock.MagicMock(),
|
||||
{}, None,
|
||||
None, None, None, {}, None,
|
||||
None)
|
||||
None, objects.TagList())
|
||||
self.assertEqual(
|
||||
0,
|
||||
len(mock_instance.return_value.keypairs.objects))
|
||||
@ -3832,6 +3833,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
'device_name': 'vda',
|
||||
'boot_index': 0,
|
||||
}))])
|
||||
instance_tags = objects.TagList(objects=[objects.Tag(tag='tag')])
|
||||
shutdown_terminate = True
|
||||
instance_group = None
|
||||
check_server_group_quota = False
|
||||
@ -3843,7 +3845,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
min_count, max_count, base_options, boot_meta,
|
||||
security_groups, block_device_mappings, shutdown_terminate,
|
||||
instance_group, check_server_group_quota,
|
||||
filter_properties, None)
|
||||
filter_properties, None, instance_tags)
|
||||
|
||||
for rs, br, im in instances_to_build:
|
||||
self.assertIsInstance(br.instance, objects.Instance)
|
||||
@ -3851,6 +3853,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
self.assertEqual(base_options['project_id'],
|
||||
br.instance.project_id)
|
||||
self.assertEqual(1, br.block_device_mappings[0].id)
|
||||
self.assertEqual(br.instance.uuid, br.tags[0].resource_id)
|
||||
br.create.assert_called_with()
|
||||
|
||||
do_test()
|
||||
@ -3923,7 +3926,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
min_count, max_count, base_options, boot_meta,
|
||||
security_groups, block_device_mapping, shutdown_terminate,
|
||||
instance_group, check_server_group_quota,
|
||||
filter_properties, None))
|
||||
filter_properties, None, objects.TagList()))
|
||||
rs, br, im = instances_to_build[0]
|
||||
self.assertTrue(uuidutils.is_uuid_like(br.instance.uuid))
|
||||
self.assertEqual(br.instance_uuid, im.instance_uuid)
|
||||
@ -4011,14 +4014,14 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
check_server_group_quota = False
|
||||
filter_properties = {'scheduler_hints': None,
|
||||
'instance_type': flavor}
|
||||
|
||||
tags = objects.TagList()
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
self.compute_api._provision_instances, ctxt,
|
||||
flavor, min_count, max_count, base_options,
|
||||
boot_meta, security_groups, block_device_mapping,
|
||||
shutdown_terminate, instance_group,
|
||||
check_server_group_quota, filter_properties,
|
||||
None)
|
||||
None, tags)
|
||||
# First instance, build_req, mapping is created and destroyed
|
||||
self.assertTrue(build_req_mocks[0].create.called)
|
||||
self.assertTrue(build_req_mocks[0].destroy.called)
|
||||
@ -4050,7 +4053,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
self.compute_api._provision_instances(ctxt, None, None, None,
|
||||
mock.MagicMock(), None, None,
|
||||
[], None, None, None, None,
|
||||
None)
|
||||
None, objects.TagList())
|
||||
secgroups = mock_secgroup.populate_security_groups.return_value
|
||||
mock_objects.RequestSpec.from_components.assert_called_once_with(
|
||||
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Adds support for applying tags when creating a server.
|
||||
The tag schema is the same as in the 2.26 microversion.
|
Loading…
x
Reference in New Issue
Block a user