Override the right log files
[functest-kubernetes.git] / functest_kubernetes / ims / ims.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2020 Orange and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 """Deploy and Test Clearwater vIMS using Kubernetes"""
11
12 from __future__ import division
13
14 import logging
15 import time
16 import re
17 import yaml
18
19 from kubernetes import client
20 from kubernetes import config
21 from kubernetes import watch
22 import pkg_resources
23
24 from xtesting.core import testcase
25
26
27 class Vims(testcase.TestCase):
28     """Deploy and Test Clearwater vIMS using Kubernetes
29
30     It leverage on the Python kubernetes client to apply operation proposed by
31     clearwater-docker.
32
33     See https://github.com/Metaswitch/clearwater-docker for more details
34     """
35     namespace = 'default'
36     zone = 'default.svc.cluster.local'
37     watch_timeout = 1200
38     metadata_name = "env-vars"
39     test_image_name = "ollivier/clearwater-live-test:latest"
40     test_container_name = "live-test"
41
42     __logger = logging.getLogger(__name__)
43
44     deployment_list = [
45         "astaire", "bono", "cassandra", "chronos", "ellis", "etcd", "homer",
46         "homestead", "homestead-prov", "ralf", "sprout"]
47
48     def __init__(self, **kwargs):
49         super(Vims, self).__init__(**kwargs)
50         config.load_kube_config()
51         self.corev1 = client.CoreV1Api()
52         self.appsv1 = client.AppsV1Api()
53         self.output_log_name = 'functest-kubernetes.log'
54         self.output_debug_log_name = 'functest-kubernetes.debug.log'
55
56     def deploy_vnf(self):
57         """Deploy vIMS as proposed by clearwater-docker
58
59         It leverages on unofficial Clearwater dockers as proposed in the
60         documentation.
61
62         See https://github.com/Metaswitch/clearwater-docker for more details
63         """
64         metadata = client.V1ObjectMeta(
65             name=self.metadata_name, namespace=self.namespace)
66         body = client.V1ConfigMap(
67             metadata=metadata,
68             data={"ADDITIONAL_SHARED_CONFIG": "", "ZONE": self.zone})
69         api_response = self.corev1.create_namespaced_config_map(
70             self.namespace, body=body)
71         self.__logger.debug("create_namespaced_config_map: %s", api_response)
72         for deployment in self.deployment_list:
73             with open(pkg_resources.resource_filename(
74                     'functest_kubernetes',
75                     'ims/{}-depl.yaml'.format(deployment))) as yfile:
76                 body = yaml.safe_load(yfile)
77                 resp = self.appsv1.create_namespaced_deployment(
78                     body=body, namespace="default")
79                 self.__logger.info("Deployment %s created", resp.metadata.name)
80                 self.__logger.debug(
81                     "create_namespaced_deployment: %s", api_response)
82         for service in self.deployment_list:
83             with open(pkg_resources.resource_filename(
84                     'functest_kubernetes',
85                     'ims/{}-svc.yaml'.format(service))) as yfile:
86                 body = yaml.safe_load(yfile)
87                 resp = self.corev1.create_namespaced_service(
88                     body=body, namespace="default")
89                 self.__logger.info("Service %s created", resp.metadata.name)
90                 self.__logger.debug(
91                     "create_namespaced_service: %s", api_response)
92         status = self.deployment_list.copy()
93         watch_deployment = watch.Watch()
94         for event in watch_deployment.stream(
95                 func=self.appsv1.list_namespaced_deployment,
96                 namespace=self.namespace, timeout_seconds=self.watch_timeout):
97             if event["object"].status.ready_replicas == 1:
98                 if event['object'].metadata.name in status:
99                     status.remove(event['object'].metadata.name)
100                     self.__logger.info(
101                         "%s started in %0.2f sec",
102                         event['object'].metadata.name,
103                         time.time()-self.start_time)
104             if not status:
105                 watch_deployment.stop()
106         self.result = 1/2 * 100
107
108     def test_vnf(self):
109         """Test vIMS as proposed by clearwater-live-test
110
111         It leverages on an unofficial Clearwater docker to allow testing from
112         the Kubernetes cluster.
113
114         See https://github.com/Metaswitch/clearwater-live-test for more details
115         """
116         container = client.V1Container(
117             name=self.test_container_name, image=self.test_image_name)
118         spec = client.V1PodSpec(containers=[container], restart_policy="Never")
119         metadata = client.V1ObjectMeta(name=self.test_container_name)
120         body = client.V1Pod(metadata=metadata, spec=spec)
121         api_response = self.corev1.create_namespaced_pod(self.namespace, body)
122         watch_deployment = watch.Watch()
123         for event in watch_deployment.stream(
124                 func=self.corev1.list_namespaced_pod,
125                 namespace=self.namespace, timeout_seconds=self.watch_timeout):
126             if event["object"].metadata.name == self.test_container_name:
127                 if (event["object"].status.phase == 'Succeeded' or
128                         event["object"].status.phase == 'Error'):
129                     watch_deployment.stop()
130         api_response = self.corev1.read_namespaced_pod_log(
131             name=self.test_container_name, namespace=self.namespace)
132         self.__logger.info(api_response)
133         vims_test_result = {}
134         try:
135             grp = re.search(
136                 r'^(\d+) failures out of (\d+) tests run.*\n'
137                 r'(\d+) tests skipped$', api_response,
138                 re.MULTILINE | re.DOTALL)
139             assert grp
140             vims_test_result["failures"] = int(grp.group(1))
141             vims_test_result["total"] = int(grp.group(2))
142             vims_test_result["skipped"] = int(grp.group(3))
143             vims_test_result['passed'] = (
144                 int(grp.group(2)) - int(grp.group(3)) - int(grp.group(1)))
145             if vims_test_result['total'] - vims_test_result['skipped'] > 0:
146                 vnf_test_rate = vims_test_result['passed'] / (
147                     vims_test_result['total'] - vims_test_result['skipped'])
148             else:
149                 vnf_test_rate = 0
150             self.result += 1/2 * 100 * vnf_test_rate
151         except Exception:  # pylint: disable=broad-except
152             self.__logger.exception("Cannot parse live tests results")
153
154     def run(self, **kwargs):
155         self.start_time = time.time()
156         try:
157             self.deploy_vnf()
158             self.test_vnf()
159         except client.rest.ApiException:
160             self.__logger.exception("Cannot deploy and test vIms")
161         self.stop_time = time.time()
162
163     def clean(self):
164         try:
165             api_response = self.corev1.delete_namespaced_config_map(
166                 name=self.metadata_name, namespace=self.namespace)
167             self.__logger.debug(
168                 "delete_namespaced_config_map: %s", api_response)
169         except client.rest.ApiException:
170             pass
171         try:
172             api_response = self.corev1.delete_namespaced_pod(
173                 name=self.test_container_name, namespace=self.namespace)
174             self.__logger.debug("delete_namespaced_pod: %s", api_response)
175         except client.rest.ApiException:
176             pass
177         for deployment in self.deployment_list:
178             try:
179                 api_response = self.appsv1.delete_namespaced_deployment(
180                     name=deployment, namespace=self.namespace)
181                 self.__logger.debug(
182                     "delete_namespaced_deployment: %s", api_response)
183             except client.rest.ApiException:
184                 pass
185             try:
186                 api_response = self.corev1.delete_namespaced_service(
187                     name=deployment, namespace=self.namespace)
188                 self.__logger.debug(
189                     "delete_namespaced_service: %s", api_response)
190             except client.rest.ApiException:
191                 pass