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