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.
Closes-Bug: 1432816
(cherry picked from commit 3becb34638)
Conflicts:
gbpservice/network/neutronv2/local_api.py
gbpservice/neutron/services/grouppolicy/drivers/resource_mapping.py
Change-Id: I1344356d4192dbe25695993545dd156d893805cc
This commit is contained in:
@@ -2,3 +2,14 @@
|
|||||||
|
|
||||||
# DNS nameservers to be used configured in the PTG subnets by this driver.
|
# DNS nameservers to be used configured in the PTG subnets by this driver.
|
||||||
# dns_nameservers = 8.8.8.7, 8.8.8.8
|
# 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>
|
||||||
15
etc/servicechain/drivers/simplechain.ini
Normal file
15
etc/servicechain/drivers/simplechain.ini
Normal file
@@ -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
|
||||||
6
etc/servicechain/servicechain.ini
Normal file
6
etc/servicechain/servicechain.ini
Normal file
@@ -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
|
import contextlib
|
||||||
|
|
||||||
|
from neutron import context as n_ctx
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
from stevedore import driver
|
from stevedore import driver
|
||||||
@@ -44,6 +46,12 @@ def load_plugin(namespace, plugin):
|
|||||||
return plugin_class()
|
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):
|
class DictClass(dict):
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
@@ -51,3 +59,20 @@ class DictClass(dict):
|
|||||||
|
|
||||||
__setattr__ = dict.__setattr__
|
__setattr__ = dict.__setattr__
|
||||||
__delattr__ = dict.__delattr__
|
__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 + '/'
|
||||||
|
|||||||
@@ -1355,6 +1355,11 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
|
|||||||
marker_obj=marker_obj,
|
marker_obj=marker_obj,
|
||||||
page_reverse=page_reverse)
|
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
|
@log.log
|
||||||
def create_network_service_policy(self, context, network_service_policy):
|
def create_network_service_policy(self, context, network_service_policy):
|
||||||
nsp = network_service_policy['network_service_policy']
|
nsp = network_service_policy['network_service_policy']
|
||||||
|
|||||||
@@ -234,6 +234,11 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||||||
context.session.add(pt_db)
|
context.session.add(pt_db)
|
||||||
return self._make_policy_target_dict(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
|
@log.log
|
||||||
def get_policy_targets(self, context, filters=None, fields=None,
|
def get_policy_targets(self, context, filters=None, fields=None,
|
||||||
sorts=None, limit=None, marker=None,
|
sorts=None, limit=None, marker=None,
|
||||||
@@ -331,6 +336,11 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||||||
marker_obj=marker_obj,
|
marker_obj=marker_obj,
|
||||||
page_reverse=page_reverse)
|
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
|
@log.log
|
||||||
def create_l3_policy(self, context, l3_policy):
|
def create_l3_policy(self, context, l3_policy):
|
||||||
l3p = l3_policy['l3_policy']
|
l3p = l3_policy['l3_policy']
|
||||||
@@ -426,6 +436,10 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||||||
marker_obj=marker_obj,
|
marker_obj=marker_obj,
|
||||||
page_reverse=page_reverse)
|
page_reverse=page_reverse)
|
||||||
|
|
||||||
|
def get_external_segments_count(self, context, filters=None):
|
||||||
|
return self._get_collection_count(context, ExternalSegmentMapping,
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def create_nat_pool(self, context, nat_pool):
|
def create_nat_pool(self, context, nat_pool):
|
||||||
np = nat_pool['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 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
|
# the GBP service to be loaded correctly. GBP extensions' path is added
|
||||||
# to Neutron's so that it's found at extension scanning time.
|
# to Neutron's so that it's found at extension scanning time.
|
||||||
|
|
||||||
extensions.append_api_extensions_path(gbpservice.neutron.extensions.__path__)
|
extensions.append_api_extensions_path(gbpservice.neutron.extensions.__path__)
|
||||||
constants.GROUP_POLICY = "GROUP_POLICY"
|
constants.GROUP_POLICY = "GROUP_POLICY"
|
||||||
constants.COMMON_PREFIXES["GROUP_POLICY"] = "/grouppolicy"
|
constants.COMMON_PREFIXES["GROUP_POLICY"] = "/grouppolicy"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
|
from neutron.db import securitygroups_db
|
||||||
|
|
||||||
|
|
||||||
# Monkey patch create floatingip to allow subnet_id to be specified.
|
# 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
|
return fip['port_id'], internal_ip_address, router_id
|
||||||
|
|
||||||
l3_db.L3_NAT_dbonly_mixin.get_assoc_data = get_assoc_data
|
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 netaddr
|
||||||
import operator
|
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.api.v2 import attributes
|
||||||
from neutron.common import constants as const
|
from neutron.common import constants as const
|
||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
@@ -25,6 +27,7 @@ from neutron.extensions import securitygroup as ext_sg
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import excutils
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from gbpservice.common import utils
|
from gbpservice.common import utils
|
||||||
@@ -41,6 +44,24 @@ from gbpservice.neutron.services.grouppolicy.common import exceptions as exc
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
DEFAULT_SG_PREFIX = 'gbp_%s'
|
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 = [
|
opts = [
|
||||||
cfg.ListOpt('dns_nameservers',
|
cfg.ListOpt('dns_nameservers',
|
||||||
@@ -102,7 +123,7 @@ class PolicyRuleSetSGsMapping(model_base.BASEV2):
|
|||||||
sa.ForeignKey('securitygroups.id'))
|
sa.ForeignKey('securitygroups.id'))
|
||||||
|
|
||||||
|
|
||||||
class PtgServiceChainInstanceMapping(model_base.BASEV2):
|
class PtgServiceChainInstanceMapping(model_base.BASEV2, models_v2.HasTenant):
|
||||||
"""Policy Target Group to ServiceChainInstance mapping DB."""
|
"""Policy Target Group to ServiceChainInstance mapping DB."""
|
||||||
|
|
||||||
__tablename__ = 'gpm_ptgs_servicechain_mapping'
|
__tablename__ = 'gpm_ptgs_servicechain_mapping'
|
||||||
@@ -174,6 +195,41 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
@log.log
|
@log.log
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self._cached_agent_notifier = None
|
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):
|
def _reject_shared(self, object, type):
|
||||||
if object.get('shared'):
|
if object.get('shared'):
|
||||||
@@ -513,7 +569,6 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
"network_service_policy_id")
|
"network_service_policy_id")
|
||||||
if not network_service_policy_id:
|
if not network_service_policy_id:
|
||||||
return
|
return
|
||||||
|
|
||||||
nsp = context._plugin.get_network_service_policy(
|
nsp = context._plugin.get_network_service_policy(
|
||||||
context._plugin_context, network_service_policy_id)
|
context._plugin_context, network_service_policy_id)
|
||||||
nsp_params = nsp.get("network_service_params")
|
nsp_params = nsp.get("network_service_params")
|
||||||
@@ -940,11 +995,16 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
context.original['direction'] != context.current['direction']):
|
context.original['direction'] != context.current['direction']):
|
||||||
sc_instances = (
|
sc_instances = (
|
||||||
self._servicechain_plugin.get_servicechain_instances(
|
self._servicechain_plugin.get_servicechain_instances(
|
||||||
context._plugin_context,
|
context._plugin_context.elevated(),
|
||||||
filters={'classifier_id': [context.current['id']]}))
|
filters={'classifier_id': [context.current['id']]}))
|
||||||
for sc_instance in sc_instances:
|
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(
|
self._servicechain_plugin.notify_chain_parameters_updated(
|
||||||
context._plugin_context, sc_instance['id'])
|
ctx, sc_instance['id'])
|
||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
def delete_policy_classifier_precommit(self, context):
|
def delete_policy_classifier_precommit(self, context):
|
||||||
@@ -1864,10 +1924,11 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
x == context.original['action_value'] else
|
x == context.original['action_value'] else
|
||||||
x for x in old_specs]
|
x for x in old_specs]
|
||||||
self._update_servicechain_instance(
|
self._update_servicechain_instance(
|
||||||
context, servicechain_instance.servicechain_instance_id,
|
context._plugin_context,
|
||||||
|
servicechain_instance.servicechain_instance_id,
|
||||||
sc_specs=new_specs)
|
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):
|
classifier_id=None, sc_specs=None):
|
||||||
sc_instance_update_data = {}
|
sc_instance_update_data = {}
|
||||||
if sc_specs:
|
if sc_specs:
|
||||||
@@ -1875,7 +1936,9 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
if classifier_id:
|
if classifier_id:
|
||||||
sc_instance_update_data.update({'classifier_id': classifier_id})
|
sc_instance_update_data.update({'classifier_id': classifier_id})
|
||||||
super(ResourceMappingDriver, self)._update_servicechain_instance(
|
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):
|
def _get_rule_ids_for_actions(self, context, action_id):
|
||||||
policy_rule_qry = context.session.query(
|
policy_rule_qry = context.session.query(
|
||||||
@@ -1948,42 +2011,42 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
context, ptg_providing_prs, ptg_consuming_prs,
|
context, ptg_providing_prs, ptg_consuming_prs,
|
||||||
spec_id,
|
spec_id,
|
||||||
parent_spec_id, classifier_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,
|
def _create_or_update_chain(self, context, provider, consumer, spec_id,
|
||||||
parent_spec_id, classifier_id,
|
parent_spec_id, classifier_id,
|
||||||
hierarchial_classifier_mismatch):
|
hierarchial_classifier_mismatch, prs_id):
|
||||||
ptg_chain_map = self._get_ptg_servicechain_mapping(
|
ptg_chain_map = self._get_ptg_servicechain_mapping(
|
||||||
context._plugin_context.session, provider, consumer)
|
context._plugin_context.session, provider, consumer)
|
||||||
if ptg_chain_map:
|
if ptg_chain_map:
|
||||||
if hierarchial_classifier_mismatch or not spec_id:
|
if hierarchial_classifier_mismatch or not spec_id:
|
||||||
self._delete_servicechain_instance(
|
ctx = self._get_chain_admin_context(
|
||||||
context._plugin_context,
|
context._plugin_context,
|
||||||
ptg_chain_map[0].servicechain_instance_id)
|
tenant_id=ptg_chain_map[0].tenant_id)
|
||||||
|
self._delete_servicechain_instance(
|
||||||
|
ctx, ptg_chain_map[0].servicechain_instance_id)
|
||||||
else:
|
else:
|
||||||
sc_specs = [spec_id]
|
sc_specs = [spec_id]
|
||||||
if parent_spec_id:
|
if parent_spec_id:
|
||||||
sc_specs.insert(0, parent_spec_id)
|
sc_specs.insert(0, parent_spec_id)
|
||||||
# One Chain between a unique pair of provider and consumer
|
# One Chain between a unique pair of provider and consumer
|
||||||
|
|
||||||
self._update_servicechain_instance(
|
self._update_servicechain_instance(
|
||||||
context,
|
context._plugin_context,
|
||||||
ptg_chain_map[0].servicechain_instance_id,
|
ptg_chain_map[0].servicechain_instance_id,
|
||||||
classifier_id=classifier_id,
|
classifier_id=classifier_id,
|
||||||
sc_specs=sc_specs)
|
sc_specs=sc_specs)
|
||||||
elif spec_id and not hierarchial_classifier_mismatch:
|
elif spec_id and not hierarchial_classifier_mismatch:
|
||||||
sc_instance = self._create_servicechain_instance(
|
self._create_servicechain_instance(context, spec_id,
|
||||||
context, spec_id,
|
parent_spec_id, provider,
|
||||||
parent_spec_id, provider,
|
consumer, classifier_id, prs_id)
|
||||||
consumer, classifier_id)
|
|
||||||
self._set_ptg_servicechain_instance_mapping(
|
|
||||||
context._plugin_context.session,
|
|
||||||
provider, consumer,
|
|
||||||
sc_instance['id'])
|
|
||||||
|
|
||||||
def _cleanup_redirect_action(self, context):
|
def _cleanup_redirect_action(self, context):
|
||||||
for ptg_chain in context.ptg_chain_map:
|
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(
|
self._delete_servicechain_instance(
|
||||||
context._plugin_context, ptg_chain.servicechain_instance_id)
|
ctx, ptg_chain.servicechain_instance_id)
|
||||||
|
|
||||||
def _restore_ip_to_allocation_pool(self, context, subnet_id, ip_address):
|
def _restore_ip_to_allocation_pool(self, context, subnet_id, ip_address):
|
||||||
# TODO(Magesh):Pass subnets and loop on subnets. Better to add logic
|
# TODO(Magesh):Pass subnets and loop on subnets. Better to add logic
|
||||||
@@ -2035,18 +2098,30 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
def _create_servicechain_instance(self, context, servicechain_spec,
|
def _create_servicechain_instance(self, context, servicechain_spec,
|
||||||
parent_servicechain_spec,
|
parent_servicechain_spec,
|
||||||
provider_ptg_id, consumer_ptg_id,
|
provider_ptg_id, consumer_ptg_id,
|
||||||
classifier_id,
|
classifier_id, policy_rule_set,
|
||||||
config_params=None):
|
config_params=None):
|
||||||
sc_spec = [servicechain_spec]
|
sc_spec = [servicechain_spec]
|
||||||
if parent_servicechain_spec:
|
if parent_servicechain_spec:
|
||||||
sc_spec.insert(0, parent_servicechain_spec)
|
sc_spec.insert(0, parent_servicechain_spec)
|
||||||
config_param_values = {}
|
config_param_values = {}
|
||||||
ptg = context._plugin.get_policy_target_group(
|
provider_ptg = context._plugin.get_policy_target_group(
|
||||||
context._plugin_context, provider_ptg_id)
|
utils.admin_context(context._plugin_context), provider_ptg_id)
|
||||||
network_service_policy_id = ptg.get("network_service_policy_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:
|
if network_service_policy_id:
|
||||||
nsp = context._plugin.get_network_service_policy(
|
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")
|
service_params = nsp.get("network_service_params")
|
||||||
for service_parameter in service_params:
|
for service_parameter in service_params:
|
||||||
param_type = service_parameter.get("type")
|
param_type = service_parameter.get("type")
|
||||||
@@ -2055,7 +2130,7 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
key = service_parameter.get("name")
|
key = service_parameter.get("name")
|
||||||
servicepolicy_ptg_ip_map = (
|
servicepolicy_ptg_ip_map = (
|
||||||
self._get_ptg_policy_ipaddress_mapping(
|
self._get_ptg_policy_ipaddress_mapping(
|
||||||
context._plugin_context.session, provider_ptg_id))
|
session, provider_ptg_id))
|
||||||
servicepolicy_ip = servicepolicy_ptg_ip_map.get(
|
servicepolicy_ip = servicepolicy_ptg_ip_map.get(
|
||||||
"ipaddress")
|
"ipaddress")
|
||||||
config_param_values[key] = servicepolicy_ip
|
config_param_values[key] = servicepolicy_ip
|
||||||
@@ -2069,8 +2144,11 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
for fip_map in fip_maps:
|
for fip_map in fip_maps:
|
||||||
servicepolicy_fip_ids.append(fip_map.floatingip_id)
|
servicepolicy_fip_ids.append(fip_map.floatingip_id)
|
||||||
config_param_values[key] = servicepolicy_fip_ids
|
config_param_values[key] = servicepolicy_fip_ids
|
||||||
attrs = {'tenant_id': context.current['tenant_id'],
|
name = 'gbp_%s_%s_%s' % (policy_rule_set['name'], provider_ptg['name'],
|
||||||
'name': 'gbp_' + ptg['name'],
|
consumer_ptg['name'] if consumer_ptg else '')
|
||||||
|
|
||||||
|
attrs = {'tenant_id': p_ctx.tenant,
|
||||||
|
'name': name,
|
||||||
'description': "",
|
'description': "",
|
||||||
'servicechain_specs': sc_spec,
|
'servicechain_specs': sc_spec,
|
||||||
'provider_ptg_id': provider_ptg_id,
|
'provider_ptg_id': provider_ptg_id,
|
||||||
@@ -2078,9 +2156,13 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
'management_ptg_id': None,
|
'management_ptg_id': None,
|
||||||
'classifier_id': classifier_id,
|
'classifier_id': classifier_id,
|
||||||
'config_param_values': jsonutils.dumps(config_param_values)}
|
'config_param_values': jsonutils.dumps(config_param_values)}
|
||||||
return super(
|
sc_instance = super(
|
||||||
ResourceMappingDriver, self)._create_servicechain_instance(
|
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
|
# Do Not Pass floating_ip_address to this method until after Kilo Release
|
||||||
def _create_floatingip(self, plugin_context, tenant_id, ext_net_id,
|
def _create_floatingip(self, plugin_context, tenant_id, ext_net_id,
|
||||||
@@ -2549,27 +2631,36 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
|
|
||||||
def _set_ptg_servicechain_instance_mapping(self, session, provider_ptg_id,
|
def _set_ptg_servicechain_instance_mapping(self, session, provider_ptg_id,
|
||||||
consumer_ptg_id,
|
consumer_ptg_id,
|
||||||
servicechain_instance_id):
|
servicechain_instance_id,
|
||||||
|
provider_tenant_id):
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
mapping = PtgServiceChainInstanceMapping(
|
mapping = PtgServiceChainInstanceMapping(
|
||||||
provider_ptg_id=provider_ptg_id,
|
provider_ptg_id=provider_ptg_id,
|
||||||
consumer_ptg_id=consumer_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)
|
session.add(mapping)
|
||||||
|
|
||||||
def _get_ptg_servicechain_mapping(self, session, provider_ptg_id,
|
def _get_ptg_servicechain_mapping(self, session, provider_ptg_id=None,
|
||||||
consumer_ptg_id):
|
consumer_ptg_id=None, tenant_id=None,
|
||||||
|
servicechain_instance_id=None):
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
query = session.query(PtgServiceChainInstanceMapping)
|
query = session.query(PtgServiceChainInstanceMapping)
|
||||||
if provider_ptg_id:
|
if provider_ptg_id:
|
||||||
query = query.filter_by(provider_ptg_id=provider_ptg_id)
|
query = query.filter_by(provider_ptg_id=provider_ptg_id)
|
||||||
if consumer_ptg_id:
|
if consumer_ptg_id:
|
||||||
query = query.filter_by(consumer_ptg_id=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()
|
all = query.all()
|
||||||
return [utils.DictClass([('provider_ptg_id', x.provider_ptg_id),
|
return [utils.DictClass([('provider_ptg_id', x.provider_ptg_id),
|
||||||
('consumer_ptg_id', x.consumer_ptg_id),
|
('consumer_ptg_id', x.consumer_ptg_id),
|
||||||
('servicechain_instance_id',
|
('servicechain_instance_id',
|
||||||
x.servicechain_instance_id)])
|
x.servicechain_instance_id),
|
||||||
|
('tenant_id', x.tenant_id)])
|
||||||
for x in all]
|
for x in all]
|
||||||
|
|
||||||
def _get_ep_cidr_list(self, context, ep):
|
def _get_ep_cidr_list(self, context, ep):
|
||||||
@@ -2746,3 +2837,25 @@ class ResourceMappingDriver(api.PolicyDriver, local_api.LocalAPI):
|
|||||||
ptg_subnet_id=",".join(ptg.get('subnets')),
|
ptg_subnet_id=",".join(ptg.get('subnets')),
|
||||||
port_subnet_id=port_subnet_id,
|
port_subnet_id=port_subnet_id,
|
||||||
policy_target_group_id=ptg_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:
|
for linked in linked_objects:
|
||||||
link_ids.add(linked['id'])
|
link_ids.add(linked['id'])
|
||||||
GroupPolicyPlugin._verify_sharing_consistency(
|
GroupPolicyPlugin._verify_sharing_consistency(
|
||||||
obj, linked, identity, ref_type)
|
obj, linked, identity, ref_type, context.is_admin)
|
||||||
# Check for missing references
|
# Check for missing references
|
||||||
missing = set(ids) - link_ids
|
missing = set(ids) - link_ids
|
||||||
if missing:
|
if missing:
|
||||||
@@ -288,20 +288,22 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
|||||||
spec = self.servicechain_plugin.get_servicechain_spec(
|
spec = self.servicechain_plugin.get_servicechain_spec(
|
||||||
context, action['action_value'])
|
context, action['action_value'])
|
||||||
GroupPolicyPlugin._verify_sharing_consistency(
|
GroupPolicyPlugin._verify_sharing_consistency(
|
||||||
action, spec, 'polocy_action', 'servicechain_spec')
|
action, spec, 'policy_action', 'servicechain_spec',
|
||||||
|
context.is_admin)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _verify_sharing_consistency(primary, reference, primary_type,
|
def _verify_sharing_consistency(primary, reference, primary_type,
|
||||||
reference_type):
|
reference_type, is_admin):
|
||||||
if not reference.get('shared'):
|
if not reference.get('shared'):
|
||||||
if primary.get('shared'):
|
if primary.get('shared'):
|
||||||
raise gp_exc.SharedResourceReferenceError(
|
raise gp_exc.SharedResourceReferenceError(
|
||||||
res_type=primary_type, res_id=primary['id'],
|
res_type=primary_type, res_id=primary['id'],
|
||||||
ref_type=reference_type, ref_id=reference['id'])
|
ref_type=reference_type, ref_id=reference['id'])
|
||||||
if primary.get('tenant_id') != reference.get('tenant_id'):
|
if not is_admin:
|
||||||
raise gp_exc.InvalidCrossTenantReference(
|
if primary.get('tenant_id') != reference.get('tenant_id'):
|
||||||
res_type=primary_type, res_id=primary['id'],
|
raise gp_exc.InvalidCrossTenantReference(
|
||||||
ref_type=reference_type, ref_id=reference['id'])
|
res_type=primary_type, res_id=primary['id'],
|
||||||
|
ref_type=reference_type, ref_id=reference['id'])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.extension_manager = ext_manager.ExtensionManager()
|
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(
|
policy_target_group = self.get_policy_target_group(
|
||||||
context, policy_target_group_id)
|
context, policy_target_group_id)
|
||||||
pt_ids = policy_target_group['policy_targets']
|
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 (
|
if pt['port_id'] and self._is_port_bound(pt['port_id']) or (
|
||||||
self._is_service_target(context, pt['id'])):
|
self._is_service_target(context, pt['id'])):
|
||||||
raise gp_exc.PolicyTargetGroupInUse(
|
raise gp_exc.PolicyTargetGroupInUse(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import time
|
|||||||
|
|
||||||
from heatclient import client as heat_client
|
from heatclient import client as heat_client
|
||||||
from heatclient import exc as heat_exc
|
from heatclient import exc as heat_exc
|
||||||
|
from keystoneclient.v2_0 import client as keyclient
|
||||||
from neutron.common import log
|
from neutron.common import log
|
||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
@@ -416,11 +417,16 @@ class HeatClient:
|
|||||||
|
|
||||||
def __init__(self, context, password=None):
|
def __init__(self, context, password=None):
|
||||||
api_version = "1"
|
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 = {
|
kwargs = {
|
||||||
'token': context.auth_token,
|
'token': self._get_auth_token(self.tenant),
|
||||||
'username': context.user_name,
|
'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.client = heat_client.Client(api_version, endpoint, **kwargs)
|
||||||
self.stacks = self.client.stacks
|
self.stacks = self.client.stacks
|
||||||
@@ -445,3 +451,25 @@ class HeatClient:
|
|||||||
|
|
||||||
def get(self, stack_id):
|
def get(self, stack_id):
|
||||||
return self.stacks.get(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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from neutron import context as n_context
|
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.plugins.common import constants as pconst
|
from neutron.plugins.common import constants as pconst
|
||||||
|
|
||||||
|
from gbpservice.common import utils
|
||||||
from gbpservice.neutron.services.servicechain.plugins.ncp import model
|
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,
|
def get_node_driver_context(sc_plugin, context, sc_instance,
|
||||||
current_node, original_node=None,
|
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(
|
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'])
|
position = _calculate_node_position(specs, current_node['id'])
|
||||||
provider, _ = _get_ptg_or_ep(
|
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(
|
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'])
|
management, _ = _get_ptg_or_ep(context, sc_instance['management_ptg_id'])
|
||||||
classifier = get_gbp_plugin().get_policy_classifier(
|
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(
|
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(
|
original_profile = sc_plugin.get_service_profile(
|
||||||
context,
|
admin_context,
|
||||||
original_node['service_profile_id']) if original_node else None
|
original_node['service_profile_id']) if original_node else None
|
||||||
if not service_targets:
|
if not service_targets:
|
||||||
service_targets = model.get_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'])
|
position=position, servicechain_node_id=current_node['id'])
|
||||||
|
|
||||||
return NodeDriverContext(sc_plugin=sc_plugin,
|
return NodeDriverContext(sc_plugin=sc_plugin,
|
||||||
@@ -147,7 +147,7 @@ class NodeDriverContext(object):
|
|||||||
@property
|
@property
|
||||||
def admin_context(self):
|
def admin_context(self):
|
||||||
if not self._admin_context:
|
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
|
return self._admin_context
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -283,7 +283,9 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||||||
self._update_chains_pt_modified(context, policy_target, 'removed')
|
self._update_chains_pt_modified(context, policy_target, 'removed')
|
||||||
|
|
||||||
def _update_chains_pt_modified(self, context, policy_target, action):
|
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:
|
for sci in scis:
|
||||||
updaters = self._get_scheduled_drivers(context, sci, 'update')
|
updaters = self._get_scheduled_drivers(context, sci, 'update')
|
||||||
@@ -317,6 +319,7 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||||||
"failed, %s"), ex.message)
|
"failed, %s"), ex.message)
|
||||||
|
|
||||||
def _get_instance_nodes(self, context, instance):
|
def _get_instance_nodes(self, context, instance):
|
||||||
|
context = utils.admin_context(context)
|
||||||
if not instance['servicechain_specs']:
|
if not instance['servicechain_specs']:
|
||||||
return []
|
return []
|
||||||
specs = self.get_servicechain_spec(
|
specs = self.get_servicechain_spec(
|
||||||
@@ -324,6 +327,7 @@ class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin,
|
|||||||
return self.get_servicechain_nodes(context, {'id': specs['nodes']})
|
return self.get_servicechain_nodes(context, {'id': specs['nodes']})
|
||||||
|
|
||||||
def _get_node_instances(self, context, node):
|
def _get_node_instances(self, context, node):
|
||||||
|
context = utils.admin_context(context)
|
||||||
specs = self.get_servicechain_specs(
|
specs = self.get_servicechain_specs(
|
||||||
context, {'id': node['servicechain_specs']})
|
context, {'id': node['servicechain_specs']})
|
||||||
result = []
|
result = []
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ class NodePlumberBase(object):
|
|||||||
|
|
||||||
for pt in pts:
|
for pt in pts:
|
||||||
try:
|
try:
|
||||||
gbp_plugin.delete_policy_target(context, pt.policy_target_id,
|
gbp_plugin.delete_policy_target(
|
||||||
notify_sc=False)
|
context.elevated(), pt.policy_target_id, notify_sc=False)
|
||||||
except group_policy.PolicyTargetNotFound as ex:
|
except group_policy.PolicyTargetNotFound as ex:
|
||||||
LOG.debug(ex.message)
|
LOG.debug(ex.message)
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ class NodePlumberBase(object):
|
|||||||
instance['id']),
|
instance['id']),
|
||||||
'name': '', 'port_id': None}
|
'name': '', 'port_id': None}
|
||||||
data.update(target)
|
data.update(target)
|
||||||
pt = gbp_plugin.create_policy_target(context,
|
pt = gbp_plugin.create_policy_target(context.elevated(),
|
||||||
{'policy_target': data},
|
{'policy_target': data},
|
||||||
notify_sc=False)
|
notify_sc=False)
|
||||||
model.set_service_target(part_context, pt['id'], relationship)
|
model.set_service_target(part_context, pt['id'], relationship)
|
||||||
|
|||||||
@@ -56,21 +56,14 @@
|
|||||||
"get_nat_pool": "rule:admin_or_owner or rule:shared_np",
|
"get_nat_pool": "rule:admin_or_owner or rule:shared_np",
|
||||||
|
|
||||||
"create_servicechain_node": "",
|
"create_servicechain_node": "",
|
||||||
"create_servicechain_node:shared": "rule:admin_only",
|
|
||||||
"get_servicechain_node": "rule:admin_or_owner or rule:shared_scn",
|
"get_servicechain_node": "rule:admin_or_owner or rule:shared_scn",
|
||||||
"update_servicechain_node:shared": "rule:admin_only",
|
|
||||||
|
|
||||||
"create_servicechain_spec": "",
|
"create_servicechain_spec": "",
|
||||||
"create_servicechain_spec:shared": "rule:admin_only",
|
|
||||||
"get_servicechain_spec": "rule:admin_or_owner or rule:shared_scs",
|
"get_servicechain_spec": "rule:admin_or_owner or rule:shared_scs",
|
||||||
"update_servicechain_spec:shared": "rule:admin_only",
|
|
||||||
|
|
||||||
"create_servicechain_instance": "",
|
"create_servicechain_instance": "",
|
||||||
"get_servicechain_instance": "rule:admin_or_owner",
|
"get_servicechain_instance": "rule:admin_or_owner",
|
||||||
"update_servicechain_instance:shared": "rule:admin_only",
|
|
||||||
|
|
||||||
"create_service_profile": "",
|
"create_service_profile": "",
|
||||||
"create_service_profile:shared": "rule:admin_only",
|
"get_service_profile": "rule:admin_or_owner or rule:shared_sp"
|
||||||
"get_service_profile": "rule:admin_or_owner or rule:shared_sp",
|
|
||||||
"update_service_profile:shared": "rule:admin_only"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ import os
|
|||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api import extensions
|
from neutron.api import extensions
|
||||||
from neutron.api.v2 import attributes as nattr
|
|
||||||
from neutron import context
|
from neutron import context
|
||||||
|
from neutron.db import api as db_api
|
||||||
|
from neutron.db import model_base
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import uuidutils
|
from neutron.openstack.common import uuidutils
|
||||||
from neutron.plugins.common import constants
|
from neutron.plugins.common import constants
|
||||||
@@ -27,7 +28,9 @@ from oslo_config import cfg
|
|||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
|
|
||||||
from gbpservice.neutron.db.grouppolicy import group_policy_db as gpdb
|
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 group_policy as gpolicy
|
||||||
|
from gbpservice.neutron.extensions import servicechain as service_chain
|
||||||
import gbpservice.neutron.tests
|
import gbpservice.neutron.tests
|
||||||
from gbpservice.neutron.tests.unit import common as cm
|
from gbpservice.neutron.tests.unit import common as cm
|
||||||
|
|
||||||
@@ -36,6 +39,7 @@ JSON_FORMAT = 'json'
|
|||||||
_uuid = uuidutils.generate_uuid
|
_uuid = uuidutils.generate_uuid
|
||||||
TESTDIR = os.path.dirname(os.path.abspath(gbpservice.neutron.tests.__file__))
|
TESTDIR = os.path.dirname(os.path.abspath(gbpservice.neutron.tests.__file__))
|
||||||
ETCDIR = os.path.join(TESTDIR, 'etc')
|
ETCDIR = os.path.join(TESTDIR, 'etc')
|
||||||
|
CHAIN_TENANT_ID = 'chain_owner'
|
||||||
|
|
||||||
|
|
||||||
class ApiManagerMixin(object):
|
class ApiManagerMixin(object):
|
||||||
@@ -123,21 +127,31 @@ class ApiManagerMixin(object):
|
|||||||
|
|
||||||
class GroupPolicyDBTestBase(ApiManagerMixin):
|
class GroupPolicyDBTestBase(ApiManagerMixin):
|
||||||
resource_prefix_map = dict(
|
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])
|
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||||
)
|
))
|
||||||
|
|
||||||
fmt = JSON_FORMAT
|
fmt = JSON_FORMAT
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
# Verify is an update of a proper GBP object
|
# 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):
|
def _is_gbp_resource(plural):
|
||||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||||
|
|
||||||
|
def _is_valid_resource(plural):
|
||||||
|
return _is_gbp_resource(plural) or _is_sc_resource(plural)
|
||||||
# Update Method
|
# Update Method
|
||||||
if item.startswith('update_'):
|
if item.startswith('update_'):
|
||||||
resource = item[len('update_'):]
|
resource = item[len('update_'):]
|
||||||
plural = cm.get_resource_plural(resource)
|
plural = cm.get_resource_plural(resource)
|
||||||
if _is_gbp_resource(plural):
|
if _is_valid_resource(plural):
|
||||||
def update_wrapper(id, **kwargs):
|
def update_wrapper(id, **kwargs):
|
||||||
return self._update_resource(id, resource, **kwargs)
|
return self._update_resource(id, resource, **kwargs)
|
||||||
return update_wrapper
|
return update_wrapper
|
||||||
@@ -145,7 +159,7 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||||||
if item.startswith('show_'):
|
if item.startswith('show_'):
|
||||||
resource = item[len('show_'):]
|
resource = item[len('show_'):]
|
||||||
plural = cm.get_resource_plural(resource)
|
plural = cm.get_resource_plural(resource)
|
||||||
if _is_gbp_resource(plural):
|
if _is_valid_resource(plural):
|
||||||
def show_wrapper(id, **kwargs):
|
def show_wrapper(id, **kwargs):
|
||||||
return self._show_resource(id, plural, **kwargs)
|
return self._show_resource(id, plural, **kwargs)
|
||||||
return show_wrapper
|
return show_wrapper
|
||||||
@@ -153,7 +167,7 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||||||
if item.startswith('create_'):
|
if item.startswith('create_'):
|
||||||
resource = item[len('create_'):]
|
resource = item[len('create_'):]
|
||||||
plural = cm.get_resource_plural(resource)
|
plural = cm.get_resource_plural(resource)
|
||||||
if _is_gbp_resource(plural):
|
if _is_valid_resource(plural):
|
||||||
def create_wrapper(**kwargs):
|
def create_wrapper(**kwargs):
|
||||||
return self._create_resource(resource, **kwargs)
|
return self._create_resource(resource, **kwargs)
|
||||||
return create_wrapper
|
return create_wrapper
|
||||||
@@ -161,13 +175,51 @@ class GroupPolicyDBTestBase(ApiManagerMixin):
|
|||||||
if item.startswith('delete_'):
|
if item.startswith('delete_'):
|
||||||
resource = item[len('delete_'):]
|
resource = item[len('delete_'):]
|
||||||
plural = cm.get_resource_plural(resource)
|
plural = cm.get_resource_plural(resource)
|
||||||
if _is_gbp_resource(plural):
|
if _is_valid_resource(plural):
|
||||||
def delete_wrapper(id, **kwargs):
|
def delete_wrapper(id, **kwargs):
|
||||||
return self._delete_resource(id, plural, **kwargs)
|
return self._delete_resource(id, plural, **kwargs)
|
||||||
return delete_wrapper
|
return delete_wrapper
|
||||||
|
|
||||||
raise AttributeError
|
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):
|
class GroupPolicyDBTestPlugin(gpdb.GroupPolicyDbPlugin):
|
||||||
|
|
||||||
@@ -178,26 +230,42 @@ DB_GP_PLUGIN_KLASS = (GroupPolicyDBTestPlugin.__module__ + '.' +
|
|||||||
GroupPolicyDBTestPlugin.__name__)
|
GroupPolicyDBTestPlugin.__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
||||||
|
|
||||||
|
supported_extension_aliases = ['servicechain']
|
||||||
|
|
||||||
|
|
||||||
|
DB_SC_PLUGIN_KLASS = (ServiceChainDBTestPlugin.__module__ + '.' +
|
||||||
|
ServiceChainDBTestPlugin.__name__)
|
||||||
|
|
||||||
|
|
||||||
class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
|
class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
|
||||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||||
|
|
||||||
def setUp(self, core_plugin=None, gp_plugin=None, service_plugins=None,
|
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
||||||
ext_mgr=None):
|
ext_mgr=None, gp_plugin=None):
|
||||||
if not gp_plugin:
|
sc_plugin = sc_plugin or DB_SC_PLUGIN_KLASS
|
||||||
gp_plugin = DB_GP_PLUGIN_KLASS
|
gp_plugin = gp_plugin or DB_GP_PLUGIN_KLASS
|
||||||
|
|
||||||
if not service_plugins:
|
if not service_plugins:
|
||||||
service_plugins = {'gp_plugin_name': gp_plugin}
|
service_plugins = {
|
||||||
nattr.PLURALS['nat_pools'] = 'nat_pool'
|
'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(
|
super(GroupPolicyDbTestCase, self).setUp(
|
||||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
plugin=core_plugin, ext_mgr=ext_mgr,
|
||||||
service_plugins=service_plugins
|
service_plugins=service_plugins
|
||||||
)
|
)
|
||||||
self.plugin = importutils.import_object(gp_plugin)
|
self.plugin = importutils.import_object(gp_plugin)
|
||||||
|
self._sc_plugin = importutils.import_object(sc_plugin)
|
||||||
if not ext_mgr:
|
if not ext_mgr:
|
||||||
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
test_policy_file = ETCDIR + "/test-policy.json"
|
engine = db_api.get_engine()
|
||||||
cfg.CONF.set_override('policy_file', test_policy_file)
|
model_base.BASEV2.metadata.create_all(engine)
|
||||||
|
|
||||||
plugins = manager.NeutronManager.get_service_plugins()
|
plugins = manager.NeutronManager.get_service_plugins()
|
||||||
self._gbp_plugin = plugins.get(constants.GROUP_POLICY)
|
self._gbp_plugin = plugins.get(constants.GROUP_POLICY)
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ class TestMappedGroupResourceAttrs(GroupPolicyMappingDbTestCase):
|
|||||||
ports = [port1['port']['id'], port2['port']['id']]
|
ports = [port1['port']['id'], port2['port']['id']]
|
||||||
pts = [self.create_policy_target(port_id=ports[0]),
|
pts = [self.create_policy_target(port_id=ports[0]),
|
||||||
self.create_policy_target(port_id=ports[1])]
|
self.create_policy_target(port_id=ports[1])]
|
||||||
|
self._test_list_resources('policy_target', pts)
|
||||||
self._test_list_resources('policy_target', [pts[0]],
|
self._test_list_resources('policy_target', [pts[0]],
|
||||||
query_params='port_id=' + ports[0])
|
query_params='port_id=' + ports[0])
|
||||||
|
|
||||||
@@ -221,8 +222,10 @@ class TestMappedGroupResourceAttrs(GroupPolicyMappingDbTestCase):
|
|||||||
l2_policies = [self.create_l2_policy(network_id=networks[0]),
|
l2_policies = [self.create_l2_policy(network_id=networks[0]),
|
||||||
self.create_l2_policy(network_id=networks[1])]
|
self.create_l2_policy(network_id=networks[1])]
|
||||||
self._test_list_resources(
|
self._test_list_resources(
|
||||||
'l2_policy', [l2_policies[0]],
|
'l2_policy', l2_policies)
|
||||||
query_params='network_id=' + networks[0])
|
self._test_list_resources(
|
||||||
|
'l2_policy', [l2_policies[0]],
|
||||||
|
query_params='network_id=' + networks[0])
|
||||||
|
|
||||||
def test_list_es(self):
|
def test_list_es(self):
|
||||||
with self.subnet(cidr='10.10.1.0/24') as subnet1:
|
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[0]),
|
||||||
self.create_external_segment(subnet_id=subnets[1])]
|
self.create_external_segment(subnet_id=subnets[1])]
|
||||||
self._test_list_resources(
|
self._test_list_resources(
|
||||||
'external_segment', [external_segments[0]],
|
'external_segment', external_segments)
|
||||||
query_params='subnet_id=' + subnets[0])
|
self._test_list_resources(
|
||||||
|
'external_segment', [external_segments[0]],
|
||||||
|
query_params='subnet_id=' + subnets[0])
|
||||||
|
|||||||
@@ -13,19 +13,11 @@
|
|||||||
|
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron import context
|
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.openstack.common import uuidutils
|
||||||
from neutron.plugins.common import constants
|
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_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.extensions import servicechain as service_chain
|
||||||
from gbpservice.neutron.tests.unit import common as cm
|
from gbpservice.neutron.tests.unit import common as cm
|
||||||
from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
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'
|
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 = (
|
GP_PLUGIN_KLASS = (
|
||||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin")
|
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin")
|
||||||
|
|
||||||
|
|
||||||
class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
class ServiceChainDbTestCase(test_group_policy_db.GroupPolicyDbTestCase):
|
||||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
|
||||||
|
|
||||||
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
||||||
ext_mgr=None, gp_plugin=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(
|
super(ServiceChainDbTestCase, self).setUp(
|
||||||
plugin=core_plugin, ext_mgr=ext_mgr,
|
gp_plugin=gp_plugin or GP_PLUGIN_KLASS, core_plugin=core_plugin,
|
||||||
service_plugins=service_plugins
|
sc_plugin=sc_plugin, service_plugins=service_plugins,
|
||||||
)
|
ext_mgr=ext_mgr)
|
||||||
self.plugin = importutils.import_object(sc_plugin)
|
self.plugin = self._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)
|
|
||||||
|
|
||||||
|
|
||||||
class TestServiceChainResources(ServiceChainDbTestCase):
|
class TestServiceChainResources(ServiceChainDbTestCase):
|
||||||
|
|||||||
@@ -149,16 +149,6 @@ class ApicMappingTestCase(
|
|||||||
self.driver.apic_manager.ext_net_dict.update(
|
self.driver.apic_manager.ext_net_dict.update(
|
||||||
self._build_external_dict(x[0], x[1]))
|
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',
|
def _create_simple_policy_rule(self, direction='bi', protocol='tcp',
|
||||||
port_range=80, shared=False,
|
port_range=80, shared=False,
|
||||||
action_type='allow', action_value=None):
|
action_type='allow', action_value=None):
|
||||||
|
|||||||
@@ -853,8 +853,8 @@ class TestNatPool(GroupPolicyPluginTestCase):
|
|||||||
|
|
||||||
class TestPolicyTarget(GroupPolicyPluginTestCase):
|
class TestPolicyTarget(GroupPolicyPluginTestCase):
|
||||||
|
|
||||||
def _test_cross_tenant_fails(self, is_admin=False):
|
def _test_cross_tenant(self, is_admin=False):
|
||||||
status = {False: 404, True: 400}
|
status = {False: 404, True: 201}
|
||||||
ptg = self.create_policy_target_group(
|
ptg = self.create_policy_target_group(
|
||||||
expected_res_status=201, tenant_id='tenant',
|
expected_res_status=201, tenant_id='tenant',
|
||||||
is_admin_context=is_admin)['policy_target_group']
|
is_admin_context=is_admin)['policy_target_group']
|
||||||
@@ -865,9 +865,6 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
|
|||||||
if not is_admin:
|
if not is_admin:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'GbpResourceNotFound', res['NeutronError']['type'])
|
'GbpResourceNotFound', res['NeutronError']['type'])
|
||||||
else:
|
|
||||||
self.assertEqual(
|
|
||||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
|
||||||
|
|
||||||
# Create EP without PTG
|
# Create EP without PTG
|
||||||
pt = self.create_policy_target(
|
pt = self.create_policy_target(
|
||||||
@@ -875,28 +872,25 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
|
|||||||
is_admin_context=is_admin)['policy_target']
|
is_admin_context=is_admin)['policy_target']
|
||||||
|
|
||||||
# Update PT fails
|
# Update PT fails
|
||||||
res = self.update_policy_target(pt['id'],
|
res = self.update_policy_target(
|
||||||
expected_res_status=status[is_admin],
|
pt['id'], tenant_id='another', policy_target_group_id=ptg['id'],
|
||||||
tenant_id='another',
|
expected_res_status=status[is_admin] if not is_admin else 200,
|
||||||
policy_target_group_id=ptg['id'],
|
is_admin_context=is_admin)
|
||||||
is_admin_context=is_admin)
|
|
||||||
if not is_admin:
|
if not is_admin:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'GbpResourceNotFound', res['NeutronError']['type'])
|
'GbpResourceNotFound', res['NeutronError']['type'])
|
||||||
else:
|
|
||||||
self.assertEqual(
|
|
||||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
|
||||||
|
|
||||||
def test_cross_tenant_fails(self):
|
def test_cross_tenant_fails(self):
|
||||||
self._test_cross_tenant_fails()
|
self._test_cross_tenant()
|
||||||
|
|
||||||
def test_cross_tenant_fails_admin(self):
|
def test_cross_tenant_admin(self):
|
||||||
self._test_cross_tenant_fails(True)
|
self._test_cross_tenant(True)
|
||||||
|
|
||||||
|
|
||||||
class TestPolicyAction(GroupPolicyPluginTestCase):
|
class TestPolicyAction(GroupPolicyPluginTestCase):
|
||||||
|
|
||||||
def test_redirect_value_fails(self):
|
def test_redirect_value(self):
|
||||||
scs_id = self._create_servicechain_spec(
|
scs_id = self._create_servicechain_spec(
|
||||||
node_types=['FIREWALL_TRANSPARENT'])
|
node_types=['FIREWALL_TRANSPARENT'])
|
||||||
res = self.create_policy_action(action_type='redirect',
|
res = self.create_policy_action(action_type='redirect',
|
||||||
@@ -913,9 +907,7 @@ class TestPolicyAction(GroupPolicyPluginTestCase):
|
|||||||
|
|
||||||
res = self.create_policy_action(
|
res = self.create_policy_action(
|
||||||
action_type='redirect', action_value=scs_id, tenant_id='different',
|
action_type='redirect', action_value=scs_id, tenant_id='different',
|
||||||
expected_res_status=400, is_admin_context=True)
|
expected_res_status=201, is_admin_context=True)
|
||||||
self.assertEqual(
|
|
||||||
'InvalidCrossTenantReference', res['NeutronError']['type'])
|
|
||||||
|
|
||||||
res = self.create_policy_action(
|
res = self.create_policy_action(
|
||||||
action_type='redirect', action_value=scs_id,
|
action_type='redirect', action_value=scs_id,
|
||||||
@@ -929,7 +921,7 @@ class TestPolicyAction(GroupPolicyPluginTestCase):
|
|||||||
node_types=['FIREWALL_TRANSPARENT'], shared=True)
|
node_types=['FIREWALL_TRANSPARENT'], shared=True)
|
||||||
self.create_policy_action(
|
self.create_policy_action(
|
||||||
action_type='redirect', action_value=scs_id, shared=True,
|
action_type='redirect', action_value=scs_id, shared=True,
|
||||||
expected_res_status=201)['policy_action']
|
expected_res_status=201)
|
||||||
data = {'servicechain_spec': {'shared': False}}
|
data = {'servicechain_spec': {'shared': False}}
|
||||||
scs_req = self.new_update_request(
|
scs_req = self.new_update_request(
|
||||||
SERVICECHAIN_SPECS, data, scs_id, self.fmt)
|
SERVICECHAIN_SPECS, data, scs_id, self.fmt)
|
||||||
|
|||||||
@@ -172,6 +172,17 @@ class TestPolicyRuleSet(OneConvergenceGBPDriverTestCase,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestServiceChain(OneConvergenceGBPDriverTestCase,
|
||||||
|
test_resource_mapping.TestServiceChain):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestServiceChainAdminOwner(
|
||||||
|
OneConvergenceGBPDriverTestCase,
|
||||||
|
test_resource_mapping.TestServiceChainAdminOwner):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestPolicyAction(OneConvergenceGBPDriverTestCase,
|
class TestPolicyAction(OneConvergenceGBPDriverTestCase,
|
||||||
test_resource_mapping.TestPolicyAction):
|
test_resource_mapping.TestPolicyAction):
|
||||||
pass
|
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 = (
|
GP_PLUGIN_KLASS = (
|
||||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
|
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
|
||||||
)
|
)
|
||||||
|
CHAIN_TENANT_ID = 'sci_owner'
|
||||||
|
|
||||||
|
|
||||||
class NodeCompositionPluginTestCase(
|
class NodeCompositionPluginTestCase(
|
||||||
@@ -155,7 +156,8 @@ class NodeCompositionPluginTestCase(
|
|||||||
provider = self.create_policy_target_group()['policy_target_group']
|
provider = self.create_policy_target_group()['policy_target_group']
|
||||||
consumer = self.create_policy_target_group()['policy_target_group']
|
consumer = self.create_policy_target_group()['policy_target_group']
|
||||||
management = self.create_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']
|
classifier = self.create_policy_classifier()['policy_classifier']
|
||||||
|
|
||||||
instance = self.create_servicechain_instance(
|
instance = self.create_servicechain_instance(
|
||||||
@@ -600,7 +602,7 @@ class NodeCompositionPluginTestCase(
|
|||||||
self.create_policy_target_group(
|
self.create_policy_target_group(
|
||||||
provided_policy_rule_sets={prs['id']: ''})
|
provided_policy_rule_sets={prs['id']: ''})
|
||||||
self.create_policy_target_group(
|
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')[
|
instances = self._list('servicechain_instances')[
|
||||||
'servicechain_instances']
|
'servicechain_instances']
|
||||||
self.assertEqual(1, len(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 = mock.Mock()
|
||||||
self.driver.get_plumbing_info.return_value = {}
|
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):
|
def _create_simple_chain(self):
|
||||||
node = self._create_profiled_servicechain_node(
|
node = self._create_profiled_servicechain_node(
|
||||||
service_type="LOADBALANCER",
|
service_type="LOADBALANCER",
|
||||||
@@ -718,9 +723,11 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||||||
for target in targets:
|
for target in targets:
|
||||||
self.assertEqual(node['id'], target.servicechain_node_id)
|
self.assertEqual(node['id'], target.servicechain_node_id)
|
||||||
pt = self.show_policy_target(
|
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'],
|
self.assertEqual(prov_cons[target.relationship]['id'],
|
||||||
pt['policy_target_group_id'])
|
pt['policy_target_group_id'])
|
||||||
|
self._assert_service_target_tenant(pt, provider)
|
||||||
self.assertNotEqual(old_relationship, target.relationship)
|
self.assertNotEqual(old_relationship, target.relationship)
|
||||||
old_relationship = target.relationship
|
old_relationship = target.relationship
|
||||||
|
|
||||||
@@ -731,7 +738,8 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||||||
self.assertEqual(0, len(new_targets))
|
self.assertEqual(0, len(new_targets))
|
||||||
for target in targets:
|
for target in targets:
|
||||||
self.show_policy_target(
|
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):
|
def test_pt_override(self):
|
||||||
context = n_context.get_admin_context()
|
context = n_context.get_admin_context()
|
||||||
@@ -742,7 +750,8 @@ class AgnosticChainPlumberTestCase(NodeCompositionPluginTestCase):
|
|||||||
targets = model.get_service_targets(context.session)
|
targets = model.get_service_targets(context.session)
|
||||||
self.assertEqual(1, len(targets))
|
self.assertEqual(1, len(targets))
|
||||||
pt = self.show_policy_target(
|
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'])
|
self.assertEqual(test_name, pt['name'])
|
||||||
|
|
||||||
def test_ptg_delete(self):
|
def test_ptg_delete(self):
|
||||||
@@ -839,3 +848,29 @@ class TestQuotasForServiceChain(test_base.ServiceChainPluginTestCase):
|
|||||||
self.assertRaises(webob.exc.HTTPClientError,
|
self.assertRaises(webob.exc.HTTPClientError,
|
||||||
self.create_policy_target_group,
|
self.create_policy_target_group,
|
||||||
consumed_policy_rule_sets={prs['id']: ''})
|
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,
|
STACK_DELETE_RETRY_WAIT,
|
||||||
group='simplechain')
|
group='simplechain')
|
||||||
super(SimpleChainDriverTestCase, self).setUp()
|
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):
|
class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||||
|
|||||||
Reference in New Issue
Block a user