Merge "Refactor run_rally-cert.py"
[functest.git] / testcases / vIMS / CI / vIMS.py
1 #!/usr/bin/python
2 # coding: utf8
3 #######################################################################
4 #
5 #   Copyright (c) 2015 Orange
6 #   valentin.boucher@orange.com
7 #
8 # All rights reserved. This program and the accompanying materials
9 # are made available under the terms of the Apache License, Version 2.0
10 # which accompanies this distribution, and is available at
11 # http://www.apache.org/licenses/LICENSE-2.0
12 ########################################################################
13
14 import os, time, subprocess, logging, argparse, yaml, pprint, sys, shutil, json, datetime
15 from git import Repo
16 import keystoneclient.v2_0.client as ksclient
17 import glanceclient.client as glclient
18 import novaclient.client as nvclient
19 from neutronclient.v2_0 import client as ntclient
20
21 import urllib
22 pp = pprint.PrettyPrinter(indent=4)
23
24
25 parser = argparse.ArgumentParser()
26 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
27 parser.add_argument("-r", "--report",
28                     help="Create json result file",
29                     action="store_true")
30 args = parser.parse_args()
31
32
33 """ logging configuration """
34 logger = logging.getLogger('vIMS')
35 logger.setLevel(logging.DEBUG)
36
37 ch = logging.StreamHandler()
38 if args.debug:
39     ch.setLevel(logging.DEBUG)
40 else:
41     ch.setLevel(logging.INFO)
42 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
43 ch.setFormatter(formatter)
44 logger.addHandler(ch)
45
46 REPO_PATH=os.environ['repos_dir']+'/functest/'
47 if not os.path.exists(REPO_PATH):
48     logger.error("Functest repository directory not found '%s'" % REPO_PATH)
49     exit(-1)
50 sys.path.append(REPO_PATH + "testcases/")
51 import functest_utils
52
53 with open(REPO_PATH + "testcases/config_functest.yaml") as f:
54     functest_yaml = yaml.safe_load(f)
55 f.close()
56
57 # Cloudify parameters
58 VIMS_DIR = REPO_PATH + functest_yaml.get("general").get("directories").get("dir_vIMS")
59 VIMS_DATA_DIR = functest_yaml.get("general").get("directories").get("dir_vIMS_data")+"/"
60 VIMS_TEST_DIR = functest_yaml.get("general").get("directories").get("dir_repo_vims_test")+"/"
61 TEST_DB = functest_yaml.get("results").get("test_db_url")
62
63 TENANT_NAME = functest_yaml.get("vIMS").get("general").get("tenant_name")
64 TENANT_DESCRIPTION = functest_yaml.get("vIMS").get("general").get("tenant_description")
65 BASE_IMAGE_URL = functest_yaml.get("vIMS").get("general").get("base_image_url")
66 BASE_IMAGE_NAME = functest_yaml.get("vIMS").get("general").get("base_image_name")
67 GLANCE_IMAGE_NAME = functest_yaml.get("vIMS").get("cloudify").get("inputs").get("image_id")
68
69 CFY_MANAGER_BLUEPRINT = functest_yaml.get("vIMS").get("cloudify").get("blueprint")
70 CFY_INPUTS =  functest_yaml.get("vIMS").get("cloudify").get("inputs")
71 CFY_INPUTS_PATH =  functest_yaml.get("vIMS").get("cloudify").get("inputs_path")
72
73 CW_BLUEPRINT = functest_yaml.get("vIMS").get("clearwater").get("blueprint")
74 CW_DEPLOYMENT_NAME = functest_yaml.get("vIMS").get("clearwater").get("deployment-name")
75 CW_INPUTS =  functest_yaml.get("vIMS").get("clearwater").get("inputs")
76 CW_DOMAIN_NAME =  functest_yaml.get("vIMS").get("clearwater").get("inputs").get("public_domain")
77
78 CFY_DEPLOYMENT_DURATION = 0
79 CW_DEPLOYMENT_DURATION = 0
80
81
82 def pMsg(value):
83     """pretty printing"""
84     pp.pprint(value)
85
86 def download_and_add_image_on_glance(glance, image_name, image_url):
87     dest_path = VIMS_DATA_DIR + "tmp/"
88     if not os.path.exists(dest_path):
89         os.makedirs(dest_path)
90     file_name = image_url.rsplit('/')[-1]
91     if not functest_utils.download_url(image_url, dest_path):
92         logger.error("Failed to download image %s" %file_name)
93         return False
94
95     image = functest_utils.create_glance_image(glance, image_name, dest_path + file_name)
96     if not image:
97         logger.error("Failed to upload image on glance")
98         return False
99
100     return image
101
102 def download_blueprints(blueprint_url, branch, dest_path):
103     if os.path.exists(dest_path):
104         shutil.rmtree(dest_path)
105     try:
106         Repo.clone_from(blueprint_url, dest_path, branch=branch)
107         return True
108     except:
109         return False
110
111 def initialize_deployments():
112     if not os.path.exists(VIMS_DATA_DIR):
113         os.makedirs(VIMS_DATA_DIR)
114
115     ks_creds = functest_utils.get_credentials("keystone")
116     nv_creds = functest_utils.get_credentials("nova")
117     nt_creds = functest_utils.get_credentials("neutron")
118
119     logger.info("Prepare OpenStack plateform (create tenant and user)")
120     keystone = ksclient.Client(**ks_creds)
121
122     user_id = functest_utils.get_user_id(keystone, ks_creds['username'])
123     if user_id == '':
124         logger.error("Error : Failed to get id of %s user" %ks_creds['username'])
125         exit(-1)
126
127     tenant_id = functest_utils.create_tenant(keystone, TENANT_NAME, TENANT_DESCRIPTION)
128     if tenant_id == '':
129         logger.error("Error : Failed to create %s tenant" %TENANT_NAME)
130         exit(-1)
131
132     role_name = "admin"
133     role_id = functest_utils.get_role_id(keystone, role_name)
134     if role_id == '':
135         logger.error("Error : Failed to get id for %s role" %role_name)
136
137     if not functest_utils.add_role_user(keystone, user_id, role_id, tenant_id):
138         logger.error("Error : Failed to add %s on tenant" %ks_creds['username'])
139
140     user_id = functest_utils.create_user(keystone, TENANT_NAME, TENANT_NAME, None, tenant_id)
141     if user_id == '':
142         logger.error("Error : Failed to create %s user" %TENANT_NAME)
143
144     logger.info("Update OpenStack creds informations")
145     ks_creds.update({
146         "username": TENANT_NAME,
147         "password": TENANT_NAME,
148         "tenant_name": TENANT_NAME,
149         })
150
151     nt_creds.update({
152         "tenant_name": TENANT_NAME,
153         })
154
155     nv_creds.update({
156         "project_id": TENANT_NAME,
157         })
158
159     logger.info("Upload ubuntu image if it doesn't exist")
160     glance_endpoint = keystone.service_catalog.url_for(service_type='image',
161                                                    endpoint_type='publicURL')
162     glance = glclient.Client(1, glance_endpoint, token=keystone.auth_token)
163
164     image_id = functest_utils.get_image_id(glance, BASE_IMAGE_NAME)
165     if image_id == '':
166         logger.info("""%s image doesn't exist on glance repository.
167                         Try downloading this image and upload on glance !""" %BASE_IMAGE_NAME)
168         image_id = download_and_add_image_on_glance(glance, BASE_IMAGE_NAME, BASE_IMAGE_URL)
169
170     if image_id == '':
171         logger.error("Error : Failed to find or upload required OS image for this deployment" %flavor_name)
172         exit(-1)
173
174     logger.info("Collect flavor id for cloudify and clearwater VMs")
175     nova = nvclient.Client("2", **nv_creds)
176
177     flavor_name = "m1.small"
178     flavor_id = functest_utils.get_flavor_id(nova, flavor_name)
179     if flavor_id == '':
180         logger.error("Failed to find %s flavor. Try with ram range requirement !" %flavor_name)
181         flavor_id = get_flavor_id_by_ram_range(nova, 1792, 2048)
182
183     if flavor_id == '':
184         logger.error("Failed to find required flavor for this deployment" %flavor_name)
185         exit(-1)
186
187     logger.info("Update security group quota for this tenant")
188     neutron = ntclient.Client(**nt_creds)
189     if not functest_utils.update_sg_quota(neutron, tenant_id, 50, 100):
190         logger.error("Failed to update security group quota for tenant %s" %TENANT_NAME)
191         exit(-1)
192
193     ext_net = functest_utils.get_external_net(neutron)
194     if not ext_net:
195         logger.error("Failed to get external network")
196         exit(-1)
197
198     logger.info("Update inputs informations")
199     CFY_INPUTS['image_id'] = image_id
200     CFY_INPUTS['flavor_id'] = flavor_id
201     CFY_INPUTS['external_network_name'] = ext_net
202
203     CW_INPUTS['image_id'] = image_id
204     CW_INPUTS['flavor_id'] = flavor_id
205     CW_INPUTS['external_network_name'] = ext_net
206
207     CFY_INPUTS['keystone_username'] = ks_creds['username']
208     CFY_INPUTS['keystone_password'] = ks_creds['password']
209     CFY_INPUTS['keystone_url'] = ks_creds['auth_url']
210     CFY_INPUTS['keystone_tenant_name'] = ks_creds['tenant_name']
211
212     logger.info("Prepare virtualenv for cloudify-cli")
213     cmd = "chmod +x " + VIMS_DIR + "create_venv.sh"
214     functest_utils.execute_command(cmd,logger)
215     cmd = VIMS_DIR + "create_venv.sh " + VIMS_DATA_DIR
216     functest_utils.execute_command(cmd,logger)
217
218 def cleanup_deployments():
219     ks_creds = functest_utils.get_credentials("keystone")
220
221     keystone = ksclient.Client(**ks_creds)
222
223     logger.info("Removing %s tenant .." %CFY_INPUTS['keystone_tenant_name'])
224     tenant_id = functest_utils.get_tenant_id(keystone, CFY_INPUTS['keystone_tenant_name'])
225     if tenant_id == '':
226         logger.error("Error : Failed to get id of %s tenant" %CFY_INPUTS['keystone_tenant_name'])
227     else:
228         if not functest_utils.delete_tenant(keystone, tenant_id):
229             logger.error("Error : Failed to remove %s tenant" %CFY_INPUTS['keystone_tenant_name'])
230
231     logger.info("Removing %s user .." %CFY_INPUTS['keystone_username'])
232     user_id = functest_utils.get_user_id(keystone, CFY_INPUTS['keystone_username'])
233     if user_id == '':
234         logger.error("Error : Failed to get id of %s user" %CFY_INPUTS['keystone_username'])
235     else:
236         if not functest_utils.delete_user(keystone, user_id):
237             logger.error("Error : Failed to remove %s user" %CFY_INPUTS['keystone_username'])
238
239 def deploy_cloudify_manager():
240
241     logger.info("Downloading the cloudify manager server blueprint")
242     download_result = download_blueprints(CFY_MANAGER_BLUEPRINT['url'],
243                                                         CFY_MANAGER_BLUEPRINT['branch'],
244                                                         VIMS_DATA_DIR + 'cloudify-manager-blueprint/')
245
246     if not download_result:
247         logger.error("Failed to download manager blueprint")
248         exit(-1)
249
250     logger.info("Writing the inputs file")
251     with open( VIMS_DATA_DIR + 'cloudify-manager-blueprint/' + CFY_INPUTS_PATH, "w") as f:
252         f.write(yaml.dump(CFY_INPUTS, default_style='"') )
253     f.close()
254
255     start_time_ts = time.time()
256     end_time_ts = start_time_ts
257     logger.info("Cloudify deployment Start Time:'%s'" % (
258         datetime.datetime.fromtimestamp(start_time_ts).strftime(
259             '%Y-%m-%d %H:%M:%S')))
260
261     logger.info("Launching the cloudify-manager deployment")
262     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
263     script += "cd " + VIMS_DATA_DIR + "; "
264     script += "cfy init -r; "
265     script += "cd cloudify-manager-blueprint/openstack; "
266     script += "cfy local create-requirements -o requirements.txt -p openstack-manager-blueprint.yaml; "
267     script += "pip install -r requirements.txt; "
268     script += "cfy bootstrap --install-plugins -p openstack-manager-blueprint.yaml -i inputs.yaml; "
269     cmd = "/bin/bash -c '" + script + "'"
270     functest_utils.execute_command(cmd, logger)
271
272     logger.info("Cloudify-manager server is UP !")
273
274     global CFY_DEPLOYMENT_DURATION
275     end_time_ts = time.time()
276     CFY_DEPLOYMENT_DURATION = round(end_time_ts - start_time_ts, 1)
277     logger.info("Cloudify deployment duration:'%s'" %CFY_DEPLOYMENT_DURATION)
278
279 def undeploy_cloudify_manager():
280
281     logger.info("Launching the cloudify-manager undeployment")
282     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
283     script += "cd " + VIMS_DATA_DIR + "; "
284     script += "cfy teardown -f; "
285     cmd = "/bin/bash -c '" + script + "'"
286     functest_utils.execute_command(cmd, logger)
287
288     logger.info("Cloudify-manager server has been successfully removed!")
289
290 def deploy_clearwater():
291
292     logger.info("Downloading the {0} blueprint".format(CW_BLUEPRINT['file_name']))
293     download_result = download_blueprints(CW_BLUEPRINT['url'], CW_BLUEPRINT['branch'],
294                                               VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'])
295
296     if not download_result:
297         logger.error("Failed to download blueprint {0}".format(CW_BLUEPRINT['file_name']))
298         exit(-1)
299
300     logger.info("Writing the inputs file")
301     with open(VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'] + "/inputs.yaml", "w") as f:
302         f.write(yaml.dump(CW_INPUTS, default_style='"') )
303     f.close()
304
305     time.sleep(30)
306
307     start_time_ts = time.time()
308     end_time_ts = start_time_ts
309     logger.info("vIMS VNF deployment Start Time:'%s'" % (
310         datetime.datetime.fromtimestamp(start_time_ts).strftime(
311             '%Y-%m-%d %H:%M:%S')))
312
313     logger.info("Launching the {0} deployment".format(CW_BLUEPRINT['name']))
314     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
315     script += "cd " + VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'] + "; "
316     script += "cfy blueprints upload -b " + CW_BLUEPRINT['name'] + " -p openstack-blueprint.yaml; "
317     script += "cfy deployments create -b " + CW_BLUEPRINT['name'] + " -d " + CW_DEPLOYMENT_NAME + " --inputs inputs.yaml; "
318     script += "cfy executions start -w install -d " + CW_DEPLOYMENT_NAME + " --timeout 1800; "
319
320     cmd = "/bin/bash -c '" + script + "'"
321     functest_utils.execute_command(cmd, logger)
322
323     logger.info("Clearwater vIMS is UP !")
324
325     global CW_DEPLOYMENT_DURATION
326     end_time_ts = time.time()
327     CW_DEPLOYMENT_DURATION = round(end_time_ts - start_time_ts, 1)
328     logger.info("vIMS VNF deployment duration:'%s'" %CW_DEPLOYMENT_DURATION)
329
330 def undeploy_clearwater():
331
332     logger.info("Launching the {0} undeployment".format(CW_BLUEPRINT['name']))
333     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
334     script += "cd " + VIMS_DATA_DIR + "; "
335     script += "cfy executions start -w uninstall -d " + CW_DEPLOYMENT_NAME + " --timeout 1800 ; "
336     script += "cfy deployments delete -d " + CW_DEPLOYMENT_NAME + "; "
337
338     cmd = "/bin/bash -c '" + script + "'"
339     functest_utils.execute_command(cmd, logger)
340
341 def test_clearwater():
342
343     time.sleep(180)
344
345     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
346     script += "cd " + VIMS_DATA_DIR + "; "
347     script += "cfy deployments outputs -d " + CW_DEPLOYMENT_NAME + " | grep Value: | sed \"s/ *Value: //g\";"
348     cmd = "/bin/bash -c '" + script + "'"
349
350     try:
351         logger.debug("Trying to get clearwater nameserver IP ... ")
352         dns_ip = os.popen(cmd).read()
353         dns_ip = dns_ip.splitlines()[0]
354     except:
355         logger.error("Unable to retrieve the IP of the DNS server !")
356
357     start_time_ts = time.time()
358     end_time_ts = start_time_ts
359     logger.info("vIMS functional test Start Time:'%s'" % (
360         datetime.datetime.fromtimestamp(start_time_ts).strftime(
361             '%Y-%m-%d %H:%M:%S')))
362
363     if dns_ip != "":
364         script = 'echo -e "nameserver ' + dns_ip + '\nnameserver 8.8.8.8\nnameserver 8.8.4.4" > /etc/resolv.conf; '
365         script += 'source /etc/profile.d/rvm.sh; '
366         script += 'cd ' + VIMS_TEST_DIR + '; '
367         script += 'rake test[' + CW_INPUTS["public_domain"] + '] SIGNUP_CODE="secret"'
368
369         cmd = "/bin/bash -c '" + script + "'"
370         output_file = "output.txt"
371         f = open(output_file, 'w+')
372         p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT)
373         f.close()
374         end_time_ts = time.time()
375         duration = round(end_time_ts - start_time_ts, 1)
376         logger.info("vIMS functional test duration:'%s'" %duration)
377         f = open(output_file, 'r')
378         result = f.read()
379         if result != "" and logger:
380             logger.debug(result)
381
382         vims_test_result=""
383         try:
384             logger.debug("Trying to load test results")
385             with open(VIMS_TEST_DIR + "temp.json") as f:
386                 vims_test_result = json.load(f)
387             f.close()
388         except:
389             logger.error("Unable to retrieve test results")
390
391         if vims_test_result != "" & args.report:
392             logger.debug("Push result into DB")
393             logger.debug("Pushing results to DB....")
394             git_version = functest_utils.get_git_branch(REPO_PATH)
395             functest_utils.push_results_to_db(db_url=TEST_DB, case_name="vIMS",
396                         logger=logger, pod_name="opnfv-jump-2", git_version=git_version,
397                         payload={'orchestrator':{'duration': CFY_DEPLOYMENT_DURATION,
398                         'result': ""},
399                         'vIMS': {'duration': CW_DEPLOYMENT_DURATION,
400                         'result': ""},
401                         'sig_test': {'duration': duration,
402                         'result': vims_test_result}})
403         try:
404             os.remove(VIMS_TEST_DIR + "temp.json")
405         except:
406             logger.error("Deleting file failed")
407
408 def main():
409     initialize_deployments()
410     deploy_cloudify_manager()
411     deploy_clearwater()
412
413     test_clearwater()
414
415     undeploy_clearwater()
416     undeploy_cloudify_manager()
417     cleanup_deployments()
418
419 if __name__ == '__main__':
420     main()