1 |
|
# Copyright 2020 Canonical Ltd. |
2 |
|
# |
3 |
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
4 |
|
# you may not use this file except in compliance with the License. |
5 |
|
# You may obtain a copy of the License at |
6 |
|
# |
7 |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
8 |
|
# |
9 |
|
# Unless required by applicable law or agreed to in writing, software |
10 |
|
# distributed under the License is distributed on an "AS IS" BASIS, |
11 |
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 |
|
# See the License for the specific language governing permissions and |
13 |
|
# limitations under the License. |
14 |
|
|
15 |
|
|
16 |
1 |
import asyncio |
17 |
1 |
import logging |
18 |
1 |
import asynctest |
19 |
1 |
from unittest.mock import Mock |
20 |
1 |
from n2vc.definitions import Offer, RelationEndpoint |
21 |
1 |
from n2vc.k8s_juju_conn import K8sJujuConnector, RBAC_LABEL_KEY_NAME |
22 |
1 |
from osm_common import fslocal |
23 |
1 |
from .utils import kubeconfig, FakeModel, FakeFileWrapper, AsyncMock, FakeApplication |
24 |
1 |
from n2vc.exceptions import MethodNotImplemented, K8sException |
25 |
1 |
from n2vc.vca.connection_data import ConnectionData |
26 |
|
|
27 |
|
|
28 |
1 |
class K8sJujuConnTestCase(asynctest.TestCase): |
29 |
1 |
@asynctest.mock.patch("n2vc.k8s_juju_conn.Libjuju") |
30 |
1 |
@asynctest.mock.patch("n2vc.k8s_juju_conn.MotorStore") |
31 |
1 |
@asynctest.mock.patch("n2vc.k8s_juju_conn.get_connection") |
32 |
1 |
@asynctest.mock.patch("n2vc.vca.connection_data.base64_to_cacert") |
33 |
1 |
def setUp( |
34 |
|
self, |
35 |
|
mock_base64_to_cacert=None, |
36 |
|
mock_get_connection=None, |
37 |
|
mock_store=None, |
38 |
|
mock_libjuju=None, |
39 |
|
): |
40 |
1 |
self.loop = asyncio.get_event_loop() |
41 |
1 |
self.db = Mock() |
42 |
1 |
mock_base64_to_cacert.return_value = """ |
43 |
|
-----BEGIN CERTIFICATE----- |
44 |
|
SOMECERT |
45 |
|
-----END CERTIFICATE-----""" |
46 |
1 |
mock_libjuju.return_value = Mock() |
47 |
1 |
mock_store.return_value = AsyncMock() |
48 |
1 |
mock_vca_connection = Mock() |
49 |
1 |
mock_get_connection.return_value = mock_vca_connection |
50 |
1 |
mock_vca_connection.data.return_value = ConnectionData( |
51 |
|
**{ |
52 |
|
"endpoints": ["1.2.3.4:17070"], |
53 |
|
"user": "user", |
54 |
|
"secret": "secret", |
55 |
|
"cacert": "cacert", |
56 |
|
"pubkey": "pubkey", |
57 |
|
"lxd-cloud": "cloud", |
58 |
|
"lxd-credentials": "credentials", |
59 |
|
"k8s-cloud": "k8s_cloud", |
60 |
|
"k8s-credentials": "k8s_credentials", |
61 |
|
"model-config": {}, |
62 |
|
"api-proxy": "api_proxy", |
63 |
|
} |
64 |
|
) |
65 |
1 |
logging.disable(logging.CRITICAL) |
66 |
|
|
67 |
1 |
self.kdu_name = "kdu_name" |
68 |
1 |
self.kdu_instance = "{}-{}".format(self.kdu_name, "id") |
69 |
1 |
self.default_namespace = self.kdu_instance |
70 |
|
|
71 |
1 |
self.k8s_juju_conn = K8sJujuConnector( |
72 |
|
fs=fslocal.FsLocal(), |
73 |
|
db=self.db, |
74 |
|
log=None, |
75 |
|
on_update_db=None, |
76 |
|
) |
77 |
1 |
self.k8s_juju_conn._store.get_vca_id.return_value = None |
78 |
1 |
self.k8s_juju_conn.libjuju = Mock() |
79 |
|
# Mock Kubectl |
80 |
1 |
self.kubectl = Mock() |
81 |
1 |
self.kubectl.get_secret_data = AsyncMock() |
82 |
1 |
self.kubectl.get_secret_data.return_value = ("token", "cacert") |
83 |
1 |
self.kubectl.get_services.return_value = [{}] |
84 |
1 |
self.k8s_juju_conn._get_kubectl = Mock() |
85 |
1 |
self.k8s_juju_conn._get_kubectl.return_value = self.kubectl |
86 |
1 |
self.k8s_juju_conn._obtain_namespace_from_db = Mock( |
87 |
|
return_value=self.default_namespace |
88 |
|
) |
89 |
|
|
90 |
|
|
91 |
1 |
class InitEnvTest(K8sJujuConnTestCase): |
92 |
1 |
def setUp(self): |
93 |
1 |
super(InitEnvTest, self).setUp() |
94 |
1 |
self.k8s_juju_conn.libjuju.add_k8s = AsyncMock() |
95 |
|
|
96 |
1 |
def test_with_cluster_uuid( |
97 |
|
self, |
98 |
|
): |
99 |
1 |
reuse_cluster_uuid = "uuid" |
100 |
1 |
uuid, created = self.loop.run_until_complete( |
101 |
|
self.k8s_juju_conn.init_env( |
102 |
|
k8s_creds=kubeconfig, reuse_cluster_uuid=reuse_cluster_uuid |
103 |
|
) |
104 |
|
) |
105 |
|
|
106 |
1 |
self.assertTrue(created) |
107 |
1 |
self.assertEqual(uuid, reuse_cluster_uuid) |
108 |
1 |
self.kubectl.get_default_storage_class.assert_called_once() |
109 |
1 |
self.k8s_juju_conn.libjuju.add_k8s.assert_called_once() |
110 |
|
|
111 |
1 |
def test_with_no_cluster_uuid( |
112 |
|
self, |
113 |
|
): |
114 |
1 |
uuid, created = self.loop.run_until_complete( |
115 |
|
self.k8s_juju_conn.init_env(k8s_creds=kubeconfig) |
116 |
|
) |
117 |
|
|
118 |
1 |
self.assertTrue(created) |
119 |
1 |
self.assertTrue(isinstance(uuid, str)) |
120 |
1 |
self.kubectl.get_default_storage_class.assert_called_once() |
121 |
1 |
self.k8s_juju_conn.libjuju.add_k8s.assert_called_once() |
122 |
|
|
123 |
1 |
def test_init_env_exception( |
124 |
|
self, |
125 |
|
): |
126 |
1 |
self.k8s_juju_conn.libjuju.add_k8s.side_effect = Exception() |
127 |
1 |
created = None |
128 |
1 |
uuid = None |
129 |
1 |
with self.assertRaises(Exception): |
130 |
1 |
uuid, created = self.loop.run_until_complete( |
131 |
|
self.k8s_juju_conn.init_env(k8s_creds=kubeconfig) |
132 |
|
) |
133 |
1 |
self.assertIsNone(created) |
134 |
1 |
self.assertIsNone(uuid) |
135 |
1 |
self.kubectl.create_cluster_role.assert_called_once() |
136 |
1 |
self.kubectl.create_service_account.assert_called_once() |
137 |
1 |
self.kubectl.create_cluster_role_binding.assert_called_once() |
138 |
1 |
self.kubectl.get_default_storage_class.assert_called_once() |
139 |
1 |
self.kubectl.delete_cluster_role.assert_called_once() |
140 |
1 |
self.kubectl.delete_service_account.assert_called_once() |
141 |
1 |
self.kubectl.delete_cluster_role_binding.assert_called_once() |
142 |
1 |
self.k8s_juju_conn.libjuju.add_k8s.assert_called_once() |
143 |
|
|
144 |
|
|
145 |
1 |
class NotImplementedTest(K8sJujuConnTestCase): |
146 |
1 |
def setUp(self): |
147 |
1 |
super(NotImplementedTest, self).setUp() |
148 |
|
|
149 |
1 |
def test_repo_add(self): |
150 |
1 |
with self.assertRaises(MethodNotImplemented): |
151 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.repo_add("", "")) |
152 |
|
|
153 |
1 |
def test_repo_list(self): |
154 |
1 |
with self.assertRaises(MethodNotImplemented): |
155 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.repo_list()) |
156 |
|
|
157 |
1 |
def test_repo_remove(self): |
158 |
1 |
with self.assertRaises(MethodNotImplemented): |
159 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.repo_remove("")) |
160 |
|
|
161 |
1 |
def test_synchronize_repos(self): |
162 |
1 |
self.assertIsNone( |
163 |
|
self.loop.run_until_complete(self.k8s_juju_conn.synchronize_repos("", "")) |
164 |
|
) |
165 |
|
|
166 |
1 |
def test_upgrade(self): |
167 |
1 |
with self.assertRaises(MethodNotImplemented): |
168 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.upgrade("", "")) |
169 |
|
|
170 |
1 |
def test_rollback(self): |
171 |
1 |
with self.assertRaises(MethodNotImplemented): |
172 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.rollback("", "")) |
173 |
|
|
174 |
1 |
def test_get_namespace(self): |
175 |
1 |
self.assertIsNone(self.k8s_juju_conn.get_namespace("")) |
176 |
|
|
177 |
1 |
def test_instances_list(self): |
178 |
1 |
res = self.loop.run_until_complete(self.k8s_juju_conn.instances_list("")) |
179 |
1 |
self.assertEqual(res, []) |
180 |
|
|
181 |
|
|
182 |
1 |
class ResetTest(K8sJujuConnTestCase): |
183 |
1 |
def setUp(self): |
184 |
1 |
super(ResetTest, self).setUp() |
185 |
1 |
self.k8s_juju_conn.libjuju.remove_cloud = AsyncMock() |
186 |
1 |
self.k8s_juju_conn.libjuju.get_cloud_credentials = AsyncMock() |
187 |
1 |
cloud_creds = Mock() |
188 |
1 |
cloud_creds.result = {"attrs": {RBAC_LABEL_KEY_NAME: "asd"}} |
189 |
1 |
self.k8s_juju_conn.libjuju.get_cloud_credentials.return_value = [cloud_creds] |
190 |
1 |
self.k8s_juju_conn.get_credentials = Mock() |
191 |
1 |
self.k8s_juju_conn.get_credentials.return_value = kubeconfig |
192 |
|
|
193 |
1 |
def test_success(self): |
194 |
1 |
removed = self.loop.run_until_complete(self.k8s_juju_conn.reset("uuid")) |
195 |
1 |
self.assertTrue(removed) |
196 |
1 |
self.k8s_juju_conn.libjuju.remove_cloud.assert_called_once() |
197 |
|
|
198 |
1 |
def test_exception(self): |
199 |
1 |
removed = None |
200 |
1 |
self.k8s_juju_conn.libjuju.remove_cloud.side_effect = Exception() |
201 |
1 |
with self.assertRaises(Exception): |
202 |
1 |
removed = self.loop.run_until_complete(self.k8s_juju_conn.reset("uuid")) |
203 |
1 |
self.assertIsNone(removed) |
204 |
1 |
self.k8s_juju_conn.libjuju.remove_cloud.assert_called_once() |
205 |
|
|
206 |
|
|
207 |
1 |
@asynctest.mock.patch("os.chdir") |
208 |
1 |
class InstallTest(K8sJujuConnTestCase): |
209 |
1 |
def setUp(self): |
210 |
1 |
super(InstallTest, self).setUp() |
211 |
1 |
self.db_dict = {"filter": {"_id": "id"}} |
212 |
1 |
self.local_bundle = "bundle" |
213 |
1 |
self.cs_bundle = "cs:bundle" |
214 |
1 |
self.http_bundle = "https://example.com/bundle.yaml" |
215 |
1 |
self.cluster_uuid = "cluster" |
216 |
1 |
self.k8s_juju_conn.libjuju.add_model = AsyncMock() |
217 |
1 |
self.k8s_juju_conn.libjuju.deploy = AsyncMock() |
218 |
|
|
219 |
1 |
def test_success_local(self, mock_chdir): |
220 |
1 |
self.loop.run_until_complete( |
221 |
|
self.k8s_juju_conn.install( |
222 |
|
self.cluster_uuid, |
223 |
|
self.local_bundle, |
224 |
|
self.kdu_instance, |
225 |
|
atomic=True, |
226 |
|
kdu_name=self.kdu_name, |
227 |
|
db_dict=self.db_dict, |
228 |
|
timeout=1800, |
229 |
|
params=None, |
230 |
|
) |
231 |
|
) |
232 |
1 |
self.assertEqual(mock_chdir.call_count, 2) |
233 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
234 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
235 |
|
"local:{}".format(self.local_bundle), |
236 |
|
model_name=self.default_namespace, |
237 |
|
wait=True, |
238 |
|
timeout=1800, |
239 |
|
instantiation_params=None, |
240 |
|
) |
241 |
|
|
242 |
1 |
def test_success_cs(self, mock_chdir): |
243 |
1 |
self.loop.run_until_complete( |
244 |
|
self.k8s_juju_conn.install( |
245 |
|
self.cluster_uuid, |
246 |
|
self.cs_bundle, |
247 |
|
self.kdu_instance, |
248 |
|
atomic=True, |
249 |
|
kdu_name=self.kdu_name, |
250 |
|
db_dict=self.db_dict, |
251 |
|
timeout=1800, |
252 |
|
params={}, |
253 |
|
) |
254 |
|
) |
255 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
256 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
257 |
|
self.cs_bundle, |
258 |
|
model_name=self.default_namespace, |
259 |
|
wait=True, |
260 |
|
timeout=1800, |
261 |
|
instantiation_params=None, |
262 |
|
) |
263 |
|
|
264 |
1 |
def test_success_http(self, mock_chdir): |
265 |
1 |
params = {"overlay": {"applications": {"squid": {"scale": 2}}}} |
266 |
1 |
self.loop.run_until_complete( |
267 |
|
self.k8s_juju_conn.install( |
268 |
|
self.cluster_uuid, |
269 |
|
self.http_bundle, |
270 |
|
self.kdu_instance, |
271 |
|
atomic=True, |
272 |
|
kdu_name=self.kdu_name, |
273 |
|
db_dict=self.db_dict, |
274 |
|
timeout=1800, |
275 |
|
params=params, |
276 |
|
) |
277 |
|
) |
278 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
279 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
280 |
|
self.http_bundle, |
281 |
|
model_name=self.default_namespace, |
282 |
|
wait=True, |
283 |
|
timeout=1800, |
284 |
|
instantiation_params=params.get("overlay"), |
285 |
|
) |
286 |
|
|
287 |
1 |
def test_success_not_kdu_name(self, mock_chdir): |
288 |
1 |
params = {"some_key": {"applications": {"squid": {"scale": 2}}}} |
289 |
1 |
self.loop.run_until_complete( |
290 |
|
self.k8s_juju_conn.install( |
291 |
|
self.cluster_uuid, |
292 |
|
self.cs_bundle, |
293 |
|
self.kdu_instance, |
294 |
|
atomic=True, |
295 |
|
db_dict=self.db_dict, |
296 |
|
timeout=1800, |
297 |
|
params=params, |
298 |
|
) |
299 |
|
) |
300 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
301 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
302 |
|
self.cs_bundle, |
303 |
|
model_name=self.default_namespace, |
304 |
|
wait=True, |
305 |
|
timeout=1800, |
306 |
|
instantiation_params=None, |
307 |
|
) |
308 |
|
|
309 |
1 |
def test_missing_db_dict(self, mock_chdir): |
310 |
1 |
kdu_instance = None |
311 |
1 |
with self.assertRaises(K8sException): |
312 |
1 |
self.loop.run_until_complete( |
313 |
|
self.k8s_juju_conn.install( |
314 |
|
self.cluster_uuid, |
315 |
|
self.cs_bundle, |
316 |
|
self.kdu_instance, |
317 |
|
atomic=True, |
318 |
|
kdu_name=self.kdu_name, |
319 |
|
timeout=1800, |
320 |
|
) |
321 |
|
) |
322 |
1 |
self.assertIsNone(kdu_instance) |
323 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_not_called() |
324 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_not_called() |
325 |
|
|
326 |
1 |
@asynctest.mock.patch("os.getcwd") |
327 |
1 |
def test_getcwd_exception(self, mock_getcwd, mock_chdir): |
328 |
1 |
mock_getcwd.side_effect = FileNotFoundError() |
329 |
1 |
self.loop.run_until_complete( |
330 |
|
self.k8s_juju_conn.install( |
331 |
|
self.cluster_uuid, |
332 |
|
self.cs_bundle, |
333 |
|
self.kdu_instance, |
334 |
|
atomic=True, |
335 |
|
kdu_name=self.kdu_name, |
336 |
|
db_dict=self.db_dict, |
337 |
|
timeout=1800, |
338 |
|
) |
339 |
|
) |
340 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
341 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
342 |
|
self.cs_bundle, |
343 |
|
model_name=self.default_namespace, |
344 |
|
wait=True, |
345 |
|
timeout=1800, |
346 |
|
instantiation_params=None, |
347 |
|
) |
348 |
|
|
349 |
1 |
def test_missing_bundle(self, mock_chdir): |
350 |
1 |
with self.assertRaises(K8sException): |
351 |
1 |
self.loop.run_until_complete( |
352 |
|
self.k8s_juju_conn.install( |
353 |
|
self.cluster_uuid, |
354 |
|
"", |
355 |
|
self.kdu_instance, |
356 |
|
atomic=True, |
357 |
|
kdu_name=self.kdu_name, |
358 |
|
timeout=1800, |
359 |
|
db_dict=self.db_dict, |
360 |
|
) |
361 |
|
) |
362 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_not_called() |
363 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_not_called() |
364 |
|
|
365 |
1 |
def test_missing_exception(self, mock_chdir): |
366 |
1 |
self.k8s_juju_conn.libjuju.deploy.side_effect = Exception() |
367 |
1 |
with self.assertRaises(Exception): |
368 |
1 |
self.loop.run_until_complete( |
369 |
|
self.k8s_juju_conn.install( |
370 |
|
self.cluster_uuid, |
371 |
|
self.local_bundle, |
372 |
|
self.kdu_instance, |
373 |
|
atomic=True, |
374 |
|
kdu_name=self.kdu_name, |
375 |
|
db_dict=self.db_dict, |
376 |
|
timeout=1800, |
377 |
|
) |
378 |
|
) |
379 |
1 |
self.k8s_juju_conn.libjuju.add_model.assert_called_once() |
380 |
1 |
self.k8s_juju_conn.libjuju.deploy.assert_called_once_with( |
381 |
|
"local:{}".format(self.local_bundle), |
382 |
|
model_name=self.default_namespace, |
383 |
|
wait=True, |
384 |
|
timeout=1800, |
385 |
|
instantiation_params=None, |
386 |
|
) |
387 |
|
|
388 |
|
|
389 |
1 |
class UninstallTest(K8sJujuConnTestCase): |
390 |
1 |
def setUp(self): |
391 |
1 |
super(UninstallTest, self).setUp() |
392 |
1 |
self.k8s_juju_conn.libjuju.destroy_model = AsyncMock() |
393 |
|
|
394 |
1 |
def test_success(self): |
395 |
1 |
destroyed = self.loop.run_until_complete( |
396 |
|
self.k8s_juju_conn.uninstall("cluster_uuid", "model_name") |
397 |
|
) |
398 |
1 |
self.assertTrue(destroyed) |
399 |
1 |
self.k8s_juju_conn.libjuju.destroy_model.assert_called_once() |
400 |
|
|
401 |
1 |
def test_exception(self): |
402 |
1 |
destroyed = None |
403 |
1 |
self.k8s_juju_conn.libjuju.destroy_model.side_effect = Exception() |
404 |
1 |
with self.assertRaises(Exception): |
405 |
1 |
destroyed = self.loop.run_until_complete( |
406 |
|
self.k8s_juju_conn.uninstall("cluster_uuid", "model_name") |
407 |
|
) |
408 |
1 |
self.assertIsNone(destroyed) |
409 |
1 |
self.k8s_juju_conn.libjuju.destroy_model.assert_called_once() |
410 |
|
|
411 |
|
|
412 |
1 |
class ExecPrimitivesTest(K8sJujuConnTestCase): |
413 |
1 |
def setUp(self): |
414 |
1 |
super(ExecPrimitivesTest, self).setUp() |
415 |
1 |
self.action_name = "touch" |
416 |
1 |
self.application_name = "myapp" |
417 |
1 |
self.k8s_juju_conn.libjuju.get_actions = AsyncMock() |
418 |
1 |
self.k8s_juju_conn.libjuju.execute_action = AsyncMock() |
419 |
|
|
420 |
1 |
def test_success(self): |
421 |
1 |
params = {"application-name": self.application_name} |
422 |
1 |
self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name] |
423 |
1 |
self.k8s_juju_conn.libjuju.execute_action.return_value = ( |
424 |
|
"success", |
425 |
|
"completed", |
426 |
|
) |
427 |
|
|
428 |
1 |
output = self.loop.run_until_complete( |
429 |
|
self.k8s_juju_conn.exec_primitive( |
430 |
|
"cluster", self.kdu_instance, self.action_name, params=params |
431 |
|
) |
432 |
|
) |
433 |
|
|
434 |
1 |
self.assertEqual(output, "success") |
435 |
1 |
self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with( |
436 |
|
kdu_instance=self.kdu_instance |
437 |
|
) |
438 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with( |
439 |
|
application_name=self.application_name, model_name=self.default_namespace |
440 |
|
) |
441 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with( |
442 |
|
application_name=self.application_name, |
443 |
|
model_name=self.default_namespace, |
444 |
|
action_name=self.action_name, |
445 |
|
**params |
446 |
|
) |
447 |
|
|
448 |
1 |
def test_exception(self): |
449 |
1 |
params = {"application-name": self.application_name} |
450 |
1 |
self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name] |
451 |
1 |
self.k8s_juju_conn.libjuju.execute_action.side_effect = Exception() |
452 |
1 |
output = None |
453 |
|
|
454 |
1 |
with self.assertRaises(Exception): |
455 |
1 |
output = self.loop.run_until_complete( |
456 |
|
self.k8s_juju_conn.exec_primitive( |
457 |
|
"cluster", self.kdu_instance, self.action_name, params=params |
458 |
|
) |
459 |
|
) |
460 |
|
|
461 |
1 |
self.assertIsNone(output) |
462 |
1 |
self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with( |
463 |
|
kdu_instance=self.kdu_instance |
464 |
|
) |
465 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with( |
466 |
|
application_name=self.application_name, model_name=self.default_namespace |
467 |
|
) |
468 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with( |
469 |
|
application_name=self.application_name, |
470 |
|
model_name=self.default_namespace, |
471 |
|
action_name=self.action_name, |
472 |
|
**params |
473 |
|
) |
474 |
|
|
475 |
1 |
def test_missing_application_name_in_params(self): |
476 |
1 |
params = {} |
477 |
1 |
output = None |
478 |
|
|
479 |
1 |
with self.assertRaises(K8sException): |
480 |
1 |
output = self.loop.run_until_complete( |
481 |
|
self.k8s_juju_conn.exec_primitive( |
482 |
|
"cluster", self.kdu_instance, self.action_name, params=params |
483 |
|
) |
484 |
|
) |
485 |
|
|
486 |
1 |
self.assertIsNone(output) |
487 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_not_called() |
488 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_not_called() |
489 |
|
|
490 |
1 |
def test_missing_params(self): |
491 |
1 |
output = None |
492 |
1 |
with self.assertRaises(K8sException): |
493 |
1 |
output = self.loop.run_until_complete( |
494 |
|
self.k8s_juju_conn.exec_primitive( |
495 |
|
"cluster", self.kdu_instance, self.action_name |
496 |
|
) |
497 |
|
) |
498 |
|
|
499 |
1 |
self.assertIsNone(output) |
500 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_not_called() |
501 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_not_called() |
502 |
|
|
503 |
1 |
def test_missing_action(self): |
504 |
1 |
output = None |
505 |
1 |
params = {"application-name": self.application_name} |
506 |
1 |
self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name] |
507 |
1 |
self.k8s_juju_conn.libjuju.execute_action.return_value = ( |
508 |
|
"success", |
509 |
|
"completed", |
510 |
|
) |
511 |
1 |
with self.assertRaises(K8sException): |
512 |
1 |
output = self.loop.run_until_complete( |
513 |
|
self.k8s_juju_conn.exec_primitive( |
514 |
|
"cluster", self.kdu_instance, "non-existing-action", params=params |
515 |
|
) |
516 |
|
) |
517 |
|
|
518 |
1 |
self.assertIsNone(output) |
519 |
1 |
self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with( |
520 |
|
kdu_instance=self.kdu_instance |
521 |
|
) |
522 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with( |
523 |
|
application_name=self.application_name, model_name=self.default_namespace |
524 |
|
) |
525 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_not_called() |
526 |
|
|
527 |
1 |
def test_missing_not_completed(self): |
528 |
1 |
output = None |
529 |
1 |
params = {"application-name": self.application_name} |
530 |
1 |
self.k8s_juju_conn.libjuju.get_actions.return_value = [self.action_name] |
531 |
1 |
self.k8s_juju_conn.libjuju.execute_action.return_value = (None, "failed") |
532 |
1 |
with self.assertRaises(K8sException): |
533 |
1 |
output = self.loop.run_until_complete( |
534 |
|
self.k8s_juju_conn.exec_primitive( |
535 |
|
"cluster", self.kdu_instance, self.action_name, params=params |
536 |
|
) |
537 |
|
) |
538 |
|
|
539 |
1 |
self.assertIsNone(output) |
540 |
1 |
self.k8s_juju_conn._obtain_namespace_from_db.assert_called_once_with( |
541 |
|
kdu_instance=self.kdu_instance |
542 |
|
) |
543 |
1 |
self.k8s_juju_conn.libjuju.get_actions.assert_called_once_with( |
544 |
|
application_name=self.application_name, model_name=self.default_namespace |
545 |
|
) |
546 |
1 |
self.k8s_juju_conn.libjuju.execute_action.assert_called_once_with( |
547 |
|
application_name=self.application_name, |
548 |
|
model_name=self.default_namespace, |
549 |
|
action_name=self.action_name, |
550 |
|
**params |
551 |
|
) |
552 |
|
|
553 |
|
|
554 |
1 |
class InspectKduTest(K8sJujuConnTestCase): |
555 |
1 |
def setUp(self): |
556 |
1 |
super(InspectKduTest, self).setUp() |
557 |
|
|
558 |
1 |
@asynctest.mock.patch("builtins.open") |
559 |
1 |
@asynctest.mock.patch("os.path.exists") |
560 |
1 |
def test_existing_file(self, mock_exists, mock_open): |
561 |
1 |
mock_exists.return_value = True |
562 |
1 |
content = """{ |
563 |
|
'description': 'test bundle', |
564 |
|
'bundle': 'kubernetes', |
565 |
|
'applications': {'app':{ }, 'app2': { }} |
566 |
|
}""" |
567 |
1 |
mock_open.return_value = FakeFileWrapper(content=content) |
568 |
1 |
kdu = self.loop.run_until_complete(self.k8s_juju_conn.inspect_kdu("model")) |
569 |
1 |
self.assertEqual(kdu, {"app": {}, "app2": {}}) |
570 |
1 |
mock_exists.assert_called_once() |
571 |
1 |
mock_open.assert_called_once() |
572 |
|
|
573 |
1 |
@asynctest.mock.patch("builtins.open") |
574 |
1 |
@asynctest.mock.patch("os.path.exists") |
575 |
1 |
def test_not_existing_file(self, mock_exists, mock_open): |
576 |
1 |
kdu = None |
577 |
1 |
mock_exists.return_value = False |
578 |
1 |
with self.assertRaises(K8sException): |
579 |
1 |
kdu = self.loop.run_until_complete(self.k8s_juju_conn.inspect_kdu("model")) |
580 |
1 |
self.assertEqual(kdu, None) |
581 |
1 |
mock_exists.assert_called_once_with("model") |
582 |
1 |
mock_open.assert_not_called() |
583 |
|
|
584 |
|
|
585 |
1 |
class HelpKduTest(K8sJujuConnTestCase): |
586 |
1 |
def setUp(self): |
587 |
1 |
super(HelpKduTest, self).setUp() |
588 |
|
|
589 |
1 |
@asynctest.mock.patch("builtins.open") |
590 |
1 |
@asynctest.mock.patch("os.listdir") |
591 |
1 |
def test_existing_file(self, mock_listdir, mock_open): |
592 |
1 |
content = "Readme file content" |
593 |
1 |
mock_open.return_value = FakeFileWrapper(content=content) |
594 |
1 |
for file in ["README.md", "README.txt", "README"]: |
595 |
1 |
mock_listdir.return_value = [file] |
596 |
1 |
help = self.loop.run_until_complete( |
597 |
|
self.k8s_juju_conn.help_kdu("kdu_instance") |
598 |
|
) |
599 |
1 |
self.assertEqual(help, content) |
600 |
|
|
601 |
1 |
self.assertEqual(mock_listdir.call_count, 3) |
602 |
1 |
self.assertEqual(mock_open.call_count, 3) |
603 |
|
|
604 |
1 |
@asynctest.mock.patch("builtins.open") |
605 |
1 |
@asynctest.mock.patch("os.listdir") |
606 |
1 |
def test_not_existing_file(self, mock_listdir, mock_open): |
607 |
1 |
for file in ["src/charm.py", "tox.ini", "requirements.txt"]: |
608 |
1 |
mock_listdir.return_value = [file] |
609 |
1 |
help = self.loop.run_until_complete( |
610 |
|
self.k8s_juju_conn.help_kdu("kdu_instance") |
611 |
|
) |
612 |
1 |
self.assertEqual(help, None) |
613 |
|
|
614 |
1 |
self.assertEqual(mock_listdir.call_count, 3) |
615 |
1 |
self.assertEqual(mock_open.call_count, 0) |
616 |
|
|
617 |
|
|
618 |
1 |
class StatusKduTest(K8sJujuConnTestCase): |
619 |
1 |
def setUp(self): |
620 |
1 |
super(StatusKduTest, self).setUp() |
621 |
1 |
self.k8s_juju_conn.libjuju.get_model_status = AsyncMock() |
622 |
|
|
623 |
1 |
def test_success(self): |
624 |
1 |
applications = {"app": {"status": {"status": "active"}}} |
625 |
1 |
model = FakeModel(applications=applications) |
626 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.return_value = model |
627 |
1 |
status = self.loop.run_until_complete( |
628 |
|
self.k8s_juju_conn.status_kdu("cluster", "kdu_instance") |
629 |
|
) |
630 |
1 |
self.assertEqual(status, {"app": {"status": "active"}}) |
631 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.assert_called_once() |
632 |
|
|
633 |
1 |
def test_exception(self): |
634 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.side_effect = Exception() |
635 |
1 |
status = None |
636 |
1 |
with self.assertRaises(Exception): |
637 |
1 |
status = self.loop.run_until_complete( |
638 |
|
self.k8s_juju_conn.status_kdu("cluster", "kdu_instance") |
639 |
|
) |
640 |
1 |
self.assertIsNone(status) |
641 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.assert_called_once() |
642 |
|
|
643 |
|
|
644 |
1 |
class GetServicesTest(K8sJujuConnTestCase): |
645 |
1 |
def setUp(self): |
646 |
1 |
super(GetServicesTest, self).setUp() |
647 |
|
|
648 |
1 |
@asynctest.mock.patch("n2vc.k8s_juju_conn.K8sJujuConnector.get_credentials") |
649 |
1 |
def test_success(self, mock_get_credentials): |
650 |
1 |
mock_get_credentials.return_value = kubeconfig |
651 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.get_services("", "", "")) |
652 |
1 |
mock_get_credentials.assert_called_once() |
653 |
1 |
self.kubectl.get_services.assert_called_once() |
654 |
|
|
655 |
|
|
656 |
1 |
class GetServiceTest(K8sJujuConnTestCase): |
657 |
1 |
def setUp(self): |
658 |
1 |
super(GetServiceTest, self).setUp() |
659 |
|
|
660 |
1 |
@asynctest.mock.patch("n2vc.k8s_juju_conn.K8sJujuConnector.get_credentials") |
661 |
1 |
def test_success(self, mock_get_credentials): |
662 |
1 |
mock_get_credentials.return_value = kubeconfig |
663 |
1 |
self.loop.run_until_complete(self.k8s_juju_conn.get_service("", "", "")) |
664 |
1 |
mock_get_credentials.assert_called_once() |
665 |
1 |
self.kubectl.get_services.assert_called_once() |
666 |
|
|
667 |
|
|
668 |
1 |
class GetCredentialsTest(K8sJujuConnTestCase): |
669 |
1 |
def setUp(self): |
670 |
1 |
super(GetCredentialsTest, self).setUp() |
671 |
|
|
672 |
1 |
@asynctest.mock.patch("yaml.safe_dump") |
673 |
1 |
def test_success(self, mock_safe_dump): |
674 |
1 |
self.k8s_juju_conn.db.get_one.return_value = { |
675 |
|
"_id": "id", |
676 |
|
"credentials": "credentials", |
677 |
|
"schema_version": "2", |
678 |
|
} |
679 |
1 |
self.k8s_juju_conn.get_credentials("cluster_uuid") |
680 |
1 |
self.k8s_juju_conn.db.get_one.assert_called_once() |
681 |
1 |
self.k8s_juju_conn.db.encrypt_decrypt_fields.assert_called_once() |
682 |
1 |
mock_safe_dump.assert_called_once() |
683 |
|
|
684 |
|
|
685 |
1 |
class UpdateVcaStatusTest(K8sJujuConnTestCase): |
686 |
1 |
def setUp(self): |
687 |
1 |
super(UpdateVcaStatusTest, self).setUp() |
688 |
1 |
self.vcaStatus = {"model": {"applications": {"app": {"actions": {}}}}} |
689 |
1 |
self.k8s_juju_conn.libjuju.get_executed_actions = AsyncMock() |
690 |
1 |
self.k8s_juju_conn.libjuju.get_actions = AsyncMock() |
691 |
1 |
self.k8s_juju_conn.libjuju.get_application_configs = AsyncMock() |
692 |
|
|
693 |
1 |
def test_success(self): |
694 |
1 |
self.loop.run_until_complete( |
695 |
|
self.k8s_juju_conn.update_vca_status(self.vcaStatus, self.kdu_instance) |
696 |
|
) |
697 |
1 |
self.k8s_juju_conn.libjuju.get_executed_actions.assert_called_once() |
698 |
1 |
self.k8s_juju_conn.libjuju.get_application_configs.assert_called_once() |
699 |
|
|
700 |
1 |
def test_exception(self): |
701 |
1 |
self.k8s_juju_conn.libjuju.get_model.return_value = None |
702 |
1 |
self.k8s_juju_conn.libjuju.get_executed_actions.side_effect = Exception() |
703 |
1 |
with self.assertRaises(Exception): |
704 |
1 |
self.loop.run_until_complete( |
705 |
|
self.k8s_juju_conn.update_vca_status(self.vcaStatus, self.kdu_instance) |
706 |
|
) |
707 |
1 |
self.k8s_juju_conn.libjuju.get_executed_actions.assert_not_called() |
708 |
0 |
self.k8s_juju_conn.libjuju.get_application_configs.assert_not_called_once() |
709 |
|
|
710 |
|
|
711 |
1 |
class ScaleTest(K8sJujuConnTestCase): |
712 |
1 |
def setUp(self): |
713 |
1 |
super(ScaleTest, self).setUp() |
714 |
1 |
self.application_name = "app" |
715 |
1 |
self.kdu_name = "kdu-instance" |
716 |
1 |
self._scale = 2 |
717 |
1 |
self.k8s_juju_conn.libjuju.scale_application = AsyncMock() |
718 |
|
|
719 |
1 |
def test_success(self): |
720 |
1 |
self.loop.run_until_complete( |
721 |
|
self.k8s_juju_conn.scale(self.kdu_name, self._scale, self.application_name) |
722 |
|
) |
723 |
1 |
self.k8s_juju_conn.libjuju.scale_application.assert_called_once() |
724 |
|
|
725 |
1 |
def test_exception(self): |
726 |
1 |
self.k8s_juju_conn.libjuju.scale_application.side_effect = Exception() |
727 |
1 |
with self.assertRaises(Exception): |
728 |
1 |
self.loop.run_until_complete( |
729 |
|
self.k8s_juju_conn.scale( |
730 |
|
self.kdu_name, self._scale, self.application_name |
731 |
|
) |
732 |
|
) |
733 |
1 |
self.k8s_juju_conn.libjuju.scale_application.assert_called_once() |
734 |
|
|
735 |
|
|
736 |
1 |
class GetScaleCount(K8sJujuConnTestCase): |
737 |
1 |
def setUp(self): |
738 |
1 |
super(GetScaleCount, self).setUp() |
739 |
1 |
self.k8s_juju_conn.libjuju.get_model_status = AsyncMock() |
740 |
|
|
741 |
1 |
def test_success(self): |
742 |
1 |
applications = {"app": FakeApplication()} |
743 |
1 |
model = FakeModel(applications=applications) |
744 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.return_value = model |
745 |
1 |
status = self.loop.run_until_complete( |
746 |
|
self.k8s_juju_conn.get_scale_count("app", "kdu_instance") |
747 |
|
) |
748 |
1 |
self.assertEqual(status, 2) |
749 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.assert_called_once() |
750 |
|
|
751 |
1 |
def test_exception(self): |
752 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.side_effect = Exception() |
753 |
1 |
status = None |
754 |
1 |
with self.assertRaises(Exception): |
755 |
1 |
status = self.loop.run_until_complete( |
756 |
|
self.k8s_juju_conn.status_kdu("app", "kdu_instance") |
757 |
|
) |
758 |
1 |
self.assertIsNone(status) |
759 |
1 |
self.k8s_juju_conn.libjuju.get_model_status.assert_called_once() |
760 |
|
|
761 |
|
|
762 |
1 |
class AddRelationTest(K8sJujuConnTestCase): |
763 |
1 |
def setUp(self): |
764 |
1 |
super(AddRelationTest, self).setUp() |
765 |
1 |
self.k8s_juju_conn.libjuju.add_relation = AsyncMock() |
766 |
1 |
self.k8s_juju_conn.libjuju.offer = AsyncMock() |
767 |
1 |
self.k8s_juju_conn.libjuju.get_controller = AsyncMock() |
768 |
1 |
self.k8s_juju_conn.libjuju.consume = AsyncMock() |
769 |
|
|
770 |
1 |
def test_standard_relation_same_model_and_controller(self): |
771 |
1 |
relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint1") |
772 |
1 |
relation_endpoint_2 = RelationEndpoint("model-1.app2.1", None, "endpoint2") |
773 |
1 |
self.loop.run_until_complete( |
774 |
|
self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2) |
775 |
|
) |
776 |
1 |
self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with( |
777 |
|
model_name="model-1", |
778 |
|
endpoint_1="app1:endpoint1", |
779 |
|
endpoint_2="app2:endpoint2", |
780 |
|
) |
781 |
1 |
self.k8s_juju_conn.libjuju.offer.assert_not_called() |
782 |
1 |
self.k8s_juju_conn.libjuju.consume.assert_not_called() |
783 |
|
|
784 |
1 |
def test_cmr_relation_same_controller(self): |
785 |
1 |
relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint") |
786 |
1 |
relation_endpoint_2 = RelationEndpoint("model-2.app2.1", None, "endpoint") |
787 |
1 |
offer = Offer("admin/model-1.app1") |
788 |
1 |
self.k8s_juju_conn.libjuju.offer.return_value = offer |
789 |
1 |
self.k8s_juju_conn.libjuju.consume.return_value = "saas" |
790 |
1 |
self.loop.run_until_complete( |
791 |
|
self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2) |
792 |
|
) |
793 |
1 |
self.k8s_juju_conn.libjuju.offer.assert_called_once_with(relation_endpoint_1) |
794 |
1 |
self.k8s_juju_conn.libjuju.consume.assert_called_once() |
795 |
1 |
self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with( |
796 |
|
"model-2", "app2:endpoint", "saas" |
797 |
|
) |
798 |
|
|
799 |
1 |
def test_cmr_relation_different_controller(self): |
800 |
1 |
self.k8s_juju_conn._get_libjuju = AsyncMock( |
801 |
|
return_value=self.k8s_juju_conn.libjuju |
802 |
|
) |
803 |
1 |
relation_endpoint_1 = RelationEndpoint("model-1.app1.0", "vca-id-1", "endpoint") |
804 |
1 |
relation_endpoint_2 = RelationEndpoint("model-1.app2.1", "vca-id-2", "endpoint") |
805 |
1 |
offer = Offer("admin/model-1.app1") |
806 |
1 |
self.k8s_juju_conn.libjuju.offer.return_value = offer |
807 |
1 |
self.k8s_juju_conn.libjuju.consume.return_value = "saas" |
808 |
1 |
self.loop.run_until_complete( |
809 |
|
self.k8s_juju_conn.add_relation(relation_endpoint_1, relation_endpoint_2) |
810 |
|
) |
811 |
1 |
self.k8s_juju_conn.libjuju.offer.assert_called_once_with(relation_endpoint_1) |
812 |
1 |
self.k8s_juju_conn.libjuju.consume.assert_called_once() |
813 |
1 |
self.k8s_juju_conn.libjuju.add_relation.assert_called_once_with( |
814 |
|
"model-1", "app2:endpoint", "saas" |
815 |
|
) |
816 |
|
|
817 |
1 |
def test_relation_exception(self): |
818 |
1 |
relation_endpoint_1 = RelationEndpoint("model-1.app1.0", None, "endpoint") |
819 |
1 |
relation_endpoint_2 = RelationEndpoint("model-2.app2.1", None, "endpoint") |
820 |
1 |
self.k8s_juju_conn.libjuju.offer.side_effect = Exception() |
821 |
1 |
with self.assertRaises(Exception): |
822 |
1 |
self.loop.run_until_complete( |
823 |
|
self.k8s_juju_conn.add_relation( |
824 |
|
relation_endpoint_1, relation_endpoint_2 |
825 |
|
) |
826 |
|
) |