Add Service Function Chain support(2)

1. What is the problem
Tricircle does not support update for Service Function Chain
Smoke test failed

2. What is the solution to the problem
Add Service Function Chain update support
There are some problems with networking-sfc and fixed it

3. What the features need to be implemented to the Tricircle
None

Signed-off-by: chenyaguang <chenyaguang@szzt.com.cn>
Co-Authored-By:tangzhuo <ztang@hnu.edu.cn>, yinxiulin <yinxiulin@huawei.com>
Change-Id: I407cb21c298a433bd12b2032b2af28ca7ebb68f0
This commit is contained in:
陈亚光 2018-04-02 16:04:35 +08:00 committed by chenyaguang
parent e941bab3be
commit d34b205cec
8 changed files with 641 additions and 29 deletions

View File

@ -16,8 +16,10 @@
from oslo_log import helpers as log_helpers from oslo_log import helpers as log_helpers
from oslo_log import log from oslo_log import log
from networking_sfc.db import sfc_db
from networking_sfc.services.flowclassifier.drivers import base as fc_driver from networking_sfc.services.flowclassifier.drivers import base as fc_driver
from neutron_lib.plugins import directory
from neutronclient.common import exceptions as client_exceptions from neutronclient.common import exceptions as client_exceptions
import tricircle.common.client as t_client import tricircle.common.client as t_client
@ -25,6 +27,8 @@ import tricircle.common.constants as t_constants
import tricircle.common.context as t_context import tricircle.common.context as t_context
from tricircle.common import xrpcapi from tricircle.common import xrpcapi
import tricircle.db.api as db_api import tricircle.db.api as db_api
from tricircle.network import central_plugin
import tricircle.network.exceptions as n_exceptions
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -79,6 +83,53 @@ class TricircleFcDriver(fc_driver.FlowClassifierDriverBase):
t_ctx, flowclassifier_id, t_constants.RT_FLOW_CLASSIFIER, t_ctx, flowclassifier_id, t_constants.RT_FLOW_CLASSIFIER,
t_ctx.project_id) t_ctx.project_id)
def _get_chain_id_by_flowclassifier_id(
self, context, fc_plugin, flowclassifier_id):
chain_classifier_assoc = fc_plugin._model_query(
context, sfc_db.ChainClassifierAssoc).filter_by(
flowclassifier_id=flowclassifier_id).first()
if chain_classifier_assoc:
return chain_classifier_assoc['portchain_id']
return None
def _get_net_id_by_portchain_id(self, context, portchain_id):
sfc_plugin = directory.get_plugin('sfc')
port_chain = sfc_plugin.get_port_chain(context, portchain_id)
if not port_chain:
raise n_exceptions.PortChainNotFound(portchain_id=portchain_id)
port_pairs = sfc_plugin.get_port_pairs(
context, {'portpairgroup_id': port_chain['port_pair_groups']})
if not port_pairs:
raise n_exceptions.PortPairsNotFoundForPortPairGroup(
portpairgroup_id=port_chain['port_pair_groups'])
core_plugin = directory.get_plugin()
port = super(central_plugin.TricirclePlugin, core_plugin
).get_port(context, port_pairs[0]['ingress'])
if not port:
raise n_exceptions.PortNotFound(port_id=port_pairs[0]['ingress'])
return port['network_id']
def update_flow_classifier_precommit(self, context):
plugin_context = context._plugin_context
t_ctx = t_context.get_context_from_neutron_context(plugin_context)
flowclassifier = context.current
mappings = db_api.get_bottom_mappings_by_top_id(
t_ctx, flowclassifier['id'], t_constants.RT_FLOW_CLASSIFIER)
if mappings:
portchain_id = self._get_chain_id_by_flowclassifier_id(
plugin_context, context._plugin, flowclassifier['id'])
if not portchain_id:
raise n_exceptions.PortChainNotFoundForFlowClassifier(
flowclassifier_id=flowclassifier['id'])
net_id = self._get_net_id_by_portchain_id(plugin_context,
portchain_id)
if not net_id:
raise n_exceptions.NetNotFoundForPortChain(
portchain_id=portchain_id)
self.xjob_handler.sync_service_function_chain(
t_ctx, flowclassifier['project_id'], portchain_id,
net_id, t_constants.POD_NOT_SPECIFIED)
@log_helpers.log_method_call @log_helpers.log_method_call
def create_flow_classifier_precommit(self, context): def create_flow_classifier_precommit(self, context):
pass pass

View File

