Adds the server group info into show server detail API.

The server-groups UUID add to response of 'GET /servers/{id}',
'PUT /servers/{server_id}" and rebuild API
'POST /servers/{server_id}/action'.

Change-Id: I4a2a584df56ece7beb8b12c0ce9b0e6b30237120
Implements: blueprint show-server-group
Co-authored-by: Gerry Kopec <Gerry.Kopec@windriver.com>
Signed-off-by: Yongli He <yongli.he@intel.com>
This commit is contained in:
Yongli He 2018-11-13 15:40:49 +08:00 committed by Matt Riedemann
parent 29e5b0ad7b
commit 2cc7c0e589
33 changed files with 914 additions and 20 deletions

View File

@ -240,6 +240,9 @@ behavior are described below:
- availability_zone: The availability_zone of the server if it was specified
during during boot time and "UNKNOWN" otherwise.
- power_state: Its value will be 0 (``NOSTATE``).
- server_groups: The UUIDs of the server groups to which the server belongs.
Currently this can contain at most one entry. Note that this key will be in
the response only from the "2.71" microversion.
A sample response for a GET /servers/{server_id} request that
includes one server from an unreachable part of the infrastructure
@ -272,6 +275,7 @@ behavior are described below:
},
"OS-EXT-AZ:availability_zone": "geneva",
"OS-EXT-STS:power_state": 0,
"server_groups": ["0fd77252-4eef-4ec4-ae9b-e05dfc98aeac"]
}
]
}

View File

@ -5861,6 +5861,14 @@ server_groups: &server_groups
in: body
required: true
type: integer
server_groups_2_71:
description: |
The UUIDs of the server groups to which the server belongs. Currently
this can contain at most one entry.
in: body
required: true
type: array
min_version: 2.71
server_groups_list:
description: |
The list of existing server groups.

View File

@ -613,6 +613,7 @@ Response
- key_name: key_name_rebuild_resp
- user_data: user_data_rebuild_resp
- trusted_image_certificates: server_trusted_image_certificates_resp
- server_groups: server_groups_2_71
**Example Rebuild Server (rebuild Action) (v2.63)**

View File

@ -768,6 +768,7 @@ Response
- description: server_description_resp
- tags: tags
- trusted_image_certificates: server_trusted_image_certificates_resp
- server_groups: server_groups_2_71
**Example Show Server Details (2.63)**
@ -859,6 +860,7 @@ Response
- description: server_description_resp
- tags: tags
- trusted_image_certificates: server_trusted_image_certificates_resp
- server_groups: server_groups_2_71
**Example Update Server (2.63)**

View File

@ -0,0 +1,65 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"addr": "192.168.0.3",
"version": 4
}
]
},
"adminPass": "seekr3t",
"created": "2019-02-28T03:16:19Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {},
"original_name": "m1.tiny",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"id": "36b2afd5-1684-4d18-a49c-915bf0f5344c",
"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/36b2afd5-1684-4d18-a49c-915bf0f5344c",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/36b2afd5-1684-4d18-a49c-915bf0f5344c",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"meta_var": "meta_val"
},
"name": "foobar",
"progress": 0,
"server_groups": [
"f3d86fe6-4246-4be8-b87c-eb894626c741"
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": null,
"updated": "2019-02-28T03:16:20Z",
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi",
"user_id": "fake"
}
}

View File

@ -0,0 +1,14 @@
{
"rebuild" : {
"accessIPv4" : "1.2.3.4",
"accessIPv6" : "80fe::",
"OS-DCF:diskConfig": "AUTO",
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
"name" : "foobar",
"adminPass" : "seekr3t",
"metadata" : {
"meta_var" : "meta_val"
},
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi"
}
}

View File

@ -0,0 +1,23 @@
{
"server" : {
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"name" : "new-server-test",
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
"flavorRef" : "1",
"OS-DCF:diskConfig": "AUTO",
"metadata" : {
"My Server Name" : "Apache1"
},
"security_groups": [
{
"name": "default"
}
],
"user_data" : "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"networks": "auto"
},
"OS-SCH-HNT:scheduler_hints": {
"group": "f3d86fe6-4246-4be8-b87c-eb894626c741"
}
}

