Add support SFC encapsulation from networking-sfc

This feature allows choosing SFC encapsulation between MPLS
and NSH (default MPLS). It also apply SFC proxy to make use
of correlation.

Change-Id: Ia5eda02df415c9e3f6f035068176d60a14ffb68f
This commit is contained in:
Cong Phuoc Hoang 2018-11-29 04:14:24 +09:00
parent 4b9bcfeeef
commit 0e7fffbc77
12 changed files with 324 additions and 59 deletions

View File

@ -0,0 +1,56 @@
#!/bin/bash
#
# 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.
echo "Deleting VNF forwarding graph VNFFG1"
for vnffg in VNFFG1; do
vnffg_id=$(openstack vnf graph list | grep $vnffg | awk '{print $2}')
if [ -n "$vnffg_id" ]; then
openstack vnf graph delete $vnffg_id
fi
done
sleep 5
echo "Deleting VNFs"
for vnf_name in VNF1 VNF2; do
vnf_id=$(openstack vnf list | grep $vnf_name | awk '{print $2}')
if [ -n "$vnf_id" ]; then
openstack vnf delete $vnf_id
fi
done
echo "Deleting VNF descriptors"
for vnfd_name in VNFD1 VNFD2; do
vnfd_id=$(openstack vnf descriptor list | grep $vnfd_name | awk '{print $2}')
if [ -n "$vnfd_id" ]; then
openstack vnf descriptor delete $vnfd_id
fi
done
echo "Deleting http_client and http_server"
for server_name in http_client http_server; do
server_id=$(openstack server list | grep $server_name | awk '{print $2}')
if [ -n "$server_id" ]; then
openstack server delete $server_id
fi
done
sleep 5
echo "Deleting VIM0"
vim_id=$(openstack vim list | grep VIM0 | awk '{print $2}')
if [ -n "$vim_id" ]; then
openstack vim delete $vim_id
fi

View File

