Merge "Replace "target_tenant" with "target_project" in RBAC OVOs and models"
This commit is contained in:
commit
74e2956aa3
@ -621,7 +621,7 @@ Use the :command:`openstack network rbac show` command to see the details:
|
||||
|
||||
The output shows that the entry allows the action ``access_as_shared``
|
||||
on object ``84a7e627-573b-49da-af66-c9a65244f3ce`` of type ``network``
|
||||
to target_tenant ``*``, which is a wildcard that represents all projects.
|
||||
to target_project ``*``, which is a wildcard that represents all projects.
|
||||
|
||||
Currently, the ``shared`` flag is just a mapping to the underlying
|
||||
RBAC policies for a network. Setting the flag to ``True`` on a network
|
||||
|
@ -25,12 +25,14 @@ RESOURCE_PATH = '/rbac-policies/{id}'
|
||||
|
||||
|
||||
rules = [
|
||||
# TODO(ralonsoh): remove 'target_tenant=*' reference.
|
||||
policy.RuleDefault(
|
||||
name='restrict_wildcard',
|
||||
check_str=base.policy_or(
|
||||
'(not field:rbac_policy:target_tenant=*)',
|
||||
'(not field:rbac_policy:target_tenant=* and '
|
||||
'not field:rbac_policy:target_project=*)',
|
||||
base.RULE_ADMIN_ONLY),
|
||||
description='Definition of a wildcard target_tenant'),
|
||||
description='Definition of a wildcard target_project'),
|
||||
|
||||
policy.DocumentedRuleDefault(
|
||||
name='create_rbac_policy',
|
||||
@ -49,11 +51,14 @@ rules = [
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY)
|
||||
),
|
||||
# TODO(ralonsoh): change name to 'create_rbac_policy:target_project'
|
||||
# and remove 'target_tenant=*' reference.
|
||||
policy.DocumentedRuleDefault(
|
||||
name='create_rbac_policy:target_tenant',
|
||||
check_str=base.policy_or(
|
||||
base.SYSTEM_ADMIN,
|
||||
'(not field:rbac_policy:target_tenant=*)'),
|
||||
'(not field:rbac_policy:target_tenant=* and '
|
||||
'not field:rbac_policy:target_project=*)'),
|
||||
description='Specify ``target_tenant`` when creating an RBAC policy',
|
||||
operations=[
|
||||
{
|
||||
@ -85,11 +90,14 @@ rules = [
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY)
|
||||
),
|
||||
# TODO(ralonsoh): change name to 'create_rbac_policy:target_project'
|
||||
# and remove 'target_tenant=*' reference.
|
||||
policy.DocumentedRuleDefault(
|
||||
name='update_rbac_policy:target_tenant',
|
||||
check_str=base.policy_or(
|
||||
base.SYSTEM_ADMIN,
|
||||
'(not field:rbac_policy:target_tenant=*)'),
|
||||
'(not field:rbac_policy:target_tenant=* and '
|
||||
'not field:rbac_policy:target_project=*)'),
|
||||
description='Update ``target_tenant`` attribute of an RBAC policy',
|
||||
operations=[
|
||||
{
|
||||
|
@ -345,7 +345,7 @@ class DbBasePluginCommon(object):
|
||||
matches = ('*',) + ((context.tenant_id,) if context else ())
|
||||
for entry in rbac_entries:
|
||||
if (entry.action == 'access_as_shared' and
|
||||
entry.target_tenant in matches):
|
||||
entry.target_project in matches):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -218,16 +218,16 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
raise exc.InvalidInput(error_message=msg)
|
||||
|
||||
tenant_to_check = None
|
||||
self_sharing = policy['target_tenant'] == net['tenant_id']
|
||||
self_sharing = policy['target_project'] == net['tenant_id']
|
||||
if self_sharing:
|
||||
return
|
||||
if event == events.BEFORE_UPDATE:
|
||||
new_tenant = payload.request_body['target_tenant']
|
||||
if policy['target_tenant'] != new_tenant:
|
||||
tenant_to_check = policy['target_tenant']
|
||||
new_tenant = payload.request_body['target_project']
|
||||
if policy['target_project'] != new_tenant:
|
||||
tenant_to_check = policy['target_project']
|
||||
|
||||
if event == events.BEFORE_DELETE:
|
||||
tenant_to_check = policy['target_tenant']
|
||||
tenant_to_check = policy['target_project']
|
||||
|
||||
if tenant_to_check:
|
||||
self.ensure_no_tenant_ports_on_network(net['id'], net['tenant_id'],
|
||||
@ -245,9 +245,9 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
# the same tenant as the network owner is ok
|
||||
other_rbac_objs = network_obj.NetworkRBAC.get_objects(
|
||||
ctx_admin, object_id=network_id, action='access_as_shared')
|
||||
allowed_tenants = [rbac['target_tenant'] for rbac
|
||||
allowed_tenants = [rbac['target_project'] for rbac
|
||||
in other_rbac_objs
|
||||
if rbac.target_tenant != tenant_id]
|
||||
if rbac.target_project != tenant_id]
|
||||
allowed_tenants.append(net_tenant_id)
|
||||
ports = ports.filter(
|
||||
~models_v2.Port.tenant_id.in_(allowed_tenants))
|
||||
@ -256,7 +256,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
# allows any ports
|
||||
if network_obj.NetworkRBAC.get_object(
|
||||
ctx_admin, object_id=network_id, action='access_as_shared',
|
||||
target_tenant='*'):
|
||||
target_project='*'):
|
||||
return
|
||||
ports = ports.filter(models_v2.Port.project_id == tenant_id)
|
||||
if ports.count():
|
||||
@ -303,8 +303,8 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
ctx_admin = ctx.get_admin_context()
|
||||
other_rbac_objs = network_obj.NetworkRBAC.get_objects(
|
||||
ctx_admin, object_id=network.id, action='access_as_shared')
|
||||
allowed_projects = {rbac['target_tenant'] for rbac in other_rbac_objs
|
||||
if rbac.target_tenant != '*'}
|
||||
allowed_projects = {rbac['target_project'] for rbac in other_rbac_objs
|
||||
if rbac.target_project != '*'}
|
||||
allowed_projects.add(network.project_id)
|
||||
if project_ids - allowed_projects:
|
||||
raise exc.InvalidSharedSetting(network=network.name)
|
||||
@ -417,7 +417,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
np_rbac_args = {'project_id': network.project_id,
|
||||
'object_id': network.id,
|
||||
'action': 'access_as_shared',
|
||||
'target_tenant': '*'}
|
||||
'target_project': '*'}
|
||||
np_rbac_obj = network_obj.NetworkRBAC(context, **np_rbac_args)
|
||||
np_rbac_obj.create()
|
||||
return network
|
||||
@ -434,7 +434,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
entry = None
|
||||
for item in network.rbac_entries:
|
||||
if (item.action == 'access_as_shared' and
|
||||
item.target_tenant == '*'):
|
||||
item.target_project == '*'):
|
||||
entry = item
|
||||
break
|
||||
setattr(network, 'shared', bool(entry))
|
||||
@ -444,14 +444,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
np_rbac_args = {'project_id': network.project_id,
|
||||
'object_id': network.id,
|
||||
'action': 'access_as_shared',
|
||||
'target_tenant': '*'}
|
||||
'target_project': '*'}
|
||||
np_rbac_obj = network_obj.NetworkRBAC(context,
|
||||
**np_rbac_args)
|
||||
np_rbac_obj.create()
|
||||
elif not update_shared and entry:
|
||||
network_obj.NetworkRBAC.delete_objects(
|
||||
context, object_id=network.id,
|
||||
action='access_as_shared', target_tenant='*')
|
||||
action='access_as_shared', target_project='*')
|
||||
|
||||
# TODO(ihrachys) Below can be removed when we make sqlalchemy
|
||||
# event listeners in neutron_lib/db/api.py to refresh expired
|
||||
|
@ -47,8 +47,8 @@ def _network_filter_hook(context, original_model, conditions):
|
||||
rbac_model = original_model.rbac_entries.property.mapper.class_
|
||||
tenant_allowed = (
|
||||
(rbac_model.action == 'access_as_external') &
|
||||
(rbac_model.target_tenant == context.tenant_id) |
|
||||
(rbac_model.target_tenant == '*'))
|
||||
(rbac_model.target_project == context.tenant_id) |
|
||||
(rbac_model.target_project == '*'))
|
||||
conditions = expr.or_(tenant_allowed, *conditions)
|
||||
return conditions
|
||||
|
||||
@ -100,7 +100,7 @@ class External_net_db_mixin(object):
|
||||
net_rbac_args = {'project_id': net_data['tenant_id'],
|
||||
'object_id': net_data['id'],
|
||||
'action': 'access_as_external',
|
||||
'target_tenant': '*'}
|
||||
'target_project': '*'}
|
||||
net_obj.NetworkRBAC(context, **net_rbac_args).create()
|
||||
net_data[extnet_apidef.EXTERNAL] = external
|
||||
|
||||
@ -121,7 +121,7 @@ class External_net_db_mixin(object):
|
||||
net_rbac_args = {'project_id': net_data['tenant_id'],
|
||||
'object_id': net_id,
|
||||
'action': 'access_as_external',
|
||||
'target_tenant': '*'}
|
||||
'target_project': '*'}
|
||||
net_obj.NetworkRBAC(context, **net_rbac_args).create()
|
||||
else:
|
||||
# must make sure we do not have any external gateway ports
|
||||
@ -196,24 +196,24 @@ class External_net_db_mixin(object):
|
||||
return
|
||||
new_project = None
|
||||
if event == events.BEFORE_UPDATE:
|
||||
new_project = payload.request_body['target_tenant']
|
||||
if new_project == policy['target_tenant']:
|
||||
new_project = payload.request_body['target_project']
|
||||
if new_project == policy['target_project']:
|
||||
# nothing to validate if the tenant didn't change
|
||||
return
|
||||
gw_ports = context.session.query(models_v2.Port.id).filter_by(
|
||||
device_owner=constants.DEVICE_OWNER_ROUTER_GW,
|
||||
network_id=policy['object_id'])
|
||||
gw_ports = [gw_port[0] for gw_port in gw_ports]
|
||||
if policy['target_tenant'] != '*':
|
||||
if policy['target_project'] != '*':
|
||||
filters = {
|
||||
'gw_port_id': gw_ports,
|
||||
'project_id': policy['target_tenant']
|
||||
'project_id': policy['target_project']
|
||||
}
|
||||
# if there is a wildcard entry we can safely proceed without the
|
||||
# router lookup because they will have access either way
|
||||
if net_obj.NetworkRBAC.count(
|
||||
context, object_id=policy['object_id'],
|
||||
action='access_as_external', target_tenant='*'):
|
||||
action='access_as_external', target_project='*'):
|
||||
return
|
||||
router_exist = l3_obj.Router.objects_exist(context, **filters)
|
||||
else:
|
||||
|
@ -1 +1 @@
|
||||
76df7844a8c6
|
||||
1ffef8d6f371
|
||||
|
@ -0,0 +1,130 @@
|
||||
# Copyright 2021 Red Hat Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""migrate RBAC registers from "target_tenant" to "target_project"
|
||||
|
||||
Revision ID: 1ffef8d6f371
|
||||
Revises: 76df7844a8c6
|
||||
Create Date: 2021-10-28 14:10:20.097125
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '1ffef8d6f371'
|
||||
down_revision = '76df7844a8c6'
|
||||
|
||||
_INSPECTOR = None
|
||||
TABLES = ['networkrbacs', 'qospolicyrbacs', 'securitygrouprbacs',
|
||||
'addressscoperbacs', 'subnetpoolrbacs', 'addressgrouprbacs']
|
||||
DROPPED_UNIQUE_CONSTRAINTS = [
|
||||
'uniq_networkrbacs0tenant_target0object_id0action',
|
||||
'qospolicyrbacs_target_tenant_object_id_action_key', # PSQL
|
||||
'target_tenant', # MySQL, name provided by mistake
|
||||
'uniq_securitygrouprbacs0target_tenant0object_id0action',
|
||||
'uniq_address_scopes_rbacs0target_tenant0object_id0action',
|
||||
'uniq_subnetpools_rbacs0target_tenant0object_id0action',
|
||||
'uniq_address_groups_rbacs0target_tenant0object_id0action']
|
||||
|
||||
|
||||
def get_inspector():
|
||||
global _INSPECTOR
|
||||
if _INSPECTOR:
|
||||
return _INSPECTOR
|
||||
else:
|
||||
bind = op.get_bind()
|
||||
_INSPECTOR = sa.engine.reflection.Inspector.from_engine(bind)
|
||||
|
||||
return _INSPECTOR
|
||||
|
||||
|
||||
def get_columns(table):
|
||||
inspector = get_inspector()
|
||||
return inspector.get_columns(table)
|
||||
|
||||
|
||||
def get_data():
|
||||
output = []
|
||||
for table in TABLES:
|
||||
for column in get_columns(table):
|
||||
if column['name'] == 'target_tenant':
|
||||
output.append((table, column))
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def delete_unique_constraint(table):
|
||||
inspector = get_inspector()
|
||||
unique_constraints = inspector.get_unique_constraints(table)
|
||||
for constraint in unique_constraints:
|
||||
op.drop_constraint(
|
||||
constraint_name=constraint['name'],
|
||||
table_name=table,
|
||||
type_='unique')
|
||||
|
||||
|
||||
def add_unique_constraint(table):
|
||||
op.create_unique_constraint(
|
||||
constraint_name='uniq_%s0target_project0object_id0action' % table,
|
||||
table_name=table, columns=['target_project', 'object_id', 'action'])
|
||||
|
||||
|
||||
def alter_column(table, column):
|
||||
op.alter_column(
|
||||
table_name=table,
|
||||
column_name='target_tenant',
|
||||
new_column_name='target_project',
|
||||
existing_type=sa.String(length=255),
|
||||
existing_nullable=column['nullable'])
|
||||
|
||||
|
||||
def recreate_index(table):
|
||||
inspector = get_inspector()
|
||||
indexes = inspector.get_indexes(table)
|
||||
index_name = 'ix_' + table + '_target_tenant'
|
||||
for idx in (idx for idx in indexes if idx['name'] == index_name):
|
||||
old_name = idx['name']
|
||||
new_name = old_name.replace('target_tenant', 'target_project')
|
||||
op.drop_index(op.f(old_name), table)
|
||||
op.create_index(new_name, table, ['target_project'])
|
||||
|
||||
|
||||
def upgrade():
|
||||
for table, column in get_data():
|
||||
delete_unique_constraint(table)
|
||||
alter_column(table, column)
|
||||
recreate_index(table)
|
||||
add_unique_constraint(table)
|
||||
|
||||
|
||||
def expand_drop_exceptions():
|
||||
"""Drop the unique constraints and "*_target_tenant" keys
|
||||
|
||||
In order to rename the ``TABLES`` column name from "target_tenant" to
|
||||
"target_project", it is needed to drop any constraint related to this
|
||||
column. For all tables in ``TABLES``, this migration will drop:
|
||||
- Unique constraint "uniq_<table>0target_tenant0object_id0action"
|
||||
- Key "ix_<table>_target_tenant"
|
||||
|
||||
Once the column name is changed, both the unique constraint and the key are
|
||||
created again.
|
||||
"""
|
||||
return {
|
||||
sa.UniqueConstraint: DROPPED_UNIQUE_CONSTRAINTS,
|
||||
sa.Index: TABLES
|
||||
}
|
@ -36,6 +36,12 @@ class RbacPluginMixin(object):
|
||||
@db_api.retry_if_session_inactive()
|
||||
def create_rbac_policy(self, context, rbac_policy):
|
||||
e = rbac_policy['rbac_policy']
|
||||
# NOTE(ralonsoh): remove this conversion when "bp/keystone-v3" is
|
||||
# widely implemented in all OpenStack projects.
|
||||
try:
|
||||
e['target_project'] = e.pop('target_tenant')
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
registry.publish(resources.RBAC_POLICY, events.BEFORE_CREATE, self,
|
||||
payload=events.DBEventPayload(
|
||||
@ -49,7 +55,7 @@ class RbacPluginMixin(object):
|
||||
rbac_args = {'project_id': e['project_id'],
|
||||
'object_id': e['object_id'],
|
||||
'action': e['action'],
|
||||
'target_tenant': e['target_tenant']}
|
||||
'target_project': e['target_project']}
|
||||
_rbac_obj = rbac_class(context, **rbac_args)
|
||||
_rbac_obj.create()
|
||||
except o_exc.NeutronDbObjectDuplicateEntry:
|
||||
@ -58,14 +64,22 @@ class RbacPluginMixin(object):
|
||||
|
||||
@staticmethod
|
||||
def _make_rbac_policy_dict(entry, fields=None):
|
||||
res = {f: entry[f] for f in ('id', 'project_id', 'target_tenant',
|
||||
res = {f: entry[f] for f in ('id', 'project_id', 'target_project',
|
||||
'action', 'object_id')}
|
||||
# TODO(ralonsoh): remove once all calls refer to "target_project"
|
||||
res['target_tenant'] = res['target_project']
|
||||
res['object_type'] = entry.db_model.object_type
|
||||
return db_utils.resource_fields(res, fields)
|
||||
|
||||
@db_api.retry_if_session_inactive()
|
||||
def update_rbac_policy(self, context, id, rbac_policy):
|
||||
pol = rbac_policy['rbac_policy']
|
||||
# NOTE(ralonsoh): remove this conversion when "bp/keystone-v3" is
|
||||
# widely implemented in all OpenStack projects.
|
||||
try:
|
||||
pol['target_project'] = pol.pop('target_tenant')
|
||||
except KeyError:
|
||||
pass
|
||||
entry = self._get_rbac_policy(context, id)
|
||||
object_type = entry.db_model.object_type
|
||||
try:
|
||||
@ -122,6 +136,12 @@ class RbacPluginMixin(object):
|
||||
pager = base_obj.Pager(sorts, limit, page_reverse)
|
||||
filters = filters or {}
|
||||
object_types = filters.pop('object_type', None)
|
||||
# NOTE(ralonsoh): remove this conversion when "bp/keystone-v3" is
|
||||
# widely implemented in all OpenStack projects.
|
||||
try:
|
||||
filters['target_project'] = filters.pop('target_tenant')
|
||||
except KeyError:
|
||||
pass
|
||||
rbac_classes_to_query = [
|
||||
o for t, o in rbac_obj.RBACBaseObject.get_type_class_map().items()
|
||||
if not object_types or t in object_types]
|
||||
|
@ -21,6 +21,7 @@ from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import directory
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.ext import declarative
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.orm import validates
|
||||
|
||||
from neutron._i18n import _
|
||||
@ -43,11 +44,11 @@ class RBACColumns(model_base.HasId, model_base.HasProject):
|
||||
RBAC types.
|
||||
"""
|
||||
|
||||
# the target_tenant is the subject that the policy will affect. this may
|
||||
# the target_project is the subject that the policy will affect. this may
|
||||
# also be a wildcard '*' to indicate all tenants or it may be a role if
|
||||
# neutron gets better integration with keystone
|
||||
target_tenant = sa.Column(sa.String(db_const.PROJECT_ID_FIELD_SIZE),
|
||||
nullable=False, index=True)
|
||||
target_project = sa.Column(sa.String(db_const.PROJECT_ID_FIELD_SIZE),
|
||||
nullable=False, index=True)
|
||||
|
||||
action = sa.Column(sa.String(255), nullable=False, index=True)
|
||||
|
||||
@ -61,7 +62,7 @@ class RBACColumns(model_base.HasId, model_base.HasProject):
|
||||
@declarative.declared_attr
|
||||
def __table_args__(cls):
|
||||
return (
|
||||
sa.UniqueConstraint('target_tenant', 'object_id', 'action'),
|
||||
sa.UniqueConstraint('target_project', 'object_id', 'action'),
|
||||
model_base.BASEV2.__table_args__
|
||||
)
|
||||
|
||||
@ -80,6 +81,20 @@ class RBACColumns(model_base.HasId, model_base.HasProject):
|
||||
# with the valid actions rbac entries
|
||||
pass
|
||||
|
||||
def get_target_tenant(self):
|
||||
return self.target_project
|
||||
|
||||
def set_target_tenant(self, value):
|
||||
self.target_project = value
|
||||
|
||||
# TODO(ralonsoh): remove once the neutron-lib code is modified and the
|
||||
# minimum required version of this library set.
|
||||
@declarative.declared_attr
|
||||
def target_tenant(cls):
|
||||
return orm.synonym(
|
||||
'target_project',
|
||||
descriptor=property(cls.get_target_tenant, cls.set_target_tenant))
|
||||
|
||||
|
||||
def get_type_model_map():
|
||||
return {table.object_type: table for table in RBACColumns.__subclasses__()}
|
||||
|
@ -26,7 +26,8 @@ from neutron.objects import securitygroup
|
||||
@base.NeutronObjectRegistry.register
|
||||
class AddressGroupRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
# Version 1.1: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.1'
|
||||
|
||||
db_model = rbac_db_models.AddressGroupRBAC
|
||||
|
||||
|
@ -27,7 +27,8 @@ from neutron.objects import subnetpool
|
||||
@base.NeutronObjectRegistry.register
|
||||
class AddressScopeRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
# Version 1.1: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.1'
|
||||
|
||||
db_model = rbac_db_models.AddressScopeRBAC
|
||||
|
||||
|
@ -41,8 +41,8 @@ class NetworkRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.1: Added 'id' and 'project_id'
|
||||
# Version 1.2: Inherit from rbac.RBACBaseObject; changed 'object_id' from
|
||||
# StringField to UUIDField
|
||||
|
||||
VERSION = '1.2'
|
||||
# Version 1.3: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.3'
|
||||
|
||||
db_model = rbac_db_models.NetworkRBAC
|
||||
|
||||
|
@ -42,8 +42,8 @@ class QosPolicyRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.1: Inherit from rbac_db.RBACBaseObject; added 'id' and
|
||||
# 'project_id'; changed 'object_id' from StringField to
|
||||
# UUIDField
|
||||
|
||||
VERSION = '1.1'
|
||||
# Version 1.2: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.2'
|
||||
|
||||
db_model = rbac_db_models.QosPolicyRBAC
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
import abc
|
||||
|
||||
from neutron_lib.objects import common_types
|
||||
from oslo_utils import versionutils
|
||||
from oslo_versionedobjects import fields as obj_fields
|
||||
from sqlalchemy import and_
|
||||
|
||||
@ -24,15 +25,14 @@ from neutron.objects import base
|
||||
|
||||
class RBACBaseObject(base.NeutronDbObject, metaclass=abc.ABCMeta):
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.1'
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
# TODO(ralonsoh): move 'target_tenant' to 'target_project'.
|
||||
fields = {
|
||||
'id': common_types.UUIDField(),
|
||||
'project_id': obj_fields.StringField(),
|
||||
'object_id': common_types.UUIDField(),
|
||||
'target_tenant': obj_fields.StringField(),
|
||||
'target_project': obj_fields.StringField(),
|
||||
'action': obj_fields.StringField(),
|
||||
}
|
||||
|
||||
@ -40,15 +40,15 @@ class RBACBaseObject(base.NeutronDbObject, metaclass=abc.ABCMeta):
|
||||
|
||||
@classmethod
|
||||
def get_projects(cls, context, object_id=None, action=None,
|
||||
target_tenant=None):
|
||||
target_project=None):
|
||||
clauses = []
|
||||
if object_id:
|
||||
clauses.append(cls.db_model.object_id == object_id)
|
||||
if action:
|
||||
clauses.append(cls.db_model.action == action)
|
||||
if target_tenant:
|
||||
clauses.append(cls.db_model.target_tenant == target_tenant)
|
||||
query = context.session.query(cls.db_model.target_tenant)
|
||||
if target_project:
|
||||
clauses.append(cls.db_model.target_project == target_project)
|
||||
query = context.session.query(cls.db_model.target_project)
|
||||
if clauses:
|
||||
query = query.filter(and_(*clauses))
|
||||
return [data[0] for data in query]
|
||||
@ -57,3 +57,8 @@ class RBACBaseObject(base.NeutronDbObject, metaclass=abc.ABCMeta):
|
||||
def get_type_class_map(cls):
|
||||
return {klass.db_model.object_type: klass
|
||||
for klass in cls.__subclasses__()}
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
_target_version = versionutils.convert_version_to_tuple(target_version)
|
||||
if _target_version < (1, 1): # NOTE(ralonsoh): remove in Yoga + 4.
|
||||
primitive['target_tenant'] = primitive.pop('target_project')
|
||||
|
@ -58,7 +58,7 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
matches = ('*',) + ((context.project_id,) if context else ())
|
||||
for entry in rbac_entries:
|
||||
if (entry.action == models.ACCESS_SHARED and
|
||||
entry.target_tenant in matches):
|
||||
entry.target_project in matches):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -70,7 +70,7 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
return (db_utils.model_query(context, rbac_db_model).filter(
|
||||
and_(rbac_db_model.object_id == obj_id,
|
||||
rbac_db_model.action == models.ACCESS_SHARED,
|
||||
rbac_db_model.target_tenant.in_(
|
||||
rbac_db_model.target_project.in_(
|
||||
['*', project_id]))).count() != 0)
|
||||
|
||||
@classmethod
|
||||
@ -98,13 +98,13 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
def _get_projects_with_shared_access_to_db_obj(cls, context, obj_id):
|
||||
rbac_db_model = cls.rbac_db_cls.db_model
|
||||
return set(itertools.chain.from_iterable(context.session.query(
|
||||
rbac_db_model.target_tenant).filter(
|
||||
rbac_db_model.target_project).filter(
|
||||
and_(rbac_db_model.object_id == obj_id,
|
||||
rbac_db_model.action == models.ACCESS_SHARED,
|
||||
rbac_db_model.target_tenant != '*'))))
|
||||
rbac_db_model.target_project != '*'))))
|
||||
|
||||
@classmethod
|
||||
def _validate_rbac_policy_delete(cls, context, obj_id, target_tenant):
|
||||
def _validate_rbac_policy_delete(cls, context, obj_id, target_project):
|
||||
ctx_admin = context.elevated()
|
||||
rb_model = cls.rbac_db_cls.db_model
|
||||
bound_project_ids = cls.get_bound_project_ids(ctx_admin, obj_id)
|
||||
@ -114,24 +114,24 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
def raise_policy_in_use():
|
||||
raise ext_rbac.RbacPolicyInUse(
|
||||
object_id=obj_id,
|
||||
details='project_id={}'.format(target_tenant))
|
||||
details='project_id={}'.format(target_project))
|
||||
|
||||
if target_tenant != '*':
|
||||
if target_project != '*':
|
||||
# if there is a wildcard rule, we can return early because it
|
||||
# shares the object globally
|
||||
wildcard_sharing_entries = db_obj_sharing_entries.filter(
|
||||
rb_model.target_tenant == '*')
|
||||
rb_model.target_project == '*')
|
||||
if wildcard_sharing_entries.count():
|
||||
return
|
||||
if target_tenant in bound_project_ids:
|
||||
if target_project in bound_project_ids:
|
||||
raise_policy_in_use()
|
||||
return
|
||||
|
||||
# for the wildcard we need to query all of the rbac entries to
|
||||
# see if any allow the object sharing
|
||||
other_target_tenants = cls._get_projects_with_shared_access_to_db_obj(
|
||||
other_target_projects = cls._get_projects_with_shared_access_to_db_obj(
|
||||
ctx_admin, obj_id)
|
||||
if not bound_project_ids.issubset(other_target_tenants):
|
||||
if not bound_project_ids.issubset(other_target_projects):
|
||||
raise_policy_in_use()
|
||||
|
||||
@classmethod
|
||||
@ -146,14 +146,14 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
|
||||
if policy['action'] != models.ACCESS_SHARED:
|
||||
return
|
||||
target_tenant = policy['target_tenant']
|
||||
target_project = policy['target_project']
|
||||
db_obj = obj_db_api.get_object(
|
||||
cls, context.elevated(), id=policy['object_id'])
|
||||
if db_obj.project_id == target_tenant:
|
||||
if db_obj.project_id == target_project:
|
||||
return
|
||||
cls._validate_rbac_policy_delete(context=context,
|
||||
obj_id=policy['object_id'],
|
||||
target_tenant=target_tenant)
|
||||
target_project=target_project)
|
||||
|
||||
@classmethod
|
||||
def validate_rbac_policy_create(cls, resource, event, trigger,
|
||||
@ -171,8 +171,8 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
"""
|
||||
policy = payload.latest_state
|
||||
|
||||
prev_project = policy['target_tenant']
|
||||
new_project = payload.request_body['target_tenant']
|
||||
prev_project = policy['target_project']
|
||||
new_project = payload.request_body['target_project']
|
||||
if prev_project == new_project:
|
||||
return
|
||||
if new_project != '*':
|
||||
@ -214,10 +214,10 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
return callback_map[event](resource, event, trigger,
|
||||
payload=payload)
|
||||
|
||||
def attach_rbac(self, obj_id, project_id, target_tenant='*'):
|
||||
def attach_rbac(self, obj_id, project_id, target_project='*'):
|
||||
obj_type = self.rbac_db_cls.db_model.object_type
|
||||
rbac_policy = {'rbac_policy': {'object_id': obj_id,
|
||||
'target_tenant': target_tenant,
|
||||
'target_project': target_project,
|
||||
'project_id': project_id,
|
||||
'object_type': obj_type,
|
||||
'action': models.ACCESS_SHARED}}
|
||||
@ -227,7 +227,7 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
admin_context = self.obj_context.elevated()
|
||||
shared_prev = obj_db_api.get_object(self.rbac_db_cls, admin_context,
|
||||
object_id=obj_id,
|
||||
target_tenant='*',
|
||||
target_project='*',
|
||||
action=models.ACCESS_SHARED)
|
||||
is_shared_prev = bool(shared_prev)
|
||||
if is_shared_prev == is_shared_new:
|
||||
@ -239,7 +239,7 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
return
|
||||
|
||||
# 'shared' goes True -> False is actually an attempt to delete
|
||||
# rbac rule for sharing obj_id with target_tenant = '*'
|
||||
# rbac rule for sharing obj_id with target_project = '*'
|
||||
self._validate_rbac_policy_delete(self.obj_context, obj_id, '*')
|
||||
return self.obj_context.session.delete(shared_prev)
|
||||
|
||||
|
@ -28,7 +28,8 @@ from neutron.objects import rbac_db
|
||||
@base.NeutronObjectRegistry.register
|
||||
class SecurityGroupRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
# Version 1.1: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.1'
|
||||
|
||||
db_model = rbac_db_models.SecurityGroupRBAC
|
||||
|
||||
|
@ -33,7 +33,8 @@ from neutron.objects import subnet
|
||||
@base.NeutronObjectRegistry.register
|
||||
class SubnetPoolRBAC(rbac.RBACBaseObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
# Version 1.1: Changed 'target_tenant' to 'target_project'
|
||||
VERSION = '1.1'
|
||||
|
||||
db_model = rbac_db_models.SubnetPoolRBAC
|
||||
|
||||
@ -127,8 +128,8 @@ class SubnetPool(rbac_db.NeutronRbacObject):
|
||||
# Ensure that target project has access to AS
|
||||
shared_to_target_project_or_to_all = (
|
||||
sa.and_(
|
||||
rbac_as_model.target_tenant.in_(
|
||||
["*", policy['target_tenant']]
|
||||
rbac_as_model.target_project.in_(
|
||||
["*", policy['target_project']]
|
||||
),
|
||||
rbac_as_model.object_id == db_obj["address_scope_id"]
|
||||
)
|
||||
|
@ -97,7 +97,7 @@ class NetworkRBACTestCase(testlib_api.SqlTestCase):
|
||||
else:
|
||||
action = 'access_as_shared'
|
||||
rbac = network_obj.NetworkRBAC.get_object(
|
||||
self.cxt, object_id=network_id, action=action, target_tenant='*')
|
||||
self.cxt, object_id=network_id, action=action, target_project='*')
|
||||
if is_none:
|
||||
self.assertIsNone(rbac)
|
||||
else:
|
||||
|
@ -14,27 +14,33 @@
|
||||
# limitations under the License.
|
||||
|
||||
from oslo_policy import policy as base_policy
|
||||
import testscenarios
|
||||
|
||||
from neutron import policy
|
||||
from neutron.tests.unit.conf.policies import base
|
||||
|
||||
|
||||
class RbacAPITestCase(base.PolicyBaseTestCase):
|
||||
class RbacAPITestCase(testscenarios.WithScenarios, base.PolicyBaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('target_tenant', {'_target_label': 'target_tenant'}),
|
||||
('target_project', {'_target_label': 'target_project'})
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(RbacAPITestCase, self).setUp()
|
||||
self.target = {
|
||||
'project_id': self.project_id,
|
||||
'target_tenant': 'other-project'}
|
||||
self._target_label: 'other-project'}
|
||||
self.alt_target = {
|
||||
'project_id': self.alt_project_id,
|
||||
'target_tenant': 'other-project'}
|
||||
self._target_label: 'other-project'}
|
||||
self.wildcard_target = {
|
||||
'project_id': self.project_id,
|
||||
'target_tenant': '*'}
|
||||
self._target_label: '*'}
|
||||
self.wildcard_alt_target = {
|
||||
'project_id': self.alt_project_id,
|
||||
'target_tenant': '*'}
|
||||
self._target_label: '*'}
|
||||
|
||||
|
||||
class SystemAdminTests(RbacAPITestCase):
|
||||
|
@ -2795,12 +2795,12 @@ class TestNetworksV2(NeutronDbPluginV2TestCase):
|
||||
ctx, object_id=network['network']['id'],
|
||||
action='access_as_shared',
|
||||
project_id=network['network']['tenant_id'],
|
||||
target_tenant='somebody_else').create()
|
||||
target_project='somebody_else').create()
|
||||
network_obj.NetworkRBAC(
|
||||
ctx, object_id=network['network']['id'],
|
||||
action='access_as_shared',
|
||||
project_id=network['network']['tenant_id'],
|
||||
target_tenant='one_more_somebody_else').create()
|
||||
target_project='one_more_somebody_else').create()
|
||||
res1 = self._create_port(self.fmt,
|
||||
network['network']['id'],
|
||||
webob.exc.HTTPCreated.code,
|
||||
@ -6560,7 +6560,7 @@ class DbModelMixin(object):
|
||||
ctx, object_id=network.id,
|
||||
action='access_as_shared',
|
||||
project_id=network.project_id,
|
||||
target_tenant='*').create()
|
||||
target_project='*').create()
|
||||
net2 = models_v2.Network(name="net_net2", status="OK",
|
||||
admin_state_up=True,
|
||||
mtu=1500)
|
||||
|
@ -40,11 +40,11 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
'object_id': network['network']['id'],
|
||||
'object_type': 'network',
|
||||
'action': action,
|
||||
'target_tenant': target}}
|
||||
'target_project': target}}
|
||||
return policy
|
||||
|
||||
def _setup_networkrbac_and_port(self, network, target_tenant):
|
||||
policy = self._make_networkrbac(network, target_tenant)
|
||||
def _setup_networkrbac_and_port(self, network, target_project):
|
||||
policy = self._make_networkrbac(network, target_project)
|
||||
netrbac = self.plugin.create_rbac_policy(self.context, policy)
|
||||
|
||||
test_port = {'port': {'name': 'test-port',
|
||||
@ -54,8 +54,8 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
'admin_state_up': True,
|
||||
'device_id': 'device_id',
|
||||
'device_owner': 'device_owner',
|
||||
'project_id': target_tenant,
|
||||
'tenant_id': target_tenant}}
|
||||
'project_id': target_project,
|
||||
'tenant_id': target_project}}
|
||||
|
||||
port = self.plugin.create_port(self.context, test_port)
|
||||
return netrbac, port
|
||||
@ -98,13 +98,13 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
orig_target,
|
||||
'access_as_external')
|
||||
netrbac = self.plugin.create_rbac_policy(self.context, policy)
|
||||
update_policy = {'rbac_policy': {'target_tenant': new_target}}
|
||||
update_policy = {'rbac_policy': {'target_project': new_target}}
|
||||
|
||||
netrbac2 = self.plugin.update_rbac_policy(self.context,
|
||||
netrbac['id'],
|
||||
update_policy)
|
||||
|
||||
policy['rbac_policy']['target_tenant'] = new_target
|
||||
policy['rbac_policy']['target_project'] = new_target
|
||||
for k, v in policy['rbac_policy'].items():
|
||||
self.assertEqual(netrbac2[k], v)
|
||||
|
||||
@ -157,20 +157,20 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
with self.network() as net:
|
||||
policy = self._make_networkrbac(net, orig_target)
|
||||
netrbac = self.plugin.create_rbac_policy(self.context, policy)
|
||||
update_policy = {'rbac_policy': {'target_tenant': new_target}}
|
||||
update_policy = {'rbac_policy': {'target_project': new_target}}
|
||||
|
||||
netrbac2 = self.plugin.update_rbac_policy(self.context,
|
||||
netrbac['id'],
|
||||
update_policy)
|
||||
|
||||
policy['rbac_policy']['target_tenant'] = new_target
|
||||
policy['rbac_policy']['target_project'] = new_target
|
||||
for k, v in policy['rbac_policy'].items():
|
||||
self.assertEqual(netrbac2[k], v)
|
||||
|
||||
def test_delete_networkrbac_in_use_fail(self):
|
||||
with self.network() as net:
|
||||
netrbac, _ = self._setup_networkrbac_and_port(
|
||||
network=net, target_tenant='test-tenant-2')
|
||||
network=net, target_project='test-tenant-2')
|
||||
|
||||
self.assertRaises(ext_rbac.RbacPolicyInUse,
|
||||
self.plugin.delete_rbac_policy,
|
||||
@ -179,7 +179,7 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
def test_port_presence_prevents_network_rbac_policy_deletion(self):
|
||||
with self.network() as net:
|
||||
netrbac, port = self._setup_networkrbac_and_port(
|
||||
network=net, target_tenant='alice')
|
||||
network=net, target_project='alice')
|
||||
self.assertRaises(ext_rbac.RbacPolicyInUse,
|
||||
self.plugin.delete_rbac_policy,
|
||||
self.context, netrbac['id'])
|
||||
@ -198,7 +198,7 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
self.context, wild_policy['id'])
|
||||
|
||||
# similarly, we can't update the policy to a different tenant
|
||||
update_policy = {'rbac_policy': {'target_tenant': 'bob'}}
|
||||
update_policy = {'rbac_policy': {'target_project': 'bob'}}
|
||||
self.assertRaises(ext_rbac.RbacPolicyInUse,
|
||||
self.plugin.update_rbac_policy,
|
||||
self.context, wild_policy['id'],
|
||||
@ -253,7 +253,7 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
get_net.return_value = net['network']
|
||||
payload = events.DBEventPayload(
|
||||
self.context, states=(policy,),
|
||||
request_body={'target_tenant': 'new-target-tenant'},
|
||||
request_body={'target_project': 'new-target-tenant'},
|
||||
metadata={'object_type': 'network'})
|
||||
self.plugin.validate_network_rbac_policy_change(
|
||||
None, events.BEFORE_UPDATE, None,
|
||||
@ -264,7 +264,7 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
return _class(id=uuidutils.generate_uuid(),
|
||||
project_id='project_id',
|
||||
object_id=uuidutils.generate_uuid(),
|
||||
target_tenant='target_tenant',
|
||||
target_project='target_project',
|
||||
action=rbac_db_models.ACCESS_SHARED)
|
||||
|
||||
@mock.patch.object(qos_policy_obj.QosPolicyRBAC, 'get_objects')
|
||||
|
@ -143,13 +143,13 @@ class ExtNetDBTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
ctx = context.Context('edinson', 'cavani')
|
||||
model = models_v2.Network
|
||||
txt = ("networkrbacs.action = :action_1 AND "
|
||||
"networkrbacs.target_tenant = :target_tenant_1 OR "
|
||||
"networkrbacs.target_tenant = :target_tenant_2")
|
||||
"networkrbacs.target_project = :target_project_1 OR "
|
||||
"networkrbacs.target_project = :target_project_2")
|
||||
conditions = external_net_db._network_filter_hook(ctx, model, [])
|
||||
self.assertEqual(conditions.__str__(), txt)
|
||||
# Try to concatenate conditions
|
||||
txt2 = (txt.replace('tenant_1', 'tenant_3').
|
||||
replace('tenant_2', 'tenant_4').
|
||||
txt2 = (txt.replace('project_1', 'project_3').
|
||||
replace('project_2', 'project_4').
|
||||
replace('action_1', 'action_2'))
|
||||
conditions = external_net_db._network_filter_hook(ctx, model,
|
||||
conditions)
|
||||
|
@ -28,9 +28,9 @@ from neutron.tests import base as test_base
|
||||
object_data = {
|
||||
'AddressAssociation': '1.0-b92160a3dd2fb7b951adcd2e6ae1665a',
|
||||
'AddressGroup': '1.2-1ddbf0a9f61785033ce31818ac62687e',
|
||||
'AddressGroupRBAC': '1.0-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'AddressGroupRBAC': '1.1-be82ed54376b85ee4f963d479ac48c91',
|
||||
'AddressScope': '1.1-dd0dfdb67775892d3adc090e28e43bd8',
|
||||
'AddressScopeRBAC': '1.0-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'AddressScopeRBAC': '1.1-be82ed54376b85ee4f963d479ac48c91',
|
||||
'Agent': '1.1-64b670752d57b3c7602cb136e0338507',
|
||||
'AllowedAddressPair': '1.0-9f9186b6f952fbf31d257b0458b852c0',
|
||||
'AutoAllocatedTopology': '1.0-74642e58c53bf3610dc224c59f81b242',
|
||||
@ -68,7 +68,7 @@ object_data = {
|
||||
'NetworkDhcpAgentBinding': '1.1-d9443c88809ffa4c45a0a5a48134b54a',
|
||||
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
|
||||
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
|
||||
'NetworkRBAC': '1.2-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'NetworkRBAC': '1.3-be82ed54376b85ee4f963d479ac48c91',
|
||||
'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
|
||||
'NetworkSegmentRange': '1.0-bdec1fffc9058ea676089b1f2f2b3cf3',
|
||||
'NetworkSubnetLock': '1.0-140de39d4b86ae346dc3d70b885bea53',
|
||||
@ -89,7 +89,7 @@ object_data = {
|
||||
'QosMinimumBandwidthRule': '1.5-314c3419f4799067cc31cc319080adff',
|
||||
'QosMinimumPacketRateRule': '1.5-d0516c55aa2f310a2646c7d243cb8620',
|
||||
'QosPacketRateLimitRule': '1.5-18411fa95f54602b8c8a5da2d3194b31',
|
||||
'QosPolicyRBAC': '1.1-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'QosPolicyRBAC': '1.2-be82ed54376b85ee4f963d479ac48c91',
|
||||
'QosRuleType': '1.5-ea51a164013e05d5956d8bf538622b33',
|
||||
'QosRuleTypeDriver': '1.0-7d8cb9f0ef661ac03700eae97118e3db',
|
||||
'QosPolicy': '1.10-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||
@ -110,7 +110,7 @@ object_data = {
|
||||
'RouterRoute': '1.0-07fc5337c801fb8c6ccfbcc5afb45907',
|
||||
'SecurityGroup': '1.5-7eb8e44c327512e7bb1759ab41ede44b',
|
||||
'SecurityGroupPortBinding': '1.0-6879d5c0af80396ef5a72934b6a6ef20',
|
||||
'SecurityGroupRBAC': '1.0-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'SecurityGroupRBAC': '1.1-be82ed54376b85ee4f963d479ac48c91',
|
||||
'SecurityGroupRule': '1.2-27793368d4ac35f2ed6e0bb653c6aaad',
|
||||
'SegmentHostMapping': '1.0-521597cf82ead26217c3bd10738f00f0',
|
||||
'ServiceProfile': '1.0-9beafc9e7d081b8258f3c5cb66ac5eed',
|
||||
@ -119,7 +119,7 @@ object_data = {
|
||||
'SubnetDNSPublishFixedIP': '1.0-db22af6fa20b143986f0cbe06cbfe0ea',
|
||||
'SubnetPool': '1.1-a0e03895d1a6e7b9d4ab7b0ca13c3867',
|
||||
'SubnetPoolPrefix': '1.0-13c15144135eb869faa4a76dc3ee3b6c',
|
||||
'SubnetPoolRBAC': '1.0-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'SubnetPoolRBAC': '1.1-be82ed54376b85ee4f963d479ac48c91',
|
||||
'SubnetServiceType': '1.0-05ae4cdb2a9026a697b143926a1add8c',
|
||||
'SubPort': '1.0-72c8471068db1f0491b5480fe49b52bb',
|
||||
'Tag': '1.0-1a0d20379920ffa3cebfd3e016d2f7a0',
|
||||
|
@ -49,7 +49,7 @@ class FakeNeutronRbacObject(base.NeutronDbObject):
|
||||
|
||||
fields = {
|
||||
'object_id': obj_fields.StringField(),
|
||||
'target_tenant': obj_fields.StringField(),
|
||||
'target_project': obj_fields.StringField(),
|
||||
'action': obj_fields.StringField(),
|
||||
}
|
||||
|
||||
@ -202,10 +202,10 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
def test_validate_rbac_policy_delete_skips_db_object_owner(self,
|
||||
mock_get_object):
|
||||
policy = {'action': rbac_db_models.ACCESS_SHARED,
|
||||
'target_tenant': 'fake_project_id',
|
||||
'target_project': 'fake_project_id',
|
||||
'object_id': 'fake_obj_id',
|
||||
'project_id': 'fake_project_id'}
|
||||
mock_get_object.return_value.project_id = policy['target_tenant']
|
||||
mock_get_object.return_value.project_id = policy['target_project']
|
||||
self._test_validate_rbac_policy_delete_handles_policy(policy)
|
||||
|
||||
@mock.patch.object(obj_db_api, 'get_object')
|
||||
@ -214,14 +214,14 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
def test_validate_rbac_policy_delete_fails_single_project_and_in_use(
|
||||
self, get_bound_project_ids_mock, mock_get_object):
|
||||
policy = {'action': rbac_db_models.ACCESS_SHARED,
|
||||
'target_tenant': 'project_id_shared_with',
|
||||
'target_project': 'project_id_shared_with',
|
||||
'project_id': 'object_owner_project_id',
|
||||
'object_id': 'fake_obj_id'}
|
||||
context = mock.Mock()
|
||||
with mock.patch.object(
|
||||
self._test_class,
|
||||
'_get_db_obj_rbac_entries') as target_tenants_mock:
|
||||
filter_mock = target_tenants_mock.return_value.filter
|
||||
'_get_db_obj_rbac_entries') as target_projects_mock:
|
||||
filter_mock = target_projects_mock.return_value.filter
|
||||
filter_mock.return_value.count.return_value = 0
|
||||
payload = events.DBEventPayload(
|
||||
context,
|
||||
@ -251,7 +251,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
self._test_class._validate_rbac_policy_delete(
|
||||
context=context,
|
||||
obj_id='fake_obj_id',
|
||||
target_tenant='fake_tid1')
|
||||
target_project='fake_tid1')
|
||||
sh_tids.assert_not_called()
|
||||
|
||||
@mock.patch.object(_test_class, '_get_db_obj_rbac_entries')
|
||||
@ -264,7 +264,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
self, get_bound_project_ids_mock, mock_projects_with_shared_access,
|
||||
_get_db_obj_rbac_entries_mock):
|
||||
policy = {'action': rbac_db_models.ACCESS_SHARED,
|
||||
'target_tenant': '*',
|
||||
'target_project': '*',
|
||||
'project_id': 'object_owner_project_id',
|
||||
'object_id': 'fake_obj_id'}
|
||||
context = mock.Mock()
|
||||
@ -294,7 +294,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
obj.update_shared(is_shared_new=True, obj_id=obj_id)
|
||||
get_object_mock.assert_called_with(
|
||||
obj.rbac_db_cls, mock.ANY, object_id=obj_id,
|
||||
target_tenant='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
target_project='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
self.assertFalse(mock_validate_delete.called)
|
||||
self.assertFalse(attach_rbac_mock.called)
|
||||
|
||||
@ -309,7 +309,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
test_neutron_obj.update_shared(is_shared_new=True, obj_id=obj_id)
|
||||
get_object_mock.assert_called_with(
|
||||
test_neutron_obj.rbac_db_cls, mock.ANY, object_id=obj_id,
|
||||
target_tenant='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
target_project='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
|
||||
attach_rbac_mock.assert_called_with(
|
||||
obj_id, test_neutron_obj.obj_context.project_id)
|
||||
@ -329,7 +329,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
obj.update_shared(is_shared_new=False, obj_id=obj_id)
|
||||
get_object_mock.assert_called_with(
|
||||
obj.rbac_db_cls, mock.ANY, object_id=obj_id,
|
||||
target_tenant='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
target_project='*', action=rbac_db_models.ACCESS_SHARED)
|
||||
|
||||
self.assertFalse(attach_rbac_mock.attach_rbac.called)
|
||||
mock_validate_delete.assert_called_with(mock.ANY, obj_id, '*')
|
||||
@ -338,12 +338,12 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
def test_attach_rbac_returns_type(self, create_rbac_mock):
|
||||
obj_id = 'fake_obj_id'
|
||||
project_id = 'fake_project_id'
|
||||
target_tenant = 'fake_target_project'
|
||||
target_project = 'fake_target_project'
|
||||
self._test_class(mock.Mock()).attach_rbac(obj_id, project_id,
|
||||
target_tenant)
|
||||
target_project)
|
||||
rbac_pol = create_rbac_mock.call_args_list[0][0][1]['rbac_policy']
|
||||
self.assertEqual(rbac_pol['object_id'], obj_id)
|
||||
self.assertEqual(rbac_pol['target_tenant'], target_tenant)
|
||||
self.assertEqual(rbac_pol['target_project'], target_project)
|
||||
self.assertEqual(rbac_pol['action'], rbac_db_models.ACCESS_SHARED)
|
||||
self.assertEqual(rbac_pol['object_type'],
|
||||
self._test_class.rbac_db_cls.db_model.object_type)
|
||||
|
@ -100,7 +100,7 @@ class SubnetPoolDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
address_scope_id):
|
||||
filter_mock.assert_called_once()
|
||||
self.assertEqual(
|
||||
"addressscoperbacs.target_tenant IN ('*', '%(project_id)s') "
|
||||
"addressscoperbacs.target_project IN ('*', '%(project_id)s') "
|
||||
"AND addressscoperbacs.object_id = '%(address_scope_id)s'" % {
|
||||
"project_id": project_id,
|
||||
"address_scope_id": address_scope_id,
|
||||
@ -119,7 +119,7 @@ class SubnetPoolDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
payload = mock.Mock(
|
||||
context=context, request_body=dict(
|
||||
object_id="fake_id",
|
||||
target_tenant=fake_project_id
|
||||
target_project=fake_project_id
|
||||
)
|
||||
)
|
||||
fake_address_scope_id = "fake_as_id"
|
||||
@ -151,7 +151,7 @@ class SubnetPoolDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
payload = mock.Mock(
|
||||
context=context, request_body=dict(
|
||||
object_id="fake_id",
|
||||
target_tenant=fake_project_id
|
||||
target_project=fake_project_id
|
||||
)
|
||||
)
|
||||
fake_address_scope_id = "fake_as_id"
|
||||
|
Loading…
x
Reference in New Issue
Block a user