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