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