Add mention to apache 2 license in Functest files and remove unused files
[functest.git] / testcases / VIM / OpenStack / CI / libraries / run_tempest.py
1 #!/usr/bin/env python
2 #
3 # Description:
4 #    Runs tempest and pushes the results to the DB
5 #
6 # Authors:
7 #    morgan.richomme@orange.com
8 #    jose.lausuch@ericsson.com
9 #    viktor.tikkanen@nokia.com
10 #
11 # All rights reserved. This program and the accompanying materials
12 # are made available under the terms of the Apache License, Version 2.0
13 # which accompanies this distribution, and is available at
14 # http://www.apache.org/licenses/LICENSE-2.0
15 #
16 import argparse
17 import json
18 import logging
19 import os
20 import re
21 import requests
22 import subprocess
23 import sys
24 import yaml
25 import keystoneclient.v2_0.client as ksclient
26 from neutronclient.v2_0 import client as neutronclient
27
28 modes = ['full', 'smoke', 'baremetal', 'compute', 'data_processing',
29          'identity', 'image', 'network', 'object_storage', 'orchestration',
30          'telemetry', 'volume', 'custom']
31
32 """ tests configuration """
33 parser = argparse.ArgumentParser()
34 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
35 parser.add_argument("-m", "--mode", help="Tempest test mode [smoke, all]",
36                     default="smoke")
37 parser.add_argument("-r", "--report",
38                     help="Create json result file",
39                     action="store_true")
40
41 args = parser.parse_args()
42
43 """ logging configuration """
44 logger = logging.getLogger('run_tempest')
45 logger.setLevel(logging.DEBUG)
46
47 ch = logging.StreamHandler()
48 if args.debug:
49     ch.setLevel(logging.DEBUG)
50 else:
51     ch.setLevel(logging.INFO)
52
53 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
54 ch.setFormatter(formatter)
55 logger.addHandler(ch)
56
57 REPO_PATH=os.environ['repos_dir']+'/functest/'
58 if not os.path.exists(REPO_PATH):
59     logger.error("Functest repository directory not found '%s'" % REPO_PATH)
60     exit(-1)
61 sys.path.append(REPO_PATH + "testcases/")
62 import functest_utils
63
64 with open("/home/opnfv/functest/conf/config_functest.yaml") as f:
65     functest_yaml = yaml.safe_load(f)
66 f.close()
67 TEST_DB = functest_yaml.get("results").get("test_db_url")
68
69 MODE = "smoke"
70 TENANT_NAME = functest_yaml.get("tempest").get("identity").get("tenant_name")
71 TENANT_DESCRIPTION = functest_yaml.get("tempest").get("identity").get("tenant_description")
72 USER_NAME = functest_yaml.get("tempest").get("identity").get("user_name")
73 USER_PASSWORD = functest_yaml.get("tempest").get("identity").get("user_password")
74 DEPLOYMENT_MAME = functest_yaml.get("rally").get("deployment_name")
75 RALLY_INSTALLATION_DIR = functest_yaml.get("general").get("directories").get("dir_rally_inst")
76
77
78 def get_info(file_result):
79     test_run = ""
80     duration = ""
81     test_failed = ""
82
83     p = subprocess.Popen('cat tempest.log',
84                          shell=True, stdout=subprocess.PIPE,
85                          stderr=subprocess.STDOUT)
86     for line in p.stdout.readlines():
87         # print line,
88         if (len(test_run) < 1):
89             test_run = re.findall("[0-9]*\.[0-9]*s", line)
90         if (len(duration) < 1):
91             duration = re.findall("[0-9]*\ tests", line)
92         regexp = r"(failures=[0-9]+)"
93         if (len(test_failed) < 1):
94             test_failed = re.findall(regexp, line)
95
96     retval = p.wait()
97
98     logger.debug("test_run:"+test_run)
99     logger.debug("duration:"+duration)
100
101
102 def push_results_to_db(payload, module, pod_name):
103
104     # TODO move DB creds into config file
105     url = TEST_DB + "/results"
106     installer = functest_utils.get_installer_type(logger)
107     git_version = functest_utils.get_git_branch(REPO_PATH)
108     logger.info("Pushing results to DB: '%s'." % url)
109
110     params = {"project_name": "functest", "case_name": "Tempest",
111               "pod_name": str(pod_name), 'installer': installer,
112               "version": git_version, 'details': payload}
113     headers = {'Content-Type': 'application/json'}
114
115     r = requests.post(url, data=json.dumps(params), headers=headers)
116     logger.debug(r)
117
118
119 def create_tempest_resources():
120     ks_creds = functest_utils.get_credentials("keystone")
121     logger.info("Creating tenant and user for Tempest suite")
122     keystone = ksclient.Client(**ks_creds)
123     tenant_id = functest_utils.create_tenant(keystone, TENANT_NAME, TENANT_DESCRIPTION)
124     if tenant_id == '':
125         logger.error("Error : Failed to create %s tenant" %TENANT_NAME)
126
127     user_id = functest_utils.create_user(keystone, USER_NAME, USER_PASSWORD, None, tenant_id)
128     if user_id == '':
129         logger.error("Error : Failed to create %s user" %USER_NAME)
130
131
132 def free_tempest_resources():
133     ks_creds = functest_utils.get_credentials("keystone")
134     logger.info("Deleting tenant and user for Tempest suite)")
135     keystone = ksclient.Client(**ks_creds)
136
137     user_id = functest_utils.get_user_id(keystone, USER_NAME)
138     if user_id == '':
139         logger.error("Error : Failed to get id of %s user" % USER_NAME)
140     else:
141         if not functest_utils.delete_user(keystone, user_id):
142             logger.error("Error : Failed to delete %s user" % USER_NAME)
143
144     tenant_id = functest_utils.get_tenant_id(keystone, TENANT_NAME)
145     if tenant_id == '':
146         logger.error("Error : Failed to get id of %s tenant" % TENANT_NAME)
147     else:
148         if not functest_utils.delete_tenant(keystone, tenant_id):
149             logger.error("Error : Failed to delete %s tenant" % TENANT_NAME)
150
151
152 def configure_tempest():
153     """
154     Add/update needed parameters into tempest.conf file generated by Rally
155     """
156
157     logger.debug("Generating tempest.conf file...")
158     cmd = "rally verify genconfig"
159     functest_utils.execute_command(cmd,logger)
160
161     logger.debug("Resolving deployment UUID...")
162     cmd = "rally deployment list | awk '/"+DEPLOYMENT_MAME+"/ {print $2}'"
163     p = subprocess.Popen(cmd, shell=True,
164                          stdout=subprocess.PIPE,
165                          stderr=subprocess.STDOUT);
166     deployment_uuid = p.stdout.readline().rstrip()
167     if deployment_uuid == "":
168         logger.debug("   Rally deployment NOT found")
169         return False
170
171     logger.debug("Finding tempest.conf file...")
172     tempest_conf_file = RALLY_INSTALLATION_DIR+"/tempest/for-deployment-" \
173                         +deployment_uuid+"/tempest.conf"
174     if tempest_conf_file == "":
175         logger.debug("   Tempest configuration file NOT found")
176         return False
177
178     logger.debug("  Updating fixed_network_name...")
179     private_net_name = ""
180     creds_neutron = functest_utils.get_credentials("neutron")
181     neutron_client = neutronclient.Client(**creds_neutron)
182     private_net = functest_utils.get_private_net(neutron_client)
183     if private_net is None:
184         logger.error("No shared private networks found.")
185     else:
186         private_net_name = private_net['name']
187     cmd = "crudini --set "+tempest_conf_file+" compute fixed_network_name " \
188           +private_net_name
189     functest_utils.execute_command(cmd,logger)
190
191     logger.debug("  Updating non-admin credentials...")
192     cmd = "crudini --set "+tempest_conf_file+" identity tenant_name " \
193           +TENANT_NAME
194     functest_utils.execute_command(cmd,logger)
195     cmd = "crudini --set "+tempest_conf_file+" identity username " \
196           +USER_NAME
197     functest_utils.execute_command(cmd,logger)
198     cmd = "crudini --set "+tempest_conf_file+" identity password " \
199           +USER_PASSWORD
200     functest_utils.execute_command(cmd,logger)
201
202     return True
203
204
205 def run_tempest(OPTION):
206     #
207     # the "main" function of the script which launches Rally to run Tempest
208     # :param option: tempest option (smoke, ..)
209     # :return: void
210     #
211     logger.info("Starting Tempest test suite: '%s'." % OPTION)
212     cmd_line = "rally verify start "+OPTION
213     logger.debug('Executing command : {}'.format(cmd_line))
214     subprocess.call(cmd_line, shell=True, stderr=subprocess.STDOUT)
215
216     cmd_line = "rally verify list"
217     logger.debug('Executing command : {}'.format(cmd_line))
218     cmd = os.popen(cmd_line)
219     output = (((cmd.read()).splitlines()[3]).replace(" ", "")).split("|")
220     # Format:
221     # | UUID | Deployment UUID | smoke | tests | failures | Created at |
222     # Duration | Status  |
223     num_tests = output[4]
224     num_failures = output[5]
225     time_start = output[6]
226     duration = output[7]
227     # Compute duration (lets assume it does not take more than 60 min)
228     dur_min=int(duration.split(':')[1])
229     dur_sec_float=float(duration.split(':')[2])
230     dur_sec_int=int(round(dur_sec_float,0))
231     dur_sec_int = dur_sec_int + 60 * dur_min
232
233     # Generate json results for DB
234     json_results = {"timestart": time_start, "duration": dur_sec_int,
235                     "tests": int(num_tests), "failures": int(num_failures)}
236     logger.info("Results: "+str(json_results))
237     pod_name = functest_utils.get_pod_name(logger)
238
239     # Push results in payload of testcase
240     if args.report:
241         logger.debug("Push result into DB")
242         push_results_to_db(json_results, MODE, pod_name)
243
244
245 def main():
246     global MODE
247     if not (args.mode):
248         MODE = "smoke"
249     elif not (args.mode in modes):
250         logger.error("Tempest mode not valid. Possible values are:\n"
251                      + str(modes))
252         exit(-1)
253     elif (args.mode == 'custom'):
254         MODE = "--tests-file "+REPO_PATH+"testcases/VIM/OpenStack/CI/custom_tests/test_list.txt"
255     else:
256         MODE = "--set "+args.mode
257
258     create_tempest_resources()
259     configure_tempest()
260     run_tempest(MODE)
261     free_tempest_resources()
262
263
264 if __name__ == '__main__':
265     main()