@ -0,0 +1,64 @@
#!/bin/bash
#
# 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.
network_name='net0'
network_id=$(openstack network list | grep $network_name | awk '{print $2}')
if [ -z "$network_id" ]; then
echo "Creating network net0"
openstack network create $network_name --provider-network-type=vxlan --provider-segment 1005
openstack subnet create --network $network_name --subnet-range 10.0.10.0/24 subnet-test
network_id=$(openstack network list | grep $network_name | awk '{print $2}')
fi
echo "Creating HTTP client"
openstack server create --flavor m1.tiny --image cirros-0.4.0-x86_64-disk --nic net-id=$network_id http_client
echo "Creating HTTP server"
openstack server create --flavor m1.tiny --image cirros-0.4.0-x86_64-disk --nic net-id=$network_id http_server
sleep 15
ip_src=$(openstack server list | grep http_client | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
network_source_port_id=$(openstack port list | grep $ip_src | awk '{print $2}')
ip_dst=$(openstack server list | grep http_server | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
network_dest_port_id=$(openstack port list | grep $ip_dst | awk '{print $2}')
echo "Creating/ Updating ns_param.yaml file"
cat > ../../samples/tosca-templates/vnffgd/vnffg-param-file.yaml << EOL
net_src_port_id: ${network_source_port_id}
ip_dst_pre: ${ip_dst}/24
net_dst_port_id: ${network_dest_port_id}
dst_port_range: 80-80
EOL
vim_default=$(openstack vim list | grep openstack | awk '{print $10}')
if [ "$vim_default" != "True" ]; then
echo "Creating default VIM"
cat > ./vim_config.yaml << EOL
auth_url: $OS_AUTH_URL
username: $OS_USERNAME
password: $OS_PASSWORD
project_name: $OS_PROJECT_NAME
project_domain_name: $OS_PROJECT_DOMAIN_ID
user_domain_name: $OS_USER_DOMAIN_ID
EOL
openstack vim register --config-file vim_config.yaml --is-default VIM0
rm ./vim_config.yaml
fi
echo "Create VNF1 and VNF2"
openstack vnf descriptor create --vnfd-file ../../samples/tosca-templates/vnffgd/tosca-vnffg-vnfd1.yaml VNFD1
openstack vnf create --vnfd-name VNFD1 --vim-name VIM0 VNF1
openstack vnf descriptor create --vnfd-file ../../samples/tosca-templates/vnffgd/tosca-vnffg-vnfd2.yaml VNFD2
openstack vnf create --vnfd-name VNFD2 --vim-name VIM0 VNF2

View File

@ -121,6 +121,7 @@ without "symmetrical", you can ommit "network_dst_port_id" and "ip_dst_prefix".
properties: properties:
id: 51 id: 51
symmetrical: true symmetrical: true
correlation: nsh
policy: policy:
type: ACL type: ACL
criteria: criteria:
@ -134,14 +135,24 @@ without "symmetrical", you can ommit "network_dst_port_id" and "ip_dst_prefix".
path: path:
- forwarder: VNFD1 - forwarder: VNFD1
capability: CP12 capability: CP12
sfc_encap: True
- forwarder: VNFD2 - forwarder: VNFD2
capability: CP22 capability: CP22
sfc_encap: False
In above template, users can set **symmetrical** in properties of a forwarding In above template, users can set **symmetrical** in properties of a forwarding
path create symmetrical VNFFG. If this property is not set, **symmetrical** path create symmetrical VNFFG. If this property is not set, **symmetrical**
will be specified by **--symmetrical** in create VNFFG command (default value will be specified by **--symmetrical** in create VNFFG command (default value
is False). is False).
In other hand, by setting **correlation** in properties let users can choose
SFC encapsulation between MPLS or NSH (default: MPLS). If sfc_encap is True,
port pair's correlation is set to same value with **correlation** to make use
of **correlation** that SFC Encapsulation provides, otherwise port pair's
correlation is set to None to install SFC proxy `SFC_PROXY`_. Detailed
information about SFC encapsulation can be found in Networking-SFC project
`SFC_ENCAPSULATION`_
You can use the sample VNFFGD template for symmetrical feature (in port chain) You can use the sample VNFFGD template for symmetrical feature (in port chain)
such as this `link <https://github.com/openstack/tacker/tree/master/samples/ such as this `link <https://github.com/openstack/tacker/tree/master/samples/
tosca-templates/vnffgd/tosca-vnffgd-symmetrical-sample.yaml>`_. tosca-templates/vnffgd/tosca-vnffgd-symmetrical-sample.yaml>`_.
@ -298,6 +309,20 @@ Using the below command query the list of existing VNFFG templates.
| 95d9-0199253db72e | myvnffg | ACTIVE | bd7829bf-85de-4f3b-960a-8482028bfb34| | 95d9-0199253db72e | myvnffg | ACTIVE | bd7829bf-85de-4f3b-960a-8482028bfb34|
+--------------------+---------+--------+-------------+--------+--------------+ +--------------------+---------+--------+-------------+--------+--------------+
To verify result, user can get information of port chain in networking-sfc:
.. code-block:: console
$ openstack sfc port chain list --fit-width
+-----------------------+-------------------+-----------------------+-----------------------+-----------------------+----------+
| ID | Name | Port Pair Groups | Flow Classifiers | Chain Parameters | Chain ID |
+-----------------------+-------------------+-----------------------+-----------------------+-----------------------+----------+
| 60d1a3ee-8455-415e- | VNFFG1-port-chain | [u'87d7d4c2-d2d1-4a99 | [u'02fa422c-9f40-4092 | {u'symmetric': False, | 51 |
| 8ff1-e0b6b9f9f277 | | -81fb-f3d5f51dd919', | -a8b0-c04355116e5e'] | u'correlation': | |
| | | u'81213b4c-0e5e-445d- | | u'nsh'} | |
| | | add6-dea2bf55078f'] | | | |
+-----------------------+-------------------+-----------------------+-----------------------+-----------------------+----------+
After the user located the VNFFG the subsequent action is to update it. After the user located the VNFFG the subsequent action is to update it.
Based on the appropriate choice, update VNFFG template. Based on the appropriate choice, update VNFFG template.
@ -394,6 +419,7 @@ By using the below VNFFGD template we can update the exisitng VNFFG.
properties: properties:
id: 52 id: 52
symmetrical: false symmetrical: false
correlation: nsh
policy: policy:
type: ACL type: ACL
criteria: criteria:
@ -406,8 +432,10 @@ By using the below VNFFGD template we can update the exisitng VNFFG.
path: path:
- forwarder: VNFD1 - forwarder: VNFD1
capability: CP1 capability: CP1
sfc_encap: True
- forwarder: VNFD2 - forwarder: VNFD2
capability: CP2 capability: CP2
sfc_encap: False
groups: groups:
VNFFG1: VNFFG1:
@ -458,3 +486,5 @@ Known Issues and Limitations
.. _VNF1: https://github.com/openstack/tacker/blob/master/samples/tosca-templates/vnffgd/tosca-vnffg-vnfd1.yaml .. _VNF1: https://github.com/openstack/tacker/blob/master/samples/tosca-templates/vnffgd/tosca-vnffg-vnfd1.yaml
.. _VNF2: https://github.com/openstack/tacker/blob/master/samples/tosca-templates/vnffgd/tosca-vnffg-vnfd2.yaml .. _VNF2: https://github.com/openstack/tacker/blob/master/samples/tosca-templates/vnffgd/tosca-vnffg-vnfd2.yaml
.. _SFC_PROXY: https://tools.ietf.org/html/rfc8300
.. _SFC_ENCAPSULATION: https://docs.openstack.org/networking-sfc/latest/contributor/ietf_sfc_encapsulation.html

View File

@ -0,0 +1,6 @@
---
features:
- |
Add support SFC encapsulation from networking-sfc. This feature allows
choosing SFC encapsulation between MPLS and NSH (default MPLS). It also
apply SFC proxy to make use of correlation.

View File

@ -25,6 +25,7 @@ topology_template:
user_data_format: RAW user_data_format: RAW
user_data: | user_data: |
#!/bin/sh #!/bin/sh
echo 1 > /proc/sys/net/ipv4/ip_forward
cat << EOF >> /etc/network/interfaces cat << EOF >> /etc/network/interfaces
auto eth1 auto eth1
iface eth1 inet dhcp iface eth1 inet dhcp

View File

@ -25,6 +25,7 @@ topology_template:
user_data_format: RAW user_data_format: RAW
user_data: | user_data: |
#!/bin/sh #!/bin/sh
echo 1 > /proc/sys/net/ipv4/ip_forward
cat << EOF >> /etc/network/interfaces cat << EOF >> /etc/network/interfaces
auto eth1 auto eth1
iface eth1 inet dhcp iface eth1 inet dhcp

View File

@ -0,0 +1,61 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: Sample VNFFG template
topology_template:
inputs:
net_src_port_id:
type: string
description: Port UUID of source VM.
dst_port_range:
type: string
description: Destination port range
ip_dst_pre:
type: string
description: Cidr format of destination ip.
net_dst_port_id:
type: string
description: Port UUID of dest VM.
node_templates:
Forwarding_path1:
type: tosca.nodes.nfv.FP.TackerV2
description: creates path (CP12->CP22)
properties:
id: 51
correlation: mpls
policy:
type: ACL
criteria:
- name: block_tcp
classifier:
network_src_port_id: { get_input: net_src_port_id }
destination_port_range: { get_input: dst_port_range }
ip_proto: 6
ip_dst_prefix: { get_input: ip_dst_pre }
network_dst_port_id: { get_input: net_dst_port_id }
path:
- forwarder: VNFD1
capability: CP12
sfc_encap: True
- forwarder: VNFD2
capability: CP22
sfc_encap: True
groups:
VNFFG1:
type: tosca.groups.nfv.VNFFG
description: HTTP to Corporate Net
properties:
vendor: tacker
version: 1.0
number_of_endpoints: 2
dependent_virtual_link: [VL12,VL22]
connection_point: [CP12,CP22]
constituent_vnfs: [VNFD1,VNFD2]
members: [Forwarding_path1]

View File

@ -502,8 +502,10 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
'capability'], vnf_id=vnf_mapping[element['forwarder']]) 'capability'], vnf_id=vnf_mapping[element['forwarder']])
# Check if this is a new VNF entry in the chain # Check if this is a new VNF entry in the chain
if element['forwarder'] != prev_forwarder: if element['forwarder'] != prev_forwarder:
chain_list.append({'name': vnf_info['name'], chain_list.append(
CP: [vnf_cp]}) {'name': vnf_info['name'],
CP: [vnf_cp],
'sfc_encap': element.get('sfc_encap', True)})
prev_forwarder = element['forwarder'] prev_forwarder = element['forwarder']
# Must be an egress CP # Must be an egress CP
else: else:
@ -512,7 +514,6 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
'forwarder']) 'forwarder'])
else: else:
chain_list[-1][CP].append(vnf_cp) chain_list[-1][CP].append(vnf_cp)
return chain_list return chain_list
@staticmethod @staticmethod
@ -1339,6 +1340,14 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
self.delete_vnffgd(context, vnffgd_id) self.delete_vnffgd(context, vnffgd_id)
def _get_symmetrical_template(self, context, vnffg): def _get_symmetrical_template(self, context, vnffg):
fp_prop = self._get_fp_properties(context, vnffg)
return fp_prop.get('symmetrical', False)
def _get_correlation_template(self, context, vnffg):
fp_prop = self._get_fp_properties(context, vnffg)
return fp_prop.get('correlation', 'mpls')
def _get_fp_properties(self, context, vnffg):
vnffgd_topo = None vnffgd_topo = None
if vnffg.get('vnffgd_template'): if vnffg.get('vnffgd_template'):
vnffgd_topo = vnffg['vnffgd_template']['topology_template'] vnffgd_topo = vnffg['vnffgd_template']['topology_template']
@ -1349,7 +1358,7 @@ class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
vnffg_name = list(vnffgd_topo['groups'].keys())[0] vnffg_name = list(vnffgd_topo['groups'].keys())[0]
nfp_name = vnffgd_topo['groups'][vnffg_name]['members'][0] nfp_name = vnffgd_topo['groups'][vnffg_name]['members'][0]
fp_prop = vnffgd_topo['node_templates'][nfp_name]['properties'] fp_prop = vnffgd_topo['node_templates'][nfp_name]['properties']
return fp_prop.get('symmetrical', None) return fp_prop
def _make_template_dict(self, template, fields=None): def _make_template_dict(self, template, fields=None):
res = {} res = {}

