b3549ee93e19e7b57cbb930330e68698a8e123bb
[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, name)]:" % 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 update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
427     json_body = {"quota": {
428         "security_group": sg_quota,
429         "security_group_rule": sg_rule_quota
430     }}
431
432     try:
433         quota = neutron_client.update_quota(tenant_id=tenant_id,
434                                             body=json_body)
435         return True
436     except Exception, e:
437         print "Error [update_sg_quota(neutron_client, '%s', '%s', "\
438             "'%s')]:" %(tenant_id,sg_quota, sg_rule_quota), e
439         return False
440
441
442 def delete_security_group(neutron_client, secgroup_id):
443     try:
444         neutron_client.delete_security_group(secgroup_id)
445         return True
446     except Exception, e:
447         print "Error [delete_security_group(neutron_client, '%s')]:" % secgroup_id, e
448         return False
449
450
451
452 #*********************************************
453 #   GLANCE
454 #*********************************************
455 def get_images(nova_client):
456     try:
457         images = nova_client.images.list()
458         return images
459     except Exception, e:
460         print "Error [get_images]:", e
461         return None
462
463
464 def get_image_id(glance_client, image_name):
465     images = glance_client.images.list()
466     id = ''
467     for i in images:
468         if i.name == image_name:
469             id = i.id
470             break
471     return id
472
473
474 def create_glance_image(glance_client, image_name, file_path, public=True):
475     if not os.path.isfile(file_path):
476         print "Error: file " + file_path + " does not exist."
477         return False
478     try:
479         with open(file_path) as fimage:
480             image = glance_client.images.create(name=image_name,
481                                                 is_public=public,
482                                                 disk_format="qcow2",
483                                                 container_format="bare",
484                                                 data=fimage)
485         return image.id
486     except Exception, e:
487         print "Error [create_glance_image(glance_client, '%s', '%s', "\
488             "'%s')]:" %(image_name,file_path, str(public)), e
489         return False
490
491
492 def delete_glance_image(nova_client, image_id):
493     try:
494         nova_client.images.delete(image_id)
495         return True
496     except Exception, e:
497         print "Error [delete_glance_image(nova_client, image_id)]:" % image_id, e
498         return False
499
500
501
502 #*********************************************
503 #   CINDER
504 #*********************************************
505 def get_volumes(cinder_client):
506     try:
507         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
508         return volumes
509     except Exception, e:
510         print "Error [get_volumes(cinder_client)]:", e
511         return None
512
513
514 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
515                         snapshots_quota, gigabytes_quota):
516     quotas_values = {"volumes": vols_quota,
517                      "snapshots": snapshots_quota,
518                      "gigabytes": gigabytes_quota}
519
520     try:
521         quotas_default = cinder_client.quotas.update(tenant_id,
522                                                       **quotas_values)
523         return True
524     except Exception, e:
525         print "Error [update_cinder_quota(cinder_client, '%s', '%s', '%s'" \
526             "'%s')]:" %(tenant_id, vols_quota, snapshots_quota, gigabytes_quota), e
527         return False
528
529
530 def delete_volume(cinder_client, volume_id, forced=False):
531     try:
532         if forced:
533             try:
534                 cinder_client.volumes.detach(volume_id)
535             except:
536                 print "Error:", sys.exc_info()[0]
537             cinder_client.volumes.force_delete(volume_id)
538         else:
539             cinder_client.volumes.delete(volume_id)
540         return True
541     except Exception, e:
542         print "Error [delete_volume(cinder_client, '%s', '%s')]:" % \
543             (volume_id, str(forced)), e
544         return False
545
546
547 def list_volume_types(cinder_client, public=True, private=True):
548     try:
549         volume_types = cinder_client.volume_types.list()
550         if not public:
551             volume_types = [vt for vt in volume_types if not vt.is_public]
552         if not private:
553             volume_types = [vt for vt in volume_types if vt.is_public]
554         return volume_types
555     except:
556         return None
557
558
559 def create_volume_type(cinder_client, name):
560     try:
561         volume_type = cinder_client.volume_types.create(name)
562         return volume_type
563     except:
564         print "Error:", sys.exc_info()[0]
565         return None
566
567
568 def delete_volume_type(cinder_client, volume_type):
569     try:
570         cinder_client.volume_types.delete(volume_type)
571         return True
572     except:
573         print "Error:", sys.exc_info()[0]
574         return False
575
576
577
578 #*********************************************
579 #   KEYSTONE
580 #*********************************************
581 def get_tenants(keystone_client):
582     try:
583         tenants = keystone_client.tenants.list()
584         return tenants
585     except Exception, e:
586         print "Error [get_tenants(keystone_client)]:", e
587         return None
588
589
590 def get_users(keystone_client):
591     try:
592         users = keystone_client.users.list()
593         return users
594     except Exception, e:
595         print "Error [get_users(keystone_client)]:", e
596         return None
597
598
599 def get_tenant_id(keystone_client, tenant_name):
600     tenants = keystone_client.tenants.list()
601     id = ''
602     for t in tenants:
603         if t.name == tenant_name:
604             id = t.id
605             break
606     return id
607
608
609 def get_user_id(keystone_client, user_name):
610     users = keystone_client.users.list()
611     id = ''
612     for u in users:
613         if u.name == user_name:
614             id = u.id
615             break
616     return id
617
618
619 def get_role_id(keystone_client, role_name):
620     roles = keystone_client.roles.list()
621     id = ''
622     for r in roles:
623         if r.name == role_name:
624             id = r.id
625             break
626     return id
627
628
629 def create_tenant(keystone_client, tenant_name, tenant_description):
630     try:
631         tenant = keystone_client.tenants.create(tenant_name,
632                                                 tenant_description,
633                                                 enabled=True)
634         return tenant.id
635     except Exception, e:
636         print "Error [create_tenant(cinder_client, '%s', '%s')]:" % \
637             (tenant_name, tenant_description), e
638         return False
639
640
641 def create_user(keystone_client, user_name, user_password,
642                 user_email, tenant_id):
643     try:
644         user = keystone_client.users.create(user_name, user_password,
645                                             user_email, tenant_id,
646                                             enabled=True)
647         return user.id
648     except Exception, e:
649         print "Error [create_user(keystone_client, '%s', '%s', '%s'" \
650             "'%s')]:" %(user_name, user_password, user_email, tenant_id), e
651         return False
652
653
654 def add_role_user(keystone_client, user_id, role_id, tenant_id):
655     try:
656         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
657         return True
658     except Exception, e:
659         print "Error [add_role_user(keystone_client, '%s', '%s'" \
660             "'%s')]:" %(user_id, role_id, tenant_id), e
661         return False
662
663
664 def delete_tenant(keystone_client, tenant_id):
665     try:
666         tenant = keystone_client.tenants.delete(tenant_id)
667         return True
668     except Exception, e:
669         print "Error [delete_tenant(keystone_client, '%s')]:" % tenant_id, e
670         return False
671
672
673 def delete_user(keystone_client, user_id):
674     try:
675         tenant = keystone_client.users.delete(user_id)
676         return True
677     except Exception, e:
678         print "Error [delete_user(keystone_client, '%s')]:" % user_id, e
679         return False
680
681
682
683
684
685
686
687 # ----------------------------------------------------------
688 #
689 #               INTERNET UTILS
690 #
691 # -----------------------------------------------------------
692 def check_internet_connectivity(url='http://www.opnfv.org/'):
693     """
694     Check if there is access to the internet
695     """
696     try:
697         urllib2.urlopen(url, timeout=5)
698         return True
699     except urllib2.URLError:
700         return False
701
702
703 def download_url(url, dest_path):
704     """
705     Download a file to a destination path given a URL
706     """
707     name = url.rsplit('/')[-1]
708     dest = dest_path + "/" + name
709     try:
710         response = urllib2.urlopen(url)
711     except (urllib2.HTTPError, urllib2.URLError):
712         return False
713
714     with open(dest, 'wb') as f:
715         shutil.copyfileobj(response, f)
716     return True
717
718
719
720
721 # ----------------------------------------------------------
722 #
723 #               CI UTILS
724 #
725 # -----------------------------------------------------------
726 def get_git_branch(repo_path):
727     """
728     Get git branch name
729     """
730     repo = Repo(repo_path)
731     branch = repo.active_branch
732     return branch.name
733
734
735 def get_installer_type(logger=None):
736     """
737     Get installer type (fuel, apex, joid, compass)
738     """
739     try:
740         installer = os.environ['INSTALLER_TYPE']
741     except KeyError:
742         if logger:
743             logger.error("Impossible to retrieve the installer type")
744         installer = "Unknown_installer"
745
746     return installer
747
748
749 def get_scenario(logger=None):
750     """
751     Get scenario
752     """
753     try:
754         scenario = os.environ['DEPLOY_SCENARIO']
755     except KeyError:
756         if logger:
757             logger.error("Impossible to retrieve the scenario")
758         scenario = "Unknown_scenario"
759
760     return scenario
761
762
763 def get_pod_name(logger=None):
764     """
765     Get PoD Name from env variable NODE_NAME
766     """
767     try:
768         return os.environ['NODE_NAME']
769     except KeyError:
770         if logger:
771             logger.error(
772                 "Unable to retrieve the POD name from environment.Using pod name 'unknown-pod'")
773         return "unknown-pod"
774
775
776 def push_results_to_db(db_url, case_name, logger, pod_name,
777                        version, payload):
778     """
779     POST results to the Result target DB
780     """
781     url = db_url + "/results"
782     installer = get_installer_type(logger)
783     params = {"project_name": "functest", "case_name": case_name,
784               "pod_name": pod_name, "installer": installer,
785               "version": version, "details": payload}
786
787     headers = {'Content-Type': 'application/json'}
788     try:
789         r = requests.post(url, data=json.dumps(params), headers=headers)
790         if logger:
791             logger.debug(r)
792         return True
793     except Exception, e:
794         print "Error []:", e
795         return False
796
797
798 def get_resolvconf_ns():
799     """
800     Get nameservers from current resolv.conf
801     """
802     nameservers = []
803     rconf = open("/etc/resolv.conf", "r")
804     line = rconf.readline()
805     while line:
806         ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
807         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
808         if ip:
809             result = sock.connect_ex((ip.group(),53))
810             if result == 0:
811                 nameservers.append(ip.group())
812         line = rconf.readline()
813     return nameservers
814
815
816 def getTestEnv(test, functest_yaml):
817     """
818     Get the config of the testcase based on functest_config.yaml
819       2 options
820         - test = test project e.g; ovno
821         - test = testcase e.g. functest/odl
822        look for the / to see if it is a test project or a testcase
823     """
824     try:
825         TEST_ENV = functest_yaml.get("test-dependencies")
826
827         if test.find("/") < 0:
828             config_test = TEST_ENV[test]
829         else:
830             test_split = test.split("/")
831             testproject = test_split[0]
832             testcase = test_split[1]
833             config_test = TEST_ENV[testproject][testcase]
834     except KeyError:
835         # if not defined in dependencies => no dependencies
836         config_test = ""
837     except Exception, e:
838         print "Error []:", e
839
840     return config_test
841
842
843 def get_ci_envvars():
844     """
845     Get the CI env variables
846     """
847     ci_env_var = {
848         "installer": os.environ.get('INSTALLER_TYPE'),
849         "scenario": os.environ.get('DEPLOY_SCENARIO')}
850     return ci_env_var
851
852
853 def isTestRunnable(test, functest_yaml):
854     """
855     Return True if the test is runnable in the current scenario
856     """
857     # By default we assume that all the tests are always runnable...
858     is_runnable = True
859     # Retrieve CI environment
860     ci_env = get_ci_envvars()
861     # Retrieve test environement from config file
862     test_env = getTestEnv(test, functest_yaml)
863
864     # if test_env not empty => dependencies to be checked
865     if test_env is not None and len(test_env) > 0:
866         # possible criteria = ["installer", "scenario"]
867         # consider test criteria from config file
868         # compare towards CI env through CI en variable
869         for criteria in test_env:
870             if re.search(test_env[criteria], ci_env[criteria]) is None:
871                 # print "Test "+ test + " cannot be run on the environment"
872                 is_runnable = False
873     return is_runnable
874
875
876 def generateTestcaseList(functest_yaml):
877     """
878     Generate a test file with the runnable test according to
879     the current scenario
880     """
881     test_list = ""
882     # get testcases
883     testcase_list = functest_yaml.get("test-dependencies")
884     projects = testcase_list.keys()
885
886     for project in projects:
887         testcases = testcase_list[project]
888         # 1 or 2 levels for testcases project[/case]l
889         # if only project name without controller or scenario
890         # => shall be runnable on any controller/scenario
891         if testcases is None:
892             test_list += project + " "
893         else:
894             for testcase in testcases:
895                 if testcase == "installer" or testcase == "scenario":
896                     # project (1 level)
897                     if isTestRunnable(project, functest_yaml):
898                         test_list += project + " "
899                 else:
900                     # project/testcase (2 levels)
901                     thetest = project + "/" + testcase
902                     if isTestRunnable(thetest, functest_yaml):
903                         test_list += testcase + " "
904
905     # sort the list to execute the test in the right order
906     test_order_list = functest_yaml.get("test_exec_priority")
907     test_sorted_list = ""
908     for test in test_order_list:
909         if test_order_list[test] in test_list:
910             test_sorted_list += test_order_list[test] + " "
911
912     # create a file that could be consumed by run-test.sh
913     # this method is used only for CI
914     # so it can be run only in container
915     # reuse default conf directory to store the list of runnable tests
916     file = open("/home/opnfv/functest/conf/testcase-list.txt", 'w')
917     file.write(test_sorted_list)
918     file.close()
919
920     return test_sorted_list
921
922
923 def execute_command(cmd, logger=None, exit_on_error=True):
924     """
925     Execute Linux command
926         prints stdout to a file and depending on if there
927         is a logger defined, it will print it or not.
928     """
929     if logger:
930         logger.debug('Executing command : {}'.format(cmd))
931     output_file = "output.txt"
932     f = open(output_file, 'w+')
933     p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT)
934     f.close()
935     f = open(output_file, 'r')
936     result = f.read()
937     if result != "" and logger:
938         logger.debug(result)
939     if p == 0:
940         return True
941     else:
942         if logger:
943             logger.error("Error when executing command %s" % cmd)
944         if exit_on_error:
945             exit(-1)
946         return False