diff --git a/nova/api/openstack/placement/handler.py b/nova/api/openstack/placement/handler.py index 18dfa7486c..62b40280d2 100644 --- a/nova/api/openstack/placement/handler.py +++ b/nova/api/openstack/placement/handler.py @@ -23,13 +23,10 @@ Routes.Mapper, including automatic handlers to respond with a method. """ -import re - import routes import webob from oslo_log import log as logging -from oslo_utils import excutils from nova.api.openstack.placement import exception from nova.api.openstack.placement.handlers import aggregate @@ -131,40 +128,6 @@ ROUTE_DECLARATIONS = { }, } -# This is a temporary list (of regexes) of the route handlers that will do -# their own granular policy check. Once all handlers are doing their own -# policy checks we can remove this along with the generic policy check in -# PlacementHandler. All entries are checked against re.match() so must -# match the start of the path. -PER_ROUTE_POLICY = [ - # The root is special in that it does not require auth. - '/$', - # /resource_providers - # /resource_providers/{uuid} - # /resource_providers/{uuid}/inventories - # /resource_providers/{uuid}/inventories/{resource_class} - '/resource_providers(/[A-Za-z0-9-]+)?(/inventories)?(/[A-Z0-9_]+)?$', - # /resource_providers/{uuid}/aggregates - '/resource_providers/[A-Za-z0-9-]+/aggregates$', - # /resource_classes - # /resource_classes/{name} - '/resource_classes', - # /resource_providers/{uuid}/usages - '/resource_providers/[A-Za-z0-9-]+/usages$', - # /resource_providers/{uuid}/allocations - '/resource_providers/[A-Za-z0-9-]+/allocations', - # /allocations - # /allocations/{consumer_uuid} - '/allocations', - # /traits - # /traits/{name} - '/traits', - # /resource_providers/{uuid}/traits - '/resource_providers/[A-Za-z0-9-]+/traits', - # /usages - '/usages' -] - def dispatch(environ, start_response, mapper): """Find a matching route for the current request. @@ -228,29 +191,7 @@ class PlacementHandler(object): # NOTE(cdent): Local config currently unused. self._map = make_map(ROUTE_DECLARATIONS) - @staticmethod - def _is_granular_policy_check(path): - for policy in PER_ROUTE_POLICY: - if re.match(policy, path): - return True - return False - def __call__(self, environ, start_response): - # Any routes that do not yet have a granular policy check default - # to admin-only. - if not self._is_granular_policy_check(environ['PATH_INFO']): - context = environ['placement.context'] - try: - if not context.can('placement', fatal=False): - raise webob.exc.HTTPForbidden( - _('admin required'), - json_formatter=util.json_error_formatter) - except Exception: - # This is here mostly for help in debugging problems with - # busted test setup. - with excutils.save_and_reraise_exception(): - LOG.exception('policy check failed for path: %s', - environ['PATH_INFO']) # Check that an incoming request with a content-length header # that is an integer > 0 and not empty, also has a content-type # header that is not empty. If not raise a 400. diff --git a/nova/api/openstack/placement/handlers/allocation_candidate.py b/nova/api/openstack/placement/handlers/allocation_candidate.py index b15761de9d..80db5254e6 100644 --- a/nova/api/openstack/placement/handlers/allocation_candidate.py +++ b/nova/api/openstack/placement/handlers/allocation_candidate.py @@ -23,6 +23,8 @@ import webob from nova.api.openstack.placement import exception from nova.api.openstack.placement import microversion from nova.api.openstack.placement.objects import resource_provider as rp_obj +from nova.api.openstack.placement.policies import allocation_candidate as \ + policies from nova.api.openstack.placement.schemas import allocation_candidate as schema from nova.api.openstack.placement import util from nova.api.openstack.placement import wsgi_wrapper @@ -210,6 +212,7 @@ def list_allocation_candidates(req): a collection of allocation requests and provider summaries """ context = req.environ['placement.context'] + context.can(policies.LIST) want_version = req.environ[microversion.MICROVERSION_ENVIRON] get_schema = schema.GET_SCHEMA_1_10 if want_version.matches((1, 25)): diff --git a/nova/api/openstack/placement/policies/__init__.py b/nova/api/openstack/placement/policies/__init__.py index 953be19b03..cd65514d39 100644 --- a/nova/api/openstack/placement/policies/__init__.py +++ b/nova/api/openstack/placement/policies/__init__.py @@ -14,6 +14,7 @@ import itertools from nova.api.openstack.placement.policies import aggregate from nova.api.openstack.placement.policies import allocation +from nova.api.openstack.placement.policies import allocation_candidate from nova.api.openstack.placement.policies import base from nova.api.openstack.placement.policies import inventory from nova.api.openstack.placement.policies import resource_class @@ -32,4 +33,5 @@ def list_rules(): usage.list_rules(), trait.list_rules(), allocation.list_rules(), + allocation_candidate.list_rules() ) diff --git a/nova/api/openstack/placement/policies/allocation_candidate.py b/nova/api/openstack/placement/policies/allocation_candidate.py new file mode 100644 index 0000000000..e2ae655370 --- /dev/null +++ b/nova/api/openstack/placement/policies/allocation_candidate.py @@ -0,0 +1,38 @@ +# 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 oslo_policy import policy + +from nova.api.openstack.placement.policies import base + + +LIST = 'placement:allocation_candidates:list' + +rules = [ + policy.DocumentedRuleDefault( + LIST, + base.RULE_ADMIN_API, + "List allocation candidates.", + [ + { + 'method': 'GET', + 'path': '/allocation_candidates' + } + ], + scope_types=['system'], + ) +] + + +def list_rules(): + return rules diff --git a/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates-policy.yaml b/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates-policy.yaml new file mode 100644 index 0000000000..6fbe75dd1b --- /dev/null +++ b/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates-policy.yaml @@ -0,0 +1,18 @@ +# This tests GET /allocation_candidates using a non-admin +# user with an open policy configuration. The response validation is +# intentionally minimal. +fixtures: + - OpenPolicyFixture + +defaults: + request_headers: + x-auth-token: user + accept: application/json + content-type: application/json + openstack-api-version: placement latest + +tests: + +- name: get allocation candidates + GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100 + status: 200