Merge "Add granular policy rules for allocation candidates"
This commit is contained in:
@@ -23,13 +23,10 @@ Routes.Mapper, including automatic handlers to respond with a
|
|||||||
method.
|
method.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
import routes
|
import routes
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
|
||||||
|
|
||||||
from nova.api.openstack.placement import exception
|
from nova.api.openstack.placement import exception
|
||||||
from nova.api.openstack.placement.handlers import aggregate
|
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):
|
def dispatch(environ, start_response, mapper):
|
||||||
"""Find a matching route for the current request.
|
"""Find a matching route for the current request.
|
||||||
@@ -228,29 +191,7 @@ class PlacementHandler(object):
|
|||||||
# NOTE(cdent): Local config currently unused.
|
# NOTE(cdent): Local config currently unused.
|
||||||
self._map = make_map(ROUTE_DECLARATIONS)
|
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):
|
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
|
# Check that an incoming request with a content-length header
|
||||||
# that is an integer > 0 and not empty, also has a content-type
|
# that is an integer > 0 and not empty, also has a content-type
|
||||||
# header that is not empty. If not raise a 400.
|
# header that is not empty. If not raise a 400.
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import webob
|
|||||||
from nova.api.openstack.placement import exception
|
from nova.api.openstack.placement import exception
|
||||||
from nova.api.openstack.placement import microversion
|
from nova.api.openstack.placement import microversion
|
||||||
from nova.api.openstack.placement.objects import resource_provider as rp_obj
|
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.schemas import allocation_candidate as schema
|
||||||
from nova.api.openstack.placement import util
|
from nova.api.openstack.placement import util
|
||||||
from nova.api.openstack.placement import wsgi_wrapper
|
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
|
a collection of allocation requests and provider summaries
|
||||||
"""
|
"""
|
||||||
context = req.environ['placement.context']
|
context = req.environ['placement.context']
|
||||||
|
context.can(policies.LIST)
|
||||||
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
||||||
get_schema = schema.GET_SCHEMA_1_10
|
get_schema = schema.GET_SCHEMA_1_10
|
||||||
if want_version.matches((1, 25)):
|
if want_version.matches((1, 25)):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import itertools
|
|||||||
|
|
||||||
from nova.api.openstack.placement.policies import aggregate
|
from nova.api.openstack.placement.policies import aggregate
|
||||||
from nova.api.openstack.placement.policies import allocation
|
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 base
|
||||||
from nova.api.openstack.placement.policies import inventory
|
from nova.api.openstack.placement.policies import inventory
|
||||||
from nova.api.openstack.placement.policies import resource_class
|
from nova.api.openstack.placement.policies import resource_class
|
||||||
@@ -32,4 +33,5 @@ def list_rules():
|
|||||||
usage.list_rules(),
|
usage.list_rules(),
|
||||||
trait.list_rules(),
|
trait.list_rules(),
|
||||||
allocation.list_rules(),
|
allocation.list_rules(),
|
||||||
|
allocation_candidate.list_rules()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user