Use NetworkRBAC OVO in neutron/db/db_base_plugin_v2.py

Migrate to use NetworkRBAC OVO in NeutronDBPluginV2.

Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db
Change-Id: I202318b4a4b91d03177d5e9792565e9daa44f9fb
This commit is contained in:
Rodolfo Alonso Hernandez 2018-10-05 10:42:30 +01:00
parent 8790832da1
commit 00c816de01
3 changed files with 44 additions and 33 deletions

View File

@ -37,7 +37,6 @@ from oslo_db import exception as os_db_exc
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import uuidutils
from sqlalchemy import and_
from sqlalchemy import exc as sql_exc
from sqlalchemy import not_
@ -53,13 +52,13 @@ from neutron.db import db_base_plugin_common
from neutron.db import ipam_pluggable_backend
from neutron.db import models_v2
from neutron.db import rbac_db_mixin as rbac_mixin
from neutron.db import rbac_db_models as rbac_db
from neutron.db import standardattrdescription_db as stattr_db
from neutron import ipam
from neutron.ipam import exceptions as ipam_exc
from neutron.ipam import subnet_alloc
from neutron import neutron_plugin_base_v2
from neutron.objects import base as base_obj
from neutron.objects import network as network_obj
from neutron.objects import ports as port_obj
from neutron.objects import subnet as subnet_obj
from neutron.objects import subnetpool as subnetpool_obj
@ -222,30 +221,27 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
def ensure_no_tenant_ports_on_network(self, network_id, net_tenant_id,
tenant_id):
ctx_admin = ctx.get_admin_context()
rb_model = rbac_db.NetworkRBAC
other_rbac_entries = model_query.query_with_hooks(
ctx_admin, rb_model).filter(
and_(rb_model.object_id == network_id,
rb_model.action == 'access_as_shared'))
ports = model_query.query_with_hooks(ctx_admin, models_v2.Port).filter(
models_v2.Port.network_id == network_id)
if tenant_id == '*':
# for the wildcard we need to get all of the rbac entries to
# see if any allow the remaining ports on the network.
other_rbac_entries = other_rbac_entries.filter(
rb_model.target_tenant != tenant_id)
# any port with another RBAC entry covering it or one belonging to
# the same tenant as the network owner is ok
allowed_tenants = [entry['target_tenant']
for entry in other_rbac_entries]
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
in other_rbac_objs
if rbac.target_tenant != tenant_id]
allowed_tenants.append(net_tenant_id)
ports = ports.filter(
~models_v2.Port.tenant_id.in_(allowed_tenants))
else:
# if there is a wildcard rule, we can return early because it
# allows any ports
query = other_rbac_entries.filter(rb_model.target_tenant == '*')
if query.count():
if network_obj.NetworkRBAC.get_object(
ctx_admin, object_id=network_id, action='access_as_shared',
target_tenant='*'):
return
ports = ports.filter(models_v2.Port.tenant_id == tenant_id)
if ports.count():
@ -290,14 +286,10 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
def _validate_projects_have_access_to_network(self, network, project_ids):
ctx_admin = ctx.get_admin_context()
rb_model = rbac_db.NetworkRBAC
other_rbac_entries = model_query.query_with_hooks(
ctx_admin, rb_model).filter(
and_(rb_model.object_id == network.id,
rb_model.action == 'access_as_shared',
rb_model.target_tenant != "*"))
allowed_projects = {entry['target_tenant']
for entry in other_rbac_entries}
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.add(network.project_id)
if project_ids - allowed_projects:
raise n_exc.InvalidSharedSetting(network=network.name)
@ -403,12 +395,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
'status': n.get('status', constants.NET_STATUS_ACTIVE),
'description': n.get('description')}
network = models_v2.Network(**args)
if n['shared']:
entry = rbac_db.NetworkRBAC(
network=network, action='access_as_shared',
target_tenant='*', tenant_id=network['tenant_id'])
context.session.add(entry)
context.session.add(network)
if n['shared']:
np_rbac_args = {'project_id': network.project_id,
'object_id': network.id,
'action': 'access_as_shared',
'target_tenant': '*'}
np_rbac_obj = network_obj.NetworkRBAC(context, **np_rbac_args)
np_rbac_obj.create()
return network
@lib_db_api.retry_if_session_inactive()
@ -428,12 +422,17 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
self._validate_shared_update(context, id, network, n)
update_shared = n.pop('shared')
if update_shared and not entry:
entry = rbac_db.NetworkRBAC(
network=network, action='access_as_shared',
target_tenant='*', tenant_id=network['tenant_id'])
context.session.add(entry)
np_rbac_args = {'project_id': network.project_id,
'object_id': network.id,
'action': 'access_as_shared',
'target_tenant': '*'}
np_rbac_obj = network_obj.NetworkRBAC(context,
**np_rbac_args)
np_rbac_obj.create()
elif not update_shared and entry:
network.rbac_entries.remove(entry)
network_obj.NetworkRBAC.delete_objects(
context, object_id=network.id,
action='access_as_shared', target_tenant='*')
# TODO(ihrachys) Below can be removed when we make sqlalchemy
# event listeners in neutron/db/api.py to refresh expired

View File

@ -14,6 +14,7 @@
from neutron_lib.api.definitions import availability_zone as az_def
from neutron_lib.api.validators import availability_zone as az_validator
from oslo_utils import versionutils
from oslo_versionedobjects import fields as obj_fields
from neutron.db.models import dns as dns_models
@ -34,16 +35,27 @@ from neutron.objects import rbac_db
@base.NeutronObjectRegistry.register
class NetworkRBAC(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Added 'id' and 'project_id'
VERSION = '1.1'
db_model = rbac_db_models.NetworkRBAC
fields = {
'id': common_types.UUIDField(),
'project_id': obj_fields.StringField(),
'object_id': obj_fields.StringField(),
'target_tenant': obj_fields.StringField(),
'action': obj_fields.StringField(),
}
def obj_make_compatible(self, primitive, target_version):
_target_version = versionutils.convert_version_to_tuple(target_version)
if _target_version < (1, 1):
standard_fields = ['id', 'project_id']
for f in standard_fields:
primitive.pop(f, None)
@base.NeutronObjectRegistry.register
class NetworkDhcpAgentBinding(base.NeutronDbObject):

View File

@ -60,7 +60,7 @@ object_data = {
'NetworkDhcpAgentBinding': '1.0-6eeceb5fb4335cd65a305016deb41c68',
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
'NetworkRBAC': '1.0-c8a67f39809c5a3c8c7f26f2f2c620b2',
'NetworkRBAC': '1.1-7f8baaf9ea4257a26408454ad0065adb',
'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
'Port': '1.4-1b6183bccfc2cd210919a1a72faefce1',
'PortBinding': '1.0-3306deeaa6deb01e33af06777d48d578',