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