View File

@ -0,0 +1,22 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"adminPass": "DB2bQBhxvq8a",
"id": "84e2b49d-39a9-4d32-9100-e62161c236db",
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db",
"rel": "bookmark"
}
],
"security_groups": [
{
"name": "default"
}
]
}
}

View File

@ -0,0 +1,32 @@
{
"server": {
"OS-EXT-AZ:availability_zone": "UNKNOWN",
"OS-EXT-STS:power_state": 0,
"created": "2019-02-28T03:16:19Z",
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {},
"original_name": "m1.tiny",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"id": "2669556b-b4a3-41f1-a0c1-f9c7ff75e53c",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"server_groups": [
"f3d86fe6-4246-4be8-b87c-eb894626c741"
],
"status": "UNKNOWN",
"tenant_id": "project",
"user_id": "fake"
}
}

View File

@ -0,0 +1,89 @@
{
"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-0scisg0g",
"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": "2019-02-28T03:16:19.600768",
"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": "2019-02-28T03:16:18Z",
"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": "84e2b49d-39a9-4d32-9100-e62161c236db",
"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/84e2b49d-39a9-4d32-9100-e62161c236db",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"server_groups": [
"f3d86fe6-4246-4be8-b87c-eb894626c741"
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": null,
"updated": "2019-02-28T03:16:19Z",
"user_id": "fake"
}
}

View File

@ -0,0 +1,6 @@
{
"server_group": {
"name": "test",
"policy": "affinity"
}
}

View File

@ -0,0 +1,11 @@
{
"server_group": {
"id": "f3d86fe6-4246-4be8-b87c-eb894626c741",
"members": [],
"name": "test",
"policy": "affinity",
"project_id": "6f70656e737461636b20342065766572",
"rules": {},
"user_id": "fake"
}
}

View File

@ -0,0 +1,9 @@
{
"server": {
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"OS-DCF:diskConfig": "AUTO",
"name": "new-server-test",
"description": "Sample description"
}
}

View File

@ -0,0 +1,62 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"addr": "192.168.0.3",
"version": 4
}
]
},
"created": "2019-02-28T03:16:19Z",
"description": "Sample description",
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {},
"original_name": "m1.tiny",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"id": "60e840f8-dd17-476b-bd1d-33785066c496",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/60e840f8-dd17-476b-bd1d-33785066c496",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/60e840f8-dd17-476b-bd1d-33785066c496",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"progress": 0,
"server_groups": [
"f3d86fe6-4246-4be8-b87c-eb894626c741"
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": null,
"updated": "2019-02-28T03:16:19Z",
"user_id": "fake"
}
}

View File

@ -19,7 +19,7 @@
}
],
"status": "CURRENT",
"version": "2.70",
"version": "2.71",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -22,7 +22,7 @@
}
],
"status": "CURRENT",
"version": "2.70",
"version": "2.71",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -172,6 +172,9 @@ REST_API_VERSION_HISTORY = """REST API Version History:
condition in the deployment like an infrastructure failure.
* 2.70 - Exposes virtual device tags in the response of the
``os-volume_attachments`` and ``os-interface`` APIs.
* 2.71 - Adds the ``server_groups`` field to ``GET /servers/{id}``,
``PUT /servers/{server_id}`` and
``POST /servers/{server_id}/action`` (rebuild) responses.
"""
# The minimum and maximum versions of the API supported
@ -180,7 +183,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.70"
_MAX_API_VERSION = "2.71"
DEFAULT_API_VERSION = _MIN_API_VERSION
# Almost all proxy APIs which are related to network, images and baremetal

View File

@ -898,3 +898,14 @@ APIs:
* GET /servers/{server_id}/os-interface (list)
* GET /servers/{server_id}/os-interface/{port_id} (show)
* POST /servers/{server_id}/os-interface (attach)
2.71
----
The ``server_groups`` parameter will be in the response body of the following
APIs to list the server groups to which the server belongs:
* ``GET /servers/{server_id}``
* ``PUT /servers/{server_id}``
* ``POST /servers/{server_id}/action (rebuild)``

