Merge "Reduce the number of iterations to ten in rally scenarios"
[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 import json
12 import os
13 import os.path
14 import re
15 import requests
16 import shutil
17 import socket
18 import subprocess
19 import sys
20 import urllib2
21 import yaml
22 from git import Repo
23
24
25 # ----------------------------------------------------------
26 #
27 #               OPENSTACK UTILS
28 #
29 # -----------------------------------------------------------
30
31
32 #*********************************************
33 #   CREDENTIALS
34 #*********************************************
35 def check_credentials():
36     """
37     Check if the OpenStack credentials (openrc) are sourced
38     """
39     env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME']
40     return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
41
42 def get_credentials(service):
43     """Returns a creds dictionary filled with the following keys:
44     * username
45     * password/api_key (depending on the service)
46     * tenant_name/project_id (depending on the service)
47     * auth_url
48     :param service: a string indicating the name of the service
49                     requesting the credentials.
50     """
51     creds = {}
52     # Unfortunately, each of the OpenStack client will request slightly
53     # different entries in their credentials dict.
54     if service.lower() in ("nova", "cinder"):
55         password = "api_key"
56         tenant = "project_id"
57     else:
58         password = "password"
59         tenant = "tenant_name"
60
61     # The most common way to pass these info to the script is to do it through
62     # environment variables.
63     creds.update({
64         "username": os.environ.get('OS_USERNAME', "admin"),
65         password: os.environ.get("OS_PASSWORD", 'admin'),
66         "auth_url": os.environ.get("OS_AUTH_URL",
67                                    "http://192.168.20.71:5000/v2.0"),
68         tenant: os.environ.get("OS_TENANT_NAME", "admin"),
69     })
70     return creds
71
72
73
74 #*********************************************
75 #   NOVA
76 #*********************************************
77 def get_instances(nova_client):
78     try:
79         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
80         return instances
81     except Exception, e:
82         print "Error [get_instances(nova_client)]:", e
83         return None
84
85
86 def get_instance_status(nova_client, instance):
87     try:
88         instance = nova_client.servers.get(instance.id)
89         return instance.status
90     except Exception, e:
91         #print "Error [get_instance_status(nova_client, '%s')]:" % \
92         #    str(instance), e
93         return None
94
95
96 def get_instance_by_name(nova_client, instance_name):
97     try:
98         instance = nova_client.servers.find(name=instance_name)
99         return instance
100     except Exception, e:
101         print "Error [get_instance_by_name(nova_client, '%s')]:" % \
102             instance_name, e
103         return None
104
105
106 def get_flavor_id(nova_client, flavor_name):
107     flavors = nova_client.flavors.list(detailed=True)
108     id = ''
109     for f in flavors:
110         if f.name == flavor_name:
111             id = f.id
112             break
113     return id
114
115
116 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
117     flavors = nova_client.flavors.list(detailed=True)
118     id = ''
119     for f in flavors:
120         if min_ram <= f.ram and f.ram <= max_ram:
121             id = f.id
122             break
123     return id
124
125
126 def get_floating_ips(nova_client):
127     try:
128         floating_ips = nova_client.floating_ips.list()
129         return floating_ips
130     except Exception, e:
131         print "Error [get_floating_ips(nova_client)]:", e
132         return None
133
134
135 def create_flavor(nova_client, flavor_name, ram, disk, vcpus):
136     try:
137         flavor = nova_client.flavors.create(flavor_name,ram,vcpus,disk)
138     except Exception, e:
139         print "Error [create_flavor(nova_client, '%s', '%s', '%s', "\
140             "'%s')]:" %(flavor_name,ram, disk, vcpus), e
141         return None
142     return flavor.id
143
144
145 def create_floating_ip(neutron_client):
146     extnet_id = get_external_net_id(neutron_client)
147     props = {'floating_network_id': extnet_id}
148     try:
149         ip_json = neutron_client.create_floatingip({'floatingip': props})
150         floating_ip = ip_json['floatingip']['floating_ip_address']
151     except Exception, e:
152         print "Error [create_floating_ip(neutron_client)]:", e
153         return None
154     return floating_ip
155
156
157 def add_floating_ip(nova_client, server_id, floatingip_id):
158     try:
159         nova_client.servers.add_floating_ip(server_id,floatingip_id)
160         return True
161     except Exception, e:
162         print "Error [add_floating_ip(nova_client, '%s', '%s')]:" % \
163             (server_id, floatingip_id), e
164         return False
165
166
167 def delete_instance(nova_client, instance_id):
168     try:
169         nova_client.servers.force_delete(instance_id)
170         return True
171     except Exception, e:
172         print "Error [delete_instance(nova_client, '%s')]:" % instance_id, e
173         return False
174
175
176 def delete_floating_ip(nova_client, floatingip_id):
177     try:
178         nova_client.floating_ips.delete(floatingip_id)
179         return True
180     except Exception, e:
181         print "Error [delete_floating_ip(nova_client, '%s')]:" % floatingip_id, e
182         return False
183
184
185
186
187 #*********************************************
188 #   NEUTRON
189 #*********************************************
190 def get_network_list(neutron_client):
191     network_list = neutron_client.list_networks()['networks']
192     if len(network_list) == 0:
193         return None
194     else:
195         return network_list
196
197
198 def get_router_list(neutron_client):
199     router_list = neutron_client.list_routers()['routers']
200     if len(router_list) == 0:
201         return None
202     else:
203         return router_list
204
205
206 def get_port_list(neutron_client):
207     port_list = neutron_client.list_ports()['ports']
208     if len(port_list) == 0:
209         return None
210     else:
211         return port_list
212
213
214 def get_network_id(neutron_client, network_name):
215     networks = neutron_client.list_networks()['networks']
216     id = ''
217     for n in networks:
218         if n['name'] == network_name:
219             id = n['id']
220             break
221     return id
222
223
224 def get_private_net(neutron_client):
225     # Checks if there is an existing shared private network
226     networks = neutron_client.list_networks()['networks']
227     if len(networks) == 0:
228         return None
229     for net in networks:
230         if (net['router:external'] is False) and (net['shared'] is True):
231             return net
232     return None
233
234
235 def get_external_net(neutron_client):
236     for network in neutron_client.list_networks()['networks']:
237         if network['router:external']:
238             return network['name']
239     return False
240
241
242 def get_external_net_id(neutron_client):
243     for network in neutron_client.list_networks()['networks']:
244         if network['router:external']:
245             return network['id']
246     return False
247
248
249 def check_neutron_net(neutron_client, net_name):
250     for network in neutron_client.list_networks()['networks']:
251         if network['name'] == net_name:
252             for subnet in network['subnets']:
253                 return True
254     return False
255
256
257 def create_neutron_net(neutron_client, name):
258     json_body = {'network': {'name': name,
259                              'admin_state_up': True}}
260     try:
261         network = neutron_client.create_network(body=json_body)
262         network_dict = network['network']
263         return network_dict['id']
264     except Exception, e:
265         print "Error [create_neutron_net(neutron_client, '%s')]:" % name, e
266         return False
267
268
269 def create_neutron_subnet(neutron_client, name, cidr, net_id):
270     json_body = {'subnets': [{'name': name, 'cidr': cidr,
271                               'ip_version': 4, 'network_id': net_id}]}
272     try:
273         subnet = neutron_client.create_subnet(body=json_body)
274         return subnet['subnets'][0]['id']
275     except Exception, e:
276         print "Error [create_neutron_subnet(neutron_client, '%s', '%s', "\
277             "'%s')]:" %(name,cidr, net_id), e
278         return False
279
280
281 def create_neutron_router(neutron_client, name):
282     json_body = {'router': {'name': name, 'admin_state_up': True}}
283     try:
284         router = neutron_client.create_router(json_body)
285         return router['router']['id']
286     except Exception, e:
287         print "Error [create_neutron_router(neutron_client, '%s')]:" % name, e
288         return False
289
290
291 def create_neutron_port(neutron_client, name, network_id, ip):
292     json_body = {'port': {
293                  'admin_state_up': True,
294                  'name': name,
295                  'network_id': network_id,
296                  'fixed_ips': [{"ip_address": ip}]
297                  }}
298     try:
299         port = neutron_client.create_port(body=json_body)
300         return port['port']['id']
301     except Exception, e:
302         print "Error [create_neutron_port(neutron_client, '%s', '%s', "\
303             "'%s')]:" %(name,network_id, ip), e
304         return False
305
306
307 def update_neutron_net(neutron_client, network_id, shared=False):
308     json_body = {'network': {'shared': shared}}
309     try:
310         neutron_client.update_network(network_id, body=json_body)
311         return True
312     except Exception, e:
313         print "Error [update_neutron_net(neutron_client, '%s', '%s')]:" % \
314             (network_id,str(shared)), e
315         return False
316
317
318 def update_neutron_port(neutron_client, port_id, device_owner):
319     json_body = {'port': {
320                  'device_owner': device_owner,
321                  }}
322     try:
323         port = neutron_client.update_port(port=port_id,
324                                           body=json_body)
325         return port['port']['id']
326     except Exception, e:
327         print "Error [update_neutron_port(neutron_client, '%s', '%s')]:" % \
328             (port_id,device_owner), e
329         return False
330
331
332 def add_interface_router(neutron_client, router_id, subnet_id):
333     json_body = {"subnet_id": subnet_id}
334     try:
335         neutron_client.add_interface_router(router=router_id, body=json_body)
336         return True
337     except Exception, e:
338         print "Error [add_interface_router(neutron_client, '%s', '%s')]:" % \
339             (router_id,subnet_id), e
340         return False
341
342 def add_gateway_router(neutron_client, router_id):
343     ext_net_id = get_external_net_id(neutron_client)
344     router_dict = {'network_id': ext_net_id}
345     try:
346         neutron_client.add_gateway_router(router_id,router_dict)
347         return True
348     except Exception, e:
349         print "Error [add_gateway_router(neutron_client, '%s')]:" % router_id, e
350         return False
351
352
353 def delete_neutron_net(neutron_client, network_id):
354     try:
355         neutron_client.delete_network(network_id)
356         return True
357     except Exception, e:
358         print "Error [delete_neutron_net(neutron_client, '%s')]:" % network_id, e
359         return False
360
361
362 def delete_neutron_subnet(neutron_client, subnet_id):
363     try:
364         neutron_client.delete_subnet(subnet_id)
365         return True
366     except Exception, e:
367         print "Error [delete_neutron_subnet(neutron_client, '%s')]:" % subnet_id, e
368         return False
369
370
371 def delete_neutron_router(neutron_client, router_id):
372     json_body = {'router': {'id': router_id}}
373     try:
374         neutron_client.delete_router(router=router_id)
375         return True
376     except Exception, e:
377         print "Error [delete_neutron_router(neutron_client, '%s')]:" % \
378             router_id, e
379         return False
380
381
382 def delete_neutron_port(neutron_client, port_id):
383     try:
384         neutron_client.delete_port(port_id)
385         return True
386     except Exception, e:
387         print "Error [delete_neutron_port(neutron_client, '%s')]:" % port_id, e
388         return False
389
390
391 def remove_interface_router(neutron_client, router_id, subnet_id):
392     json_body = {"subnet_id": subnet_id}
393     try:
394         neutron_client.remove_interface_router(router=router_id,
395                                                body=json_body)
396         return True
397     except Exception, e:
398         print "Error [remove_interface_router(neutron_client, '%s', '%s')]:" % \
399             (router_id,subnet_id), e
400         return False
401
402
403 def remove_gateway_router(neutron_client, router_id):
404     try:
405         neutron_client.remove_gateway_router(router_id)
406         return True
407     except Exception, e:
408         print "Error [remove_gateway_router(neutron_client, '%s')]:" % router_id, e
409         return False
410
411
412
413 #*********************************************
414 #   SEC GROUPS
415 #*********************************************
416 def get_security_groups(neutron_client):
417     try:
418         security_groups = neutron_client.list_security_groups()[
419             'security_groups']
420         return security_groups
421     except Exception, e:
422         print "Error [get_security_groups(neutron_client)]:", e
423         return None
424
425
426 def create_security_group(neutron_client, sg_name, sg_description):
427     json_body= {'security_group' : { 'name' : sg_name, \
428                                     'description' : sg_description }}
429     try:
430         secgroup = neutron_client.create_security_group(json_body)
431         return secgroup['security_group']
432     except Exception, e:
433         print "Error [create_security_group(neutron_client, '%s', '%s')]:" % \
434             (sg_name,sg_description), e
435         return False
436
437
438 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
439                          port_range_min = None, port_range_max = None):
440     if port_range_min == None and port_range_max == None:
441         json_body = { 'security_group_rule' : \
442                          { 'direction' : direction, \
443                           'security_group_id' : sg_id, \
444                           'protocol' : protocol } }
445     elif port_range_min != None and port_range_max != None:
446         json_body = { 'security_group_rule' : \
447                              { 'direction' : direction, \
448                               'security_group_id' : sg_id, \
449                               'port_range_min': port_range_min, \
450                               'port_range_max' : port_range_max, \
451                               'protocol' : protocol } }
452     else:
453         print "Error [create_secgroup_rule(neutron_client, '%s', '%s', "\
454             "'%s', '%s', '%s', '%s')]:" %(neutron_client, sg_id, direction, \
455                                 port_range_min, port_range_max, protocol),\
456                                 " Invalid values for port_range_min, port_range_max"
457         return False
458     try:
459         neutron_client.create_security_group_rule(json_body)
460         return True
461     except Exception, e:
462         print "Error [create_secgroup_rule(neutron_client, '%s', '%s', "\
463             "'%s', '%s', '%s', '%s')]:" %(neutron_client, sg_id, direction, \
464                                 port_range_min, port_range_max, protocol), e
465         return False
466
467
468 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
469     try:
470         nova_client.servers.add_security_group(instance_id, secgroup_id)
471         return True
472     except Exception, e:
473         print "Error [add_secgroup_to_instance(nova_client, '%s', '%s')]: " % \
474             (instance_id, secgroup_id), e
475         return False
476
477
478 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
479     json_body = {"quota": {
480         "security_group": sg_quota,
481         "security_group_rule": sg_rule_quota
482     }}
483
484     try:
485         quota = neutron_client.update_quota(tenant_id=tenant_id,
486                                             body=json_body)
487         return True
488     except Exception, e:
489         print "Error [update_sg_quota(neutron_client, '%s', '%s', "\
490             "'%s')]:" %(tenant_id, sg_quota, sg_rule_quota), e
491         return False
492
493
494 def delete_security_group(neutron_client, secgroup_id):
495     try:
496         neutron_client.delete_security_group(secgroup_id)
497         return True
498     except Exception, e:
499         print "Error [delete_security_group(neutron_client, '%s')]:" % secgroup_id, e
500         return False
501
502
503
504
505 #*********************************************
506 #   GLANCE
507 #*********************************************
508 def get_images(nova_client):
509     try:
510         images = nova_client.images.list()
511         return images
512     except Exception, e:
513         print "Error [get_images]:", e
514         return None
515
516
517 def get_image_id(glance_client, image_name):
518     images = glance_client.images.list()
519     id = ''
520     for i in images:
521         if i.name == image_name:
522             id = i.id
523             break
524     return id
525
526
527 def create_glance_image(glance_client, image_name, file_path, public=True):
528     if not os.path.isfile(file_path):
529         print "Error: file " + file_path + " does not exist."
530         return False
531     try:
532         with open(file_path) as fimage:
533             image = glance_client.images.create(name=image_name,
534                                                 is_public=public,
535                                                 disk_format="qcow2",
536                                                 container_format="bare",
537                                                 data=fimage)
538         return image.id
539     except Exception, e:
540         print "Error [create_glance_image(glance_client, '%s', '%s', "\
541             "'%s')]:" %(image_name, file_path, str(public)), e
542         return False
543
544
545 def delete_glance_image(nova_client, image_id):
546     try:
547         nova_client.images.delete(image_id)
548         return True
549     except Exception, e:
550         print "Error [delete_glance_image(nova_client, '%s')]:" % image_id, e
551         return False
552
553
554
555 #*********************************************
556 #   CINDER
557 #*********************************************
558 def get_volumes(cinder_client):
559     try:
560         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
561         return volumes
562     except Exception, e:
563         print "Error [get_volumes(cinder_client)]:", e
564         return None
565
566
567 def list_volume_types(cinder_client, public=True, private=True):
568     try:
569         volume_types = cinder_client.volume_types.list()
570         if not public:
571             volume_types = [vt for vt in volume_types if not vt.is_public]
572         if not private:
573             volume_types = [vt for vt in volume_types if vt.is_public]
574         return volume_types
575     except Exception, e:
576         print "Error [list_volume_types(cinder_client)]:", e
577         return None
578
579
580 def create_volume_type(cinder_client, name):
581     try:
582         volume_type = cinder_client.volume_types.create(name)
583         return volume_type
584     except Exception, e:
585         print "Error [create_volume_type(cinder_client, '%s')]:" % name, e
586         return None
587
588
589 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
590                         snapshots_quota, gigabytes_quota):
591     quotas_values = {"volumes": vols_quota,
592                      "snapshots": snapshots_quota,
593                      "gigabytes": gigabytes_quota}
594
595     try:
596         quotas_default = cinder_client.quotas.update(tenant_id,
597                                                       **quotas_values)
598         return True
599     except Exception, e:
600         print "Error [update_cinder_quota(cinder_client, '%s', '%s', '%s'" \
601             "'%s')]:" %(tenant_id, vols_quota, snapshots_quota, gigabytes_quota), e
602         return False
603
604
605 def delete_volume(cinder_client, volume_id, forced=False):
606     try:
607         if forced:
608             try:
609                 cinder_client.volumes.detach(volume_id)
610             except:
611                 print "Error:", sys.exc_info()[0]
612             cinder_client.volumes.force_delete(volume_id)
613         else:
614             cinder_client.volumes.delete(volume_id)
615         return True
616     except Exception, e:
617         print "Error [delete_volume(cinder_client, '%s', '%s')]:" % \
618             (volume_id, str(forced)), e
619         return False
620
621
622 def delete_volume_type(cinder_client, volume_type):
623     try:
624         cinder_client.volume_types.delete(volume_type)
625         return True
626     except Exception, e:
627         print "Error [delete_volume_type(cinder_client, '%s')]:" % volume_type, e
628         return False
629
630
631
632 #*********************************************
633 #   KEYSTONE
634 #*********************************************
635 def get_tenants(keystone_client):
636     try:
637         tenants = keystone_client.tenants.list()
638         return tenants
639     except Exception, e:
640         print "Error [get_tenants(keystone_client)]:", e
641         return None
642
643
644 def get_users(keystone_client):
645     try:
646         users = keystone_client.users.list()
647         return users
648     except Exception, e:
649         print "Error [get_users(keystone_client)]:", e
650         return None
651
652
653 def get_tenant_id(keystone_client, tenant_name):
654     tenants = keystone_client.tenants.list()
655     id = ''
656     for t in tenants:
657         if t.name == tenant_name:
658             id = t.id
659             break
660     return id
661
662
663 def get_user_id(keystone_client, user_name):
664     users = keystone_client.users.list()
665     id = ''
666     for u in users:
667         if u.name == user_name:
668             id = u.id
669             break
670     return id
671
672
673 def get_role_id(keystone_client, role_name):
674     roles = keystone_client.roles.list()
675     id = ''
676     for r in roles:
677         if r.name == role_name:
678             id = r.id
679             break
680     return id
681
682
683 def create_tenant(keystone_client, tenant_name, tenant_description):
684     try:
685         tenant = keystone_client.tenants.create(tenant_name,
686                                                 tenant_description,
687                                                 enabled=True)
688         return tenant.id
689     except Exception, e:
690         print "Error [create_tenant(cinder_client, '%s', '%s')]:" % \
691             (tenant_name, tenant_description), e
692         return False
693
694
695 def create_user(keystone_client, user_name, user_password,
696                 user_email, tenant_id):
697     try:
698         user = keystone_client.users.create(user_name, user_password,
699                                             user_email, tenant_id,
700                                             enabled=True)
701         return user.id
702     except Exception, e:
703         print "Error [create_user(keystone_client, '%s', '%s', '%s'" \
704             "'%s')]:" %(user_name, user_password, user_email, tenant_id), e
705         return False
706
707
708 def add_role_user(keystone_client, user_id, role_id, tenant_id):
709     try:
710         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
711         return True
712     except Exception, e:
713         print "Error [add_role_user(keystone_client, '%s', '%s'" \
714             "'%s')]:" %(user_id, role_id, tenant_id), e
715         return False
716
717
718 def delete_tenant(keystone_client, tenant_id):
719     try:
720         tenant = keystone_client.tenants.delete(tenant_id)
721         return True
722     except Exception, e:
723         print "Error [delete_tenant(keystone_client, '%s')]:" % tenant_id, e
724         return False
725
726
727 def delete_user(keystone_client, user_id):
728     try:
729         tenant = keystone_client.users.delete(user_id)
730         return True
731     except Exception, e:
732         print "Error [delete_user(keystone_client, '%s')]:" % user_id, e
733         return False
734
735
736
737
738
739
740
741 # ----------------------------------------------------------
742 #
743 #               INTERNET UTILS
744 #
745 # -----------------------------------------------------------
746 def check_internet_connectivity(url='http://www.opnfv.org/'):
747     """
748     Check if there is access to the internet
749     """
750     try:
751         urllib2.urlopen(url, timeout=5)
752         return True
753     except urllib2.URLError:
754         return False
755
756
757 def download_url(url, dest_path):
758     """
759     Download a file to a destination path given a URL
760     """
761     name = url.rsplit('/')[-1]
762     dest = dest_path + "/" + name
763     try:
764         response = urllib2.urlopen(url)
765     except (urllib2.HTTPError, urllib2.URLError):
766         return False
767
768     with open(dest, 'wb') as f:
769         shutil.copyfileobj(response, f)
770     return True
771
772
773
774
775 # ----------------------------------------------------------
776 #
777 #               CI UTILS
778 #
779 # -----------------------------------------------------------
780 def get_git_branch(repo_path):
781     """
782     Get git branch name
783     """
784     repo = Repo(repo_path)
785     branch = repo.active_branch
786     return branch.name
787
788
789 def get_installer_type(logger=None):
790     """
791     Get installer type (fuel, apex, joid, compass)
792     """
793     try:
794         installer = os.environ['INSTALLER_TYPE']
795     except KeyError:
796         if logger:
797             logger.error("Impossible to retrieve the installer type")
798         installer = "Unknown_installer"
799
800     return installer
801
802
803 def get_scenario(logger=None):
804     """
805     Get scenario
806     """
807     try:
808         scenario = os.environ['DEPLOY_SCENARIO']
809     except KeyError:
810         if logger:
811             logger.error("Impossible to retrieve the scenario")
812         scenario = "Unknown_scenario"
813
814     return scenario
815
816
817 def get_pod_name(logger=None):
818     """
819     Get PoD Name from env variable NODE_NAME
820     """
821     try:
822         return os.environ['NODE_NAME']
823     except KeyError:
824         if logger:
825             logger.error(
826                 "Unable to retrieve the POD name from environment.Using pod name 'unknown-pod'")
827         return "unknown-pod"
828
829
830 def push_results_to_db(db_url, case_name, logger, pod_name,
831                        version, payload):
832     """
833     POST results to the Result target DB
834     """
835     url = db_url + "/results"
836     installer = get_installer_type(logger)
837     params = {"project_name": "functest", "case_name": case_name,
838               "pod_name": pod_name, "installer": installer,
839               "version": version, "details": payload}
840
841     headers = {'Content-Type': 'application/json'}
842     try:
843         r = requests.post(url, data=json.dumps(params), headers=headers)
844         if logger:
845             logger.debug(r)
846         return True
847     except Exception, e:
848         print "Error [push_results_to_db('%s', '%s', '%s', '%s', '%s')]:" \
849             % (db_url, case_name, pod_name, version, payload), e
850         return False
851
852
853 def get_resolvconf_ns():
854     """
855     Get nameservers from current resolv.conf
856     """
857     nameservers = []
858     rconf = open("/etc/resolv.conf", "r")
859     line = rconf.readline()
860     while line:
861         ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
862         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
863         if ip:
864             result = sock.connect_ex((ip.group(),53))
865             if result == 0:
866                 nameservers.append(ip.group())
867         line = rconf.readline()
868     return nameservers
869
870
871 def getTestEnv(test, functest_yaml):
872     """
873     Get the config of the testcase based on functest_config.yaml
874       2 options
875         - test = test project e.g; ovno
876         - test = testcase e.g. functest/odl
877        look for the / to see if it is a test project or a testcase
878     """
879     try:
880         TEST_ENV = functest_yaml.get("test-dependencies")
881
882         if test.find("/") < 0:
883             config_test = TEST_ENV[test]
884         else:
885             test_split = test.split("/")
886             testproject = test_split[0]
887             testcase = test_split[1]
888             config_test = TEST_ENV[testproject][testcase]
889     except KeyError:
890         # if not defined in dependencies => no dependencies
891         config_test = ""
892     except Exception, e:
893         print "Error [getTestEnv]:", e
894
895     return config_test
896
897
898 def get_ci_envvars():
899     """
900     Get the CI env variables
901     """
902     ci_env_var = {
903         "installer": os.environ.get('INSTALLER_TYPE'),
904         "scenario": os.environ.get('DEPLOY_SCENARIO')}
905     return ci_env_var
906
907
908 def isTestRunnable(test, functest_yaml):
909     """
910     Return True if the test is runnable in the current scenario
911     """
912     # By default we assume that all the tests are always runnable...
913     is_runnable = True
914     # Retrieve CI environment
915     ci_env = get_ci_envvars()
916     # Retrieve test environement from config file
917     test_env = getTestEnv(test, functest_yaml)
918
919     # if test_env not empty => dependencies to be checked
920     if test_env is not None and len(test_env) > 0:
921         # possible criteria = ["installer", "scenario"]
922         # consider test criteria from config file
923         # compare towards CI env through CI en variable
924         for criteria in test_env:
925             if re.search(test_env[criteria], ci_env[criteria]) is None:
926                 # print "Test "+ test + " cannot be run on the environment"
927                 is_runnable = False
928     return is_runnable
929
930
931 def generateTestcaseList(functest_yaml):
932     """
933     Generate a test file with the runnable test according to
934     the current scenario
935     """
936     test_list = ""
937     # get testcases
938     testcase_list = functest_yaml.get("test-dependencies")
939     projects = testcase_list.keys()
940
941     for project in projects:
942         testcases = testcase_list[project]
943         # 1 or 2 levels for testcases project[/case]l
944         # if only project name without controller or scenario
945         # => shall be runnable on any controller/scenario
946         if testcases is None:
947             test_list += project + " "
948         else:
949             for testcase in testcases:
950                 if testcase == "installer" or testcase == "scenario":
951                     # project (1 level)
952                     if isTestRunnable(project, functest_yaml):
953                         test_list += project + " "
954                 else:
955                     # project/testcase (2 levels)
956                     thetest = project + "/" + testcase
957                     if isTestRunnable(thetest, functest_yaml):
958                         test_list += testcase + " "
959
960     # sort the list to execute the test in the right order
961     test_order_list = functest_yaml.get("test_exec_priority")
962     test_sorted_list = ""
963     for test in test_order_list:
964         if test_order_list[test] in test_list:
965             test_sorted_list += test_order_list[test] + " "
966
967     # create a file that could be consumed by run-test.sh
968     # this method is used only for CI
969     # so it can be run only in container
970     # reuse default conf directory to store the list of runnable tests
971     file = open("/home/opnfv/functest/conf/testcase-list.txt", 'w')
972     file.write(test_sorted_list)
973     file.close()
974
975     return test_sorted_list
976
977
978 def execute_command(cmd, logger=None, exit_on_error=True):
979     """
980     Execute Linux command
981         prints stdout to a file and depending on if there
982         is a logger defined, it will print it or not.
983     """
984     if logger:
985         logger.debug('Executing command : {}'.format(cmd))
986     output_file = "output.txt"
987     f = open(output_file, 'w+')
988     p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT)
989     f.close()
990     f = open(output_file, 'r')
991     result = f.read()
992     if result != "" and logger:
993         logger.debug(result)
994     if p == 0:
995         return True
996     else:
997         if logger:
998             logger.error("Error when executing command %s" % cmd)
999         if exit_on_error:
1000             exit(-1)
1001         return False