Ensure nameserver ip works
[functest.git] / testcases / functest_utils.py
1 #!/usr/bin/env python
2 #
3 # jose.lausuch@ericsson.com
4 # valentin.boucher@orange.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11
12 import os
13 import os.path
14 import urllib2
15 import subprocess
16 import sys
17 import requests
18 import json
19 import shutil
20 import re
21 import yaml
22 import socket
23 from git import Repo
24
25
26 # ############ CREDENTIALS OPENSTACK #############
27 def check_credentials():
28     """
29     Check if the OpenStack credentials (openrc) are sourced
30     """
31     env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME']
32     return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
33
34
35 def get_credentials(service):
36     """Returns a creds dictionary filled with the following keys:
37     * username
38     * password/api_key (depending on the service)
39     * tenant_name/project_id (depending on the service)
40     * auth_url
41     :param service: a string indicating the name of the service
42                     requesting the credentials.
43     """
44     creds = {}
45     # Unfortunately, each of the OpenStack client will request slightly
46     # different entries in their credentials dict.
47     if service.lower() in ("nova", "cinder"):
48         password = "api_key"
49         tenant = "project_id"
50     else:
51         password = "password"
52         tenant = "tenant_name"
53
54     # The most common way to pass these info to the script is to do it through
55     # environment variables.
56     creds.update({
57         "username": os.environ.get('OS_USERNAME', "admin"),
58         password: os.environ.get("OS_PASSWORD", 'admin'),
59         "auth_url": os.environ.get("OS_AUTH_URL",
60                                    "http://192.168.20.71:5000/v2.0"),
61         tenant: os.environ.get("OS_TENANT_NAME", "admin"),
62     })
63
64     return creds
65
66
67 # ################ NOVA #################
68 def get_instances(nova_client):
69     try:
70         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
71         return instances
72     except:
73         return None
74
75
76 def get_instance_status(nova_client, instance):
77     try:
78         instance = nova_client.servers.get(instance.id)
79         return instance.status
80     except:
81         return None
82
83
84 def get_instance_by_name(nova_client, instance_name):
85     try:
86         instance = nova_client.servers.find(name=instance_name)
87         return instance
88     except:
89         return None
90
91
92 def get_flavor_id(nova_client, flavor_name):
93     flavors = nova_client.flavors.list(detailed=True)
94     id = ''
95     for f in flavors:
96         if f.name == flavor_name:
97             id = f.id
98             break
99     return id
100
101
102 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
103     flavors = nova_client.flavors.list(detailed=True)
104     id = ''
105     for f in flavors:
106         if min_ram <= f.ram and f.ram <= max_ram:
107             id = f.id
108             break
109     return id
110
111
112 def delete_instance(nova_client, instance_id):
113     try:
114         nova_client.servers.force_delete(instance_id)
115         return True
116     except:
117         print "Error:", sys.exc_info()[0]
118         return False
119
120
121 def get_floating_ips(nova_client):
122     try:
123         floating_ips = nova_client.floating_ips.list()
124         return floating_ips
125     except:
126         return None
127
128
129 def delete_floating_ip(nova_client, floatingip_id):
130     try:
131         nova_client.floating_ips.delete(floatingip_id)
132         return True
133     except:
134         print "Error:", sys.exc_info()[0]
135         return None
136
137
138 # ################ NEUTRON #################
139 def create_neutron_net(neutron_client, name):
140     json_body = {'network': {'name': name,
141                              'admin_state_up': True}}
142     try:
143         network = neutron_client.create_network(body=json_body)
144         network_dict = network['network']
145         return network_dict['id']
146     except:
147         print "Error:", sys.exc_info()[0]
148         return False
149
150
151 def update_neutron_net(neutron_client, network_id, shared=False):
152     json_body = {'network': {'shared': shared}}
153     try:
154         neutron_client.update_network(network_id, body=json_body)
155         return True
156     except:
157         print "Error:", sys.exc_info()[0]
158         return False
159
160
161 def delete_neutron_net(neutron_client, network_id):
162     try:
163         neutron_client.delete_network(network_id)
164         return True
165     except:
166         print "Error:", sys.exc_info()[0]
167         return False
168
169
170 def create_neutron_subnet(neutron_client, name, cidr, net_id):
171     json_body = {'subnets': [{'name': name, 'cidr': cidr,
172                               'ip_version': 4, 'network_id': net_id}]}
173     try:
174         subnet = neutron_client.create_subnet(body=json_body)
175         return subnet['subnets'][0]['id']
176     except:
177         print "Error:", sys.exc_info()[0]
178         return False
179
180
181 def delete_neutron_subnet(neutron_client, subnet_id):
182     try:
183         neutron_client.delete_subnet(subnet_id)
184         return True
185     except:
186         print "Error:", sys.exc_info()[0]
187         return False
188
189
190 def create_neutron_router(neutron_client, name):
191     json_body = {'router': {'name': name, 'admin_state_up': True}}
192     try:
193         router = neutron_client.create_router(json_body)
194         return router['router']['id']
195     except:
196         print "Error:", sys.exc_info()[0]
197         return False
198
199
200 def delete_neutron_router(neutron_client, router_id):
201     json_body = {'router': {'id': router_id}}
202     try:
203         neutron_client.delete_router(router=router_id)
204         return True
205     except:
206         print "Error:", sys.exc_info()[0]
207         return False
208
209
210 def add_interface_router(neutron_client, router_id, subnet_id):
211     json_body = {"subnet_id": subnet_id}
212     try:
213         neutron_client.add_interface_router(router=router_id, body=json_body)
214         return True
215     except:
216         print "Error:", sys.exc_info()[0]
217         return False
218
219
220 def remove_interface_router(neutron_client, router_id, subnet_id):
221     json_body = {"subnet_id": subnet_id}
222     try:
223         neutron_client.remove_interface_router(router=router_id,
224                                                body=json_body)
225         return True
226     except:
227         print "Error:", sys.exc_info()[0]
228         return False
229
230
231 def remove_gateway_router(neutron_client, router_id):
232     try:
233         neutron_client.remove_gateway_router(router_id)
234         return True
235     except:
236         print "Error:", sys.exc_info()[0]
237         return False
238
239
240 def create_neutron_port(neutron_client, name, network_id, ip):
241     json_body = {'port': {
242                  'admin_state_up': True,
243                  'name': name,
244                  'network_id': network_id,
245                  'fixed_ips': [{"ip_address": ip}]
246                  }}
247     try:
248         port = neutron_client.create_port(body=json_body)
249         return port['port']['id']
250     except:
251         print "Error:", sys.exc_info()[0]
252         return False
253
254
255 def update_neutron_port(neutron_client, port_id, device_owner):
256     json_body = {'port': {
257                  'device_owner': device_owner,
258                  }}
259     try:
260         port = neutron_client.update_port(port=port_id,
261                                           body=json_body)
262         return port['port']['id']
263     except:
264         print "Error:", sys.exc_info()[0]
265         return False
266
267
268 def delete_neutron_port(neutron_client, port_id):
269     try:
270         neutron_client.delete_port(port_id)
271         return True
272     except:
273         print "Error:", sys.exc_info()[0]
274         return False
275
276
277 def get_network_id(neutron_client, network_name):
278     networks = neutron_client.list_networks()['networks']
279     id = ''
280     for n in networks:
281         if n['name'] == network_name:
282             id = n['id']
283             break
284     return id
285
286
287 def check_neutron_net(neutron_client, net_name):
288     for network in neutron_client.list_networks()['networks']:
289         if network['name'] == net_name:
290             for subnet in network['subnets']:
291                 return True
292     return False
293
294
295 def get_network_list(neutron_client):
296     network_list = neutron_client.list_networks()['networks']
297     if len(network_list) == 0:
298         return None
299     else:
300         return network_list
301
302
303 def get_router_list(neutron_client):
304     router_list = neutron_client.list_routers()['routers']
305     if len(router_list) == 0:
306         return None
307     else:
308         return router_list
309
310
311 def get_port_list(neutron_client):
312     port_list = neutron_client.list_ports()['ports']
313     if len(port_list) == 0:
314         return None
315     else:
316         return port_list
317
318
319 def get_external_net(neutron_client):
320     for network in neutron_client.list_networks()['networks']:
321         if network['router:external']:
322             return network['name']
323     return False
324
325
326 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
327     json_body = {"quota": {
328         "security_group": sg_quota,
329         "security_group_rule": sg_rule_quota
330     }}
331
332     try:
333         quota = neutron_client.update_quota(tenant_id=tenant_id,
334                                             body=json_body)
335         return True
336     except:
337         print "Error:", sys.exc_info()[0]
338         return False
339
340
341 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
342                         snapshots_quota, gigabytes_quota):
343     quotas_values = {"volumes": vols_quota,
344                      "snapshots": snapshots_quota,
345                      "gigabytes": gigabytes_quota}
346
347     try:
348         quotas_default = cinder_client.quotas.update(tenant_id,
349                                                       **quotas_values)
350         return True
351     except:
352         print "Error:", sys.exc_info()[0]
353         return False
354
355
356 def get_private_net(neutron_client):
357     # Checks if there is an existing shared private network
358     networks = neutron_client.list_networks()['networks']
359     if len(networks) == 0:
360         return None
361     for net in networks:
362         if (net['router:external'] is False) and (net['shared'] is True):
363             return net
364     return None
365
366
367 # ################ GLANCE #################
368 def get_images(nova_client):
369     try:
370         images = nova_client.images.list()
371         return images
372     except:
373         return None
374
375
376 def get_image_id(glance_client, image_name):
377     images = glance_client.images.list()
378     id = ''
379     for i in images:
380         if i.name == image_name:
381             id = i.id
382             break
383     return id
384
385
386 def create_glance_image(glance_client, image_name, file_path, public=True):
387     if not os.path.isfile(file_path):
388         print "Error: file " + file_path + " does not exist."
389         return False
390     try:
391         with open(file_path) as fimage:
392             image = glance_client.images.create(name=image_name,
393                                                 is_public=public,
394                                                 disk_format="qcow2",
395                                                 container_format="bare",
396                                                 data=fimage)
397         return image.id
398     except:
399         print "Error:", sys.exc_info()[0]
400         return False
401
402
403 def delete_glance_image(nova_client, image_id):
404     try:
405         nova_client.images.delete(image_id)
406         return True
407     except:
408         print "Error:", sys.exc_info()[0]
409         return False
410
411
412 # ################ CINDER #################
413 def get_volumes(cinder_client):
414     try:
415         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
416         return volumes
417     except:
418         return None
419
420
421 def delete_volume(cinder_client, volume_id, forced=False):
422     try:
423         if forced:
424             try:
425                 cinder_client.volumes.detach(volume_id)
426             except:
427                 print "Error:", sys.exc_info()[0]
428             cinder_client.volumes.force_delete(volume_id)
429         else:
430             cinder_client.volumes.delete(volume_id)
431         return True
432     except:
433         print "Error:", sys.exc_info()[0]
434         return False
435
436
437 # ################ CINDER #################
438 def get_security_groups(neutron_client):
439     try:
440         security_groups = neutron_client.list_security_groups()[
441             'security_groups']
442         return security_groups
443     except:
444         return None
445
446
447 def delete_security_group(neutron_client, secgroup_id):
448     try:
449         neutron_client.delete_security_group(secgroup_id)
450         return True
451     except:
452         print "Error:", sys.exc_info()[0]
453         return False
454
455
456 # ################ KEYSTONE #################
457 def get_tenants(keystone_client):
458     try:
459         tenants = keystone_client.tenants.list()
460         return tenants
461     except:
462         return None
463
464
465 def get_tenant_id(keystone_client, tenant_name):
466     tenants = keystone_client.tenants.list()
467     id = ''
468     for t in tenants:
469         if t.name == tenant_name:
470             id = t.id
471             break
472     return id
473
474
475 def get_users(keystone_client):
476     try:
477         users = keystone_client.users.list()
478         return users
479     except:
480         return None
481
482
483 def get_role_id(keystone_client, role_name):
484     roles = keystone_client.roles.list()
485     id = ''
486     for r in roles:
487         if r.name == role_name:
488             id = r.id
489             break
490     return id
491
492
493 def get_user_id(keystone_client, user_name):
494     users = keystone_client.users.list()
495     id = ''
496     for u in users:
497         if u.name == user_name:
498             id = u.id
499             break
500     return id
501
502
503 def create_tenant(keystone_client, tenant_name, tenant_description):
504     try:
505         tenant = keystone_client.tenants.create(tenant_name,
506                                                 tenant_description,
507                                                 enabled=True)
508         return tenant.id
509     except:
510         print "Error:", sys.exc_info()[0]
511         return False
512
513
514 def delete_tenant(keystone_client, tenant_id):
515     try:
516         tenant = keystone_client.tenants.delete(tenant_id)
517         return True
518     except:
519         print "Error:", sys.exc_info()[0]
520         return False
521
522
523 def create_user(keystone_client, user_name, user_password,
524                 user_email, tenant_id):
525     try:
526         user = keystone_client.users.create(user_name, user_password,
527                                             user_email, tenant_id,
528                                             enabled=True)
529         return user.id
530     except:
531         print "Error:", sys.exc_info()[0]
532         return False
533
534
535 def delete_user(keystone_client, user_id):
536     try:
537         tenant = keystone_client.users.delete(user_id)
538         return True
539     except:
540         print "Error:", sys.exc_info()[0]
541         return False
542
543
544 def add_role_user(keystone_client, user_id, role_id, tenant_id):
545     try:
546         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
547         return True
548     except:
549         print "Error:", sys.exc_info()[0]
550         return False
551
552
553 # ################ UTILS #################
554 def check_internet_connectivity(url='http://www.opnfv.org/'):
555     """
556     Check if there is access to the internet
557     """
558     try:
559         urllib2.urlopen(url, timeout=5)
560         return True
561     except urllib2.URLError:
562         return False
563
564
565 def download_url(url, dest_path):
566     """
567     Download a file to a destination path given a URL
568     """
569     name = url.rsplit('/')[-1]
570     dest = dest_path + "/" + name
571     try:
572         response = urllib2.urlopen(url)
573     except (urllib2.HTTPError, urllib2.URLError):
574         return False
575
576     with open(dest, 'wb') as f:
577         shutil.copyfileobj(response, f)
578     return True
579
580
581 def execute_command(cmd, logger=None, exit_on_error=True):
582     """
583     Execute Linux command
584     """
585     if logger:
586         logger.debug('Executing command : {}'.format(cmd))
587     output_file = "output.txt"
588     f = open(output_file, 'w+')
589     p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT)
590     f.close()
591     f = open(output_file, 'r')
592     result = f.read()
593     if result != "" and logger:
594         logger.debug(result)
595     if p == 0:
596         return True
597     else:
598         if logger:
599             logger.error("Error when executing command %s" % cmd)
600         if exit_on_error:
601             exit(-1)
602         return False
603
604
605 def get_git_branch(repo_path):
606     """
607     Get git branch name
608     """
609     repo = Repo(repo_path)
610     branch = repo.active_branch
611     return branch.name
612
613
614 def get_installer_type(logger=None):
615     """
616     Get installer type (fuel, apex, joid, compass)
617     """
618     try:
619         installer = os.environ['INSTALLER_TYPE']
620     except KeyError:
621         if logger:
622             logger.error("Impossible to retrieve the installer type")
623         installer = "Unkown"
624
625     return installer
626
627
628 def get_pod_name(logger=None):
629     """
630     Get PoD Name from env variable NODE_NAME
631     """
632     try:
633         return os.environ['NODE_NAME']
634     except KeyError:
635         if logger:
636             logger.error(
637                 "Unable to retrieve the POD name from environment.Using pod name 'unknown-pod'")
638         return "unknown-pod"
639
640
641 def push_results_to_db(db_url, case_name, logger, pod_name,
642                        git_version, payload):
643     url = db_url + "/results"
644     installer = get_installer_type(logger)
645     params = {"project_name": "functest", "case_name": case_name,
646               "pod_name": pod_name, "installer": installer,
647               "version": git_version, "details": payload}
648
649     headers = {'Content-Type': 'application/json'}
650     try:
651         r = requests.post(url, data=json.dumps(params), headers=headers)
652         if logger:
653             logger.debug(r)
654         return True
655     except:
656         print "Error:", sys.exc_info()[0]
657         return False
658
659
660 def get_resolvconf_ns():
661     nameservers = []
662     rconf = open("/etc/resolv.conf", "r")
663     line = rconf.readline()
664     while line:
665         ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
666         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
667         if ip:
668             result = sock.connect_ex((ip.group(),53))
669             if result == 0:
670                 nameservers.append(ip.group())
671         line = rconf.readline()
672     return nameservers
673
674 def getTestEnv(test, functest_yaml):
675     # get the config of the testcase based on functest_config.yaml
676     # 2 options
677     # - test = test project e.g; ovno
678     # - test = testcase e.g. functest/odl
679     # look for the / to see if it is a test project or a testcase
680     try:
681         TEST_ENV = functest_yaml.get("test-dependencies")
682
683         if test.find("/") < 0:
684             config_test = TEST_ENV[test]
685         else:
686             test_split = test.split("/")
687             testproject = test_split[0]
688             testcase = test_split[1]
689             config_test = TEST_ENV[testproject][testcase]
690     except KeyError:
691         # if not defined in dependencies => no dependencies
692         config_test = ""
693     except:
694         print "Error getTestEnv:", sys.exc_info()[0]
695
696     return config_test
697
698
699 def get_ci_envvars():
700     """
701     Get the CI env variables
702     """
703     ci_env_var = {
704         "installer": os.environ.get('INSTALLER_TYPE'),
705         "scenario": os.environ.get('DEPLOY_SCENARIO')}
706     return ci_env_var
707
708
709 def isTestRunnable(test, functest_yaml):
710     # By default we assume that all the tests are always runnable...
711     is_runnable = True
712     # Retrieve CI environment
713     ci_env = get_ci_envvars()
714     # Retrieve test environement from config file
715     test_env = getTestEnv(test, functest_yaml)
716
717     # if test_env not empty => dependencies to be checked
718     if test_env is not None and len(test_env) > 0:
719         # possible criteria = ["installer", "scenario"]
720         # consider test criteria from config file
721         # compare towards CI env through CI en variable
722         for criteria in test_env:
723             if re.search(test_env[criteria], ci_env[criteria]) is None:
724                 # print "Test "+ test + " cannot be run on the environment"
725                 is_runnable = False
726     return is_runnable
727
728
729 def generateTestcaseList(functest_yaml):
730     test_list = ""
731     # get testcases
732     testcase_list = functest_yaml.get("test-dependencies")
733     projects = testcase_list.keys()
734
735     for project in projects:
736         testcases = testcase_list[project]
737         # 1 or 2 levels for testcases project[/case]
738         # if only project name without controller or scenario
739         # => shall be runnable on any controller/scenario
740         if testcases is None:
741             test_list += project + " "
742         else:
743             for testcase in testcases:
744                 if testcase == "installer" or testcase == "scenario":
745                     # project (1 level)
746                     if isTestRunnable(project, functest_yaml):
747                         test_list += project + " "
748                 else:
749                     # project/testcase (2 levels)
750                     thetest = project + "/" + testcase
751                     if isTestRunnable(thetest, functest_yaml):
752                         test_list += testcase + " "
753
754     # sort the list to execute the test in the right order
755     test_order_list = functest_yaml.get("test_exec_priority")
756     test_sorted_list = ""
757     for test in test_order_list:
758         if test_order_list[test] in test_list:
759             test_sorted_list += test_order_list[test] + " "
760
761     # create a file that could be consumed by run-test.sh
762     # this method is used only for CI
763     # so it can be run only in container
764     # reuse default conf directory to store the list of runnable tests
765     file = open("/home/opnfv/functest/conf/testcase-list.txt", 'w')
766     file.write(test_sorted_list)
767     file.close()
768
769     return test_sorted_list
770