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