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