Merge "Config guide workflow simplification"
[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     logger.debug("Floating IPs for SFs: %s..." % ips)
242
243     # SSH TO START THE VXLAN_TOOL ON SF1
244     logger.info("Configuring the SFs")
245     try:
246         ssh.connect(ips[0], username="root",
247                     password="opnfv", timeout=2)
248         command = ("nohup python vxlan_tool.py -i eth0 "
249                    "-d forward -v off -b 80 > /dev/null 2>&1 &")
250         (stdin, stdout, stderr) = ssh.exec_command(command)
251     except:
252         logger.debug("Waiting for %s..." % ips[0])
253         time.sleep(6)
254         # timeout -= 1
255
256     try:
257         while 1:
258             (stdin, stdout, stderr) = ssh.exec_command("ps lax | grep python")
259             if "vxlan_tool.py" in stdout.readlines()[0]:
260                 logger.debug("HTTP firewall started")
261                 break
262             else:
263                 logger.debug("HTTP firewall not started")
264                 time.sleep(3)
265     except:
266         logger.error("vxlan_tool not started in SF1")
267
268     # SSH TO START THE VXLAN_TOOL ON SF2
269     try:
270         ssh.connect(ips[1], username="root",
271                     password="opnfv", timeout=2)
272         command = ("nohup python vxlan_tool.py -i eth0 "
273                    "-d forward -v off -b 22 > /dev/null 2>&1 &")
274         (stdin, stdout, stderr) = ssh.exec_command(command)
275     except:
276         logger.debug("Waiting for %s..." % ips[1])
277         time.sleep(6)
278         # timeout -= 1
279
280     try:
281         while 1:
282             (stdin, stdout, stderr) = ssh.exec_command("ps lax | grep python")
283             if "vxlan_tool.py" in stdout.readlines()[0]:
284                 logger.debug("SSH firewall started")
285                 break
286             else:
287                 logger.debug("SSH firewall not started")
288                 time.sleep(3)
289     except:
290         logger.error("vxlan_tool not started in SF2")
291
292     # SSH to modify the classification flows in compute
293
294     contr_cmd3 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
295                   " 'ssh " + ip_compute + " 'bash correct_classifier.bash''")
296     logger.info("Executing script to modify the classi: '%s'" % contr_cmd3)
297     process = subprocess.Popen(contr_cmd3,
298                                shell=True,
299                                stdout=subprocess.PIPE)
300
301     # SSH TO EXECUTE cmd_client
302
303     logger.info("TEST STARTED")
304     try:
305         ssh.connect(floatip_client, username="root",
306                     password="opnfv", timeout=2)
307         command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
308         (stdin, stdout, stderr) = ssh.exec_command(command)
309     except:
310         logger.debug("Waiting for %s..." % floatip_client)
311         time.sleep(6)
312         # timeout -= 1
313
314     # WRITE THE CORRECT WAY TO DO LOGGING
315     i = 0
316     if "timed out" in stdout.readlines()[0]:
317         logger.info('\033[92m' + "TEST 1 [PASSED] "
318                     "==> SSH BLOCKED" + '\033[0m')
319         i = i + 1
320     else:
321         logger.error('\033[91m' + "TEST 1 [FAILED] "
322                      "==> SSH NOT BLOCKED" + '\033[0m')
323         return
324
325     # SSH TO EXECUTE cmd_client
326
327     try:
328         ssh.connect(floatip_client, username="root",
329                     password="opnfv", timeout=2)
330         command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
331         (stdin, stdout, stderr) = ssh.exec_command(command)
332     except:
333         logger.debug("Waiting for %s..." % floatip_client)
334         time.sleep(6)
335         # timeout -= 1
336
337     if "succeeded" in stdout.readlines()[0]:
338         logger.info('\033[92m' + "TEST 2 [PASSED] "
339                     "==> HTTP WORKS" + '\033[0m')
340         i = i + 1
341     else:
342         logger.error('\033[91m' + "TEST 2 [FAILED] "
343                      "==> HTTP BLOCKED" + '\033[0m')
344         return
345
346     # CHANGE OF CLASSIFICATION #
347     logger.info("Changing the classification")
348     tacker_classi = "/home/opnfv/repos/functest/testcases/features/sfc/" + \
349         TACKER_CHANGECLASSI
350     subprocess.call(tacker_classi, shell=True)
351
352     logger.info("Wait for ODL to update the classification rules in OVS")
353     time.sleep(10)
354
355     # SSH to modify the classification flows in compute
356
357     contr_cmd4 = ("sshpass -p r00tme ssh " + ssh_options + " root@10.20.0.2"
358                   " 'ssh " + ip_compute + " 'bash correct_classifier.bash''")
359     logger.info("Executing script to modify the classi: '%s'" % contr_cmd4)
360     process = subprocess.Popen(contr_cmd4,
361                                shell=True,
362                                stdout=subprocess.PIPE)
363
364     # SSH TO EXECUTE cmd_client
365
366     try:
367         ssh.connect(floatip_client, username="root",
368                     password="opnfv", timeout=2)
369         command = "nc -w 5 -zv " + instance_ip_2 + " 80 2>&1"
370         (stdin, stdout, stderr) = ssh.exec_command(command)
371     except:
372         logger.debug("Waiting for %s..." % floatip_client)
373         time.sleep(6)
374         # timeout -= 1
375
376     if "timed out" in stdout.readlines()[0]:
377         logger.info('\033[92m' + "TEST 3 [WORKS] "
378                     "==> HTTP BLOCKED" + '\033[0m')
379         i = i + 1
380     else:
381         logger.error('\033[91m' + "TEST 3 [FAILED] "
382                      "==> HTTP NOT BLOCKED" + '\033[0m')
383         return
384
385     # SSH TO EXECUTE cmd_client
386
387     try:
388         ssh.connect(floatip_client, username="root",
389                     password="opnfv", timeout=2)
390         command = "nc -w 5 -zv " + instance_ip_2 + " 22 2>&1"
391         (stdin, stdout, stderr) = ssh.exec_command(command)
392     except:
393         logger.debug("Waiting for %s..." % floatip_client)
394         time.sleep(6)
395         # timeout -= 1
396
397     if "succeeded" in stdout.readlines()[0]:
398         logger.info('\033[92m' + "TEST 4 [WORKS] "
399                     "==> SSH WORKS" + '\033[0m')
400         i = i + 1
401     else:
402         logger.error('\033[91m' + "TEST 4 [FAILED] "
403                      "==> SSH BLOCKED" + '\033[0m')
404         return
405
406     if i == 4:
407         for x in range(0, 5):
408             logger.info('\033[92m' + "SFC TEST WORKED"
409                         " :) \n" + '\033[0m')
410
411     # TODO report results to DB
412     # functest_utils.logger_test_results(logger, "SFC",
413     # "odl-sfc",
414     # status, details)
415     # see doctor, promise, domino, ...
416     # if args.report:
417         # logger.info("Pushing odl-SFC results")
418         # functest_utils.push_results_to_db("functest",
419         #                                  "odl-sfc",
420         #                                  logger,
421         #                                  start_time,
422         #                                  stop_time,
423         #                                  status,
424         #                                  details)
425
426     sys.exit(0)
427
428 if __name__ == '__main__':
429     main()