Merge "Handle uuids in os-hypervisors API"
This commit is contained in:
commit
15cac9d7e5
@ -25,7 +25,7 @@ the ``policy.json`` file.
|
|||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
Error response codes: unauthorized(401), forbidden(403)
|
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
@ -34,6 +34,9 @@ Request
|
|||||||
|
|
||||||
- limit: hypervisor_limit
|
- limit: hypervisor_limit
|
||||||
- marker: hypervisor_marker
|
- marker: hypervisor_marker
|
||||||
|
- marker: hypervisor_marker_uuid
|
||||||
|
- hypervisor_hostname_pattern: hypervisor_hostname_pattern_query
|
||||||
|
- with_servers: hypervisor_with_servers_query
|
||||||
|
|
||||||
Response
|
Response
|
||||||
--------
|
--------
|
||||||
@ -43,15 +46,24 @@ Response
|
|||||||
- hypervisors: hypervisors
|
- hypervisors: hypervisors
|
||||||
- hypervisor_hostname: hypervisor_hostname
|
- hypervisor_hostname: hypervisor_hostname
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body
|
||||||
|
- id: hypervisor_id_body_uuid
|
||||||
- state: hypervisor_state
|
- state: hypervisor_state
|
||||||
- status: hypervisor_status
|
- status: hypervisor_status
|
||||||
- hypervisor_links: hypervisor_links
|
- hypervisor_links: hypervisor_links
|
||||||
|
- servers: hypervisor_servers
|
||||||
|
- servers.uuid: hypervisor_servers_uuid
|
||||||
|
- servers.name: hypervisor_servers_name
|
||||||
|
|
||||||
**Example List Hypervisors (v2.33): JSON response**
|
**Example List Hypervisors (v2.33): JSON response**
|
||||||
|
|
||||||
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.33/hypervisors-list-resp.json
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.33/hypervisors-list-resp.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
**Example List Hypervisors With Servers (v2.53): JSON response**
|
||||||
|
|
||||||
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.53/hypervisors-with-servers-resp.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
List Hypervisors Details
|
List Hypervisors Details
|
||||||
========================
|
========================
|
||||||
|
|
||||||
@ -65,7 +77,7 @@ the ``policy.json`` file.
|
|||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
Error response codes: unauthorized(401), forbidden(403)
|
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
@ -74,6 +86,9 @@ Request
|
|||||||
|
|
||||||
- limit: hypervisor_limit
|
- limit: hypervisor_limit
|
||||||
- marker: hypervisor_marker
|
- marker: hypervisor_marker
|
||||||
|
- marker: hypervisor_marker_uuid
|
||||||
|
- hypervisor_hostname_pattern: hypervisor_hostname_pattern_query
|
||||||
|
- with_servers: hypervisor_with_servers_query
|
||||||
|
|
||||||
Response
|
Response
|
||||||
--------
|
--------
|
||||||
@ -93,14 +108,19 @@ Response
|
|||||||
- hypervisor_type: hypervisor_type_body
|
- hypervisor_type: hypervisor_type_body
|
||||||
- hypervisor_version: hypervisor_version
|
- hypervisor_version: hypervisor_version
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body
|
||||||
|
- id: hypervisor_id_body_uuid
|
||||||
- local_gb: local_gb
|
- local_gb: local_gb
|
||||||
- local_gb_used: local_gb_used
|
- local_gb_used: local_gb_used
|
||||||
- memory_mb: memory_mb
|
- memory_mb: memory_mb
|
||||||
- memory_mb_used: memory_mb_used
|
- memory_mb_used: memory_mb_used
|
||||||
- running_vms: running_vms
|
- running_vms: running_vms
|
||||||
|
- servers: hypervisor_servers
|
||||||
|
- servers.uuid: hypervisor_servers_uuid
|
||||||
|
- servers.name: hypervisor_servers_name
|
||||||
- service: hypervisor_service
|
- service: hypervisor_service
|
||||||
- service.host: host_name_body
|
- service.host: host_name_body
|
||||||
- service.id: service_id_body
|
- service.id: service_id_body_2_52
|
||||||
|
- service.id: service_id_body_2_53
|
||||||
- service.disable_reason: service_disable_reason
|
- service.disable_reason: service_disable_reason
|
||||||
- vcpus: hypervisor_vcpus
|
- vcpus: hypervisor_vcpus
|
||||||
- vcpus_used: hypervisor_vcpus_used
|
- vcpus_used: hypervisor_vcpus_used
|
||||||
@ -111,6 +131,11 @@ Response
|
|||||||
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.33/hypervisors-detail-resp.json
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.33/hypervisors-detail-resp.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
**Example List Hypervisors Details (v2.53): JSON response**
|
||||||
|
|
||||||
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.53/hypervisors-detail-resp.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
Show Hypervisor Statistics
|
Show Hypervisor Statistics
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
@ -163,7 +188,7 @@ the ``policy.json`` file.
|
|||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
|
Error response codes: badRequest(400), unauthorized(401), forbidden(403), itemNotFound(404)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
@ -171,6 +196,8 @@ Request
|
|||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- hypervisor_id: hypervisor_id
|
- hypervisor_id: hypervisor_id
|
||||||
|
- hypervisor_id: hypervisor_id_uuid
|
||||||
|
- with_servers: hypervisor_with_servers_query
|
||||||
|
|
||||||
Response
|
Response
|
||||||
--------
|
--------
|
||||||
@ -190,14 +217,19 @@ Response
|
|||||||
- hypervisor_type: hypervisor_type_body
|
- hypervisor_type: hypervisor_type_body
|
||||||
- hypervisor_version: hypervisor_version
|
- hypervisor_version: hypervisor_version
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body
|
||||||
|
- id: hypervisor_id_body_uuid
|
||||||
- local_gb: local_gb
|
- local_gb: local_gb
|
||||||
- local_gb_used: local_gb_used
|
- local_gb_used: local_gb_used
|
||||||
- memory_mb: memory_mb
|
- memory_mb: memory_mb
|
||||||
- memory_mb_used: memory_mb_used
|
- memory_mb_used: memory_mb_used
|
||||||
- running_vms: running_vms
|
- running_vms: running_vms
|
||||||
|
- servers: hypervisor_servers
|
||||||
|
- servers.uuid: hypervisor_servers_uuid
|
||||||
|
- servers.name: hypervisor_servers_name
|
||||||
- service: hypervisor_service
|
- service: hypervisor_service
|
||||||
- service.host: host_name_body
|
- service.host: host_name_body
|
||||||
- service.id: service_id_body
|
- service.id: service_id_body_2_52
|
||||||
|
- service.id: service_id_body_2_53
|
||||||
- service.disable_reason: service_disable_reason
|
- service.disable_reason: service_disable_reason
|
||||||
- vcpus: hypervisor_vcpus
|
- vcpus: hypervisor_vcpus
|
||||||
- vcpus_used: hypervisor_vcpus_used
|
- vcpus_used: hypervisor_vcpus_used
|
||||||
@ -207,6 +239,11 @@ Response
|
|||||||
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.28/hypervisors-show-resp.json
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.28/hypervisors-show-resp.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
**Example Show Hypervisor Details With Servers (v2.53): JSON response**
|
||||||
|
|
||||||
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.53/hypervisors-show-with-servers-resp.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
Show Hypervisor Uptime
|
Show Hypervisor Uptime
|
||||||
======================
|
======================
|
||||||
|
|
||||||
@ -220,7 +257,7 @@ the ``policy.json`` file.
|
|||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
|
Error response codes: badRequest(400), unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
@ -228,6 +265,7 @@ Request
|
|||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- hypervisor_id: hypervisor_id
|
- hypervisor_id: hypervisor_id
|
||||||
|
- hypervisor_id: hypervisor_id_uuid
|
||||||
|
|
||||||
Response
|
Response
|
||||||
--------
|
--------
|
||||||
@ -237,6 +275,7 @@ Response
|
|||||||
- hypervisor: hypervisor
|
- hypervisor: hypervisor
|
||||||
- hypervisor_hostname: hypervisor_hostname
|
- hypervisor_hostname: hypervisor_hostname
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body
|
||||||
|
- id: hypervisor_id_body_uuid
|
||||||
- state: hypervisor_state
|
- state: hypervisor_state
|
||||||
- status: hypervisor_status
|
- status: hypervisor_status
|
||||||
- uptime: uptime
|
- uptime: uptime
|
||||||
@ -246,13 +285,23 @@ Response
|
|||||||
.. literalinclude:: ../../doc/api_samples/os-hypervisors/hypervisors-uptime-resp.json
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/hypervisors-uptime-resp.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
**Example Show Hypervisor Uptime (v2.53): JSON response**
|
||||||
|
|
||||||
|
.. literalinclude:: ../../doc/api_samples/os-hypervisors/v2.53/hypervisors-uptime-resp.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
Search Hypervisor
|
Search Hypervisor
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. rest_method:: GET /os-hypervisors/{hypervisor_hostname_pattern}/search
|
.. rest_method:: GET /os-hypervisors/{hypervisor_hostname_pattern}/search
|
||||||
|
max_version: 2.52
|
||||||
|
|
||||||
Search hypervisor by a given hypervisor host name or portion of it.
|
Search hypervisor by a given hypervisor host name or portion of it.
|
||||||
|
|
||||||
|
.. warning:: This API is deprecated starting with microversion 2.53. Use
|
||||||
|
`List Hypervisors`_ with the ``hypervisor_hostname_pattern`` query
|
||||||
|
parameter with microversion 2.53 and later.
|
||||||
|
|
||||||
Policy defaults enable only users with the administrative role to perform
|
Policy defaults enable only users with the administrative role to perform
|
||||||
this operation. Cloud providers can change these permissions through
|
this operation. Cloud providers can change these permissions through
|
||||||
the ``policy.json`` file.
|
the ``policy.json`` file.
|
||||||
@ -275,7 +324,7 @@ Response
|
|||||||
|
|
||||||
- hypervisors: hypervisors
|
- hypervisors: hypervisors
|
||||||
- hypervisor_hostname: hypervisor_hostname
|
- hypervisor_hostname: hypervisor_hostname
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body_no_version
|
||||||
- state: hypervisor_state
|
- state: hypervisor_state
|
||||||
- status: hypervisor_status
|
- status: hypervisor_status
|
||||||
|
|
||||||
@ -288,10 +337,15 @@ List Hypervisor Servers
|
|||||||
=======================
|
=======================
|
||||||
|
|
||||||
.. rest_method:: GET /os-hypervisors/{hypervisor_hostname_pattern}/servers
|
.. rest_method:: GET /os-hypervisors/{hypervisor_hostname_pattern}/servers
|
||||||
|
max_version: 2.52
|
||||||
|
|
||||||
List all servers belong to each hypervisor whose host name is matching
|
List all servers belong to each hypervisor whose host name is matching
|
||||||
a given hypervisor host name or portion of it.
|
a given hypervisor host name or portion of it.
|
||||||
|
|
||||||
|
.. warning:: This API is deprecated starting with microversion 2.53. Use
|
||||||
|
`List Hypervisors`_ with the ``hypervisor_hostname_pattern`` and
|
||||||
|
``with_servers`` query parameters with microversion 2.53 and later.
|
||||||
|
|
||||||
Policy defaults enable only users with the administrative role to perform
|
Policy defaults enable only users with the administrative role to perform
|
||||||
this operation. Cloud providers can change these permissions through
|
this operation. Cloud providers can change these permissions through
|
||||||
the ``policy.json`` file.
|
the ``policy.json`` file.
|
||||||
@ -314,7 +368,7 @@ Response
|
|||||||
|
|
||||||
- hypervisors: hypervisors
|
- hypervisors: hypervisors
|
||||||
- hypervisor_hostname: hypervisor_hostname
|
- hypervisor_hostname: hypervisor_hostname
|
||||||
- id: hypervisor_id_body
|
- id: hypervisor_id_body_no_version
|
||||||
- state: hypervisor_state
|
- state: hypervisor_state
|
||||||
- status: hypervisor_status
|
- status: hypervisor_status
|
||||||
- servers: servers
|
- servers: servers
|
||||||
|
@ -182,6 +182,14 @@ hypervisor_id:
|
|||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
|
max_version: 2.52
|
||||||
|
hypervisor_id_uuid:
|
||||||
|
description: |
|
||||||
|
The ID of the hypervisor as a UUID.
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
image_id:
|
image_id:
|
||||||
description: |
|
description: |
|
||||||
The UUID of the image.
|
The UUID of the image.
|
||||||
@ -565,6 +573,19 @@ hostname_query_server:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
hypervisor_hostname_pattern_query:
|
||||||
|
description: |
|
||||||
|
The hypervisor host name or a portion of it. The hypervisor hosts are
|
||||||
|
selected with the host name matching this pattern.
|
||||||
|
|
||||||
|
.. note:: ``limit`` and ``marker`` query parameters for paging are
|
||||||
|
not supported when listing hypervisors using a hostname pattern.
|
||||||
|
Also, ``links`` will not be returned in the response when using this
|
||||||
|
query parameter.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
hypervisor_limit:
|
hypervisor_limit:
|
||||||
description: |
|
description: |
|
||||||
Requests a page size of items. Returns a number of items up to a limit value.
|
Requests a page size of items. Returns a number of items up to a limit value.
|
||||||
@ -584,12 +605,29 @@ hypervisor_marker:
|
|||||||
required: false
|
required: false
|
||||||
type: integer
|
type: integer
|
||||||
min_version: 2.33
|
min_version: 2.33
|
||||||
|
max_version: 2.52
|
||||||
|
hypervisor_marker_uuid:
|
||||||
|
description: |
|
||||||
|
The ID of the last-seen item as a UUID. Use the ``limit`` parameter to make
|
||||||
|
an initial limited request and use the ID of the last-seen item from the
|
||||||
|
response as the ``marker`` parameter value in a subsequent limited request.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
hypervisor_query:
|
hypervisor_query:
|
||||||
description: |
|
description: |
|
||||||
Filters the response by a hypervisor type.
|
Filters the response by a hypervisor type.
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
hypervisor_with_servers_query:
|
||||||
|
description: |
|
||||||
|
Include all servers which belong to each hypervisor in the response output.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
min_version: 2.53
|
||||||
image_name_query:
|
image_name_query:
|
||||||
description: |
|
description: |
|
||||||
Filters the response by an image name, as a string.
|
Filters the response by an image name, as a string.
|
||||||
@ -2969,6 +3007,20 @@ hypervisor_id_body:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
|
max_version: 2.52
|
||||||
|
hypervisor_id_body_no_version:
|
||||||
|
description: |
|
||||||
|
The id of the hypervisor.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
hypervisor_id_body_uuid:
|
||||||
|
description: |
|
||||||
|
The id of the hypervisor as a UUID.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
hypervisor_links:
|
hypervisor_links:
|
||||||
description: |
|
description: |
|
||||||
Links to the hypervisors resource. See `API Guide / Links and
|
Links to the hypervisors resource. See `API Guide / Links and
|
||||||
@ -2986,6 +3038,27 @@ hypervisor_os_diagnostics:
|
|||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
min_version: 2.48
|
min_version: 2.48
|
||||||
|
hypervisor_servers:
|
||||||
|
description: |
|
||||||
|
A list of ``server`` objects.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: array
|
||||||
|
min_version: 2.53
|
||||||
|
hypervisor_servers_name:
|
||||||
|
description: |
|
||||||
|
The server name.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
|
hypervisor_servers_uuid:
|
||||||
|
description: |
|
||||||
|
The server ID.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
min_version: 2.53
|
||||||
hypervisor_service:
|
hypervisor_service:
|
||||||
description: |
|
description: |
|
||||||
The hypervisor service object.
|
The hypervisor service object.
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"status": "enabled",
|
||||||
|
"state": "up",
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "1.1.1.1",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "1bb62a04-c576-402c-8147-9e89757a09e3",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "host1",
|
||||||
|
"id": "62f62f6e-a713-4cbe-87d3-3ecf8a1e0f8d",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hypervisors_links": [
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/hypervisors/detail?limit=1&marker=1bb62a04-c576-402c-8147-9e89757a09e3",
|
||||||
|
"rel": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"state": "up",
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "1.1.1.1",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "host1",
|
||||||
|
"id": "5d343e1d-938e-4284-b98b-6a2b5406ba76",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "1bb62a04-c576-402c-8147-9e89757a09e3",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hypervisors_links": [
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/hypervisors?limit=1&marker=1bb62a04-c576-402c-8147-9e89757a09e3",
|
||||||
|
"rel": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "1.1.1.1",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "043b3cacf6f34c90a7245151fc8ebcda",
|
||||||
|
"id": "5d343e1d-938e-4284-b98b-6a2b5406ba76",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "1.1.1.1",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "043b3cacf6f34c90a7245151fc8ebcda",
|
||||||
|
"id": "5d343e1d-938e-4284-b98b-6a2b5406ba76",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"hypervisor_statistics": {
|
||||||
|
"count": 1,
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"uptime": " 08:32:11 up 93 days, 18:25, 12 users, load average: 0.20, 0.12, 0.14"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -124,9 +124,10 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
|||||||
non-admins can see instance action event details except for the
|
non-admins can see instance action event details except for the
|
||||||
traceback field.
|
traceback field.
|
||||||
* 2.52 - Adds support for applying tags when creating a server.
|
* 2.52 - Adds support for applying tags when creating a server.
|
||||||
* 2.53 - Service database ids are hidden. The os-services API now returns
|
* 2.53 - Service and compute node (hypervisor) database ids are hidden.
|
||||||
a uuid in the id field, and takes a uuid in
|
The os-services and os-hypervisors APIs now return a uuid in the
|
||||||
DELETE /services/{service_uuid}.
|
id field, and takes a uuid in requests. PUT and GET requests
|
||||||
|
and responses are also changed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The minimum and maximum versions of the API supported
|
# The minimum and maximum versions of the API supported
|
||||||
|
@ -17,21 +17,29 @@
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import strutils
|
||||||
|
from oslo_utils import uuidutils
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from nova.api.openstack import api_version_request
|
from nova.api.openstack import api_version_request
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
|
from nova.api.openstack.compute.schemas import hypervisors as hyper_schema
|
||||||
from nova.api.openstack.compute.views import hypervisors as hyper_view
|
from nova.api.openstack.compute.views import hypervisors as hyper_view
|
||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
|
from nova.api import validation
|
||||||
|
from nova.cells import utils as cells_utils
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
from nova.policies import hypervisors as hv_policies
|
from nova.policies import hypervisors as hv_policies
|
||||||
from nova import servicegroup
|
from nova import servicegroup
|
||||||
|
from nova import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
UUID_FOR_ID_MIN_VERSION = '2.53'
|
||||||
|
|
||||||
|
|
||||||
class HypervisorsController(wsgi.Controller):
|
class HypervisorsController(wsgi.Controller):
|
||||||
"""The Hypervisors API controller for the OpenStack API."""
|
"""The Hypervisors API controller for the OpenStack API."""
|
||||||
@ -46,15 +54,18 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
def _view_hypervisor(self, hypervisor, service, detail, req, servers=None,
|
def _view_hypervisor(self, hypervisor, service, detail, req, servers=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
alive = self.servicegroup_api.service_is_up(service)
|
alive = self.servicegroup_api.service_is_up(service)
|
||||||
|
# The 2.53 microversion returns the compute node uuid rather than id.
|
||||||
|
uuid_for_id = api_version_request.is_supported(
|
||||||
|
req, min_version=UUID_FOR_ID_MIN_VERSION)
|
||||||
hyp_dict = {
|
hyp_dict = {
|
||||||
'id': hypervisor.id,
|
'id': hypervisor.uuid if uuid_for_id else hypervisor.id,
|
||||||
'hypervisor_hostname': hypervisor.hypervisor_hostname,
|
'hypervisor_hostname': hypervisor.hypervisor_hostname,
|
||||||
'state': 'up' if alive else 'down',
|
'state': 'up' if alive else 'down',
|
||||||
'status': ('disabled' if service.disabled
|
'status': ('disabled' if service.disabled
|
||||||
else 'enabled'),
|
else 'enabled'),
|
||||||
}
|
}
|
||||||
|
|
||||||
if detail and not servers:
|
if detail:
|
||||||
for field in ('vcpus', 'memory_mb', 'local_gb', 'vcpus_used',
|
for field in ('vcpus', 'memory_mb', 'local_gb', 'vcpus_used',
|
||||||
'memory_mb_used', 'local_gb_used',
|
'memory_mb_used', 'local_gb_used',
|
||||||
'hypervisor_type', 'hypervisor_version',
|
'hypervisor_type', 'hypervisor_version',
|
||||||
@ -62,8 +73,9 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
'running_vms', 'disk_available_least', 'host_ip'):
|
'running_vms', 'disk_available_least', 'host_ip'):
|
||||||
hyp_dict[field] = getattr(hypervisor, field)
|
hyp_dict[field] = getattr(hypervisor, field)
|
||||||
|
|
||||||
|
service_id = service.uuid if uuid_for_id else service.id
|
||||||
hyp_dict['service'] = {
|
hyp_dict['service'] = {
|
||||||
'id': service.id,
|
'id': service_id,
|
||||||
'host': hypervisor.host,
|
'host': hypervisor.host,
|
||||||
'disabled_reason': service.disabled_reason,
|
'disabled_reason': service.disabled_reason,
|
||||||
}
|
}
|
||||||
@ -108,21 +120,58 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(hv_policies.BASE_POLICY_NAME)
|
context.can(hv_policies.BASE_POLICY_NAME)
|
||||||
|
|
||||||
try:
|
# The 2.53 microversion moves the search and servers routes into
|
||||||
compute_nodes = self.host_api.compute_node_get_all(
|
# GET /os-hypervisors and GET /os-hypervisors/detail with query
|
||||||
context, limit=limit, marker=marker)
|
# parameters.
|
||||||
except exception.MarkerNotFound:
|
if api_version_request.is_supported(
|
||||||
msg = _('marker [%s] not found') % marker
|
req, min_version=UUID_FOR_ID_MIN_VERSION):
|
||||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
hypervisor_match = req.GET.get('hypervisor_hostname_pattern')
|
||||||
|
with_servers = strutils.bool_from_string(
|
||||||
|
req.GET.get('with_servers', False), strict=True)
|
||||||
|
else:
|
||||||
|
hypervisor_match = None
|
||||||
|
with_servers = False
|
||||||
|
|
||||||
|
if hypervisor_match is not None:
|
||||||
|
# We have to check for 'limit' in the request itself because
|
||||||
|
# the limit passed in is CONF.api.max_limit by default.
|
||||||
|
if 'limit' in req.GET or marker:
|
||||||
|
# Paging with hostname pattern isn't supported.
|
||||||
|
raise webob.exc.HTTPBadRequest(
|
||||||
|
_('Paging over hypervisors with the '
|
||||||
|
'hypervisor_hostname_pattern query parameter is not '
|
||||||
|
'supported.'))
|
||||||
|
|
||||||
|
# Explicitly do not try to generate links when querying with the
|
||||||
|
# hostname pattern since the request in the link would fail the
|
||||||
|
# check above.
|
||||||
|
links = False
|
||||||
|
|
||||||
|
# Get all compute nodes with a hypervisor_hostname that matches
|
||||||
|
# the given pattern. If none are found then it's a 404 error.
|
||||||
|
compute_nodes = self._get_compute_nodes_by_name_pattern(
|
||||||
|
context, hypervisor_match)
|
||||||
|
else:
|
||||||
|
# Get all compute nodes.
|
||||||
|
try:
|
||||||
|
compute_nodes = self.host_api.compute_node_get_all(
|
||||||
|
context, limit=limit, marker=marker)
|
||||||
|
except exception.MarkerNotFound:
|
||||||
|
msg = _('marker [%s] not found') % marker
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
hypervisors_list = []
|
hypervisors_list = []
|
||||||
for hyp in compute_nodes:
|
for hyp in compute_nodes:
|
||||||
try:
|
try:
|
||||||
|
instances = None
|
||||||
|
if with_servers:
|
||||||
|
instances = self.host_api.instance_get_all_by_host(
|
||||||
|
context, hyp.host)
|
||||||
service = self.host_api.service_get_by_compute_host(
|
service = self.host_api.service_get_by_compute_host(
|
||||||
context, hyp.host)
|
context, hyp.host)
|
||||||
hypervisors_list.append(
|
hypervisors_list.append(
|
||||||
self._view_hypervisor(
|
self._view_hypervisor(
|
||||||
hyp, service, detail, req))
|
hyp, service, detail, req, servers=instances))
|
||||||
except (exception.ComputeHostNotFound,
|
except (exception.ComputeHostNotFound,
|
||||||
exception.HostMappingNotFound):
|
exception.HostMappingNotFound):
|
||||||
# The compute service could be deleted which doesn't delete
|
# The compute service could be deleted which doesn't delete
|
||||||
@ -140,7 +189,21 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
hypervisors_dict['hypervisors_links'] = hypervisors_links
|
hypervisors_dict['hypervisors_links'] = hypervisors_links
|
||||||
return hypervisors_dict
|
return hypervisors_dict
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.33") # noqa
|
@wsgi.Controller.api_version(UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@validation.query_schema(hyper_schema.list_query_schema_v253,
|
||||||
|
UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@extensions.expected_errors((400, 404))
|
||||||
|
def index(self, req):
|
||||||
|
"""Starting with the 2.53 microversion, the id field in the response
|
||||||
|
is the compute_nodes.uuid value. Also, the search and servers routes
|
||||||
|
are superseded and replaced with query parameters for listing
|
||||||
|
hypervisors by a hostname pattern and whether or not to include
|
||||||
|
hosted servers in the response.
|
||||||
|
"""
|
||||||
|
limit, marker = common.get_limit_and_marker(req)
|
||||||
|
return self._index(req, limit=limit, marker=marker, links=True)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.33", "2.52") # noqa
|
||||||
@extensions.expected_errors((400))
|
@extensions.expected_errors((400))
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
limit, marker = common.get_limit_and_marker(req)
|
limit, marker = common.get_limit_and_marker(req)
|
||||||
@ -155,7 +218,21 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
return self._get_hypervisors(req, detail=False, limit=limit,
|
return self._get_hypervisors(req, detail=False, limit=limit,
|
||||||
marker=marker, links=links)
|
marker=marker, links=links)
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.33") # noqa
|
@wsgi.Controller.api_version(UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@validation.query_schema(hyper_schema.list_query_schema_v253,
|
||||||
|
UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@extensions.expected_errors((400, 404))
|
||||||
|
def detail(self, req):
|
||||||
|
"""Starting with the 2.53 microversion, the id field in the response
|
||||||
|
is the compute_nodes.uuid value. Also, the search and servers routes
|
||||||
|
are superseded and replaced with query parameters for listing
|
||||||
|
hypervisors by a hostname pattern and whether or not to include
|
||||||
|
hosted servers in the response.
|
||||||
|
"""
|
||||||
|
limit, marker = common.get_limit_and_marker(req)
|
||||||
|
return self._detail(req, limit=limit, marker=marker, links=True)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.33", "2.52") # noqa
|
||||||
@extensions.expected_errors((400))
|
@extensions.expected_errors((400))
|
||||||
def detail(self, req):
|
def detail(self, req):
|
||||||
limit, marker = common.get_limit_and_marker(req)
|
limit, marker = common.get_limit_and_marker(req)
|
||||||
@ -170,12 +247,69 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
return self._get_hypervisors(req, detail=True, limit=limit,
|
return self._get_hypervisors(req, detail=True, limit=limit,
|
||||||
marker=marker, links=links)
|
marker=marker, links=links)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _validate_id(req, hypervisor_id):
|
||||||
|
"""Validates that the id is a uuid for microversions that require it.
|
||||||
|
|
||||||
|
:param req: The HTTP request object which contains the requested
|
||||||
|
microversion information.
|
||||||
|
:param hypervisor_id: The provided hypervisor id.
|
||||||
|
:raises: webob.exc.HTTPBadRequest if the requested microversion is
|
||||||
|
greater than or equal to 2.53 and the id is not a uuid.
|
||||||
|
:raises: webob.exc.HTTPNotFound if the requested microversion is
|
||||||
|
less than 2.53 and the id is not an integer.
|
||||||
|
"""
|
||||||
|
expect_uuid = api_version_request.is_supported(
|
||||||
|
req, min_version=UUID_FOR_ID_MIN_VERSION)
|
||||||
|
if expect_uuid:
|
||||||
|
if not uuidutils.is_uuid_like(hypervisor_id):
|
||||||
|
msg = _('Invalid uuid %s') % hypervisor_id
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
else:
|
||||||
|
# This API is supported for cells v1 and as such the id can be
|
||||||
|
# a cell v1 delimited string, so we have to parse it first.
|
||||||
|
if cells_utils.CELL_ITEM_SEP in str(hypervisor_id):
|
||||||
|
hypervisor_id = cells_utils.split_cell_and_item(
|
||||||
|
hypervisor_id)[1]
|
||||||
|
try:
|
||||||
|
utils.validate_integer(hypervisor_id, 'id')
|
||||||
|
except exception.InvalidInput:
|
||||||
|
msg = (_("Hypervisor with ID '%s' could not be found.") %
|
||||||
|
hypervisor_id)
|
||||||
|
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version(UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@validation.query_schema(hyper_schema.show_query_schema_v253,
|
||||||
|
UUID_FOR_ID_MIN_VERSION)
|
||||||
|
@extensions.expected_errors((400, 404))
|
||||||
|
def show(self, req, id):
|
||||||
|
"""The 2.53 microversion requires that the id is a uuid and as a result
|
||||||
|
it can also return a 400 response if an invalid uuid is passed.
|
||||||
|
|
||||||
|
The 2.53 microversion also supports the with_servers query parameter
|
||||||
|
to include a list of servers on the given hypervisor if requested.
|
||||||
|
"""
|
||||||
|
with_servers = strutils.bool_from_string(
|
||||||
|
req.GET.get('with_servers', False), strict=True)
|
||||||
|
return self._show(req, id, with_servers)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", "2.52") # noqa F811
|
||||||
@extensions.expected_errors(404)
|
@extensions.expected_errors(404)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
|
return self._show(req, id)
|
||||||
|
|
||||||
|
def _show(self, req, id, with_servers=False):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(hv_policies.BASE_POLICY_NAME)
|
context.can(hv_policies.BASE_POLICY_NAME)
|
||||||
|
|
||||||
|
self._validate_id(req, id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hyp = self.host_api.compute_node_get(context, id)
|
hyp = self.host_api.compute_node_get(context, id)
|
||||||
|
instances = None
|
||||||
|
if with_servers:
|
||||||
|
instances = self.host_api.instance_get_all_by_host(
|
||||||
|
context, hyp.host)
|
||||||
service = self.host_api.service_get_by_compute_host(
|
service = self.host_api.service_get_by_compute_host(
|
||||||
context, hyp.host)
|
context, hyp.host)
|
||||||
except (ValueError, exception.ComputeHostNotFound,
|
except (ValueError, exception.ComputeHostNotFound,
|
||||||
@ -183,12 +317,15 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
msg = _("Hypervisor with ID '%s' could not be found.") % id
|
msg = _("Hypervisor with ID '%s' could not be found.") % id
|
||||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||||
return dict(hypervisor=self._view_hypervisor(
|
return dict(hypervisor=self._view_hypervisor(
|
||||||
hyp, service, True, req))
|
hyp, service, True, req, instances))
|
||||||
|
|
||||||
@extensions.expected_errors((400, 404, 501))
|
@extensions.expected_errors((400, 404, 501))
|
||||||
def uptime(self, req, id):
|
def uptime(self, req, id):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(hv_policies.BASE_POLICY_NAME)
|
context.can(hv_policies.BASE_POLICY_NAME)
|
||||||
|
|
||||||
|
self._validate_id(req, id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hyp = self.host_api.compute_node_get(context, id)
|
hyp = self.host_api.compute_node_get(context, id)
|
||||||
except (ValueError, exception.ComputeHostNotFound):
|
except (ValueError, exception.ComputeHostNotFound):
|
||||||
@ -214,8 +351,14 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
return dict(hypervisor=self._view_hypervisor(hyp, service, False, req,
|
return dict(hypervisor=self._view_hypervisor(hyp, service, False, req,
|
||||||
uptime=uptime))
|
uptime=uptime))
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.1', '2.52')
|
||||||
@extensions.expected_errors(404)
|
@extensions.expected_errors(404)
|
||||||
def search(self, req, id):
|
def search(self, req, id):
|
||||||
|
"""Prior to microversion 2.53 you could search for hypervisors by a
|
||||||
|
hostname pattern on a dedicated route. Starting with 2.53, searching
|
||||||
|
by a hostname pattern is a query parameter in the GET /os-hypervisors
|
||||||
|
index and detail methods.
|
||||||
|
"""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(hv_policies.BASE_POLICY_NAME)
|
context.can(hv_policies.BASE_POLICY_NAME)
|
||||||
hypervisors = self._get_compute_nodes_by_name_pattern(context, id)
|
hypervisors = self._get_compute_nodes_by_name_pattern(context, id)
|
||||||
@ -231,8 +374,15 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
msg = _("No hypervisor matching '%s' could be found.") % id
|
msg = _("No hypervisor matching '%s' could be found.") % id
|
||||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.1', '2.52')
|
||||||
@extensions.expected_errors(404)
|
@extensions.expected_errors(404)
|
||||||
def servers(self, req, id):
|
def servers(self, req, id):
|
||||||
|
"""Prior to microversion 2.53 you could search for hypervisors by a
|
||||||
|
hostname pattern and include servers on those hosts in the response on
|
||||||
|
a dedicated route. Starting with 2.53, searching by a hostname pattern
|
||||||
|
and including hosted servers is a query parameter in the
|
||||||
|
GET /os-hypervisors index and detail methods.
|
||||||
|
"""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(hv_policies.BASE_POLICY_NAME)
|
context.can(hv_policies.BASE_POLICY_NAME)
|
||||||
compute_nodes = self._get_compute_nodes_by_name_pattern(context, id)
|
compute_nodes = self._get_compute_nodes_by_name_pattern(context, id)
|
||||||
|
@ -656,3 +656,30 @@ user documentation.
|
|||||||
|
|
||||||
* ``PUT /os-services/{service_uuid}`` will now return a full service resource
|
* ``PUT /os-services/{service_uuid}`` will now return a full service resource
|
||||||
representation like in a ``GET`` response
|
representation like in a ``GET`` response
|
||||||
|
|
||||||
|
**os-hypervisors**
|
||||||
|
|
||||||
|
Hypervisors are now identified by uuid instead of database id to ensure
|
||||||
|
uniqueness across cells. This microversion brings the following changes:
|
||||||
|
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_hostname_pattern}/search`` is deprecated
|
||||||
|
and replaced with the ``hypervisor_hostname_pattern`` query parameter on
|
||||||
|
the ``GET /os-hypervisors`` and ``GET /os-hypervisors/detail`` APIs.
|
||||||
|
Paging with ``hypervisor_hostname_pattern`` is not supported.
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_hostname_pattern}/servers`` is deprecated
|
||||||
|
and replaced with the ``with_servers`` query parameter on the
|
||||||
|
``GET /os-hypervisors`` and ``GET /os-hypervisors/detail`` APIs.
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_id}`` supports the ``with_servers`` query
|
||||||
|
parameter to include hosted server details in the response.
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_id}`` and
|
||||||
|
``GET /os-hypervisors/{hypervisor_id}/uptime`` APIs now take a uuid value
|
||||||
|
for the ``{hypervisor_id}`` path parameter.
|
||||||
|
* The ``GET /os-hypervisors`` and ``GET /os-hypervisors/detail`` APIs will
|
||||||
|
now use a uuid marker for paging across cells.
|
||||||
|
* The following APIs will now return a uuid value for the hypervisor id and
|
||||||
|
optionally service id fields in the response:
|
||||||
|
|
||||||
|
* ``GET /os-hypervisors``
|
||||||
|
* ``GET /os-hypervisors/detail``
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_id}``
|
||||||
|
* ``GET /os-hypervisors/{hypervisor_id}/uptime``
|
||||||
|
43
nova/api/openstack/compute/schemas/hypervisors.py
Normal file
43
nova/api/openstack/compute/schemas/hypervisors.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from nova.api.validation import parameter_types
|
||||||
|
|
||||||
|
|
||||||
|
list_query_schema_v253 = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
# The 2.33 microversion added support for paging by limit and marker.
|
||||||
|
'limit': parameter_types.single_param(
|
||||||
|
parameter_types.non_negative_integer),
|
||||||
|
'marker': parameter_types.single_param({'type': 'string'}),
|
||||||
|
# The 2.53 microversion adds support for filtering by hostname pattern
|
||||||
|
# and requesting hosted servers in the GET /os-hypervisors and
|
||||||
|
# GET /os-hypervisors/detail response.
|
||||||
|
'hypervisor_hostname_pattern': parameter_types.single_param(
|
||||||
|
parameter_types.hostname),
|
||||||
|
'with_servers': parameter_types.single_param(
|
||||||
|
parameter_types.boolean)
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
|
||||||
|
show_query_schema_v253 = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'with_servers': parameter_types.single_param(
|
||||||
|
parameter_types.boolean)
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
@ -34,7 +34,7 @@ PATH_CELL_SEP = '!'
|
|||||||
# meaningful PATH_CELL_SEP in an invalid way will need to suffice.
|
# meaningful PATH_CELL_SEP in an invalid way will need to suffice.
|
||||||
BLOCK_SYNC_FLAG = '!!'
|
BLOCK_SYNC_FLAG = '!!'
|
||||||
# Separator used between cell name and item
|
# Separator used between cell name and item
|
||||||
_CELL_ITEM_SEP = '@'
|
CELL_ITEM_SEP = '@'
|
||||||
|
|
||||||
CONF = nova.conf.CONF
|
CONF = nova.conf.CONF
|
||||||
|
|
||||||
@ -192,12 +192,12 @@ def cell_with_item(cell_name, item):
|
|||||||
"""Turn cell_name and item into <cell_name>@<item>."""
|
"""Turn cell_name and item into <cell_name>@<item>."""
|
||||||
if cell_name is None:
|
if cell_name is None:
|
||||||
return item
|
return item
|
||||||
return cell_name + _CELL_ITEM_SEP + str(item)
|
return cell_name + CELL_ITEM_SEP + str(item)
|
||||||
|
|
||||||
|
|
||||||
def split_cell_and_item(cell_and_item):
|
def split_cell_and_item(cell_and_item):
|
||||||
"""Split a combined cell@item and return them."""
|
"""Split a combined cell@item and return them."""
|
||||||
result = cell_and_item.rsplit(_CELL_ITEM_SEP, 1)
|
result = cell_and_item.rsplit(CELL_ITEM_SEP, 1)
|
||||||
if len(result) == 1:
|
if len(result) == 1:
|
||||||
return (None, cell_and_item)
|
return (None, cell_and_item)
|
||||||
else:
|
else:
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "%(ip)s",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "%(host_name)s",
|
||||||
|
"id": "%(service_id)s",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hypervisors_links": [
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/hypervisors/detail?limit=1&marker=%(hypervisor_id)s",
|
||||||
|
"rel": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"host_ip": "%(ip)s",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "%(host_name)s",
|
||||||
|
"id": "%(service_id)s",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hypervisors_links": [
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/hypervisors?limit=1&marker=%(hypervisor_id)s",
|
||||||
|
"rel": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"host_ip": "%(ip)s",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "%(host_name)s",
|
||||||
|
"id": "%(service_id)s",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"cpu_info": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"model": "Nehalem",
|
||||||
|
"vendor": "Intel",
|
||||||
|
"features": [
|
||||||
|
"pge",
|
||||||
|
"clflush"
|
||||||
|
],
|
||||||
|
"topology": {
|
||||||
|
"cores": 1,
|
||||||
|
"threads": 1,
|
||||||
|
"sockets": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"host_ip": "%(ip)s",
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"hypervisor_type": "fake",
|
||||||
|
"hypervisor_version": 1000,
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"service": {
|
||||||
|
"host": "%(host_name)s",
|
||||||
|
"id": "%(service_id)s",
|
||||||
|
"disabled_reason": null
|
||||||
|
},
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"hypervisor_statistics": {
|
||||||
|
"count": 1,
|
||||||
|
"current_workload": 0,
|
||||||
|
"disk_available_least": 0,
|
||||||
|
"free_disk_gb": 1028,
|
||||||
|
"free_ram_mb": 7680,
|
||||||
|
"local_gb": 1028,
|
||||||
|
"local_gb_used": 0,
|
||||||
|
"memory_mb": 8192,
|
||||||
|
"memory_mb_used": 512,
|
||||||
|
"running_vms": 0,
|
||||||
|
"vcpus": 1,
|
||||||
|
"vcpus_used": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"hypervisor": {
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"uptime": " 08:32:11 up 93 days, 18:25, 12 users, load average: 0.20, 0.12, 0.14"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"hypervisors": [
|
||||||
|
{
|
||||||
|
"hypervisor_hostname": "fake-mini",
|
||||||
|
"id": "%(hypervisor_id)s",
|
||||||
|
"state": "up",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -169,3 +169,147 @@ class HypervisorsSampleJson233Tests(api_sample_base.ApiSampleTestBaseV21):
|
|||||||
}
|
}
|
||||||
response = self._do_get('os-hypervisors/detail?limit=1&marker=1')
|
response = self._do_get('os-hypervisors/detail?limit=1&marker=1')
|
||||||
self._verify_response('hypervisors-detail-resp', subs, response, 200)
|
self._verify_response('hypervisors-detail-resp', subs, response, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class HypervisorsSampleJson253Tests(HypervisorsSampleJson228Tests):
|
||||||
|
microversion = '2.53'
|
||||||
|
scenarios = [('v2_53', {'api_major_version': 'v2.1'})]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(HypervisorsSampleJson253Tests, self).setUp()
|
||||||
|
self.compute_node_1 = self.compute.service_ref.compute_node
|
||||||
|
|
||||||
|
def generalize_subs(self, subs, vanilla_regexes):
|
||||||
|
"""Give the test a chance to modify subs after the server response
|
||||||
|
was verified, and before the on-disk doc/api_samples file is checked.
|
||||||
|
"""
|
||||||
|
# When comparing the template to the sample we just care that the
|
||||||
|
# hypervisor id and service id are UUIDs.
|
||||||
|
subs['hypervisor_id'] = vanilla_regexes['uuid']
|
||||||
|
subs['service_id'] = vanilla_regexes['uuid']
|
||||||
|
return subs
|
||||||
|
|
||||||
|
def test_hypervisors_list(self):
|
||||||
|
# Start another compute service to get a 2nd compute for paging tests.
|
||||||
|
compute_node_2 = self.start_service(
|
||||||
|
'compute', host='host2').service_ref.compute_node
|
||||||
|
marker = self.compute_node_1.uuid
|
||||||
|
response = self._do_get('os-hypervisors?limit=1&marker=%s' % marker)
|
||||||
|
subs = {'hypervisor_id': compute_node_2.uuid}
|
||||||
|
self._verify_response('hypervisors-list-resp', subs, response, 200)
|
||||||
|
|
||||||
|
def test_hypervisors_detail(self):
|
||||||
|
# Start another compute service to get a 2nd compute for paging tests.
|
||||||
|
service_2 = self.start_service('compute', host='host2').service_ref
|
||||||
|
compute_node_2 = service_2.compute_node
|
||||||
|
marker = self.compute_node_1.uuid
|
||||||
|
subs = {
|
||||||
|
'hypervisor_id': compute_node_2.uuid,
|
||||||
|
'service_id': service_2.uuid
|
||||||
|
}
|
||||||
|
response = self._do_get('os-hypervisors/detail?limit=1&marker=%s' %
|
||||||
|
marker)
|
||||||
|
self._verify_response('hypervisors-detail-resp', subs, response, 200)
|
||||||
|
|
||||||
|
@mock.patch("nova.compute.api.HostAPI.instance_get_all_by_host")
|
||||||
|
def test_hypervisors_detail_with_servers(self, instance_get_all_by_host):
|
||||||
|
"""List hypervisors with details and with hosted servers."""
|
||||||
|
instances = [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}]
|
||||||
|
instance_get_all_by_host.return_value = instances
|
||||||
|
response = self._do_get('os-hypervisors/detail?with_servers=1')
|
||||||
|
subs = {
|
||||||
|
'hypervisor_id': self.compute_node_1.uuid,
|
||||||
|
'service_id': self.compute.service_ref.uuid,
|
||||||
|
}
|
||||||
|
self._verify_response('hypervisors-detail-with-servers-resp',
|
||||||
|
subs, response, 200)
|
||||||
|
|
||||||
|
def test_hypervisors_search(self):
|
||||||
|
"""The search route is deprecated in 2.53 and is now a query parameter
|
||||||
|
on the GET /os-hypervisors API.
|
||||||
|
"""
|
||||||
|
response = self._do_get(
|
||||||
|
'os-hypervisors?hypervisor_hostname_pattern=fake')
|
||||||
|
subs = {'hypervisor_id': self.compute_node_1.uuid}
|
||||||
|
self._verify_response('hypervisors-search-resp', subs, response, 200)
|
||||||
|
|
||||||
|
@mock.patch("nova.compute.api.HostAPI.instance_get_all_by_host")
|
||||||
|
def test_hypervisors_with_servers(self, instance_get_all_by_host):
|
||||||
|
"""The servers route is deprecated in 2.53 and is now a query parameter
|
||||||
|
on the GET /os-hypervisors API.
|
||||||
|
"""
|
||||||
|
instances = [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}]
|
||||||
|
instance_get_all_by_host.return_value = instances
|
||||||
|
response = self._do_get('os-hypervisors?with_servers=true')
|
||||||
|
subs = {'hypervisor_id': self.compute_node_1.uuid}
|
||||||
|
self._verify_response('hypervisors-with-servers-resp', subs,
|
||||||
|
response, 200)
|
||||||
|
|
||||||
|
def test_hypervisors_without_servers(self):
|
||||||
|
# This is the same as GET /os-hypervisors in 2.53 which is covered by
|
||||||
|
# test_hypervisors_list already.
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_hypervisors_uptime(self):
|
||||||
|
def fake_get_host_uptime(self, context, hyp):
|
||||||
|
return (" 08:32:11 up 93 days, 18:25, 12 users, load average:"
|
||||||
|
" 0.20, 0.12, 0.14")
|
||||||
|
|
||||||
|
self.stub_out('nova.compute.api.HostAPI.get_host_uptime',
|
||||||
|
fake_get_host_uptime)
|
||||||
|
hypervisor_id = self.compute_node_1.uuid
|
||||||
|
response = self._do_get('os-hypervisors/%s/uptime' % hypervisor_id)
|
||||||
|
subs = {
|
||||||
|
'hypervisor_id': hypervisor_id,
|
||||||
|
}
|
||||||
|
self._verify_response('hypervisors-uptime-resp', subs, response, 200)
|
||||||
|
|
||||||
|
def test_hypervisors_show(self):
|
||||||
|
hypervisor_id = self.compute_node_1.uuid
|
||||||
|
subs = {
|
||||||
|
'hypervisor_id': hypervisor_id,
|
||||||
|
'service_id': self.compute.service_ref.uuid,
|
||||||
|
}
|
||||||
|
response = self._do_get('os-hypervisors/%s' % hypervisor_id)
|
||||||
|
self._verify_response('hypervisors-show-resp', subs, response, 200)
|
||||||
|
|
||||||
|
@mock.patch("nova.compute.api.HostAPI.instance_get_all_by_host")
|
||||||
|
def test_hypervisors_show_with_servers(self, instance_get_all_by_host):
|
||||||
|
"""Tests getting details for a specific hypervisor and including the
|
||||||
|
hosted servers in the response.
|
||||||
|
"""
|
||||||
|
instances = [
|
||||||
|
{
|
||||||
|
"name": "test_server1",
|
||||||
|
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_server2",
|
||||||
|
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||||
|
}]
|
||||||
|
instance_get_all_by_host.return_value = instances
|
||||||
|
hypervisor_id = self.compute_node_1.uuid
|
||||||
|
subs = {
|
||||||
|
'hypervisor_id': hypervisor_id,
|
||||||
|
'service_id': self.compute.service_ref.uuid,
|
||||||
|
}
|
||||||
|
response = self._do_get('os-hypervisors/%s?with_servers=1' %
|
||||||
|
hypervisor_id)
|
||||||
|
self._verify_response('hypervisors-show-with-servers-resp', subs,
|
||||||
|
response, 200)
|
||||||
|
@ -48,6 +48,8 @@ class ExtendedHypervisorsTestV21(test.NoDBTestCase):
|
|||||||
del DETAIL_HYPERS_DICTS[1]['service_id']
|
del DETAIL_HYPERS_DICTS[1]['service_id']
|
||||||
del DETAIL_HYPERS_DICTS[0]['host']
|
del DETAIL_HYPERS_DICTS[0]['host']
|
||||||
del DETAIL_HYPERS_DICTS[1]['host']
|
del DETAIL_HYPERS_DICTS[1]['host']
|
||||||
|
del DETAIL_HYPERS_DICTS[0]['uuid']
|
||||||
|
del DETAIL_HYPERS_DICTS[1]['uuid']
|
||||||
DETAIL_HYPERS_DICTS[0].update({'state': 'up',
|
DETAIL_HYPERS_DICTS[0].update({'state': 'up',
|
||||||
'status': 'enabled',
|
'status': 'enabled',
|
||||||
'service': dict(id=1, host='compute1',
|
'service': dict(id=1, host='compute1',
|
||||||
|
@ -18,6 +18,7 @@ import copy
|
|||||||
import mock
|
import mock
|
||||||
import netaddr
|
import netaddr
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
import six
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack.compute import hypervisors \
|
from nova.api.openstack.compute import hypervisors \
|
||||||
@ -39,6 +40,7 @@ CPU_INFO = """
|
|||||||
|
|
||||||
TEST_HYPERS = [
|
TEST_HYPERS = [
|
||||||
dict(id=1,
|
dict(id=1,
|
||||||
|
uuid=uuids.hyper1,
|
||||||
service_id=1,
|
service_id=1,
|
||||||
host="compute1",
|
host="compute1",
|
||||||
vcpus=4,
|
vcpus=4,
|
||||||
@ -58,6 +60,7 @@ TEST_HYPERS = [
|
|||||||
disk_available_least=100,
|
disk_available_least=100,
|
||||||
host_ip=netaddr.IPAddress('1.1.1.1')),
|
host_ip=netaddr.IPAddress('1.1.1.1')),
|
||||||
dict(id=2,
|
dict(id=2,
|
||||||
|
uuid=uuids.hyper2,
|
||||||
service_id=2,
|
service_id=2,
|
||||||
host="compute2",
|
host="compute2",
|
||||||
vcpus=4,
|
vcpus=4,
|
||||||
@ -80,6 +83,7 @@ TEST_HYPERS = [
|
|||||||
|
|
||||||
TEST_SERVICES = [
|
TEST_SERVICES = [
|
||||||
objects.Service(id=1,
|
objects.Service(id=1,
|
||||||
|
uuid=uuids.service1,
|
||||||
host="compute1",
|
host="compute1",
|
||||||
binary="nova-compute",
|
binary="nova-compute",
|
||||||
topic="compute_topic",
|
topic="compute_topic",
|
||||||
@ -88,6 +92,7 @@ TEST_SERVICES = [
|
|||||||
disabled_reason=None,
|
disabled_reason=None,
|
||||||
availability_zone="nova"),
|
availability_zone="nova"),
|
||||||
objects.Service(id=2,
|
objects.Service(id=2,
|
||||||
|
uuid=uuids.service2,
|
||||||
host="compute2",
|
host="compute2",
|
||||||
binary="nova-compute",
|
binary="nova-compute",
|
||||||
topic="compute_topic",
|
topic="compute_topic",
|
||||||
@ -110,12 +115,13 @@ TEST_SERVERS = [dict(name="inst1", uuid=uuids.instance_1, host="compute1"),
|
|||||||
|
|
||||||
|
|
||||||
def fake_compute_node_get_all(context, limit=None, marker=None):
|
def fake_compute_node_get_all(context, limit=None, marker=None):
|
||||||
if marker in ['99999']:
|
if marker in ['99999', uuids.invalid_marker]:
|
||||||
raise exception.MarkerNotFound(marker)
|
raise exception.MarkerNotFound(marker)
|
||||||
marker_found = True if marker is None else False
|
marker_found = True if marker is None else False
|
||||||
output = []
|
output = []
|
||||||
for hyper in TEST_HYPERS_OBJ:
|
for hyper in TEST_HYPERS_OBJ:
|
||||||
if not marker_found and marker == str(hyper.id):
|
# Starting with the 2.53 microversion, the marker is a uuid.
|
||||||
|
if not marker_found and marker in (str(hyper.id), hyper.uuid):
|
||||||
marker_found = True
|
marker_found = True
|
||||||
elif marker_found:
|
elif marker_found:
|
||||||
if limit is None or len(output) < int(limit):
|
if limit is None or len(output) < int(limit):
|
||||||
@ -129,7 +135,7 @@ def fake_compute_node_search_by_hypervisor(context, hypervisor_re):
|
|||||||
|
|
||||||
def fake_compute_node_get(context, compute_id):
|
def fake_compute_node_get(context, compute_id):
|
||||||
for hyper in TEST_HYPERS_OBJ:
|
for hyper in TEST_HYPERS_OBJ:
|
||||||
if hyper.id == int(compute_id):
|
if hyper.uuid == compute_id or hyper.id == int(compute_id):
|
||||||
return hyper
|
return hyper
|
||||||
raise exception.ComputeHostNotFound(host=compute_id)
|
raise exception.ComputeHostNotFound(host=compute_id)
|
||||||
|
|
||||||
@ -177,6 +183,9 @@ def fake_instance_get_all_by_host(context, host):
|
|||||||
|
|
||||||
class HypervisorsTestV21(test.NoDBTestCase):
|
class HypervisorsTestV21(test.NoDBTestCase):
|
||||||
api_version = '2.1'
|
api_version = '2.1'
|
||||||
|
# Allow subclasses to override if the id value in the response is the
|
||||||
|
# compute node primary key integer id or the uuid.
|
||||||
|
expect_uuid_for_id = False
|
||||||
|
|
||||||
# copying the objects locally so the cells testcases can provide their own
|
# copying the objects locally so the cells testcases can provide their own
|
||||||
TEST_HYPERS_OBJ = copy.deepcopy(TEST_HYPERS_OBJ)
|
TEST_HYPERS_OBJ = copy.deepcopy(TEST_HYPERS_OBJ)
|
||||||
@ -188,6 +197,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
del DETAIL_HYPERS_DICTS[1]['service_id']
|
del DETAIL_HYPERS_DICTS[1]['service_id']
|
||||||
del DETAIL_HYPERS_DICTS[0]['host']
|
del DETAIL_HYPERS_DICTS[0]['host']
|
||||||
del DETAIL_HYPERS_DICTS[1]['host']
|
del DETAIL_HYPERS_DICTS[1]['host']
|
||||||
|
del DETAIL_HYPERS_DICTS[0]['uuid']
|
||||||
|
del DETAIL_HYPERS_DICTS[1]['uuid']
|
||||||
DETAIL_HYPERS_DICTS[0].update({'state': 'up',
|
DETAIL_HYPERS_DICTS[0].update({'state': 'up',
|
||||||
'status': 'enabled',
|
'status': 'enabled',
|
||||||
'service': dict(id=1, host='compute1',
|
'service': dict(id=1, host='compute1',
|
||||||
@ -213,6 +224,15 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
self.controller.servicegroup_api.service_is_up = mock.MagicMock(
|
self.controller.servicegroup_api.service_is_up = mock.MagicMock(
|
||||||
return_value=True)
|
return_value=True)
|
||||||
|
|
||||||
|
def _get_hyper_id(self):
|
||||||
|
"""Helper function to get the proper hypervisor id for a request
|
||||||
|
|
||||||
|
:returns: The first hypervisor's uuid for microversions that expect a
|
||||||
|
uuid for the id, otherwise the hypervisor's id primary key
|
||||||
|
"""
|
||||||
|
return (self.TEST_HYPERS_OBJ[0].uuid if self.expect_uuid_for_id
|
||||||
|
else self.TEST_HYPERS_OBJ[0].id)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(HypervisorsTestV21, self).setUp()
|
super(HypervisorsTestV21, self).setUp()
|
||||||
self._set_up_controller()
|
self._set_up_controller()
|
||||||
@ -317,7 +337,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
result = self.controller.index(req)
|
result = self.controller.index(req)
|
||||||
self.assertEqual(1, len(result['hypervisors']))
|
self.assertEqual(1, len(result['hypervisors']))
|
||||||
expected = {
|
expected = {
|
||||||
'id': compute_nodes[0].id,
|
'id': compute_nodes[0].uuid if self.expect_uuid_for_id
|
||||||
|
else compute_nodes[0].id,
|
||||||
'hypervisor_hostname': compute_nodes[0].hypervisor_hostname,
|
'hypervisor_hostname': compute_nodes[0].hypervisor_hostname,
|
||||||
'state': 'up',
|
'state': 'up',
|
||||||
'status': 'enabled',
|
'status': 'enabled',
|
||||||
@ -350,7 +371,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
result = self.controller.index(req)
|
result = self.controller.index(req)
|
||||||
self.assertEqual(1, len(result['hypervisors']))
|
self.assertEqual(1, len(result['hypervisors']))
|
||||||
expected = {
|
expected = {
|
||||||
'id': compute_nodes[0].id,
|
'id': compute_nodes[0].uuid if self.expect_uuid_for_id
|
||||||
|
else compute_nodes[0].id,
|
||||||
'hypervisor_hostname': compute_nodes[0].hypervisor_hostname,
|
'hypervisor_hostname': compute_nodes[0].hypervisor_hostname,
|
||||||
'state': 'up',
|
'state': 'up',
|
||||||
'status': 'enabled',
|
'status': 'enabled',
|
||||||
@ -461,31 +483,25 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
don't fail when listing hypervisors.
|
don't fail when listing hypervisors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# two computes, a matching service only exists for the first one
|
|
||||||
compute_nodes = objects.ComputeNodeList(objects=[
|
|
||||||
objects.ComputeNode(**TEST_HYPERS[0]),
|
|
||||||
objects.ComputeNode(**TEST_HYPERS[1])
|
|
||||||
])
|
|
||||||
|
|
||||||
def fake_service_get_by_compute_host(context, host):
|
|
||||||
return TEST_SERVICES[0]
|
|
||||||
|
|
||||||
@mock.patch.object(self.controller.host_api, 'compute_node_get',
|
@mock.patch.object(self.controller.host_api, 'compute_node_get',
|
||||||
fake_service_get_by_compute_host)
|
return_value=self.TEST_HYPERS_OBJ[0])
|
||||||
@mock.patch.object(self.controller.host_api,
|
@mock.patch.object(self.controller.host_api,
|
||||||
'service_get_by_compute_host')
|
'service_get_by_compute_host')
|
||||||
def _test(self, mock_service):
|
def _test(self, mock_service, mock_compute_node_get):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
mock_service.side_effect = exception.HostMappingNotFound(
|
mock_service.side_effect = exception.HostMappingNotFound(
|
||||||
name='foo')
|
name='foo')
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
self.assertRaises(exc.HTTPNotFound, self.controller.show,
|
self.assertRaises(exc.HTTPNotFound, self.controller.show,
|
||||||
req, compute_nodes[0].id)
|
req, hyper_id)
|
||||||
self.assertTrue(mock_service.called)
|
self.assertTrue(mock_service.called)
|
||||||
|
mock_compute_node_get.assert_called_once_with(mock.ANY, hyper_id)
|
||||||
_test(self)
|
_test(self)
|
||||||
|
|
||||||
def test_show_noid(self):
|
def test_show_noid(self):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
self.assertRaises(exc.HTTPNotFound, self.controller.show, req, '3')
|
hyperid = uuids.hyper3 if self.expect_uuid_for_id else '3'
|
||||||
|
self.assertRaises(exc.HTTPNotFound, self.controller.show, req, hyperid)
|
||||||
|
|
||||||
def test_show_non_integer_id(self):
|
def test_show_non_integer_id(self):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
@ -493,7 +509,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
|
|
||||||
def test_show_withid(self):
|
def test_show_withid(self):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
result = self.controller.show(req, self.TEST_HYPERS_OBJ[0].id)
|
hyper_id = self._get_hyper_id()
|
||||||
|
result = self.controller.show(req, hyper_id)
|
||||||
|
|
||||||
self.assertEqual(dict(hypervisor=self.DETAIL_HYPERS_DICTS[0]), result)
|
self.assertEqual(dict(hypervisor=self.DETAIL_HYPERS_DICTS[0]), result)
|
||||||
|
|
||||||
@ -501,20 +518,22 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
req = self._get_request(False)
|
req = self._get_request(False)
|
||||||
self.assertRaises(exception.PolicyNotAuthorized,
|
self.assertRaises(exception.PolicyNotAuthorized,
|
||||||
self.controller.show, req,
|
self.controller.show, req,
|
||||||
self.TEST_HYPERS_OBJ[0].id)
|
self._get_hyper_id())
|
||||||
|
|
||||||
def test_uptime_noid(self):
|
def test_uptime_noid(self):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
self.assertRaises(exc.HTTPNotFound, self.controller.uptime, req, '3')
|
hyper_id = uuids.hyper3 if self.expect_uuid_for_id else '3'
|
||||||
|
self.assertRaises(exc.HTTPNotFound, self.controller.uptime, req,
|
||||||
|
hyper_id)
|
||||||
|
|
||||||
def test_uptime_notimplemented(self):
|
def test_uptime_notimplemented(self):
|
||||||
with mock.patch.object(self.controller.host_api, 'get_host_uptime',
|
with mock.patch.object(self.controller.host_api, 'get_host_uptime',
|
||||||
side_effect=exc.HTTPNotImplemented()
|
side_effect=exc.HTTPNotImplemented()
|
||||||
) as mock_get_uptime:
|
) as mock_get_uptime:
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
self.assertRaises(exc.HTTPNotImplemented,
|
self.assertRaises(exc.HTTPNotImplemented,
|
||||||
self.controller.uptime, req,
|
self.controller.uptime, req, hyper_id)
|
||||||
self.TEST_HYPERS_OBJ[0].id)
|
|
||||||
self.assertEqual(1, mock_get_uptime.call_count)
|
self.assertEqual(1, mock_get_uptime.call_count)
|
||||||
|
|
||||||
def test_uptime_implemented(self):
|
def test_uptime_implemented(self):
|
||||||
@ -522,7 +541,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
return_value="fake uptime"
|
return_value="fake uptime"
|
||||||
) as mock_get_uptime:
|
) as mock_get_uptime:
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
result = self.controller.uptime(req, self.TEST_HYPERS_OBJ[0].id)
|
hyper_id = self._get_hyper_id()
|
||||||
|
result = self.controller.uptime(req, hyper_id)
|
||||||
|
|
||||||
expected_dict = copy.deepcopy(self.INDEX_HYPER_DICTS[0])
|
expected_dict = copy.deepcopy(self.INDEX_HYPER_DICTS[0])
|
||||||
expected_dict.update({'uptime': "fake uptime"})
|
expected_dict.update({'uptime': "fake uptime"})
|
||||||
@ -544,9 +564,9 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
side_effect=exception.ComputeServiceUnavailable(host='dummy')
|
side_effect=exception.ComputeServiceUnavailable(host='dummy')
|
||||||
) as mock_get_uptime:
|
) as mock_get_uptime:
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
self.assertRaises(exc.HTTPBadRequest,
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
self.controller.uptime, req,
|
self.controller.uptime, req, hyper_id)
|
||||||
self.TEST_HYPERS_OBJ[0].id)
|
|
||||||
mock_get_uptime.assert_called_once_with(
|
mock_get_uptime.assert_called_once_with(
|
||||||
mock.ANY, self.TEST_HYPERS_OBJ[0].host)
|
mock.ANY, self.TEST_HYPERS_OBJ[0].host)
|
||||||
|
|
||||||
@ -559,9 +579,9 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
name='dummy'))
|
name='dummy'))
|
||||||
def _test(mock_get, _, __):
|
def _test(mock_get, _, __):
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
self.assertRaises(exc.HTTPNotFound,
|
self.assertRaises(exc.HTTPNotFound,
|
||||||
self.controller.uptime, req,
|
self.controller.uptime, req, hyper_id)
|
||||||
self.TEST_HYPERS_OBJ[0].id)
|
|
||||||
self.assertTrue(mock_get.called)
|
self.assertTrue(mock_get.called)
|
||||||
|
|
||||||
_test()
|
_test()
|
||||||
@ -571,9 +591,9 @@ class HypervisorsTestV21(test.NoDBTestCase):
|
|||||||
side_effect=exception.HostMappingNotFound(name='dummy')
|
side_effect=exception.HostMappingNotFound(name='dummy')
|
||||||
) as mock_get_uptime:
|
) as mock_get_uptime:
|
||||||
req = self._get_request(True)
|
req = self._get_request(True)
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
self.assertRaises(exc.HTTPNotFound,
|
self.assertRaises(exc.HTTPNotFound,
|
||||||
self.controller.uptime, req,
|
self.controller.uptime, req, hyper_id)
|
||||||
self.TEST_HYPERS_OBJ[0].id)
|
|
||||||
mock_get_uptime.assert_called_once_with(
|
mock_get_uptime.assert_called_once_with(
|
||||||
mock.ANY, self.TEST_HYPERS_OBJ[0].host)
|
mock.ANY, self.TEST_HYPERS_OBJ[0].host)
|
||||||
|
|
||||||
@ -872,3 +892,398 @@ class HypervisorsTestV233(HypervisorsTestV228):
|
|||||||
'/v2/1234/os-hypervisors/detail?marker=99999')
|
'/v2/1234/os-hypervisors/detail?marker=99999')
|
||||||
self.assertRaises(exc.HTTPBadRequest,
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
self.controller.detail, req)
|
self.controller.detail, req)
|
||||||
|
|
||||||
|
|
||||||
|
class HypervisorsTestV252(HypervisorsTestV233):
|
||||||
|
"""This is a boundary test to make sure 2.52 works like 2.33."""
|
||||||
|
api_version = '2.52'
|
||||||
|
|
||||||
|
|
||||||
|
class HypervisorsTestV253(HypervisorsTestV252):
|
||||||
|
api_version = hypervisors_v21.UUID_FOR_ID_MIN_VERSION
|
||||||
|
expect_uuid_for_id = True
|
||||||
|
|
||||||
|
# This is an expected response for index().
|
||||||
|
INDEX_HYPER_DICTS = [
|
||||||
|
dict(id=uuids.hyper1, hypervisor_hostname="hyper1",
|
||||||
|
state='up', status='enabled'),
|
||||||
|
dict(id=uuids.hyper2, hypervisor_hostname="hyper2",
|
||||||
|
state='up', status='enabled')]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(HypervisorsTestV253, self).setUp()
|
||||||
|
# This is an expected response for detail().
|
||||||
|
for index, detail_hyper_dict in enumerate(self.DETAIL_HYPERS_DICTS):
|
||||||
|
detail_hyper_dict['id'] = TEST_HYPERS[index]['uuid']
|
||||||
|
detail_hyper_dict['service']['id'] = TEST_SERVICES[index].uuid
|
||||||
|
|
||||||
|
def test_servers(self):
|
||||||
|
"""Asserts that calling the servers route after 2.48 fails."""
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.servers,
|
||||||
|
self._get_request(True), 'hyper')
|
||||||
|
|
||||||
|
def test_servers_with_no_server(self):
|
||||||
|
"""Tests GET /os-hypervisors?with_servers=1 when there are no
|
||||||
|
instances on the given host.
|
||||||
|
"""
|
||||||
|
with mock.patch.object(self.controller.host_api,
|
||||||
|
'instance_get_all_by_host',
|
||||||
|
return_value=[]) as mock_inst_get_all:
|
||||||
|
req = self._get_request(use_admin_context=True,
|
||||||
|
url='/os-hypervisors?with_servers=1')
|
||||||
|
result = self.controller.index(req)
|
||||||
|
self.assertEqual(dict(hypervisors=self.INDEX_HYPER_DICTS), result)
|
||||||
|
# instance_get_all_by_host is called for each hypervisor
|
||||||
|
self.assertEqual(2, mock_inst_get_all.call_count)
|
||||||
|
mock_inst_get_all.assert_has_calls((
|
||||||
|
mock.call(req.environ['nova.context'], TEST_HYPERS_OBJ[0].host),
|
||||||
|
mock.call(req.environ['nova.context'], TEST_HYPERS_OBJ[1].host)))
|
||||||
|
|
||||||
|
def test_servers_not_mapped(self):
|
||||||
|
"""Tests that instance_get_all_by_host fails with HostMappingNotFound.
|
||||||
|
"""
|
||||||
|
req = self._get_request(use_admin_context=True,
|
||||||
|
url='/os-hypervisors?with_servers=1')
|
||||||
|
with mock.patch.object(
|
||||||
|
self.controller.host_api, 'instance_get_all_by_host',
|
||||||
|
side_effect=exception.HostMappingNotFound(name='something')):
|
||||||
|
result = self.controller.index(req)
|
||||||
|
self.assertEqual(dict(hypervisors=[]), result)
|
||||||
|
|
||||||
|
def test_list_with_servers(self):
|
||||||
|
"""Tests GET /os-hypervisors?with_servers=True"""
|
||||||
|
instances = [
|
||||||
|
objects.InstanceList(objects=[objects.Instance(
|
||||||
|
id=1, uuid=uuids.hyper1_instance1)]),
|
||||||
|
objects.InstanceList(objects=[objects.Instance(
|
||||||
|
id=2, uuid=uuids.hyper2_instance1)])]
|
||||||
|
with mock.patch.object(self.controller.host_api,
|
||||||
|
'instance_get_all_by_host',
|
||||||
|
side_effect=instances) as mock_inst_get_all:
|
||||||
|
req = self._get_request(use_admin_context=True,
|
||||||
|
url='/os-hypervisors?with_servers=True')
|
||||||
|
result = self.controller.index(req)
|
||||||
|
index_with_servers = copy.deepcopy(self.INDEX_HYPER_DICTS)
|
||||||
|
index_with_servers[0]['servers'] = [
|
||||||
|
{'name': 'instance-00000001', 'uuid': uuids.hyper1_instance1}]
|
||||||
|
index_with_servers[1]['servers'] = [
|
||||||
|
{'name': 'instance-00000002', 'uuid': uuids.hyper2_instance1}]
|
||||||
|
self.assertEqual(dict(hypervisors=index_with_servers), result)
|
||||||
|
# instance_get_all_by_host is called for each hypervisor
|
||||||
|
self.assertEqual(2, mock_inst_get_all.call_count)
|
||||||
|
mock_inst_get_all.assert_has_calls((
|
||||||
|
mock.call(req.environ['nova.context'], TEST_HYPERS_OBJ[0].host),
|
||||||
|
mock.call(req.environ['nova.context'], TEST_HYPERS_OBJ[1].host)))
|
||||||
|
|
||||||
|
def test_list_with_servers_invalid_parameter(self):
|
||||||
|
"""Tests using an invalid with_servers query parameter."""
|
||||||
|
req = self._get_request(use_admin_context=True,
|
||||||
|
url='/os-hypervisors?with_servers=invalid')
|
||||||
|
self.assertRaises(
|
||||||
|
exception.ValidationError, self.controller.index, req)
|
||||||
|
|
||||||
|
def test_list_with_hostname_pattern_and_paging_parameters(self):
|
||||||
|
"""This is a negative test to validate that trying to list hypervisors
|
||||||
|
with a hostname pattern and paging parameters results in a 400 error.
|
||||||
|
"""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?hypervisor_hostname_pattern=foo&'
|
||||||
|
'limit=1&marker=%s' % uuids.marker)
|
||||||
|
ex = self.assertRaises(exc.HTTPBadRequest, self.controller.index, req)
|
||||||
|
self.assertIn('Paging over hypervisors with the '
|
||||||
|
'hypervisor_hostname_pattern query parameter is not '
|
||||||
|
'supported.', six.text_type(ex))
|
||||||
|
|
||||||
|
def test_servers_with_non_integer_hypervisor_id(self):
|
||||||
|
"""This is a poorly named test, it's really checking the 404 case where
|
||||||
|
there is no match for the hostname pattern.
|
||||||
|
"""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?with_servers=yes&'
|
||||||
|
'hypervisor_hostname_pattern=shenzhen')
|
||||||
|
with mock.patch.object(self.controller.host_api,
|
||||||
|
'compute_node_search_by_hypervisor',
|
||||||
|
return_value=objects.ComputeNodeList()) as s:
|
||||||
|
self.assertRaises(exc.HTTPNotFound, self.controller.index, req)
|
||||||
|
s.assert_called_once_with(req.environ['nova.context'], 'shenzhen')
|
||||||
|
|
||||||
|
def test_servers_non_admin(self):
|
||||||
|
"""There is no reason to test this for 2.53 since the
|
||||||
|
/os-hypervisors/servers route is deprecated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_servers_non_id(self):
|
||||||
|
"""There is no reason to test this for 2.53 since the
|
||||||
|
/os-hypervisors/servers route is deprecated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_search_old_route(self):
|
||||||
|
"""Asserts that calling the search route after 2.48 fails."""
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.search,
|
||||||
|
self._get_request(True), 'hyper')
|
||||||
|
|
||||||
|
def test_search(self):
|
||||||
|
"""Test listing hypervisors with details and using the
|
||||||
|
hypervisor_hostname_pattern query string.
|
||||||
|
"""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?hypervisor_hostname_pattern=shenzhen')
|
||||||
|
with mock.patch.object(self.controller.host_api,
|
||||||
|
'compute_node_search_by_hypervisor',
|
||||||
|
return_value=objects.ComputeNodeList(
|
||||||
|
objects=[TEST_HYPERS_OBJ[0]])) as s:
|
||||||
|
result = self.controller.detail(req)
|
||||||
|
s.assert_called_once_with(req.environ['nova.context'], 'shenzhen')
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'hypervisors': [
|
||||||
|
{'cpu_info': {'arch': 'x86_64',
|
||||||
|
'features': [],
|
||||||
|
'model': '',
|
||||||
|
'topology': {'cores': 1,
|
||||||
|
'sockets': 1,
|
||||||
|
'threads': 1},
|
||||||
|
'vendor': 'fake'},
|
||||||
|
'current_workload': 2,
|
||||||
|
'disk_available_least': 100,
|
||||||
|
'free_disk_gb': 125,
|
||||||
|
'free_ram_mb': 5120,
|
||||||
|
'host_ip': netaddr.IPAddress('1.1.1.1'),
|
||||||
|
'hypervisor_hostname': 'hyper1',
|
||||||
|
'hypervisor_type': 'xen',
|
||||||
|
'hypervisor_version': 3,
|
||||||
|
'id': TEST_HYPERS_OBJ[0].uuid,
|
||||||
|
'local_gb': 250,
|
||||||
|
'local_gb_used': 125,
|
||||||
|
'memory_mb': 10240,
|
||||||
|
'memory_mb_used': 5120,
|
||||||
|
'running_vms': 2,
|
||||||
|
'service': {'disabled_reason': None,
|
||||||
|
'host': 'compute1',
|
||||||
|
'id': TEST_SERVICES[0].uuid},
|
||||||
|
'state': 'up',
|
||||||
|
'status': 'enabled',
|
||||||
|
'vcpus': 4,
|
||||||
|
'vcpus_used': 2}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
# There are no links when using the hypervisor_hostname_pattern
|
||||||
|
# query string since we can't page using a pattern matcher.
|
||||||
|
self.assertNotIn('hypervisors_links', result)
|
||||||
|
self.assertDictEqual(expected, result)
|
||||||
|
|
||||||
|
def test_search_invalid_hostname_pattern_parameter(self):
|
||||||
|
"""Tests passing an invalid hypervisor_hostname_pattern query
|
||||||
|
parameter.
|
||||||
|
"""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?hypervisor_hostname_pattern=invalid~host')
|
||||||
|
self.assertRaises(
|
||||||
|
exception.ValidationError, self.controller.detail, req)
|
||||||
|
|
||||||
|
def test_search_non_exist(self):
|
||||||
|
"""This is a duplicate of test_servers_with_non_integer_hypervisor_id.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_search_non_admin(self):
|
||||||
|
"""There is no reason to test this for 2.53 since the
|
||||||
|
/os-hypervisors/search route is deprecated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_search_unmapped(self):
|
||||||
|
"""This is already tested with test_index_compute_host_not_mapped."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_show_non_integer_id(self):
|
||||||
|
"""There is no reason to test this for 2.53 since 2.53 requires a
|
||||||
|
non-integer id (requires a uuid).
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_show_integer_id(self):
|
||||||
|
"""Tests that we get a 400 if passed a hypervisor integer id to show().
|
||||||
|
"""
|
||||||
|
req = self._get_request(True)
|
||||||
|
ex = self.assertRaises(exc.HTTPBadRequest,
|
||||||
|
self.controller.show, req, '1')
|
||||||
|
self.assertIn('Invalid uuid 1', six.text_type(ex))
|
||||||
|
|
||||||
|
def test_show_with_servers_invalid_parameter(self):
|
||||||
|
"""Tests passing an invalid value for the with_servers query parameter
|
||||||
|
to the show() method to make sure the query parameter is validated.
|
||||||
|
"""
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/%s?with_servers=invalid' % hyper_id)
|
||||||
|
ex = self.assertRaises(
|
||||||
|
exception.ValidationError, self.controller.show, req, hyper_id)
|
||||||
|
self.assertIn('with_servers', six.text_type(ex))
|
||||||
|
|
||||||
|
def test_show_with_servers_host_mapping_not_found(self):
|
||||||
|
"""Tests that a 404 is returned if instance_get_all_by_host raises
|
||||||
|
HostMappingNotFound.
|
||||||
|
"""
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/%s?with_servers=true' % hyper_id)
|
||||||
|
with mock.patch.object(
|
||||||
|
self.controller.host_api, 'instance_get_all_by_host',
|
||||||
|
side_effect=exception.HostMappingNotFound(name=hyper_id)):
|
||||||
|
self.assertRaises(exc.HTTPNotFound, self.controller.show,
|
||||||
|
req, hyper_id)
|
||||||
|
|
||||||
|
def test_show_with_servers(self):
|
||||||
|
"""Tests the show() result when servers are included in the output."""
|
||||||
|
instances = objects.InstanceList(objects=[objects.Instance(
|
||||||
|
id=1, uuid=uuids.hyper1_instance1)])
|
||||||
|
hyper_id = self._get_hyper_id()
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/%s?with_servers=on' % hyper_id)
|
||||||
|
with mock.patch.object(self.controller.host_api,
|
||||||
|
'instance_get_all_by_host',
|
||||||
|
return_value=instances) as mock_inst_get_all:
|
||||||
|
result = self.controller.show(req, hyper_id)
|
||||||
|
show_with_servers = copy.deepcopy(self.DETAIL_HYPERS_DICTS[0])
|
||||||
|
show_with_servers['servers'] = [
|
||||||
|
{'name': 'instance-00000001', 'uuid': uuids.hyper1_instance1}]
|
||||||
|
self.assertDictEqual(dict(hypervisor=show_with_servers), result)
|
||||||
|
# instance_get_all_by_host is called
|
||||||
|
mock_inst_get_all.assert_called_once_with(
|
||||||
|
req.environ['nova.context'], TEST_HYPERS_OBJ[0].host)
|
||||||
|
|
||||||
|
def test_uptime_non_integer_id(self):
|
||||||
|
"""There is no reason to test this for 2.53 since 2.53 requires a
|
||||||
|
non-integer id (requires a uuid).
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_uptime_integer_id(self):
|
||||||
|
"""Tests that we get a 400 if passed a hypervisor integer id to
|
||||||
|
uptime().
|
||||||
|
"""
|
||||||
|
req = self._get_request(True)
|
||||||
|
ex = self.assertRaises(exc.HTTPBadRequest,
|
||||||
|
self.controller.uptime, req, '1')
|
||||||
|
self.assertIn('Invalid uuid 1', six.text_type(ex))
|
||||||
|
|
||||||
|
def test_detail_pagination(self):
|
||||||
|
"""Tests details paging with uuid markers."""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/detail?limit=1&marker=%s' %
|
||||||
|
TEST_HYPERS_OBJ[0].uuid)
|
||||||
|
result = self.controller.detail(req)
|
||||||
|
link = ('http://localhost/v2/hypervisors/detail?limit=1&marker=%s' %
|
||||||
|
TEST_HYPERS_OBJ[1].uuid)
|
||||||
|
expected = {
|
||||||
|
'hypervisors': [
|
||||||
|
{'cpu_info': {'arch': 'x86_64',
|
||||||
|
'features': [],
|
||||||
|
'model': '',
|
||||||
|
'topology': {'cores': 1,
|
||||||
|
'sockets': 1,
|
||||||
|
'threads': 1},
|
||||||
|
'vendor': 'fake'},
|
||||||
|
'current_workload': 2,
|
||||||
|
'disk_available_least': 100,
|
||||||
|
'free_disk_gb': 125,
|
||||||
|
'free_ram_mb': 5120,
|
||||||
|
'host_ip': netaddr.IPAddress('2.2.2.2'),
|
||||||
|
'hypervisor_hostname': 'hyper2',
|
||||||
|
'hypervisor_type': 'xen',
|
||||||
|
'hypervisor_version': 3,
|
||||||
|
'id': TEST_HYPERS_OBJ[1].uuid,
|
||||||
|
'local_gb': 250,
|
||||||
|
'local_gb_used': 125,
|
||||||
|
'memory_mb': 10240,
|
||||||
|
'memory_mb_used': 5120,
|
||||||
|
'running_vms': 2,
|
||||||
|
'service': {'disabled_reason': None,
|
||||||
|
'host': 'compute2',
|
||||||
|
'id': TEST_SERVICES[1].uuid},
|
||||||
|
'state': 'up',
|
||||||
|
'status': 'enabled',
|
||||||
|
'vcpus': 4,
|
||||||
|
'vcpus_used': 2}
|
||||||
|
],
|
||||||
|
'hypervisors_links': [{'href': link, 'rel': 'next'}]
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_detail_pagination_with_invalid_marker(self):
|
||||||
|
"""Tests detail paging with an invalid marker (not found)."""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/detail?marker=%s' % uuids.invalid_marker)
|
||||||
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
|
self.controller.detail, req)
|
||||||
|
|
||||||
|
def test_index_pagination(self):
|
||||||
|
"""Tests index paging with uuid markers."""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?limit=1&marker=%s' %
|
||||||
|
TEST_HYPERS_OBJ[0].uuid)
|
||||||
|
result = self.controller.index(req)
|
||||||
|
link = ('http://localhost/v2/hypervisors?limit=1&marker=%s' %
|
||||||
|
TEST_HYPERS_OBJ[1].uuid)
|
||||||
|
expected = {
|
||||||
|
'hypervisors': [{
|
||||||
|
'hypervisor_hostname': 'hyper2',
|
||||||
|
'id': TEST_HYPERS_OBJ[1].uuid,
|
||||||
|
'state': 'up',
|
||||||
|
'status': 'enabled'
|
||||||
|
}],
|
||||||
|
'hypervisors_links': [{'href': link, 'rel': 'next'}]
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_index_pagination_with_invalid_marker(self):
|
||||||
|
"""Tests index paging with an invalid marker (not found)."""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?marker=%s' % uuids.invalid_marker)
|
||||||
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
|
self.controller.index, req)
|
||||||
|
|
||||||
|
def test_list_duplicate_query_parameters_validation(self):
|
||||||
|
"""Tests that the list query parameter schema enforces only a single
|
||||||
|
entry for any query parameter.
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
'limit': 1,
|
||||||
|
'marker': uuids.marker,
|
||||||
|
'hypervisor_hostname_pattern': 'foo',
|
||||||
|
'with_servers': 'true'
|
||||||
|
}
|
||||||
|
for param, value in params.items():
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors?%s=%s&%s=%s' %
|
||||||
|
(param, value, param, value))
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller.index, req)
|
||||||
|
|
||||||
|
def test_show_duplicate_query_parameters_validation(self):
|
||||||
|
"""Tests that the show query parameter schema enforces only a single
|
||||||
|
entry for any query parameter.
|
||||||
|
"""
|
||||||
|
req = self._get_request(
|
||||||
|
use_admin_context=True,
|
||||||
|
url='/os-hypervisors/%s?with_servers=1&with_servers=1' %
|
||||||
|
uuids.hyper1)
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller.show, req, uuids.hyper1)
|
||||||
|
@ -147,7 +147,7 @@ class CellsUtilsTestCase(test.NoDBTestCase):
|
|||||||
cell = cells_utils.PATH_CELL_SEP.join(path)
|
cell = cells_utils.PATH_CELL_SEP.join(path)
|
||||||
item = 'host_5'
|
item = 'host_5'
|
||||||
together = cells_utils.cell_with_item(cell, item)
|
together = cells_utils.cell_with_item(cell, item)
|
||||||
self.assertEqual(cells_utils._CELL_ITEM_SEP.join([cell, item]),
|
self.assertEqual(cells_utils.CELL_ITEM_SEP.join([cell, item]),
|
||||||
together)
|
together)
|
||||||
|
|
||||||
# Test normal usage
|
# Test normal usage
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
features:
|
features:
|
||||||
- |
|
- |
|
||||||
Microversion 2.53 changes service IDs to UUIDs to ensure uniqueness across
|
Microversion 2.53 changes service and hypervisor IDs to UUIDs to ensure
|
||||||
cells. Prior to this, ID collisions were possible in multi-cell
|
uniqueness across cells. Prior to this, ID collisions were possible in
|
||||||
deployments. See the `REST API Version History`_ and
|
multi-cell deployments. See the `REST API Version History`_ and
|
||||||
`Compute API reference`_ for details.
|
`Compute API reference`_ for details.
|
||||||
|
|
||||||
.. _REST API Version History: https://docs.openstack.org/developer/nova/api_microversion_history.html
|
.. _REST API Version History: https://docs.openstack.org/developer/nova/api_microversion_history.html
|
||||||
|
Loading…
x
Reference in New Issue
Block a user