Merge "api: Add response body schemas for hypervisors APIs (2/3)"
This commit is contained in:
@@ -255,6 +255,11 @@ class HypervisorsController(wsgi.Controller):
|
||||
@validation.query_schema(schema.index_query, '2.1', '2.32')
|
||||
@validation.query_schema(schema.index_query_v233, '2.33', '2.52')
|
||||
@validation.query_schema(schema.index_query_v253, '2.53')
|
||||
@validation.response_body_schema(schema.detail_response, '2.1', '2.26')
|
||||
@validation.response_body_schema(schema.detail_response_v227, '2.27', '2.32') # noqa: E501
|
||||
@validation.response_body_schema(schema.detail_response_v233, '2.33', '2.52') # noqa: E501
|
||||
@validation.response_body_schema(schema.detail_response_v253, '2.53', '2.87') # noqa: E501
|
||||
@validation.response_body_schema(schema.detail_response_v288, '2.88')
|
||||
def detail(self, req):
|
||||
"""List hypervisors with extra details.
|
||||
|
||||
@@ -307,6 +312,10 @@ class HypervisorsController(wsgi.Controller):
|
||||
@wsgi.expected_errors((400, 404), '2.53')
|
||||
@validation.query_schema(schema.show_query, '2.1', '2.52')
|
||||
@validation.query_schema(schema.show_query_v253, '2.53')
|
||||
@validation.response_body_schema(schema.show_response, '2.1', '2.26')
|
||||
@validation.response_body_schema(schema.show_response_v227, '2.27', '2.52')
|
||||
@validation.response_body_schema(schema.show_response_v253, '2.53', '2.87')
|
||||
@validation.response_body_schema(schema.show_response_v288, '2.88')
|
||||
def show(self, req, id):
|
||||
"""Show a hypervisor.
|
||||
|
||||
@@ -365,6 +374,8 @@ class HypervisorsController(wsgi.Controller):
|
||||
@wsgi.api_version('2.1', '2.87')
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.query_schema(schema.uptime_query)
|
||||
@validation.response_body_schema(schema.uptime_response, '2.1', '2.52')
|
||||
@validation.response_body_schema(schema.uptime_response_v253, '2.53', '2.87') # noqa: E501
|
||||
def uptime(self, req, id):
|
||||
"""Prior to microversion 2.88, you could retrieve a special version of
|
||||
the hypervisor detail view that included uptime. Starting in 2.88, this
|
||||
|
||||
@@ -104,6 +104,95 @@ _hypervisor_response_v253['properties'].update({
|
||||
'servers': copy.deepcopy(_servers_response),
|
||||
})
|
||||
|
||||
_hypervisor_detail_response = copy.deepcopy(_hypervisor_response)
|
||||
_hypervisor_detail_response['properties'].update({
|
||||
'cpu_info': {'type': 'string'},
|
||||
'current_workload': {'type': 'integer'},
|
||||
'disk_available_least': {'type': 'integer'},
|
||||
'free_disk_gb': {'type': 'integer'},
|
||||
'free_ram_mb': {'type': 'integer'},
|
||||
'host_ip': {'type': 'string'},
|
||||
'hypervisor_type': {'type': 'string'},
|
||||
'hypervisor_version': {'type': ['string', 'integer']},
|
||||
'local_gb': {'type': 'integer'},
|
||||
'local_gb_used': {'type': 'integer'},
|
||||
'memory_mb': {'type': 'integer'},
|
||||
'memory_mb_used': {'type': 'integer'},
|
||||
'running_vms': {'type': 'integer'},
|
||||
'service': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'disabled_reason': {'type': ['null', 'string']},
|
||||
'host': {'type': 'string'},
|
||||
'id': {'type': 'integer'},
|
||||
},
|
||||
'required': ['disabled_reason', 'host', 'id'],
|
||||
},
|
||||
'vcpus': {'type': 'integer'},
|
||||
'vcpus_used': {'type': 'integer'},
|
||||
})
|
||||
_hypervisor_detail_response['required'].extend([
|
||||
'cpu_info',
|
||||
'current_workload',
|
||||
'free_disk_gb',
|
||||
'free_ram_mb',
|
||||
'local_gb',
|
||||
'local_gb_used',
|
||||
'memory_mb',
|
||||
'memory_mb_used',
|
||||
'running_vms',
|
||||
'service',
|
||||
'vcpus',
|
||||
'vcpus_used',
|
||||
])
|
||||
|
||||
_hypervisor_detail_response_v227 = copy.deepcopy(_hypervisor_detail_response)
|
||||
_hypervisor_detail_response_v227['properties'].update({
|
||||
'cpu_info': {
|
||||
# NOTE(stephenfin): This is virt-driver specific hence no schema
|
||||
'type': 'object',
|
||||
'properties': {},
|
||||
'required': [],
|
||||
'additionalProperties': True,
|
||||
},
|
||||
})
|
||||
|
||||
_hypervisor_detail_response_v253 = copy.deepcopy(
|
||||
_hypervisor_detail_response_v227
|
||||
)
|
||||
_hypervisor_detail_response_v253['properties'].update(
|
||||
_hypervisor_response_v253['properties']
|
||||
)
|
||||
_hypervisor_detail_response_v253['properties']['service'][
|
||||
'properties'
|
||||
].update({
|
||||
'id': {'type': 'string', 'format': 'uuid'},
|
||||
})
|
||||
|
||||
_hypervisor_detail_response_v288 = copy.deepcopy(
|
||||
_hypervisor_detail_response_v253
|
||||
)
|
||||
for field in {
|
||||
'cpu_info',
|
||||
'current_workload',
|
||||
'free_disk_gb',
|
||||
'free_ram_mb',
|
||||
'local_gb',
|
||||
'local_gb_used',
|
||||
'memory_mb',
|
||||
'memory_mb_used',
|
||||
'running_vms',
|
||||
'vcpus',
|
||||
'vcpus_used',
|
||||
}:
|
||||
del _hypervisor_detail_response_v288['properties'][field]
|
||||
_hypervisor_detail_response_v288['required'].remove(field)
|
||||
|
||||
_hypervisor_detail_response_v288['properties'].update({
|
||||
'uptime': {'type': ['string', 'null']}
|
||||
})
|
||||
_hypervisor_detail_response_v288['required'].append('uptime')
|
||||
|
||||
index_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
@@ -137,3 +226,82 @@ servers_response = copy.deepcopy(index_response)
|
||||
servers_response['properties']['hypervisors']['items']['properties'].update({
|
||||
'servers': copy.deepcopy(_servers_response),
|
||||
})
|
||||
|
||||
detail_response = copy.deepcopy(index_response)
|
||||
detail_response['properties']['hypervisors'][
|
||||
'items'
|
||||
] = _hypervisor_detail_response
|
||||
|
||||
# v2.27 changes the 'cpu_info' field from a stringified object to a real object
|
||||
detail_response_v227 = copy.deepcopy(detail_response)
|
||||
detail_response_v227['properties']['hypervisors'][
|
||||
'items'
|
||||
] = _hypervisor_detail_response_v227
|
||||
|
||||
# v2.33 adds the hypervisors_links field
|
||||
detail_response_v233 = copy.deepcopy(detail_response_v227)
|
||||
detail_response_v233['properties'].update({
|
||||
'hypervisors_links': response_types.collection_links,
|
||||
})
|
||||
|
||||
# v2.53 adds the 'servers' field but only if a user requests it via the
|
||||
# 'with_servers' query arg. It also changes the 'id' field to a UUID. Note that
|
||||
# v2.75 makes the 'servers' property always present even if empty, but that's
|
||||
# not something we can capture with jsonschema so we don't try
|
||||
detail_response_v253 = copy.deepcopy(detail_response_v233)
|
||||
detail_response_v253['properties']['hypervisors'][
|
||||
'items'
|
||||
] = _hypervisor_detail_response_v253
|
||||
|
||||
# v2.88 drops a whole lot of fields that were now duplicated in placement. It
|
||||
# also adds the uptime field into the response rather than a separate API
|
||||
detail_response_v288 = copy.deepcopy(detail_response_v253)
|
||||
detail_response_v288['properties']['hypervisors'][
|
||||
'items'
|
||||
] = _hypervisor_detail_response_v288
|
||||
|
||||
show_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'hypervisor': copy.deepcopy(_hypervisor_detail_response),
|
||||
},
|
||||
'required': ['hypervisor'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
show_response_v227 = copy.deepcopy(show_response)
|
||||
show_response_v227['properties']['hypervisor'] = copy.deepcopy(
|
||||
_hypervisor_detail_response_v227
|
||||
)
|
||||
|
||||
show_response_v253 = copy.deepcopy(show_response_v227)
|
||||
show_response_v253['properties']['hypervisor'] = copy.deepcopy(
|
||||
_hypervisor_detail_response_v253
|
||||
)
|
||||
|
||||
show_response_v288 = copy.deepcopy(show_response_v253)
|
||||
show_response_v288['properties']['hypervisor'] = copy.deepcopy(
|
||||
_hypervisor_detail_response_v288
|
||||
)
|
||||
|
||||
uptime_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'hypervisor': copy.deepcopy(_hypervisor_response),
|
||||
},
|
||||
'required': ['hypervisor'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
uptime_response['properties']['hypervisor']['properties'].update({
|
||||
'uptime': {'type': ['string', 'null']}
|
||||
})
|
||||
uptime_response['properties']['hypervisor']['required'].append('uptime')
|
||||
|
||||
uptime_response_v253 = copy.deepcopy(uptime_response)
|
||||
uptime_response_v253['properties']['hypervisor'] = copy.deepcopy(
|
||||
_hypervisor_response_v253
|
||||
)
|
||||
uptime_response_v253['properties']['hypervisor']['properties'].update({
|
||||
'uptime': {'type': ['string', 'null']}
|
||||
})
|
||||
uptime_response_v253['properties']['hypervisor']['required'].append('uptime')
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
from unittest import mock
|
||||
|
||||
from nova.api.openstack.compute import hypervisors
|
||||
from nova import objects
|
||||
from nova.policies import base as base_policy
|
||||
from nova.policies import hypervisors as hv_policies
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
@@ -33,8 +35,43 @@ class HypervisorsPolicyTest(base.BasePolicyTest):
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
self.controller._get_compute_nodes_by_name_pattern = mock.MagicMock()
|
||||
self.controller.host_api.compute_node_get_all = mock.MagicMock()
|
||||
self.controller.host_api.service_get_by_compute_host = mock.MagicMock()
|
||||
self.controller.host_api.compute_node_get = mock.MagicMock()
|
||||
self.controller.host_api.service_get_by_compute_host = mock.MagicMock(
|
||||
return_value=objects.Service(
|
||||
id=123,
|
||||
binary='nova-compute',
|
||||
created_at=datetime.datetime(2012, 9, 18, 2, 46, 27),
|
||||
disabled=False,
|
||||
disabled_reason=None,
|
||||
forced_down=False,
|
||||
host='foo',
|
||||
last_seen_up=None,
|
||||
)
|
||||
)
|
||||
self.controller.host_api.compute_node_get = mock.MagicMock(
|
||||
return_value=objects.ComputeNode(
|
||||
id=123,
|
||||
cpu_info='{}',
|
||||
current_workload=1,
|
||||
disk_available_least=10,
|
||||
free_disk_gb=50,
|
||||
free_ram_mb=512,
|
||||
host='foo',
|
||||
host_ip='1.2.3.4',
|
||||
hypervisor_hostname='foo',
|
||||
hypervisor_type='libvirt',
|
||||
hypervisor_version='123',
|
||||
local_gb=1000,
|
||||
local_gb_used=10,
|
||||
memory_mb=8192,
|
||||
memory_mb_used=1024,
|
||||
running_vms=1,
|
||||
vcpus=16,
|
||||
vcpus_used=8,
|
||||
),
|
||||
)
|
||||
self.controller.host_api.get_host_uptime = mock.MagicMock(
|
||||
return_value=None
|
||||
)
|
||||
|
||||
# With legacy rule and scope check disabled by default, system admin,
|
||||
# legacy admin, and project admin will be able to perform hypervisors
|
||||
@@ -59,26 +96,26 @@ class HypervisorsPolicyTest(base.BasePolicyTest):
|
||||
rule_name = hv_policies.BASE_POLICY_NAME % 'show'
|
||||
self.common_policy_auth(self.project_admin_authorized_contexts,
|
||||
rule_name, self.controller.show,
|
||||
self.req, 11111)
|
||||
self.req, '123')
|
||||
|
||||
@mock.patch('nova.compute.api.HostAPI.get_host_uptime')
|
||||
def test_uptime_hypervisors_policy(self, mock_uptime):
|
||||
rule_name = hv_policies.BASE_POLICY_NAME % 'uptime'
|
||||
self.common_policy_auth(self.project_admin_authorized_contexts,
|
||||
rule_name, self.controller.uptime,
|
||||
self.req, 11111)
|
||||
self.req, '123')
|
||||
|
||||
def test_search_hypervisors_policy(self):
|
||||
rule_name = hv_policies.BASE_POLICY_NAME % 'search'
|
||||
self.common_policy_auth(self.project_admin_authorized_contexts,
|
||||
rule_name, self.controller.search,
|
||||
self.req, 11111)
|
||||
self.req, '123')
|
||||
|
||||
def test_servers_hypervisors_policy(self):
|
||||
rule_name = hv_policies.BASE_POLICY_NAME % 'servers'
|
||||
self.common_policy_auth(self.project_admin_authorized_contexts,
|
||||
rule_name, self.controller.servers,
|
||||
self.req, 11111)
|
||||
self.req, '123')
|
||||
|
||||
@mock.patch('nova.compute.api.HostAPI.compute_node_statistics')
|
||||
def test_statistics_hypervisors_policy(self, mock_statistics):
|
||||
|
||||
Reference in New Issue
Block a user