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