change path to create rally forlder and scenarios+results subfolders, change image...
[functest.git] / testcases / config_functest.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2015 Ericsson
4 # jose.lausuch@ericsson.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 re, json, os, urllib2, argparse, logging, shutil, subprocess
12 from git import Repo
13
14 actions = ['start', 'check', 'clean']
15
16 """ global variables """
17 functest_dir = os.environ['HOME'] + '/.functest/'
18 image_url = 'https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img'
19 #image_url = 'http://download.cirros-cloud.net/0.3.0/cirros-0.3.0-i386-disk.img'
20 image_disk_format = 'raw'
21 image_name = image_url.rsplit('/')[-1]
22 image_path = functest_dir + image_name
23 rally_repo_dir = functest_dir + "Rally_repo/"
24 rally_test_dir = functest_dir + "Rally_test/"
25 rally_installation_dir = os.environ['HOME'] + "/.rally"
26
27
28
29 parser = argparse.ArgumentParser()
30 parser.add_argument("action", help="Possible actions are: '{d[0]}|{d[1]}|{d[2]}' ".format(d=actions))
31 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
32 args = parser.parse_args()
33
34
35 """ logging configuration """
36 logger = logging.getLogger('config_functest')
37 logger.setLevel(logging.DEBUG)
38
39 ch = logging.StreamHandler()
40 if args.debug:
41     ch.setLevel(logging.DEBUG)
42 else:
43     ch.setLevel(logging.INFO)
44
45 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
46 ch.setFormatter(formatter)
47 logger.addHandler(ch)
48
49
50
51 def config_functest_start():
52     """
53     Start the functest environment installation
54     """
55     if config_functest_check():
56         logger.info("Functest environment already installed in %s. Nothing to do." %functest_dir)
57         exit(0)
58     elif not check_internet_connectivity():
59         logger.error("There is no Internet connectivity. Please check the network configuration.")
60         exit(-1)
61     elif not check_credentials():
62         logger.error("Please source the openrc credentials and run the script again.")
63         #TODO: source the credentials in this script
64         exit(-1)
65     else:
66         config_functest_clean()
67
68         logger.info("Starting installationg of functest environment in %s" %functest_dir)
69         os.makedirs(functest_dir)
70         if not os.path.exists(functest_dir):
71             logger.error("There has been a problem while creating the environment directory.")
72             exit(-1)
73
74
75         logger.info("Installing Rally...")
76         if not install_rally():
77             logger.error("There has been a problem while installing Rally.")
78             config_functest_clean()
79             exit(-1)
80
81         logger.info("Installing Robot...")
82         if not install_robot():
83             logger.error("There has been a problem while installing Robot.")
84             config_functest_clean()
85             exit(-1)
86
87         logger.info("Donwloading test scripts and scenarios...")
88         if not download_tests():
89             logger.error("There has been a problem while downloading the test scripts and scenarios.")
90             config_functest_clean()
91             exit(-1)
92
93         logger.info("Donwloading image...")
94         if not download_url_with_progress(image_url, functest_dir):
95             logger.error("There has been a problem while downloading the image.")
96             config_functest_clean()
97             exit(-1)
98
99         logger.info("Creating Glance image: %s ..." %image_name)
100         if not create_glance_image(image_path,image_name,image_disk_format):
101             logger.error("There has been a problem while creating the Glance image.")
102             config_functest_clean()
103             exit(-1)
104         
105         exit(0)
106
107
108
109 def config_functest_check():
110     """
111     Check if the functest environment is installed
112     """
113     logger.info("Checking current functest configuration...")
114     if os.path.exists(functest_dir) and os.path.exists(rally_installation_dir):
115         logger.info("Functest environment directory found in %s" %functest_dir)
116         return True
117     else:
118         logger.info("Functest environment directory not found")
119         return False
120
121
122
123 def config_functest_clean():
124     """
125     Clean the existing functest environment
126     """
127     logger.info("Removing current functest environment...")
128     if os.path.exists(rally_installation_dir):
129         logger.debug("Removing rally installation directory %s" % rally_installation_dir)
130         shutil.rmtree(rally_installation_dir,ignore_errors=True)
131         
132     if os.path.exists(functest_dir):
133         logger.debug("Removing functest directory %s" % functest_dir)
134         cmd = "sudo rm -rf " + functest_dir #need to be sudo, not possible with rmtree
135         execute_command(cmd)
136     
137     logger.debug("Deleting glance images")
138     cmd = "glance image-list | grep "+image_name+" | cut -c3-38"
139     p = os.popen(cmd,"r")
140     
141     #while image_id = p.readline() 
142     for image_id in p.readlines():
143         cmd = "glance image-delete " + image_id
144         execute_command(cmd)
145         
146     return True
147
148
149 def install_rally():
150     if check_rally():
151         logger.info("Rally is already installed.")
152     else:
153         logger.debug("Cloning repository...")
154         url = "https://git.openstack.org/openstack/rally"
155         Repo.clone_from(url, rally_repo_dir)
156
157         logger.debug("Executing %s./install_rally.sh..." %rally_repo_dir)
158         install_script = rally_repo_dir + "install_rally.sh"
159         cmd = 'sudo ' + install_script
160         execute_command(cmd)
161         #subprocess.call(['sudo', install_script])
162
163         logger.debug("Creating Rally environment...")
164         cmd = "rally deployment create --fromenv --name=opnfv-arno-rally"
165         execute_command(cmd)
166
167         logger.debug("Installing tempest...")
168         cmd = "rally-manage tempest install"
169         execute_command(cmd)
170
171         cmd = "rally deployment check"
172         execute_command(cmd)
173         #TODO: check that everything is 'Available' and warn if not
174
175         cmd = "rally show images"
176         execute_command(cmd)
177
178         cmd = "rally show flavors"
179         execute_command(cmd)
180
181     return True
182
183
184
185 def check_rally():
186     """
187     Check if Rally is installed and properly configured
188     """
189     if os.path.exists(os.environ['HOME']+"/.rally/"):
190         #TODO: do a more consistent check, for example running the comand rally deployment check
191         return True
192     else:
193         return False
194
195
196 def install_robot():
197     cmd = "sudo pip install requests"
198     execute_command(cmd)
199     cmd = "sudo pip install robotframework"
200     execute_command(cmd)
201     cmd = "sudo pip install robotframework-sshlibrary"
202     execute_command(cmd)
203     cmd = "sudo pip install robotframework-requests"
204     execute_command(cmd)
205     #cmd = "mkvirtualenv robot"
206     #execute_command(cmd)
207     return True
208
209
210 def check_credentials():
211     """
212     Check if the OpenStack credentials (openrc) are sourced
213     """
214     #TODO: there must be a short way to do this, doing if os.environ["something"] == "" throws an error
215     try:
216        os.environ['OS_AUTH_URL']
217     except KeyError:
218         return False
219     try:
220        os.environ['OS_USERNAME']
221     except KeyError:
222         return False
223     try:
224        os.environ['OS_PASSWORD']
225     except KeyError:
226         return False
227     try:
228        os.environ['OS_TENANT_NAME']
229     except KeyError:
230         return False
231     try:
232        os.environ['OS_REGION_NAME']
233     except KeyError:
234         return False
235     return True
236
237
238 def download_tests():
239     vPing_dir = functest_dir + "vPing/"
240     odl_dir = functest_dir + "ODL/"
241     bench_tests_dir = rally_test_dir + "scenarios/"
242
243     os.makedirs(vPing_dir)
244     os.makedirs(odl_dir)
245     os.makedirs(bench_tests_dir)
246
247     logger.info("Downloading vPing test...")
248     vPing_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/vPing/CI/libraries/vPing.py'
249     if not download_url(vPing_url,vPing_dir):
250         return False
251     
252     vPing_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/vPing/CI/libraries/vPing.py'
253     if not download_url(vPing_url,vPing_dir):
254         return False
255
256     logger.info("Downloading Rally bench tests...")
257     run_rally_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/VIM/OpenStack/CI/libraries/run_rally.py'
258     if not download_url(run_rally_url,rally_test_dir  ):
259         return False
260     
261     rally_bench_base_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/VIM/OpenStack/CI/suites/'
262     bench_tests = ['authenticate', 'cinder', 'glance', 'heat', 'keystone', 'neutron', 'nova', 'quotas', 'requests', 'tempest', 'vm']
263     for i in bench_tests:
264         rally_bench_url = rally_bench_base_url + "opnfv-" + i + ".json"
265         logger.debug("Downloading %s" %rally_bench_url)
266         if not download_url(rally_bench_url,bench_tests_dir):
267             return False
268
269     logger.info("Downloading OLD tests...")
270     odl_base_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/Controllers/ODL/CI/'
271     odl_tests = ['start_tests.sh', 'test_list.txt']
272     for i in odl_tests:
273         odl_url = odl_base_url + i
274         logger.debug("Downloading %s" %odl_url)
275         if not download_url(odl_url,odl_dir):
276             return False
277         
278     return True
279     #TODO: complete
280
281
282
283 def create_glance_image(path,name,disk_format):
284     """
285     Create a glance image given the absolute path of the image, its name and the disk format
286     """
287     cmd = "glance image-create --name "+name+" --is-public true --disk-format "+disk_format+" --container-format bare --file "+path
288     execute_command(cmd)
289     return True
290
291
292 def download_url(url, dest_path):
293     """
294     Download a file to a destination path given a URL
295     """
296     name = url.rsplit('/')[-1]
297     dest = dest_path + name
298     try:
299         response = urllib2.urlopen(url)
300     except (urllib2.HTTPError, urllib2.URLError):
301         logger.error("Error in fetching %s" %url)
302         return False
303
304     with open(dest, 'wb') as f:
305         f.write(response.read())
306     return True
307
308
309 def download_url_with_progress(url, dest_path):
310     """
311     Download a file to a destination path given a URL showing the progress
312     """
313     name = url.rsplit('/')[-1]
314     dest = dest_path + name
315     try:
316         response = urllib2.urlopen(url)
317     except (urllib2.HTTPError, urllib2.URLError):
318         logger.error("Error in fetching %s" %url)
319         return False
320
321     f = open(dest, 'wb')
322     meta = response.info()
323     file_size = int(meta.getheaders("Content-Length")[0])
324     logger.info("Downloading: %s Bytes: %s" %(dest, file_size))
325
326     file_size_dl = 0
327     block_sz = 8192
328     while True:
329         buffer = response.read(block_sz)
330         if not buffer:
331             break
332
333         file_size_dl += len(buffer)
334         f.write(buffer)
335         status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
336         status = status + chr(8)*(len(status)+1)
337         print status,
338
339     f.close()
340     print("\n")
341     return True
342
343
344 def check_internet_connectivity(url='http://www.google.com/'):
345     """
346     Check if there is access to the internet
347     """
348     try:
349         urllib2.urlopen(url, timeout=5)
350         return True
351     except urllib.request.URLError:
352         return False
353
354 def execute_command(cmd):
355     """
356     Execute Linux command
357     """
358     logger.debug('Executing command : {}'.format(cmd))
359     #p = os.popen(cmd,"r")
360     #logger.debug(p.read())
361     output_file = "/tmp/output.txt"
362     f = open(output_file, 'w+')
363     p = subprocess.call(cmd,shell=True, stdout=f, stderr=subprocess.STDOUT)
364     f.close()
365     f = open(output_file, 'r')
366     logger.debug(f.read())
367     #p = subprocess.call(cmd,shell=True);
368     if p == 0 :
369         return True
370     else:
371         logger.error("Error when executing command %s" %cmd)
372         exit(-1)
373
374
375
376
377 def main():
378     if not (args.action in actions):
379         logger.error('argument not valid')
380         exit(-1)
381
382     if args.action == "start":
383         config_functest_start()
384
385     if args.action == "check":
386         config_functest_check()
387
388     if args.action == "clean":
389         while True:
390             print("Are you sure? [y|n]")
391             answer = raw_input("")
392             if answer == "y":
393                 config_functest_clean()
394                 break
395             elif answer == "n":
396                 break
397             else:
398                 print("Invalid option.")
399     exit(0)
400
401
402 if __name__ == '__main__':
403     main()
404