View File

@ -425,11 +425,15 @@ class ServersController(wsgi.Controller):
context.can(server_policies.SERVERS % 'show')
cell_down_support = api_version_request.is_supported(
req, min_version=PARTIAL_CONSTRUCT_FOR_CELL_DOWN_MIN_VERSION)
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
instance = self._get_server(
context, req, id, is_detail=True,
cell_down_support=cell_down_support)
return self._view_builder.show(
req, instance, cell_down_support=cell_down_support)
req, instance, cell_down_support=cell_down_support,
show_server_groups=show_server_groups)
@staticmethod
def _process_bdms_for_create(
@ -779,6 +783,8 @@ class ServersController(wsgi.Controller):
ctxt.can(server_policies.SERVERS % 'update',
target={'user_id': instance.user_id,
'project_id': instance.project_id})
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
server = body['server']
@ -795,17 +801,19 @@ class ServersController(wsgi.Controller):
try:
instance = self.compute_api.update_instance(ctxt, instance,
update_dict)
return self._view_builder.show(req, instance,
extend_address=False,
show_AZ=False,
show_config_drive=False,
show_extended_attr=False,
show_host_status=False,
show_keypair=False,
show_srv_usg=False,
show_sec_grp=False,
show_extended_status=False,
show_extended_volumes=False)
return self._view_builder.show(
req, instance,
extend_address=False,
show_AZ=False,
show_config_drive=False,
show_extended_attr=False,
show_host_status=False,
show_keypair=False,
show_srv_usg=False,
show_sec_grp=False,
show_extended_status=False,
show_extended_volumes=False,
show_server_groups=show_server_groups)
except exception.InstanceNotFound:
msg = _("Instance could not be found")
raise exc.HTTPNotFound(explanation=msg)
@ -1087,6 +1095,9 @@ class ServersController(wsgi.Controller):
# from microversion 2.54 onwards.
show_keypair = api_version_request.is_supported(
req, min_version='2.54')
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
view = self._view_builder.show(req, instance, extend_address=False,
show_AZ=False,
show_config_drive=False,
@ -1096,7 +1107,8 @@ class ServersController(wsgi.Controller):
show_srv_usg=False,
show_sec_grp=False,
show_extended_status=False,
show_extended_volumes=False)
show_extended_volumes=False,
show_server_groups=show_server_groups)
# Add on the admin_password attribute since the view doesn't do it
# unless instance passwords are disabled

View File

@ -140,7 +140,8 @@ class ViewBuilder(common.ViewBuilder):
# results.
return sorted(list(set(self._show_expected_attrs + expected_attrs)))
def _show_from_down_cell(self, request, instance, show_extra_specs):
def _show_from_down_cell(self, request, instance, show_extra_specs,
show_server_groups):
"""Function that constructs the partial response for the instance."""
ret = {
"server": {
@ -172,6 +173,10 @@ class ViewBuilder(common.ViewBuilder):
# in case its an old request spec which doesn't have the user_id
# data migrated, return UNKNOWN.
ret["server"]["user_id"] = instance.user_id or "UNKNOWN"
if show_server_groups:
context = request.environ['nova.context']
ret['server']['server_groups'] = self._get_server_groups(
context, instance)
else:
# GET /servers/detail includes links for GET /servers/{server_id}.
ret['server']["links"] = self._get_links(
@ -183,7 +188,7 @@ class ViewBuilder(common.ViewBuilder):
show_extended_attr=None, show_host_status=None,
show_keypair=True, show_srv_usg=True, show_sec_grp=True,
show_extended_status=True, show_extended_volumes=True,
bdms=None, cell_down_support=False):
bdms=None, cell_down_support=False, show_server_groups=False):
"""Detailed view of a single instance."""
if show_extra_specs is None:
# detail will pre-calculate this for us. If we're doing show,
@ -201,7 +206,7 @@ class ViewBuilder(common.ViewBuilder):
# `display_name`) and return partial constructs based on the
# information available from the nova_api database.
return self._show_from_down_cell(
request, instance, show_extra_specs)
request, instance, show_extra_specs, show_server_groups)
ip_v4 = instance.get('access_ip_v4')
ip_v6 = instance.get('access_ip_v6')
@ -339,6 +344,10 @@ class ViewBuilder(common.ViewBuilder):
trusted_certs = instance.trusted_certs.ids
server["server"]["trusted_image_certificates"] = trusted_certs
if show_server_groups:
server['server']['server_groups'] = self._get_server_groups(
context,
instance)
return server
def index(self, request, instances, cell_down_support=False):
@ -633,3 +642,12 @@ class ViewBuilder(common.ViewBuilder):
# with v2.0.
key = "os-extended-volumes:volumes_attached"
server[key] = volumes_attached
@staticmethod
def _get_server_groups(context, instance):
try:
sg = objects.InstanceGroup.get_by_instance_uuid(context,
instance.uuid)
return [sg.uuid]
except exception.InstanceGroupNotFound:
return []

