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