View File

@ -84,6 +84,7 @@ FC_MAP = {'name': 'name',
'network_dst_port_id': 'logical_destination_port'} 'network_dst_port_id': 'logical_destination_port'}
CONNECTION_POINT = 'connection_points' CONNECTION_POINT = 'connection_points'
SFC_ENCAP = 'sfc_encap'
def config_opts(): def config_opts():
@ -386,7 +387,7 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
raise ValueError('empty match field for input flow classifier') raise ValueError('empty match field for input flow classifier')
def create_chain(self, name, path_id, fc_ids, vnfs, symmetrical=False, def create_chain(self, name, path_id, fc_ids, vnfs, symmetrical=False,
auth_attr=None): correlation='mpls', auth_attr=None):
if not auth_attr: if not auth_attr:
LOG.warning("auth information required for n-sfc driver") LOG.warning("auth information required for n-sfc driver")
return None return None
@ -424,6 +425,12 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
ingress = cp_list[0] ingress = cp_list[0]
egress = cp_list[1] egress = cp_list[1]
# If sfc_encap is True, pp_corr is set to correlation to
# make use of correlation, otherwise pp_corr is set to None
# to install SFC proxy
sfc_encap = vnf.get(SFC_ENCAP, True)
pp_corr = correlation if sfc_encap else None
# valid_port_in_use function is used to find out the # valid_port_in_use function is used to find out the
# port_pair_group_id of the existing port pair group # port_pair_group_id of the existing port pair group
# which was created by ingress and egress of current VNF # which was created by ingress and egress of current VNF
@ -436,6 +443,8 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
port_pair['description'] = 'port pair for ' + vnf['name'] port_pair['description'] = 'port pair for ' + vnf['name']
port_pair['ingress'] = ingress port_pair['ingress'] = ingress
port_pair['egress'] = egress port_pair['egress'] = egress
port_pair['service_function_parameters'] = {
'correlation': pp_corr}
port_pair_id = neutronclient_.port_pair_create(port_pair) port_pair_id = neutronclient_.port_pair_create(port_pair)
if not port_pair_id: if not port_pair_id:
LOG.warning("Chain creation failed due to port pair" LOG.warning("Chain creation failed due to port pair"
@ -488,9 +497,9 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
port_chain['description'] = 'port-chain for Tacker VNFFG' port_chain['description'] = 'port-chain for Tacker VNFFG'
port_chain['port_pair_groups'] = port_pair_group_list port_chain['port_pair_groups'] = port_pair_group_list
port_chain['flow_classifiers'] = fc_ids port_chain['flow_classifiers'] = fc_ids
if symmetrical: port_chain['chain_parameters'] = {}
port_chain['chain_parameters'] = {} port_chain['chain_parameters']['symmetric'] = symmetrical
port_chain['chain_parameters']['symmetric'] = True port_chain['chain_parameters']['correlation'] = correlation
return neutronclient_.port_chain_create(port_chain) return neutronclient_.port_chain_create(port_chain)
def update_chain(self, chain_id, fc_ids, vnfs, def update_chain(self, chain_id, fc_ids, vnfs,

View File

@ -345,11 +345,13 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
name_match_list.append(classifier_dict) name_match_list.append(classifier_dict)
# grab the first VNF to check it's VIM type # grab the first VNF to check it's VIM type
# we have already checked that all VNFs are in the same VIM # we have already checked that all VNFs are in the same VIM
vim_obj = self._get_vim_from_vnf(context, vim_obj = self._get_vim_from_vnf(
list(vnffg_dict[ context, list(vnffg_dict['vnf_mapping'].values())[0])
'vnf_mapping'].values())[0])
# TODO(trozet): figure out what auth info we actually need to pass # TODO(trozet): figure out what auth info we actually need to pass
# to the driver. Is it a session, or is full vim obj good enough? # to the driver. Is it a session, or is full vim obj good enough?
correlation = super(NfvoPlugin, self)._get_correlation_template(
context, vnffg_info)
driver_type = vim_obj['type'] driver_type = vim_obj['type']
try: try:
fc_ids = [] fc_ids = []
@ -366,6 +368,7 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
vnfs=sfc['chain'], vnfs=sfc['chain'],
fc_ids=fc_ids, fc_ids=fc_ids,
symmetrical=sfc['symmetrical'], symmetrical=sfc['symmetrical'],
correlation=correlation,
auth_attr=vim_obj['auth_cred']) auth_attr=vim_obj['auth_cred'])
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():

View File

@ -651,14 +651,15 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('status', result) self.assertIn('status', result)
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY)
def test_create_vnffg_abstract_types(self): def test_create_vnffg_abstract_types(self):
with patch.object(TackerManager, 'get_service_plugins') as \ with patch.object(TackerManager, 'get_service_plugins') as \
@ -673,14 +674,15 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('status', result) self.assertIn('status', result)
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY)
@mock.patch('tacker.nfvo.nfvo_plugin.NfvoPlugin.create_vnffgd') @mock.patch('tacker.nfvo.nfvo_plugin.NfvoPlugin.create_vnffgd')
def test_create_vnffg_abstract_types_inline(self, mock_create_vnffgd): def test_create_vnffg_abstract_types_inline(self, mock_create_vnffgd):
@ -700,14 +702,15 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self.assertEqual('dummy_vnffg_inline', result['name']) self.assertEqual('dummy_vnffg_inline', result['name'])
mock_create_vnffgd.assert_called_once_with(mock.ANY, mock.ANY) mock_create_vnffgd.assert_called_once_with(mock.ANY, mock.ANY)
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY)
def test_create_vnffg_param_values(self): def test_create_vnffg_param_values(self):
with patch.object(TackerManager, 'get_service_plugins') as \ with patch.object(TackerManager, 'get_service_plugins') as \
@ -722,14 +725,15 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('status', result) self.assertIn('status', result)
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY)
def test_create_vnffg_no_classifier(self): def test_create_vnffg_no_classifier(self):
with patch.object(TackerManager, 'get_service_plugins') as \ with patch.object(TackerManager, 'get_service_plugins') as \
@ -744,14 +748,15 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('status', result) self.assertIn('status', result)
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY)
def test_create_vnffg_param_value_format_error(self): def test_create_vnffg_param_value_format_error(self):
with patch.object(TackerManager, 'get_service_plugins') as \ with patch.object(TackerManager, 'get_service_plugins') as \
@ -786,14 +791,16 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('status', result) self.assertIn('status', result)
self.assertEqual('PENDING_CREATE', result['status']) self.assertEqual('PENDING_CREATE', result['status'])
self._driver_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._driver_manager.invoke.assert_called_with(
name=mock.ANY, mock.ANY, mock.ANY,
path_id=mock.ANY, name=mock.ANY,
vnfs=mock.ANY, path_id=mock.ANY,
fc_ids=mock.ANY, vnfs=mock.ANY,
auth_attr=mock.ANY, fc_ids=mock.ANY,
symmetrical=mock.ANY auth_attr=mock.ANY,
) symmetrical=mock.ANY,
correlation=mock.ANY
)
def test_create_vnffg_duplicate_criteria(self): def test_create_vnffg_duplicate_criteria(self):
with patch.object(TackerManager, 'get_service_plugins') as \ with patch.object(TackerManager, 'get_service_plugins') as \

View File

@ -7,6 +7,10 @@ data_types:
capability: capability:
type: string type: string
required: true required: true
sfc_encap:
type: boolean
required: false
default: true
tosca.nfv.datatypes.aclType: tosca.nfv.datatypes.aclType:
properties: properties:
@ -308,6 +312,13 @@ node_types:
symmetrical: symmetrical:
type: boolean type: boolean
required: false required: false
default: false
correlation:
type: string
required: false
constraints:
- valid_values: [ mpls, nsh ]
default: mpls
policy: policy:
type: tosca.nfv.datatypes.policyTypeV2 type: tosca.nfv.datatypes.policyTypeV2
required: false required: false
@ -327,6 +338,13 @@ node_types:
symmetrical: symmetrical:
type: boolean type: boolean
required: false required: false
default: false
correlation:
type: string
required: false
constraints:
- valid_values: [ mpls, nsh ]
default: mpls
policy: policy:
type: tosca.nfv.datatypes.policyType type: tosca.nfv.datatypes.policyType
required: true required: true