Add service function chaining smoke test

1. What is the problem
Smoke test engine has been implemented[1] and tests for single
north-south gateway topology and multiple north-south gateway
topology have been added. But we still lack test for service
function chain.

2. What is the solution for the problem
Define service function chain related test using YAML file.

3. What features need to be implemented to the Tricircle to
realize the solution
N/A

[1] https://review.openstack.org/#/c/477500/

Implements: blueprint smoke-test-engine
Change-Id: I02a9bc8a6c7cebe166a633764e424e3812a9a042
This commit is contained in:
zhiyuan_cai 2017-07-13 14:46:56 +08:00
parent eb2662b33e
commit 8af1e2e08b
11 changed files with 806 additions and 5 deletions

View File

@ -282,8 +282,18 @@ function start_central_neutron_server {
iniset $NEUTRON_CONF.$server_index client auto_refresh_endpoint True
iniset $NEUTRON_CONF.$server_index client top_region_name $CENTRAL_REGION_NAME
local service_plugins=''
if [ "$TRICIRCLE_ENABLE_TRUNK" == "True" ]; then
iniset $NEUTRON_CONF.$server_index DEFAULT service_plugins "tricircle.network.central_trunk_plugin.TricircleTrunkPlugin"
service_plugins+=",tricircle.network.central_trunk_plugin.TricircleTrunkPlugin"
fi
if [ "$TRICIRCLE_ENABLE_SFC" == "True" ]; then
service_plugins+=",networking_sfc.services.flowclassifier.plugin.FlowClassifierPlugin,tricircle.network.central_sfc_plugin.TricircleSfcPlugin"
iniset $NEUTRON_CONF.$server_index sfc drivers tricircle_sfc
iniset $NEUTRON_CONF.$server_index flowclassifier drivers tricircle_fc
fi
if [ -n service_plugins ]; then
service_plugins=$(echo $service_plugins| sed 's/^,//')
iniset $NEUTRON_CONF.$server_index DEFAULT service_plugins "$service_plugins"
fi
local type_drivers=''

View File

@ -12,6 +12,7 @@ TRICIRCLE_DEPLOY_WITH_CELL=${TRICIRCLE_DEPLOY_WITH_CELL:-False}
# extensions working with tricircle
TRICIRCLE_ENABLE_TRUNK=${TRICIRCLE_ENABLE_TRUNK:-False}
TRICIRCLE_ENABLE_SFC=${TRICIRCLE_ENABLE_SFC:-False}
# these default settings are used for devstack based gate/check jobs
TRICIRCLE_DEFAULT_VLAN_BRIDGE=${TRICIRCLE_DEFAULT_VLAN_BRIDGE:-br-vlan}

View File

@ -26,6 +26,7 @@ GATE_DEST=$BASE/new
function _setup_tricircle_multinode {
export PROJECTS="openstack/networking-sfc $PROJECTS"
PRIMARY_NODE_IP=$(cat /etc/nodepool/primary_node_private)
SUBNODE_IP=$(head -n1 /etc/nodepool/sub_nodes_private)
@ -39,11 +40,14 @@ function _setup_tricircle_multinode {
export OVERRIDE_ENABLED_SERVICES+="dstat,peakmem_tracker,rabbit,mysql"
ENABLE_TRICIRCLE="enable_plugin tricircle https://git.openstack.org/openstack/tricircle/"
ENABLE_SFC="enable_plugin networking-sfc https://git.openstack.org/openstack/networking-sfc/"
# Configure primary node
export DEVSTACK_LOCAL_CONFIG="$ENABLE_TRICIRCLE"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"$ENABLE_SFC"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TRICIRCLE_START_SERVICES=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TRICIRCLE_ENABLE_TRUNK=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TRICIRCLE_ENABLE_SFC=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"REGION_NAME=RegionOne"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"HOST_IP=$PRIMARY_NODE_IP"
@ -52,6 +56,8 @@ function _setup_tricircle_multinode {
ML2_CONFIG+=$'\n'"[ml2]"
ML2_CONFIG+=$'\n'"mechanism_drivers = openvswitch,linuxbridge,l2population"
ML2_CONFIG+=$'\n'"[agent]"
ML2_CONFIG+=$'\n'"extensions=sfc"
ML2_CONFIG+=$'\n'"arp_responder=True"
ML2_CONFIG+=$'\n'"tunnel_types=vxlan"
ML2_CONFIG+=$'\n'"l2_population=True"
@ -59,8 +65,10 @@ function _setup_tricircle_multinode {
# Configure sub-node
export DEVSTACK_SUBNODE_CONFIG="$ENABLE_TRICIRCLE"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"$ENABLE_SFC"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"TRICIRCLE_START_SERVICES=False"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"TRICIRCLE_ENABLE_TRUNK=True"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"TRICIRCLE_ENABLE_SFC=True"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"REGION_NAME=RegionTwo"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"HOST_IP=$SUBNODE_IP"
export DEVSTACK_SUBNODE_CONFIG+=$'\n'"KEYSTONE_REGION_NAME=RegionOne"

View File

@ -0,0 +1,556 @@
- task_set_id: preparation
tasks:
- task_id: image1
type: image
region: region1
query:
get_one: true
- task_id: image2
type: image
region: region2
query:
get_one: true
- task_id: net1
type: network
region: central
params:
name: net1
provider_network_type: vxlan
- task_id: subnet1
type: subnet
region: central
depend: [net1]
params:
name: subnet1
ip_version: 4
cidr: 10.0.1.0/24
network_id: net1@id
- task_id: p1
type: port
region: central
depend:
- net1
- subnet1
params:
name: p1
network_id: net1@id
- task_id: p2
type: port
region: central
depend:
- net1
- subnet1
params:
name: p2
network_id: net1@id
- task_id: p3
type: port
region: central
depend:
- net1
- subnet1
params:
name: p3
network_id: net1@id
- task_id: p4
type: port
region: central
depend:
- net1
- subnet1
params:
name: p4
network_id: net1@id
- task_id: p5
type: port
region: central
depend:
- net1
- subnet1
params:
name: p5
network_id: net1@id
- task_id: p6
type: port
region: central
depend:
- net1
- subnet1
params:
name: p6
network_id: net1@id
- task_id: vm_sfc1
region: region1
type: server
depend:
- p2
- p3
- image1
params:
flavor_id: 1
image_id: image1@id
name: vm_sfc1
networks:
- port: p2@id
- port: p3@id
- task_id: vm_sfc2
region: region2
type: server
depend:
- p4
- p5
- image2
params:
flavor_id: 1
image_id: image2@id
name: vm_sfc2
networks:
- port: p4@id
- port: p5@id
- task_id: vm_src
region: region1
type: server
depend:
- p1
- image1
params:
flavor_id: 1
image_id: image1@id
name: vm_src
networks:
- port: p1@id
- task_id: vm_dst
region: region2
type: server
depend:
- p6
- image2
params:
flavor_id: 1
image_id: image2@id
name: vm_dst
networks:
- port: p6@id
- task_id: wait-servers1
region: region1
type: server
depend:
- vm_src
- vm_sfc1
validate:
predicate: any
retries: 10
condition:
- status: ACTIVE
name: vm_src
- status: ACTIVE
name: vm_sfc1
- task_id: wait-servers2
region: region2
type: server
depend:
- wait-servers1
- vm_dst
- vm_sfc2
validate:
predicate: any
retries: 10
condition:
- status: ACTIVE
name: vm_dst
- status: ACTIVE
name: vm_sfc2
- task_id: pp1
region: central
type: port_pair
depend:
- vm_sfc1
- p2
- p3
- wait-servers2
params:
name: pp1
ingress: p2@id
egress: p3@id
- task_id: pp2
region: central
type: port_pair
depend:
- vm_sfc2
- p4
- p5
- wait-servers2
params:
name: pp2
ingress: p4@id
egress: p5@id
- task_id: ppg1
region: central
type: port_pair_group
depend: [pp1]
params:
name: ppg1
port_pairs: [pp1@id]
- task_id: ppg2
region: central
type: port_pair_group
depend: [pp2]
params:
name: ppg2
port_pairs: [pp2@id]
- task_id: fc
region: central
type: flow_classifier
depend: [p1]
params:
name: fc
logical_source_port: p1@id
source_ip_prefix: 10.0.1.0/24
- task_id: pc
region: central
type: port_chain
depend:
- ppg1
- ppg2
- fc
params:
name: pc
flow_classifiers: [fc@id]
port_pair_groups:
- ppg1@id
- ppg2@id
- 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
depend: [preparation]
tasks:
- task_id: pp1-1
region: region1
type: port_pair
query:
get_one: true
params:
name: pp1
- task_id: pp1-2
region: region2
type: port_pair
query:
get_one: true
params:
name: pp1
- task_id: pp2-1
region: region1
type: port_pair
query:
get_one: true
params:
name: pp2
- task_id: pp2-2
region: region2
type: port_pair
query:
get_one: true
params:
name: pp2
- 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: ppg2-1
region: region1
type: port_pair_group
query:
get_one: true
params:
name: ppg2
- task_id: ppg2-2
region: region2
type: port_pair_group
query:
get_one: true
params:
name: ppg2
- task_id: fc-1
region: region1
type: flow_classifier
query:
get_one: true
params:
name: fc
- task_id: fc-2
region: region2
type: flow_classifier
query:
get_one: true
params:
name: fc
- task_id: check-pp-1
region: region1
type: port_pair
validate:
predicate: any
condition:
- ingress: preparation@p2@id
egress: preparation@p3@id
name: pp1
- ingress: preparation@p4@id
egress: preparation@p5@id
name: pp2
- task_id: check-pp-2
region: region2
type: port_pair
validate:
predicate: any
condition:
- ingress: preparation@p2@id
egress: preparation@p3@id
name: pp1
- ingress: preparation@p4@id
egress: preparation@p5@id
name: pp2
- task_id: check-ppg-1
region: region1
type: port_pair_group
depend:
- pp1-1
- pp2-1
validate:
predicate: any
condition:
- name: ppg1
port_pairs: [pp1-1@id]
- name: ppg2
port_pairs: [pp2-1@id]
- task_id: check-ppg-2
region: region2
type: port_pair_group
depend:
- pp1-2
- pp2-2
validate:
predicate: any
condition:
- name: ppg1
port_pairs: [pp1-2@id]
- name: ppg2
port_pairs: [pp2-2@id]
- task_id: check-pc-1
region: region1
type: port_chain
depend:
- ppg1-1
- ppg2-1
- fc-1
validate:
predicate: any
condition:
- name: pc
port_pair_groups:
- ppg1-1@id
- ppg2-1@id
flow_classifiers: [fc-1@id]
- task_id: check-pc-2
region: region2
type: port_chain
depend:
- ppg1-2
- ppg2-2
- fc-2
validate:
predicate: any
condition:
- name: pc
port_pair_groups:
- ppg1-2@id
- ppg2-2@id
flow_classifiers: [fc-2@id]
- task_set_id: clean
depend: [preparation]
tasks:
- task_id: delete-pc
region: central
type: port_chain
action:
target: preparation@pc@id
method: delete
- task_id: delete-fc
region: central
type: flow_classifier
depend: [delete-pc]
action:
target: preparation@fc@id
method: delete
- task_id: delete-ppg1
region: central
type: port_pair_group
depend: [delete-pc]
action:
target: preparation@ppg1@id
method: delete
- task_id: delete-ppg2
region: central
type: port_pair_group
depend: [delete-pc]
action:
target: preparation@ppg2@id
method: delete
- task_id: delete-pp1
region: central
type: port_pair
depend: [delete-ppg1]
action:
target: preparation@pp1@id
method: delete
- task_id: delete-pp2
region: central
type: port_pair
depend: [delete-ppg2]
action:
target: preparation@pp2@id
method: delete
- task_id: delete-vm-src
region: region1
type: server
action:
target: preparation@vm_src@id
method: delete
- task_id: delete-vm-sfc1
region: region1
type: server
depend: [delete-pp1]
action:
target: preparation@vm_sfc1@id
method: delete
- task_id: delete-vm-dst
region: region2
type: server
action:
target: preparation@vm_dst@id
method: delete
- task_id: delete-vm-sfc2
region: region2
type: server
depend: [delete-pp2]
action:
target: preparation@vm_sfc2@id
method: delete
- task_set_id: wait-server-delete
tasks:
- task_id: check-no-servers-1
region: region1
type: server
validate:
retries: 10
predicate: all
condition:
- name: invalid-name
- task_id: check-no-servers-2
region: region2
type: server
validate:
retries: 10
predicate: all
condition:
- name: invalid-name
- task_set_id: clean-cont
depend: [preparation]
tasks:
- task_id: delete-p1
region: central
type: port
action:
target: preparation@p1@id
method: delete
- task_id: delete-p2
region: central
type: port
action:
target: preparation@p2@id
method: delete
- task_id: delete-p3
region: central
type: port
action:
target: preparation@p3@id
method: delete
- task_id: delete-p4
region: central
type: port
action:
target: preparation@p4@id
method: delete
- task_id: delete-p5
region: central
type: port
action:
target: preparation@p5@id
method: delete
- task_id: delete-p6
region: central
type: port
action:
target: preparation@p6@id
method: delete
- task_id: delete-subnet
region: central
depend:
- delete-p1
- delete-p2
- delete-p3
- delete-p4
- delete-p5
- delete-p6
type: subnet
action:
target: preparation@subnet1@id
method: delete
retries: 3
- task_id: delete-net
region: central
depend: [delete-subnet]
type: network
action:
target: preparation@net1@id
method: delete
- task_set_id: clean-check
tasks:
- task_id: check-no-networks1
region: region1
type: network
validate:
predicate: all
condition:
- name: invalid-name
- task_id: check-no-networks2
region: region2
type: network
validate:
predicate: all
condition:
- name: invalid-name
- task_id: check-jobs
region: central
type: job
validate:
predicate: all
retries: 10
condition:
- status: SUCCESS

View File

@ -5,15 +5,23 @@ DEVSTACK_DIR=$DEST/devstack
source $DEVSTACK_DIR/openrc admin admin
unset OS_REGION_NAME
echo "Start to run single gateway topology test"
python run_yaml_test.py single_gw_topology_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD"
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in single gateway topology test"
fi
echo "Start to run multi gateway topology test"
python run_yaml_test.py multi_gw_topology_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD"
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in multi gateway topology test"
fi
echo "Start to run trunk test"
python run_yaml_test.py trunk_test.yaml "$OS_AUTH_URL" "$OS_TENANT_NAME" "$OS_USERNAME" "$OS_PASSWORD"
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in trunk test"
fi
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"
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in service function chain test"
fi

View File

@ -66,7 +66,8 @@ class DummyRunner(object):
return []
def validate(self, region, _type, predicate, conditions, params):
pass
msg = 'validate %s, conditions: %s' % (_type, conditions)
LOG.info(msg)
class SDKRunner(object):
@ -74,7 +75,9 @@ class SDKRunner(object):
'region1': 'RegionOne',
'region2': 'RegionTwo'}
serv_reslist_map = {
'network_sdk': ['network', 'subnet', 'port', 'router', 'fip', 'trunk'],
'network_sdk': ['network', 'subnet', 'port', 'router', 'fip', 'trunk',
'flow_classifier', 'port_pair', 'port_pair_group',
'port_chain'],
'compute': ['server'],
'image': ['image'],
'tricircle_sdk': ['job']}
@ -190,12 +193,14 @@ class SDKRunner(object):
for condition in conditions:
if not validate_any_condition(results, condition):
raise Exception(
'Validation fail, acutal results: %s' % results)
'Validation fail, acutal results: %s, '
'expected results: %s' % (results, condition))
elif predicate == 'all':
for condition in conditions:
if not validate_all_condition(results, condition):
raise Exception(
'Validation fail, acutal results: %s' % results)
'Validation fail, acutal results: %s, '
'expected results: %s' % (results, condition))
class RunnerEngine(object):
@ -246,6 +251,8 @@ class RunnerEngine(object):
requires = []
if 'params' in task:
collect_require_from_dict(requires, task['params'])
if 'validate' in task:
collect_require_from_dict(requires, task['validate'])
if 'action' in task:
requires.append(task['action']['target'])
depend = task.get('depend', [])

View File

@ -14,10 +14,15 @@
from openstack.network.v2 import _proxy
import tricircle.tests.network_sdk.v2.flow_classifier as _fc
import tricircle.tests.network_sdk.v2.port_chain as _pc
import tricircle.tests.network_sdk.v2.port_pair as _pp
import tricircle.tests.network_sdk.v2.port_pair_group as _ppg
import tricircle.tests.network_sdk.v2.trunk as _trunk
class Proxy(_proxy.Proxy):
# trunk
def create_trunk(self, **attrs):
return self._create(_trunk.Trunk, **attrs)
@ -39,3 +44,55 @@ class Proxy(_proxy.Proxy):
trunk = self._get_resource(_trunk.Trunk, trunk)
body = {'sub_ports': subports}
return trunk.remove_subports(self._session, **body)
# port pair
def create_port_pair(self, **attrs):
return self._create(_pp.PortPair, **attrs)
def delete_port_pair(self, pp, ignore_missing=True):
self._delete(_pp.PortPair, pp, ignore_missing=ignore_missing)
def update_port_pair(self, pp, **attrs):
return self._update(_pp.PortPair, pp, **attrs)
def port_pairs(self, **query):
return self._list(_pp.PortPair, pagination=False, **query)
# port pair group
def create_port_pair_group(self, **attrs):
return self._create(_ppg.PortPairGroup, **attrs)
def delete_port_pair_group(self, ppg, ignore_missing=True):
self._delete(_ppg.PortPairGroup, ppg, ignore_missing=ignore_missing)
def update_port_pair_group(self, ppg, **attrs):
return self._update(_ppg.PortPairGroup, ppg, **attrs)
def port_pair_groups(self, **query):
return self._list(_ppg.PortPairGroup, pagination=False, **query)
# port chain
def create_port_chain(self, **attrs):
return self._create(_pc.PortChain, **attrs)
def delete_port_chain(self, pc, ignore_missing=True):
self._delete(_pc.PortChain, pc, ignore_missing=ignore_missing)
def update_port_chain(self, pc, **attrs):
return self._update(_pc.PortChain, pc, **attrs)
def port_chains(self, **query):
return self._list(_pc.PortChain, pagination=False, **query)
# flow classifier
def create_flow_classifier(self, **attrs):
return self._create(_fc.FlowClassifier, **attrs)
def delete_flow_classifier(self, fc, ignore_missing=True):
self._delete(_fc.FlowClassifier, fc, ignore_missing=ignore_missing)
def update_flow_classifier(self, fc, **attrs):
return self._update(_fc.FlowClassifier, fc, **attrs)
def flow_classifiers(self, **query):
return self._list(_fc.FlowClassifier, pagination=False, **query)

View File

@ -0,0 +1,44 @@
# 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.
from openstack import resource2
from tricircle.tests.network_sdk import network_service
class FlowClassifier(resource2.Resource):
resource_key = 'flow_classifier'
resources_key = 'flow_classifiers'
base_path = '/sfc/flow_classifiers'
service = network_service.NetworkService()
allow_create = True
allow_get = True
allow_update = True
allow_delete = True
allow_list = True
_query_mapping = resource2.QueryParameters('name')
name = resource2.Body('name')
description = resource2.Body('description')
ethertype = resource2.Body('ingress')
protocol = resource2.Body('protocol')
source_port_range_min = resource2.Body('source_port_range_min')
source_port_range_max = resource2.Body('source_port_range_max')
destination_port_range_min = resource2.Body('destination_port_range_min')
destination_port_range_max = resource2.Body('destination_port_range_max')
source_ip_prefix = resource2.Body('source_ip_prefix')
destination_ip_prefix = resource2.Body('destination_ip_prefix')
logical_source_port = resource2.Body('logical_source_port')
logical_destination_port = resource2.Body('logical_destination_port')
l7_parameters = resource2.Body('l7_parameters', type=dict)

View File

@ -0,0 +1,37 @@
# 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.
from openstack import resource2
from tricircle.tests.network_sdk import network_service
class PortChain(resource2.Resource):
resource_key = 'port_chain'
resources_key = 'port_chains'
base_path = '/sfc/port_chains'
service = network_service.NetworkService()
allow_create = True
allow_get = True
allow_update = True
allow_delete = True
allow_list = True
_query_mapping = resource2.QueryParameters('name')
name = resource2.Body('name')
description = resource2.Body('description')
port_pair_groups = resource2.Body('port_pair_groups', type=list)
flow_classifiers = resource2.Body('flow_classifiers', type=list)
chain_parameters = resource2.Body('chain_parameters', type=dict)
chain_id = resource2.Body('chain_id')

View File

@ -0,0 +1,37 @@
# 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.
from openstack import resource2
from tricircle.tests.network_sdk import network_service
class PortPair(resource2.Resource):
resource_key = 'port_pair'
resources_key = 'port_pairs'
base_path = '/sfc/port_pairs'
service = network_service.NetworkService()
allow_create = True
allow_get = True
allow_update = True
allow_delete = True
allow_list = True
_query_mapping = resource2.QueryParameters('name')
name = resource2.Body('name')
description = resource2.Body('description')
ingress = resource2.Body('ingress')
egress = resource2.Body('egress')
service_function_parameters = resource2.Body('service_function_parameters',
type=dict)

View File

@ -0,0 +1,36 @@
# 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.
from openstack import resource2
from tricircle.tests.network_sdk import network_service
class PortPairGroup(resource2.Resource):
resource_key = 'port_pair_group'
resources_key = 'port_pair_groups'
base_path = '/sfc/port_pair_groups'
service = network_service.NetworkService()
allow_create = True
allow_get = True
allow_update = True
allow_delete = True
allow_list = True
_query_mapping = resource2.QueryParameters('name')
name = resource2.Body('name')
description = resource2.Body('description')
port_pairs = resource2.Body('port_pairs', type=list)
port_pair_group_parameters = resource2.Body('port_pair_group_parameters',
type=dict)