api: Add response body schemas for hosts APIs

Change-Id: I9b045e9d8d344f2cd8caf7fcbd45f0d8b610da04
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane
2024-08-27 23:44:19 +01:00
parent 4520a058c8
commit f7a03e5834
3 changed files with 110 additions and 14 deletions
+14 -7
View File
@@ -19,7 +19,7 @@ from oslo_log import log as logging
import webob.exc
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import hosts
from nova.api.openstack.compute.schemas import hosts as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova.compute import api as compute
@@ -31,6 +31,7 @@ from nova.policies import hosts as hosts_policies
LOG = logging.getLogger(__name__)
@validation.validated
class HostController(wsgi.Controller):
"""The Hosts API controller for the OpenStack API."""
@@ -39,8 +40,9 @@ class HostController(wsgi.Controller):
self.api = compute.HostAPI()
@wsgi.api_version("2.1", "2.42")
@validation.query_schema(hosts.index_query)
@wsgi.expected_errors(())
@validation.query_schema(schema.index_query)
@validation.response_body_schema(schema.index_response)
def index(self, req):
"""Returns a dict in the format
@@ -90,7 +92,8 @@ class HostController(wsgi.Controller):
@wsgi.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
@validation.schema(hosts.update)
@validation.schema(schema.update)
@validation.response_body_schema(schema.update_response)
def update(self, req, id, body):
"""Return booleanized version of body dict.
@@ -182,7 +185,8 @@ class HostController(wsgi.Controller):
@wsgi.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
@validation.query_schema(hosts.startup_query)
@validation.query_schema(schema.startup_query)
@validation.response_body_schema(schema.startup_response)
def startup(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'start',
@@ -191,7 +195,8 @@ class HostController(wsgi.Controller):
@wsgi.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
@validation.query_schema(hosts.shutdown_query)
@validation.query_schema(schema.shutdown_query)
@validation.response_body_schema(schema.shutdown_response)
def shutdown(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'shutdown',
@@ -200,7 +205,8 @@ class HostController(wsgi.Controller):
@wsgi.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
@validation.query_schema(hosts.reboot_query)
@validation.query_schema(schema.reboot_query)
@validation.response_body_schema(schema.reboot_response)
def reboot(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'reboot',
@@ -258,7 +264,8 @@ class HostController(wsgi.Controller):
@wsgi.api_version("2.1", "2.42")
@wsgi.expected_errors(404)
@validation.query_schema(hosts.show_query)
@validation.query_schema(schema.show_query)
@validation.response_body_schema(schema.show_response)
def show(self, req, id):
"""Shows the physical/usage resource given by hosts.
@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
from nova.api.validation import parameter_types
update = {
@@ -55,3 +57,84 @@ startup_query = {}
shutdown_query = {}
reboot_query = {}
show_query = {}
index_response = {
'type': 'object',
'properties': {
'hosts': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'host_name': {'type': 'string'},
# TODO(stephenfin): This should be an enum
'service': {'type': 'string'},
'zone': {'type': 'string'},
},
'required': ['host_name', 'service', 'zone'],
'additionalProperties': False,
},
},
},
'required': ['hosts'],
'additionalProperties': False,
}
show_response = {
'type': 'object',
'properties': {
'host': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'resource': {
'type': 'object',
'properties': {
'cpu': {'type': 'integer'},
'disk_gb': {'type': 'integer'},
'host': {'type': 'string'},
'memory_mb': {'type': 'integer'},
'project': {'type': 'string'},
},
'required': [
'cpu', 'disk_gb', 'host', 'memory_mb', 'project'
],
'additionalProperties': False,
},
},
'required': ['resource'],
'additionalProperties': False,
},
},
},
'required': ['host'],
'additionalProperties': False,
}
update_response = {
'type': 'object',
'properties': {
'host': {'type': 'string'},
'maintenance_mode': {'enum': ['on_maintenance', 'off_maintenance']},
'status': {'enum': ['enabled', 'disabled']},
},
'required': ['host'],
'additionalProperties': False,
}
_power_action_response = {
'type': 'object',
'properties': {
'host': {'type': 'string'},
# NOTE(stephenfin): This is virt driver specific and the API is
# deprecated, so this is left empty
'power_action': {},
},
'required': ['host', 'power_action'],
'additionalProperties': False,
}
startup_response = copy.deepcopy(_power_action_response)
shutdown_response = copy.deepcopy(_power_action_response)
reboot_response = copy.deepcopy(_power_action_response)
+13 -7
View File
@@ -13,6 +13,7 @@
from unittest import mock
from nova.api.openstack.compute import hosts
from nova import objects
from nova.policies import base as base_policy
from nova.policies import hosts as policies
from nova.tests.unit.api.openstack import fakes
@@ -48,14 +49,18 @@ class HostsPolicyTest(base.BasePolicyTest):
@mock.patch('nova.context.set_target_cell')
@mock.patch('nova.objects.HostMapping.get_by_host')
@mock.patch('nova.objects.ComputeNode.'
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.objects.ComputeNode.get_first_node_by_host_for_old_compat') # noqa: E501
@mock.patch('nova.compute.api.HostAPI.instance_get_all_by_host')
def test_show_host_policy(self, mock_get, mock_node, mock_map, mock_set):
mock_get.return_value = []
mock_node.return_value = objects.ComputeNode(
vcpus=16, memory_mb=8192, local_gb=1000,
vcpus_used=4, memory_mb_used=1024, local_gb_used=10,
)
rule_name = policies.POLICY_NAME % 'show'
self.common_policy_auth(self.project_admin_authorized_contexts,
rule_name, self.controller.show,
self.req, 11111)
self.req, 'hostname')
@mock.patch('nova.compute.api.HostAPI.set_host_enabled')
def test_update_host_policy(self, mock_set_host_enabled):
@@ -63,28 +68,29 @@ class HostsPolicyTest(base.BasePolicyTest):
rule_name = policies.POLICY_NAME % 'update'
self.common_policy_auth(self.project_admin_authorized_contexts,
rule_name, self.controller.update,
self.req, 11111, body={'status': 'enable'})
self.req, 'hostname',
body={'status': 'enable'})
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_reboot_host_policy(self, mock_action):
rule_name = policies.POLICY_NAME % 'reboot'
self.common_policy_auth(self.project_admin_authorized_contexts,
rule_name, self.controller.reboot,
self.req, 11111)
self.req, 'hostname')
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_shutdown_host_policy(self, mock_action):
rule_name = policies.POLICY_NAME % 'shutdown'
self.common_policy_auth(self.project_admin_authorized_contexts,
rule_name, self.controller.shutdown,
self.req, 11111)
self.req, 'hostname')
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_startup_host_policy(self, mock_action):
rule_name = policies.POLICY_NAME % 'start'
self.common_policy_auth(self.project_admin_authorized_contexts,
rule_name, self.controller.startup,
self.req, 11111)
self.req, 'hostname')
class HostsNoLegacyNoScopePolicyTest(HostsPolicyTest):