Merge "Update rally version"
[functest-xtesting.git] / testcases / vnf / vIMS / 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 datetime
15 import json
16 import os
17 import pprint
18 import subprocess
19 import time
20
21 import argparse
22 import keystoneclient.v2_0.client as ksclient
23 import novaclient.client as nvclient
24 import requests
25 from neutronclient.v2_0 import client as ntclient
26
27 import functest.utils.functest_logger as ft_logger
28 import functest.utils.functest_utils as ft_utils
29 import functest.utils.openstack_utils as os_utils
30 from clearwater import clearwater
31 from orchestrator import orchestrator
32
33 pp = pprint.PrettyPrinter(indent=4)
34
35
36 parser = argparse.ArgumentParser()
37 parser.add_argument("-d", "--debug", help="Debug mode", action="store_true")
38 parser.add_argument("-r", "--report",
39                     help="Create json result file",
40                     action="store_true")
41 parser.add_argument("-n", "--noclean",
42                     help="Don't clean the created resources for this test.",
43                     action="store_true")
44 args = parser.parse_args()
45
46 """ logging configuration """
47 logger = ft_logger.Logger("vIMS").getLogger()
48
49
50 # Cloudify parameters
51 VIMS_DIR = ft_utils.FUNCTEST_REPO + '/' + \
52            ft_utils.get_functest_config('general.directories.dir_vIMS')
53
54 VIMS_DATA_DIR = \
55     ft_utils.get_functest_config('general.directories.dir_vIMS_data') + \
56     '/'
57 VIMS_TEST_DIR = \
58     ft_utils.get_functest_config('general.directories.dir_repo_vims_test') + \
59     '/'
60 DB_URL = \
61     ft_utils.get_functest_config('results.test_db_url')
62
63 TENANT_NAME = \
64     ft_utils.get_functest_config('vIMS.general.tenant_name')
65 TENANT_DESCRIPTION = \
66     ft_utils.get_functest_config('vIMS.general.tenant_description')
67 IMAGES = \
68     ft_utils.get_functest_config('vIMS.general.images')
69
70 CFY_MANAGER_BLUEPRINT = \
71     ft_utils.get_functest_config('vIMS.cloudify.blueprint')
72 CFY_MANAGER_REQUIERMENTS = \
73     ft_utils.get_functest_config('vIMS.cloudify.requierments')
74 CFY_INPUTS = ft_utils.get_functest_config('vIMS.cloudify.inputs')
75
76 CW_BLUEPRINT = \
77     ft_utils.get_functest_config('vIMS.clearwater.blueprint')
78 CW_DEPLOYMENT_NAME = \
79     ft_utils.get_functest_config('vIMS.clearwater.deployment-name')
80 CW_INPUTS = \
81     ft_utils.get_functest_config('vIMS.clearwater.inputs')
82 CW_REQUIERMENTS = \
83     ft_utils.get_functest_config('vIMS.clearwater.requierments')
84
85 CFY_DEPLOYMENT_DURATION = 0
86 CW_DEPLOYMENT_DURATION = 0
87
88 TESTCASE_START_TIME = time.time()
89 RESULTS = {'orchestrator': {'duration': 0, 'result': ''},
90            'vIMS': {'duration': 0, 'result': ''},
91            'sig_test': {'duration': 0, 'result': ''}}
92
93
94 def download_and_add_image_on_glance(glance, image_name, image_url):
95     dest_path = VIMS_DATA_DIR + "tmp/"
96     if not os.path.exists(dest_path):
97         os.makedirs(dest_path)
98     file_name = image_url.rsplit('/')[-1]
99     if not ft_utils.download_url(image_url, dest_path):
100         logger.error("Failed to download image %s" % file_name)
101         return False
102
103     image = os_utils.create_glance_image(
104         glance, image_name, dest_path + file_name)
105     if not image:
106         logger.error("Failed to upload image on glance")
107         return False
108
109     return image
110
111
112 def step_failure(step_name, error_msg):
113     logger.error(error_msg)
114     set_result(step_name, 0, error_msg)
115     status = "FAIL"
116     # in case of failure starting and stoping time are not correct
117     stop_time = time.time()
118     if step_name == "sig_test":
119         status = "PASS"
120     ft_utils.push_results_to_db("functest",
121                                 "vims",
122                                 TESTCASE_START_TIME,
123                                 stop_time,
124                                 status,
125                                 RESULTS)
126     exit(-1)
127
128
129 def set_result(step_name, duration=0, result=""):
130     RESULTS[step_name] = {'duration': duration, 'result': result}
131
132
133 def test_clearwater():
134     script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
135     script += "cd " + VIMS_DATA_DIR + "; "
136     script += "cfy status | grep -Eo \"([0-9]{1,3}\.){3}[0-9]{1,3}\""
137     cmd = "/bin/bash -c '" + script + "'"
138
139     try:
140         logger.debug("Trying to get clearwater manager IP ... ")
141         mgr_ip = os.popen(cmd).read()
142         mgr_ip = mgr_ip.splitlines()[0]
143     except:
144         step_failure("sig_test", "Unable to retrieve the IP of the "
145                      "cloudify manager server !")
146
147     api_url = "http://" + mgr_ip + "/api/v2"
148     dep_outputs = requests.get(api_url + "/deployments/" +
149                                CW_DEPLOYMENT_NAME + "/outputs")
150     dns_ip = dep_outputs.json()['outputs']['dns_ip']
151     ellis_ip = dep_outputs.json()['outputs']['ellis_ip']
152
153     ellis_url = "http://" + ellis_ip + "/"
154     url = ellis_url + "accounts"
155
156     params = {"password": "functest",
157               "full_name": "opnfv functest user",
158               "email": "functest@opnfv.fr",
159               "signup_code": "secret"}
160
161     rq = requests.post(url, data=params)
162     i = 20
163     while rq.status_code != 201 and i > 0:
164         rq = requests.post(url, data=params)
165         i = i - 1
166         time.sleep(10)
167
168     if rq.status_code == 201:
169         url = ellis_url + "session"
170         rq = requests.post(url, data=params)
171         cookies = rq.cookies
172
173     url = ellis_url + "accounts/" + params['email'] + "/numbers"
174     if cookies != "":
175         rq = requests.post(url, cookies=cookies)
176         i = 24
177         while rq.status_code != 200 and i > 0:
178             rq = requests.post(url, cookies=cookies)
179             i = i - 1
180             time.sleep(25)
181
182     if rq.status_code != 200:
183         step_failure("sig_test", "Unable to create a number: %s"
184                      % rq.json()['reason'])
185
186     start_time_ts = time.time()
187     end_time_ts = start_time_ts
188     logger.info("vIMS functional test Start Time:'%s'" % (
189         datetime.datetime.fromtimestamp(start_time_ts).strftime(
190             '%Y-%m-%d %H:%M:%S')))
191     nameservers = ft_utils.get_resolvconf_ns()
192     resolvconf = ""
193     for ns in nameservers:
194         resolvconf += "\nnameserver " + ns
195
196     if dns_ip != "":
197         script = ('echo -e "nameserver ' + dns_ip + resolvconf +
198                   '" > /etc/resolv.conf; ')
199         script += 'source /etc/profile.d/rvm.sh; '
200         script += 'cd ' + VIMS_TEST_DIR + '; '
201         script += ('rake test[' + CW_INPUTS["public_domain"] +
202                    '] SIGNUP_CODE="secret"')
203
204         cmd = "/bin/bash -c '" + script + "'"
205         output_file = "output.txt"
206         f = open(output_file, 'w+')
207         subprocess.call(cmd, shell=True, stdout=f,
208                         stderr=subprocess.STDOUT)
209         f.close()
210         end_time_ts = time.time()
211         duration = round(end_time_ts - start_time_ts, 1)
212         logger.info("vIMS functional test duration:'%s'" % duration)
213         f = open(output_file, 'r')
214         result = f.read()
215         if result != "" and logger:
216             logger.debug(result)
217
218         vims_test_result = ""
219         try:
220             logger.debug("Trying to load test results")
221             with open(VIMS_TEST_DIR + "temp.json") as f:
222                 vims_test_result = json.load(f)
223             f.close()
224         except:
225             logger.error("Unable to retrieve test results")
226
227         set_result("sig_test", duration, vims_test_result)
228
229         # success criteria for vIMS (for Brahmaputra)
230         # - orchestrator deployed
231         # - VNF deployed
232         # TODO use test criteria defined in config file
233         status = "FAIL"
234         try:
235             if (RESULTS['orchestrator']['duration'] > 0 and
236                     RESULTS['vIMS']['duration'] > 0):
237                 status = "PASS"
238         except:
239             logger.error("Unable to set test status")
240
241         ft_utils.push_results_to_db("functest",
242                                     "vims",
243                                     TESTCASE_START_TIME,
244                                     end_time_ts,
245                                     status,
246                                     RESULTS)
247
248         try:
249             os.remove(VIMS_TEST_DIR + "temp.json")
250         except:
251             logger.error("Deleting file failed")
252
253
254 def main():
255
256     # ############### GENERAL INITIALISATION ################
257
258     if not os.path.exists(VIMS_DATA_DIR):
259         os.makedirs(VIMS_DATA_DIR)
260
261     ks_creds = os_utils.get_credentials("keystone")
262     nv_creds = os_utils.get_credentials("nova")
263     nt_creds = os_utils.get_credentials("neutron")
264
265     logger.info("Prepare OpenStack plateform (create tenant and user)")
266     keystone = ksclient.Client(**ks_creds)
267
268     user_id = os_utils.get_user_id(keystone, ks_creds['username'])
269     if user_id == '':
270         step_failure("init", "Error : Failed to get id of " +
271                      ks_creds['username'])
272
273     tenant_id = os_utils.create_tenant(
274         keystone, TENANT_NAME, TENANT_DESCRIPTION)
275     if not tenant_id:
276         step_failure("init", "Error : Failed to create " +
277                      TENANT_NAME + " tenant")
278
279     roles_name = ["admin", "Admin"]
280     role_id = ''
281     for role_name in roles_name:
282         if role_id == '':
283             role_id = os_utils.get_role_id(keystone, role_name)
284
285     if role_id == '':
286         logger.error("Error : Failed to get id for %s role" % role_name)
287
288     if not os_utils.add_role_user(keystone, user_id, role_id, tenant_id):
289         logger.error("Error : Failed to add %s on tenant" %
290                      ks_creds['username'])
291
292     user_id = os_utils.create_user(
293         keystone, TENANT_NAME, TENANT_NAME, None, tenant_id)
294     if not user_id:
295         logger.error("Error : Failed to create %s user" % TENANT_NAME)
296
297     logger.info("Update OpenStack creds informations")
298     ks_creds.update({
299         "username": TENANT_NAME,
300         "password": TENANT_NAME,
301         "tenant_name": TENANT_NAME,
302     })
303
304     nt_creds.update({
305         "tenant_name": TENANT_NAME,
306     })
307
308     nv_creds.update({
309         "project_id": TENANT_NAME,
310     })
311
312     logger.info("Upload some OS images if it doesn't exist")
313     glance = os_utils.get_glance_client()
314
315     for img in IMAGES.keys():
316         image_name = IMAGES[img]['image_name']
317         image_url = IMAGES[img]['image_url']
318
319         image_id = os_utils.get_image_id(glance, image_name)
320
321         if image_id == '':
322             logger.info("""%s image doesn't exist on glance repository. Try
323             downloading this image and upload on glance !""" % image_name)
324             image_id = download_and_add_image_on_glance(
325                 glance, image_name, image_url)
326
327         if image_id == '':
328             step_failure(
329                 "init",
330                 "Error : Failed to find or upload required OS "
331                 "image for this deployment")
332
333     nova = nvclient.Client("2", **nv_creds)
334
335     logger.info("Update security group quota for this tenant")
336     neutron = ntclient.Client(**nt_creds)
337     if not os_utils.update_sg_quota(neutron, tenant_id, 50, 100):
338         step_failure(
339             "init",
340             "Failed to update security group quota for tenant " + TENANT_NAME)
341
342     # ############### CLOUDIFY INITIALISATION ################
343     public_auth_url = keystone.service_catalog.url_for(
344         service_type='identity', endpoint_type='publicURL')
345
346     cfy = orchestrator(VIMS_DATA_DIR, CFY_INPUTS)
347
348     cfy.set_credentials(username=ks_creds['username'], password=ks_creds[
349                         'password'], tenant_name=ks_creds['tenant_name'],
350                         auth_url=public_auth_url)
351
352     logger.info("Collect flavor id for cloudify manager server")
353     nova = nvclient.Client("2", **nv_creds)
354
355     flavor_name = "m1.large"
356     flavor_id = os_utils.get_flavor_id(nova, flavor_name)
357     for requirement in CFY_MANAGER_REQUIERMENTS:
358         if requirement == 'ram_min':
359             flavor_id = os_utils.get_flavor_id_by_ram_range(
360                 nova, CFY_MANAGER_REQUIERMENTS['ram_min'], 10000)
361
362     if flavor_id == '':
363         logger.error(
364             "Failed to find %s flavor. "
365             "Try with ram range default requirement !" % flavor_name)
366         flavor_id = os_utils.get_flavor_id_by_ram_range(nova, 4000, 8196)
367
368     if flavor_id == '':
369         step_failure("orchestrator",
370                      "Failed to find required flavor for this deployment")
371
372     cfy.set_flavor_id(flavor_id)
373
374     image_name = "centos_7"
375     image_id = os_utils.get_image_id(glance, image_name)
376     for requirement in CFY_MANAGER_REQUIERMENTS:
377         if requirement == 'os_image':
378             image_id = os_utils.get_image_id(
379                 glance, CFY_MANAGER_REQUIERMENTS['os_image'])
380
381     if image_id == '':
382         step_failure(
383             "orchestrator",
384             "Error : Failed to find required OS image for cloudify manager")
385
386     cfy.set_image_id(image_id)
387
388     ext_net = os_utils.get_external_net(neutron)
389     if not ext_net:
390         step_failure("orchestrator", "Failed to get external network")
391
392     cfy.set_external_network_name(ext_net)
393
394     ns = ft_utils.get_resolvconf_ns()
395     if ns:
396         cfy.set_nameservers(ns)
397
398     if 'compute' in nova.client.services_url:
399         cfy.set_nova_url(nova.client.services_url['compute'])
400     if neutron.httpclient.endpoint_url is not None:
401         cfy.set_neutron_url(neutron.httpclient.endpoint_url)
402
403     logger.info("Prepare virtualenv for cloudify-cli")
404     cmd = "chmod +x " + VIMS_DIR + "create_venv.sh"
405     ft_utils.execute_command(cmd)
406     time.sleep(3)
407     cmd = VIMS_DIR + "create_venv.sh " + VIMS_DATA_DIR
408     ft_utils.execute_command(cmd)
409
410     cfy.download_manager_blueprint(
411         CFY_MANAGER_BLUEPRINT['url'], CFY_MANAGER_BLUEPRINT['branch'])
412
413     # ############### CLOUDIFY DEPLOYMENT ################
414     start_time_ts = time.time()
415     end_time_ts = start_time_ts
416     logger.info("Cloudify deployment Start Time:'%s'" % (
417         datetime.datetime.fromtimestamp(start_time_ts).strftime(
418             '%Y-%m-%d %H:%M:%S')))
419
420     error = cfy.deploy_manager()
421     if error:
422         step_failure("orchestrator", error)
423
424     end_time_ts = time.time()
425     duration = round(end_time_ts - start_time_ts, 1)
426     logger.info("Cloudify deployment duration:'%s'" % duration)
427     set_result("orchestrator", duration, "")
428
429     # ############### CLEARWATER INITIALISATION ################
430
431     cw = clearwater(CW_INPUTS, cfy, logger)
432
433     logger.info("Collect flavor id for all clearwater vm")
434     nova = nvclient.Client("2", **nv_creds)
435
436     flavor_name = "m1.small"
437     flavor_id = os_utils.get_flavor_id(nova, flavor_name)
438     for requirement in CW_REQUIERMENTS:
439         if requirement == 'ram_min' and flavor_id == '':
440             flavor_id = os_utils.get_flavor_id_by_ram_range(
441                 nova, CW_REQUIERMENTS['ram_min'], 4500)
442
443     if flavor_id == '':
444         logger.error(
445             "Failed to find %s flavor. Try with ram range "
446             "default requirement !" % flavor_name)
447         flavor_id = os_utils.get_flavor_id_by_ram_range(nova, 4000, 8196)
448
449     if flavor_id == '':
450         step_failure(
451             "vIMS", "Failed to find required flavor for this deployment")
452
453     cw.set_flavor_id(flavor_id)
454
455     image_name = "ubuntu_14.04"
456     image_id = os_utils.get_image_id(glance, image_name)
457     for requirement in CW_REQUIERMENTS:
458         if requirement == 'os_image':
459             image_id = os_utils.get_image_id(
460                 glance, CW_REQUIERMENTS['os_image'])
461
462     if image_id == '':
463         step_failure(
464             "vIMS",
465             "Error : Failed to find required OS image for cloudify manager")
466
467     cw.set_image_id(image_id)
468
469     ext_net = os_utils.get_external_net(neutron)
470     if not ext_net:
471         step_failure("vIMS", "Failed to get external network")
472
473     cw.set_external_network_name(ext_net)
474
475     # ############### CLEARWATER DEPLOYMENT ################
476
477     start_time_ts = time.time()
478     end_time_ts = start_time_ts
479     logger.info("vIMS VNF deployment Start Time:'%s'" % (
480         datetime.datetime.fromtimestamp(start_time_ts).strftime(
481             '%Y-%m-%d %H:%M:%S')))
482
483     error = cw.deploy_vnf(CW_BLUEPRINT)
484     if error:
485         step_failure("vIMS", error)
486
487     end_time_ts = time.time()
488     duration = round(end_time_ts - start_time_ts, 1)
489     logger.info("vIMS VNF deployment duration:'%s'" % duration)
490     set_result("vIMS", duration, "")
491
492     # ############### CLEARWATER TEST ################
493
494     test_clearwater()
495
496     # ########## CLEARWATER UNDEPLOYMENT ############
497
498     cw.undeploy_vnf()
499
500     # ########### CLOUDIFY UNDEPLOYMENT #############
501
502     cfy.undeploy_manager()
503
504     # ############## GENERAL CLEANUP ################
505     if args.noclean:
506         exit(0)
507
508     ks_creds = os_utils.get_credentials("keystone")
509
510     keystone = ksclient.Client(**ks_creds)
511
512     logger.info("Removing %s tenant .." % CFY_INPUTS['keystone_tenant_name'])
513     tenant_id = os_utils.get_tenant_id(
514         keystone, CFY_INPUTS['keystone_tenant_name'])
515     if tenant_id == '':
516         logger.error("Error : Failed to get id of %s tenant" %
517                      CFY_INPUTS['keystone_tenant_name'])
518     else:
519         if not os_utils.delete_tenant(keystone, tenant_id):
520             logger.error("Error : Failed to remove %s tenant" %
521                          CFY_INPUTS['keystone_tenant_name'])
522
523     logger.info("Removing %s user .." % CFY_INPUTS['keystone_username'])
524     user_id = os_utils.get_user_id(
525         keystone, CFY_INPUTS['keystone_username'])
526     if user_id == '':
527         logger.error("Error : Failed to get id of %s user" %
528                      CFY_INPUTS['keystone_username'])
529     else:
530         if not os_utils.delete_user(keystone, user_id):
531             logger.error("Error : Failed to remove %s user" %
532                          CFY_INPUTS['keystone_username'])
533
534
535 if __name__ == '__main__':
536     main()