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