summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/_static/favicon.icobin0 -> 15086 bytes
-rw-r--r--docs/_static/logo.pngbin0 -> 2829 bytes
-rw-r--r--docs/index.rst1
-rw-r--r--docs/release/release-notes/index.rst4
-rw-r--r--odl-pipeline/lib/odl_reinstaller/odl_reinstaller.py1
-rwxr-xr-xodl-pipeline/lib/test_environment/test_environment.py1
-rwxr-xr-xodl-pipeline/lib/tripleo_introspector/tripleo_introspector.py1
-rwxr-xr-xodl-pipeline/lib/utils/processutils.py1
-rw-r--r--requirements.txt2
-rw-r--r--sdnvpn/artifacts/testcase_1bis.yaml234
-rw-r--r--sdnvpn/artifacts/testcase_4bis.yaml247
-rw-r--r--sdnvpn/lib/openstack_utils.py96
-rw-r--r--sdnvpn/lib/utils.py117
-rw-r--r--sdnvpn/test/functest/config.yaml70
-rw-r--r--sdnvpn/test/functest/testcase_10.py2
-rw-r--r--sdnvpn/test/functest/testcase_1bis.py209
-rw-r--r--sdnvpn/test/functest/testcase_3.py2
-rw-r--r--sdnvpn/test/functest/testcase_4bis.py215
-rw-r--r--test-requirements.txt5
-rw-r--r--tox.ini46
20 files changed, 1193 insertions, 61 deletions
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644
index 0000000..bbe55ab
--- /dev/null
+++ b/docs/_static/favicon.ico
Binary files differ
diff --git a/docs/_static/logo.png b/docs/_static/logo.png
new file mode 100644
index 0000000..1519503
--- /dev/null
+++ b/docs/_static/logo.png
Binary files differ
diff --git a/docs/index.rst b/docs/index.rst
index d07beb2..d58d5d5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,6 +17,7 @@ OPNFV SDNVPN
release/configguide/index
release/userguide/index
release/installation/index
+ release/scenarios/os-odl-bgpvpn/index
development/requirements/index
development/overview/index
development/design/index
diff --git a/docs/release/release-notes/index.rst b/docs/release/release-notes/index.rst
index 2b6664a..c7e07ee 100644
--- a/docs/release/release-notes/index.rst
+++ b/docs/release/release-notes/index.rst
@@ -4,9 +4,9 @@
.. http://creativecommons.org/licenses/by/4.0
.. (c) Nikolas Hermanns, (nikolas.hermanns@ericsson.com) and others
-==================
+=====================
SDN VPN release notes
-==================
+=====================
.. toctree::
:maxdepth: 3
diff --git a/odl-pipeline/lib/odl_reinstaller/odl_reinstaller.py b/odl-pipeline/lib/odl_reinstaller/odl_reinstaller.py
index 9a8973f..3d29724 100644
--- a/odl-pipeline/lib/odl_reinstaller/odl_reinstaller.py
+++ b/odl-pipeline/lib/odl_reinstaller/odl_reinstaller.py
@@ -281,5 +281,6 @@ class ODLReinstallerException(Exception):
def main():
ODLReInstaller().start()
+
if __name__ == '__main__':
main()
diff --git a/odl-pipeline/lib/test_environment/test_environment.py b/odl-pipeline/lib/test_environment/test_environment.py
index 65d40bb..a56c36f 100755
--- a/odl-pipeline/lib/test_environment/test_environment.py
+++ b/odl-pipeline/lib/test_environment/test_environment.py
@@ -157,5 +157,6 @@ def main():
main = TestEnvironment()
main.start()
+
if __name__ == '__main__':
main()
diff --git a/odl-pipeline/lib/tripleo_introspector/tripleo_introspector.py b/odl-pipeline/lib/tripleo_introspector/tripleo_introspector.py
index aa6ebbb..9258e83 100755
--- a/odl-pipeline/lib/tripleo_introspector/tripleo_introspector.py
+++ b/odl-pipeline/lib/tripleo_introspector/tripleo_introspector.py
@@ -122,5 +122,6 @@ class TripleOInspectorException(Exception):
def main():
TripleOIntrospector().start()
+
if __name__ == '__main__':
main()
diff --git a/odl-pipeline/lib/utils/processutils.py b/odl-pipeline/lib/utils/processutils.py
index 98162c8..901e74b 100755
--- a/odl-pipeline/lib/utils/processutils.py
+++ b/odl-pipeline/lib/utils/processutils.py
@@ -29,6 +29,7 @@ def _subprocess_setup():
# non-Python subprocesses expect.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
# NOTE(flaper87): The following globals are used by `mask_password`
_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
diff --git a/requirements.txt b/requirements.txt
index 1979004..252b214 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,8 +6,6 @@ requests # Apache-2.0
opnfv
PyYAML # MIT
networking-bgpvpn>=7.0.0 # Apache-2.0
-python-cinderclient!=4.0.0 # Apache-2.0
-python-heatclient # Apache-2.0
python-keystoneclient!=2.1.0 # Apache-2.0
python-neutronclient # Apache-2.0
xtesting # Apache-2.0
diff --git a/sdnvpn/artifacts/testcase_1bis.yaml b/sdnvpn/artifacts/testcase_1bis.yaml
new file mode 100644
index 0000000..f269943
--- /dev/null
+++ b/sdnvpn/artifacts/testcase_1bis.yaml
@@ -0,0 +1,234 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for SDNVPN testcase 1
+ VPN provides connectivity between subnets
+
+parameters:
+ flavor:
+ type: string
+ description: flavor for the servers to be created
+ constraints:
+ - custom_constraint: nova.flavor
+ image_n:
+ type: string
+ description: image for the servers to be created
+ constraints:
+ - custom_constraint: glance.image
+ av_zone_1:
+ type: string
+ description: availability zone 1
+ av_zone_2:
+ type: string
+ description: availability zone 2
+
+ net_1_name:
+ type: string
+ description: network 1
+ subnet_1_name:
+ type: string
+ description: subnet 1 name
+ subnet_1_cidr:
+ type: string
+ description: subnet 1 cidr
+ net_2_name:
+ type: string
+ description: network 2
+ subnet_2_name:
+ type: string
+ description: subnet 2 name
+ subnet_2_cidr:
+ type: string
+ description: subnet 1 cidr
+
+ secgroup_name:
+ type: string
+ description: security group name
+ secgroup_descr:
+ type: string
+ description: security group slogan
+
+ instance_1_name:
+ type: string
+ description: instance name
+ instance_2_name:
+ type: string
+ description: instance name
+ instance_3_name:
+ type: string
+ description: instance name
+ instance_4_name:
+ type: string
+ description: instance name
+ instance_5_name:
+ type: string
+ description: instance name
+
+ ping_count:
+ type: string
+ description: ping count for user data script
+ default: 10
+
+resources:
+ net_1:
+ type: OS::Neutron::Net
+ properties:
+ name: { get_param: net_1_name }
+ subnet_1:
+ type: OS::Neutron::Subnet
+ properties:
+ name: { get_param: subnet_1_name }
+ network: { get_resource: net_1 }
+ cidr: { get_param: subnet_1_cidr }
+ net_2:
+ type: OS::Neutron::Net
+ properties:
+ name: { get_param: net_2_name }
+ subnet_2:
+ type: OS::Neutron::Subnet
+ properties:
+ name: { get_param: subnet_2_name }
+ network: { get_resource: net_2 }
+ cidr: { get_param: subnet_2_cidr }
+
+ sec_group:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ name: { get_param: secgroup_name }
+ description: { get_param: secgroup_descr }
+ rules:
+ - protocol: icmp
+ remote_ip_prefix: 0.0.0.0/0
+ - protocol: tcp
+ port_range_min: 22
+ port_range_max: 22
+ remote_ip_prefix: 0.0.0.0/0
+
+ vm1:
+ type: OS::Nova::Server
+ depends_on: [ vm2, vm3, vm4, vm5 ]
+ properties:
+ name: { get_param: instance_1_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ config_drive: True
+ user_data_format: RAW
+ user_data:
+ str_replace:
+ template: |
+ #!/bin/sh
+ set $IP_VM2 $IP_VM3 $IP_VM4 $IP_VM5
+ while true; do
+ for i do
+ ip=$i
+ ping -c $COUNT $ip 2>&1 >/dev/null
+ RES=$?
+ if [ \"Z$RES\" = \"Z0\" ] ; then
+ echo ping $ip OK
+ else echo ping $ip KO
+ fi
+ done
+ sleep 1
+ done
+ params:
+ $IP_VM2: { get_attr: [vm2, addresses, { get_resource: net_1}, 0, addr] }
+ $IP_VM3: { get_attr: [vm3, addresses, { get_resource: net_1}, 0, addr] }
+ $IP_VM4: { get_attr: [vm4, addresses, { get_resource: net_2}, 0, addr] }
+ $IP_VM5: { get_attr: [vm5, addresses, { get_resource: net_2}, 0, addr] }
+ $COUNT: { get_param: ping_count }
+ vm2:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_2_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ vm3:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_3_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_2 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ vm4:
+ type: OS::Nova::Server
+ depends_on: vm5
+ properties:
+ name: { get_param: instance_4_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_2 }
+ config_drive: True
+ user_data_format: RAW
+ user_data:
+ str_replace:
+ template: |
+ #!/bin/sh
+ set $IP_VM5
+ while true; do
+ for i do
+ ip=$i
+ ping -c $COUNT $ip 2>&1 >/dev/null
+ RES=$?
+ if [ \"Z$RES\" = \"Z0\" ] ; then
+ echo ping $ip OK
+ else echo ping $ip KO
+ fi
+ done
+ sleep 1
+ done
+ params:
+ $IP_VM5: { get_attr: [vm5, addresses, { get_resource: net_2}, 0, addr] }
+ $COUNT: { get_param: ping_count }
+
+ vm5:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_5_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_2 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_2 }
+
+outputs:
+ net_1_o:
+ description: the id of network 1
+ value: { get_attr: [net_1, show, id] }
+ net_2_o:
+ description: the id of network 2
+ value: { get_attr: [net_2, show, id] }
+ vm1_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm1, show, name] }
+ vm2_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm2, show, name] }
+ vm3_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm3, show, name] }
+ vm4_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm4, show, name] }
+ vm5_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm5, show, name] }
diff --git a/sdnvpn/artifacts/testcase_4bis.yaml b/sdnvpn/artifacts/testcase_4bis.yaml
new file mode 100644
index 0000000..ee59e1d
--- /dev/null
+++ b/sdnvpn/artifacts/testcase_4bis.yaml
@@ -0,0 +1,247 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for SDNVPN testcase 4
+ VPN provides connectivity between subnets using router association
+
+parameters:
+ flavor:
+ type: string
+ description: flavor for the servers to be created
+ constraints:
+ - custom_constraint: nova.flavor
+ image_n:
+ type: string
+ description: image for the servers to be created
+ constraints:
+ - custom_constraint: glance.image
+ av_zone_1:
+ type: string
+ description: availability zone 1
+ av_zone_2:
+ type: string
+ description: availability zone 2
+
+ net_1_name:
+ type: string
+ description: network 1
+ subnet_1_name:
+ type: string
+ description: subnet 1 name
+ subnet_1_cidr:
+ type: string
+ description: subnet 1 cidr
+ router_1_name:
+ type: string
+ description: router 1 cidr
+ net_2_name:
+ type: string
+ description: network 2
+ subnet_2_name:
+ type: string
+ description: subnet 2 name
+ subnet_2_cidr:
+ type: string
+ description: subnet 1 cidr
+
+ secgroup_name:
+ type: string
+ description: security group name
+ secgroup_descr:
+ type: string
+ description: security group slogan
+
+ instance_1_name:
+ type: string
+ description: instance name
+ instance_2_name:
+ type: string
+ description: instance name
+ instance_3_name:
+ type: string
+ description: instance name
+ instance_4_name:
+ type: string
+ description: instance name
+ instance_5_name:
+ type: string
+ description: instance name
+
+ ping_count:
+ type: string
+ description: ping count for user data script
+ default: 10
+
+resources:
+ net_1:
+ type: OS::Neutron::Net
+ properties:
+ name: { get_param: net_1_name }
+ subnet_1:
+ type: OS::Neutron::Subnet
+ properties:
+ name: { get_param: subnet_1_name }
+ network: { get_resource: net_1 }
+ cidr: { get_param: subnet_1_cidr }
+ router_1:
+ type: OS::Neutron::Router
+ properties:
+ name: { get_param: router_1_name }
+ routerinterface_1:
+ type: OS::Neutron::RouterInterface
+ properties:
+ router_id: { get_resource: router_1 }
+ subnet_id: { get_resource: subnet_1 }
+
+ net_2:
+ type: OS::Neutron::Net
+ properties:
+ name: { get_param: net_2_name }
+ subnet_2:
+ type: OS::Neutron::Subnet
+ properties:
+ name: { get_param: subnet_2_name }
+ network: { get_resource: net_2 }
+ cidr: { get_param: subnet_2_cidr }
+
+ sec_group:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ name: { get_param: secgroup_name }
+ description: { get_param: secgroup_descr }
+ rules:
+ - protocol: icmp
+ remote_ip_prefix: 0.0.0.0/0
+ - protocol: tcp
+ port_range_min: 22
+ port_range_max: 22
+ remote_ip_prefix: 0.0.0.0/0
+
+ vm1:
+ type: OS::Nova::Server
+ depends_on: [ vm2, vm3, vm4, vm5 ]
+ properties:
+ name: { get_param: instance_1_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ config_drive: True
+ user_data_format: RAW
+ user_data:
+ str_replace:
+ template: |
+ #!/bin/sh
+ set $IP_VM2 $IP_VM3 $IP_VM4 $IP_VM5
+ while true; do
+ for i do
+ ip=$i
+ ping -c $COUNT $ip 2>&1 >/dev/null
+ RES=$?
+ if [ \"Z$RES\" = \"Z0\" ] ; then
+ echo ping $ip OK
+ else echo ping $ip KO
+ fi
+ done
+ sleep 1
+ done
+ params:
+ $IP_VM2: { get_attr: [vm2, addresses, { get_resource: net_1}, 0, addr] }
+ $IP_VM3: { get_attr: [vm3, addresses, { get_resource: net_1}, 0, addr] }
+ $IP_VM4: { get_attr: [vm4, addresses, { get_resource: net_2}, 0, addr] }
+ $IP_VM5: { get_attr: [vm5, addresses, { get_resource: net_2}, 0, addr] }
+ $COUNT: { get_param: ping_count }
+ vm2:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_2_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ vm3:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_3_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_2 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_1 }
+ vm4:
+ type: OS::Nova::Server
+ depends_on: vm5
+ properties:
+ name: { get_param: instance_4_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_1 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_2 }
+ config_drive: True
+ user_data_format: RAW
+ user_data:
+ str_replace:
+ template: |
+ #!/bin/sh
+ set $IP_VM5
+ while true; do
+ for i do
+ ip=$i
+ ping -c $COUNT $ip 2>&1 >/dev/null
+ RES=$?
+ if [ \"Z$RES\" = \"Z0\" ] ; then
+ echo ping $ip OK
+ else echo ping $ip KO
+ fi
+ done
+ sleep 1
+ done
+ params:
+ $IP_VM5: { get_attr: [vm5, addresses, { get_resource: net_2}, 0, addr] }
+ $COUNT: { get_param: ping_count }
+
+ vm5:
+ type: OS::Nova::Server
+ properties:
+ name: { get_param: instance_5_name }
+ image: { get_param: image_n }
+ flavor: { get_param: flavor }
+ availability_zone: { get_param: av_zone_2 }
+ security_groups:
+ - { get_resource: sec_group }
+ networks:
+ - subnet: { get_resource: subnet_2 }
+
+outputs:
+ router_1_o:
+ description: the id of network 1
+ value: { get_attr: [router_1, show, id] }
+ net_2_o:
+ description: the id of network 2
+ value: { get_attr: [net_2, show, id] }
+ vm1_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm1, show, name] }
+ vm2_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm2, show, name] }
+ vm3_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm3, show, name] }
+ vm4_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm4, show, name] }
+ vm5_o:
+ description: the deployed vm resource
+ value: { get_attr: [vm5, show, name] }
diff --git a/sdnvpn/lib/openstack_utils.py b/sdnvpn/lib/openstack_utils.py
index fc36c5b..d377c33 100644
--- a/sdnvpn/lib/openstack_utils.py
+++ b/sdnvpn/lib/openstack_utils.py
@@ -18,19 +18,17 @@ import urllib
from keystoneauth1 import loading
from keystoneauth1 import session
-from cinderclient import client as cinderclient
-from heatclient import client as heatclient
from keystoneclient import client as keystoneclient
from neutronclient.neutron import client as neutronclient
from openstack import connection
from openstack import cloud as os_cloud
+from openstack.exceptions import ResourceNotFound
from functest.utils import env
logger = logging.getLogger(__name__)
DEFAULT_API_VERSION = '2'
-DEFAULT_HEAT_API_VERSION = '1'
# *********************************************
@@ -165,20 +163,6 @@ def get_keystone_client(other_creds={}):
interface=os.getenv('OS_INTERFACE', 'admin'))
-def get_cinder_client_version():
- api_version = os.getenv('OS_VOLUME_API_VERSION')
- if api_version is not None:
- logger.info("OS_VOLUME_API_VERSION is set in env as '%s'",
- api_version)
- return api_version
- return DEFAULT_API_VERSION
-
-
-def get_cinder_client(other_creds={}):
- sess = get_session(other_creds)
- return cinderclient.Client(get_cinder_client_version(), session=sess)
-
-
def get_neutron_client_version():
api_version = os.getenv('OS_NETWORK_API_VERSION')
if api_version is not None:
@@ -193,20 +177,6 @@ def get_neutron_client(other_creds={}):
return neutronclient.Client(get_neutron_client_version(), session=sess)
-def get_heat_client_version():
- api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
- if api_version is not None:
- logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
- api_version)
- return api_version
- return DEFAULT_HEAT_API_VERSION
-
-
-def get_heat_client(other_creds={}):
- sess = get_session(other_creds)
- return heatclient.Client(get_heat_client_version(), session=sess)
-
-
def download_url(url, dest_path):
"""
Download a file to a destination path given a URL
@@ -440,7 +410,7 @@ def create_instance(flavor_name,
conn = get_os_connection()
try:
flavor = conn.compute.find_flavor(flavor_name, ignore_missing=False)
- except:
+ except Exception:
flavors = [flavor.name for flavor in conn.compute.flavors()]
logger.error("Error: Flavor '%s' not found. Available flavors are: "
"\n%s" % (flavor_name, flavors))
@@ -963,7 +933,7 @@ def create_secgroup_rule(conn, sg_id, direction, protocol,
try:
conn.network.create_security_group_rule(**secgroup_rule_attrs)
return True
- except:
+ except Exception:
logger.exception("Impossible to create_security_group_rule,"
"security group rule probably already exists")
return False
@@ -1198,7 +1168,7 @@ def delete_volume(cloud, volume_id, forced=False):
for attachment in volume.attachments:
server = cloud.get_server(attachment.server_id)
cloud.detach_volume(server, volume)
- except:
+ except Exception:
logger.error(sys.exc_info()[0])
cloud.delete_volume(volume_id, force=True)
else:
@@ -1325,9 +1295,9 @@ def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
return True
else:
return False
- except:
+ except Exception:
raise Exception("Impossible to create a Tenant for the VNF {}".format(
- tenant_name))
+ tenant_name))
def create_user(keystone_client, user_name, user_password,
@@ -1385,10 +1355,10 @@ def get_or_create_user_for_vnf(keystone_client, vnf_ref):
role_id = get_role_id(keystone_client, 'admin')
tenant_id = get_tenant_id(keystone_client, vnf_ref)
add_role_user(keystone_client, user_id, role_id, tenant_id)
- except:
+ except Exception:
logger.warn("Cannot associate user to role admin on tenant")
return created
- except:
+ except Exception:
raise Exception("Impossible to create a user for the VNF {}".format(
vnf_ref))
@@ -1434,10 +1404,52 @@ def delete_user(keystone_client, user_id):
# *********************************************
# HEAT
# *********************************************
-def get_resource(heat_client, stack_id, resource):
+def get_resource(conn, stack_id, resource):
try:
- resources = heat_client.resources.get(stack_id, resource)
- return resources
+ resource = conn.orchestration.resources(stack_id, id=resource).next()
+ return resource
except Exception as e:
- logger.error("Error [get_resource]: %s" % e)
+ logger.error("Error [get_resource(orchestration)]: %s" % e)
return None
+
+
+def create_stack(conn, **kwargs):
+ try:
+ stack = conn.orchestration.create_stack(**kwargs)
+ stack_id = stack.id
+ if stack_id is None:
+ logger.error("Stack create start failed")
+ raise SystemError("Stack create start failed")
+ return stack_id
+ except Exception as e:
+ logger.error("Error [create_stack(orchestration)]: %s" % e)
+ return None
+
+
+def delete_stack(conn, stack_id):
+ try:
+ conn.orchestration.delete_stack(stack_id)
+ return True
+ except Exception as e:
+ logger.error("Error [delete_stack(orchestration)]: %s" % e)
+ return False
+
+
+def list_stacks(conn, **kwargs):
+ try:
+ result = conn.orchestration.stacks(**kwargs)
+ return result
+ except Exception as e:
+ logger.error("Error [list_stack(orchestration)]: %s" % e)
+ return None
+
+
+def get_output(conn, stack_id, output_key):
+ try:
+ stack = conn.orchestration.get_stack(stack_id)
+ for output in stack.outputs:
+ if output['output_key'] == output_key:
+ return output
+ except ResourceNotFound as e:
+ logger.error("Error [get_output(orchestration)]: %s" % e)
+ return None
diff --git a/sdnvpn/lib/utils.py b/sdnvpn/lib/utils.py
index c508596..50e508a 100644
--- a/sdnvpn/lib/utils.py
+++ b/sdnvpn/lib/utils.py
@@ -15,7 +15,7 @@ import requests
import re
import subprocess
from concurrent.futures import ThreadPoolExecutor
-from openstack.exceptions import ResourceNotFound
+from openstack.exceptions import ResourceNotFound, NotFoundException
from requests.auth import HTTPBasicAuth
from opnfv.deployment.factory import Factory as DeploymentFactory
@@ -1009,3 +1009,118 @@ def is_fib_entry_present_on_odl(controllers, ip_prefix, vrf_id):
logger.error('Failed to find ip prefix %s with error %s'
% (ip_prefix, e))
return False
+
+
+def wait_stack_for_status(conn, stack_id, stack_status, limit=12):
+ """ Waits to reach specified stack status. To be used with
+ CREATE_COMPLETE and UPDATE_COMPLETE.
+ Will try a specific number of attempts at 10sec intervals
+ (default 2min)
+
+ :param stack_id: the stack id returned by create_stack api call
+ :param stack_status: the stack status waiting for
+ :param limit: the maximum number of attempts
+ """
+ logger.debug("Stack '%s' create started" % stack_id)
+
+ stack_create_complete = False
+ attempts = 0
+ while attempts < limit:
+ try:
+ stack_st = conn.orchestration.get_stack(stack_id).status
+ except NotFoundException:
+ logger.error("Stack create failed")
+ raise SystemError("Stack create failed")
+ return False
+ if stack_st == stack_status:
+ stack_create_complete = True
+ break
+ attempts += 1
+ time.sleep(10)
+
+ logger.debug("Stack status check: %s times" % attempts)
+ if stack_create_complete is False:
+ logger.error("Stack create failed")
+ raise SystemError("Stack create failed")
+ return False
+
+ return True
+
+
+def delete_stack_and_wait(conn, stack_id, limit=12):
+ """ Starts and waits for completion of delete stack
+
+ Will try a specific number of attempts at 10sec intervals
+ (default 2min)
+
+ :param stack_id: the id of the stack to be deleted
+ :param limit: the maximum number of attempts
+ """
+ delete_started = False
+ if stack_id is not None:
+ delete_started = os_utils.delete_stack(conn, stack_id)
+
+ if delete_started is True:
+ logger.debug("Stack delete succesfully started")
+ else:
+ logger.error("Stack delete start failed")
+
+ stack_delete_complete = False
+ attempts = 0
+ while attempts < limit:
+ try:
+ stack_st = conn.orchestration.get_stack(stack_id).status
+ if stack_st == 'DELETE_COMPLETE':
+ stack_delete_complete = True
+ break
+ attempts += 1
+ time.sleep(10)
+ except NotFoundException:
+ stack_delete_complete = True
+ break
+
+ logger.debug("Stack status check: %s times" % attempts)
+ if not stack_delete_complete:
+ logger.error("Stack delete failed")
+ raise SystemError("Stack delete failed")
+ return False
+
+ return True
+
+
+def get_heat_environment(testcase, common_config):
+ """ Reads the heat parameters of a testcase into a yaml object
+
+ Each testcase where Heat Orchestratoin Template (HOT) is introduced
+ has an associated parameters section.
+ Reads testcase.heat_parameters section and read COMMON_CONFIG.flavor
+ and place it under parameters tree.
+
+ :param testcase: the tescase for which the HOT file is fetched
+ :param common_config: the common config section
+ :return environment: a yaml object to be used as environment
+ """
+ fl = common_config.default_flavor
+ param_dict = testcase.heat_parameters
+ param_dict['flavor'] = fl
+ env_dict = {'parameters': param_dict}
+ return env_dict
+
+
+def get_vms_from_stack_outputs(conn, stack_id, vm_stack_output_keys):
+ """ Converts a vm name from a heat stack output to a nova vm object
+
+ :param stack_id: the id of the stack to fetch the vms from
+ :param vm_stack_output_keys: a list of stack outputs with the vm names
+ :return vms: a list of vm objects corresponding to the outputs
+ """
+ vms = []
+ for vmk in vm_stack_output_keys:
+ vm_output = os_utils.get_output(conn, stack_id, vmk)
+ if vm_output is not None:
+ vm_name = vm_output['output_value']
+ logger.debug("vm '%s' read from heat output" % vm_name)
+ vm = os_utils.get_instance_by_name(conn, vm_name)
+ if vm is not None:
+ vms.append(vm)
+ return vms
diff --git a/sdnvpn/test/functest/config.yaml b/sdnvpn/test/functest/config.yaml
index 31dce67..809eed1 100644
--- a/sdnvpn/test/functest/config.yaml
+++ b/sdnvpn/test/functest/config.yaml
@@ -1,5 +1,6 @@
+---
defaults:
- flavor: m1.tiny # adapt to your environment
+ flavor: m1.tiny # adapt to your environment
testcases:
sdnvpn.test.functest.testcase_1:
@@ -26,6 +27,31 @@ testcases:
targets2: '55:55'
route_distinguishers: '11:11'
+ sdnvpn.test.functest.testcase_1bis:
+ enabled: true
+ order: 14
+ description: Test bed for HOT introduction - same tests as case 1
+ image_name: sdnvpn-image
+ stack_name: stack-1bis
+ hot_file_name: artifacts/testcase_1bis.yaml
+ heat_parameters:
+ instance_1_name: sdnvpn-1-1
+ instance_2_name: sdnvpn-1-2
+ instance_3_name: sdnvpn-1-3
+ instance_4_name: sdnvpn-1-4
+ instance_5_name: sdnvpn-1-5
+ net_1_name: sdnvpn-1-1-net
+ subnet_1_name: sdnvpn-1-1-subnet
+ subnet_1_cidr: 10.10.10.0/24
+ net_2_name: sdnvpn-1-2-net
+ subnet_2_name: sdnvpn-1-2-subnet
+ subnet_2_cidr: 10.10.11.0/24
+ secgroup_name: sdnvpn-sg
+ secgroup_descr: Security group for SDNVPN test cases
+ targets1: '88:88'
+ targets2: '55:55'
+ route_distinguishers: '11:11'
+
sdnvpn.test.functest.testcase_2:
enabled: true
order: 2
@@ -91,7 +117,8 @@ testcases:
sdnvpn.test.functest.testcase_4:
enabled: true
order: 4
- description: VPN provides connectivity between subnets using router association
+ description: "VPN provides connectivity between subnets using router \
+ association"
instance_1_name: sdnvpn-4-1
instance_2_name: sdnvpn-4-2
instance_3_name: sdnvpn-4-3
@@ -112,6 +139,32 @@ testcases:
targets2: '55:55'
route_distinguishers: '12:12'
+ sdnvpn.test.functest.testcase_4bis:
+ enabled: true
+ order: 15
+ description: Test bed for HOT introduction - same tests as case 4
+ image_name: sdnvpn-image
+ stack_name: stack-4bis
+ hot_file_name: artifacts/testcase_4bis.yaml
+ heat_parameters:
+ instance_1_name: sdnvpn-4-1
+ instance_2_name: sdnvpn-4-2
+ instance_3_name: sdnvpn-4-3
+ instance_4_name: sdnvpn-4-4
+ instance_5_name: sdnvpn-4-5
+ net_1_name: sdnvpn-4-1-net
+ subnet_1_name: sdnvpn-4-1-subnet
+ subnet_1_cidr: 10.10.10.0/24
+ router_1_name: sdnvpn-4-1-router
+ net_2_name: sdnvpn-4-2-net
+ subnet_2_name: sdnvpn-4-2-subnet
+ subnet_2_cidr: 10.10.11.0/24
+ secgroup_name: sdnvpn-sg
+ secgroup_descr: Security group for SDNVPN test cases
+ targets1: '88:88'
+ targets2: '55:55'
+ route_distinguishers: '12:12'
+
sdnvpn.test.functest.testcase_7:
enabled: false
order: 7
@@ -155,12 +208,14 @@ testcases:
sdnvpn.test.functest.testcase_9:
enabled: true
order: 9
- description: Verify that all OpenStack nodes OVS br-int have fail_mode set to secure.
+ description: "Verify that all OpenStack nodes OVS br-int have fail_mode \
+ set to secure."
sdnvpn.test.functest.testcase_10:
enabled: true
order: 10
- description: Test if interupts occure during ping, when removing and adding instances
+ description: "Test if interupts occure during ping, when removing and \
+ adding instances"
instance_1_name: sdnvpn-10-1
instance_2_name: sdnvpn-10-2
instance_3_name: sdnvpn-10-3
@@ -176,7 +231,8 @@ testcases:
sdnvpn.test.functest.testcase_11:
enabled: true
order: 11
- description: Check relevant OVS groups are removed upon deletion of OpenStack topology
+ description: "Check relevant OVS groups are removed upon deletion of \
+ OpenStack topology"
instance_1_name: sdnvpn-11-1
instance_2_name: sdnvpn-11-2
image_name: sdnvpn-image
@@ -227,5 +283,5 @@ testcases:
targets1: '88:88'
targets2: '88:88'
route_distinguishers:
- - '12:12'
- - '13:13'
+ - '12:12'
+ - '13:13'
diff --git a/sdnvpn/test/functest/testcase_10.py b/sdnvpn/test/functest/testcase_10.py
index dbfbfd4..3ba93a9 100644
--- a/sdnvpn/test/functest/testcase_10.py
+++ b/sdnvpn/test/functest/testcase_10.py
@@ -55,7 +55,7 @@ def monitor(conn, in_data, out_data, vm):
logger.info("Ping from instance {}: {}".
format(vm.name, console_line))
lines_offset = len(vm_console_out_lines)
- except:
+ except Exception:
# Atomic write to std out
with std_out_lock:
logger.error("Failure in monitor_thread of instance {}".
diff --git a/sdnvpn/test/functest/testcase_1bis.py b/sdnvpn/test/functest/testcase_1bis.py
new file mode 100644
index 0000000..c090182
--- /dev/null
+++ b/sdnvpn/test/functest/testcase_1bis.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2018 All rights reserved
+# This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+import logging
+import sys
+import pkg_resources
+
+from random import randint
+from sdnvpn.lib import config as sdnvpn_config
+from sdnvpn.lib import openstack_utils as os_utils
+from sdnvpn.lib import utils as test_utils
+from sdnvpn.lib.results import Results
+
+logger = logging.getLogger(__name__)
+
+COMMON_CONFIG = sdnvpn_config.CommonConfig()
+TESTCASE_CONFIG = sdnvpn_config.TestcaseConfig(
+ 'sdnvpn.test.functest.testcase_1bis')
+
+
+def main():
+ conn = os_utils.get_os_connection()
+ results = Results(COMMON_CONFIG.line_length, conn)
+
+ results.add_to_summary(0, "=")
+ results.add_to_summary(2, "STATUS", "SUBTEST")
+ results.add_to_summary(0, "=")
+
+ conn = os_utils.get_os_connection()
+ # neutron client is needed as long as bgpvpn heat module
+ # is not yet installed by default in apex (APEX-618)
+ neutron_client = os_utils.get_neutron_client()
+
+ image_ids = []
+ bgpvpn_ids = []
+
+ try:
+ # image created outside HOT (OS::Glance::Image deprecated since ocata)
+ image_id = os_utils.create_glance_image(
+ conn, TESTCASE_CONFIG.image_name,
+ COMMON_CONFIG.image_path, disk=COMMON_CONFIG.image_format,
+ container="bare", public='public')
+ image_ids = [image_id]
+
+ compute_nodes = test_utils.assert_and_get_compute_nodes(conn)
+ az_1 = "nova:" + compute_nodes[0]
+ az_2 = "nova:" + compute_nodes[1]
+
+ file_path = pkg_resources.resource_filename(
+ 'sdnvpn', TESTCASE_CONFIG.hot_file_name)
+ templ = open(file_path, 'r').read()
+ logger.debug("Template is read: '%s'" % templ)
+ env = test_utils.get_heat_environment(TESTCASE_CONFIG, COMMON_CONFIG)
+ logger.debug("Environment is read: '%s'" % env)
+
+ env['name'] = TESTCASE_CONFIG.stack_name
+ env['template'] = templ
+ env['parameters']['image_n'] = TESTCASE_CONFIG.image_name
+ env['parameters']['av_zone_1'] = az_1
+ env['parameters']['av_zone_2'] = az_2
+
+ stack_id = os_utils.create_stack(conn, **env)
+ if stack_id is None:
+ logger.error("Stack create start failed")
+ raise SystemError("Stack create start failed")
+
+ test_utils.wait_stack_for_status(conn, stack_id, 'CREATE_COMPLETE')
+
+ net_1_output = os_utils.get_output(conn, stack_id, 'net_1_o')
+ network_1_id = net_1_output['output_value']
+ net_2_output = os_utils.get_output(conn, stack_id, 'net_2_o')
+ network_2_id = net_2_output['output_value']
+
+ vm_stack_output_keys = ['vm1_o', 'vm2_o', 'vm3_o', 'vm4_o', 'vm5_o']
+ vms = test_utils.get_vms_from_stack_outputs(conn,
+ stack_id,
+ vm_stack_output_keys)
+
+ logger.debug("Entering base test case with stack '%s'" % stack_id)
+
+ msg = ("Create VPN with eRT<>iRT")
+ results.record_action(msg)
+ vpn_name = "sdnvpn-" + str(randint(100000, 999999))
+ kwargs = {
+ "import_targets": TESTCASE_CONFIG.targets1,
+ "export_targets": TESTCASE_CONFIG.targets2,
+ "route_distinguishers": TESTCASE_CONFIG.route_distinguishers,
+ "name": vpn_name
+ }
+ bgpvpn = test_utils.create_bgpvpn(neutron_client, **kwargs)
+ bgpvpn_id = bgpvpn['bgpvpn']['id']
+ logger.debug("VPN created details: %s" % bgpvpn)
+ bgpvpn_ids.append(bgpvpn_id)
+
+ msg = ("Associate network '%s' to the VPN." %
+ TESTCASE_CONFIG.heat_parameters['net_1_name'])
+ results.record_action(msg)
+ results.add_to_summary(0, "-")
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_1_id)
+
+ # Remember: vms[X] is former vm_X+1
+
+ results.get_ping_status(vms[0], vms[1], expected="PASS", timeout=200)
+ results.get_ping_status(vms[0], vms[2], expected="PASS", timeout=30)
+ results.get_ping_status(vms[0], vms[3], expected="FAIL", timeout=30)
+
+ msg = ("Associate network '%s' to the VPN." %
+ TESTCASE_CONFIG.heat_parameters['net_2_name'])
+ results.add_to_summary(0, "-")
+ results.record_action(msg)
+ results.add_to_summary(0, "-")
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_2_id)
+
+ test_utils.wait_for_bgp_net_assocs(neutron_client,
+ bgpvpn_id,
+ network_1_id,
+ network_2_id)
+
+ logger.info("Waiting for the VMs to connect to each other using the"
+ " updated network configuration")
+ test_utils.wait_before_subtest()
+
+ results.get_ping_status(vms[3], vms[4], expected="PASS", timeout=30)
+ # TODO enable again when isolation in VPN with iRT != eRT works
+ # results.get_ping_status(vms[0], vms[3], expected="FAIL", timeout=30)
+ # results.get_ping_status(vms[0], vms[4], expected="FAIL", timeout=30)
+
+ msg = ("Update VPN with eRT=iRT ...")
+ results.add_to_summary(0, "-")
+ results.record_action(msg)
+ results.add_to_summary(0, "-")
+
+ # use bgpvpn-create instead of update till NETVIRT-1067 bug is fixed
+ # kwargs = {"import_targets": TESTCASE_CONFIG.targets1,
+ # "export_targets": TESTCASE_CONFIG.targets1,
+ # "name": vpn_name}
+ # bgpvpn = test_utils.update_bgpvpn(neutron_client,
+ # bgpvpn_id, **kwargs)
+
+ test_utils.delete_bgpvpn(neutron_client, bgpvpn_id)
+ bgpvpn_ids.remove(bgpvpn_id)
+ kwargs = {
+ "import_targets": TESTCASE_CONFIG.targets1,
+ "export_targets": TESTCASE_CONFIG.targets1,
+ "route_distinguishers": TESTCASE_CONFIG.route_distinguishers,
+ "name": vpn_name
+ }
+
+ test_utils.wait_before_subtest()
+
+ bgpvpn = test_utils.create_bgpvpn(neutron_client, **kwargs)
+ bgpvpn_id = bgpvpn['bgpvpn']['id']
+ logger.debug("VPN re-created details: %s" % bgpvpn)
+ bgpvpn_ids.append(bgpvpn_id)
+
+ msg = ("Associate network '%s' to the VPN." %
+ TESTCASE_CONFIG.heat_parameters['net_1_name'])
+ results.record_action(msg)
+ results.add_to_summary(0, "-")
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_1_id)
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_2_id)
+
+ test_utils.wait_for_bgp_net_assocs(neutron_client,
+ bgpvpn_id,
+ network_1_id,
+ network_2_id)
+ # The above code has to be removed after re-enabling bgpvpn-update
+
+ logger.info("Waiting for the VMs to connect to each other using the"
+ " updated network configuration")
+ test_utils.wait_before_subtest()
+
+ results.get_ping_status(vms[0], vms[3], expected="PASS", timeout=30)
+ results.get_ping_status(vms[0], vms[4], expected="PASS", timeout=30)
+
+ except Exception as e:
+ logger.error("exception occurred while executing testcase_1bis: %s", e)
+ raise
+ finally:
+ test_utils.cleanup_glance(conn, image_ids)
+ test_utils.cleanup_neutron(conn, neutron_client, [], bgpvpn_ids,
+ [], [], [], [])
+
+ try:
+ test_utils.delete_stack_and_wait(conn, stack_id)
+ except Exception as e:
+ logger.error(
+ "exception occurred while executing testcase_1bis: %s", e)
+
+ return results.compile_summary()
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/sdnvpn/test/functest/testcase_3.py b/sdnvpn/test/functest/testcase_3.py
index 2a3a530..a4e9121 100644
--- a/sdnvpn/test/functest/testcase_3.py
+++ b/sdnvpn/test/functest/testcase_3.py
@@ -370,7 +370,7 @@ def main():
instance_ids.append(vm_bgpvpn.id)
# wait for VM to get IP
- instance_up = test_utils.wait_for_instances_up(vm_bgpvpn)
+ instance_up = test_utils.wait_for_instances_get_dhcp(vm_bgpvpn)
if not instance_up:
logger.error("One or more instances are down")
diff --git a/sdnvpn/test/functest/testcase_4bis.py b/sdnvpn/test/functest/testcase_4bis.py
new file mode 100644
index 0000000..6245f7c
--- /dev/null
+++ b/sdnvpn/test/functest/testcase_4bis.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2018 All rights reserved
+# This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+import logging
+import sys
+import pkg_resources
+
+from random import randint
+from sdnvpn.lib import config as sdnvpn_config
+from sdnvpn.lib import openstack_utils as os_utils
+from sdnvpn.lib import utils as test_utils
+from sdnvpn.lib.results import Results
+
+logger = logging.getLogger(__name__)
+
+COMMON_CONFIG = sdnvpn_config.CommonConfig()
+TESTCASE_CONFIG = sdnvpn_config.TestcaseConfig(
+ 'sdnvpn.test.functest.testcase_4bis')
+
+
+def main():
+ conn = os_utils.get_os_connection()
+ results = Results(COMMON_CONFIG.line_length, conn)
+
+ results.add_to_summary(0, '=')
+ results.add_to_summary(2, 'STATUS', 'SUBTEST')
+ results.add_to_summary(0, '=')
+
+ conn = os_utils.get_os_connection()
+ # neutron client is needed as long as bgpvpn heat module
+ # is not yet installed by default in apex (APEX-618)
+ neutron_client = os_utils.get_neutron_client()
+
+ image_ids = []
+ bgpvpn_ids = []
+
+ try:
+ image_id = os_utils.create_glance_image(
+ conn, TESTCASE_CONFIG.image_name,
+ COMMON_CONFIG.image_path, disk=COMMON_CONFIG.image_format,
+ container='bare', public='public')
+ image_ids = [image_id]
+
+ compute_nodes = test_utils.assert_and_get_compute_nodes(conn)
+ az_1 = 'nova:' + compute_nodes[0]
+ az_2 = 'nova:' + compute_nodes[1]
+
+ file_path = pkg_resources.resource_filename(
+ 'sdnvpn', TESTCASE_CONFIG.hot_file_name)
+ templ = open(file_path, 'r').read()
+ logger.debug("Template is read: '%s'" % templ)
+ env = test_utils.get_heat_environment(TESTCASE_CONFIG, COMMON_CONFIG)
+ logger.debug("Environment is read: '%s'" % env)
+
+ env['name'] = TESTCASE_CONFIG.stack_name
+ env['template'] = templ
+ env['parameters']['image_n'] = TESTCASE_CONFIG.image_name
+ env['parameters']['av_zone_1'] = az_1
+ env['parameters']['av_zone_2'] = az_2
+
+ stack_id = os_utils.create_stack(conn, **env)
+ if stack_id is None:
+ logger.error('Stack create start failed')
+ raise SystemError('Stack create start failed')
+
+ test_utils.wait_stack_for_status(conn, stack_id, 'CREATE_COMPLETE')
+
+ router_1_output = os_utils.get_output(conn, stack_id, 'router_1_o')
+ router_1_id = router_1_output['output_value']
+ net_2_output = os_utils.get_output(conn, stack_id, 'net_2_o')
+ network_2_id = net_2_output['output_value']
+
+ vm_stack_output_keys = ['vm1_o', 'vm2_o', 'vm3_o', 'vm4_o', 'vm5_o']
+ vms = test_utils.get_vms_from_stack_outputs(conn,
+ stack_id,
+ vm_stack_output_keys)
+
+ logger.debug("Entering base test case with stack '%s'" % stack_id)
+
+ msg = ('Create VPN with eRT<>iRT')
+ results.record_action(msg)
+ vpn_name = 'sdnvpn-' + str(randint(100000, 999999))
+ kwargs = {
+ 'import_targets': TESTCASE_CONFIG.targets1,
+ 'export_targets': TESTCASE_CONFIG.targets2,
+ 'route_distinguishers': TESTCASE_CONFIG.route_distinguishers,
+ 'name': vpn_name
+ }
+ bgpvpn = test_utils.create_bgpvpn(neutron_client, **kwargs)
+ bgpvpn_id = bgpvpn['bgpvpn']['id']
+ logger.debug("VPN created details: %s" % bgpvpn)
+ bgpvpn_ids.append(bgpvpn_id)
+
+ msg = ("Associate router '%s' to the VPN." %
+ TESTCASE_CONFIG.heat_parameters['router_1_name'])
+ results.record_action(msg)
+ results.add_to_summary(0, '-')
+
+ test_utils.create_router_association(
+ neutron_client, bgpvpn_id, router_1_id)
+
+ # Remember: vms[X] is former vm_X+1
+
+ results.get_ping_status(vms[0], vms[1], expected='PASS', timeout=200)
+ results.get_ping_status(vms[0], vms[2], expected='PASS', timeout=30)
+ results.get_ping_status(vms[0], vms[3], expected='FAIL', timeout=30)
+
+ msg = ("Associate network '%s' to the VPN." %
+ TESTCASE_CONFIG.heat_parameters['net_2_name'])
+ results.add_to_summary(0, '-')
+ results.record_action(msg)
+ results.add_to_summary(0, '-')
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_2_id)
+
+ test_utils.wait_for_bgp_router_assoc(
+ neutron_client, bgpvpn_id, router_1_id)
+ test_utils.wait_for_bgp_net_assocs(
+ neutron_client, bgpvpn_id, network_2_id)
+
+ logger.info('Waiting for the VMs to connect to each other using the'
+ ' updated network configuration')
+ test_utils.wait_before_subtest()
+
+ results.get_ping_status(vms[3], vms[4], expected='PASS', timeout=30)
+ # TODO enable again when isolation in VPN with iRT != eRT works
+ # results.get_ping_status(vms[0], vms[3], expected="FAIL", timeout=30)
+ # results.get_ping_status(vms[0], vms[4], expected="FAIL", timeout=30)
+
+ msg = ('Update VPN with eRT=iRT ...')
+ results.add_to_summary(0, "-")
+ results.record_action(msg)
+ results.add_to_summary(0, "-")
+
+ # use bgpvpn-create instead of update till NETVIRT-1067 bug is fixed
+ # kwargs = {"import_targets": TESTCASE_CONFIG.targets1,
+ # "export_targets": TESTCASE_CONFIG.targets1,
+ # "name": vpn_name}
+ # bgpvpn = test_utils.update_bgpvpn(neutron_client,
+ # bgpvpn_id, **kwargs)
+
+ test_utils.delete_bgpvpn(neutron_client, bgpvpn_id)
+ bgpvpn_ids.remove(bgpvpn_id)
+ kwargs = {
+ 'import_targets': TESTCASE_CONFIG.targets1,
+ 'export_targets': TESTCASE_CONFIG.targets1,
+ 'route_distinguishers': TESTCASE_CONFIG.route_distinguishers,
+ 'name': vpn_name
+ }
+
+ test_utils.wait_before_subtest()
+
+ bgpvpn = test_utils.create_bgpvpn(neutron_client, **kwargs)
+ bgpvpn_id = bgpvpn['bgpvpn']['id']
+ logger.debug("VPN re-created details: %s" % bgpvpn)
+ bgpvpn_ids.append(bgpvpn_id)
+
+ msg = ("Associate again network '%s' and router '%s 'to the VPN."
+ % (TESTCASE_CONFIG.heat_parameters['net_2_name'],
+ TESTCASE_CONFIG.heat_parameters['router_1_name']))
+ results.add_to_summary(0, '-')
+ results.record_action(msg)
+ results.add_to_summary(0, '-')
+
+ test_utils.create_router_association(
+ neutron_client, bgpvpn_id, router_1_id)
+
+ test_utils.create_network_association(
+ neutron_client, bgpvpn_id, network_2_id)
+
+ test_utils.wait_for_bgp_router_assoc(
+ neutron_client, bgpvpn_id, router_1_id)
+ test_utils.wait_for_bgp_net_assoc(
+ neutron_client, bgpvpn_id, network_2_id)
+ # The above code has to be removed after re-enabling bgpvpn-update
+
+ logger.info('Waiting for the VMs to connect to each other using the'
+ ' updated network configuration')
+ test_utils.wait_before_subtest()
+
+ # TODO: uncomment the following once ODL netvirt fixes the following
+ # bug: https://jira.opendaylight.org/browse/NETVIRT-932
+ # results.get_ping_status(vms[0], vms[3], expected="PASS", timeout=30)
+ # results.get_ping_status(vms[0], vms[4], expected="PASS", timeout=30)
+
+ results.add_to_summary(0, '=')
+ logger.info("\n%s" % results.summary)
+
+ except Exception as e:
+ logger.error("exception occurred while executing testcase_4bis: %s", e)
+ raise
+ finally:
+ test_utils.cleanup_glance(conn, image_ids)
+ test_utils.cleanup_neutron(conn, neutron_client, [], bgpvpn_ids,
+ [], [], [], [])
+
+ try:
+ test_utils.delete_stack_and_wait(conn, stack_id)
+ except Exception as e:
+ logger.error(
+ "exception occurred while executing testcase_4bis: %s", e)
+
+ return results.compile_summary()
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..646bbae
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,5 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+flake8 # MIT
+yamllint
diff --git a/tox.ini b/tox.ini
index 69aa189..7880718 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,16 +2,52 @@
minversion = 1.6
envlist =
docs,
- docs-linkcheck
+ docs-linkcheck,
+ pep8,
+ yamllint
skipsdist = true
+[testenv]
+usedevelop = False
+setenv=
+ HOME = {envtmpdir}
+ PYTHONPATH = {toxinidir}
+deps =
+ -chttps://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=master
+ -chttps://git.opnfv.org/functest/plain/upper-constraints.txt?h=master
+ -r{toxinidir}/test-requirements.txt
+ -r{toxinidir}/requirements.txt
+install_command = pip install {opts} {packages}
+
[testenv:docs]
-deps = -rdocs/requirements.txt
+basepython = python2.7
+deps = -r{toxinidir}/docs/requirements.txt
commands =
- sphinx-build -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html
+ sphinx-build -W -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html
echo "Generated docs available in {toxinidir}/docs/_build/html"
whitelist_externals = echo
[testenv:docs-linkcheck]
-deps = -rdocs/requirements.txt
-commands = sphinx-build -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck
+basepython = python2.7
+deps = -r{toxinidir}/docs/requirements.txt
+commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck
+
+[testenv:yamllint]
+basepython = python2.7
+files =
+ {toxinidir}/docs
+ {toxinidir}/sdnvpn/test/functest/
+commands =
+ yamllint -s {[testenv:yamllint]files}
+
+[testenv:pep8]
+basepython = python2.7
+commands = flake8 {toxinidir}
+
+[flake8]
+# E123, E125 skipped as they are invalid PEP-8.
+
+show-source = True
+ignore = E123,E125
+builtins = _
+exclude = build,dist,doc,legacy,.eggs,.git,.tox,.venv,testapi_venv,venv