@ -15,6 +15,7 @@
from oslo_log import helpers as log_helpers from oslo_log import helpers as log_helpers
from networking_sfc.db import sfc_db
from networking_sfc.services.sfc.drivers import base as sfc_driver from networking_sfc.services.sfc.drivers import base as sfc_driver
from oslo_log import log from oslo_log import log
@ -28,6 +29,7 @@ import tricircle.common.context as t_context
from tricircle.common import xrpcapi from tricircle.common import xrpcapi
import tricircle.db.api as db_api import tricircle.db.api as db_api
from tricircle.network import central_plugin from tricircle.network import central_plugin
import tricircle.network.exceptions as n_exceptions
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -47,6 +49,14 @@ class TricircleSfcDriver(sfc_driver.SfcDriverBase):
self.clients[region_name] = t_client.Client(region_name) self.clients[region_name] = t_client.Client(region_name)
return self.clients[region_name] return self.clients[region_name]
def _get_net_id_by_port_id(self, context, port_id):
core_plugin = directory.get_plugin()
port = super(central_plugin.TricirclePlugin, core_plugin
).get_port(context, port_id)
if not port:
raise n_exceptions.PortNotFound(port_id=port_id)
return port['network_id']
def _get_net_id_by_portpairgroups(self, context, def _get_net_id_by_portpairgroups(self, context,
sfc_plugin, port_pair_groups): sfc_plugin, port_pair_groups):
if not port_pair_groups: if not port_pair_groups:
@ -55,12 +65,7 @@ class TricircleSfcDriver(sfc_driver.SfcDriverBase):
context, {'portpairgroup_id': port_pair_groups}) context, {'portpairgroup_id': port_pair_groups})
if not port_pairs: if not port_pairs:
return None return None
# currently we only support port pairs in the same network return self._get_net_id_by_port_id(context, port_pairs[0]['ingress'])
first_ingress = port_pairs[0]['ingress']
core_plugin = directory.get_plugin()
ingress_port = super(central_plugin.TricirclePlugin, core_plugin
).get_port(context, first_ingress)
return ingress_port['network_id']
@log_helpers.log_method_call @log_helpers.log_method_call
def create_port_chain(self, context): def create_port_chain(self, context):
@ -160,6 +165,81 @@ class TricircleSfcDriver(sfc_driver.SfcDriverBase):
t_ctx, portpair_id, t_constants.RT_PORT_PAIR, t_ctx, portpair_id, t_constants.RT_PORT_PAIR,
t_ctx.project_id) t_ctx.project_id)
def update_port_chain_precommit(self, context):
plugin_context = context._plugin_context
t_ctx = t_context.get_context_from_neutron_context(plugin_context)
port_chain = context.current
mappings = db_api.get_bottom_mappings_by_top_id(
t_ctx, port_chain['id'], t_constants.RT_PORT_CHAIN)
if mappings:
net_id = self._get_net_id_by_portpairgroups(
plugin_context, context._plugin,
port_chain['port_pair_groups'])
if not net_id:
return
self.xjob_handler.sync_service_function_chain(
t_ctx, port_chain['project_id'], port_chain['id'],
net_id, t_constants.POD_NOT_SPECIFIED)
def _get_chain_id_by_group_id(self, context, sfc_plugin, portpairgroup_id):
chain_group_assoc = sfc_plugin._model_query(
context, sfc_db.ChainGroupAssoc).filter_by(
portpairgroup_id=portpairgroup_id).first()
if chain_group_assoc:
return chain_group_assoc['portchain_id']
return None
def update_port_pair_group_precommit(self, context):
plugin_context = context._plugin_context
t_ctx = t_context.get_context_from_neutron_context(
context._plugin_context)
port_pair_group = context.current
mappings = db_api.get_bottom_mappings_by_top_id(
t_ctx, port_pair_group['id'], t_constants.RT_PORT_PAIR_GROUP)
if mappings:
portchain_id = self._get_chain_id_by_group_id(
plugin_context, context._plugin, port_pair_group['id'])
if port_pair_group['port_pairs']:
net_id = self._get_net_id_by_portpairgroups(
plugin_context, context._plugin, [port_pair_group['id']])
elif context.original['port_pairs']:
portpair_id = context.original['port_pairs'][0]
port_pair = context._plugin._get_port_pair(
plugin_context, portpair_id)
net_id = self._get_net_id_by_port_id(
plugin_context, port_pair['ingress'])
else:
net_id = ''
if not portchain_id and not net_id:
return
self.xjob_handler.sync_service_function_chain(
t_ctx, port_pair_group['project_id'], portchain_id, net_id,
t_constants.POD_NOT_SPECIFIED)
def _get_chain_id_by_pair_id(self, context, sfc_plugin, portpair_id):
port_pair = sfc_plugin._get_port_pair(context, portpair_id)
if not port_pair:
raise n_exceptions.PortPairNotFound(portpair_id=portpair_id)
return self._get_chain_id_by_group_id(
context, sfc_plugin, port_pair['portpairgroup_id'])
def update_port_pair_precommit(self, context):
plugin_context = context._plugin_context
t_ctx = t_context.get_context_from_neutron_context(plugin_context)
port_pair = context.current
mappings = db_api.get_bottom_mappings_by_top_id(
t_ctx, port_pair['id'], t_constants.RT_PORT_PAIR)
if mappings:
portchain_id = self._get_chain_id_by_pair_id(
plugin_context, context._plugin, port_pair['id'])
net_id = self._get_net_id_by_port_id(
plugin_context, port_pair['ingress'])
if not portchain_id or not net_id:
return
self.xjob_handler.sync_service_function_chain(
t_ctx, port_pair['project_id'], portchain_id,
net_id, t_constants.POD_NOT_SPECIFIED)
@log_helpers.log_method_call @log_helpers.log_method_call
def update_port_chain(self, context): def update_port_chain(self, context):
pass pass