View File

@ -0,0 +1,63 @@
{
"server": {
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"version": 4
}
]
},
"adminPass": "%(password)s",
"created": "%(isotime)s",
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {},
"original_name": "m1.tiny",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(uuid)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"
}
],
"locked": false,
"metadata": {
"meta_var": "meta_val"
},
"server_groups": ["%(uuid)s"],
"trusted_image_certificates": null,
"name": "%(name)s",
"description": null,
"progress": 0,
"OS-DCF:diskConfig": "AUTO",
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"updated": "%(isotime)s",
"user_id": "fake",
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi"
}
}

View File

@ -0,0 +1,14 @@
{
"rebuild" : {
"accessIPv4" : "%(access_ip_v4)s",
"accessIPv6" : "%(access_ip_v6)s",
"OS-DCF:diskConfig": "AUTO",
"imageRef" : "%(uuid)s",
"name" : "%(name)s",
"adminPass" : "%(pass)s",
"metadata" : {
"meta_var" : "meta_val"
},
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi"
}
}

View File

@ -0,0 +1,23 @@
{
"server" : {
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"name" : "new-server-test",
"imageRef" : "%(image_id)s",
"flavorRef" : "1",
"OS-DCF:diskConfig": "AUTO",
"metadata" : {
"My Server Name" : "Apache1"
},
"security_groups": [
{
"name": "default"
}
],
"user_data" : "%(user_data)s",
"networks": "auto"
},
"OS-SCH-HNT:scheduler_hints": {
"group": "%(sg_uuid)s"
}
}

View File

@ -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"
}
]
}
}

View File

@ -0,0 +1,30 @@
{
"server": {
"OS-EXT-STS:power_state": 0,
"OS-EXT-AZ:availability_zone": "UNKNOWN",
"created": "%(isotime)s",
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {},
"original_name": "m1.tiny",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"id": "%(id)s",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"status": "UNKNOWN",
"server_groups": ["%(uuid)s"],
"tenant_id": "project",
"user_id": "fake"
}
}

View File

@ -0,0 +1,87 @@
{
"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": [],
"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": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"server_groups": ["%(uuid)s"],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": null,
"updated": "%(isotime)s",
"user_id": "fake"
}
}

View File

@ -0,0 +1,6 @@
{
"server_group": {
"name": "%(name)s",
"policy": "affinity"
}
}

View File

@ -0,0 +1,11 @@
{
"server_group": {
"id": "%(id)s",
"members": [],
"name": "test",
"policy": "affinity",
"project_id": "6f70656e737461636b20342065766572",
"rules": {},
"user_id": "fake"
}
}

View File

@ -0,0 +1,9 @@
{
"server": {
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"OS-DCF:diskConfig": "AUTO",
"name": "new-server-test",
"description": "Sample description"
}
}

View File

@ -0,0 +1,61 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "192.168.0.3",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": "Sample description",
"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"
}
]
},
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(id)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(id)s",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"progress": 0,
"status": "ACTIVE",
"server_groups": ["%(uuid)s"],
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": null,
"updated": "%(isotime)s",
"user_id": "fake"
}
}

