api: Add response body schemas for hosts APIs
Change-Id: I9b045e9d8d344f2cd8caf7fcbd45f0d8b610da04 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -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,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):
|
||||
|
||||
Reference in New Issue
Block a user