View File

@ -55,3 +55,29 @@ class SecurityGroupRuleNotFound(exceptions.NotFound):
class NetAttachedToNonLocalRouter(exceptions.Conflict): class NetAttachedToNonLocalRouter(exceptions.Conflict):
message = _('Network %(network_id)s has already been attached to non ' message = _('Network %(network_id)s has already been attached to non '
'local router %(router_id)s') 'local router %(router_id)s')
class PortNotFound(exceptions.NotFound):
message = _('Port for id %(port_id)s not found')
class PortPairsNotFoundForPortPairGroup(exceptions.NotFound):
message = _(
'Port pairs for port pair group %(portpairgroup_id)s not found')
class PortPairNotFound(exceptions.NotFound):
message = _('Port pair for id %(portpair_id)s not found')
class PortChainNotFound(exceptions.NotFound):
message = _('Port chain for id %(portchain_id)s not found')
class PortChainNotFoundForFlowClassifier(exceptions.NotFound):
message = _(
'Port chain for flow classifier %(flowclassifier_id)s not found')
class NetNotFoundForPortChain(exceptions.NotFound):
message = _('Net for port chain %(portchain_id)s not found')

View File

@ -229,6 +229,236 @@
retries: 10 retries: 10
condition: condition:
- status: SUCCESS - status: SUCCESS
- task_set_id: update-port-chain
depend: [preparation]
tasks:
- task_id: update-pc
region: central
type: port_chain
action:
target: preparation@pc@id
method: update
params:
name: pc-update
port_pair_groups: [preparation@ppg1@id]
flow_classifiers: []
- task_id: check-job
region: central
type: job
depend: [update-pc]
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS
- task_id: ppg1-1
region: region1
type: port_pair_group
query:
get_one: true
params:
name: ppg1
- task_id: ppg1-2
region: region2
type: port_pair_group
query:
get_one: true
params:
name: ppg1
- task_id: check-update-pc-1
region: region1
type: port_chain
depend:
- check-job
- ppg1-1
validate:
predicate: any
condition:
- name: pc-update
port_pair_groups: [ppg1-1@id]
flow_classifiers: []
- task_id: check-update-pc-2
region: region2
type: port_chain
depend:
- check-job
- ppg1-2
validate:
predicate: any
condition:
- name: pc-update
port_pair_groups: [ppg1-2@id]
flow_classifiers: []
- task_id: update-pc-to-original
region: central
type: port_chain
depend:
- check-update-pc-1
- check-update-pc-2
action:
target: preparation@pc@id
method: update
params:
name: pc
flow_classifiers: [preparation@fc@id]
port_pair_groups:
- preparation@ppg1@id
- preparation@ppg2@id
- task_set_id: update-flow-classifier
depend: [preparation]
tasks:
- task_id: update-fc
region: central
type: flow_classifier
action:
target: preparation@fc@id
method: update
params:
name: fc-update
- task_id: check-job
region: central
type: job
depend: [update-fc]
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS
- task_id: check-update-fc-1
region: region1
type: flow_classifier
depend: [check-job]
query:
get_one: true
params:
name: fc-update
- task_id: check-update-fc-2
region: region2
type: flow_classifier
depend: [check-job]
query:
get_one: true
params:
name: fc-update
- task_id: update-fc-to-original
region: central
type: flow_classifier
depend:
- check-update-fc-1
- check-update-fc-2
action:
target: preparation@fc@id
method: update
params:
name: fc
- task_set_id: update-port-pair-group
depend: [preparation]
tasks:
- task_id: update-ppg1
region: central
type: port_pair_group
action:
target: preparation@ppg1@id
method: update
params:
name: ppg1-update
port_pairs: []
- task_id: check-job
region: central
type: job
depend: [update-ppg1]
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS
- task_id: check-update-ppg1-1
region: region1
type: port_pair_group
depend: [check-job]
validate:
predicate: any
condition:
- name: ppg1-update
port_pairs: []
- task_id: check-update-ppg1-2
region: region2
type: port_pair_group
depend: [check-job]
validate:
predicate: any
condition:
- name: ppg1-update
port_pairs: []
- task_id: update-ppg1-to-original
region: central
type: port_pair_group
depend:
- check-update-ppg1-1
- check-update-ppg1-2
action:
target: preparation@ppg1@id
method: update
params:
name: ppg1
port_pairs: [preparation@pp1@id]
- task_set_id: update-port-pair
depend: [preparation]
tasks:
- task_id: update-pp1
region: central
type: port_pair
action:
target: preparation@pp1@id
method: update
params:
name: pp1-update
- task_id: check-job
region: central
type: job
depend: [update-pp1]
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS
- task_id: check-update-pp1-1
region: region1
type: port_pair
depend: [check-job]
query:
get_one: true
params:
name: pp1-update
- task_id: check-update-pp1-2
region: region2
type: port_pair
depend: [check-job]
query:
get_one: true
params:
name: pp1-update
- task_id: update-pp1-to-original
region: central
type: port_pair
depend:
- check-update-pp1-1
- check-update-pp1-2
action:
target: preparation@pp1@id
method: update
params:
name: pp1
- task_set_id: wait-for-job
tasks:
- task_id: check-job
region: central
type: job
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS
- task_set_id: check - task_set_id: check
depend: [preparation] depend: [preparation]
tasks: tasks:

