3 # Copyright (c) 2020 Orange and others.
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
10 """Deploy and Test Clearwater vIMS using Kubernetes"""
17 from kubernetes import client
18 from kubernetes import config
19 from kubernetes import watch
22 from xtesting.core import testcase
25 class Vims(testcase.TestCase):
26 """Deploy and Test Clearwater vIMS using Kubernetes
28 It leverage on the Python kubernetes client to apply operation proposed by
31 See https://github.com/Metaswitch/clearwater-docker for more details
34 zone = 'default.svc.cluster.local'
36 metadata_name = "env-vars"
37 test_image_name = "ollivier/clearwater-live-test:latest"
38 test_container_name = "live-test"
40 __logger = logging.getLogger(__name__)
43 "astaire", "bono", "cassandra", "chronos", "ellis", "etcd", "homer",
44 "homestead", "homestead-prov", "ralf", "sprout"]
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()
53 """Deploy vIMS as proposed by clearwater-docker
55 It leverages on unofficial Clearwater dockers as proposed in the
58 See https://github.com/Metaswitch/clearwater-docker for more details
60 metadata = client.V1ObjectMeta(
61 name=self.metadata_name, namespace=self.namespace)
62 body = client.V1ConfigMap(
64 data={"ADDITIONAL_SHARED_CONFIG": "", "ZONE": self.zone})
65 api_response = self.corev1.create_namespaced_config_map(
66 self.namespace, body=body)
67 self.__logger.debug("create_namespaced_config_map: %s", api_response)
68 for deployment in self.deployment_list:
69 with open(pkg_resources.resource_filename(
70 'functest_kubernetes',
71 'ims/{}-depl.yaml'.format(deployment))) as yfile:
72 body = yaml.safe_load(yfile)
73 resp = self.appsv1.create_namespaced_deployment(
74 body=body, namespace="default")
75 self.__logger.info("Deployment %s created", resp.metadata.name)
77 "create_namespaced_deployment: %s", api_response)
78 for service in self.deployment_list:
79 with open(pkg_resources.resource_filename(
80 'functest_kubernetes',
81 'ims/{}-svc.yaml'.format(service))) as yfile:
82 body = yaml.safe_load(yfile)
83 resp = self.corev1.create_namespaced_service(
84 body=body, namespace="default")
85 self.__logger.info("Service %s created", resp.metadata.name)
87 "create_namespaced_service: %s", api_response)
88 status = self.deployment_list.copy()
89 watch_deployment = watch.Watch()
90 for event in watch_deployment.stream(
91 func=self.appsv1.list_namespaced_deployment,
92 namespace=self.namespace, timeout_seconds=self.watch_timeout):
93 if event["object"].status.ready_replicas == 1:
94 if event['object'].metadata.name in status:
95 status.remove(event['object'].metadata.name)
97 "%s started in %0.2f sec",
98 event['object'].metadata.name,
99 time.time()-self.start_time)
101 watch_deployment.stop()
102 self.result = 1/2 * 100
105 """Test vIMS as proposed by clearwater-live-test
107 It leverages on an unofficial Clearwater docker to allow testing from
108 the Kubernetes cluster.
110 See https://github.com/Metaswitch/clearwater-live-test for more details
112 container = client.V1Container(
113 name=self.test_container_name, image=self.test_image_name)
114 spec = client.V1PodSpec(containers=[container], restart_policy="Never")
115 metadata = client.V1ObjectMeta(name=self.test_container_name)
116 body = client.V1Pod(metadata=metadata, spec=spec)
117 api_response = self.corev1.create_namespaced_pod(self.namespace, body)
118 watch_deployment = watch.Watch()
119 for event in watch_deployment.stream(
120 func=self.corev1.list_namespaced_pod,
121 namespace=self.namespace, timeout_seconds=self.watch_timeout):
122 if event["object"].metadata.name == self.test_container_name:
123 if (event["object"].status.phase == 'Succeeded'
124 or event["object"].status.phase == 'Error'):
125 watch_deployment.stop()
126 api_response = self.corev1.read_namespaced_pod_log(
127 name=self.test_container_name, namespace=self.namespace)
128 self.__logger.info(api_response)
129 vims_test_result = {}
132 r'^(\d+) failures out of (\d+) tests run.*\n'
133 r'(\d+) tests skipped$', api_response,
134 re.MULTILINE | re.DOTALL)
136 vims_test_result["failures"] = int(grp.group(1))
137 vims_test_result["total"] = int(grp.group(2))
138 vims_test_result["skipped"] = int(grp.group(3))
139 vims_test_result['passed'] = (
140 int(grp.group(2)) - int(grp.group(3)) - int(grp.group(1)))
141 if vims_test_result['total'] - vims_test_result['skipped'] > 0:
142 vnf_test_rate = vims_test_result['passed'] / (
143 vims_test_result['total'] - vims_test_result['skipped'])
146 self.result += 1/2 * 100 * vnf_test_rate
147 except Exception: # pylint: disable=broad-except
148 self.__logger.exception("Cannot parse live tests results")
150 def run(self, **kwargs):
151 self.start_time = time.time()
155 except client.rest.ApiException:
156 self.__logger.exception("Cannot deploy and test vIms")
157 self.stop_time = time.time()
161 api_response = self.corev1.delete_namespaced_config_map(
162 name=self.metadata_name, namespace=self.namespace)
164 "delete_namespaced_config_map: %s", api_response)
165 except client.rest.ApiException:
168 api_response = self.corev1.delete_namespaced_pod(
169 name=self.test_container_name, namespace=self.namespace)
170 self.__logger.debug("delete_namespaced_pod: %s", api_response)
171 except client.rest.ApiException:
173 for deployment in self.deployment_list:
175 api_response = self.appsv1.delete_namespaced_deployment(
176 name=deployment, namespace=self.namespace)
178 "delete_namespaced_deployment: %s", api_response)
179 except client.rest.ApiException:
182 api_response = self.corev1.delete_namespaced_service(
183 name=deployment, namespace=self.namespace)
185 "delete_namespaced_service: %s", api_response)
186 except client.rest.ApiException: