Merge "Add wrappers for Tacker Python client"
[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     iptable_cmd1 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
85                     " ssh " + ip_server + " iptables -P INPUT ACCEPT ")
86     iptable_cmd2 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
87                     " ssh " + ip_server + " iptables -t nat -P INPUT ACCEPT ")
88     iptable_cmd3 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
89                     " ssh " + ssh_options + " " + ip_server +
90                     " iptables -A INPUT -m state"
91                     " --state NEW,ESTABLISHED,RELATED -j ACCEPT")
92
93     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd1)
94     subprocess.call(iptable_cmd1, shell=True, stderr=subprocess.PIPE)
95
96     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd2)
97     subprocess.call(iptable_cmd2, shell=True, stderr=subprocess.PIPE)
98
99     logger.info("Changing firewall policy in controller: '%s'" % iptable_cmd3)
100     subprocess.call(iptable_cmd2, shell=True, stderr=subprocess.PIPE)
101
102 # Getting the different clients
103
104     nova_client = os_utils.get_nova_client()
105     neutron_client = os_utils.get_neutron_client()
106     glance_client = os_utils.get_glance_client()
107
108 # Download the image
109
110     if not os.path.isfile(IMAGE_PATH):
111         logger.info("Downloading image")
112         ft_utils.download_url(
113             "http://artifacts.opnfv.org/sfc/demo/sf_nsh_colorado.qcow2",
114             "/home/opnfv/functest/data/")
115     else:
116         logger.info("Using old image")
117
118 # Create glance image and the neutron network
119
120     image_id = os_utils.create_glance_image(glance_client,
121                                             IMAGE_NAME,
122                                             IMAGE_PATH,
123                                             disk=IMAGE_FORMAT,
124                                             container="bare",
125                                             public=True)
126
127     network_dic = os_utils.create_network_full(neutron_client,
128                                                NET_NAME,
129                                                SUBNET_NAME,
130                                                ROUTER_NAME,
131                                                SUBNET_CIDR)
132     if not network_dic:
133         logger.error(
134             "There has been a problem when creating the neutron network")
135         sys.exit(-1)
136
137     network_id = network_dic["net_id"]
138
139     sg_id = os_utils.create_security_group_full(neutron_client,
140                                                 SECGROUP_NAME, SECGROUP_DESCR)
141
142     secgroups = os_utils.get_security_groups(neutron_client)
143
144     for sg in secgroups:
145         os_utils.create_secgroup_rule(neutron_client, sg['id'],
146                                       'ingress', 'tcp',
147                                       port_range_min=22,
148                                       port_range_max=22)
149         os_utils.create_secgroup_rule(neutron_client, sg['id'],
150                                       'egress', 'tcp',
151                                       port_range_min=22,
152                                       port_range_max=22)
153         os_utils.create_secgroup_rule(neutron_client, sg['id'],
154                                       'ingress', 'tcp',
155                                       port_range_min=80,
156                                       port_range_max=80)
157         os_utils.create_secgroup_rule(neutron_client, sg['id'],
158                                       'egress', 'tcp',
159                                       port_range_min=80,
160                                       port_range_max=80)
161
162     _, custom_flv_id = os_utils.get_or_create_flavor(
163         'custom', 1500, 10, 1, public=True)
164     if not custom_flv_id:
165         logger.error("Failed to create custom flavor")
166         sys.exit(1)
167
168     iterator = 0
169     while(iterator < 6):
170         # boot INSTANCE
171         logger.info("Creating instance '%s'..." % INSTANCE_NAME)
172         logger.debug(
173             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
174             "network=%s \n" % (INSTANCE_NAME, FLAVOR, image_id, network_id))
175         instance = os_utils.create_instance_and_wait_for_active(
176             FLAVOR,
177             image_id,
178             network_id,
179             INSTANCE_NAME,
180             av_zone='nova')
181
182         if instance is None:
183             logger.error("Error while booting instance.")
184             iterator += 1
185             continue
186         # Retrieve IP of INSTANCE
187         instance_ip = instance.networks.get(NET_NAME)[0]
188         logger.debug("Instance '%s' got private ip '%s'." %
189                      (INSTANCE_NAME, instance_ip))
190
191         logger.info("Adding '%s' to security group '%s'..."
192                     % (INSTANCE_NAME, SECGROUP_NAME))
193         os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
194
195         logger.info("Creating floating IP for VM '%s'..." % INSTANCE_NAME)
196         floatip_dic = os_utils.create_floating_ip(neutron_client)
197         floatip_client = floatip_dic['fip_addr']
198         # floatip_id = floatip_dic['fip_id']
199
200         if floatip_client is None:
201             logger.error("Cannot create floating IP.")
202             iterator += 1
203             continue
204         logger.info("Floating IP created: '%s'" % floatip_client)
205
206         logger.info("Associating floating ip: '%s' to VM '%s' "
207                     % (floatip_client, INSTANCE_NAME))
208         if not os_utils.add_floating_ip(nova_client,
209                                         instance.id,
210                                         floatip_client):
211             logger.error("Cannot associate floating IP to VM.")
212             iterator += 1
213             continue
214
215     # STARTING SECOND VM (server) ###
216
217         # boot INTANCE
218         logger.info("Creating instance '%s'..." % INSTANCE_NAME)
219         logger.debug(
220             "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
221             "network=%s \n" % (INSTANCE_NAME_2, FLAVOR, image_id, network_id))
222         instance_2 = os_utils.create_instance_and_wait_for_active(
223             FLAVOR,
224             image_id,
225             network_id,
226             INSTANCE_NAME_2,
227             av_zone='nova')
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         i = 0
391
392         # SSH TO EXECUTE cmd_client
393         logger.info("TEST STARTED")
394         try:
395             ssh.connect(floatip_client, username="root",
396                         password="opnfv", timeout=2)
397             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
398             (stdin, stdout, stderr) = ssh.exec_command(command)
399
400             # WRITE THE CORRECT WAY TO DO LOGGING
401             if "timed out" in stdout.readlines()[0]:
402                 logger.info('\033[92m' + "TEST 1 [PASSED] "
403                             "==> SSH BLOCKED" + '\033[0m')
404                 i = i + 1
405                 json_results.update({"Test 1: SSH Blocked": "Passed"})
406             else:
407                 logger.error('\033[91m' + "TEST 1 [FAILED] "
408                              "==> SSH NOT BLOCKED" + '\033[0m')
409                 status = "FAIL"
410                 json_results.update({"Test 1: SSH Blocked": "Failed"})
411                 failures += 1
412         except:
413             logger.debug("Waiting for %s..." % floatip_client)
414             time.sleep(6)
415             # timeout -= 1
416
417         # SSH TO EXECUTE cmd_client
418         try:
419             ssh.connect(floatip_client, username="root",
420                         password="opnfv", timeout=2)
421             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
422             (stdin, stdout, stderr) = ssh.exec_command(command)
423
424             if "succeeded" in stdout.readlines()[0]:
425                 logger.info('\033[92m' + "TEST 2 [PASSED] "
426                             "==> HTTP WORKS" + '\033[0m')
427                 i = i + 1
428                 json_results.update({"Test 2: HTTP works": "Passed"})
429             else:
430                 logger.error('\033[91m' + "TEST 2 [FAILED] "
431                              "==> HTTP BLOCKED" + '\033[0m')
432                 status = "FAIL"
433                 json_results.update({"Test 2: HTTP works": "Failed"})
434                 failures += 1
435         except:
436             logger.debug("Waiting for %s..." % floatip_client)
437             time.sleep(6)
438             # timeout -= 1
439
440         # CHANGE OF CLASSIFICATION #
441         logger.info("Changing the classification")
442         tacker_classi = "%s/testcases/features/sfc/%s" % \
443                         (FUNCTEST_REPO, TACKER_CHANGECLASSI)
444         subprocess.call(tacker_classi, shell=True)
445
446         logger.info("Wait for ODL to update the classification rules in OVS")
447         time.sleep(100)
448
449         # SSH TO EXECUTE cmd_client
450
451         try:
452             ssh.connect(floatip_client, username="root",
453                         password="opnfv", timeout=2)
454             command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
455             (stdin, stdout, stderr) = ssh.exec_command(command)
456
457             if "timed out" in stdout.readlines()[0]:
458                 logger.info('\033[92m' + "TEST 3 [PASSED] "
459                             "==> HTTP BLOCKED" + '\033[0m')
460                 i = i + 1
461                 json_results.update({"Test 3: HTTP Blocked": "Passed"})
462             else:
463                 logger.error('\033[91m' + "TEST 3 [FAILED] "
464                              "==> HTTP NOT BLOCKED" + '\033[0m')
465                 status = "FAIL"
466                 json_results.update({"Test 3: HTTP Blocked": "Failed"})
467                 failures += 1
468         except:
469             logger.debug("Waiting for %s..." % floatip_client)
470             time.sleep(6)
471             # timeout -= 1
472
473         # SSH TO EXECUTE cmd_client
474         try:
475             ssh.connect(floatip_client, username="root",
476                         password="opnfv", timeout=2)
477             command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
478             (stdin, stdout, stderr) = ssh.exec_command(command)
479
480             if "succeeded" in stdout.readlines()[0]:
481                 logger.info('\033[92m' + "TEST 4 [PASSED] "
482                             "==> SSH WORKS" + '\033[0m')
483                 i = i + 1
484                 json_results.update({"Test 4: SSH works": "Passed"})
485             else:
486                 logger.error('\033[91m' + "TEST 4 [FAILED] "
487                              "==> SSH BLOCKED" + '\033[0m')
488                 status = "FAIL"
489                 json_results.update({"Test 4: SSH works": "Failed"})
490                 failures += 1
491         except:
492             logger.debug("Waiting for %s..." % floatip_client)
493             time.sleep(6)
494             # timeout -= 1
495
496         iterator += 1
497         if i == 4:
498             for x in range(0, 5):
499                 logger.info('\033[92m' + "SFC TEST WORKED"
500                             " :) \n" + '\033[0m')
501             break
502         else:
503             logger.debug("Iterating again!")
504             delete = ("bash delete.sh")
505             subprocess.call(delete, shell=True, stderr=subprocess.PIPE)
506             time.sleep(10)
507
508     if args.report:
509         stop_time = time.time()
510         json_results.update({"tests": "4", "failures": int(failures)})
511         logger.debug("Promise Results json: " + str(json_results))
512         ft_utils.push_results_to_db("sfc",
513                                     "functest-odl-sfc",
514                                     start_time,
515                                     stop_time,
516                                     status,
517                                     json_results)
518     if status == "PASS":
519         sys.exit(0)
520     else:
521         sys.exit(1)
522
523 if __name__ == '__main__':
524     main()