Admin or Provider tenant to own implicit SCIs
Whenever a Redirect action is provided/consumed GBP, the implicitly created SCI could be owned by different tenants depending on the actor triggering it. To make this consistent, this patch proposes to have a single configurable admin tenant that will own all the chain resources. When the said tenant is not configured, the provider PTG's tenant will be used instead. Change-Id: I4862b87c41b48344a53dbf72c004a8dc18c2aa99 Closes-Bug: 1432816
This commit is contained in:
parent
dab68def4a
commit
3becb34638
|
@ -2,3 +2,14 @@
|
|||
|
||||
# DNS nameservers to be used configured in the PTG subnets by this driver.
|
||||
# dns_nameservers = 8.8.8.7, 8.8.8.8
|
||||
|
||||
# Chain owner username. If set, will be used in place of the Neutron service
|
||||
# admin for retrieving tenant owner information through Keystone.
|
||||
# chain_owner_user = <username>
|
||||
|
||||
# Chain owner password.
|
||||
# chain_owner_password = <secret>
|
||||
|
||||
# Name of the Tenant that will own the service chain instances for this driver.
|
||||
# Leave empty for provider owned chains.
|
||||
# chain_owner_tenant_name = <tenant_name>
|
|
@ -0,0 +1,15 @@
|
|||
[simplechain]
|
||||
# Heat server address to create services specified in the service chain
|
||||
# heat_uri = http://localhost:8004/v1
|
||||
|
||||
# CA file for heatclient to verify server certificates
|
||||
# heat_ca_certificates_file =
|
||||
|
||||
# Boolean to control ignoring SSL errors on the heat url
|
||||
# heat_api_insecure = False
|
||||
|
||||
# Number of attempts to retry for stack deletion
|
||||
# stack_delete_retries = 5
|
||||
|
||||
# Wait time between two successive stack delete retries
|
||||
# stack_delete_retry_wait = 3
|
|
@ -0,0 +1,6 @@
|
|||
[servicechain]
|
||||
|
||||
# An ordered list of service chain drivers entrypoints to be loaded from the
|
||||
# gbpservice.neutron.servicechain.servicechain_drivers namespace.
|
||||
|
||||
# servicechain_drivers=simplechain_driver,oneconvergence_servicechain_driver
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
import contextlib
|
||||
|
||||
from neutron import context as n_ctx
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
from stevedore import driver
|
||||
|
@ -44,6 +46,12 @@ def load_plugin(namespace, plugin):
|
|||
return plugin_class()
|
||||
|
||||
|
||||
def admin_context(context):
|
||||
admin_context = n_ctx.get_admin_context()
|
||||
admin_context._session = context.session
|
||||
return admin_context
|
||||
|
||||
|
||||
class DictClass(dict):
|
||||
|
||||
def __getattr__(self, item):
|
||||
|
@ -51,3 +59,20 @@ class DictClass(dict):
|
|||
|
||||
__setattr__ = dict.__setattr__
|
||||
__delattr__ = dict.__delattr__
|
||||
|
||||
|
||||
def get_keystone_creds():
|
||||
keystone_conf = cfg.CONF.keystone_authtoken
|
||||
user = keystone_conf.admin_user
|
||||
pw = keystone_conf.admin_password
|
||||
tenant = keystone_conf.admin_tenant_name
|
||||
if keystone_conf.get('auth_uri'):
|
||||
auth_url = keystone_conf.auth_uri.rstrip('/')
|
||||
if not auth_url.endswith('/v2.0'):
|
||||
auth_url += '/v2.0'
|
||||
else:
|
||||
auth_url = ('%s://%s:%s/v2.0' % (
|
||||
keystone_conf.auth_protocol,
|
||||
keystone_conf.auth_host,
|
||||
keystone_conf.auth_port))
|
||||
return user, pw, tenant, auth_url + '/'
|
||||
|
|
|
@ -356,10 +356,9 @@ class LocalAPI(object):
|
|||
return self._update_resource(self._servicechain_plugin, plugin_context,
|
||||
'servicechain_instance', sci_id, attrs)
|
||||
|
||||
def _delete_servicechain_instance(self, context, sci_id):
|
||||
def _delete_servicechain_instance(self, plugin_context, sci_id):
|
||||
try:
|
||||
self._delete_resource(self._servicechain_plugin,
|
||||
context._plugin_context,
|
||||
self._delete_resource(self._servicechain_plugin, plugin_context,
|
||||
'servicechain_instance', sci_id)
|
||||
except sc_ext.ServiceChainInstanceNotFound:
|
||||
# SC could have been already deleted
|
||||
|
|
|
@ -1355,6 +1355,11 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
|
|||
marker_obj=marker_obj,
|
||||
page_reverse=page_reverse)
|
||||
|
||||
@log.log
|
||||
def get_l3_policies_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, L3Policy,
|
||||
filters=filters)
|
||||
|
||||
@log.log
|
||||
def create_network_service_policy(self, context, network_service_policy):
|
||||
nsp = network_service_policy['network_service_policy']
|
||||
|
|
|
@ -234,6 +234,11 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
context.session.add(pt_db)
|
||||
return self._make_policy_target_dict(pt_db)
|
||||
|
||||
@log.log
|
||||
def get_policy_targets_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, PolicyTargetMapping,
|
||||
filters=filters)
|
||||
|
||||
@log.log
|
||||
def get_policy_targets(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
|
@ -331,6 +336,11 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
marker_obj=marker_obj,
|
||||
page_reverse=page_reverse)
|
||||
|
||||
@log.log
|
||||
def get_l2_policies_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, L2PolicyMapping,
|
||||
filters=filters)
|
||||
|
||||
@log.log
|
||||
def create_l3_policy(self, context, l3_policy):
|
||||
l3p = l3_policy['l3_policy']
|
||||
|
@ -426,6 +436,10 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
marker_obj=marker_obj,
|
||||
page_reverse=page_reverse)
|
||||
|
||||
def get_external_segments_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, ExternalSegmentMapping,
|
||||
filters=filters)
|
||||
|
||||
@log.log
|
||||
def create_nat_pool(self, context, nat_pool):
|
||||
np = nat_pool['nat_pool']
|
||||
|
|
|
@ -1 +1 @@
|
|||
1fadeb573886
|
||||
c2a9d04c8cef
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""Admin owns SCI (admin_owns_sci)
|
||||
|
||||
Revision ID: c2a9d04c8cef
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c2a9d04c8cef'
|
||||
down_revision = '1fadeb573886'
|
||||
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
op.add_column(
|
||||
'gpm_ptgs_servicechain_mapping',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column('gpm_ptgs_servicechain_mapping', 'tenant_id')
|
|
@ -34,7 +34,6 @@ from gbpservice.neutron.services.grouppolicy.common import (
|
|||
# The code below is a monkey patch of key Neutron's modules. This is needed for
|
||||
# the GBP service to be loaded correctly. GBP extensions' path is added
|
||||
# to Neutron's so that it's found at extension scanning time.
|
||||
|
||||
extensions.append_api_extensions_path(gbpservice.neutron.extensions.__path__)
|
||||
constants.GROUP_POLICY = "GROUP_POLICY"
|
||||
constants.COMMON_PREFIXES["GROUP_POLICY"] = "/grouppolicy"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import securitygroups_db
|
||||
|
||||
|
||||
# Monkey patch create floatingip to allow subnet_id to be specified.
|
||||
|
@ -94,3 +95,37 @@ def get_assoc_data(self, context, fip, floating_network_id):
|
|||
return fip['port_id'], internal_ip_address, router_id
|
||||
|
||||
l3_db.L3_NAT_dbonly_mixin.get_assoc_data = get_assoc_data
|
||||
|
||||
|
||||
# REVISIT(ivar): Neutron adds a tenant filter on SG lookup for a given port,
|
||||
# this breaks our service chain plumbing model so for now we should monkey
|
||||
# patch the specific method. A follow up with the Neutron team is needed to
|
||||
# figure out the reason for this and how to proceed for future releases.
|
||||
def _get_security_groups_on_port(self, context, port):
|
||||
"""Check that all security groups on port belong to tenant.
|
||||
|
||||
:returns: all security groups IDs on port belonging to tenant.
|
||||
"""
|
||||
p = port['port']
|
||||
if not securitygroups_db.attributes.is_attr_set(
|
||||
p.get(securitygroups_db.ext_sg.SECURITYGROUPS)):
|
||||
return
|
||||
if p.get('device_owner') and p['device_owner'].startswith('network:'):
|
||||
return
|
||||
|
||||
port_sg = p.get(securitygroups_db.ext_sg.SECURITYGROUPS, [])
|
||||
filters = {'id': port_sg}
|
||||
valid_groups = set(g['id'] for g in
|
||||
self.get_security_groups(context, fields=['id'],
|
||||
filters=filters))
|
||||
|
||||
requested_groups = set(port_sg)
|
||||
port_sg_missing = requested_groups - valid_groups
|
||||
if port_sg_missing:
|
||||
raise securitygroups_db.ext_sg.SecurityGroupNotFound(
|
||||
id=', '.join(port_sg_missing))
|
||||
|
||||
return requested_groups
|
||||
|
||||
securitygroups_db.SecurityGroupDbMixin._get_security_groups_on_port = (
|
||||
_get_security_groups_on_port)
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
import netaddr
|
||||
import operator
|
||||
|
||||
from keystoneclient import exceptions as k_exceptions
|
||||
from keystoneclient.v2_0 import client as k_client
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import constants as const
|
||||
from neutron.common import exceptions as n_exc
|
||||
|
@ -24,6 +26,7 @@ from neutron.extensions import securitygroup as ext_sg
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import excutils
|
||||
import sqlalchemy as sa
|
||||
|
||||
from gbpservice.common import utils
|
||||
|
@ -40,6 +43,24 @@ from gbpservice.neutron.services.grouppolicy.common import exceptions as exc
|
|||
LOG = logging.getLogger(__name__)
|
||||
DEFAULT_SG_PREFIX = 'gbp_%s'
|
||||
|
||||
group_policy_opts = [
|
||||
cfg.StrOpt('chain_owner_user',
|
||||
help=_("Chain owner username. If set, will be used in "
|
||||
"place of the Neutron service admin for retrieving "
|
||||
"tenant owner information through Keystone."),
|
||||
default=''),
|
||||
cfg.StrOpt('chain_owner_password',
|
||||
help=_("Chain owner password."), default='',
|
||||
secret=True),
|
||||
cfg.StrOpt('chain_owner_tenant_name',
|
||||
help=_("Name of the Tenant that will own the service chain "
|
||||
"instances for this driver. Leave empty for provider "
|
||||
"owned chains."), default=''),
|
||||
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(group_policy_opts, "resource_mapping")
|
||||
|
||||
|
||||
opts = [
|
||||
cfg.ListOpt('dns_nameservers',
|
||||
|
@ -101,7 +122,7 @@ class PolicyRuleSetSGsMapping(model_base.BASEV2):
|
|||
sa.ForeignKey('securitygroups.id'))
|
||||
|
||||
|
||||
class PtgServiceChainInstanceMapping(model_base.BASEV2):
|
||||
class PtgServiceChainInstanceMapping(model_base.BASEV2, models_v2.HasTenant):
|
||||
"""Policy Target Group to ServiceChainInstance mapping DB."""
|
||||
|
||||
__tablename__ = 'gpm_ptgs_servicechain_mapping'
|
||||
|
@ -173,6 +194,41 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
@log.log
|
||||
def initialize(self):
|
||||
self._cached_agent_notifier = None
|
||||
self.chain_owner = ResourceMappingDriver.chain_tenant_id(reraise=True)
|
||||
|
||||
@staticmethod
|
||||
def chain_tenant_id(reraise=False):
|
||||
keystone = ResourceMappingDriver.chain_tenant_keystone_client()
|
||||
if keystone:
|
||||
tenant = cfg.CONF.resource_mapping.chain_owner_tenant_name
|
||||
try:
|
||||
# Can it be retrieved directly, without a further keystone
|
||||
# call?
|
||||
tenant = keystone.tenants.find(name=tenant)
|
||||
return tenant.id
|
||||
except k_exceptions.NotFound:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error(_('No tenant with name %s exists.'), tenant)
|
||||
except k_exceptions.NoUniqueMatch:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error(_('Multiple tenants matches found for %s'),
|
||||
tenant)
|
||||
|
||||
@staticmethod
|
||||
def chain_tenant_keystone_client():
|
||||
chain_user = cfg.CONF.resource_mapping.chain_owner_user
|
||||
user, pwd, tenant, auth_url = utils.get_keystone_creds()
|
||||
user = (chain_user or user)
|
||||
pwd = (cfg.CONF.resource_mapping.chain_owner_password or
|
||||
(pwd if not chain_user else ''))
|
||||
|
||||
# Tenant must be configured in the resource_mapping section, provider
|
||||
# owner will be used otherwise.
|
||||
tenant = cfg.CONF.resource_mapping.chain_owner_tenant_name
|
||||
|
||||
if tenant:
|
||||
return k_client.Client(username=user, password=pwd,
|
||||
auth_url=auth_url)
|
||||
|
||||
def _reject_shared(self, object, type):
|
||||
if object.get('shared'):
|
||||
|
@ -512,7 +568,6 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
"network_service_policy_id")
|
||||
if not network_service_policy_id:
|
||||
return
|
||||
|
||||
nsp = context._plugin.get_network_service_policy(
|
||||
context._plugin_context, network_service_policy_id)
|
||||
nsp_params = nsp.get("network_service_params")
|
||||
|
@ -937,11 +992,16 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
context.original['direction'] != context.current['direction']):
|
||||
sc_instances = (
|
||||
self._servicechain_plugin.get_servicechain_instances(
|
||||
context._plugin_context,
|
||||
context._plugin_context.elevated(),
|
||||
filters={'classifier_id': [context.current['id']]}))
|
||||
for sc_instance in sc_instances:
|
||||
cmap = self._get_ptg_servicechain_mapping(
|
||||
context._plugin_context.session,
|
||||
servicechain_instance_id=sc_instance['id'])
|
||||
ctx = self._get_chain_admin_context(context._plugin_context,
|
||||
cmap[0].tenant_id)
|
||||
self._servicechain_plugin.notify_chain_parameters_updated(
|
||||
context._plugin_context, sc_instance['id'])
|
||||
ctx, sc_instance['id'])
|
||||
|
||||
@log.log
|
||||
def delete_policy_classifier_precommit(self, context):
|
||||
|
@ -1856,10 +1916,11 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
x == context.original['action_value'] else
|
||||
x for x in old_specs]
|
||||
self._update_servicechain_instance(
|
||||
context, servicechain_instance.servicechain_instance_id,
|
||||
context._plugin_context,
|
||||
servicechain_instance.servicechain_instance_id,
|
||||
sc_specs=new_specs)
|
||||
|
||||
def _update_servicechain_instance(self, context, sc_instance_id,
|
||||
def _update_servicechain_instance(self, plugin_context, sc_instance_id,
|
||||
classifier_id=None, sc_specs=None):
|
||||
sc_instance_update_data = {}
|
||||
if sc_specs:
|
||||
|
@ -1867,7 +1928,9 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
if classifier_id:
|
||||
sc_instance_update_data.update({'classifier_id': classifier_id})
|
||||
super(ResourceMappingDriver, self)._update_servicechain_instance(
|
||||
context._plugin_context, sc_instance_id, sc_instance_update_data)
|
||||
self._get_chain_admin_context(
|
||||
plugin_context, instance_id=sc_instance_id),
|
||||
sc_instance_id, sc_instance_update_data)
|
||||
|
||||
def _get_rule_ids_for_actions(self, context, action_id):
|
||||
policy_rule_qry = context.session.query(
|
||||
|
@ -1940,41 +2003,42 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
context, ptg_providing_prs, ptg_consuming_prs,
|
||||
spec_id,
|
||||
parent_spec_id, classifier_id,
|
||||
hierarchial_classifier_mismatch)
|
||||
hierarchial_classifier_mismatch, policy_rule_set)
|
||||
|
||||
def _create_or_update_chain(self, context, provider, consumer, spec_id,
|
||||
parent_spec_id, classifier_id,
|
||||
hierarchial_classifier_mismatch):
|
||||
hierarchial_classifier_mismatch, prs_id):
|
||||
ptg_chain_map = self._get_ptg_servicechain_mapping(
|
||||
context._plugin_context.session, provider, consumer)
|
||||
if ptg_chain_map:
|
||||
if hierarchial_classifier_mismatch or not spec_id:
|
||||
ctx = self._get_chain_admin_context(
|
||||
context._plugin_context,
|
||||
tenant_id=ptg_chain_map[0].tenant_id)
|
||||
self._delete_servicechain_instance(
|
||||
context, ptg_chain_map[0].servicechain_instance_id)
|
||||
ctx, ptg_chain_map[0].servicechain_instance_id)
|
||||
else:
|
||||
sc_specs = [spec_id]
|
||||
if parent_spec_id:
|
||||
sc_specs.insert(0, parent_spec_id)
|
||||
# One Chain between a unique pair of provider and consumer
|
||||
|
||||
self._update_servicechain_instance(
|
||||
context,
|
||||
context._plugin_context,
|
||||
ptg_chain_map[0].servicechain_instance_id,
|
||||
classifier_id=classifier_id,
|
||||
sc_specs=sc_specs)
|
||||
elif spec_id and not hierarchial_classifier_mismatch:
|
||||
sc_instance = self._create_servicechain_instance(
|
||||
context, spec_id,
|
||||
parent_spec_id, provider,
|
||||
consumer, classifier_id)
|
||||
self._set_ptg_servicechain_instance_mapping(
|
||||
context._plugin_context.session,
|
||||
provider, consumer,
|
||||
sc_instance['id'])
|
||||
self._create_servicechain_instance(context, spec_id,
|
||||
parent_spec_id, provider,
|
||||
consumer, classifier_id, prs_id)
|
||||
|
||||
def _cleanup_redirect_action(self, context):
|
||||
for ptg_chain in context.ptg_chain_map:
|
||||
ctx = self._get_chain_admin_context(context._plugin_context,
|
||||
tenant_id=ptg_chain.tenant_id)
|
||||
self._delete_servicechain_instance(
|
||||
context, ptg_chain.servicechain_instance_id)
|
||||
ctx, ptg_chain.servicechain_instance_id)
|
||||
|
||||
def _restore_ip_to_allocation_pool(self, context, subnet_id, ip_address):
|
||||
# TODO(Magesh):Pass subnets and loop on subnets. Better to add logic
|
||||
|
@ -2026,18 +2090,30 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
def _create_servicechain_instance(self, context, servicechain_spec,
|
||||
parent_servicechain_spec,
|
||||
provider_ptg_id, consumer_ptg_id,
|
||||
classifier_id,
|
||||
classifier_id, policy_rule_set,
|
||||
config_params=None):
|
||||
sc_spec = [servicechain_spec]
|
||||
if parent_servicechain_spec:
|
||||
sc_spec.insert(0, parent_servicechain_spec)
|
||||
config_param_values = {}
|
||||
ptg = context._plugin.get_policy_target_group(
|
||||
context._plugin_context, provider_ptg_id)
|
||||
network_service_policy_id = ptg.get("network_service_policy_id")
|
||||
provider_ptg = context._plugin.get_policy_target_group(
|
||||
utils.admin_context(context._plugin_context), provider_ptg_id)
|
||||
p_ctx = self._get_chain_admin_context(
|
||||
context._plugin_context,
|
||||
provider_tenant_id=provider_ptg['tenant_id'])
|
||||
session = context._plugin_context.session
|
||||
if consumer_ptg_id:
|
||||
try:
|
||||
consumer_ptg = context._plugin.get_policy_target_group(
|
||||
p_ctx, consumer_ptg_id)
|
||||
except gp_ext.PolicyTargetGroupNotFound:
|
||||
consumer_ptg = context._plugin.get_external_policy(
|
||||
p_ctx, consumer_ptg_id)
|
||||
network_service_policy_id = provider_ptg.get(
|
||||
"network_service_policy_id")
|
||||
if network_service_policy_id:
|
||||
nsp = context._plugin.get_network_service_policy(
|
||||
context._plugin_context, network_service_policy_id)
|
||||
p_ctx, network_service_policy_id)
|
||||
service_params = nsp.get("network_service_params")
|
||||
for service_parameter in service_params:
|
||||
param_type = service_parameter.get("type")
|
||||
|
@ -2046,7 +2122,7 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
key = service_parameter.get("name")
|
||||
servicepolicy_ptg_ip_map = (
|
||||
self._get_ptg_policy_ipaddress_mapping(
|
||||
context._plugin_context.session, provider_ptg_id))
|
||||
session, provider_ptg_id))
|
||||
servicepolicy_ip = servicepolicy_ptg_ip_map.get(
|
||||
"ipaddress")
|
||||
config_param_values[key] = servicepolicy_ip
|
||||
|
@ -2060,8 +2136,11 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
for fip_map in fip_maps:
|
||||
servicepolicy_fip_ids.append(fip_map.floatingip_id)
|
||||
config_param_values[key] = servicepolicy_fip_ids
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'gbp_' + ptg['name'],
|
||||
name = 'gbp_%s_%s_%s' % (policy_rule_set['name'], provider_ptg['name'],
|
||||
consumer_ptg['name'] if consumer_ptg else '')
|
||||
|
||||
attrs = {'tenant_id': p_ctx.tenant,
|
||||
'name': name,
|
||||
'description': "",
|
||||
'servicechain_specs': sc_spec,
|
||||
'provider_ptg_id': provider_ptg_id,
|
||||
|
@ -2069,9 +2148,13 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
'management_ptg_id': None,
|
||||
'classifier_id': classifier_id,
|
||||
'config_param_values': jsonutils.dumps(config_param_values)}
|
||||
return super(
|
||||
sc_instance = super(
|
||||
ResourceMappingDriver, self)._create_servicechain_instance(
|
||||
context._plugin_context, attrs)
|
||||
p_ctx, attrs)
|
||||
self._set_ptg_servicechain_instance_mapping(
|
||||
session, provider_ptg_id, consumer_ptg_id, sc_instance['id'],
|
||||
p_ctx.tenant)
|
||||
return sc_instance
|
||||
|
||||
# Do Not Pass floating_ip_address to this method until after Kilo Release
|
||||
def _create_floatingip(self, plugin_context, tenant_id, ext_net_id,
|
||||
|
@ -2540,27 +2623,36 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
|
||||
def _set_ptg_servicechain_instance_mapping(self, session, provider_ptg_id,
|
||||
consumer_ptg_id,
|
||||
servicechain_instance_id):
|
||||
servicechain_instance_id,
|
||||
provider_tenant_id):
|
||||
with session.begin(subtransactions=True):
|
||||
mapping = PtgServiceChainInstanceMapping(
|
||||
provider_ptg_id=provider_ptg_id,
|
||||
consumer_ptg_id=consumer_ptg_id,
|
||||
servicechain_instance_id=servicechain_instance_id)
|
||||
servicechain_instance_id=servicechain_instance_id,
|
||||
tenant_id=provider_tenant_id)
|
||||
session.add(mapping)
|
||||
|
||||
def _get_ptg_servicechain_mapping(self, session, provider_ptg_id,
|
||||
consumer_ptg_id):
|
||||
def _get_ptg_servicechain_mapping(self, session, provider_ptg_id=None,
|
||||
consumer_ptg_id=None, tenant_id=None,
|
||||
servicechain_instance_id=None):
|
||||
with session.begin(subtransactions=True):
|
||||
query = session.query(PtgServiceChainInstanceMapping)
|
||||
if provider_ptg_id:
|
||||
query = query.filter_by(provider_ptg_id=provider_ptg_id)
|
||||
if consumer_ptg_id:
|
||||
query = query.filter_by(consumer_ptg_id=consumer_ptg_id)
|
||||
if servicechain_instance_id:
|
||||
query = query.filter_by(
|
||||
servicechain_instance_id=servicechain_instance_id)
|
||||
if tenant_id:
|
||||
query = query.filter_by(consumer_ptg_id=tenant_id)
|
||||
all = query.all()
|
||||
return [utils.DictClass([('provider_ptg_id', x.provider_ptg_id),
|
||||
('consumer_ptg_id', x.consumer_ptg_id),
|
||||
('servicechain_instance_id',
|
||||
x.servicechain_instance_id)])
|
||||
x.servicechain_instance_id),
|
||||
('tenant_id', x.tenant_id)])
|
||||
for x in all]
|
||||
|
||||
def _get_ep_cidr_list(self, context, ep):
|
||||
|
@ -2737,3 +2829,25 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||
ptg_subnet_id=",".join(ptg.get('subnets')),
|
||||
port_subnet_id=port_subnet_id,
|
||||
policy_target_group_id=ptg_id)
|
||||
|
||||
def _get_chain_admin_context(self, plugin_context, tenant_id=None,
|
||||
provider_tenant_id=None, instance_id=None):
|
||||
ctx = plugin_context.elevated()
|
||||
# REVISIT(Ivar): Any particular implication when a provider owned PT
|
||||
# exist in the consumer PTG? Especially when the consumer PTG belongs
|
||||
# to another tenant? We may want to consider a strong convention
|
||||
# for reference plumbers to absolutely avoid this kind of inter tenant
|
||||
# object creation when the owner is the provider (in which case, the
|
||||
# context can as well be a normal context without admin capabilities).
|
||||
ctx.tenant_id = None
|
||||
if instance_id:
|
||||
cmap = self._get_ptg_servicechain_mapping(
|
||||
ctx.session, servicechain_instance_id=instance_id)
|
||||
if cmap:
|
||||
ctx.tenant_id = cmap[0].tenant_id
|
||||
if not ctx.tenant_id:
|
||||
ctx.tenant_id = tenant_id or self.chain_owner or provider_tenant_id
|
||||
if self.chain_owner == ctx.tenant_id:
|
||||
ctx.auth_token = self.chain_tenant_keystone_client().get_token(
|
||||
self.chain_owner)
|
||||
return ctx
|
||||
|
|
|
@ -131,7 +131,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
|||
for linked in linked_objects:
|
||||
link_ids.add(linked['id'])
|
||||
GroupPolicyPlugin._verify_sharing_consistency(
|
||||
obj, linked, identity, ref_type)
|
||||
obj, linked, identity, ref_type, context.is_admin)
|
||||
# Check for missing references
|
||||
missing = set(ids) - link_ids
|
||||
if missing:
|
||||
|
@ -288,20 +288,22 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
|||
spec = self.servicechain_plugin.get_servicechain_spec(
|
||||
context, action['action_value'])
|
||||
GroupPolicyPlugin._verify_sharing_consistency(
|
||||
action, spec, 'polocy_action', 'servicechain_spec')
|
||||
action, spec, 'policy_action', 'servicechain_spec',
|
||||
context.is_admin)
|
||||
|
||||
@staticmethod
|
||||
def _verify_sharing_consistency(primary, reference, primary_type,
|
||||
reference_type):
|
||||
reference_type, is_admin):
|
||||
if not reference.get('shared'):
|
||||
if primary.get('shared'):
|
||||
raise gp_exc.SharedResourceReferenceError(
|
||||
res_type=primary_type, res_id=primary['id'],
|
||||
ref_type=reference_type, ref_id=reference['id'])
|
||||
if primary.get('tenant_id') != reference.get('tenant_id'):
|
||||
raise gp_exc.InvalidCrossTenantReference(
|
||||
res_type=primary_type, res_id=primary['id'],
|
||||
ref_type=reference_type, ref_id=reference['id'])
|
||||
if not is_admin:
|
||||
if primary.get('tenant_id') != reference.get('tenant_id'):
|
||||
raise gp_exc.InvalidCrossTenantReference(
|
||||
res_type=primary_type, res_id=primary['id'],
|
||||
ref_type=reference_type, ref_id=reference['id'])
|
||||
|
||||
def __init__(self):
|
||||
self.extension_manager = ext_manager.ExtensionManager()
|
||||
|
@ -484,7 +486,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
|||
policy_target_group = self.get_policy_target_group(
|
||||
context, policy_target_group_id)
|
||||
pt_ids = policy_target_group['policy_targets']
|
||||
for pt in self.get_policy_targets(context, {'id': pt_ids}):
|
||||
for pt in self.get_policy_targets(context.elevated(),
|
||||
{'id': pt_ids}):
|
||||
if pt['port_id'] and self._is_port_bound(pt['port_id']) or (
|
||||
self._is_service_target(context, pt['id'])):
|
||||
raise gp_exc.PolicyTargetGroupInUse(
|
||||
|
|
|
@ -15,6 +15,7 @@ import time
|
|||
|
||||
from heatclient import client as heat_client
|
||||
from heatclient import exc as heat_exc
|
||||
from keystoneclient.v2_0 import client as keyclient
|
||||
from neutron.common import log
|
||||
from neutron.db import model_base
|
||||
from neutron import manager
|
||||
|
@ -416,11 +417,16 @@ class HeatClient:
|
|||
|
||||
def __init__(self, context, password=None):
|
||||
api_version = "1"
|
||||
endpoint = "%s/%s" % (cfg.CONF.simplechain.heat_uri, context.tenant)
|
||||
self.tenant = context.tenant
|
||||
|
||||
self._keystone = None
|
||||
endpoint = "%s/%s" % (cfg.CONF.simplechain.heat_uri, self.tenant)
|
||||
kwargs = {
|
||||
'token': context.auth_token,
|
||||
'token': self._get_auth_token(self.tenant),
|
||||
'username': context.user_name,
|
||||
'password': password
|
||||
'password': password,
|
||||
'cacert': cfg.CONF.simplechain.heat_ca_certificates_file,
|
||||
'insecure': cfg.CONF.simplechain.heat_api_insecure
|
||||
}
|
||||
self.client = heat_client.Client(api_version, endpoint, **kwargs)
|
||||
self.stacks = self.client.stacks
|
||||
|
@ -445,3 +451,25 @@ class HeatClient:
|
|||
|
||||
def get(self, stack_id):
|
||||
return self.stacks.get(stack_id)
|
||||
|
||||
@property
|
||||
def keystone(self):
|
||||
if not self._keystone:
|
||||
keystone_conf = cfg.CONF.keystone_authtoken
|
||||
if keystone_conf.get('auth_uri'):
|
||||
auth_url = keystone_conf.auth_uri
|
||||
else:
|
||||
auth_url = ('%s://%s:%s/v2.0/' % (
|
||||
keystone_conf.auth_protocol,
|
||||
keystone_conf.auth_host,
|
||||
keystone_conf.auth_port))
|
||||
user = (keystone_conf.get('admin_user') or keystone_conf.username)
|
||||
pw = (keystone_conf.get('admin_password') or
|
||||
keystone_conf.password)
|
||||
self._keystone = keyclient.Client(
|
||||
username=user, password=pw, auth_url=auth_url,
|
||||
tenant_id=self.tenant)
|
||||
return self._keystone
|
||||
|
||||
def _get_auth_token(self, tenant):
|
||||
return self.keystone.get_token(tenant)
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron import context as n_context
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants as pconst
|
||||
|
||||
from gbpservice.common import utils
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import model
|
||||
|
||||
|
||||
|
@ -23,26 +23,26 @@ def get_gbp_plugin():
|
|||
|
||||
def get_node_driver_context(sc_plugin, context, sc_instance,
|
||||
current_node, original_node=None,
|
||||
service_targets=None):
|
||||
management_group=None, service_targets=None):
|
||||
admin_context = utils.admin_context(context)
|
||||
specs = sc_plugin.get_servicechain_specs(
|
||||
context, filters={'id': sc_instance['servicechain_specs']})
|
||||
admin_context, filters={'id': sc_instance['servicechain_specs']})
|
||||
position = _calculate_node_position(specs, current_node['id'])
|
||||
provider, _ = _get_ptg_or_ep(
|
||||
context, sc_instance['provider_ptg_id'])
|
||||
admin_context, sc_instance['provider_ptg_id'])
|
||||
consumer, is_consumer_external = _get_ptg_or_ep(
|
||||
context, sc_instance['consumer_ptg_id'])
|
||||
admin_context, sc_instance['consumer_ptg_id'])
|
||||
management, _ = _get_ptg_or_ep(context, sc_instance['management_ptg_id'])
|
||||
classifier = get_gbp_plugin().get_policy_classifier(
|
||||
context, sc_instance['classifier_id'])
|
||||
|
||||
admin_context, sc_instance['classifier_id'])
|
||||
current_profile = sc_plugin.get_service_profile(
|
||||
context, current_node['service_profile_id'])
|
||||
admin_context, current_node['service_profile_id'])
|
||||
original_profile = sc_plugin.get_service_profile(
|
||||
context,
|
||||
admin_context,
|
||||
original_node['service_profile_id']) if original_node else None
|
||||
if not service_targets:
|
||||
service_targets = model.get_service_targets(
|
||||
context.session, servicechain_instance_id=sc_instance['id'],
|
||||
admin_context.session, servicechain_instance_id=sc_instance['id'],
|
||||
position=position, servicechain_node_id=current_node['id'])
|
||||
|
||||
return NodeDriverContext(sc_plugin=sc_plugin,
|
||||
|
@ -147,7 +147,7 @@ class NodeDriverContext(object):
|
|||
@property
|
||||
def admin_context(self):
|
||||
if not self._admin_context:
|
||||
self._admin_context = n_context.get_admin_context()
|
||||
self._admin_context = utils.admin_context(self.plugin_context)
|
||||
return self._admin_context
|
||||
|
||||
@property
|
||||
|
|
|
@ -283,7 +283,9 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||
self._update_chains_pt_modified(context, policy_target, 'removed')
|
||||
|
||||
def _update_chains_pt_modified(self, context, policy_target, action):
|
||||
scis = self._get_instances_from_policy_target(context, policy_target)
|
||||
admin_context = utils.admin_context(context)
|
||||
scis = self._get_instances_from_policy_target(
|
||||
admin_context, policy_target)
|
||||
|
||||
for sci in scis:
|
||||
updaters = self._get_scheduled_drivers(context, sci, 'update')
|
||||
|
@ -317,6 +319,7 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||
"failed, %s"), ex.message)
|
||||
|
||||
def _get_instance_nodes(self, context, instance):
|
||||
context = utils.admin_context(context)
|
||||
if not instance['servicechain_specs']:
|
||||
return []
|
||||
specs = self.get_servicechain_spec(
|
||||
|
@ -324,6 +327,7 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||
return self.get_servicechain_nodes(context, {'id': specs['nodes']})
|
||||
|
||||
def _get_node_instances(self, context, node):
|
||||
context = utils.admin_context(context)
|
||||
specs = self.get_servicechain_specs(
|
||||
context, {'id': node['servicechain_specs']})
|
||||
result = []
|
||||
|
|
|
@ -113,8 +113,8 @@ class NodePlumberBase(object):
|
|||
|
||||
for pt in pts:
|
||||
try:
|
||||
gbp_plugin.delete_policy_target(context, pt.policy_target_id,
|
||||
notify_sc=False)
|
||||
gbp_plugin.delete_policy_target(
|
||||
context.elevated(), pt.policy_target_id, notify_sc=False)
|
||||
except group_policy.PolicyTargetNotFound as ex:
|
||||
LOG.debug(ex.message)
|
||||
|
||||
|
@ -134,7 +134,7 @@ class NodePlumberBase(object):
|
|||
instance['id']),
|
||||
'name': '', 'port_id': None}
|
||||
data.update(target)
|
||||
pt = gbp_plugin.create_policy_target(context,
|
||||
pt = gbp_plugin.create_policy_target(context.elevated(),
|
||||
{'policy_target': data},
|
||||
notify_sc=False)
|
||||
model.set_service_target(part_context, pt['id'], relationship)
|
||||
|
|
|
@ -56,21 +56,14 @@
|
|||
"get_nat_pool": "rule:admin_or_owner or rule:shared_np",
|
||||
|
||||
"create_servicechain_node": "",
|
||||
"create_servicechain_node:shared": "rule:admin_only",
|
||||
"get_servicechain_node": "rule:admin_or_owner or rule:shared_scn",
|
||||
"update_servicechain_node:shared": "rule:admin_only",
|
||||
|
||||
"create_servicechain_spec": "",
|
||||
"create_servicechain_spec:shared": "rule:admin_only",
|
||||
"get_servicechain_spec": "rule:admin_or_owner or rule:shared_scs",
|
||||
"update_servicechain_spec:shared": "rule:admin_only",
|
||||
|
||||
"create_servicechain_instance": "",
|
||||
"get_servicechain_instance": "rule:admin_or_owner",
|
||||
"update_servicechain_instance:shared": "rule:admin_only",
|
||||
|
||||
"create_service_profile": "",
|
||||
"create_service_profile:shared": "rule:admin_only",
|
||||
"get_service_profile": "rule:admin_or_owner or rule:shared_sp",
|
||||
"update_service_profile:shared": "rule:admin_only"
|
||||
"get_service_profile": "rule:admin_or_owner or rule:shared_sp"
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ import os
|
|||
import webob.exc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as nattr
|
||||
from neutron import context
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import model_base
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
|
@ -27,7 +28,9 @@ from oslo_config import cfg
|
|||
from oslo_utils import importutils
|
||||
|
||||
from gbpservice.neutron.db.grouppolicy import group_policy_db as gpdb
|
||||
from gbpservice.neutron.db import servicechain_db as svcchain_db
|
||||
from gbpservice.neutron.extensions import group_policy as gpolicy
|
||||
from gbpservice.neutron.extensions import servicechain as service_chain
|
||||
import gbpservice.neutron.tests
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
|
||||
|
@ -36,6 +39,7 @@ JSON_FORMAT = 'json'
|
|||
_uuid = uuidutils.generate_uuid
|
||||
TESTDIR = os.path.dirname(os.path.abspath(gbpservice.neutron.tests.__file__))
|
||||
ETCDIR = os.path.join(TESTDIR, 'etc')
|
||||
CHAIN_TENANT_ID = 'chain_owner'
|
||||
|
||||
|
||||
class ApiManagerMixin(object):
|
||||
|
@ -123,21 +127,31 @@ class ApiManagerMixin(object):
|
|||
|
||||
class GroupPolicyDBTestBase(ApiManagerMixin):
|
||||
resource_prefix_map = dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.SERVICECHAIN])
|
||||
for k in service_chain.RESOURCE_ATTRIBUTE_MAP.keys())
|
||||
resource_prefix_map.update(dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
)
|
||||
))
|
||||
|
||||
fmt = JSON_FORMAT
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Verify is an update of a proper GBP object
|
||||
|
||||
def _is_sc_resource(plural):
|
||||
return plural in service_chain.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_gbp_resource(plural):
|
||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_valid_resource(plural):
|
||||
return _is_gbp_resource(plural) or _is_sc_resource(plural)
|
||||
# Update Method
|
||||
if item.startswith('update_'):
|
||||
resource = item[len('update_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
if _is_valid_resource(plural):
|
||||
def update_wrapper(id, **kwargs):
|
||||
return self._update_resource(id, resource, **kwargs)
|
||||
return update_wrapper
|
||||
|
@ -145,7 +159,7 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||
if item.startswith('show_'):
|
||||
resource = item[len('show_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
if _is_valid_resource(plural):
|
||||
def show_wrapper(id, **kwargs):
|
||||
return self._show_resource(id, plural, **kwargs)
|
||||
return show_wrapper
|
||||
|
@ -153,7 +167,7 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||
if item.startswith('create_'):
|
||||
resource = item[len('create_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
if _is_valid_resource(plural):
|
||||
def create_wrapper(**kwargs):
|
||||
return self._create_resource(resource, **kwargs)
|
||||
return create_wrapper
|
||||
|
@ -161,13 +175,51 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||
if item.startswith('delete_'):
|
||||
resource = item[len('delete_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
if _is_valid_resource(plural):
|
||||
def delete_wrapper(id, **kwargs):
|
||||
return self._delete_resource(id, plural, **kwargs)
|
||||
return delete_wrapper
|
||||
|
||||
raise AttributeError
|
||||
|
||||
def _get_resource_plural(self, resource):
|
||||
if resource.endswith('y'):
|
||||
resource_plural = resource.replace('y', 'ies')
|
||||
else:
|
||||
resource_plural = resource + 's'
|
||||
|
||||
return resource_plural
|
||||
|
||||
def _test_list_resources(self, resource, items,
|
||||
neutron_context=None,
|
||||
query_params=None):
|
||||
resource_plural = self._get_resource_plural(resource)
|
||||
|
||||
res = self._list(resource_plural,
|
||||
neutron_context=neutron_context,
|
||||
query_params=query_params)
|
||||
params = None
|
||||
if query_params:
|
||||
params = query_params.split('&')
|
||||
params = dict((x.split('=')[0], x.split('=')[1].split(','))
|
||||
for x in params)
|
||||
count = getattr(self.plugin, 'get_%s_count' % resource_plural)(
|
||||
neutron_context or context.get_admin_context(), params)
|
||||
self.assertEqual(len(res[resource_plural]), count)
|
||||
resource = resource.replace('-', '_')
|
||||
self.assertEqual(sorted([i['id'] for i in res[resource_plural]]),
|
||||
sorted([i[resource]['id'] for i in items]))
|
||||
|
||||
def _create_profiled_servicechain_node(
|
||||
self, service_type=constants.LOADBALANCER, shared_profile=False,
|
||||
profile_tenant_id=None, **kwargs):
|
||||
prof = self.create_service_profile(
|
||||
service_type=service_type,
|
||||
shared=shared_profile,
|
||||
tenant_id=profile_tenant_id or self._tenant_id)['service_profile']
|
||||
return self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], **kwargs)
|
||||
|
||||
|
||||
class GroupPolicyDBTestPlugin(gpdb.GroupPolicyDbPlugin):
|
||||
|
||||
|
@ -178,26 +230,42 @@ DB_GP_PLUGIN_KLASS = (GroupPolicyDBTestPlugin.__module__ + '.' +
|
|||
GroupPolicyDBTestPlugin.__name__)
|
||||
|
||||
|
||||
class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
||||
|
||||
supported_extension_aliases = ['servicechain']
|
||||
|
||||
|
||||
DB_SC_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
||||
ServiceChainDBTestPlugin.__name__)
|
||||
|
||||
|
||||
class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
|
||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
|
||||
def setUp(self, core_plugin=None, gp_plugin=None, service_plugins=None,
|
||||
ext_mgr=None):
|
||||
if not gp_plugin:
|
||||
gp_plugin = DB_GP_PLUGIN_KLASS
|
||||
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
||||
ext_mgr=None, gp_plugin=None):
|
||||
sc_plugin = sc_plugin or DB_SC_PLUGIN_KLASS
|
||||
gp_plugin = gp_plugin or DB_GP_PLUGIN_KLASS
|
||||
|
||||
if not service_plugins:
|
||||
service_plugins = {'gp_plugin_name': gp_plugin}
|
||||
nattr.PLURALS['nat_pools'] = 'nat_pool'
|
||||
service_plugins = {
|
||||
'l3_plugin_name': 'router',
|
||||
'gp_plugin_name': gp_plugin,
|
||||
'sc_plugin_name': sc_plugin}
|
||||
|
||||
test_policy_file = ETCDIR + "/test-policy.json"
|
||||
cfg.CONF.set_override('policy_file', test_policy_file)
|
||||
super(GroupPolicyDbTestCase, self).setUp(
|
||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
||||
service_plugins=service_plugins
|
||||
)
|
||||
self.plugin = importutils.import_object(gp_plugin)
|
||||
self._sc_plugin = importutils.import_object(sc_plugin)
|
||||
if not ext_mgr:
|
||||
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||
test_policy_file = ETCDIR + "/test-policy.json"
|
||||
cfg.CONF.set_override('policy_file', test_policy_file)
|
||||
engine = db_api.get_engine()
|
||||
model_base.BASEV2.metadata.create_all(engine)
|
||||
|
||||
plugins = manager.NeutronManager.get_service_plugins()
|
||||
self._gbp_plugin = plugins.get(constants.GROUP_POLICY)
|
||||
|
|
|
@ -210,6 +210,7 @@ class TestMappedGroupResourceAttrs(GroupPolicyMappingDbTestCase):
|
|||
ports = [port1['port']['id'], port2['port']['id']]
|
||||
pts = [self.create_policy_target(port_id=ports[0]),
|
||||
self.create_policy_target(port_id=ports[1])]
|
||||
self._test_list_resources('policy_target', pts)
|
||||
self._test_list_resources('policy_target', [pts[0]],
|
||||
query_params='port_id=' + ports[0])
|
||||
|
||||
|
@ -221,8 +222,10 @@ class TestMappedGroupResourceAttrs(GroupPolicyMappingDbTestCase):
|
|||
l2_policies = [self.create_l2_policy(network_id=networks[0]),
|
||||
self.create_l2_policy(network_id=networks[1])]
|
||||
self._test_list_resources(
|
||||
'l2_policy', [l2_policies[0]],
|
||||
query_params='network_id=' + networks[0])
|
||||
'l2_policy', l2_policies)
|
||||
self._test_list_resources(
|
||||
'l2_policy', [l2_policies[0]],
|
||||
query_params='network_id=' + networks[0])
|
||||
|
||||
def test_list_es(self):
|
||||
with self.subnet(cidr='10.10.1.0/24') as subnet1:
|
||||
|
@ -232,5 +235,7 @@ class TestMappedGroupResourceAttrs(GroupPolicyMappingDbTestCase):
|
|||
self.create_external_segment(subnet_id=subnets[0]),
|
||||
self.create_external_segment(subnet_id=subnets[1])]
|
||||
self._test_list_resources(
|
||||
'external_segment', [external_segments[0]],
|
||||
query_params='subnet_id=' + subnets[0])
|
||||
'external_segment', external_segments)
|
||||
self._test_list_resources(
|
||||
'external_segment', [external_segments[0]],
|
||||
query_params='subnet_id=' + subnets[0])
|
||||
|
|
|
@ -13,19 +13,11 @@
|
|||
|
||||
import webob.exc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron import context
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import model_base
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.tests.unit.api import test_extensions
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
|
||||
from gbpservice.neutron.db import servicechain_db as svcchain_db
|
||||
from gbpservice.neutron.extensions import group_policy as gpolicy
|
||||
from gbpservice.neutron.extensions import servicechain as service_chain
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
|
@ -33,135 +25,20 @@ from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
|||
JSON_FORMAT = 'json'
|
||||
|
||||
|
||||
class ServiceChainDBTestBase(test_group_policy_db.ApiManagerMixin):
|
||||
resource_prefix_map = dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.SERVICECHAIN])
|
||||
for k in service_chain.RESOURCE_ATTRIBUTE_MAP.keys())
|
||||
resource_prefix_map.update(dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
))
|
||||
|
||||
fmt = JSON_FORMAT
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Verify is an update of a proper GBP object
|
||||
|
||||
def _is_sc_resource(plural):
|
||||
return plural in service_chain.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_gbp_resource(plural):
|
||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_valid_resource(plural):
|
||||
return _is_gbp_resource(plural) or _is_sc_resource(plural)
|
||||
# Update Method
|
||||
if item.startswith('update_'):
|
||||
resource = item[len('update_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def update_wrapper(id, **kwargs):
|
||||
return self._update_resource(id, resource, **kwargs)
|
||||
return update_wrapper
|
||||
# Show Method
|
||||
if item.startswith('show_'):
|
||||
resource = item[len('show_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def show_wrapper(id, **kwargs):
|
||||
return self._show_resource(id, plural, **kwargs)
|
||||
return show_wrapper
|
||||
# Create Method
|
||||
if item.startswith('create_'):
|
||||
resource = item[len('create_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def create_wrapper(**kwargs):
|
||||
return self._create_resource(resource, **kwargs)
|
||||
return create_wrapper
|
||||
# Delete Method
|
||||
if item.startswith('delete_'):
|
||||
resource = item[len('delete_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def delete_wrapper(id, **kwargs):
|
||||
return self._delete_resource(id, plural, **kwargs)
|
||||
return delete_wrapper
|
||||
|
||||
raise AttributeError
|
||||
|
||||
def _get_resource_plural(self, resource):
|
||||
if resource.endswith('y'):
|
||||
resource_plural = resource.replace('y', 'ies')
|
||||
else:
|
||||
resource_plural = resource + 's'
|
||||
|
||||
return resource_plural
|
||||
|
||||
def _test_list_resources(self, resource, items,
|
||||
neutron_context=None,
|
||||
query_params=None):
|
||||
resource_plural = self._get_resource_plural(resource)
|
||||
|
||||
res = self._list(resource_plural,
|
||||
neutron_context=neutron_context,
|
||||
query_params=query_params)
|
||||
params = query_params.split('&')
|
||||
params = dict((x.split('=')[0], x.split('=')[1].split(','))
|
||||
for x in params)
|
||||
count = getattr(self.plugin, 'get_%s_count' % resource_plural)(
|
||||
neutron_context or context.get_admin_context(), params)
|
||||
self.assertEqual(len(res[resource_plural]), count)
|
||||
resource = resource.replace('-', '_')
|
||||
self.assertEqual(sorted([i['id'] for i in res[resource_plural]]),
|
||||
sorted([i[resource]['id'] for i in items]))
|
||||
|
||||
def _create_profiled_servicechain_node(
|
||||
self, service_type=constants.LOADBALANCER, shared_profile=False,
|
||||
profile_tenant_id=None, **kwargs):
|
||||
prof = self.create_service_profile(
|
||||
service_type=service_type,
|
||||
shared=shared_profile,
|
||||
tenant_id=profile_tenant_id or self._tenant_id)['service_profile']
|
||||
return self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], **kwargs)
|
||||
|
||||
|
||||
class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
||||
|
||||
supported_extension_aliases = ['servicechain']
|
||||
|
||||
|
||||
DB_GP_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
||||
ServiceChainDBTestPlugin.__name__)
|
||||
|
||||
GP_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin")
|
||||
|
||||
|
||||
class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
class ServiceChainDbTestCase(test_group_policy_db.GroupPolicyDbTestCase):
|
||||
|
||||
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
||||
ext_mgr=None, gp_plugin=None):
|
||||
if not sc_plugin:
|
||||
sc_plugin = DB_GP_PLUGIN_KLASS
|
||||
if not service_plugins:
|
||||
service_plugins = {
|
||||
'l3_plugin_name': 'router',
|
||||
'gp_plugin_name': gp_plugin or GP_PLUGIN_KLASS,
|
||||
'sc_plugin_name': sc_plugin}
|
||||
|
||||
super(ServiceChainDbTestCase, self).setUp(
|
||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
||||
service_plugins=service_plugins
|
||||
)
|
||||
self.plugin = importutils.import_object(sc_plugin)
|
||||
if not ext_mgr:
|
||||
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||
engine = db_api.get_engine()
|
||||
model_base.BASEV2.metadata.create_all(engine)
|
||||
gp_plugin=gp_plugin or GP_PLUGIN_KLASS, core_plugin=core_plugin,
|
||||
sc_plugin=sc_plugin, service_plugins=service_plugins,
|
||||
ext_mgr=ext_mgr)
|
||||
self.plugin = self._sc_plugin
|
||||
|
||||
|
||||
class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
|
|
|
@ -148,16 +148,6 @@ class ApicMappingTestCase(
|
|||
self.driver.apic_manager.ext_net_dict.update(
|
||||
self._build_external_dict(x[0], x[1]))
|
||||
|
||||
def _check_call_list(self, expected, observed):
|
||||
for call in expected:
|
||||
self.assertTrue(call in observed,
|
||||
msg='Call not found, expected:\n%s\nobserved:'
|
||||
'\n%s' % (str(call), str(observed)))
|
||||
observed.remove(call)
|
||||
self.assertFalse(
|
||||
len(observed),
|
||||
msg='There are more calls than expected: %s' % str(observed))
|
||||
|
||||
def _create_simple_policy_rule(self, direction='bi', protocol='tcp',
|
||||
port_range=80, shared=False,
|
||||
action_type='allow', action_value=None):
|
||||
|
|
|
@ -853,8 +853,8 @@ class TestNatPool(GroupPolicyPluginTestCase):
|
|||
|
||||
class TestPolicyTarget(GroupPolicyPluginTestCase):
|
||||
|
||||
def _test_cross_tenant_fails(self, is_admin=False):
|
||||
status = {False: 404, True: 400}
|
||||
def _test_cross_tenant(self, is_admin=False):
|
||||
status = {False: 404, True: 201}
|
||||
ptg = self.create_policy_target_group(
|
||||
expected_res_status=201, tenant_id='tenant',
|
||||
is_admin_context=is_admin)['policy_target_group']
|
||||
|
@ -865,9 +865,6 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
|
|||
if not is_admin:
|
||||
self.assertEqual(
|
||||
'GbpResourceNotFound', res['NeutronError']['type'])
|
||||
else:
|
||||
self.assertEqual(
|
||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
||||
|
||||
# Create EP without PTG
|
||||
pt = self.create_policy_target(
|
||||
|
@ -875,28 +872,25 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
|
|||
is_admin_context=is_admin)['policy_target']
|
||||
|
||||
# Update PT fails
|
||||
res = self.update_policy_target(pt['id'],
|
||||
expected_res_status=status[is_admin],
|
||||
tenant_id='another',
|
||||
policy_target_group_id=ptg['id'],
|
||||
is_admin_context=is_admin)
|
||||
res = self.update_policy_target(
|
||||
pt['id'], tenant_id='another', policy_target_group_id=ptg['id'],
|
||||
expected_res_status=status[is_admin] if not is_admin else 200,
|
||||
is_admin_context=is_admin)
|
||||
|
||||
if not is_admin:
|
||||
self.assertEqual(
|
||||
'GbpResourceNotFound', res['NeutronError']['type'])
|
||||
else:
|
||||
self.assertEqual(
|
||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
||||
|
||||
def test_cross_tenant_fails(self):
|
||||
self._test_cross_tenant_fails()
|
||||
self._test_cross_tenant()
|
||||
|
||||
def test_cross_tenant_fails_admin(self):
|
||||
self._test_cross_tenant_fails(True)
|
||||
def test_cross_tenant_admin(self):
|
||||
self._test_cross_tenant(True)
|
||||
|
||||
|
||||
class TestPolicyAction(GroupPolicyPluginTestCase):
|
||||
|
||||
def test_redirect_value_fails(self):
|
||||
def test_redirect_value(self):
|
||||
scs_id = self._create_servicechain_spec(
|
||||
node_types=['FIREWALL_TRANSPARENT'])
|
||||
res = self.create_policy_action(action_type='redirect',
|
||||
|
@ -913,9 +907,7 @@ class TestPolicyAction(GroupPolicyPluginTestCase):
|
|||
|
||||
res = self.create_policy_action(
|
||||
action_type='redirect', action_value=scs_id, tenant_id='different',
|
||||
expected_res_status=400, is_admin_context=True)
|
||||
self.assertEqual(
|
||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
||||
expected_res_status=201, is_admin_context=True)
|
||||
|
||||
res = self.create_policy_action(
|
||||
action_type='redirect', action_value=scs_id,
|
||||
|
@ -929,7 +921,7 @@ class TestPolicyAction(GroupPolicyPluginTestCase):
|
|||
node_types=['FIREWALL_TRANSPARENT'], shared=True)
|
||||
self.create_policy_action(
|
||||
action_type='redirect', action_value=scs_id, shared=True,
|
||||
expected_res_status=201)['policy_action']
|
||||
expected_res_status=201)
|
||||
data = {'servicechain_spec': {'shared': False}}
|
||||
scs_req = self.new_update_request(
|
||||
SERVICECHAIN_SPECS, data, scs_id, self.fmt)
|
||||
|
|
|
@ -172,6 +172,17 @@ class TestPolicyRuleSet(OneConvergenceGBPDriverTestCase,
|
|||
pass
|
||||
|
||||
|
||||
class TestServiceChain(OneConvergenceGBPDriverTestCase,
|
||||
test_resource_mapping.TestServiceChain):
|
||||
pass
|
||||
|
||||
|
||||
class TestServiceChainAdminOwner(
|
||||
OneConvergenceGBPDriverTestCase,
|
||||
test_resource_mapping.TestServiceChainAdminOwner):
|
||||
pass
|
||||
|
||||
|
||||
class TestPolicyAction(OneConvergenceGBPDriverTestCase,
|
||||
test_resource_mapping.TestPolicyAction):
|
||||
pass
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -47,6 +47,7 @@ CORE_PLUGIN = ('gbpservice.neutron.tests.unit.services.grouppolicy.'
|
|||
GP_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
|
||||
)
|
||||
CHAIN_TENANT_ID = 'sci_owner'
|
||||
|
||||
|
||||
class NodeCompositionPluginTestCase(
|
||||
|
@ -155,7 +156,8 @@ class NodeCompositionPluginTestCase(
|
|||
provider = self.create_policy_target_group()['policy_target_group']
|
||||
consumer = self.create_policy_target_group()['policy_target_group']
|
||||
management = self.create_policy_target_group(
|
||||
service_management=True)['policy_target_group']
|
||||
service_management=True,
|
||||
is_admin_context=True)['policy_target_group']
|
||||
classifier = self.create_policy_classifier()['policy_classifier']
|
||||
|
||||
instance = self.create_servicechain_instance(
|
||||
|
@ -600,7 +602,7 @@ class NodeCompositionPluginTestCase(
|
|||
self.create_policy_target_group(
|
||||
provided_policy_rule_sets={prs['id']: ''})
|
||||
self.create_policy_target_group(
|
||||
consumed_policy_rule_sets={prs['id']: ''})['policy_target_group']
|
||||
consumed_policy_rule_sets={prs['id']: ''})
|
||||
instances = self._list('servicechain_instances')[
|
||||
'servicechain_instances']
|
||||
self.assertEqual(1, len(instances))
|
||||
|
@ -679,6 +681,9 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||
self.driver.get_plumbing_info = mock.Mock()
|
||||
self.driver.get_plumbing_info.return_value = {}
|
||||
|
||||
def _assert_service_target_tenant(self, policy_target, provider):
|
||||
self.assertEqual(provider['tenant_id'], policy_target['tenant_id'])
|
||||
|
||||
def _create_simple_chain(self):
|
||||
node = self._create_profiled_servicechain_node(
|
||||
service_type="LOADBALANCER",
|
||||
|
@ -718,9 +723,11 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||
for target in targets:
|
||||
self.assertEqual(node['id'], target.servicechain_node_id)
|
||||
pt = self.show_policy_target(
|
||||
target.policy_target_id)['policy_target']
|
||||
target.policy_target_id,
|
||||
is_admin_context=True)['policy_target']
|
||||
self.assertEqual(prov_cons[target.relationship]['id'],
|
||||
pt['policy_target_group_id'])
|
||||
self._assert_service_target_tenant(pt, provider)
|
||||
self.assertNotEqual(old_relationship, target.relationship)
|
||||
old_relationship = target.relationship
|
||||
|
||||
|
@ -731,7 +738,8 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||
self.assertEqual(0, len(new_targets))
|
||||
for target in targets:
|
||||
self.show_policy_target(
|
||||
target.policy_target_id, expected_res_status=404)
|
||||
target.policy_target_id, is_admin_context=True,
|
||||
expected_res_status=404)
|
||||
|
||||
def test_pt_override(self):
|
||||
context = n_context.get_admin_context()
|
||||
|
@ -742,7 +750,8 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||
targets = model.get_service_targets(context.session)
|
||||
self.assertEqual(1, len(targets))
|
||||
pt = self.show_policy_target(
|
||||
targets[0].policy_target_id)['policy_target']
|
||||
targets[0].policy_target_id,
|
||||
is_admin_context=True)['policy_target']
|
||||
self.assertEqual(test_name, pt['name'])
|
||||
|
||||
def test_ptg_delete(self):
|
||||
|
@ -839,3 +848,29 @@ class TestQuotasForServiceChain(test_base.ServiceChainPluginTestCase):
|
|||
self.assertRaises(webob.exc.HTTPClientError,
|
||||
self.create_policy_target_group,
|
||||
consumed_policy_rule_sets={prs['id']: ''})
|
||||
|
||||
|
||||
class AgnosticChainPlumberAdminOwner(AgnosticChainPlumberTestCase):
|
||||
|
||||
def setUp(self):
|
||||
mock.patch('gbpservice.neutron.services.grouppolicy.drivers.'
|
||||
'resource_mapping.ResourceMappingDriver.'
|
||||
'chain_tenant_keystone_client').start()
|
||||
res = mock.patch('gbpservice.neutron.services.grouppolicy.drivers.'
|
||||
'resource_mapping.ResourceMappingDriver.'
|
||||
'chain_tenant_id').start()
|
||||
res.return_value = CHAIN_TENANT_ID
|
||||
super(AgnosticChainPlumberAdminOwner, self).setUp()
|
||||
|
||||
def _assert_service_target_tenant(self, policy_target, provider):
|
||||
self.assertEqual(CHAIN_TENANT_ID, policy_target['tenant_id'])
|
||||
|
||||
def test_update_service_chain(self):
|
||||
# This directly updates the SCI, which requires the right tenant to be
|
||||
# done
|
||||
pass
|
||||
|
||||
def test_instance_update(self):
|
||||
# This directly updates the SCI, which requires the right tenant to be
|
||||
# done
|
||||
pass
|
||||
|
|
|
@ -64,6 +64,10 @@ class SimpleChainDriverTestCase(
|
|||
STACK_DELETE_RETRY_WAIT,
|
||||
group='simplechain')
|
||||
super(SimpleChainDriverTestCase, self).setUp()
|
||||
key_client = mock.patch(
|
||||
'gbpservice.neutron.services.servicechain.plugins.msc.drivers.'
|
||||
'simplechain_driver.HeatClient._get_auth_token').start()
|
||||
key_client.return_value = 'mysplendidtoken'
|
||||
|
||||
|
||||
class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
|
Loading…
Reference in New Issue