d31541d1370a50b25f4f8dc27362f25fbfb17684
[functest.git] / testcases / features / sfc / sfc_colorado1.py
1 import os
2 import subprocess
3 import sys
4 import time
5 import argparse
6 import paramiko
7
8 import functest.utils.functest_logger as ft_logger
9 import functest.utils.functest_utils as ft_utils
10 import functest.utils.openstack_utils as os_utils
11 import SSHUtils as ssh_utils
12 import ovs_utils
13
14 parser = argparse.ArgumentParser()
15
16 parser.add_argument("-r", "--report",
17                     help="Create json result file",
18                     action="store_true")
19
20 args = parser.parse_args()
21
22 """ logging configuration """
23 logger = ft_logger.Logger("ODL_SFC").getLogger()
24
25 FUNCTEST_RESULTS_DIR = '/home/opnfv/functest/results/odl-sfc'
26 FUNCTEST_REPO = ft_utils.FUNCTEST_REPO
27
28 HOME = os.environ['HOME'] + "/"
29
30 VM_BOOT_TIMEOUT = 180
31 INSTANCE_NAME = "client"
32 FLAVOR = "custom"
33 IMAGE_NAME = "sf_nsh_colorado"
34 IMAGE_FILENAME = "sf_nsh_colorado.qcow2"
35 IMAGE_FORMAT = "qcow2"
36 IMAGE_PATH = "/home/opnfv/functest/data" + "/" + IMAGE_FILENAME
37
38 # NEUTRON Private Network parameters
39
40 NET_NAME = "example-net"
41 SUBNET_NAME = "example-subnet"
42 SUBNET_CIDR = "11.0.0.0/24"
43 ROUTER_NAME = "example-router"
44
45 SECGROUP_NAME = "example-sg"
46 SECGROUP_DESCR = "Example Security group"
47
48 INSTANCE_NAME_2 = "server"
49
50 # TEST_DB = ft_utils.get_parameter_from_yaml("results.test_db_url")
51
52 PRE_SETUP_SCRIPT = 'sfc_pre_setup.bash'
53 TACKER_SCRIPT = 'sfc_tacker.bash'
54 TEARDOWN_SCRIPT = "sfc_teardown.bash"
55 TACKER_CHANGECLASSI = "sfc_change_classi.bash"
56
57 ssh_options = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
58
59 PROXY = {
60     'ip': '10.20.0.2',
61     'username': 'root',
62     'password': 'r00tme'
63 }
64
65
66 def check_ssh(ip):
67     cmd = "sshpass -p opnfv ssh " + ssh_options + " -q " + ip + " exit"
68     success = subprocess.call(cmd, shell=True) == 0
69     if not success:
70         logger.debug("Wating for SSH connectivity in SF with IP: %s" % ip)
71     return success
72
73
74 def main():
75
76     # Allow any port so that tacker commands reaches the server.
77     # This will be deleted when tacker is included in OPNFV installation
78
79     status = "PASS"
80     failures = 0
81     start_time = time.time()
82     json_results = {}
83
84     contr_cmd = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
85                  " 'fuel node'|grep controller|awk '{print $10}'")
86     logger.info("Executing script to get ip_server: '%s'" % contr_cmd)
87     process = subprocess.Popen(contr_cmd,
88                                shell=True,
89                                stdout=subprocess.PIPE,
90                                stderr=subprocess.PIPE)
91     ip_server = process.stdout.readline().rstrip()
92
93     comp_cmd = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
94                 " 'fuel node'|grep compute|awk '{print $10}'")
95     logger.info("Executing script to get compute IPs: '%s'" % comp_cmd)
96     process = subprocess.Popen(comp_cmd,
97                                shell=True,
98                                stdout=subprocess.PIPE,
99                                stderr=subprocess.PIPE)
100     ip_computes = [ip.strip() for ip in process.stdout.readlines()]
101
102     iptable_cmd1 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
103                     " ssh " + ip_server + " iptables -P INPUT ACCEPT ")
104     iptable_cmd2 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
105                     " ssh " + ip_server + " iptables -t nat -P INPUT ACCEPT ")
106     iptable_cmd3 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
107                     " ssh " + ssh_options + " " + ip_server +
108                     " iptables -A INPUT -m state"
109                     " --state NEW,ESTABLISHED,RELATED -j ACCEPT")
110
111     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd1)
112     subprocess.call(iptable_cmd1, shell=True, stderr=subprocess.PIPE)
113
114     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd2)
115     subprocess.call(iptable_cmd2, shell=True, stderr=subprocess.PIPE)
116
117     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd3)
118     subprocess.call(iptable_cmd2, shell=True, stderr=subprocess.PIPE)
119
120 # Getting the different clients
121
122     nova_client = os_utils.get_nova_client()
123     neutron_client = os_utils.get_neutron_client()
124     glance_client = os_utils.get_glance_client()
125
126     ovs_logger = ovs_utils.OVSLogger(
127         os.path.join(os.getcwd(), 'ovs-logs'),
128         FUNCTEST_RESULTS_DIR)
129
130     controller_clients = [ssh_utils.get_ssh_client(ip_server,
131                                                    'root',
132                                                    proxy=PROXY)]
133     compute_clients = []
134     for c_ip in ip_computes:
135         c_client = ssh_utils.get_ssh_client(c_ip,
136                                             'root',
137                                             proxy=PROXY)
138         compute_clients.append(c_client)
139
140 # Download the image
141
142     if not os.path.isfile(IMAGE_PATH):
143         logger.info("Downloading image")
144         ft_utils.download_url(
145             "http://artifacts.opnfv.org/sfc/demo/sf_nsh_colorado.qcow2",
146             "/home/opnfv/functest/data/")
147     else:
148         logger.info("Using old image")
149
150 # Create glance image and the neutron network
151
152     image_id = os_utils.create_glance_image(glance_client,
153                                             IMAGE_NAME,
154                                             IMAGE_PATH,
155                                             disk=IMAGE_FORMAT,
156                                             container="bare",
157                                             public=True)
158
159     network_dic = os_utils.create_network_full(neutron_client,
160                                                NET_NAME,
161                                                SUBNET_NAME,
162                                                ROUTER_NAME,
163                                                SUBNET_CIDR)
164     if not network_dic:
165         logger.error(
166             "There has been a problem when creating the neutron network")
167         sys.exit(-1)
168
169     network_id = network_dic["net_id"]
170
171     sg_id = os_utils.create_security_group_full(neutron_client,
172                                                 SECGROUP_NAME, SECGROUP_DESCR)
173
174     secgroups = os_utils.get_security_groups(neutron_client)
175
176     for sg in secgroups:
177         os_utils.create_secgroup_rule(neutron_client, sg['id'],
178                                       'ingress', 'udp',
179                                       port_range_min=67,
180                                       port_range_max=68)
181         os_utils.create_secgroup_rule(neutron_client, sg['id'],
182                                       'egress', 'udp',
183                                       port_range_min=67,
184                                       port_range_max=68)
185         os_utils.create_secgroup_rule(neutron_client, sg['id'],
186                                       'ingress', 'tcp',
187                                       port_range_min=22,
188                                       port_range_max=22)
189         os_utils.create_secgroup_rule(neutron_client, sg['id'],
190                                       'egress', 'tcp',
191                                       port_range_min=22,
192                                       port_range_max=22)
193         os_utils.create_secgroup_rule(neutron_client, sg['id'],
194                                       'ingress', 'tcp',
195                                       port_range_min=80,
196                                       port_range_max=80)
197         os_utils.create_secgroup_rule(neutron_client, sg['id'],
198                                       'egress', 'tcp',
199                                       port_range_min=80,
200                                       port_range_max=80)
201
202     _, custom_flv_id = os_utils.get_or_create_flavor(
203         'custom', 1500, 10, 1, public=True)
204     if not custom_flv_id:
205         logger.error("Failed to create custom flavor")
206         sys.exit(1)
207
208     iterator = 0
209     while(iterator < 6):
210         # boot INSTANCE
211         logger.info("Creating instance '%s'..." % INSTANCE_NAME)
212         logger.debug(
213             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
214             "network=%s \n" % (INSTANCE_NAME, FLAVOR, image_id, network_id))
215         instance = os_utils.create_instance_and_wait_for_active(
216             FLAVOR,
217             image_id,
218             network_id,
219             INSTANCE_NAME,
220             av_zone='nova')
221
222         if instance is None:
223             logger.error("Error while booting instance.")
224             iterator += 1
225             continue
226         # Retrieve IP of INSTANCE
227         instance_ip = instance.networks.get(NET_NAME)[0]
228         logger.debug("Instance '%s' got private ip '%s'." %
229                      (INSTANCE_NAME, instance_ip))
230
231         logger.info("Adding '%s' to security group '%s'..."
232                     % (INSTANCE_NAME, SECGROUP_NAME))
233         os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
234
235         logger.info("Creating floating IP for VM '%s'..." % INSTANCE_NAME)
236         floatip_dic = os_utils.create_floating_ip(neutron_client)
237         floatip_client = floatip_dic['fip_addr']
238         # floatip_id = floatip_dic['fip_id']
239
240         if floatip_client is None:
241             logger.error("Cannot create floating IP.")
242             iterator += 1
243             continue
244         logger.info("Floating IP created: '%s'" % floatip_client)
245
246         logger.info("Associating floating ip: '%s' to VM '%s' "
247                     % (floatip_client, INSTANCE_NAME))
248         if not os_utils.add_floating_ip(nova_client,
249                                         instance.id,
250                                         floatip_client):
251             logger.error("Cannot associate floating IP to VM.")
252             iterator += 1
253             continue
254
255     # STARTING SECOND VM (server) ###
256
257         # boot INTANCE
258         logger.info("Creating instance '%s'..." % INSTANCE_NAME_2)
259         logger.debug(
260             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
261             "network=%s \n" % (INSTANCE_NAME_2, FLAVOR, image_id, network_id))
262         instance_2 = os_utils.create_instance_and_wait_for_active(
263             FLAVOR,
264             image_id,
265             network_id,
266             INSTANCE_NAME_2,
267             av_zone='nova')
268
269         if instance_2 is None:
270             logger.error("Error while booting instance.")
271             iterator += 1
272             continue
273         # Retrieve IP of INSTANCE
274         instance_ip_2 = instance_2.networks.get(NET_NAME)[0]
275         logger.debug("Instance '%s' got private ip '%s'." %
276                      (INSTANCE_NAME_2, instance_ip_2))
277
278         logger.info("Adding '%s' to security group '%s'..."
279                     % (INSTANCE_NAME_2, SECGROUP_NAME))
280         os_utils.add_secgroup_to_instance(nova_client, instance_2.id, sg_id)
281
282         logger.info("Creating floating IP for VM '%s'..." % INSTANCE_NAME_2)
283         floatip_dic = os_utils.create_floating_ip(neutron_client)
284         floatip_server = floatip_dic['fip_addr']
285         # floatip_id = floatip_dic['fip_id']
286
287         if floatip_server is None:
288             logger.error("Cannot create floating IP.")
289             iterator += 1
290             continue
291         logger.info("Floating IP created: '%s'" % floatip_server)
292
293         logger.info("Associating floating ip: '%s' to VM '%s' "
294                     % (floatip_server, INSTANCE_NAME_2))
295
296         if not os_utils.add_floating_ip(nova_client,
297                                         instance_2.id,
298                                         floatip_server):
299             logger.error("Cannot associate floating IP to VM.")
300             iterator += 1
301             continue
302
303         # CREATION OF THE 2 SF ####
304
305         tacker_script = "%s/testcases/features/sfc/%s" % \
306                         (FUNCTEST_REPO, TACKER_SCRIPT)
307         logger.info("Executing tacker script: '%s'" % tacker_script)
308         subprocess.call(tacker_script, shell=True)
309
310         # SSH CALL TO START HTTP SERVER
311         ssh = paramiko.SSHClient()
312         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
313
314         try:
315             ssh.connect(floatip_server, username="root",
316                         password="opnfv", timeout=2)
317             command = "python -m SimpleHTTPServer 80 > /dev/null 2>&1 &"
318             logger.info("Starting HTTP server")
319             (stdin, stdout, stderr) = ssh.exec_command(command)
320         except:
321             logger.debug("Waiting for %s..." % floatip_server)
322             time.sleep(6)
323             # timeout -= 1
324
325         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
326         ips = []
327         try:
328             for instance in instances:
329                 if "server" not in instance.name:
330                     if "client" not in instance.name:
331                         logger.debug(
332                             "This is the instance name: %s " % instance.name)
333                         floatip_dic = os_utils.create_floating_ip(
334                             neutron_client)
335                         floatip = floatip_dic['fip_addr']
336                         ips.append(floatip)
337                         instance.add_floating_ip(floatip)
338         except:
339             logger.debug("Problems assigning floating IP to SFs")
340
341         # If no IPs were obtained, then we cant continue
342         if not ips:
343             logger.error('Failed to obtain IPs, cant continue, exiting')
344             return
345
346         logger.debug("Floating IPs for SFs: %s..." % ips)
347
348         # Check SSH connectivity to VNFs
349         r = 0
350         retries = 100
351         check = [False, False]
352
353         logger.info("Checking SSH connectivity to the SFs with ips {0}"
354                     .format(str(ips)))
355         while r < retries and not all(check):
356             try:
357                 check = [check_ssh(ips[0]), check_ssh(ips[1])]
358             except Exception:
359                 logger.exception("SSH check failed")
360                 check = [False, False]
361             time.sleep(3)
362             r += 1
363
364         if not all(check):
365             logger.error("Cannot establish SSH connection to the SFs")
366             iterator += 1
367             continue
368
369         logger.info("SSH connectivity to the SFs established")
370
371         # SSH TO START THE VXLAN_TOOL ON SF1
372         logger.info("Configuring the SFs")
373         try:
374             ssh.connect(ips[0], username="root",
375                         password="opnfv", timeout=2)
376             command = ("nohup python vxlan_tool.py -i eth0 "
377                        "-d forward -v off -b 80 > /dev/null 2>&1 &")
378             (stdin, stdout, stderr) = ssh.exec_command(command)
379         except:
380             logger.debug("Waiting for %s..." % ips[0])
381             time.sleep(6)
382             # timeout -= 1
383
384         try:
385             n = 0
386             while 1:
387                 (stdin, stdout, stderr) = ssh.exec_command(
388                     "ps aux | grep \"vxlan_tool.py\" | grep -v grep")
389                 if len(stdout.readlines()) > 0:
390                     logger.debug("HTTP firewall started")
391                     break
392                 else:
393                     n += 1
394                     if (n > 7):
395                         break
396                     logger.debug("HTTP firewall not started")
397                     time.sleep(3)
398         except Exception:
399             logger.exception("vxlan_tool not started in SF1")
400
401         # SSH TO START THE VXLAN_TOOL ON SF2
402         try:
403             ssh.connect(ips[1], username="root",
404                         password="opnfv", timeout=2)
405             command = ("nohup python vxlan_tool.py -i eth0 "
406                        "-d forward -v off -b 22 > /dev/null 2>&1 &")
407             (stdin, stdout, stderr) = ssh.exec_command(command)
408         except:
409             logger.debug("Waiting for %s..." % ips[1])
410             time.sleep(6)
411             # timeout -= 1
412
413         try:
414             n = 0
415             while 1:
416                 (stdin, stdout, stderr) = ssh.exec_command(
417                     "ps aux | grep \"vxlan_tool.py\" | grep -v grep")
418                 if len(stdout.readlines()) > 0:
419                     logger.debug("SSH firewall started")
420                     break
421                 else:
422                     n += 1
423                     if (n > 7):
424                         break
425                     logger.debug("SSH firewall not started")
426                     time.sleep(3)
427         except Exception:
428             logger.exception("vxlan_tool not started in SF2")
429
430         i = 0
431
432         # SSH TO EXECUTE cmd_client
433         logger.info("TEST STARTED")
434         time.sleep(70)
435         try:
436             ssh.connect(floatip_client, username="root",
437                         password="opnfv", timeout=2)
438             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
439             (stdin, stdout, stderr) = ssh.exec_command(command)
440
441             # WRITE THE CORRECT WAY TO DO LOGGING
442             if "timed out" in stdout.readlines()[0]:
443                 logger.info('\033[92m' + "TEST 1 [PASSED] "
444                             "==> SSH BLOCKED" + '\033[0m')
445                 i = i + 1
446                 json_results.update({"Test 1: SSH Blocked": "Passed"})
447             else:
448                 timestamp = time.strftime("%Y%m%d-%H%M%S")
449                 error = ('\033[91m' + "TEST 1 [FAILED] "
450                          "==> SSH NOT BLOCKED" + '\033[0m')
451                 logger.error(error)
452                 ovs_logger.dump_ovs_logs(controller_clients,
453                                          compute_clients,
454                                          related_error=error,
455                                          timestamp=timestamp)
456                 status = "FAIL"
457                 json_results.update({"Test 1: SSH Blocked": "Failed"})
458                 failures += 1
459         except:
460             logger.debug("Waiting for %s..." % floatip_client)
461             time.sleep(6)
462             # timeout -= 1
463
464         # SSH TO EXECUTE cmd_client
465         try:
466             ssh.connect(floatip_client, username="root",
467                         password="opnfv", timeout=2)
468             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
469             (stdin, stdout, stderr) = ssh.exec_command(command)
470
471             if "succeeded" in stdout.readlines()[0]:
472                 logger.info('\033[92m' + "TEST 2 [PASSED] "
473                             "==> HTTP WORKS" + '\033[0m')
474                 i = i + 1
475                 json_results.update({"Test 2: HTTP works": "Passed"})
476             else:
477                 timestamp = time.strftime("%Y%m%d-%H%M%S")
478                 error = ('\033[91m' + "TEST 2 [FAILED] "
479                          "==> HTTP BLOCKED" + '\033[0m')
480                 logger.error(error)
481                 ovs_logger.dump_ovs_logs(controller_clients,
482                                          compute_clients,
483                                          related_error=error,
484                                          timestamp=timestamp)
485                 status = "FAIL"
486                 json_results.update({"Test 2: HTTP works": "Failed"})
487                 failures += 1
488         except:
489             logger.debug("Waiting for %s..." % floatip_client)
490             time.sleep(6)
491             # timeout -= 1
492
493         # CHANGE OF CLASSIFICATION #
494         logger.info("Changing the classification")
495         tacker_classi = "%s/testcases/features/sfc/%s" % \
496                         (FUNCTEST_REPO, TACKER_CHANGECLASSI)
497         subprocess.call(tacker_classi, shell=True)
498
499         logger.info("Wait for ODL to update the classification rules in OVS")
500         time.sleep(100)
501
502         # SSH TO EXECUTE cmd_client
503
504         try:
505             ssh.connect(floatip_client, username="root",
506                         password="opnfv", timeout=2)
507             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
508             (stdin, stdout, stderr) = ssh.exec_command(command)
509
510             if "timed out" in stdout.readlines()[0]:
511                 logger.info('\033[92m' + "TEST 3 [PASSED] "
512                             "==> HTTP BLOCKED" + '\033[0m')
513                 i = i + 1
514                 json_results.update({"Test 3: HTTP Blocked": "Passed"})
515             else:
516                 timestamp = time.strftime("%Y%m%d-%H%M%S")
517                 error = ('\033[91m' + "TEST 3 [FAILED] "
518                          "==> HTTP NOT BLOCKED" + '\033[0m')
519                 logger.error(error)
520                 ovs_logger.dump_ovs_logs(controller_clients,
521                                          compute_clients,
522                                          related_error=error,
523                                          timestamp=timestamp)
524                 status = "FAIL"
525                 json_results.update({"Test 3: HTTP Blocked": "Failed"})
526                 failures += 1
527         except:
528             logger.debug("Waiting for %s..." % floatip_client)
529             time.sleep(6)
530             # timeout -= 1
531
532         # SSH TO EXECUTE cmd_client
533         try:
534             ssh.connect(floatip_client, username="root",
535                         password="opnfv", timeout=2)
536             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
537             (stdin, stdout, stderr) = ssh.exec_command(command)
538
539             if "succeeded" in stdout.readlines()[0]:
540                 logger.info('\033[92m' + "TEST 4 [PASSED] "
541                             "==> SSH WORKS" + '\033[0m')
542                 i = i + 1
543                 json_results.update({"Test 4: SSH works": "Passed"})
544             else:
545                 timestamp = time.strftime("%Y%m%d-%H%M%S")
546                 error = ('\033[91m' + "TEST 4 [FAILED] "
547                          "==> SSH BLOCKED" + '\033[0m')
548                 logger.error(error)
549                 ovs_logger.dump_ovs_logs(controller_clients,
550                                          compute_clients,
551                                          related_error=error,
552                                          timestamp=timestamp)
553                 status = "FAIL"
554                 json_results.update({"Test 4: SSH works": "Failed"})
555                 failures += 1
556         except:
557             logger.debug("Waiting for %s..." % floatip_client)
558             time.sleep(6)
559             # timeout -= 1
560
561         ovs_logger.create_artifact_archive()
562
563         iterator += 1
564         if i == 4:
565             for x in range(0, 5):
566                 logger.info('\033[92m' + "SFC TEST WORKED"
567                             " :) \n" + '\033[0m')
568             break
569         else:
570             logger.info("Iterating again!")
571             delete = "bash %s/testcases/features/sfc/delete.sh" % \
572                      (FUNCTEST_REPO)
573             try:
574                 subprocess.call(delete, shell=True, stderr=subprocess.PIPE)
575                 time.sleep(10)
576             except Exception, e:
577                 logger.error("Problem when executing the delete.sh")
578                 logger.error("Problem %s" % e)
579
580     if args.report:
581         stop_time = time.time()
582         json_results.update({"tests": "4", "failures": int(failures)})
583         logger.debug("Promise Results json: " + str(json_results))
584         ft_utils.push_results_to_db("sfc",
585                                     "functest-odl-sfc",
586                                     start_time,
587                                     stop_time,
588                                     status,
589                                     json_results)
590     if status == "PASS":
591         sys.exit(0)
592     else:
593         sys.exit(1)
594
595 if __name__ == '__main__':
596     main()