3 # Copyright (c) 2015 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
13 from random import randint
17 import functest.utils.functest_logger as ft_logger
18 import functest.utils.functest_utils as ft_utils
19 import functest.utils.openstack_utils as os_utils
22 parser = argparse.ArgumentParser()
24 parser.add_argument("-r", "--report",
25 help="Create json result file",
28 args = parser.parse_args()
30 logger = ft_logger.Logger("sdnvpn-testcase-2").getLogger()
32 REPO_PATH = os.environ['repos_dir'] + '/sdnvpn/'
36 config_file = REPO_PATH + 'test/functest/config.yaml'
38 INSTANCE_1_NAME = ft_utils.get_parameter_from_yaml(
39 "testcases.testcase_2.instance_1_name", config_file)
40 INSTANCE_1_IP = "10.10.10.11"
41 INSTANCE_2_NAME = ft_utils.get_parameter_from_yaml(
42 "testcases.testcase_2.instance_2_name", config_file)
43 INSTANCE_2_IP = "10.10.10.12"
44 INSTANCE_3_NAME = ft_utils.get_parameter_from_yaml(
45 "testcases.testcase_2.instance_3_name", config_file)
46 INSTANCE_3_IP = "10.10.11.13"
47 INSTANCE_4_NAME = ft_utils.get_parameter_from_yaml(
48 "testcases.testcase_2.instance_4_name", config_file)
49 INSTANCE_4_IP = "10.10.10.12"
50 INSTANCE_5_NAME = ft_utils.get_parameter_from_yaml(
51 "testcases.testcase_2.instance_5_name", config_file)
52 INSTANCE_5_IP = "10.10.11.13"
53 FLAVOR = ft_utils.get_parameter_from_yaml(
54 "testcases.testcase_2.flavor", config_file)
55 IMAGE_NAME = ft_utils.get_parameter_from_yaml(
56 "testcases.testcase_2.image_name", config_file)
57 IMAGE_FILENAME = ft_utils.get_parameter_from_yaml(
58 "general.openstack.image_file_name")
59 IMAGE_FORMAT = ft_utils.get_parameter_from_yaml(
60 "general.openstack.image_disk_format")
61 IMAGE_PATH = ft_utils.get_parameter_from_yaml(
62 "general.directories.dir_functest_data") + "/" + IMAGE_FILENAME
64 KEYFILE_PATH = REPO_PATH + 'test/functest/id_rsa'
66 # NEUTRON Private Network parameters
68 NET_1_NAME = ft_utils.get_parameter_from_yaml(
69 "testcases.testcase_2.net_1_name", config_file)
70 SUBNET_1a_NAME = ft_utils.get_parameter_from_yaml(
71 "testcases.testcase_2.subnet_1a_name", config_file)
72 SUBNET_1a_CIDR = ft_utils.get_parameter_from_yaml(
73 "testcases.testcase_2.subnet_1a_cidr", config_file)
74 SUBNET_1b_NAME = ft_utils.get_parameter_from_yaml(
75 "testcases.testcase_2.subnet_1b_name", config_file)
76 SUBNET_1b_CIDR = ft_utils.get_parameter_from_yaml(
77 "testcases.testcase_2.subnet_1b_cidr", config_file)
78 ROUTER_1_NAME = ft_utils.get_parameter_from_yaml(
79 "testcases.testcase_2.router_1_name", config_file)
80 NET_2_NAME = ft_utils.get_parameter_from_yaml(
81 "testcases.testcase_2.net_2_name", config_file)
82 SUBNET_2a_NAME = ft_utils.get_parameter_from_yaml(
83 "testcases.testcase_2.subnet_2a_name", config_file)
84 SUBNET_2a_CIDR = ft_utils.get_parameter_from_yaml(
85 "testcases.testcase_2.subnet_2a_cidr", config_file)
86 SUBNET_2b_NAME = ft_utils.get_parameter_from_yaml(
87 "testcases.testcase_2.subnet_2b_name", config_file)
88 SUBNET_2b_CIDR = ft_utils.get_parameter_from_yaml(
89 "testcases.testcase_2.subnet_2b_cidr", config_file)
90 ROUTER_1_NAME = ft_utils.get_parameter_from_yaml(
91 "testcases.testcase_2.router_1_name", config_file)
92 ROUTER_2_NAME = ft_utils.get_parameter_from_yaml(
93 "testcases.testcase_2.router_2_name", config_file)
94 SECGROUP_NAME = ft_utils.get_parameter_from_yaml(
95 "testcases.testcase_2.sdnvpn_sg_name", config_file)
96 SECGROUP_DESCR = ft_utils.get_parameter_from_yaml(
97 "testcases.testcase_2.sdnvpn_sg_descr", config_file)
98 TARGETS_1 = ft_utils.get_parameter_from_yaml(
99 "testcases.testcase_2.targets1", config_file)
100 TARGETS_2 = ft_utils.get_parameter_from_yaml(
101 "testcases.testcase_2.targets2", config_file)
102 SUCCESS_CRITERIA = ft_utils.get_parameter_from_yaml(
103 "testcases.testcase_1.succes_criteria", config_file)
104 TEST_DB = ft_utils.get_parameter_from_yaml("results.test_db_url")
108 LINE_LENGTH = 90 # length for the summary table
114 def create_network(neutron_client, net, subnet1, cidr1,
115 router, subnet2=None, cidr2=None):
116 network_dic = os_utils.create_network_full(logger,
124 "There has been a problem when creating the neutron network")
126 net_id = network_dic["net_id"]
127 if subnet2 is not None:
128 logger.debug("Creating and attaching a second subnet...")
129 subnet_id = os_utils.create_neutron_subnet(
130 neutron_client, subnet2, cidr2, net_id)
133 "There has been a problem when creating the second subnet")
135 logger.debug("Subnet '%s' created successfully" % subnet_id)
139 def create_instance(nova_client,
149 logger.info("Creating instance '%s'..." % name)
151 "Configuration:\n name=%s \n flavor=%s \n image=%s \n"
152 " network=%s\n secgroup=%s \n hypervisor=%s \n"
153 " fixed_ip=%s\n files=%s\n userdata=\n%s\n"
154 % (name, flavor, image_id, network_id, sg_id,
155 compute_node, fixed_ip, files, userdata))
156 instance = os_utils.create_instance_and_wait_for_active(
163 av_zone=compute_node,
168 logger.error("Error while booting instance.")
170 # Retrieve IP of INSTANCE
171 # instance_ip = instance.networks.get(network_id)[0]
173 logger.debug("Adding '%s' to security group '%s'..."
174 % (name, SECGROUP_NAME))
175 os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
180 def generate_userdata_common():
181 return ("#!/bin/sh\n"
182 "sudo mkdir -p /home/cirros/.ssh/\n"
183 "sudo chown cirros:cirros /home/cirros/.ssh/\n"
184 "sudo chown cirros:cirros /home/cirros/id_rsa\n"
185 "mv /home/cirros/id_rsa /home/cirros/.ssh/\n"
186 "sudo echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWtSS98Am516e"
187 "stBsq0jbyOB4eLMUYDdgzsUHsnxFQCtACwwAg9/2uq3FoGUBUWeHZNsT6jcK9"
188 "sCMEYiS479CUCzbrxcd8XaIlK38HECcDVglgBNwNzX/WDfMejXpKzZG61s98rU"
189 "ElNvZ0YDqhaqZGqxIV4ejalqLjYrQkoly3R+2k= "
190 "cirros@test1>/home/cirros/.ssh/authorized_keys\n"
191 "sudo chown cirros:cirros /home/cirros/.ssh/authorized_keys\n"
192 "chmod 700 /home/cirros/.ssh\n"
193 "chmod 644 /home/cirros/.ssh/authorized_keys\n"
194 "chmod 600 /home/cirros/.ssh/id_rsa\n"
198 def generate_userdata_with_ssh(ips_array):
199 u1 = generate_userdata_common()
203 ips = ("%s %s" % (ips, ip))
205 ips = ips.replace(' ', ' ')
211 " hostname=$(ssh -y -i /home/cirros/.ssh/id_rsa "
212 "cirros@$ip 'hostname' </dev/zero 2>/dev/null)\n"
214 " if [ \"Z$RES\" = \"Z0\" ]; then echo $ip $hostname;\n"
215 " else echo $ip 'not reachable';fi;\n"
223 def check_ssh_output(vm_source, ip_source,
224 vm_target, ip_target,
225 expected, timeout=30):
226 console_log = vm_source.get_console_output()
230 if "request failed" in console_log:
231 # Normally, cirros displays this message when userdata fails
232 logger.debug("It seems userdata is not supported in "
236 tab = ("%s" % (" " * 53))
237 test_case_name = ("[%s] returns 'I am %s' to '%s'[%s]" %
238 (ip_target, expected,
239 vm_source.name, ip_source))
240 logger.debug("%sSSH\n%sfrom '%s' (%s)\n%sto '%s' (%s).\n"
241 "%s-->Expected result: %s.\n"
242 % (tab, tab, vm_source.name, ip_source,
243 tab, vm_target.name, ip_target,
246 console_log = vm_source.get_console_output()
247 # the console_log is a long string, we want to take
248 # the last 4 lines (for example)
249 lines = console_log.split('\n')
250 last_n_lines = lines[-5:]
251 if ("%s %s" % (ip_target, expected)) in last_n_lines:
252 logger.debug("[PASS] %s" % test_case_name)
253 add_to_summary(2, "PASS", test_case_name)
255 elif ("%s not reachable" % ip_target) in last_n_lines:
256 logger.debug("[FAIL] %s" % test_case_name)
257 add_to_summary(2, "FAIL", test_case_name)
264 logger.debug("[FAIL] Timeout reached for '%s'. No ping output "
265 "captured in the console log" % vm_source.name)
266 add_to_summary(2, "FAIL", test_case_name)
270 def add_to_summary(num_cols, col1, col2=""):
271 global SUMMARY, LINE_LENGTH, NUM_TESTS, NUM_TESTS_FAILED
273 SUMMARY += ("+%s+\n" % (col1 * (LINE_LENGTH - 2)))
275 SUMMARY += ("| " + col1.ljust(LINE_LENGTH - 3) + "|\n")
277 SUMMARY += ("| %s" % col1.ljust(7) + "| ")
278 SUMMARY += (col2.ljust(LINE_LENGTH - 12) + "|\n")
279 if col1 in ("FAIL", "PASS"):
280 DETAILS.append({col2: col1})
283 NUM_TESTS_FAILED += 1
287 global TEST_RESULT, SUMMARY
289 add_to_summary(0, "=")
290 add_to_summary(2, "STATUS", "SUBTEST")
291 add_to_summary(0, "=")
293 nova_client = os_utils.get_nova_client()
294 neutron_client = os_utils.get_neutron_client()
295 glance_client = os_utils.get_glance_client()
297 logger.debug("Using private key %s injected to the VMs." % KEYFILE_PATH)
298 keyfile = open(KEYFILE_PATH, 'r')
301 files = {"/home/cirros/id_rsa": key}
303 image_id = os_utils.create_glance_image(glance_client,
310 network_1_id = create_network(neutron_client,
317 network_2_id = create_network(neutron_client,
324 sg_id = os_utils.create_security_group_full(logger, neutron_client,
325 SECGROUP_NAME, SECGROUP_DESCR)
327 # Get hypervisors zones
328 compute_nodes = os_utils.get_hypervisors(nova_client)
329 num_compute_nodes = len(compute_nodes)
330 if num_compute_nodes < 2:
331 logger.error("There are %s compute nodes in the deployment. "
332 "Minimum number of nodes to complete the test is 2."
336 logger.debug("Compute nodes: %s" % compute_nodes)
337 av_zone_1 = "nova:" + compute_nodes[0]
338 av_zone_2 = "nova:" + compute_nodes[1]
341 userdata_common = generate_userdata_common()
342 vm_2 = create_instance(nova_client,
349 compute_node=av_zone_1,
350 userdata=userdata_common)
351 vm_2_ip = vm_2.networks.itervalues().next()[0]
352 logger.debug("Instance '%s' booted successfully. IP='%s'." %
353 (INSTANCE_2_NAME, vm_2_ip))
355 vm_3 = create_instance(nova_client,
361 compute_node=av_zone_2,
362 userdata=userdata_common)
363 vm_3_ip = vm_3.networks.itervalues().next()[0]
364 logger.debug("Instance '%s' booted successfully. IP='%s'." %
365 (INSTANCE_3_NAME, vm_3_ip))
367 vm_5 = create_instance(nova_client,
373 fixed_ip=INSTANCE_5_IP,
374 compute_node=av_zone_2,
375 userdata=userdata_common)
376 vm_5_ip = vm_5.networks.itervalues().next()[0]
377 logger.debug("Instance '%s' booted successfully. IP='%s'." %
378 (INSTANCE_5_NAME, vm_5_ip))
380 # We boot vm5 first because we need vm5_ip for vm4 userdata
381 u4 = generate_userdata_with_ssh(
382 [INSTANCE_1_IP, INSTANCE_3_IP, INSTANCE_5_IP])
383 vm_4 = create_instance(nova_client,
389 fixed_ip=INSTANCE_4_IP,
390 compute_node=av_zone_1,
393 vm_4_ip = vm_4.networks.itervalues().next()[0]
394 logger.debug("Instance '%s' booted successfully. IP='%s'." %
395 (INSTANCE_4_NAME, vm_4_ip))
397 # We boot VM1 at the end because we need to get the IPs first to generate
399 u1 = generate_userdata_with_ssh(
400 [INSTANCE_2_IP, INSTANCE_3_IP, INSTANCE_4_IP, INSTANCE_5_IP])
401 vm_1 = create_instance(nova_client,
407 fixed_ip=INSTANCE_1_IP,
408 compute_node=av_zone_1,
411 vm_1_ip = vm_1.networks.itervalues().next()[0]
412 logger.debug("Instance '%s' booted successfully. IP='%s'." %
413 (INSTANCE_1_NAME, vm_1_ip))
415 msg = ("Create VPN1 with eRT=iRT")
417 add_to_summary(1, msg)
418 vpn1_name = "sdnvpn-1-" + str(randint(100000, 999999))
419 kwargs = {"import_targets": TARGETS_2,
420 "export_targets": TARGETS_2,
421 "route_targets": TARGETS_2,
423 bgpvpn1 = os_utils.create_bgpvpn(neutron_client, **kwargs)
424 bgpvpn1_id = bgpvpn1['bgpvpn']['id']
425 logger.debug("VPN1 created details: %s" % bgpvpn1)
427 msg = ("Associate network '%s' to the VPN." % NET_1_NAME)
429 add_to_summary(1, msg)
430 add_to_summary(0, "-")
432 os_utils.create_network_association(
433 neutron_client, bgpvpn1_id, network_1_id)
435 # Wait for VMs to get ips.
438 # 10.10.10.12 should return sdnvpn-2 to sdnvpn-1
440 vm_1, vm_1_ip, vm_2, vm_2_ip, expected=INSTANCE_2_NAME, timeout=200)
441 # 10.10.11.13 should return sdnvpn-3 to sdnvpn-1
443 vm_1, vm_1_ip, vm_3, vm_3_ip, expected=INSTANCE_3_NAME, timeout=30)
445 add_to_summary(0, "-")
446 msg = ("Create VPN2 with eRT=iRT")
448 add_to_summary(1, msg)
449 vpn2_name = "sdnvpn-2-" + str(randint(100000, 999999))
450 kwargs = {"import_targets": TARGETS_1,
451 "export_targets": TARGETS_1,
452 "route_targets": TARGETS_1,
454 bgpvpn2 = os_utils.create_bgpvpn(neutron_client, **kwargs)
455 bgpvpn2_id = bgpvpn2['bgpvpn']['id']
456 logger.debug("VPN created details: %s" % bgpvpn2)
458 msg = ("Associate network '%s' to the VPN2." % NET_2_NAME)
460 add_to_summary(1, msg)
461 add_to_summary(0, "-")
463 os_utils.create_network_association(
464 neutron_client, bgpvpn2_id, network_2_id)
466 # Wait a bit for this to take effect
469 # 10.10.11.13 should return sdnvpn-5 to sdnvpn-4
471 vm_4, vm_4_ip, vm_5, vm_5_ip, expected=INSTANCE_5_NAME, timeout=30)
473 # 10.10.10.11 should return "not reachable" to sdnvpn-4
475 vm_4, vm_4_ip, vm_1, vm_1_ip, expected="not reachable", timeout=30)
477 add_to_summary(0, "=")
478 logger.info("\n%s" % SUMMARY)
480 if TEST_RESULT == "PASS":
481 logger.info("All the sub tests have passed as expected.")
483 logger.info("One or more sub tests have failed.")
486 success = 100 - (100 * int(NUM_TESTS_FAILED) / int(NUM_TESTS))
487 if success < int(SUCCESS_CRITERIA):
490 return {"status": status, "details": DETAILS}
493 if __name__ == '__main__':