api: Add support for 'hostname' parameter
Add microversion 2.90, which allows allows users to configure the hostname that will be exposed via the nova metadata service when creating their instance. Change-Id: I95047c1689ac14fa73eba48e19dc438988b78aad Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
982d459c65
commit
5e2c31ab78
@ -737,8 +737,10 @@ hostname_query_server:
|
||||
description: |
|
||||
Filter the server list result by the host name of server.
|
||||
|
||||
This parameter is only valid when specified by administrators.
|
||||
If non-admin users specify this parameter, it is ignored.
|
||||
This parameter is only valid when specified by administrators until
|
||||
microversion 2.90, after which it can be specified by all users.
|
||||
If non-admin users specify this parameter before microversion 2.90, it is
|
||||
ignored.
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
@ -6330,21 +6332,36 @@ server_host_create:
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.74
|
||||
server_hostname:
|
||||
server_hostname: &server_hostname
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
description: |
|
||||
The hostname set on the instance when it is booted.
|
||||
By default, it appears in the response for administrative users only.
|
||||
The hostname of the instance reported in the metadata service.
|
||||
This parameter only appears in responses for administrators until
|
||||
microversion 2.90, after which it is shown for all users.
|
||||
|
||||
.. note::
|
||||
|
||||
This information is published via the metadata service and requires
|
||||
application such as ``cloud-init`` to propogate it through to the
|
||||
instance.
|
||||
min_version: 2.3
|
||||
server_hostname_update_rebuild:
|
||||
server_hostname_req:
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
description: |
|
||||
The hostname set on the instance when it is booted.
|
||||
By default, it appears in the response for administrative users only.
|
||||
The hostname to configure for the instance in the metadata service.
|
||||
|
||||
.. note::
|
||||
|
||||
This information is published via the metadata service and requires
|
||||
application such as ``cloud-init`` to propogate it through to the
|
||||
instance.
|
||||
min_version: 2.90
|
||||
server_hostname_update_rebuild:
|
||||
<<: *server_hostname
|
||||
min_version: 2.75
|
||||
# This is the hypervisor_hostname in a POST (create instance) request body.
|
||||
server_hypervisor_hostname_create:
|
||||
|
@ -22,6 +22,7 @@ into a server since Mitaka release.
|
||||
|
||||
You can get an RDP, serial, SPICE, or VNC console for a server.
|
||||
|
||||
|
||||
Add (Associate) Floating Ip (addFloatingIp Action) (DEPRECATED)
|
||||
================================================================
|
||||
|
||||
@ -469,6 +470,7 @@ Response
|
||||
|
||||
If successful, this method does not return content in the response body.
|
||||
|
||||
|
||||
.. _reboot:
|
||||
|
||||
Reboot Server (reboot Action)
|
||||
@ -582,12 +584,18 @@ Request
|
||||
- key_name: key_name_rebuild_req
|
||||
- user_data: user_data_rebuild_req
|
||||
- trusted_image_certificates: server_trusted_image_certificates_rebuild_req
|
||||
- hostname: server_hostname_req
|
||||
|
||||
**Example Rebuild Server (rebuild Action) (v2.63)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.63/server-action-rebuild.json
|
||||
:language: javascript
|
||||
|
||||
**Example Rebuild Server (rebuild Action) (v2.90)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.90/server-action-rebuild.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
@ -662,6 +670,7 @@ Response
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.75/server-action-rebuild-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Remove (Disassociate) Floating Ip (removeFloatingIp Action) (DEPRECATED)
|
||||
=========================================================================
|
||||
|
||||
@ -791,6 +800,7 @@ Response
|
||||
.. literalinclude:: ../../doc/api_samples/os-rescue/server-rescue.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Resize Server (resize Action)
|
||||
=============================
|
||||
|
||||
|
@ -368,7 +368,6 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
|
||||
- server: server
|
||||
- flavorRef: flavorRef
|
||||
- name: server_name
|
||||
@ -404,6 +403,7 @@ Request
|
||||
- security_groups: security_groups
|
||||
- user_data: user_data
|
||||
- description: server_description
|
||||
- hostname: server_hostname_req
|
||||
- tags: server_tags_create
|
||||
- trusted_image_certificates: server_trusted_image_certificates_create_req
|
||||
- host: server_host_create
|
||||
@ -443,6 +443,11 @@ Request
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.74/server-create-req-with-host-and-node.json
|
||||
:language: javascript
|
||||
|
||||
**Example Create Server With Hostname (v2.90)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/servers/v2.90/server-create-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
@ -633,8 +638,15 @@ Response
|
||||
- OS-DCF:diskConfig: disk_config
|
||||
- OS-EXT-AZ:availability_zone: OS-EXT-AZ:availability_zone
|
||||
- OS-EXT-SRV-ATTR:host: OS-EXT-SRV-ATTR:host
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname
|
||||
- OS-EXT-SRV-ATTR:hypervisor_hostname: OS-EXT-SRV-ATTR:hypervisor_hostname
|
||||
- OS-EXT-SRV-ATTR:instance_name: OS-EXT-SRV-ATTR:instance_name
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data
|
||||
- OS-EXT-STS:power_state: OS-EXT-STS:power_state
|
||||
- OS-EXT-STS:task_state: OS-EXT-STS:task_state
|
||||
- OS-EXT-STS:vm_state: OS-EXT-STS:vm_state
|
||||
@ -656,13 +668,6 @@ Response
|
||||
- security_groups: security_groups_obj_optional
|
||||
- security_group.name: name
|
||||
- servers_links: servers_links
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data
|
||||
- locked: locked
|
||||
- host_status: host_status
|
||||
- description: server_description_resp
|
||||
@ -757,8 +762,15 @@ Response
|
||||
- OS-DCF:diskConfig: disk_config
|
||||
- OS-EXT-AZ:availability_zone: OS-EXT-AZ:availability_zone
|
||||
- OS-EXT-SRV-ATTR:host: OS-EXT-SRV-ATTR:host
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname
|
||||
- OS-EXT-SRV-ATTR:hypervisor_hostname: OS-EXT-SRV-ATTR:hypervisor_hostname
|
||||
- OS-EXT-SRV-ATTR:instance_name: OS-EXT-SRV-ATTR:instance_name
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data
|
||||
- OS-EXT-STS:power_state: OS-EXT-STS:power_state
|
||||
- OS-EXT-STS:task_state: OS-EXT-STS:task_state
|
||||
- OS-EXT-STS:vm_state: OS-EXT-STS:vm_state
|
||||
@ -779,13 +791,6 @@ Response
|
||||
- progress: progress
|
||||
- security_groups: security_groups_obj_optional
|
||||
- security_group.name: name
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data
|
||||
- locked: locked
|
||||
- host_status: host_status
|
||||
- description: server_description_resp
|
||||
@ -830,11 +835,14 @@ Request
|
||||
- accessIPv4: accessIPv4_in
|
||||
- accessIPv6: accessIPv6_in
|
||||
- name: server_name_optional
|
||||
- hostname: server_hostname_req
|
||||
- OS-DCF:diskConfig: OS-DCF:diskConfig
|
||||
- description: server_description
|
||||
|
||||
.. note:: You can specify parameters to update independently.
|
||||
e.g. ``name`` only, ``description`` only, ``name`` and ``description``, etc.
|
||||
.. note::
|
||||
|
||||
You can specify parameters to update independently.
|
||||
e.g. ``name`` only, ``description`` only, ``name`` and ``description``, etc.
|
||||
|
||||
**Example Update Server (2.63)**
|
||||
|
||||
@ -889,18 +897,18 @@ Response
|
||||
- config_drive: config_drive_resp_update_rebuild
|
||||
- OS-EXT-AZ:availability_zone: OS-EXT-AZ:availability_zone_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:host: OS-EXT-SRV-ATTR:host_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:hypervisor_hostname: OS-EXT-SRV-ATTR:hypervisor_hostname_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:instance_name: OS-EXT-SRV-ATTR:instance_name_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data_update
|
||||
- OS-EXT-STS:power_state: OS-EXT-STS:power_state_update_rebuild
|
||||
- OS-EXT-STS:task_state: OS-EXT-STS:task_state_update_rebuild
|
||||
- OS-EXT-STS:vm_state: OS-EXT-STS:vm_state_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:hostname: server_hostname_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:reservation_id: server_reservation_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:launch_index: server_launch_index_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:kernel_id: server_kernel_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:ramdisk_id: server_ramdisk_id_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:root_device_name: server_root_device_name_update_rebuild
|
||||
- OS-EXT-SRV-ATTR:user_data: server_user_data_update
|
||||
- os-extended-volumes:volumes_attached: os-extended-volumes:volumes_attached_update_rebuild
|
||||
- os-extended-volumes:volumes_attached.id: os-extended-volumes:volumes_attached.id_update_rebuild
|
||||
- os-extended-volumes:volumes_attached.delete_on_termination: os-extended-volumes:volumes_attached.delete_on_termination_update_rebuild
|
||||
|
@ -0,0 +1,80 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "us-west",
|
||||
"OS-EXT-SRV-ATTR:hostname": "updated-hostname",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"OS-SRV-USG:launched_at": "2021-08-19T15:16:22.177882",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"addr": "192.168.1.30",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"adminPass": "seekr3t",
|
||||
"config_drive": "",
|
||||
"created": "2019-04-23T17:10:22Z",
|
||||
"description": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
|
||||
"id": "0c37a84a-c757-4f22-8c7f-0bf8b6970886",
|
||||
"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/0c37a84a-c757-4f22-8c7f-0bf8b6970886",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0c37a84a-c757-4f22-8c7f-0bf8b6970886",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"metadata": {
|
||||
"meta_var": "meta_val"
|
||||
},
|
||||
"name": "foobar",
|
||||
"os-extended-volumes:volumes_attached": [],
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"server_groups": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "2019-04-23T17:10:24Z",
|
||||
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
15
doc/api_samples/servers/v2.90/server-action-rebuild.json
Normal file
15
doc/api_samples/servers/v2.90/server-action-rebuild.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"accessIPv4" : "1.2.3.4",
|
||||
"accessIPv6" : "80fe::",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"name" : "foobar",
|
||||
"adminPass" : "seekr3t",
|
||||
"hostname": "custom-hostname",
|
||||
"metadata" : {
|
||||
"meta_var" : "meta_val"
|
||||
},
|
||||
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi"
|
||||
}
|
||||
}
|
30
doc/api_samples/servers/v2.90/server-create-req.json
Normal file
30
doc/api_samples/servers/v2.90/server-create-req.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"server" : {
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavorRef" : "1",
|
||||
"availability_zone": "us-west",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"hostname": "custom-hostname",
|
||||
"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=="
|
||||
},
|
||||
"OS-SCH-HNT:scheduler_hints": {
|
||||
"same_host": "48e6a9f6-30af-47e0-bc04-acaed113bb4e"
|
||||
}
|
||||
}
|
22
doc/api_samples/servers/v2.90/server-create-resp.json
Normal file
22
doc/api_samples/servers/v2.90/server-create-resp.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"adminPass": "6NpUwoz2QDRN",
|
||||
"id": "f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
81
doc/api_samples/servers/v2.90/server-get-resp.json
Normal file
81
doc/api_samples/servers/v2.90/server-get-resp.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "192.168.1.30",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "2013-09-03T04:01:32Z",
|
||||
"description": null,
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "92154fab69d5883ba2c8622b7e65f745dd33257221c07af363c51b29",
|
||||
"id": "0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"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/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"config_drive": "",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:hostname": "custom-hostname",
|
||||
"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": "2013-09-23T13:37:00.880302",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"server_groups": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "2013-09-03T04:01:33Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
8
doc/api_samples/servers/v2.90/server-update-req.json
Normal file
8
doc/api_samples/servers/v2.90/server-update-req.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "4.3.2.1",
|
||||
"accessIPv6": "80fe::",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"hostname" : "new-server-hostname"
|
||||
}
|
||||
}
|
78
doc/api_samples/servers/v2.90/server-update-resp.json
Normal file
78
doc/api_samples/servers/v2.90/server-update-resp.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "192.168.1.30",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "2013-09-03T04:01:32Z",
|
||||
"description": null,
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "92154fab69d5883ba2c8622b7e65f745dd33257221c07af363c51b29",
|
||||
"id": "0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"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/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"config_drive": "",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "us-west",
|
||||
"OS-EXT-SRV-ATTR:hostname": "new-server-hostname",
|
||||
"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": "2013-09-23T13:37:00.880302",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"server_groups": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "2013-09-03T04:01:33Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
88
doc/api_samples/servers/v2.90/servers-details-resp.json
Normal file
88
doc/api_samples/servers/v2.90/servers-details-resp.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "192.168.1.30",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "2013-09-03T04:01:32Z",
|
||||
"description": "",
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "bcf92836fc9ed4203a75cb0337afc7f917d2be504164b995c2334b25",
|
||||
"id": "f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"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/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"My Server Name": "Apache1"
|
||||
},
|
||||
"name": "new-server-test",
|
||||
"config_drive": "",
|
||||
"locked": false,
|
||||
"locked_reason": "",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:hostname": "custom-hostname",
|
||||
"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": "2013-09-23T13:53:12.774549",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "2013-09-03T04:01:32Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
],
|
||||
"servers_links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/detail?limit=1&marker=f5dc173b-6804-445a-a6d8-c705dad5b5eb",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
24
doc/api_samples/servers/v2.90/servers-list-resp.json
Normal file
24
doc/api_samples/servers/v2.90/servers-list-resp.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"id": "22c91117-08de-4894-9aa9-6ef382400985",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/22c91117-08de-4894-9aa9-6ef382400985",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/22c91117-08de-4894-9aa9-6ef382400985",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "new-server-test"
|
||||
}
|
||||
],
|
||||
"servers_links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers?limit=1&marker=22c91117-08de-4894-9aa9-6ef382400985",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.89",
|
||||
"version": "2.90",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.89",
|
||||
"version": "2.90",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -243,7 +243,10 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 2.89 - Add ``attachment_id``, ``bdm_uuid`` and remove ``id`` from the
|
||||
responses of ``GET /servers/{server_id}/os-volume_attachments``
|
||||
and ``GET /servers/{server_id}/os-volume_attachments/{volume_id}``
|
||||
|
||||
* 2.90 - Add support for requesting a specific hostname when creating,
|
||||
updating or rebuilding an instance. The
|
||||
``OS-EXT-SRV-ATTR:hostname`` attribute is now returned in various
|
||||
server responses regardless of policy configuration.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -252,7 +255,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.89'
|
||||
_MAX_API_VERSION = '2.90'
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
# Almost all proxy APIs which are related to network, images and baremetal
|
||||
|
@ -1180,11 +1180,25 @@ has been removed in favour of including this field in the primary ``GET
|
||||
|
||||
.. _microversion 2.89:
|
||||
|
||||
2.89 (Maximum in Xena)
|
||||
----------------------
|
||||
2.89
|
||||
----
|
||||
|
||||
``attachment_id`` and ``bdm_uuid`` are now included in the responses for ``GET
|
||||
/servers/{server_id}/os-volume_attachments`` and ``GET
|
||||
/servers/{server_id}/os-volume_attachments/{volume_id}``. Additionally the
|
||||
``id`` field is dropped from the response as it duplicates the ``volumeId``
|
||||
field.
|
||||
|
||||
.. _microversion 2.90:
|
||||
|
||||
2.90 (Maximum in Xena)
|
||||
----------------------
|
||||
|
||||
The ``POST /servers`` (create server), ``PUT /servers/{id}`` (update server)
|
||||
and ``POST /servers/{server_id}/action (rebuild)`` (rebuild server) APIs now
|
||||
accept a ``hostname`` parameter, allowing users to configure a hostname when
|
||||
creating the instance. When specified, this will replace the auto-generated
|
||||
hostname based on the display name.
|
||||
|
||||
In addition, the ``OS-EXT-SRV-ATTR:hostname`` field for all server
|
||||
responses is now visible to all users. Previously this was an admin-only field.
|
||||
|
@ -355,6 +355,10 @@ create_v274['properties']['server'][
|
||||
create_v274['properties']['server'][
|
||||
'properties']['hypervisor_hostname'] = parameter_types.fqdn
|
||||
|
||||
# Add hostname in server
|
||||
create_v290 = copy.deepcopy(create_v274)
|
||||
create_v290['properties']['server'][
|
||||
'properties']['hostname'] = parameter_types.hostname
|
||||
|
||||
update = {
|
||||
'type': 'object',
|
||||
@ -383,6 +387,10 @@ update_v219['properties']['server'][
|
||||
'properties']['description'] = parameter_types.description
|
||||
|
||||
|
||||
update_v290 = copy.deepcopy(update_v219)
|
||||
update_v290['properties']['server'][
|
||||
'properties']['hostname'] = parameter_types.hostname
|
||||
|
||||
rebuild = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
@ -437,6 +445,10 @@ rebuild_v263 = copy.deepcopy(rebuild_v257)
|
||||
rebuild_v263['properties']['rebuild']['properties'][
|
||||
'trusted_image_certificates'] = parameter_types.trusted_certs
|
||||
|
||||
rebuild_v290 = copy.deepcopy(rebuild_v263)
|
||||
rebuild_v290['properties']['rebuild']['properties'][
|
||||
'hostname'] = parameter_types.hostname
|
||||
|
||||
|
||||
resize = {
|
||||
'type': 'object',
|
||||
|
@ -665,7 +665,8 @@ class ServersController(wsgi.Controller):
|
||||
@validation.schema(schema_servers.create_v257, '2.57', '2.62')
|
||||
@validation.schema(schema_servers.create_v263, '2.63', '2.66')
|
||||
@validation.schema(schema_servers.create_v267, '2.67', '2.73')
|
||||
@validation.schema(schema_servers.create_v274, '2.74')
|
||||
@validation.schema(schema_servers.create_v274, '2.74', '2.89')
|
||||
@validation.schema(schema_servers.create_v290, '2.90')
|
||||
def create(self, req, body):
|
||||
"""Creates a new server for a given user."""
|
||||
context = req.environ['nova.context']
|
||||
@ -675,6 +676,9 @@ class ServersController(wsgi.Controller):
|
||||
description = name
|
||||
if api_version_request.is_supported(req, min_version='2.19'):
|
||||
description = server_dict.get('description')
|
||||
hostname = None
|
||||
if api_version_request.is_supported(req, min_version='2.90'):
|
||||
hostname = server_dict.get('hostname')
|
||||
|
||||
# Arguments to be passed to instance create function
|
||||
create_kwargs = {}
|
||||
@ -772,6 +776,7 @@ class ServersController(wsgi.Controller):
|
||||
image_uuid,
|
||||
display_name=name,
|
||||
display_description=description,
|
||||
hostname=hostname,
|
||||
availability_zone=availability_zone,
|
||||
forced_host=host, forced_node=node,
|
||||
metadata=server_dict.get('metadata', {}),
|
||||
@ -815,6 +820,7 @@ class ServersController(wsgi.Controller):
|
||||
exception.MismatchVolumeAZException,
|
||||
exception.MultiplePortsNotApplicable,
|
||||
exception.InvalidFixedIpAndMaxCountRequest,
|
||||
exception.AmbiguousHostnameForMultipleInstances,
|
||||
exception.InstanceUserDataMalformed,
|
||||
exception.PortNotFound,
|
||||
exception.FixedIpAlreadyInUse,
|
||||
@ -888,7 +894,8 @@ class ServersController(wsgi.Controller):
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.schema(schema_servers.update_v20, '2.0', '2.0')
|
||||
@validation.schema(schema_servers.update, '2.1', '2.18')
|
||||
@validation.schema(schema_servers.update_v219, '2.19')
|
||||
@validation.schema(schema_servers.update_v219, '2.19', '2.89')
|
||||
@validation.schema(schema_servers.update_v290, '2.90')
|
||||
def update(self, req, id, body):
|
||||
"""Update server then pass on to version-specific controller."""
|
||||
|
||||
@ -899,7 +906,7 @@ class ServersController(wsgi.Controller):
|
||||
target={'user_id': instance.user_id,
|
||||
'project_id': instance.project_id})
|
||||
show_server_groups = api_version_request.is_supported(
|
||||
req, min_version='2.71')
|
||||
req, min_version='2.71')
|
||||
|
||||
server = body['server']
|
||||
|
||||
@ -911,11 +918,14 @@ class ServersController(wsgi.Controller):
|
||||
# This is allowed to be None (remove description)
|
||||
update_dict['display_description'] = server['description']
|
||||
|
||||
if 'hostname' in server:
|
||||
update_dict['hostname'] = server['hostname']
|
||||
|
||||
helpers.translate_attributes(helpers.UPDATE, server, update_dict)
|
||||
|
||||
try:
|
||||
instance = self.compute_api.update_instance(ctxt, instance,
|
||||
update_dict)
|
||||
instance = self.compute_api.update_instance(
|
||||
ctxt, instance, update_dict)
|
||||
|
||||
# NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild
|
||||
# API response will show all attributes like GET /servers API.
|
||||
@ -1134,7 +1144,8 @@ class ServersController(wsgi.Controller):
|
||||
@validation.schema(schema_servers.rebuild_v219, '2.19', '2.53')
|
||||
@validation.schema(schema_servers.rebuild_v254, '2.54', '2.56')
|
||||
@validation.schema(schema_servers.rebuild_v257, '2.57', '2.62')
|
||||
@validation.schema(schema_servers.rebuild_v263, '2.63')
|
||||
@validation.schema(schema_servers.rebuild_v263, '2.63', '2.89')
|
||||
@validation.schema(schema_servers.rebuild_v290, '2.90')
|
||||
def _action_rebuild(self, req, id, body):
|
||||
"""Rebuild an instance with the given attributes."""
|
||||
rebuild_dict = body['rebuild']
|
||||
@ -1158,8 +1169,10 @@ class ServersController(wsgi.Controller):
|
||||
|
||||
helpers.translate_attributes(helpers.REBUILD, rebuild_dict, kwargs)
|
||||
|
||||
if (api_version_request.is_supported(req, min_version='2.54') and
|
||||
'key_name' in rebuild_dict):
|
||||
if (
|
||||
api_version_request.is_supported(req, min_version='2.54') and
|
||||
'key_name' in rebuild_dict
|
||||
):
|
||||
kwargs['key_name'] = rebuild_dict.get('key_name')
|
||||
|
||||
# If user_data is not specified, we don't include it in kwargs because
|
||||
@ -1171,17 +1184,25 @@ class ServersController(wsgi.Controller):
|
||||
|
||||
# Skip policy check for 'rebuild:trusted_certs' if no trusted
|
||||
# certificate IDs were provided.
|
||||
if ((api_version_request.is_supported(req, min_version='2.63')) and
|
||||
# Note that this is different from server create since with
|
||||
# rebuild a user can unset/reset the trusted certs by
|
||||
# specifying trusted_image_certificates=None, similar to
|
||||
# key_name.
|
||||
('trusted_image_certificates' in rebuild_dict)):
|
||||
if (
|
||||
api_version_request.is_supported(req, min_version='2.63') and
|
||||
# Note that this is different from server create since with
|
||||
# rebuild a user can unset/reset the trusted certs by
|
||||
# specifying trusted_image_certificates=None, similar to
|
||||
# key_name.
|
||||
'trusted_image_certificates' in rebuild_dict
|
||||
):
|
||||
kwargs['trusted_certs'] = rebuild_dict.get(
|
||||
'trusted_image_certificates')
|
||||
context.can(server_policies.SERVERS % 'rebuild:trusted_certs',
|
||||
target=target)
|
||||
|
||||
if (
|
||||
api_version_request.is_supported(req, min_version='2.90') and
|
||||
'hostname' in rebuild_dict
|
||||
):
|
||||
kwargs['hostname'] = rebuild_dict['hostname']
|
||||
|
||||
for request_attribute, instance_attribute in attr_map.items():
|
||||
try:
|
||||
if request_attribute == 'name':
|
||||
@ -1380,6 +1401,8 @@ class ServersController(wsgi.Controller):
|
||||
'created_at', 'launched_at', 'terminated_at',
|
||||
'power_state', 'task_state', 'vm_state', 'progress',
|
||||
'user_id',)
|
||||
if api_version_request.is_supported(req, min_version='2.90'):
|
||||
opt_list += ('hostname',)
|
||||
return opt_list
|
||||
|
||||
def _get_instance(self, context, instance_uuid):
|
||||
|
@ -313,6 +313,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
show_extended_attr = context.can(
|
||||
esa_policies.BASE_POLICY_NAME, fatal=False,
|
||||
target={'project_id': instance.project_id})
|
||||
|
||||
if show_extended_attr:
|
||||
properties = ['host', 'name', 'node']
|
||||
if api_version_request.is_supported(request, min_version='2.3'):
|
||||
@ -342,6 +343,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
# the OS-EXT-SRV-ATTR prefix for the attribute key name.
|
||||
key = "OS-EXT-SRV-ATTR:%s" % attr
|
||||
server["server"][key] = getattr(instance, attr)
|
||||
|
||||
if show_extended_status:
|
||||
# NOTE(gmann): Removed 'locked_by' from extended status
|
||||
# to make it same as V2. If needed it can be added with
|
||||
@ -352,6 +354,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
# compat with v2.0.
|
||||
key = "%s:%s" % ('OS-EXT-STS', state)
|
||||
server["server"][key] = instance[state]
|
||||
|
||||
if show_extended_volumes:
|
||||
# NOTE(mriedem): The os-extended-volumes prefix should not be used
|
||||
# for new attributes after v2.1. They are only in v2.1 for backward
|
||||
@ -364,7 +367,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
self._add_volumes_attachments(server["server"],
|
||||
bdms,
|
||||
add_delete_on_termination)
|
||||
if (api_version_request.is_supported(request, min_version='2.16')):
|
||||
|
||||
if api_version_request.is_supported(request, min_version='2.16'):
|
||||
if show_host_status is None:
|
||||
unknown_only = self._get_host_status_unknown_only(
|
||||
context, instance)
|
||||
@ -404,6 +408,13 @@ class ViewBuilder(common.ViewBuilder):
|
||||
trusted_certs = instance.trusted_certs.ids
|
||||
server["server"]["trusted_image_certificates"] = trusted_certs
|
||||
|
||||
if api_version_request.is_supported(request, min_version='2.90'):
|
||||
# API 2.90 made this field visible to non-admins, but we only show
|
||||
# it if it's not already added
|
||||
if not show_extended_attr:
|
||||
server["server"]["OS-EXT-SRV-ATTR:hostname"] = \
|
||||
instance.hostname
|
||||
|
||||
if show_server_groups:
|
||||
server['server']['server_groups'] = self._get_server_groups(
|
||||
context,
|
||||
|
@ -245,6 +245,38 @@ non_negative_integer = {
|
||||
'pattern': '^[0-9]*$', 'minimum': 0, 'minLength': 1
|
||||
}
|
||||
|
||||
# A host-specific or leaf label.
|
||||
#
|
||||
# This is based on the specifications from two RFCs, RFCC 952 and RFC 1123.
|
||||
#
|
||||
# From RFC 952:
|
||||
#
|
||||
# A "name" (Net, Host, Gateway, or Domain name) is a text string up to 24
|
||||
# characters drawn from the alphabet (A-Z), digits (0-9), minus sign (-), and
|
||||
# period (.). Note that periods are only allowed when they serve to delimit
|
||||
# components of "domain style names". (See RFC-921, "Domain Name System
|
||||
# Implementation Schedule", for background). No blank or space characters are
|
||||
# permitted as part of a name. No distinction is made between upper and lower
|
||||
# case. The first character must be an alpha character. The last character
|
||||
# must not be a minus sign or period. [...] Single character names or
|
||||
# nicknames are not allowed.
|
||||
#
|
||||
# From RFC 1123, which revises RFC 952:
|
||||
#
|
||||
# The syntax of a legal Internet host name was specified in RFC-952 [DNS:4].
|
||||
# One aspect of host name syntax is hereby changed: the restriction on the
|
||||
# first character is relaxed to allow either a letter or a digit. Host
|
||||
# software MUST support this more liberal syntax.
|
||||
#
|
||||
# Host software MUST handle host names of up to 63 characters and SHOULD
|
||||
# handle host names of up to 255 characters.
|
||||
hostname = {
|
||||
'type': 'string',
|
||||
'minLength': 2,
|
||||
'maxLength': 63,
|
||||
'pattern': '^[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+$',
|
||||
}
|
||||
|
||||
fqdn = {
|
||||
'type': 'string', 'minLength': 1, 'maxLength': 255,
|
||||
# NOTE: 'host' is defined in "services" table, and that
|
||||
|
@ -999,7 +999,7 @@ class API:
|
||||
|
||||
def _validate_and_build_base_options(
|
||||
self, context, flavor, boot_meta, image_href, image_id, kernel_id,
|
||||
ramdisk_id, display_name, display_description, key_name,
|
||||
ramdisk_id, display_name, display_description, hostname, key_name,
|
||||
key_data, security_groups, availability_zone, user_data, metadata,
|
||||
access_ip_v4, access_ip_v6, requested_networks, config_drive,
|
||||
auto_disk_config, reservation_id, max_count,
|
||||
@ -1091,6 +1091,7 @@ class API:
|
||||
'ephemeral_gb': flavor['ephemeral_gb'],
|
||||
'display_name': display_name,
|
||||
'display_description': display_description,
|
||||
'hostname': hostname,
|
||||
'user_data': user_data,
|
||||
'key_name': key_name,
|
||||
'key_data': key_data,
|
||||
@ -1500,7 +1501,7 @@ class API:
|
||||
def _create_instance(self, context, flavor,
|
||||
image_href, kernel_id, ramdisk_id,
|
||||
min_count, max_count,
|
||||
display_name, display_description,
|
||||
display_name, display_description, hostname,
|
||||
key_name, key_data, security_groups,
|
||||
availability_zone, user_data, metadata, injected_files,
|
||||
admin_password, access_ip_v4, access_ip_v6,
|
||||
@ -1550,7 +1551,7 @@ class API:
|
||||
) = self._validate_and_build_base_options(
|
||||
context, flavor, boot_meta, image_href, image_id,
|
||||
kernel_id, ramdisk_id, display_name, display_description,
|
||||
key_name, key_data, security_groups, availability_zone,
|
||||
hostname, key_name, key_data, security_groups, availability_zone,
|
||||
user_data, metadata, access_ip_v4, access_ip_v6,
|
||||
requested_networks, config_drive, auto_disk_config,
|
||||
reservation_id, max_count, supports_port_resource_request,
|
||||
@ -1586,8 +1587,8 @@ class API:
|
||||
flavor, metadata, injected_files,
|
||||
block_device_mapping.root_bdm(), validate_numa=False)
|
||||
|
||||
instance_group = self._get_requested_instance_group(context,
|
||||
filter_properties)
|
||||
instance_group = self._get_requested_instance_group(
|
||||
context, filter_properties)
|
||||
|
||||
tags = self._create_tag_list_obj(context, tags)
|
||||
|
||||
@ -1903,24 +1904,21 @@ class API:
|
||||
if 'display_name' not in instance or instance.display_name is None:
|
||||
instance.display_name = 'Server %s' % instance.uuid
|
||||
|
||||
# if we're booting multiple instances, we need to add an indexing
|
||||
# suffix to both instance.hostname and instance.display_name. This is
|
||||
# not necessary for a single instance.
|
||||
if num_instances == 1:
|
||||
default_hostname = 'Server-%s' % instance.uuid
|
||||
instance.hostname = utils.sanitize_hostname(
|
||||
instance.display_name, default_hostname)
|
||||
elif num_instances > 1:
|
||||
old_display_name = instance.display_name
|
||||
new_display_name = '%s-%d' % (old_display_name, index + 1)
|
||||
# only set the hostname if the user hasn't already requested one
|
||||
if 'hostname' not in instance or not instance.hostname:
|
||||
# if we're booting multiple instances, we need to add an indexing
|
||||
# suffix to both instance.hostname and instance.display_name.
|
||||
# This is not necessary for a single instance.
|
||||
hostname = utils.sanitize_hostname(instance.display_name)
|
||||
if not hostname:
|
||||
hostname = f'Server-{instance.uuid}'
|
||||
elif num_instances > 1:
|
||||
hostname = f'{hostname}-{index + 1}'
|
||||
|
||||
if utils.sanitize_hostname(old_display_name) == "":
|
||||
instance.hostname = 'Server-%s' % instance.uuid
|
||||
else:
|
||||
instance.hostname = utils.sanitize_hostname(
|
||||
new_display_name)
|
||||
instance.hostname = hostname
|
||||
|
||||
instance.display_name = new_display_name
|
||||
if num_instances > 1:
|
||||
instance.display_name = f'{instance.display_name}-{index + 1}'
|
||||
|
||||
def _populate_instance_for_create(
|
||||
self, context, instance, image, index, security_groups, flavor,
|
||||
@ -2029,7 +2027,7 @@ class API:
|
||||
self, context, flavor,
|
||||
image_href, kernel_id=None, ramdisk_id=None,
|
||||
min_count=None, max_count=None,
|
||||
display_name=None, display_description=None,
|
||||
display_name=None, display_description=None, hostname=None,
|
||||
key_name=None, key_data=None, security_groups=None,
|
||||
availability_zone=None, forced_host=None, forced_node=None,
|
||||
user_data=None, metadata=None, injected_files=None,
|
||||
@ -2054,6 +2052,9 @@ class API:
|
||||
self._check_multiple_instances_with_neutron_ports(
|
||||
requested_networks)
|
||||
|
||||
if hostname and max_count is not None and max_count > 1:
|
||||
raise exception.AmbiguousHostnameForMultipleInstances()
|
||||
|
||||
if availability_zone and forced_host is None:
|
||||
azs = availability_zones.get_availability_zones(
|
||||
context.elevated(), self.host_api, get_only_available=True)
|
||||
@ -2068,7 +2069,7 @@ class API:
|
||||
context, flavor,
|
||||
image_href, kernel_id, ramdisk_id,
|
||||
min_count, max_count,
|
||||
display_name, display_description,
|
||||
display_name, display_description, hostname,
|
||||
key_name, key_data, security_groups,
|
||||
availability_zone, user_data, metadata,
|
||||
injected_files, admin_password,
|
||||
@ -3483,6 +3484,9 @@ class API:
|
||||
instance.trusted_certs = self._retrieve_trusted_certs_object(
|
||||
context, trusted_certs, rebuild=True)
|
||||
|
||||
if 'hostname' in kwargs:
|
||||
instance.hostname = kwargs.pop('hostname')
|
||||
|
||||
image_id, image = self._get_image(context, image_href)
|
||||
self._check_auto_disk_config(image=image,
|
||||
auto_disk_config=auto_disk_config)
|
||||
|
@ -501,6 +501,10 @@ class MultiplePortsNotApplicable(Invalid):
|
||||
msg_fmt = _("Failed to launch instances: %(reason)s")
|
||||
|
||||
|
||||
class AmbiguousHostnameForMultipleInstances(Invalid):
|
||||
msg_fmt = _("Unable to allocate a single hostname to multiple instances")
|
||||
|
||||
|
||||
class InvalidFixedIpAndMaxCountRequest(Invalid):
|
||||
msg_fmt = _("Failed to launch instances: %(reason)s")
|
||||
|
||||
|
@ -42,6 +42,10 @@ This rule will control the visibility for a set of servers attributes:
|
||||
Microvision 2.75 added the above attributes in the ``PUT /servers/{server_id}``
|
||||
and ``POST /servers/{server_id}/action (rebuild)`` API responses which are
|
||||
also controlled by this policy rule, like the ``GET /servers*`` APIs.
|
||||
|
||||
Microversion 2.90 made the ``OS-EXT-SRV-ATTR:hostname`` attribute available to
|
||||
all users, so this policy has no effect on that field for microversions 2.90
|
||||
and greater.
|
||||
""",
|
||||
operations=[
|
||||
{
|
||||
|
@ -0,0 +1,80 @@
|
||||
{
|
||||
"server": {
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "us-west",
|
||||
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"OS-EXT-STS:vm_state": "active",
|
||||
"OS-SRV-USG:launched_at": "%(strtime)s",
|
||||
"OS-SRV-USG:terminated_at": null,
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "80fe::",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"addr": "192.168.1.30",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"adminPass": "seekr3t",
|
||||
"config_drive": "",
|
||||
"created": "%(isotime)s",
|
||||
"description": null,
|
||||
"flavor": {
|
||||
"disk": 1,
|
||||
"ephemeral": 0,
|
||||
"extra_specs": {},
|
||||
"original_name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": 0,
|
||||
"vcpus": 1
|
||||
},
|
||||
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"metadata": {
|
||||
"meta_var": "meta_val"
|
||||
},
|
||||
"name": "foobar",
|
||||
"os-extended-volumes:volumes_attached": [],
|
||||
"progress": 0,
|
||||
"security_groups": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
],
|
||||
"server_groups": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "%(isotime)s",
|
||||
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"accessIPv4" : "%(access_ip_v4)s",
|
||||
"accessIPv6" : "%(access_ip_v6)s",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"imageRef" : "%(uuid)s",
|
||||
"name" : "%(name)s",
|
||||
"adminPass" : "%(pass)s",
|
||||
"hostname": "%(hostname)s",
|
||||
"metadata" : {
|
||||
"meta_var" : "meta_val"
|
||||
},
|
||||
"user_data": "ZWNobyAiaGVsbG8gd29ybGQi"
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"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",
|
||||
"hostname": "custom-hostname"
|
||||
}
|
||||
}
|
@ -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,81 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "%(isotime)s",
|
||||
"description": null,
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"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:hostname": "%(hostname)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"
|
||||
}
|
||||
],
|
||||
"server_groups": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "%(isotime)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"hostname": "new-server-hostname"
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "%(isotime)s",
|
||||
"description": null,
|
||||
"locked": false,
|
||||
"locked_reason": null,
|
||||
"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": "",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "us-west",
|
||||
"OS-EXT-SRV-ATTR:hostname": "new-server-hostname",
|
||||
"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": [],
|
||||
"status": "ACTIVE",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "%(isotime)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"accessIPv4": "%(access_ip_v4)s",
|
||||
"accessIPv6": "%(access_ip_v6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74",
|
||||
"OS-EXT-IPS:type": "fixed",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"created": "%(isotime)s",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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",
|
||||
"locked": false,
|
||||
"locked_reason": "",
|
||||
"OS-DCF:diskConfig": "AUTO",
|
||||
"OS-EXT-AZ:availability_zone": "nova",
|
||||
"OS-EXT-SRV-ATTR:hostname": "custom-hostname",
|
||||
"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",
|
||||
"tags": [],
|
||||
"tenant_id": "6f70656e737461636b20342065766572",
|
||||
"trusted_image_certificates": null,
|
||||
"updated": "%(isotime)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
],
|
||||
"servers_links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers/detail?limit=1&marker=%(id)s",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"servers_links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/servers?limit=1&marker=%(id)s",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
@ -596,9 +596,6 @@ class ServersSampleJson274Test(ServersSampleBase):
|
||||
def _setup_compute_service(self):
|
||||
return self.start_service('compute', host='openstack-node-01')
|
||||
|
||||
def setUp(self):
|
||||
super(ServersSampleJson274Test, self).setUp()
|
||||
|
||||
def test_servers_post_with_only_host(self):
|
||||
self._post_server(use_common_server_api_samples=False,
|
||||
sample_name='server-create-req-with-only-host')
|
||||
@ -612,6 +609,15 @@ class ServersSampleJson274Test(ServersSampleBase):
|
||||
sample_name='server-create-req-with-host-and-node')
|
||||
|
||||
|
||||
class ServersSampleJson290Test(ServersSampleJsonTest):
|
||||
microversion = '2.90'
|
||||
scenarios = [('v2_90', {'api_major_version': 'v2.1'})]
|
||||
use_common_server_post = False
|
||||
|
||||
# we want to show that the non-admin response includes the hostname
|
||||
ADMIN_API = False
|
||||
|
||||
|
||||
class ServersUpdateSampleJsonTest(ServersSampleBase):
|
||||
|
||||
# Many of the 'os_compute_api:servers:*' policies are admin-only, and we
|
||||
@ -634,7 +640,7 @@ class ServersUpdateSampleJson247Test(ServersUpdateSampleJsonTest):
|
||||
scenarios = [('v2_47', {'api_major_version': 'v2.1'})]
|
||||
|
||||
|
||||
class ServersSampleJson275Test(ServersUpdateSampleJsonTest):
|
||||
class ServersUpdateSampleJson275Test(ServersUpdateSampleJsonTest):
|
||||
microversion = '2.75'
|
||||
scenarios = [('v2_75', {'api_major_version': 'v2.1'})]
|
||||
|
||||
@ -656,6 +662,46 @@ class ServersSampleJson275Test(ServersUpdateSampleJsonTest):
|
||||
self._verify_response('server-action-rebuild-resp', subs, resp, 202)
|
||||
|
||||
|
||||
class ServersUpdateSampleJson289Test(ServersUpdateSampleJsonTest):
|
||||
microversion = '2.90'
|
||||
scenarios = [('v2_90', {'api_major_version': 'v2.1'})]
|
||||
|
||||
# we want to show that the non-admin response includes the hostname
|
||||
ADMIN_API = False
|
||||
|
||||
def test_update_server(self):
|
||||
uuid = self._post_server()
|
||||
subs = {}
|
||||
subs['hostid'] = '[a-f0-9]+'
|
||||
subs['access_ip_v4'] = '1.2.3.4'
|
||||
subs['access_ip_v6'] = '80fe::'
|
||||
subs['hostname'] = 'updated-hostname'
|
||||
response = self._do_put('servers/%s' % uuid,
|
||||
'server-update-req', subs)
|
||||
self._verify_response('server-update-resp', subs, response, 200)
|
||||
|
||||
def test_server_rebuild(self):
|
||||
uuid = self._post_server()
|
||||
params = {
|
||||
'uuid': self.glance.auto_disk_config_enabled_image['id'],
|
||||
'name': 'foobar',
|
||||
'pass': 'seekr3t',
|
||||
'hostid': '[a-f0-9]+',
|
||||
'access_ip_v4': '1.2.3.4',
|
||||
'access_ip_v6': '80fe::',
|
||||
'hostname': 'updated-hostname',
|
||||
}
|
||||
|
||||
resp = self._do_post(
|
||||
'servers/%s/action' % uuid,
|
||||
'server-action-rebuild',
|
||||
params,
|
||||
)
|
||||
subs = params.copy()
|
||||
del subs['uuid']
|
||||
self._verify_response('server-action-rebuild-resp', subs, resp, 202)
|
||||
|
||||
|
||||
class ServerSortKeysJsonTests(ServersSampleBase):
|
||||
sample_dir = 'servers-sort'
|
||||
|
||||
|
@ -2845,6 +2845,67 @@ class ServersControllerTestV283(ControllerTest):
|
||||
self.assertEqual(uuids.fake, servers[0]['id'])
|
||||
|
||||
|
||||
class ServersControllerTestV290(ControllerTest):
|
||||
filters = ['hostname']
|
||||
|
||||
def test_get_servers_by_new_filter_for_non_admin(self):
|
||||
def fake_get_all(context, search_opts=None, **kwargs):
|
||||
self.assertIsNotNone(search_opts)
|
||||
for f in self.filters:
|
||||
self.assertIn(f, search_opts)
|
||||
return objects.InstanceList(
|
||||
objects=[fakes.stub_instance_obj(100, uuid=uuids.fake)])
|
||||
|
||||
self.mock_get_all.side_effect = fake_get_all
|
||||
|
||||
query_str = '&'.join('%s=test_value' % f for f in self.filters)
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.path_with_query % query_str, version='2.90')
|
||||
servers = self.controller.index(req)['servers']
|
||||
|
||||
self.assertEqual(1, len(servers))
|
||||
self.assertEqual(uuids.fake, servers[0]['id'])
|
||||
|
||||
def test_get_servers_new_filters_for_non_admin_old_version(self):
|
||||
def fake_get_all(context, search_opts=None, **kwargs):
|
||||
self.assertIsNotNone(search_opts)
|
||||
for f in self.filters:
|
||||
self.assertNotIn(f, search_opts)
|
||||
return objects.InstanceList(objects=[])
|
||||
|
||||
# Without policy edition, test will fail and admin filter will work.
|
||||
self.policy.set_rules({'os_compute_api:servers:index': ''})
|
||||
self.mock_get_all.side_effect = fake_get_all
|
||||
|
||||
query_str = '&'.join('%s=test_value' % f for f in self.filters)
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.path_with_query % query_str, version='2.89')
|
||||
servers = self.controller.index(req)['servers']
|
||||
|
||||
self.assertEqual(0, len(servers))
|
||||
|
||||
def test_get_servers_by_node_fail_non_admin(self):
|
||||
def fake_get_all(context, search_opts=None, **kwargs):
|
||||
self.assertIsNotNone(search_opts)
|
||||
self.assertNotIn('node', search_opts)
|
||||
return objects.InstanceList(
|
||||
objects=[fakes.stub_instance_obj(100, uuid=uuids.fake)])
|
||||
|
||||
self.mock_get_all.side_effect = fake_get_all
|
||||
self.policy.set_rules({
|
||||
'os_compute_api:servers:index': '',
|
||||
'os_compute_api:servers:allow_all_filters': 'role:admin',
|
||||
})
|
||||
|
||||
query_str = "node=node1"
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.path_with_query % query_str, version='2.90')
|
||||
servers = self.controller.index(req)['servers']
|
||||
|
||||
self.assertEqual(1, len(servers))
|
||||
self.assertEqual(uuids.fake, servers[0]['id'])
|
||||
|
||||
|
||||
class ServersControllerDeleteTest(ControllerTest):
|
||||
|
||||
def setUp(self):
|
||||
@ -3609,6 +3670,11 @@ class ServersControllerRebuildTestV263(ControllerTest):
|
||||
server = self.controller._action_rebuild(
|
||||
self.req, FAKE_UUID, body=self.body).obj['server']
|
||||
|
||||
# TODO(stephenfin): This is a lie. We call '_get_server' immediately
|
||||
# after making the call to 'nova.compute.api.API().rebuild_server' in
|
||||
# '_action_rebuild', which means all we're testing here is the value
|
||||
# returned by 'mock_get' above. Drop it in favour of testing the calls
|
||||
# to the API itself
|
||||
if certs:
|
||||
self.assertEqual(certs, server['trusted_image_certificates'])
|
||||
else:
|
||||
@ -3761,6 +3827,69 @@ class ServersControllerRebuildTestV271(ControllerTest):
|
||||
self.assertEqual([], server['server_groups'])
|
||||
|
||||
|
||||
class ServersControllerRebuildTestV290(ControllerTest):
|
||||
microversion = '2.90'
|
||||
image_uuid = nova_fixtures.GlanceFixture.image3['id']
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
mock_rebuild = mock.patch(
|
||||
'nova.compute.api.API.rebuild', return_value=None)
|
||||
self.mock_rebuild = mock_rebuild.start()
|
||||
self.addCleanup(mock_rebuild.stop)
|
||||
|
||||
def _get_request(self, body=None):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.path_action % FAKE_UUID,
|
||||
use_admin_context=True,
|
||||
)
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = jsonutils.dump_as_bytes(body)
|
||||
req.api_version_request = api_version_request.APIVersionRequest(
|
||||
self.microversion)
|
||||
|
||||
return req
|
||||
|
||||
def test_rebuild_server_with_hostname(self):
|
||||
body = {
|
||||
'rebuild': {
|
||||
'imageRef': self.image_uuid,
|
||||
'hostname': 'new-hostname',
|
||||
}
|
||||
}
|
||||
req = self._get_request(body)
|
||||
|
||||
# There's nothing to check here from the return value since the
|
||||
# 'rebuild' API is a cast and we immediately fetch the instance from
|
||||
# the database after this cast...which returns a mocked Instance
|
||||
self.controller._action_rebuild(
|
||||
req, FAKE_UUID, body=body,
|
||||
).obj['server']
|
||||
|
||||
# ...so instead we check the call to the API itself
|
||||
self.mock_rebuild.assert_called_once()
|
||||
self.assertIn('hostname', self.mock_rebuild.call_args[0][1])
|
||||
|
||||
def test_rebuild_server_with_hostname_old_version(self):
|
||||
"""Tests that trying to rebuild with hostname before 2.90 fails."""
|
||||
body = {
|
||||
'rebuild': {
|
||||
'imageRef': self.image_uuid,
|
||||
'hostname': 'new-hostname',
|
||||
}
|
||||
}
|
||||
req = self._get_request(body)
|
||||
req.api_version_request = api_version_request.APIVersionRequest('2.89')
|
||||
|
||||
ex = self.assertRaises(
|
||||
exception.ValidationError,
|
||||
self.controller._action_rebuild,
|
||||
req, FAKE_UUID, body=body)
|
||||
self.assertIn('hostname', str(ex))
|
||||
|
||||
|
||||
class _ServersControllerUpdateTest(ControllerTest):
|
||||
|
||||
microversion = None
|
||||
@ -3970,6 +4099,47 @@ class ServersControllerUpdateTestV271(_ServersControllerUpdateTest):
|
||||
self.assertEqual([], res_dict['server']['server_groups'])
|
||||
|
||||
|
||||
class ServersControllerUpdateTestV290(_ServersControllerUpdateTest):
|
||||
|
||||
microversion = '2.90'
|
||||
|
||||
def test_update_server_with_hostname(self):
|
||||
body = {'server': {'hostname': 'my-hostname'}}
|
||||
req = self._get_request(body)
|
||||
res_dict = self.controller.update(req, FAKE_UUID, body=body)
|
||||
|
||||
self.assertEqual(res_dict['server']['id'], FAKE_UUID)
|
||||
self.assertEqual(
|
||||
res_dict['server']["OS-EXT-SRV-ATTR:hostname"], 'my-hostname')
|
||||
|
||||
def test_update_server_with_hostname__too_long(self):
|
||||
body = {'server': {'hostname': 'a' * 64}}
|
||||
req = self._get_request(body)
|
||||
self.assertRaises(
|
||||
exception.ValidationError, self.controller.update,
|
||||
req, FAKE_UUID, body=body)
|
||||
|
||||
def test_update_server_with_hostname__invalid_fqdn(self):
|
||||
# only hostnames are allowed, not FQDN
|
||||
body = {'server': {'hostname': 'hostname.example.com'}}
|
||||
req = self._get_request(body)
|
||||
self.assertRaises(
|
||||
exception.ValidationError, self.controller.update,
|
||||
req, FAKE_UUID, body=body)
|
||||
|
||||
def test_update_server_with_hostname_old_version(self):
|
||||
"""Tests that trying to update with hostname before 2.90 fails."""
|
||||
body = {'server': {'hostname': 'new-hostname'}}
|
||||
req = self._get_request(body)
|
||||
req.api_version_request = api_version_request.APIVersionRequest('2.89')
|
||||
|
||||
ex = self.assertRaises(
|
||||
exception.ValidationError,
|
||||
self.controller.update,
|
||||
req, FAKE_UUID, body=body)
|
||||
self.assertIn('hostname', str(ex))
|
||||
|
||||
|
||||
class ServersControllerTriggerCrashDumpTest(ControllerTest):
|
||||
|
||||
def setUp(self):
|
||||
@ -7049,6 +7219,52 @@ class ServersControllerCreateTestV274(ServersControllerCreateTest):
|
||||
pass
|
||||
|
||||
|
||||
class ServersControllerCreateTestV290(ServersControllerCreateTest):
|
||||
|
||||
def _generate_req(self, hostname=None, api_version='2.90'):
|
||||
if hostname:
|
||||
self.body['server']['hostname'] = hostname
|
||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||
self.req.api_version_request = \
|
||||
api_version_request.APIVersionRequest(api_version)
|
||||
|
||||
def test_create_instance_with_hostname(self):
|
||||
self._generate_req(hostname='test-hostname')
|
||||
self.controller.create(self.req, body=self.body).obj['server']
|
||||
|
||||
def test_create_instance_with_hostname_invalid(self):
|
||||
self._generate_req(hostname='example.com')
|
||||
|
||||
ex = self.assertRaises(
|
||||
exception.ValidationError,
|
||||
self.controller.create,
|
||||
self.req, body=self.body)
|
||||
self.assertIn('Invalid input for field/attribute hostname.', str(ex))
|
||||
|
||||
def test_create_instance_with_hostname_old_version(self):
|
||||
self._generate_req(hostname='hostname', api_version='2.89')
|
||||
|
||||
ex = self.assertRaises(
|
||||
exception.ValidationError,
|
||||
self.controller.create,
|
||||
self.req, body=self.body)
|
||||
self.assertIn("'hostname' was unexpected", str(ex))
|
||||
|
||||
@mock.patch.object(
|
||||
compute_api.API, 'create',
|
||||
side_effect=exception.AmbiguousHostnameForMultipleInstances())
|
||||
def test_create_multiple_instances_with_hostname(self, mock_create):
|
||||
self.body['server']['hostname'] = 'hostname'
|
||||
self.body['server']['max_count'] = 2
|
||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||
self.req.api_version_request = \
|
||||
api_version_request.APIVersionRequest('2.90')
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.create,
|
||||
self.req, body=self.body)
|
||||
|
||||
|
||||
class ServersControllerCreateTestWithMock(test.TestCase):
|
||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
flavor_ref = 'http://localhost/123/flavors/3'
|
||||
|
@ -355,6 +355,14 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
self.compute_api.create, self.context, 'fake_flavor', 'image_id',
|
||||
max_count=2, requested_networks=requested_networks)
|
||||
|
||||
def test_specified_hostname_and_multiple_instances(self):
|
||||
# Tests that if hostname is specified then there is only one instance
|
||||
# request allowed (i.e max_count == 1)
|
||||
self.assertRaises(
|
||||
exception.AmbiguousHostnameForMultipleInstances,
|
||||
self.compute_api.create, self.context, 'fake_flavor', 'image_id',
|
||||
max_count=2, hostname='foo')
|
||||
|
||||
# TODO(huaqiang): Remove in Wallaby
|
||||
@mock.patch('nova.compute.api.API._check_requested_networks',
|
||||
new=mock.Mock(return_value=1))
|
||||
@ -4856,8 +4864,7 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
volume_types)
|
||||
self.assertEqual(bdms[0].volume_type, volume_types[0]['name'])
|
||||
|
||||
def _test_provision_instances_with_cinder_error(self,
|
||||
expected_exception):
|
||||
def _test_provision_instances_with_cinder_error(self, expected_exception):
|
||||
@mock.patch('nova.compute.utils.check_num_instances_quota')
|
||||
@mock.patch.object(objects.Instance, 'create')
|
||||
@mock.patch.object(objects.RequestSpec, 'from_components')
|
||||
@ -7185,11 +7192,11 @@ class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase):
|
||||
self.compute_api._validate_and_build_base_options(
|
||||
self.context, flavor, boot_meta, uuids.image_href,
|
||||
mock.sentinel.image_id, kernel_id, ramdisk_id,
|
||||
'fake-display-name', 'fake-description', key_name,
|
||||
key_data, requested_secgroups, 'fake-az', user_data,
|
||||
metadata, access_ip_v4, access_ip_v6, requested_networks,
|
||||
config_drive, auto_disk_config, reservation_id, max_count,
|
||||
supports_port_resource_request
|
||||
'fake-display-name', 'fake-description', 'fake-hostname',
|
||||
key_name, key_data, requested_secgroups, 'fake-az',
|
||||
user_data, metadata, access_ip_v4, access_ip_v6,
|
||||
requested_networks, config_drive, auto_disk_config,
|
||||
reservation_id, max_count, supports_port_resource_request,
|
||||
)
|
||||
)
|
||||
# Assert the neutron security group API get method was called once
|
||||
|
16
releasenotes/notes/microversion-2-90-59fb6d4ec420b9f4.yaml
Normal file
16
releasenotes/notes/microversion-2-90-59fb6d4ec420b9f4.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The 2.90 microversion has been added. This microversion allows users to
|
||||
specify a requested hostname to be configured for the instance metadata
|
||||
when creating an instance (``POST /servers``), updating an instance
|
||||
(``PUT /servers/{id}``), or rebuilding an instance
|
||||
(``POST /servers/{server_id}/action (rebuild)``). When specified, this
|
||||
hostname replaces the hostname that nova auto-generates from the instance
|
||||
display name. As with the auto-generated hostnames, a service such as
|
||||
``cloud-init`` can automatically configure the hostname in the guest OS
|
||||
using this information retrieved from the metadata service.
|
||||
|
||||
In addition, starting with the 2.90 microversion, the
|
||||
``OS-EXT-SRV-ATTR:hostname`` field is now returned for all users.
|
||||
Previously this was restricted to admin users.
|
Loading…
Reference in New Issue
Block a user