3 # Copyright (c) 2017 All rights reserved
4 # This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
16 import functest.utils.functest_logger as ft_logger
17 import functest.utils.openstack_utils as os_utils
19 from sdnvpn.lib import config as sdnvpn_config
21 logger = ft_logger.Logger("sndvpn_test_utils").getLogger()
23 common_config = sdnvpn_config.CommonConfig()
29 def create_net(neutron_client, name):
30 logger.debug("Creating network %s", name)
31 net_id = os_utils.create_neutron_net(neutron_client, name)
34 "There has been a problem when creating the neutron network")
39 def create_subnet(neutron_client, name, cidr, net_id):
40 logger.debug("Creating subnet %s in network %s with cidr %s",
42 subnet_id = os_utils.create_neutron_subnet(neutron_client,
48 "There has been a problem when creating the neutron subnet")
53 def create_network(neutron_client, net, subnet1, cidr1,
54 router, subnet2=None, cidr2=None):
55 """Network assoc will not work for networks/subnets created by this function.
57 It is an ODL limitation due to it handling routers as vpns.
58 See https://bugs.opendaylight.org/show_bug.cgi?id=6962"""
59 network_dic = os_utils.create_network_full(neutron_client,
66 "There has been a problem when creating the neutron network")
68 net_id = network_dic["net_id"]
69 subnet_id = network_dic["subnet_id"]
70 router_id = network_dic["router_id"]
72 if subnet2 is not None:
73 logger.debug("Creating and attaching a second subnet...")
74 subnet_id = os_utils.create_neutron_subnet(
75 neutron_client, subnet2, cidr2, net_id)
78 "There has been a problem when creating the second subnet")
80 logger.debug("Subnet '%s' created successfully" % subnet_id)
81 return net_id, subnet_id, router_id
84 def create_instance(nova_client,
96 if 'flavor' not in kwargs:
97 kwargs['flavor'] = common_config.default_flavor
99 logger.info("Creating instance '%s'..." % name)
101 "Configuration:\n name=%s \n flavor=%s \n image=%s \n"
102 " network=%s\n secgroup=%s \n hypervisor=%s \n"
103 " fixed_ip=%s\n files=%s\n userdata=\n%s\n"
104 % (name, kwargs['flavor'], image_id, network_id, sg_id,
105 compute_node, fixed_ip, files, userdata))
106 instance = os_utils.create_instance_and_wait_for_active(
113 av_zone=compute_node,
118 logger.error("Error while booting instance.")
121 logger.debug("Instance '%s' booted successfully. IP='%s'." %
122 (name, instance.networks.itervalues().next()[0]))
123 # Retrieve IP of INSTANCE
124 # instance_ip = instance.networks.get(network_id)[0]
127 logger.debug("Adding '%s' to security group '%s'..."
128 % (name, secgroup_name))
130 logger.debug("Adding '%s' to security group '%s'..."
132 os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
137 def generate_ping_userdata(ips_array):
140 ips = ("%s %s" % (ips, ip))
142 ips = ips.replace(' ', ' ')
143 return ("#!/bin/sh\n"
148 " ping -c 1 $ip 2>&1 >/dev/null\n"
150 " if [ \"Z$RES\" = \"Z0\" ] ; then\n"
151 " echo ping $ip OK\n"
152 " else echo ping $ip KO\n"
160 def generate_userdata_common():
161 return ("#!/bin/sh\n"
162 "sudo mkdir -p /home/cirros/.ssh/\n"
163 "sudo chown cirros:cirros /home/cirros/.ssh/\n"
164 "sudo chown cirros:cirros /home/cirros/id_rsa\n"
165 "mv /home/cirros/id_rsa /home/cirros/.ssh/\n"
166 "sudo echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWtSS98Am516e"
167 "stBsq0jbyOB4eLMUYDdgzsUHsnxFQCtACwwAg9/2uq3FoGUBUWeHZNsT6jcK9"
168 "sCMEYiS479CUCzbrxcd8XaIlK38HECcDVglgBNwNzX/WDfMejXpKzZG61s98rU"
169 "ElNvZ0YDqhaqZGqxIV4ejalqLjYrQkoly3R+2k= "
170 "cirros@test1>/home/cirros/.ssh/authorized_keys\n"
171 "sudo chown cirros:cirros /home/cirros/.ssh/authorized_keys\n"
172 "chmod 700 /home/cirros/.ssh\n"
173 "chmod 644 /home/cirros/.ssh/authorized_keys\n"
174 "chmod 600 /home/cirros/.ssh/id_rsa\n"
178 def generate_userdata_with_ssh(ips_array):
179 u1 = generate_userdata_common()
183 ips = ("%s %s" % (ips, ip))
185 ips = ips.replace(' ', ' ')
191 " hostname=$(ssh -y -i /home/cirros/.ssh/id_rsa "
192 "cirros@$ip 'hostname' </dev/zero 2>/dev/null)\n"
194 " if [ \"Z$RES\" = \"Z0\" ]; then echo $ip $hostname;\n"
195 " else echo $ip 'not reachable';fi;\n"
203 def wait_for_instance(instance):
204 logger.info("Waiting for instance %s to get a DHCP lease..." % instance.id)
205 # The sleep this function replaced waited for 80s
208 pattern = "Lease of .* obtained, lease time"
209 expected_regex = re.compile(pattern)
211 while tries > 0 and not expected_regex.search(console_log):
212 console_log = instance.get_console_output()
213 time.sleep(sleep_time)
216 if not expected_regex.search(console_log):
217 logger.error("Instance %s seems to have failed leasing an IP."
223 def wait_for_instances_up(*args):
224 check = [wait_for_instance(instance) for instance in args]
228 def wait_for_bgp_net_assoc(neutron_client, bgpvpn_id, net_id):
232 logger.debug("Waiting for network %s to associate with BGPVPN %s "
233 % (bgpvpn_id, net_id))
235 while tries > 0 and net_id not in nets:
236 nets = os_utils.get_bgpvpn_networks(neutron_client, bgpvpn_id)
237 time.sleep(sleep_time)
239 if net_id not in nets:
240 logger.error("Association of network %s with BGPVPN %s failed" %
246 def wait_for_bgp_net_assocs(neutron_client, bgpvpn_id, *args):
247 check = [wait_for_bgp_net_assoc(neutron_client, bgpvpn_id, id)
249 # Return True if all associations succeeded
253 def wait_for_bgp_router_assoc(neutron_client, bgpvpn_id, router_id):
257 logger.debug("Waiting for router %s to associate with BGPVPN %s "
258 % (bgpvpn_id, router_id))
259 while tries > 0 and router_id not in routers:
260 routers = os_utils.get_bgpvpn_routers(neutron_client, bgpvpn_id)
261 time.sleep(sleep_time)
263 if router_id not in routers:
264 logger.error("Association of router %s with BGPVPN %s failed" %
265 (router_id, bgpvpn_id))
270 def wait_for_bgp_router_assocs(neutron_client, bgpvpn_id, *args):
271 check = [wait_for_bgp_router_assoc(neutron_client, bgpvpn_id, id)
273 # Return True if all associations succeeded
277 def wait_before_subtest(*args, **kwargs):
278 ''' This is a placeholder.
279 TODO: Replace delay with polling logic. '''
283 def assert_and_get_compute_nodes(nova_client, required_node_number=2):
284 """Get the compute nodes in the deployment
286 Exit if the deployment doesn't have enough compute nodes"""
287 compute_nodes = os_utils.get_hypervisors(nova_client)
289 num_compute_nodes = len(compute_nodes)
290 if num_compute_nodes < 2:
291 logger.error("There are %s compute nodes in the deployment. "
292 "Minimum number of nodes to complete the test is 2."
296 logger.debug("Compute nodes: %s" % compute_nodes)
300 def open_icmp_ssh(neutron_client, security_group_id):
301 os_utils.create_secgroup_rule(neutron_client,
305 os_utils.create_secgroup_rule(neutron_client,
311 def open_bgp_port(neutron_client, security_group_id):
312 os_utils.create_secgroup_rule(neutron_client,
318 def exec_cmd(cmd, verbose):
320 logger.debug("Executing '%s'" % cmd)
321 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
322 stderr=subprocess.STDOUT)
324 for line in iter(p.stdout.readline, b''):
331 returncode = p.wait()
333 logger.error("Command %s failed to execute." % cmd)
336 return output, success
339 def check_odl_fib(ip, controller_ip):
340 """Check that there is an entry in the ODL Fib for `ip`"""
341 url = "http://" + controller_ip + \
342 ":8181/restconf/config/odl-fib:fibEntries/"
343 logger.debug("Querring '%s' for FIB entries", url)
344 res = requests.get(url, auth=(ODL_USER, ODL_PASS))
345 if res.status_code != 200:
346 logger.error("OpenDaylight response status code: %s", res.status_code)
348 logger.debug("Checking whether '%s' is in the OpenDaylight FIB"
350 logger.debug("OpenDaylight FIB: \n%s" % res.text)
351 return ip in res.text
354 def run_odl_cmd(odl_node, cmd):
356 Run a command in the OpenDaylight Karaf shell
358 This is a bit flimsy because of shell quote escaping, make sure that
359 the cmd passed does not have any top level double quotes or this
362 karaf_cmd = '/opt/opendaylight/bin/client "%s" ' % cmd
363 return odl_node.run_cmd(karaf_cmd)