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