View File

@ -20,11 +20,11 @@ python run_yaml_test.py trunk_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_US
if [ $? != 0 ]; then if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in trunk test" die $LINENO "Smoke test fails, error in trunk test"
fi fi
#echo "Start to run service function chain test" echo "Start to run service function chain test"
#python run_yaml_test.py sfc_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD" python run_yaml_test.py sfc_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD" "$OS_PROJECT_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
#if [ $? != 0 ]; then if [ $? != 0 ]; then
# die $LINENO "Smoke test fails, error in service function chain test" die $LINENO "Smoke test fails, error in service function chain test"
#fi fi
echo "Start to run qos policy function test" echo "Start to run qos policy function test"
python run_yaml_test.py qos_policy_rule_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD" "$OS_PROJECT_DOMAIN_ID" "$OS_USER_DOMAIN_ID" python run_yaml_test.py qos_policy_rule_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD" "$OS_PROJECT_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
if [ $? != 0 ]; then if [ $? != 0 ]; then

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
import copy
from mock import patch from mock import patch
import six import six
import unittest import unittest
@ -51,6 +52,9 @@ TOP_PORTPAIRS = _resource_store.TOP_SFC_PORT_PAIRS
TOP_PORTPAIRGROUPS = _resource_store.TOP_SFC_PORT_PAIR_GROUPS TOP_PORTPAIRGROUPS = _resource_store.TOP_SFC_PORT_PAIR_GROUPS
TOP_PORTCHAINS = _resource_store.TOP_SFC_PORT_CHAINS TOP_PORTCHAINS = _resource_store.TOP_SFC_PORT_CHAINS
TOP_FLOWCLASSIFIERS = _resource_store.TOP_SFC_FLOW_CLASSIFIERS TOP_FLOWCLASSIFIERS = _resource_store.TOP_SFC_FLOW_CLASSIFIERS
TOP_CHAIN_GROUP_ASSOCS = _resource_store.TOP_SFC_CHAIN_GROUP_ASSOCIATIONS
TOP_CHAIN_CLASSIFIER_ASSOCS = (
_resource_store.TOP_SFC_CHAIN_CLASSIFIER_ASSOCIATIONS)
BOTTOM1_PORTS = _resource_store.BOTTOM1_PORTS BOTTOM1_PORTS = _resource_store.BOTTOM1_PORTS
BOTTOM2_PORTS = _resource_store.BOTTOM2_PORTS BOTTOM2_PORTS = _resource_store.BOTTOM2_PORTS
BOTTOM1_PORTPAIRS = _resource_store.BOTTOM1_SFC_PORT_PAIRS BOTTOM1_PORTPAIRS = _resource_store.BOTTOM1_SFC_PORT_PAIRS
@ -174,16 +178,21 @@ class FakeClient(test_utils.FakeClient):
return super(FakeClient, self).create_resources(_type, ctx, body) return super(FakeClient, self).create_resources(_type, ctx, body)
def get_port_chains(self, ctx, portchain_id): def get_port_chains(self, ctx, portchain_id):
return self.get_resource('port_chain', ctx, portchain_id) res = self.get_resource('port_chain', ctx, portchain_id)
return copy.copy(res) if res else res
def get_port_pair_groups(self, ctx, portpairgroup_id): def get_port_pair_groups(self, ctx, portpairgroup_id):
return self.get_resource('port_pair_group', ctx, portpairgroup_id) res = self.get_resource('port_pair_group', ctx, portpairgroup_id)
return copy.copy(res) if res else res
def get_flow_classifiers(self, ctx, flowclassifier_id): def get_flow_classifiers(self, ctx, flowclassifier_id):
return self.get_resource('flow_classifier', ctx, flowclassifier_id) res = self.get_resource('flow_classifier', ctx, flowclassifier_id)
return copy.copy(res) if res else res
def list_port_pairs(self, ctx, filters=None): def list_port_pairs(self, ctx, filters=None, _copy=True):
return self.list_resources('port_pair', ctx, filters) portpairs = self.list_resources('port_pair', ctx, filters)
portpairs_copy = [copy.copy(pp) for pp in portpairs]
return portpairs_copy if _copy else portpairs
def list_flow_classifiers(self, ctx, filters=None): def list_flow_classifiers(self, ctx, filters=None):
return self.list_resources('flow_classifier', ctx, filters) return self.list_resources('flow_classifier', ctx, filters)
@ -194,15 +203,27 @@ class FakeClient(test_utils.FakeClient):
def list_port_pair_groups(self, ctx, filters=None): def list_port_pair_groups(self, ctx, filters=None):
return self.list_resources('port_pair_group', ctx, filters) return self.list_resources('port_pair_group', ctx, filters)
def update_port_pair_groups(self, ctx, id, port_pair_group): def update_port_pairs(self, ctx, portpair_id, body):
return self.update_resources('port_pair', ctx,
portpair_id, body)
def update_port_pair_groups(self, ctx, portpairgroup_id, body):
filters = [{'key': 'portpairgroup_id', filters = [{'key': 'portpairgroup_id',
'comparator': 'eq', 'comparator': 'eq',
'value': id}] 'value': portpairgroup_id}]
pps = self.list_port_pairs(ctx, filters) pps = self.list_port_pairs(ctx, filters, False)
for pp in pps: for pp in pps:
pp['portpairgroup_id'] = None pp['portpairgroup_id'] = None
return self.update_resources('port_pair_group', return self.update_resources('port_pair_group', ctx,
ctx, id, port_pair_group) portpairgroup_id, body)
def update_flow_classifiers(self, ctx, flowclassifier_id, body):
return self.update_resources('flow_classifier', ctx,
flowclassifier_id, body)
def update_port_chains(self, ctx, portchain_id, body):
return self.update_resources('port_chain', ctx,
portchain_id, body)
def get_ports(self, ctx, port_id): def get_ports(self, ctx, port_id):
return self.get_resource('port', ctx, port_id) return self.get_resource('port', ctx, port_id)
@ -314,13 +335,15 @@ class FakeSfcPlugin(sfc_plugin.TricircleSfcPlugin):
return FakeClient(region_name) return FakeClient(region_name)
def get_port_pairs(self, context, filters=None): def get_port_pairs(self, context, filters=None):
ret = []
client = self._get_client('top') client = self._get_client('top')
_filter = []
for key, values in six.iteritems(filters): for key, values in six.iteritems(filters):
for v in values: for v in values:
_filter.append( _filter = [{'key': key, 'comparator': 'eq', 'value': v}]
{'key': key, 'comparator': 'eq', 'value': v}) res = client.list_resources('port_pair', context, _filter)
return client.list_resources('port_pair', context, _filter) if res:
ret.extend(res)
return ret
def get_port_chain(self, context, id, fields=None): def get_port_chain(self, context, id, fields=None):
client = self._get_client('top') client = self._get_client('top')
@ -337,10 +360,25 @@ def fake_get_context_from_neutron_context(q_context):
return ctx return ctx
def fake_validate_pps_in_ppg(self, portpairs_list, id=None):
pass
def fake_make_port_pair_group_dict(self, port_pair_group, fields=None): def fake_make_port_pair_group_dict(self, port_pair_group, fields=None):
port_pairs = port_pair_group.port_pairs
if isinstance(port_pairs[0], test_utils.DotDict):
port_pair_group['port_pairs'] = [pp['id'] for pp in port_pairs]
return port_pair_group return port_pair_group
def fake_make_port_chain_dict(self, port_chain, fields=None):
port_chain['port_pair_groups'] = [assoc['portpairgroup_id'] for assoc in
port_chain.chain_group_associations]
port_chain['flow_classifiers'] = [assoc['flowclassifier_id'] for assoc in
port_chain.chain_classifier_associations]
return port_chain
def fake_make_port_pair_dict(self, port_pair, fields=None): def fake_make_port_pair_dict(self, port_pair, fields=None):
return port_pair return port_pair
@ -586,6 +624,17 @@ class PluginTest(unittest.TestCase):
return t_fc_id, b_fc_id return t_fc_id, b_fc_id
def _prepare_chain_group_assoc_test(self, chain_id, group_id):
chain_group_assoc = {'portpairgroup_id': group_id,
'portchain_id': chain_id}
TOP_CHAIN_GROUP_ASSOCS.append(DotDict(chain_group_assoc))
def _prepare_chain_classifier_assoc_test(self,
chain_id, flowclassifier_id):
chain_classifier_assoc = {'flowclassifier_id': flowclassifier_id,
'portchain_id': chain_id}
TOP_CHAIN_CLASSIFIER_ASSOCS.append(DotDict(chain_classifier_assoc))
def _prepare_port_chain_test(self, project_id, t_ctx, pod_name, def _prepare_port_chain_test(self, project_id, t_ctx, pod_name,
index, create_bottom, ids): index, create_bottom, ids):
t_pc_id = uuidutils.generate_uuid() t_pc_id = uuidutils.generate_uuid()
@ -879,6 +928,129 @@ class PluginTest(unittest.TestCase):
self.assertEqual(len(TOP_FLOWCLASSIFIERS), 0) self.assertEqual(len(TOP_FLOWCLASSIFIERS), 0)
self.assertEqual(len(ppg_mappings), 0) self.assertEqual(len(ppg_mappings), 0)
@patch.object(sfc_db.SfcDbPlugin, '_validate_pps_in_ppg',
new=fake_validate_pps_in_ppg)
@patch.object(sfc_db.SfcDbPlugin, '_make_port_chain_dict',
new=fake_make_port_chain_dict)
@patch.object(sfc_db.SfcDbPlugin, '_make_port_pair_group_dict',
new=fake_make_port_pair_group_dict)
@patch.object(sfc_db.SfcDbPlugin, '_make_port_pair_dict',
new=fake_make_port_pair_dict)
@patch.object(sfc_db.SfcDbPlugin, 'get_port_chain',
new=FakeSfcPlugin.get_port_chain)
@patch.object(db_base_plugin_v2.NeutronDbPluginV2, 'get_port',
new=FakeCorePlugin.get_port)
@patch.object(sfc_db.SfcDbPlugin, 'get_port_pairs',
new=FakeSfcPlugin.get_port_pairs)
@patch.object(context, 'get_context_from_neutron_context',
new=fake_get_context_from_neutron_context)
def test_update_service_function_chain(self):
project_id = TEST_TENANT_ID
q_ctx = FakeNeutronContext()
t_ctx = context.get_db_context()
self._basic_pod_setup()
fake_sfc_plugin = FakeSfcPlugin()
fake_fc_plugin = FakeFcPlugin()
t_net_id = self._prepare_net_test(project_id, t_ctx, 'pod_1')
src_port_id = self._prepare_port_test(project_id,
t_ctx, 'pod_1', t_net_id)
ingress1 = self._prepare_port_test(project_id, t_ctx,
'pod_1', t_net_id)
egress1 = self._prepare_port_test(project_id, t_ctx, 'pod_1', t_net_id)
t_pp1_id, b_pp1_id = self._prepare_port_pair_test(
project_id, t_ctx, 'pod_1', 0, ingress1, egress1, True)
t_ppg1_id, b_ppg1_id = self._prepare_port_pair_group_test(
project_id, t_ctx, 'pod_1', 0,
[t_pp1_id], True, [b_pp1_id])
ppg_mapping = {t_pp1_id: t_ppg1_id}
self._update_port_pair_test(ppg_mapping, TOP_PORTPAIRS)
t_fc1_id, b_fc1_id = self._prepare_flow_classifier_test(
project_id, t_ctx, 'pod_1', 0, src_port_id, True)
ids = {'t_ppg_id': [t_ppg1_id],
'b_ppg_id': [b_ppg1_id],
't_fc_id': [t_fc1_id],
'b_fc_id': [b_fc1_id]}
t_pc1_id, b_pc1_id = self._prepare_port_chain_test(
project_id, t_ctx, 'pod_1', 0, True, ids)
self._prepare_chain_group_assoc_test(t_pc1_id, t_ppg1_id)
self._prepare_chain_classifier_assoc_test(t_pc1_id, t_fc1_id)
pp_body = {'port_pair': {
'name': 'new_name',
'description': 'new_pp_description'}}
fake_sfc_plugin.update_port_pair(q_ctx, t_pp1_id, pp_body)
self.assertEqual(TOP_PORTPAIRS[0]['description'], 'new_pp_description')
self.assertEqual(TOP_PORTPAIRS[0]['name'], 'new_name')
self.assertEqual(BOTTOM1_PORTPAIRS[0]['description'],
'new_pp_description')
self.assertEqual(BOTTOM1_PORTPAIRS[0]['name'], 'new_name')
fc_body = {'flow_classifier': {
'name': 'new_name',
'description': 'new_fc_description'}}
fake_fc_plugin.update_flow_classifier(q_ctx, t_fc1_id, fc_body)
self.assertEqual(TOP_FLOWCLASSIFIERS[0]['name'], 'new_name')
self.assertEqual(TOP_FLOWCLASSIFIERS[0]['description'],
'new_fc_description')
self.assertEqual(BOTTOM1_FLOWCLASSIFIERS[0]['name'], 'new_name')
self.assertEqual(BOTTOM1_FLOWCLASSIFIERS[0]['description'],
'new_fc_description')
ingress2 = self._prepare_port_test(project_id, t_ctx,
'pod_1', t_net_id)
egress2 = self._prepare_port_test(project_id, t_ctx, 'pod_1', t_net_id)
t_pp2_id, b_pp2_id = self._prepare_port_pair_test(
project_id, t_ctx, 'pod_1', 0, ingress2, egress2, True)
ppg_body = {'port_pair_group': {
'name': 'new_name',
'description': 'new_ppg_description',
'port_pairs': [t_pp1_id, t_pp2_id]}}
ppg_mapping = {t_pp2_id: t_ppg1_id}
self._update_port_pair_test(ppg_mapping, TOP_PORTPAIRS)
fake_sfc_plugin.update_port_pair_group(q_ctx, t_ppg1_id, ppg_body)
self.assertEqual(TOP_PORTPAIRGROUPS[0]['name'], 'new_name')
self.assertEqual(TOP_PORTPAIRGROUPS[0]['description'],
'new_ppg_description')
self.assertEqual(TOP_PORTPAIRGROUPS[0]['port_pairs'],
[t_pp1_id, t_pp2_id])
self.assertEqual(BOTTOM1_PORTPAIRGROUPS[0]['name'], 'new_name')
self.assertEqual(BOTTOM1_PORTPAIRGROUPS[0]['description'],
'new_ppg_description')
self.assertEqual(BOTTOM1_PORTPAIRGROUPS[0]['port_pairs'],
[b_pp1_id, b_pp2_id])
t_ppg2_id, b_ppg2_id = self._prepare_port_pair_group_test(
project_id, t_ctx, 'pod_1', 0,
[], True, [])
t_fc2_id, b_fc2_id = self._prepare_flow_classifier_test(
project_id, t_ctx, 'pod_1', 0, src_port_id, True)
self._prepare_chain_group_assoc_test(t_pc1_id, t_ppg2_id)
self._prepare_chain_classifier_assoc_test(t_pc1_id, t_fc2_id)
pc_body = {'port_chain': {
'name': 'new_name',
'description': 'new_pc_description',
'port_pair_groups': [t_ppg1_id, t_ppg2_id],
'flow_classifiers': [t_fc1_id, t_fc2_id]}}
fake_sfc_plugin.update_port_chain(q_ctx, t_pc1_id, pc_body)
self.assertEqual(TOP_PORTCHAINS[0]['name'], 'new_name')
self.assertEqual(TOP_PORTCHAINS[0]['description'],
'new_pc_description')
self.assertEqual(TOP_PORTCHAINS[0]['port_pair_groups'],
[t_ppg1_id, t_ppg2_id])
self.assertEqual(TOP_PORTCHAINS[0]['flow_classifiers'],
[t_fc1_id, t_fc2_id])
self.assertEqual(BOTTOM1_PORTCHAINS[0]['name'], 'new_name')
self.assertEqual(BOTTOM1_PORTCHAINS[0]['description'],
'new_pc_description')
self.assertEqual(BOTTOM1_PORTCHAINS[0]['port_pair_groups'],
[b_ppg1_id, b_ppg2_id])
self.assertEqual(BOTTOM1_PORTCHAINS[0]['flow_classifiers'],
[b_fc1_id, b_fc2_id])
def tearDown(self): def tearDown(self):
core.ModelBase.metadata.drop_all(core.get_engine()) core.ModelBase.metadata.drop_all(core.get_engine())
test_utils.get_resource_store().clean() test_utils.get_resource_store().clean()

