Add granular policy rules for traits in placement

This adds the granular policy rule defaults for
traits-related APIs in the placement service. By
default these are backward-compatible and require
the admin role. They also specify the system scope
type since traits are defined and used by the system,
but scope enforcement is disabled by default in
oslo.policy.

Part of blueprint granular-placement-policy

Change-Id: I9a8af3cae34e32438df12125b9bf32ccdde3b792
This commit is contained in:
Matt Riedemann 2018-05-25 20:46:24 -04:00
parent 9e44dc3466
commit e26a5997b0
5 changed files with 190 additions and 0 deletions

View File

@ -151,6 +151,11 @@ PER_ROUTE_POLICY = [
'/resource_classes',
# /resource_providers/{uuid}/usages
'/resource_providers/[A-Za-z0-9-]+/usages$',
# /traits
# /traits/{name}
'/traits',
# /resource_providers/{uuid}/traits
'/resource_providers/[A-Za-z0-9-]+/traits',
# /usages
'/usages'
]

View File

@ -20,6 +20,7 @@ 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 trait as policies
from nova.api.openstack.placement.schemas import trait as schema
from nova.api.openstack.placement import util
from nova.api.openstack.placement import wsgi_wrapper
@ -64,6 +65,7 @@ def _serialize_traits(traits, want_version):
@microversion.version_handler('1.6')
def put_trait(req):
context = req.environ['placement.context']
context.can(policies.TRAITS_UPDATE)
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
name = util.wsgi_path_item(req.environ, 'name')
@ -99,6 +101,7 @@ def put_trait(req):
@microversion.version_handler('1.6')
def get_trait(req):
context = req.environ['placement.context']
context.can(policies.TRAITS_SHOW)
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
name = util.wsgi_path_item(req.environ, 'name')
@ -119,6 +122,7 @@ def get_trait(req):
@microversion.version_handler('1.6')
def delete_trait(req):
context = req.environ['placement.context']
context.can(policies.TRAITS_DELETE)
name = util.wsgi_path_item(req.environ, 'name')
try:
@ -141,6 +145,7 @@ def delete_trait(req):
@util.check_accept('application/json')
def list_traits(req):
context = req.environ['placement.context']
context.can(policies.TRAITS_LIST)
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
filters = {}
@ -172,6 +177,7 @@ def list_traits(req):
@util.check_accept('application/json')
def list_traits_for_resource_provider(req):
context = req.environ['placement.context']
context.can(policies.RP_TRAIT_LIST)
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
uuid = util.wsgi_path_item(req.environ, 'uuid')
@ -206,6 +212,7 @@ def list_traits_for_resource_provider(req):
@util.require_content('application/json')
def update_traits_for_resource_provider(req):
context = req.environ['placement.context']
context.can(policies.RP_TRAIT_UPDATE)
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
uuid = util.wsgi_path_item(req.environ, 'uuid')
data = util.extract_json(req.body, schema.SET_TRAITS_FOR_RP_SCHEMA)
@ -246,6 +253,7 @@ def update_traits_for_resource_provider(req):
@microversion.version_handler('1.6')
def delete_traits_for_resource_provider(req):
context = req.environ['placement.context']
context.can(policies.RP_TRAIT_DELETE)
uuid = util.wsgi_path_item(req.environ, 'uuid')
resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)

View File

@ -17,6 +17,7 @@ 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
from nova.api.openstack.placement.policies import resource_provider
from nova.api.openstack.placement.policies import trait
from nova.api.openstack.placement.policies import usage
@ -28,4 +29,5 @@ def list_rules():
inventory.list_rules(),
aggregate.list_rules(),
usage.list_rules(),
trait.list_rules(),
)

View File

@ -0,0 +1,120 @@
# 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
RP_TRAIT_PREFIX = 'placement:resource_providers:traits:%s'
RP_TRAIT_LIST = RP_TRAIT_PREFIX % 'list'
RP_TRAIT_UPDATE = RP_TRAIT_PREFIX % 'update'
RP_TRAIT_DELETE = RP_TRAIT_PREFIX % 'delete'
TRAITS_PREFIX = 'placement:traits:%s'
TRAITS_LIST = TRAITS_PREFIX % 'list'
TRAITS_SHOW = TRAITS_PREFIX % 'show'
TRAITS_UPDATE = TRAITS_PREFIX % 'update'
TRAITS_DELETE = TRAITS_PREFIX % 'delete'
rules = [
policy.DocumentedRuleDefault(
TRAITS_LIST,
base.RULE_ADMIN_API,
"List traits.",
[
{
'method': 'GET',
'path': '/traits'
}
],
scope_types=['system']
),
policy.DocumentedRuleDefault(
TRAITS_SHOW,
base.RULE_ADMIN_API,
"Show trait.",
[
{
'method': 'GET',
'path': '/traits/{name}'
}
],
scope_types=['system'],
),
policy.DocumentedRuleDefault(
TRAITS_UPDATE,
base.RULE_ADMIN_API,
"Update trait.",
[
{
'method': 'PUT',
'path': '/traits/{name}'
}
],
scope_types=['system'],
),
policy.DocumentedRuleDefault(
TRAITS_DELETE,
base.RULE_ADMIN_API,
"Delete trait.",
[
{
'method': 'DELETE',
'path': '/traits/{name}'
}
],
scope_types=['system'],
),
policy.DocumentedRuleDefault(
RP_TRAIT_LIST,
base.RULE_ADMIN_API,
"List resource provider traits.",
[
{
'method': 'GET',
'path': '/resource_providers/{uuid}/traits'
}
],
scope_types=['system'],
),
policy.DocumentedRuleDefault(
RP_TRAIT_UPDATE,
base.RULE_ADMIN_API,
"Update resource provider traits.",
[
{
'method': 'PUT',
'path': '/resource_providers/{uuid}/traits'
}
],
scope_types=['system'],
),
policy.DocumentedRuleDefault(
RP_TRAIT_DELETE,
base.RULE_ADMIN_API,
"Delete resource provider traits.",
[
{
'method': 'DELETE',
'path': '/resource_providers/{uuid}/traits'
}
],
scope_types=['system'],
),
]
def list_rules():
return rules

View File

@ -0,0 +1,55 @@
# This tests the individual CRUD operations on
# /traits* and /resource_providers/{uuid}/traits 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: list traits
GET: /traits
status: 200
- name: create a trait
PUT: /traits/CUSTOM_TRAIT_X
status: 201
- name: show trait
GET: /traits/CUSTOM_TRAIT_X
status: 204
- name: create resource provider
POST: /resource_providers
data:
name: $ENVIRON['RP_NAME']
uuid: $ENVIRON['RP_UUID']
status: 200
- name: list resource provider traits
GET: /resource_providers/$ENVIRON['RP_UUID']/traits
status: 200
- name: update resource provider traits
PUT: /resource_providers/$ENVIRON['RP_UUID']/traits
request_headers:
content-type: application/json
status: 200
data:
traits:
- CUSTOM_TRAIT_X
resource_provider_generation: 0
- name: delete resource provider traits
DELETE: /resource_providers/$ENVIRON['RP_UUID']/traits
status: 204
- name: delete trait
DELETE: /traits/CUSTOM_TRAIT_X
status: 204