Place config_functest.yaml outside the functest repo
[functest.git] / testcases / VIM / OpenStack / CI / libraries / run_rally-cert.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2015 Orange
4 # guyrodrigue.koffi@orange.com
5 # morgan.richomme@orange.com
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # 0.1 (05/2015) initial commit
12 # 0.2 (28/09/2015) extract Tempest, format json result, add ceilometer suite
13 # 0.3 (19/10/2015) remove Tempest from run_rally
14 # and push result into test DB
15 #
16
17 import re
18 import json
19 import os
20 import argparse
21 import logging
22 import yaml
23 import requests
24 import sys
25 import novaclient.v2.client as novaclient
26 from glanceclient import client as glanceclient
27 from keystoneclient.v2_0 import client as keystoneclient
28 from neutronclient.v2_0 import client as neutronclient
29
30 """ tests configuration """
31 tests = ['authenticate', 'glance', 'cinder', 'heat', 'keystone',
32          'neutron', 'nova', 'quotas', 'requests', 'vm', 'all']
33 parser = argparse.ArgumentParser()
34 parser.add_argument("repo_path", help="Path to the repository")
35 parser.add_argument("test_name",
36                     help="Module name to be tested. "
37                          "Possible values are : "
38                          "[ {d[0]} | {d[1]} | {d[2]} | {d[3]} | {d[4]} | "
39                          "{d[5]} | {d[6]} | {d[7]} | {d[8]} | {d[9]} | "
40                          "{d[10]} ] "
41                          "The 'all' value "
42                          "performs all possible test scenarios"
43                          .format(d=tests))
44
45 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
46 parser.add_argument("-r", "--report",
47                     help="Create json result file",
48                     action="store_true")
49 parser.add_argument("-s", "--smoke",
50                     help="Smoke test mode",
51                     action="store_true")
52
53 args = parser.parse_args()
54
55 client_dict = {}
56
57 sys.path.append(args.repo_path + "testcases/")
58 import functest_utils
59
60 """ logging configuration """
61 logger = logging.getLogger("run_rally")
62 logger.setLevel(logging.DEBUG)
63
64 ch = logging.StreamHandler()
65 if args.debug:
66     ch.setLevel(logging.DEBUG)
67 else:
68     ch.setLevel(logging.INFO)
69
70 formatter = logging.Formatter("%(asctime)s - %(name)s - "
71                               "%(levelname)s - %(message)s")
72 ch.setFormatter(formatter)
73 logger.addHandler(ch)
74
75 with open("/home/opnfv/functest/conf/config_functest.yaml") as f:
76     functest_yaml = yaml.safe_load(f)
77 f.close()
78
79 HOME = os.environ['HOME']+"/"
80 REPO_PATH = args.repo_path
81 ####todo:
82 #SCENARIOS_DIR = REPO_PATH + functest_yaml.get("general"). \
83 #    get("directories").get("dir_rally_scn")
84 SCENARIOS_DIR = REPO_PATH + "testcases/VIM/OpenStack/CI/rally_cert/"
85 ###
86 TEMPLATE_DIR = SCENARIOS_DIR + "scenario/templates"
87 SUPPORT_DIR = SCENARIOS_DIR + "scenario/support"
88 ###todo:
89 FLAVOR_NAME = "m1.tiny"
90 USERS_AMOUNT = 2
91 TENANTS_AMOUNT = 3
92 CONTROLLERS_AMOUNT = 2
93 ###
94 RESULTS_DIR = functest_yaml.get("general").get("directories"). \
95     get("dir_rally_res")
96 TEST_DB = functest_yaml.get("results").get("test_db_url")
97 FLOATING_NETWORK = functest_yaml.get("general"). \
98     get("openstack").get("neutron_public_net_name")
99 FLOATING_SUBNET_CIDR = functest_yaml.get("general"). \
100     get("openstack").get("neutron_public_subnet_cidr")
101 PRIVATE_NETWORK = functest_yaml.get("general"). \
102     get("openstack").get("neutron_private_net_name")
103
104 GLANCE_IMAGE_NAME = functest_yaml.get("general"). \
105     get("openstack").get("image_name")
106 GLANCE_IMAGE_FILENAME = functest_yaml.get("general"). \
107     get("openstack").get("image_file_name")
108 GLANCE_IMAGE_FORMAT = functest_yaml.get("general"). \
109     get("openstack").get("image_disk_format")
110 GLANCE_IMAGE_PATH = functest_yaml.get("general"). \
111     get("directories").get("dir_functest_data") + "/" + GLANCE_IMAGE_FILENAME
112
113
114 def push_results_to_db(payload):
115
116     url = TEST_DB + "/results"
117     installer = functest_utils.get_installer_type(logger)
118     git_version = functest_utils.get_git_branch(args.repo_path)
119     pod_name = functest_utils.get_pod_name(logger)
120     # TODO pod_name hardcoded, info shall come from Jenkins
121     params = {"project_name": "functest", "case_name": "Rally",
122               "pod_name": pod_name, "installer": installer,
123               "version": git_version, "details": payload}
124
125     headers = {'Content-Type': 'application/json'}
126     r = requests.post(url, data=json.dumps(params), headers=headers)
127     logger.debug(r)
128
129
130 def get_task_id(cmd_raw):
131     """
132     get task id from command rally result
133     :param cmd_raw:
134     :return: task_id as string
135     """
136     taskid_re = re.compile('^Task +(.*): started$')
137     for line in cmd_raw.splitlines(True):
138         line = line.strip()
139         match = taskid_re.match(line)
140         if match:
141             return match.group(1)
142     return None
143
144
145 def task_succeed(json_raw):
146     """
147     Parse JSON from rally JSON results
148     :param json_raw:
149     :return: Bool
150     """
151     rally_report = json.loads(json_raw)
152     rally_report = rally_report[0]
153     if rally_report is None:
154         return False
155     if rally_report.get('result') is None:
156         return False
157
158     for result in rally_report.get('result'):
159         if len(result.get('error')) > 0:
160             return False
161
162     return True
163
164
165 def build_task_args(test_file_name):
166     task_args = {'service_list': [test_file_name]}
167     task_args['smoke'] = args.smoke
168     task_args['image_name'] = GLANCE_IMAGE_NAME
169     task_args['flavor_name'] = FLAVOR_NAME
170     task_args['glance_image_location'] = GLANCE_IMAGE_PATH
171     task_args['floating_network'] = FLOATING_NETWORK
172     task_args['floating_subnet_cidr'] = FLOATING_SUBNET_CIDR
173     task_args['netid'] = functest_utils.get_network_id(client_dict['neutron'],
174                                     PRIVATE_NETWORK).encode('ascii', 'ignore')
175     task_args['tmpl_dir'] = TEMPLATE_DIR
176     task_args['sup_dir'] = SUPPORT_DIR
177     task_args['users_amount'] = USERS_AMOUNT
178     task_args['tenants_amount'] = TENANTS_AMOUNT
179     task_args['controllers_amount'] = CONTROLLERS_AMOUNT
180
181     return task_args
182
183
184 def run_task(test_name):
185     #
186     # the "main" function of the script who launch rally for a task
187     # :param test_name: name for the rally test
188     # :return: void
189     #
190
191     logger.info('starting {} test ...'.format(test_name))
192
193     task_file = '{}task.yaml'.format(SCENARIOS_DIR)
194     if not os.path.exists(task_file):
195         logger.error("Task file '%s' does not exist." % task_file)
196         exit(-1)
197
198     test_file_name = '{}opnfv-{}.yaml'.format(SCENARIOS_DIR + "scenario/", test_name)
199     if not os.path.exists(test_file_name):
200         logger.error("The scenario '%s' does not exist." % test_file_name)
201         exit(-1)
202
203     logger.debug('Scenario fetched from : {}'.format(test_file_name))
204
205     cmd_line = "rally task start --abort-on-sla-failure " + \
206                "--task {} ".format(task_file) + \
207                "--task-args \"{}\" ".format(build_task_args(test_name))
208     logger.debug('running command line : {}'.format(cmd_line))
209     cmd = os.popen(cmd_line)
210     task_id = get_task_id(cmd.read())
211     logger.debug('task_id : {}'.format(task_id))
212
213     if task_id is None:
214         logger.error("failed to retrieve task_id")
215         exit(-1)
216
217     # check for result directory and create it otherwise
218     if not os.path.exists(RESULTS_DIR):
219         logger.debug('does not exists, we create it'.format(RESULTS_DIR))
220         os.makedirs(RESULTS_DIR)
221
222     # write html report file
223     report_file_name = '{}opnfv-{}.html'.format(RESULTS_DIR, test_name)
224     cmd_line = "rally task report {} --out {}".format(task_id,
225                                                       report_file_name)
226
227     logger.debug('running command line : {}'.format(cmd_line))
228     os.popen(cmd_line)
229
230     # get and save rally operation JSON result
231     cmd_line = "rally task results %s" % task_id
232     logger.debug('running command line : {}'.format(cmd_line))
233     cmd = os.popen(cmd_line)
234     json_results = cmd.read()
235     with open('{}opnfv-{}.json'.format(RESULTS_DIR, test_name), 'w') as f:
236         logger.debug('saving json file')
237         f.write(json_results)
238
239     with open('{}opnfv-{}.json'
240               .format(RESULTS_DIR, test_name)) as json_file:
241         json_data = json.load(json_file)
242
243     # Push results in payload of testcase
244     if args.report:
245         logger.debug("Push result into DB")
246         push_results_to_db(json_data)
247
248     """ parse JSON operation result """
249     if task_succeed(json_results):
250         print 'Test OK'
251     else:
252         print 'Test KO'
253
254
255 def main():
256     # configure script
257     if not (args.test_name in tests):
258         logger.error('argument not valid')
259         exit(-1)
260
261     creds_nova = functest_utils.get_credentials("nova")
262     nova_client = novaclient.Client(**creds_nova)
263     creds_neutron = functest_utils.get_credentials("neutron")
264     neutron_client = neutronclient.Client(**creds_neutron)
265     creds_keystone = functest_utils.get_credentials("keystone")
266     keystone_client = keystoneclient.Client(**creds_keystone)
267     glance_endpoint = keystone_client.service_catalog.url_for(service_type='image',
268                                                    endpoint_type='publicURL')
269     glance_client = glanceclient.Client(1, glance_endpoint,
270                                         token=keystone_client.auth_token)
271
272     client_dict['neutron'] = neutron_client
273
274     logger.debug("Creating image '%s' from '%s'..." % (GLANCE_IMAGE_NAME, GLANCE_IMAGE_PATH))
275     image_id = functest_utils.create_glance_image(glance_client,
276                                             GLANCE_IMAGE_NAME,GLANCE_IMAGE_PATH)
277     if not image_id:
278         logger.error("Failed to create a Glance image...")
279         exit(-1)
280     # Check if the given image exists
281     try:
282         nova_client.images.find(name=GLANCE_IMAGE_NAME)
283         logger.info("Glance image found '%s'" % GLANCE_IMAGE_NAME)
284     except:
285         logger.error("ERROR: Glance image '%s' not found." % GLANCE_IMAGE_NAME)
286         logger.info("Available images are: ")
287         exit(-1)
288
289     if args.test_name == "all":
290         for test_name in tests:
291             if not (test_name == 'all' or
292                     test_name == 'vm'):
293                 print(test_name)
294                 run_task(test_name)
295     else:
296         print(args.test_name)
297         run_task(args.test_name)
298
299     logger.debug("Deleting image...")
300     if not functest_utils.delete_glance_image(nova_client, image_id):
301         logger.error("Error deleting the glance image")
302
303 if __name__ == '__main__':
304     main()