Merge "SFC test: Add port 80 to security groups"
[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 = "m1.small"
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     iterator = 0
172     while(iterator < 6):
173         # boot INSTANCE
174         logger.info("Creating instance '%s'..." % INSTANCE_NAME)
175         logger.debug(
176             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
177             "network=%s \n" % (INSTANCE_NAME, FLAVOR, image_id, network_id))
178         instance = os_utils.create_instance_and_wait_for_active(FLAVOR,
179                                                                 image_id,
180                                                                 network_id,
181                                                                 INSTANCE_NAME)
182
183         if instance is None:
184             logger.error("Error while booting instance.")
185             iterator += 1
186             continue
187         # Retrieve IP of INSTANCE
188         instance_ip = instance.networks.get(NET_NAME)[0]
189         logger.debug("Instance '%s' got private ip '%s'." %
190                      (INSTANCE_NAME, instance_ip))
191
192         logger.info("Adding '%s' to security group '%s'..."
193                     % (INSTANCE_NAME, SECGROUP_NAME))
194         os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
195
196         logger.info("Creating floating IP for VM '%s'..." % INSTANCE_NAME)
197         floatip_dic = os_utils.create_floating_ip(neutron_client)
198         floatip_client = floatip_dic['fip_addr']
199         # floatip_id = floatip_dic['fip_id']
200
201         if floatip_client is None:
202             logger.error("Cannot create floating IP.")
203             iterator += 1
204             continue
205         logger.info("Floating IP created: '%s'" % floatip_client)
206
207         logger.info("Associating floating ip: '%s' to VM '%s' "
208                     % (floatip_client, INSTANCE_NAME))
209         if not os_utils.add_floating_ip(nova_client,
210                                         instance.id,
211                                         floatip_client):
212             logger.error("Cannot associate floating IP to VM.")
213             iterator += 1
214             continue
215
216     # STARTING SECOND VM (server) ###
217
218         # boot INTANCE
219         logger.info("Creating instance '%s'..." % INSTANCE_NAME)
220         logger.debug(
221             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
222             "network=%s \n" % (INSTANCE_NAME, FLAVOR, image_id, network_id))
223         instance_2 = os_utils.create_instance_and_wait_for_active(
224             FLAVOR,
225             image_id,
226             network_id,
227             INSTANCE_NAME_2)
228
229         if instance_2 is None:
230             logger.error("Error while booting instance.")
231             iterator += 1
232             continue
233         # Retrieve IP of INSTANCE
234         instance_ip_2 = instance_2.networks.get(NET_NAME)[0]
235         logger.debug("Instance '%s' got private ip '%s'." %
236                      (INSTANCE_NAME_2, instance_ip_2))
237
238         logger.info("Adding '%s' to security group '%s'..."
239                     % (INSTANCE_NAME_2, SECGROUP_NAME))
240         os_utils.add_secgroup_to_instance(nova_client, instance_2.id, sg_id)
241
242         logger.info("Creating floating IP for VM '%s'..." % INSTANCE_NAME_2)
243         floatip_dic = os_utils.create_floating_ip(neutron_client)
244         floatip_server = floatip_dic['fip_addr']
245         # floatip_id = floatip_dic['fip_id']
246
247         if floatip_server is None:
248             logger.error("Cannot create floating IP.")
249             iterator += 1
250             continue
251         logger.info("Floating IP created: '%s'" % floatip_server)
252
253         logger.info("Associating floating ip: '%s' to VM '%s' "
254                     % (floatip_server, INSTANCE_NAME_2))
255
256         if not os_utils.add_floating_ip(nova_client,
257                                         instance_2.id,
258                                         floatip_server):
259             logger.error("Cannot associate floating IP to VM.")
260             iterator += 1
261             continue
262
263         # CREATION OF THE 2 SF ####
264
265         tacker_script = "%s/testcases/features/sfc/%s" % \
266                         (FUNCTEST_REPO, TACKER_SCRIPT)
267         logger.info("Executing tacker script: '%s'" % tacker_script)
268         subprocess.call(tacker_script, shell=True)
269
270         # SSH CALL TO START HTTP SERVER
271         ssh = paramiko.SSHClient()
272         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
273
274         try:
275             ssh.connect(floatip_server, username="root",
276                         password="opnfv", timeout=2)
277             command = "python -m SimpleHTTPServer 80 > /dev/null 2>&1 &"
278             logger.info("Starting HTTP server")
279             (stdin, stdout, stderr) = ssh.exec_command(command)
280         except:
281             logger.debug("Waiting for %s..." % floatip_server)
282             time.sleep(6)
283             # timeout -= 1
284
285         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
286         ips = []
287         try:
288             for instance in instances:
289                 if "server" not in instance.name:
290                     if "client" not in instance.name:
291                         logger.debug(
292                             "This is the instance name: %s " % instance.name)
293                         floatip_dic = os_utils.create_floating_ip(
294                             neutron_client)
295                         floatip = floatip_dic['fip_addr']
296                         ips.append(floatip)
297                         instance.add_floating_ip(floatip)
298         except:
299             logger.debug("Problems assigning floating IP to SFs")
300
301         # If no IPs were obtained, then we cant continue
302         if not ips:
303             logger.error('Failed to obtain IPs, cant continue, exiting')
304             return
305
306         logger.debug("Floating IPs for SFs: %s..." % ips)
307
308         # Check SSH connectivity to VNFs
309         r = 0
310         retries = 100
311         check = [False, False]
312
313         logger.info("Checking SSH connectivity to the SFs with ips {0}"
314                     .format(str(ips)))
315         while r < retries and not all(check):
316             try:
317                 check = [check_ssh(ips[0]), check_ssh(ips[1])]
318             except Exception:
319                 logger.exception("SSH check failed")
320                 check = [False, False]
321             time.sleep(3)
322             r += 1
323
324         if not all(check):
325             logger.error("Cannot establish SSH connection to the SFs")
326             iterator += 1
327             continue
328
329         logger.info("SSH connectivity to the SFs established")
330
331         # SSH TO START THE VXLAN_TOOL ON SF1
332         logger.info("Configuring the SFs")
333         try:
334             ssh.connect(ips[0], username="root",
335                         password="opnfv", timeout=2)
336             command = ("nohup python vxlan_tool.py -i eth0 "
337                        "-d forward -v off -b 80 > /dev/null 2>&1 &")
338             (stdin, stdout, stderr) = ssh.exec_command(command)
339         except:
340             logger.debug("Waiting for %s..." % ips[0])
341             time.sleep(6)
342             # timeout -= 1
343
344         try:
345             n = 0
346             while 1:
347                 (stdin, stdout, stderr) = ssh.exec_command(
348                     "ps aux | grep \"vxlan_tool.py\" | grep -v grep")
349                 if len(stdout.readlines()) > 0:
350                     logger.debug("HTTP firewall started")
351                     break
352                 else:
353                     n += 1
354                     if (n > 7):
355                         break
356                     logger.debug("HTTP firewall not started")
357                     time.sleep(3)
358         except Exception:
359             logger.exception("vxlan_tool not started in SF1")
360
361         # SSH TO START THE VXLAN_TOOL ON SF2
362         try:
363             ssh.connect(ips[1], username="root",
364                         password="opnfv", timeout=2)
365             command = ("nohup python vxlan_tool.py -i eth0 "
366                        "-d forward -v off -b 22 > /dev/null 2>&1 &")
367             (stdin, stdout, stderr) = ssh.exec_command(command)
368         except:
369             logger.debug("Waiting for %s..." % ips[1])
370             time.sleep(6)
371             # timeout -= 1
372
373         try:
374             n = 0
375             while 1:
376                 (stdin, stdout, stderr) = ssh.exec_command(
377                     "ps aux | grep \"vxlan_tool.py\" | grep -v grep")
378                 if len(stdout.readlines()) > 0:
379                     logger.debug("SSH firewall started")
380                     break
381                 else:
382                     n += 1
383                     if (n > 7):
384                         break
385                     logger.debug("SSH firewall not started")
386                     time.sleep(3)
387         except Exception:
388             logger.exception("vxlan_tool not started in SF2")
389
390         # SSH to modify the classification flows in compute
391
392         contr_cmd3 = ("sshpass -p r00tme ssh " + ssh_options + " "
393                       "root@10.20.0.2 'ssh " + ip_compute + " "
394                       "'bash correct_classifier.bash''")
395         logger.info("Executing script to modify the classi: '%s'" % contr_cmd3)
396         process = subprocess.Popen(contr_cmd3,
397                                    shell=True,
398                                    stdout=subprocess.PIPE)
399
400         i = 0
401
402         # SSH TO EXECUTE cmd_client
403         logger.info("TEST STARTED")
404         try:
405             ssh.connect(floatip_client, username="root",
406                         password="opnfv", timeout=2)
407             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
408             (stdin, stdout, stderr) = ssh.exec_command(command)
409
410             # WRITE THE CORRECT WAY TO DO LOGGING
411             if "timed out" in stdout.readlines()[0]:
412                 logger.info('\033[92m' + "TEST 1 [PASSED] "
413                             "==> SSH BLOCKED" + '\033[0m')
414                 i = i + 1
415                 json_results.update({"Test 1: SSH Blocked": "Passed"})
416             else:
417                 logger.error('\033[91m' + "TEST 1 [FAILED] "
418                              "==> SSH NOT BLOCKED" + '\033[0m')
419                 status = "FAIL"
420                 json_results.update({"Test 1: SSH Blocked": "Failed"})
421                 failures += 1
422         except:
423             logger.debug("Waiting for %s..." % floatip_client)
424             time.sleep(6)
425             # timeout -= 1
426
427         # SSH TO EXECUTE cmd_client
428         try:
429             ssh.connect(floatip_client, username="root",
430                         password="opnfv", timeout=2)
431             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
432             (stdin, stdout, stderr) = ssh.exec_command(command)
433
434             if "succeeded" in stdout.readlines()[0]:
435                 logger.info('\033[92m' + "TEST 2 [PASSED] "
436                             "==> HTTP WORKS" + '\033[0m')
437                 i = i + 1
438                 json_results.update({"Test 2: HTTP works": "Passed"})
439             else:
440                 logger.error('\033[91m' + "TEST 2 [FAILED] "
441                              "==> HTTP BLOCKED" + '\033[0m')
442                 status = "FAIL"
443                 json_results.update({"Test 2: HTTP works": "Failed"})
444                 failures += 1
445         except:
446             logger.debug("Waiting for %s..." % floatip_client)
447             time.sleep(6)
448             # timeout -= 1
449
450         # CHANGE OF CLASSIFICATION #
451         logger.info("Changing the classification")
452         tacker_classi = "%s/testcases/features/sfc/%s" % \
453                         (FUNCTEST_REPO, TACKER_CHANGECLASSI)
454         subprocess.call(tacker_classi, shell=True)
455
456         logger.info("Wait for ODL to update the classification rules in OVS")
457         time.sleep(10)
458
459         # SSH to modify the classification flows in compute
460
461         contr_cmd4 = ("sshpass -p r00tme ssh " + ssh_options + " "
462                       "root@10.20.0.2 'ssh " + ip_compute + " "
463                       "'bash correct_classifier.bash''")
464         logger.info("Executing script to modify the classi: '%s'" % contr_cmd4)
465         process = subprocess.Popen(contr_cmd4,
466                                    shell=True,
467                                    stdout=subprocess.PIPE)
468
469         # SSH TO EXECUTE cmd_client
470
471         try:
472             ssh.connect(floatip_client, username="root",
473                         password="opnfv", timeout=2)
474             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
475             (stdin, stdout, stderr) = ssh.exec_command(command)
476
477             if "timed out" in stdout.readlines()[0]:
478                 logger.info('\033[92m' + "TEST 3 [PASSED] "
479                             "==> HTTP BLOCKED" + '\033[0m')
480                 i = i + 1
481                 json_results.update({"Test 3: HTTP Blocked": "Passed"})
482             else:
483                 logger.error('\033[91m' + "TEST 3 [FAILED] "
484                              "==> HTTP NOT BLOCKED" + '\033[0m')
485                 status = "FAIL"
486                 json_results.update({"Test 3: HTTP Blocked": "Failed"})
487                 failures += 1
488         except:
489             logger.debug("Waiting for %s..." % floatip_client)
490             time.sleep(6)
491             # timeout -= 1
492
493         # SSH TO EXECUTE cmd_client
494         try:
495             ssh.connect(floatip_client, username="root",
496                         password="opnfv", timeout=2)
497             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
498             (stdin, stdout, stderr) = ssh.exec_command(command)
499
500             if "succeeded" in stdout.readlines()[0]:
501                 logger.info('\033[92m' + "TEST 4 [PASSED] "
502                             "==> SSH WORKS" + '\033[0m')
503                 i = i + 1
504                 json_results.update({"Test 4: SSH works": "Passed"})
505             else:
506                 logger.error('\033[91m' + "TEST 4 [FAILED] "
507                              "==> SSH BLOCKED" + '\033[0m')
508                 status = "FAIL"
509                 json_results.update({"Test 4: SSH works": "Failed"})
510                 failures += 1
511         except:
512             logger.debug("Waiting for %s..." % floatip_client)
513             time.sleep(6)
514             # timeout -= 1
515
516         iterator += 1
517         if i == 4:
518             for x in range(0, 5):
519                 logger.info('\033[92m' + "SFC TEST WORKED"
520                             " :) \n" + '\033[0m')
521             break
522         else:
523             logger.debug("Iterating again!")
524             delete = ("bash delete.sh")
525             subprocess.call(delete, shell=True, stderr=subprocess.PIPE)
526             time.sleep(10)
527
528     if args.report:
529         stop_time = time.time()
530         json_results.update({"tests": "4", "failures": int(failures)})
531         logger.debug("Promise Results json: " + str(json_results))
532         ft_utils.push_results_to_db("sfc",
533                                     "functest-odl-sfc",
534                                     start_time,
535                                     stop_time,
536                                     status,
537                                     json_results)
538     if status == "PASS":
539         sys.exit(0)
540     else:
541         sys.exit(1)
542
543 if __name__ == '__main__':
544     main()