Correct forwarding graph 'id' to match 'chain_id' in port chain

This patch lets forwarding graph 'id' to match 'chain_id' in
port chain. When users don't provide forwarding graph 'id',
that 'id' will be updated automatically by port chain creation
in networking-sfc.

Change-Id: I4e1dba75078593ba35f3995a26336ed538669579
This commit is contained in:
Cong Phuoc Hoang 2018-07-24 22:10:52 +09:00
parent 0da9469017
commit 4e1e284764
9 changed files with 97 additions and 21 deletions

View File

@ -449,15 +449,23 @@ as VNFFG ID and can not see any VNFFG is created.
| | 522bf | | | | |
+---------------------+---------------------+---------------------+--------+---------------------+-----------------------+
$ openstack vnf network forwarding path list
+--------------------------------------+------------------+--------+--------------------------------------+---------+
| ID | Name | Status | VNFFG ID | Path ID |
+--------------------------------------+------------------+--------+--------------------------------------+---------+
| 3d24b870-fe0d-4af9-a03f-9e0811859256 | Forwarding_path2 | ACTIVE | a601e938-a37b-493c-a48c-2c90aba73a77 | 52 |
| a2ca3a24-f02e-4629-b12c-54256886c050 | Forwarding_path1 | ACTIVE | 1f48603b-6740-4b94-a981-15de8c5c0fb3 | 51 |
+--------------------------------------+------------------+--------+--------------------------------------+---------+
$ openstack sfc port chain list --fit-width
+---------------------+---------------------+---------------------+---------------------+---------------------+----------+
| ID | Name | Port Pair Groups | Flow Classifiers | Chain Parameters | Chain ID |
+---------------------+---------------------+---------------------+---------------------+---------------------+----------+
| 2950fa88-d98f-4812 | NS2_VNFFG2_a7f77e11 | [u'e92feb43-4906-45 | [u'3eff5973-c612-43 | {u'symmetric': | 1 |
| 2950fa88-d98f-4812 | NS2_VNFFG2_a7f77e11 | [u'e92feb43-4906-45 | [u'3eff5973-c612-43 | {u'symmetric': | 51 |
| -830a-ae15452a8c08 | -d847-4090-aa79 | 21-852f- | 83-aee2-d1eb05c832e | False, | |
| | -496610c522bf-port- | 1940c2f344a6'] | e'] | u'correlation': | |
| | chain | | | u'mpls'} | |
| 61c938f9-15a1-4ec8 | NS2_VNFFG1_a7f77e11 | [u'e92feb43-4906-45 | [u'b4cb5575-cb3c-41 | {u'symmetric': | 2 |
| 61c938f9-15a1-4ec8 | NS2_VNFFG1_a7f77e11 | [u'e92feb43-4906-45 | [u'b4cb5575-cb3c-41 | {u'symmetric': | 52 |
| -8dec-44e5f8af70ff | -d847-4090-aa79 | 21-852f- | a3-8649-c69e0cd48db | False, | |
| | -496610c522bf-port- | 1940c2f344a6', u'82 | e'] | u'correlation': | |
| | chain | dab526-540e-4047 | | u'mpls'} | |

View File

@ -0,0 +1,38 @@
# Copyright 2018 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.
#
"""Change nullable value of path_id
Revision ID: 13ecc2dd6f7f
Revises: 4747cc26b9c6
Create Date: 2018-07-24 16:47:01.378226
"""
# revision identifiers, used by Alembic.
revision = '13ecc2dd6f7f'
down_revision = '4747cc26b9c6'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.alter_column('vnffgchains', 'path_id',
existing_type=sa.String(length=255),
nullable=True)
op.alter_column('vnffgnfps', 'path_id',
existing_type=sa.String(length=255),
nullable=True)

View File

@ -1 +1 @@
4747cc26b9c6
13ecc2dd6f7f

View File

@ -115,7 +115,7 @@ class VnffgNfp(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
uselist=False)
status = sa.Column(sa.String(255), nullable=False)
path_id = sa.Column(sa.String(255), nullable=False)
path_id = sa.Column(sa.String(255), nullable=True)
# symmetry of forwarding path
symmetrical = sa.Column(sa.Boolean(), default=False)
@ -134,7 +134,7 @@ class VnffgChain(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
# chain
chain = sa.Column(types.Json)
path_id = sa.Column(sa.String(255), nullable=False)
path_id = sa.Column(sa.String(255), nullable=True)
nfp_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgnfps.id'))
@ -376,6 +376,17 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
# create NFP dict
nfp_dict = self._create_nfp_pre(template_db)
LOG.debug('NFP: %s', nfp_dict)
path_id = nfp_dict['path_id']
try:
if path_id:
vnffgNfp_db = (self._model_query(context, VnffgNfp).
filter(VnffgNfp.path_id == path_id).one())
raise nfvo.NfpDuplicatePathID(path_id=path_id,
nfp_name=vnffgNfp_db.name,
vnffg_name=name)
except orm_exc.NoResultFound:
pass
vnffg_db = Vnffg(id=vnffg_id,
tenant_id=tenant_id,
name=name,
@ -401,7 +412,7 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
tenant_id=tenant_id,
name=nfp_dict['name'],
status=constants.PENDING_CREATE,
path_id=nfp_dict['path_id'],
path_id=path_id,
symmetrical=symmetrical)
context.session.add(nfp_db)
@ -414,7 +425,7 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
symmetrical=symmetrical,
chain=chain,
nfp_id=nfp_id,
path_id=nfp_dict['path_id'])
path_id=path_id)
context.session.add(sfc_db)
@ -446,13 +457,8 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
# we assume only one NFP for initial implementation
nfp_dict['name'] = template['groups'][vnffg_name]['members'][0]
nfp_dict['path_id'] = template['node_templates'][nfp_dict['name']][
'properties']['id']
if not nfp_dict['path_id']:
# TODO(trozet): do we need to check if this path ID is already
# taken by another VNFFG
nfp_dict['path_id'] = random.randint(1, 16777216)
'properties'].get('id', None)
# 'path_id' will be updated when creating port chain is done
return nfp_dict
def _create_port_chain(self, context, vnf_mapping, template_db, nfp_name):
@ -760,7 +766,7 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
# called internally, not by REST API
# instance_id = None means error on creation
def _create_vnffg_post(self, context, sfc_instance_id,
def _create_vnffg_post(self, context, sfc_instance_id, path_id,
classifiers_map, vnffg_dict):
LOG.debug('SFC created instance is %s', sfc_instance_id)
LOG.debug('Flow Classifiers created instances are %s',
@ -768,11 +774,16 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
nfp_dict = self.get_nfp(context, vnffg_dict['forwarding_paths'])
sfc_id = nfp_dict['chain_id']
with context.session.begin(subtransactions=True):
nfp_query = (self._model_query(context, VnffgNfp).
filter(VnffgNfp.id == nfp_dict['id']).
filter(VnffgNfp.status == constants.PENDING_CREATE).
one())
nfp_query.update({'path_id': path_id})
query = (self._model_query(context, VnffgChain).
filter(VnffgChain.id == sfc_id).
filter(VnffgChain.status == constants.PENDING_CREATE).
one())
query.update({'instance_id': sfc_instance_id})
query.update({'instance_id': sfc_instance_id, 'path_id': path_id})
if sfc_instance_id is None:
query.update({'status': constants.ERROR})
else:

View File

@ -208,6 +208,11 @@ class NfpDuplicatePolicyCriteria(exceptions.TackerException):
message = _('The %(first_dict)s and %(sec_dict)s are overlapped')
class NfpDuplicatePathID(exceptions.TackerException):
message = _('The path_id %(path_id)s is overlapped with '
'NFP %(nfp_name)s in %(vnffg_name)s')
class NfpPolicyTypeError(exceptions.PolicyCheckError):
message = _('Unsupported Policy Type: %(type)s')

View File

@ -387,7 +387,7 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
raise ValueError('empty match field for input flow classifier')
def create_chain(self, name, fc_ids, vnfs, symmetrical=False,
def create_chain(self, name, path_id, fc_ids, vnfs, symmetrical=False,
auth_attr=None):
if not auth_attr:
LOG.warning("auth information required for n-sfc driver")
@ -485,6 +485,8 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
# TODO(s3wong): should the chain name be given as a parameter?
port_chain = {}
port_chain['name'] = name + '-port-chain'
if path_id:
port_chain['chain_id'] = path_id
port_chain['description'] = 'port-chain for Tacker VNFFG'
port_chain['port_pair_groups'] = port_pair_group_list
port_chain['flow_classifiers'] = fc_ids
@ -915,7 +917,7 @@ class NeutronClient(object):
raise ValueError(str(e))
if pc and len(pc):
return pc['port_chain']['id']
return pc['port_chain']['id'], pc['port_chain']['chain_id']
else:
return None

View File

@ -351,9 +351,10 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
name=item['name'],
fc=item['match'],
auth_attr=vim_obj['auth_cred']))
sfc_id = self._vim_drivers.invoke(driver_type,
sfc_id, path_id = self._vim_drivers.invoke(driver_type,
'create_chain',
name=vnffg_dict['name'],
path_id=sfc['path_id'],
vnfs=sfc['chain'],
fc_ids=fc_ids,
symmetrical=sfc['symmetrical'],
@ -364,7 +365,7 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
classifiers_map = super(NfvoPlugin, self). \
create_classifiers_map(nfp['classifier_ids'], fc_ids)
super(NfvoPlugin, self)._create_vnffg_post(context, sfc_id,
classifiers_map,
path_id, classifiers_map,
vnffg_dict)
super(NfvoPlugin, self)._create_vnffg_status(context, vnffg_dict)
return vnffg_dict

View File

@ -183,6 +183,7 @@ class TestChainSFC(base.TestCase):
vnfs = [vnf_1, vnf_2, vnf_3]
chain_id = self.sfc_driver.create_chain(name='fake_ffg',
path_id=None,
fc_ids=fc_id,
vnfs=vnfs,
auth_attr=auth_attr)
@ -238,6 +239,7 @@ class TestChainSFC(base.TestCase):
vnfs = [vnf_1, vnf_2, vnf_3]
result = self.sfc_driver.create_chain(name='fake_ffg',
path_id=None,
fc_ids=fc_id,
vnfs=vnfs,
auth_attr=auth_attr)
@ -269,6 +271,7 @@ class TestChainSFC(base.TestCase):
vnfs = [vnf_1, vnf_2, vnf_3]
chain_id = self.sfc_driver.create_chain(name='fake_ffg',
path_id=None,
fc_ids=fc_id,
vnfs=vnfs,
auth_attr=auth_attr)

View File

@ -54,9 +54,11 @@ def _get_template(name):
class FakeDriverManager(mock.Mock):
def invoke(self, *args, **kwargs):
if any(x in ['create', 'create_chain', 'create_flow_classifier'] for
if any(x in ['create', 'create_flow_classifier'] for
x in args):
return uuidutils.generate_uuid()
elif 'create_chain' in args:
return uuidutils.generate_uuid(), uuidutils.generate_uuid()
elif 'execute_workflow' in args:
mock_execution = mock.Mock()
mock_execution.id.return_value = \
@ -656,6 +658,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,
@ -677,6 +680,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,
@ -703,6 +707,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
mock_create_vnffgd.assert_called_once_with(mock.ANY, mock.ANY)
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,
@ -724,6 +729,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,
@ -745,6 +751,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,
@ -787,6 +794,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
name=mock.ANY,
path_id=mock.ANY,
vnfs=mock.ANY,
fc_ids=mock.ANY,
auth_attr=mock.ANY,