aboutsummaryrefslogtreecommitdiffstats
path: root/sfc/lib
diff options
context:
space:
mode:
authorJaime Caamaño Ruiz <jcaamano@suse.com>2018-03-06 19:43:20 +0100
committerJaime Caamaño Ruiz <jcaamano@suse.com>2018-04-04 16:52:08 +0200
commit8e85daee26c523cd181f5884858646b7589c50af (patch)
tree5b2d21ac54d9a470cde4ce329c9098b936b91200 /sfc/lib
parentf66a8164cfb2ef172ee3ea274992b9c07306f08c (diff)
Update symmetric chain test case
Update the symmetric chain test case aligning it with updates available from ODL Oxygen: - ODL networking-sfc implementation now supports symmetric paths. It is no longer needed to configure the ACL or chain directly through the ODL rest api. It can now be fully relied on tacker for this. - ODL networking-sfc implementation now supports different ingress and egress ports for port pairs. The test case exercises this by setting up a VNF with two distinct ports. Note that this requires an updated VNF image that supports two nics and bundles a vxlan_tool capable of using them. Change-Id: Ie711abb93109943dcbf699ece7b2b570500a3711 Signed-off-by: Jaime Caamaño Ruiz <jcaamano@suse.com>
Diffstat (limited to 'sfc/lib')
-rw-r--r--sfc/lib/config.py2
-rw-r--r--sfc/lib/openstack_utils.py125
-rw-r--r--sfc/lib/test_utils.py9
3 files changed, 98 insertions, 38 deletions
diff --git a/sfc/lib/config.py b/sfc/lib/config.py
index 5ee3077a..8cc1efb4 100644
--- a/sfc/lib/config.py
+++ b/sfc/lib/config.py
@@ -30,7 +30,7 @@ class CommonConfig(object):
"""
def __init__(self):
- self.line_length = 30
+ self.line_length = 35
self.functest_repo_path = os.path.dirname(functest.__file__)
self.functest_logging_api = os.path.join(self.functest_repo_path,
"ci", "logging.ini")
diff --git a/sfc/lib/openstack_utils.py b/sfc/lib/openstack_utils.py
index 4a1c634d..b7254bf1 100644
--- a/sfc/lib/openstack_utils.py
+++ b/sfc/lib/openstack_utils.py
@@ -157,18 +157,30 @@ class OpenStackSFC:
'''
Return the compute where the client sits
'''
+ return self.get_vm_compute('client')
+
+ def get_compute_server(self):
+ '''
+ Return the compute where the server sits
+ '''
+ return self.get_vm_compute('server')
+
+ def get_vm_compute(self, vm_name):
+ '''
+ Return the compute where the vm sits
+ '''
for creator in self.creators:
# We want to filter the vm creators
if hasattr(creator, 'get_vm_inst'):
- # We want to fetch only the client
- if creator.get_vm_inst().name == 'client':
+ # We want to fetch by vm_name
+ if creator.get_vm_inst().name == vm_name:
return creator.get_vm_inst().compute_host
- raise Exception("There is no client VM!!")
+ raise Exception("There is no VM with name '{}'!!".format(vm_name))
def assign_floating_ip(self, router, vm, vm_creator):
'''
- Assign a floating ips to all the VMs
+ Assign floating ips to all the VMs
'''
name = vm.name + "-float"
port_name = vm.ports[0].name
@@ -180,9 +192,11 @@ class OpenStackSFC:
return ip.ip
# We need this function because tacker VMs cannot be created through SNAPs
- def assign_floating_ip_vnfs(self, router):
+ def assign_floating_ip_vnfs(self, router, ips=None):
'''
- Assign a floating ips to all the SFs
+ Assign floating ips to all the SFs. Optionally specify the
+ subnet IPs that a floating IP should be assigned to, assuming that the
+ SF is connected to a single subnet globally and per port.
'''
stacks = self.heat.stacks.list()
fips = []
@@ -198,8 +212,25 @@ class OpenStackSFC:
servers[0],
self.image_settings,
project_name)
- port_name = servers[0].ports[0].name
+
name = servers[0].name + "-float"
+ if ips is None:
+ port_name = servers[0].ports[0].name
+ else:
+ port_name = None
+ for port in servers[0].ports:
+ if port.ips[0]['ip_address'] in ips:
+ port_name = port.name
+ break
+
+ if port_name is None:
+ err_msg = "The VNF {} does not have any suitable port {} " \
+ "for floating IP assignment".format(
+ name,
+ 'with ip any of ' + str(ips) if ips else '')
+ logger.error(err_msg)
+ raise Exception(err_msg)
+
float_ip = FloatingIpConfig(name=name,
port_name=port_name,
router_name=router.name)
@@ -298,7 +329,7 @@ def list_vnfds(tacker_client, verbose=False):
if not verbose:
vnfds = [vnfd['id'] for vnfd in vnfds['vnfds']]
return vnfds
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_vnfds(tacker_client)]: %s" % e)
return None
@@ -313,7 +344,7 @@ def create_vnfd(tacker_client, tosca_file=None, vnfd_name=None):
return tacker_client.create_vnfd(
body={"vnfd": {"attributes": {"vnfd": vnfd_body},
"name": vnfd_name}})
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_vnfd(tacker_client, '%s')]: %s"
% (tosca_file, e))
return None
@@ -327,7 +358,7 @@ def delete_vnfd(tacker_client, vnfd_id=None, vnfd_name=None):
raise Exception('You need to provide VNFD id or VNFD name')
vnfd = get_vnfd_id(tacker_client, vnfd_name)
return tacker_client.delete_vnfd(vnfd)
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_vnfd(tacker_client, '%s', '%s')]: %s"
% (vnfd_id, vnfd_name, e))
return None
@@ -339,7 +370,7 @@ def list_vnfs(tacker_client, verbose=False):
if not verbose:
vnfs = [vnf['id'] for vnf in vnfs['vnfs']]
return vnfs
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_vnfs(tacker_client)]: %s" % e)
return None
@@ -374,7 +405,7 @@ def create_vnf(tacker_client, vnf_name, vnfd_id=None,
vnf_body['vnf']['vim_id'] = get_vim_id(tacker_client, vim_name)
return tacker_client.create_vnf(body=vnf_body)
- except Exception, e:
+ except Exception as e:
logger.error("error [create_vnf(tacker_client,"
" '%s', '%s', '%s')]: %s"
% (vnf_name, vnfd_id, vnfd_name, e))
@@ -394,12 +425,28 @@ def get_vnf(tacker_client, vnf_id=None, vnf_name=None):
else:
raise Exception('Could not retrieve ID from name [%s]' % vnf_name)
- except Exception, e:
+ except Exception as e:
logger.error("Could not retrieve VNF [vnf_id=%s, vnf_name=%s] - %s"
% (vnf_id, vnf_name, e))
return None
+def get_vnf_ip(tacker_client, vnf_id=None, vnf_name=None):
+ """
+ Get the management ip of the first VNF component as obtained from the
+ tacker REST API:
+
+ {
+ "vnf": {
+ ...
+ "mgmt_url": "{\"VDU1\": \"192.168.120.3\"}",
+ ...
+ }
+ """
+ vnf = get_vnf(tacker_client, vnf_id, vnf_name)
+ return json.loads(vnf['mgmt_url']).values()[0]
+
+
def wait_for_vnf(tacker_client, vnf_id=None, vnf_name=None, timeout=100):
try:
vnf = get_vnf(tacker_client, vnf_id, vnf_name)
@@ -419,7 +466,7 @@ def wait_for_vnf(tacker_client, vnf_id=None, vnf_name=None, timeout=100):
raise Exception('Timeout when booting vnf %s' % vnf['id'])
return vnf['id']
- except Exception, e:
+ except Exception as e:
logger.error("error [wait_for_vnf(tacker_client, '%s', '%s')]: %s"
% (vnf_id, vnf_name, e))
return None
@@ -433,7 +480,7 @@ def delete_vnf(tacker_client, vnf_id=None, vnf_name=None):
raise Exception('You need to provide a VNF id or name')
vnf = get_vnf_id(tacker_client, vnf_name)
return tacker_client.delete_vnf(vnf)
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_vnf(tacker_client, '%s', '%s')]: %s"
% (vnf_id, vnf_name, e))
return None
@@ -447,7 +494,7 @@ def create_vim(tacker_client, vim_file=None):
vim_body = json.load(vim_fd)
logger.info('VIM template:\n{0}'.format(vim_body))
return tacker_client.create_vim(body=vim_body)
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_vim(tacker_client, '%s')]: %s"
% (vim_file, e))
return None
@@ -463,14 +510,14 @@ def create_vnffgd(tacker_client, tosca_file=None, vnffgd_name=None):
return tacker_client.create_vnffgd(
body={'vnffgd': {'name': vnffgd_name,
'template': {'vnffgd': vnffgd_body}}})
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_vnffgd(tacker_client, '%s')]: %s"
% (tosca_file, e))
return None
def create_vnffg(tacker_client, vnffg_name=None, vnffgd_id=None,
- vnffgd_name=None, param_file=None):
+ vnffgd_name=None, param_file=None, symmetrical=False):
'''
Creates the vnffg which will provide the RSP and the classifier
'''
@@ -478,7 +525,8 @@ def create_vnffg(tacker_client, vnffg_name=None, vnffgd_id=None,
vnffg_body = {
'vnffg': {
'attributes': {},
- 'name': vnffg_name
+ 'name': vnffg_name,
+ 'symmetrical': symmetrical
}
}
if param_file is not None:
@@ -495,7 +543,7 @@ def create_vnffg(tacker_client, vnffg_name=None, vnffgd_id=None,
vnffg_body['vnffg']['vnffgd_id'] = get_vnffgd_id(tacker_client,
vnffgd_name)
return tacker_client.create_vnffg(body=vnffg_body)
- except Exception, e:
+ except Exception as e:
logger.error("error [create_vnffg(tacker_client,"
" '%s', '%s', '%s')]: %s"
% (vnffg_name, vnffgd_id, vnffgd_name, e))
@@ -508,7 +556,7 @@ def list_vnffgds(tacker_client, verbose=False):
if not verbose:
vnffgds = [vnffgd['id'] for vnffgd in vnffgds['vnffgds']]
return vnffgds
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_vnffgds(tacker_client)]: %s" % e)
return None
@@ -519,7 +567,7 @@ def list_vnffgs(tacker_client, verbose=False):
if not verbose:
vnffgs = [vnffg['id'] for vnffg in vnffgs['vnffgs']]
return vnffgs
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_vnffgs(tacker_client)]: %s" % e)
return None
@@ -532,7 +580,7 @@ def delete_vnffg(tacker_client, vnffg_id=None, vnffg_name=None):
raise Exception('You need to provide a VNFFG id or name')
vnffg = get_vnffg_id(tacker_client, vnffg_name)
return tacker_client.delete_vnffg(vnffg)
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_vnffg(tacker_client, '%s', '%s')]: %s"
% (vnffg_id, vnffg_name, e))
return None
@@ -546,7 +594,7 @@ def delete_vnffgd(tacker_client, vnffgd_id=None, vnffgd_name=None):
raise Exception('You need to provide VNFFGD id or VNFFGD name')
vnffgd = get_vnffgd_id(tacker_client, vnffgd_name)
return tacker_client.delete_vnffgd(vnffgd)
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_vnffgd(tacker_client, '%s', '%s')]: %s"
% (vnffgd_id, vnffgd_name, e))
return None
@@ -558,7 +606,7 @@ def list_vims(tacker_client, verbose=False):
if not verbose:
vims = [vim['id'] for vim in vims['vims']]
return vims
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_vims(tacker_client)]: %s" % e)
return None
@@ -571,7 +619,7 @@ def delete_vim(tacker_client, vim_id=None, vim_name=None):
raise Exception('You need to provide VIM id or VIM name')
vim = get_vim_id(tacker_client, vim_name)
return tacker_client.delete_vim(vim)
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_vim(tacker_client, '%s', '%s')]: %s"
% (vim_id, vim_name, e))
return None
@@ -626,19 +674,28 @@ def create_vnf_in_av_zone(
def create_vnffg_with_param_file(tacker_client, vnffgd_name, vnffg_name,
- default_param_file, neutron_port):
+ default_param_file, client_port,
+ server_port=None, server_ip=None):
param_file = default_param_file
-
- if neutron_port is not None:
+ data = {}
+ if client_port:
+ data['net_src_port_id'] = client_port
+ if server_port:
+ data['net_dst_port_id'] = server_port
+ if server_ip:
+ data['ip_dst_prefix'] = server_ip
+
+ if client_port is not None or server_port is not None:
param_file = os.path.join(
'/tmp',
- 'param_{0}.json'.format(neutron_port))
- data = {
- 'net_src_port_id': neutron_port
- }
+ 'param_{0}.json'.format(vnffg_name))
with open(param_file, 'w+') as f:
json.dump(data, f)
+
+ symmetrical = True if client_port and server_port else False
+
create_vnffg(tacker_client,
vnffgd_name=vnffgd_name,
vnffg_name=vnffg_name,
- param_file=param_file)
+ param_file=param_file,
+ symmetrical=symmetrical)
diff --git a/sfc/lib/test_utils.py b/sfc/lib/test_utils.py
index c495aa11..18c55dc1 100644
--- a/sfc/lib/test_utils.py
+++ b/sfc/lib/test_utils.py
@@ -124,17 +124,20 @@ def start_http_server(ip, iterations_check=10):
return False
-def start_vxlan_tool(remote_ip, interface="eth0", block=None):
+def start_vxlan_tool(remote_ip, interface="eth0", output=None, block=None):
"""
Starts vxlan_tool on a remote host.
vxlan_tool.py converts a regular Service Function into a NSH-aware SF
when the "--do forward" option is used, it decrements the NSI appropiately.
- 'block' parameters allows to specify a port where packets will be dropped.
+ 'output' allows to specify an interface through which to forward if
+ different than the input interface.
+ 'block' parameter allows to specify a port where packets will be dropped.
"""
command = "nohup python /root/vxlan_tool.py"
- options = "{do} {interface} {block_option}".format(
+ options = "{do} {interface} {output_option} {block_option}".format(
do="--do forward",
interface="--interface {}".format(interface),
+ output_option="--output {}".format(output) if output else "",
block_option="--block {}".format(block) if block is not None else "")
output_redirection = "> /dev/null 2>&1"