View File

@ -53,7 +53,8 @@ class ServersSampleBase(api_sample_base.ApiSampleTestBaseV21):
avr.APIVersionRequest(min), avr.APIVersionRequest(max)):
return name
def _post_server(self, use_common_server_api_samples=True, name=None):
def _post_server(self, use_common_server_api_samples=True, name=None,
extra_subs=None):
# param use_common_server_api_samples: Boolean to set whether tests use
# common sample files for server post request and response.
# Default is True which means _get_sample_path method will fetch the
@ -73,6 +74,8 @@ class ServersSampleBase(api_sample_base.ApiSampleTestBaseV21):
'-[0-9a-f]{4}-[0-9a-f]{12}',
'name': 'new-server-test' if name is None else name,
}
if extra_subs:
subs.update(extra_subs)
orig_value = self.__class__._use_common_server_api_samples
try:
@ -414,6 +417,99 @@ class ServersSampleJson269Test(ServersSampleBase):
self._verify_response('server-get-resp', subs, response, 200)
class ServersSampleJson271Test(ServersSampleBase):
microversion = '2.71'
scenarios = [('v2_71', {'api_major_version': 'v2.1'})]
def setUp(self):
super(ServersSampleJson271Test, self).setUp()
self.common_subs = {
'hostid': '[a-f0-9]+',
'instance_name': 'instance-\d{8}',
'hypervisor_hostname': r'[\w\.\-]+',
'hostname': r'[\w\.\-]+',
'access_ip_v4': '1.2.3.4',
'access_ip_v6': '80fe::',
'user_data': (self.user_data if six.PY2
else self.user_data.decode('utf-8')),
'cdrive': '.*',
}
# create server group
subs = {'name': 'test'}
response = self._do_post('os-server-groups',
'server-groups-post-req', subs)
self.sg_uuid = self._verify_response('server-groups-post-resp',
subs, response, 200)
def _test_servers_post(self):
return self._post_server(
use_common_server_api_samples=False,
extra_subs={'sg_uuid': self.sg_uuid})
def test_servers_get_with_server_group(self):
uuid = self._test_servers_post()
response = self._do_get('servers/%s' % uuid)
subs = self.common_subs.copy()
subs['id'] = uuid
self._verify_response('server-get-resp', subs, response, 200)
def test_servers_update_with_server_groups(self):
uuid = self._test_servers_post()
subs = self.common_subs.copy()
subs['id'] = uuid
response = self._do_put('servers/%s' % uuid,
'server-update-req', subs)
self._verify_response('server-update-resp', subs, response, 200)
def test_servers_rebuild_with_server_groups(self):
uuid = self._test_servers_post()
fakes.stub_out_key_pair_funcs(self)
image = fake.get_valid_image_id()
params = {
'uuid': image,
'name': 'foobar',
'key_name': 'new-key',
'description': 'description of foobar',
'pass': 'seekr3t',
'access_ip_v4': '1.2.3.4',
'access_ip_v6': '80fe::',
}
resp = self._do_post('servers/%s/action' % uuid,
'server-action-rebuild', params)
subs = self.common_subs.copy()
subs.update(params)
subs['id'] = uuid
del subs['uuid']
self._verify_response('server-action-rebuild-resp', subs, resp, 202)
def test_server_get_from_down_cells(self):
def _fake_instancemapping_get_by_cell_and_project(*args, **kwargs):
# global cell based on which rest of the functions are stubbed out
cell_fixture = nova_fixtures.SingleCellSimple()
return [{
'id': 1,
'updated_at': None,
'created_at': None,
'instance_uuid': utils_fixture.uuidsentinel.inst,
'cell_id': 1,
'project_id': "6f70656e737461636b20342065766572",
'cell_mapping': cell_fixture._fake_cell_list()[0],
'queued_for_delete': False
}]
self.stub_out('nova.objects.InstanceMappingList.'
'_get_not_deleted_by_cell_and_project_from_db',
_fake_instancemapping_get_by_cell_and_project)
uuid = self._test_servers_post()
with nova_fixtures.DownCellFixture():
response = self._do_get('servers/%s' % uuid)
subs = {'id': uuid}
self._verify_response('server-get-down-cell-resp',
subs, response, 200)
class ServersUpdateSampleJsonTest(ServersSampleBase):
def test_update_server(self):

