Merge "Check microversions before validations for allocations and deploy templates"
This commit is contained in:
commit
5614d251bb
@ -16,6 +16,7 @@ from ironic_lib import metrics_utils
|
|||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import pecan
|
import pecan
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
|
from webob import exc as webob_exc
|
||||||
import wsme
|
import wsme
|
||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
|
|
||||||
@ -200,6 +201,13 @@ class AllocationsController(pecan.rest.RestController):
|
|||||||
|
|
||||||
invalid_sort_key_list = ['extra', 'candidate_nodes', 'traits']
|
invalid_sort_key_list = ['extra', 'candidate_nodes', 'traits']
|
||||||
|
|
||||||
|
@pecan.expose()
|
||||||
|
def _route(self, args, request=None):
|
||||||
|
if not api_utils.allow_allocations():
|
||||||
|
raise webob_exc.HTTPNotFound(_(
|
||||||
|
"The API version does not allow allocations"))
|
||||||
|
return super(AllocationsController, self)._route(args, request)
|
||||||
|
|
||||||
def _get_allocations_collection(self, node_ident=None, resource_class=None,
|
def _get_allocations_collection(self, node_ident=None, resource_class=None,
|
||||||
state=None, marker=None, limit=None,
|
state=None, marker=None, limit=None,
|
||||||
sort_key='id', sort_dir='asc',
|
sort_key='id', sort_dir='asc',
|
||||||
@ -282,9 +290,6 @@ class AllocationsController(pecan.rest.RestController):
|
|||||||
:param fields: Optional, a list with a specified set of fields
|
:param fields: Optional, a list with a specified set of fields
|
||||||
of the resource to be returned.
|
of the resource to be returned.
|
||||||
"""
|
"""
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
cdict = pecan.request.context.to_policy_values()
|
cdict = pecan.request.context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
||||||
|
|
||||||
@ -302,9 +307,6 @@ class AllocationsController(pecan.rest.RestController):
|
|||||||
:param fields: Optional, a list with a specified set of fields
|
:param fields: Optional, a list with a specified set of fields
|
||||||
of the resource to be returned.
|
of the resource to be returned.
|
||||||
"""
|
"""
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
cdict = pecan.request.context.to_policy_values()
|
cdict = pecan.request.context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
||||||
|
|
||||||
@ -320,9 +322,6 @@ class AllocationsController(pecan.rest.RestController):
|
|||||||
|
|
||||||
:param allocation: an allocation within the request body.
|
:param allocation: an allocation within the request body.
|
||||||
"""
|
"""
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
cdict = context.to_policy_values()
|
cdict = context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:create', cdict, cdict)
|
policy.authorize('baremetal:allocation:create', cdict, cdict)
|
||||||
@ -383,9 +382,6 @@ class AllocationsController(pecan.rest.RestController):
|
|||||||
|
|
||||||
:param allocation_ident: UUID or logical name of an allocation.
|
:param allocation_ident: UUID or logical name of an allocation.
|
||||||
"""
|
"""
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
cdict = context.to_policy_values()
|
cdict = context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:delete', cdict, cdict)
|
policy.authorize('baremetal:allocation:delete', cdict, cdict)
|
||||||
@ -414,6 +410,13 @@ class NodeAllocationController(pecan.rest.RestController):
|
|||||||
|
|
||||||
invalid_sort_key_list = ['extra', 'candidate_nodes', 'traits']
|
invalid_sort_key_list = ['extra', 'candidate_nodes', 'traits']
|
||||||
|
|
||||||
|
@pecan.expose()
|
||||||
|
def _route(self, args, request=None):
|
||||||
|
if not api_utils.allow_allocations():
|
||||||
|
raise webob_exc.HTTPNotFound(_(
|
||||||
|
"The API version does not allow allocations"))
|
||||||
|
return super(NodeAllocationController, self)._route(args, request)
|
||||||
|
|
||||||
def __init__(self, node_ident):
|
def __init__(self, node_ident):
|
||||||
super(NodeAllocationController, self).__init__()
|
super(NodeAllocationController, self).__init__()
|
||||||
self.parent_node_ident = node_ident
|
self.parent_node_ident = node_ident
|
||||||
@ -422,9 +425,6 @@ class NodeAllocationController(pecan.rest.RestController):
|
|||||||
@METRICS.timer('NodeAllocationController.get_all')
|
@METRICS.timer('NodeAllocationController.get_all')
|
||||||
@expose.expose(Allocation, types.listtype)
|
@expose.expose(Allocation, types.listtype)
|
||||||
def get_all(self, fields=None):
|
def get_all(self, fields=None):
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
cdict = pecan.request.context.to_policy_values()
|
cdict = pecan.request.context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
policy.authorize('baremetal:allocation:get', cdict, cdict)
|
||||||
|
|
||||||
@ -440,9 +440,6 @@ class NodeAllocationController(pecan.rest.RestController):
|
|||||||
@METRICS.timer('NodeAllocationController.delete')
|
@METRICS.timer('NodeAllocationController.delete')
|
||||||
@expose.expose(None, status_code=http_client.NO_CONTENT)
|
@expose.expose(None, status_code=http_client.NO_CONTENT)
|
||||||
def delete(self):
|
def delete(self):
|
||||||
if not api_utils.allow_allocations():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
cdict = context.to_policy_values()
|
cdict = context.to_policy_values()
|
||||||
policy.authorize('baremetal:allocation:delete', cdict, cdict)
|
policy.authorize('baremetal:allocation:delete', cdict, cdict)
|
||||||
|
@ -20,6 +20,7 @@ from oslo_utils import uuidutils
|
|||||||
import pecan
|
import pecan
|
||||||
from pecan import rest
|
from pecan import rest
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
|
from webob import exc as webob_exc
|
||||||
import wsme
|
import wsme
|
||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
|
|
||||||
@ -46,11 +47,6 @@ _DEPLOY_INTERFACE_TYPE = wtypes.Enum(
|
|||||||
wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)
|
wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)
|
||||||
|
|
||||||
|
|
||||||
def _check_api_version():
|
|
||||||
if not api_utils.allow_deploy_templates():
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
|
|
||||||
class DeployStepType(wtypes.Base, base.AsDictMixin):
|
class DeployStepType(wtypes.Base, base.AsDictMixin):
|
||||||
"""A type describing a deployment step."""
|
"""A type describing a deployment step."""
|
||||||
|
|
||||||
@ -260,6 +256,13 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
|
|
||||||
invalid_sort_key_list = ['extra', 'steps']
|
invalid_sort_key_list = ['extra', 'steps']
|
||||||
|
|
||||||
|
@pecan.expose()
|
||||||
|
def _route(self, args, request=None):
|
||||||
|
if not api_utils.allow_deploy_templates():
|
||||||
|
raise webob_exc.HTTPNotFound(_(
|
||||||
|
"The API version does not allow deploy templates"))
|
||||||
|
return super(DeployTemplatesController, self)._route(args, request)
|
||||||
|
|
||||||
def _update_changed_fields(self, template, rpc_template):
|
def _update_changed_fields(self, template, rpc_template):
|
||||||
"""Update rpc_template based on changed fields in a template."""
|
"""Update rpc_template based on changed fields in a template."""
|
||||||
for field in objects.DeployTemplate.fields:
|
for field in objects.DeployTemplate.fields:
|
||||||
@ -295,7 +298,6 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
:param detail: Optional, boolean to indicate whether retrieve a list
|
:param detail: Optional, boolean to indicate whether retrieve a list
|
||||||
of deploy templates with detail.
|
of deploy templates with detail.
|
||||||
"""
|
"""
|
||||||
_check_api_version()
|
|
||||||
api_utils.check_policy('baremetal:deploy_template:get')
|
api_utils.check_policy('baremetal:deploy_template:get')
|
||||||
|
|
||||||
api_utils.check_allowed_fields(fields)
|
api_utils.check_allowed_fields(fields)
|
||||||
@ -338,7 +340,6 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
:param fields: Optional, a list with a specified set of fields
|
:param fields: Optional, a list with a specified set of fields
|
||||||
of the resource to be returned.
|
of the resource to be returned.
|
||||||
"""
|
"""
|
||||||
_check_api_version()
|
|
||||||
api_utils.check_policy('baremetal:deploy_template:get')
|
api_utils.check_policy('baremetal:deploy_template:get')
|
||||||
|
|
||||||
api_utils.check_allowed_fields(fields)
|
api_utils.check_allowed_fields(fields)
|
||||||
@ -356,7 +357,6 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
|
|
||||||
:param template: a deploy template within the request body.
|
:param template: a deploy template within the request body.
|
||||||
"""
|
"""
|
||||||
_check_api_version()
|
|
||||||
api_utils.check_policy('baremetal:deploy_template:create')
|
api_utils.check_policy('baremetal:deploy_template:create')
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
@ -387,7 +387,6 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
:param template_ident: UUID or logical name of a deploy template.
|
:param template_ident: UUID or logical name of a deploy template.
|
||||||
:param patch: a json PATCH document to apply to this deploy template.
|
:param patch: a json PATCH document to apply to this deploy template.
|
||||||
"""
|
"""
|
||||||
_check_api_version()
|
|
||||||
api_utils.check_policy('baremetal:deploy_template:update')
|
api_utils.check_policy('baremetal:deploy_template:update')
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
@ -434,7 +433,6 @@ class DeployTemplatesController(rest.RestController):
|
|||||||
|
|
||||||
:param template_ident: UUID or logical name of a deploy template.
|
:param template_ident: UUID or logical name of a deploy template.
|
||||||
"""
|
"""
|
||||||
_check_api_version()
|
|
||||||
api_utils.check_policy('baremetal:deploy_template:delete')
|
api_utils.check_policy('baremetal:deploy_template:delete')
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
|
@ -152,6 +152,14 @@ class TestListAllocations(test_api_base.BaseApiTest):
|
|||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
|
def test_get_one_invalid_api_version_without_check(self):
|
||||||
|
# Invalid name, but the check happens after the microversion check.
|
||||||
|
response = self.get_json(
|
||||||
|
'/allocations/ba!na!na!',
|
||||||
|
headers={api_base.Version.string: str(api_v1.min_version())},
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
def test_many(self):
|
def test_many(self):
|
||||||
allocations = []
|
allocations = []
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
@ -326,6 +334,14 @@ class TestListAllocations(test_api_base.BaseApiTest):
|
|||||||
self.assertEqual({}, data["extra"])
|
self.assertEqual({}, data["extra"])
|
||||||
self.assertEqual(self.node.uuid, data["node_uuid"])
|
self.assertEqual(self.node.uuid, data["node_uuid"])
|
||||||
|
|
||||||
|
def test_get_by_node_resource_invalid_api_version(self):
|
||||||
|
obj_utils.create_test_allocation(self.context, node_id=self.node.id)
|
||||||
|
response = self.get_json(
|
||||||
|
'/nodes/%s/allocation' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: str(api_v1.min_version())},
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
def test_get_by_node_resource_with_fields(self):
|
def test_get_by_node_resource_with_fields(self):
|
||||||
obj_utils.create_test_allocation(self.context, node_id=self.node.id)
|
obj_utils.create_test_allocation(self.context, node_id=self.node.id)
|
||||||
data = self.get_json('/nodes/%s/allocation?fields=name,extra' %
|
data = self.get_json('/nodes/%s/allocation?fields=name,extra' %
|
||||||
@ -666,6 +682,14 @@ class TestDelete(test_api_base.BaseApiTest):
|
|||||||
headers={api_base.Version.string: '1.14'})
|
headers={api_base.Version.string: '1.14'})
|
||||||
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
|
def test_delete_allocation_invalid_api_version_without_check(self,
|
||||||
|
mock_destroy):
|
||||||
|
# Invalid name, but the check happens after the microversion check.
|
||||||
|
response = self.delete('/allocations/ba!na!na1',
|
||||||
|
expect_errors=True,
|
||||||
|
headers={api_base.Version.string: '1.14'})
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
def test_delete_allocation_by_name(self, mock_destroy):
|
def test_delete_allocation_by_name(self, mock_destroy):
|
||||||
self.delete('/allocations/%s' % self.allocation.name,
|
self.delete('/allocations/%s' % self.allocation.name,
|
||||||
headers=self.headers)
|
headers=self.headers)
|
||||||
@ -708,3 +732,12 @@ class TestDelete(test_api_base.BaseApiTest):
|
|||||||
res = self.delete('/nodes/%s/allocation' % uuidutils.generate_uuid(),
|
res = self.delete('/nodes/%s/allocation' % uuidutils.generate_uuid(),
|
||||||
expect_errors=True, headers=self.headers)
|
expect_errors=True, headers=self.headers)
|
||||||
self.assertEqual(http_client.NOT_FOUND, res.status_code)
|
self.assertEqual(http_client.NOT_FOUND, res.status_code)
|
||||||
|
|
||||||
|
def test_delete_allocation_by_node_invalid_api_version(self, mock_destroy):
|
||||||
|
obj_utils.create_test_allocation(self.context, node_id=self.node.id)
|
||||||
|
response = self.delete(
|
||||||
|
'/nodes/%s/allocation' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: str(api_v1.min_version())},
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
self.assertFalse(mock_destroy.called)
|
||||||
|
@ -417,6 +417,16 @@ class TestPatch(BaseDeployTemplatesAPITest):
|
|||||||
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
self.assertFalse(mock_save.called)
|
self.assertFalse(mock_save.called)
|
||||||
|
|
||||||
|
def test_update_by_name_old_api_version(self, mock_save):
|
||||||
|
name = 'CUSTOM_DT2'
|
||||||
|
response = self.patch_json('/deploy_templates/%s' % self.template.name,
|
||||||
|
[{'path': '/name',
|
||||||
|
'value': name,
|
||||||
|
'op': 'add'}],
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
self.assertFalse(mock_save.called)
|
||||||
|
|
||||||
def test_update_not_found(self, mock_save):
|
def test_update_not_found(self, mock_save):
|
||||||
name = 'CUSTOM_DT2'
|
name = 'CUSTOM_DT2'
|
||||||
uuid = uuidutils.generate_uuid()
|
uuid = uuidutils.generate_uuid()
|
||||||
@ -936,6 +946,13 @@ class TestDelete(BaseDeployTemplatesAPITest):
|
|||||||
headers=self.invalid_version_headers)
|
headers=self.invalid_version_headers)
|
||||||
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
|
def test_delete_old_api_version(self, mock_dpt):
|
||||||
|
# Names like CUSTOM_1 were not valid in API 1.1, but the check should
|
||||||
|
# go after the microversion check.
|
||||||
|
response = self.delete('/deploy_templates/%s' % self.template.name,
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(http_client.NOT_FOUND, response.status_int)
|
||||||
|
|
||||||
def test_delete_by_name_non_existent(self, mock_dpt):
|
def test_delete_by_name_non_existent(self, mock_dpt):
|
||||||
res = self.delete('/deploy_templates/%s' % 'blah', expect_errors=True,
|
res = self.delete('/deploy_templates/%s' % 'blah', expect_errors=True,
|
||||||
headers=self.headers)
|
headers=self.headers)
|
||||||
|
Loading…
Reference in New Issue
Block a user