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