View File

@ -57,6 +57,7 @@ from nova import exception
from nova.image import glance
from nova import objects
from nova.objects import instance as instance_obj
from nova.objects.instance_group import InstanceGroup
from nova.objects import tag
from nova.policies import servers as server_policies
from nova import policy
@ -2508,6 +2509,21 @@ class ServerControllerTestV266(ControllerTest):
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req)
class ServersControllerTestV271(ControllerTest):
wsgi_api_version = '2.71'
def req(self, url, use_admin_context=False):
return fakes.HTTPRequest.blank(url,
use_admin_context=use_admin_context,
version=self.wsgi_api_version)
def test_show_server_group_not_exist(self):
req = self.req('/fake/servers/%s' % FAKE_UUID)
servers = self.controller.show(req, FAKE_UUID)
expect_sg = []
self.assertEqual(expect_sg, servers['server']['server_groups'])
class ServersControllerDeleteTest(ControllerTest):
def setUp(self):
@ -3433,6 +3449,43 @@ class ServersControllerRebuildTestV263(ControllerTest):
six.text_type(ex))
class ServersControllerRebuildTestV271(ControllerTest):
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
def setUp(self):
super(ServersControllerRebuildTestV271, self).setUp()
self.req = fakes.HTTPRequest.blank('/fake/servers/a/action',
use_admin_context=True)
self.req.method = 'POST'
self.req.headers["content-type"] = "application/json"
self.req_user_id = self.req.environ['nova.context'].user_id
self.req_project_id = self.req.environ['nova.context'].project_id
self.req.api_version_request = (api_version_request.
APIVersionRequest('2.71'))
self.body = {
"rebuild": {
"imageRef": self.image_uuid,
"user_data": None
}
}
@mock.patch('nova.compute.api.API.get')
def _rebuild_server(self, mock_get):
ctx = self.req.environ['nova.context']
mock_get.return_value = fakes.stub_instance_obj(ctx,
vm_state=vm_states.ACTIVE, project_id=self.req_project_id,
user_id=self.req_user_id)
server = self.controller._action_rebuild(
self.req, FAKE_UUID, body=self.body).obj['server']
return server
@mock.patch.object(InstanceGroup, 'get_by_instance_uuid',
side_effect=exception.InstanceGroupNotFound(group_uuid=FAKE_UUID))
def test_rebuild_with_server_group_not_exist(self, mock_sg_get):
server = self._rebuild_server()
self.assertEqual([], server['server_groups'])
class ServersControllerUpdateTest(ControllerTest):
def _get_request(self, body=None):
@ -3721,6 +3774,23 @@ class ServersControllerUpdateTestV219(ServersControllerUpdateTest):
req, FAKE_UUID, body=body)
class ServersControllerUpdateTestV271(ServersControllerUpdateTest):
body = {'server': {'name': 'server_test'}}
def _get_request(self, body=None):
req = super(ServersControllerUpdateTestV271, self)._get_request(
body=body)
req.api_version_request = api_version_request.APIVersionRequest('2.71')
return req
@mock.patch.object(InstanceGroup, 'get_by_instance_uuid',
side_effect=exception.InstanceGroupNotFound(group_uuid=FAKE_UUID))
def test_update_with_server_group_not_exist(self, mock_sg_get):
req = self._get_request(self.body)
res_dict = self.controller.update(req, FAKE_UUID, body=self.body)
self.assertEqual([], res_dict['server']['server_groups'])
class ServerStatusTest(test.TestCase):
def setUp(self):

View File

@ -0,0 +1,10 @@
---
features:
- |
Starting with the 2.71 microversion the ``server_groups`` parameter will be
in the response body of the following APIs to list the server groups to
which the server belongs:
* ``GET /servers/{server_id}``
* ``PUT /servers/{server_id}``
* ``POST /servers/{server_id}/action (rebuild)``