View File

@ -61,6 +61,8 @@ class ResourceStore(object):
('sfc_port_pair_groups', constants.RT_PORT_PAIR_GROUP), ('sfc_port_pair_groups', constants.RT_PORT_PAIR_GROUP),
('sfc_port_chains', constants.RT_PORT_CHAIN), ('sfc_port_chains', constants.RT_PORT_CHAIN),
('sfc_flow_classifiers', constants.RT_FLOW_CLASSIFIER), ('sfc_flow_classifiers', constants.RT_FLOW_CLASSIFIER),
('sfc_chain_group_associations', None),
('sfc_chain_classifier_associations', None),
('qos_policies', constants.RT_QOS), ('qos_policies', constants.RT_QOS),
('qos_bandwidth_limit_rules', ('qos_bandwidth_limit_rules',
'qos_bandwidth_limit_rules')] 'qos_bandwidth_limit_rules')]

View File

@ -1455,8 +1455,12 @@ class XManager(PeriodicTasks):
constants.JT_SFC_SYNC].split('#') constants.JT_SFC_SYNC].split('#')
if b_pod_id == constants.POD_NOT_SPECIFIED: if b_pod_id == constants.POD_NOT_SPECIFIED:
mappings = db_api.get_bottom_mappings_by_top_id( if net_id:
ctx, net_id, constants.RT_NETWORK) mappings = db_api.get_bottom_mappings_by_top_id(
ctx, net_id, constants.RT_NETWORK)
elif t_port_chain_id:
mappings = db_api.get_bottom_mappings_by_top_id(
ctx, t_port_chain_id, constants.RT_PORT_CHAIN)
b_pods = [mapping[0] for mapping in mappings] b_pods = [mapping[0] for mapping in mappings]
for b_pod in b_pods: for b_pod in b_pods:
self.xjob_handler.sync_service_function_chain( self.xjob_handler.sync_service_function_chain(
@ -1503,6 +1507,16 @@ class XManager(PeriodicTasks):
ctx, pp['project_id'], b_pod, {'id': pp_id}, ctx, pp['project_id'], b_pod, {'id': pp_id},
constants.RT_PORT_PAIR, {'port_pair': pp}, b_client, constants.RT_PORT_PAIR, {'port_pair': pp}, b_client,
ingress=pp['ingress']) ingress=pp['ingress'])
pp_body = {'port_pair': {
'name': pp['name'],
'description': pp['description']}}
try:
b_client.update_port_pairs(ctx, b_pp_id, pp_body)
except q_cli_exceptions.NotFound:
LOG.Error(('port pair: %(pp_id)s not found,'
'region name: %(name)s'),
{'pp_id': pp_id, 'name': region_name})
raise
b_pp_ids[key].append(b_pp_id) b_pp_ids[key].append(b_pp_id)
b_ppg_ids = [] b_ppg_ids = []
@ -1514,6 +1528,18 @@ class XManager(PeriodicTasks):
ctx, ppg['project_id'], b_pod, {'id': ppg_id}, ctx, ppg['project_id'], b_pod, {'id': ppg_id},
constants.RT_PORT_PAIR_GROUP, {'port_pair_group': ppg}, constants.RT_PORT_PAIR_GROUP, {'port_pair_group': ppg},
b_client, port_pairs=ppg['port_pairs']) b_client, port_pairs=ppg['port_pairs'])
ppg_body = {'port_pair_group': {
'name': ppg['name'],
'description': ppg['description'],
'port_pairs': ppg['port_pairs']
}}
try:
b_client.update_port_pair_groups(ctx, b_ppg_id, ppg_body)
except q_cli_exceptions.NotFound:
LOG.Error(('port pair group: %(t_ppg_id)s not found,'
'region name: %(name)s'),
{'t_ppg_id': ppg_id, 'name': region_name})
raise
b_ppg_ids.append(b_ppg_id) b_ppg_ids.append(b_ppg_id)
b_fc_ids = [] b_fc_ids = []
@ -1525,15 +1551,40 @@ class XManager(PeriodicTasks):
ctx, ppg['project_id'], b_pod, {'id': fc_id}, ctx, ppg['project_id'], b_pod, {'id': fc_id},
constants.RT_FLOW_CLASSIFIER, {'flow_classifier': fc}, constants.RT_FLOW_CLASSIFIER, {'flow_classifier': fc},
b_client, logical_source_port=fc['logical_source_port']) b_client, logical_source_port=fc['logical_source_port'])
fc_body = {'flow_classifier': {
'name': fc['name'],
'description': fc['description']
}}
try:
b_client.update_flow_classifiers(ctx, b_fc_id, fc_body)
except q_cli_exceptions.NotFound:
LOG.Error(('flow classifier: %(fc_id)s not found,'
'region name: %(name)s'),
{'fc_id': fc_id, 'name': region_name})
raise
b_fc_ids.append(b_fc_id) b_fc_ids.append(b_fc_id)
t_pc.pop('id') t_pc.pop('id')
t_pc['port_pair_groups'] = b_ppg_ids t_pc['port_pair_groups'] = b_ppg_ids
t_pc['flow_classifiers'] = b_fc_ids t_pc['flow_classifiers'] = b_fc_ids
self._prepare_sfc_bottom_element( b_pc_id = self._prepare_sfc_bottom_element(
ctx, t_pc['project_id'], b_pod, {'id': t_port_chain_id}, ctx, t_pc['project_id'], b_pod, {'id': t_port_chain_id},
constants.RT_PORT_CHAIN, {'port_chain': t_pc}, b_client, constants.RT_PORT_CHAIN, {'port_chain': t_pc}, b_client,
fc_id=b_fc_ids[0]) fc_id=b_fc_ids[0] if b_fc_ids else None)
pc_body = {'port_chain': {
'name': t_pc['name'],
'description': t_pc['description'],
'port_pair_groups': t_pc['port_pair_groups'],
'flow_classifiers': t_pc['flow_classifiers']
}}
try:
b_client.update_port_chains(ctx, b_pc_id, pc_body)
except q_cli_exceptions.NotFound:
LOG.Error(('port chain: %(pc_id)s not found, '
'region name: %(name)s'),
{'pc_id': t_port_chain_id, 'name': region_name})
raise
self.xjob_handler.recycle_resources(ctx, t_pc['project_id']) self.xjob_handler.recycle_resources(ctx, t_pc['project_id'])