Feature 10509 manual scaling for native k8s charm
[osm/N2VC.git] / n2vc / tests / unit / utils.py
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 import asyncio
16
17 from n2vc.utils import Dict, N2VCDeploymentStatus
18 from n2vc.n2vc_conn import N2VCConnector
19 from unittest.mock import MagicMock
20
21
22 kubeconfig = """apiVersion: v1
23 clusters:
24 - cluster:
25 certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1\
26 JSURBVENDQWVtZ0F3SUJBZ0lKQUxjMk9xVUpwcnVCTUEwR0NTcUdTSWIzRFFFQk\
27 N3VUFNQmN4RlRBVEJnTlYKQkFNTURERXdMakUxTWk0eE9ETXVNVEFlRncweU1EQ\
28 TVNVEV4TkRJeU16VmFGdzB6TURBNU1Ea3hOREl5TXpWYQpNQmN4RlRBVEJnTlZC\
29 QU1NRERFd0xqRTFNaTR4T0RNdU1UQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQUR\
30 nZ0VQCkFEQ0NBUW9DZ2dFQkFNV0tyQkdxWlJRT0VONDExR2RESmY2ckZWRDcvMU\
31 xHNlZMWjNhd1BRdHBhRTRxdVdyNisKWjExTWwra2kwVEU1cGZFV3dKenVUZXlCU\
32 XVkUEpnYm1QTjF1VWROdGRiNlpocHEzeC9oT0hCMVJLNC9iSlNFUgpiZ0dITmN6\
33 MzR6SHRaZ1dwb2NPTXpPOW9oRUdhMTZUaDhmQWVxYU1CQTJRaklmeUFlaVp3VHJ\
34 nZ3BrY2dBMUlOCjBvQkdqSURnSGVoSU5tbGZOOURkQ3hNN1FNTmtSbzRXdE13bF\
35 JSRWZ4QnFiVkNpZGFjbVhhb1VPUjJPeFVmQWEKN1orSUU1TmN5ZFQ1TGovazdwd\
36 XZCVkdIa0JQWnE0TmlBa3R4aXd5NVB5R29GTk9mT0NrV2I2VnBzVzNhTlNJeAo4\
37 aXBITkc3enV3elc1TGQ5TkhQYWpRckZwdFZBSHpJNWNhRUNBd0VBQWFOUU1FNHd\
38 IUVlEVlIwT0JCWUVGQ1dVCkFaTXNaeE13L1k1OGlXMGZJWVAzcDdTYk1COEdBMV\
39 VkSXdRWU1CYUFGQ1dVQVpNc1p4TXcvWTU4aVcwZklZUDMKcDdTYk1Bd0dBMVVkR\
40 XdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUJaMlYxMWowRzhh\
41 Z1Z6Twp2YWtKTGt4UGZ0UE1NMFFOaVRzZmV6RzlicnBkdEVLSjFyalFCblNXYTN\
42 WbThWRGZTYkhLQUNXaGh0OEhzcXhtCmNzdVQyOWUyaGZBNHVIOUxMdy9MVG5EdE\
43 tJSjZ6aWFzaTM5RGh3UGwwaExuamJRMjk4VVo5TGovVlpnZGlqemIKWnVPdHlpT\
44 nVOS0E2Nmd0dGxXcWZRQ2hkbnJ5MlZUbjBjblR5dU9UalByYWdOdXJMdlVwL3Nl\
45 eURhZmsxNXJ4egozcmlYZldiQnRhUUk1dnM0ekFKU2xneUg2RnpiZStoTUhlUzF\
46 mM2ppb3dJV0lRR2NNbHpGT1RpMm1xWFRybEJYCnh1WmpLZlpOcndjQVNGbk9qYV\
47 BWeFQ1ODJ4WWhtTm8wR3J2MlZEck51bDlSYkgvK3lNS2J5NEhkOFRvVThMU2kKY\
48 3Uxajh3cz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
49 server: https://192.168.0.22:16443
50 name: microk8s-cluster
51 contexts:
52 - context:
53 cluster: microk8s-cluster
54 user: admin
55 name: microk8s
56 current-context: microk8s
57 kind: Config
58 preferences: {}
59 users:
60 - name: admin
61 user:
62 token: clhkRExRem5Xd1dCdnFEVXdvRGtDRGE5b1F3WnNrZk5qeHFCOU10bHBZRT0K
63 """
64
65
66 async def AsyncMockFunc():
67 await asyncio.sleep(1)
68
69
70 class AsyncMock(MagicMock):
71 async def __call__(self, *args, **kwargs):
72 return super(AsyncMock, self).__call__(*args, **kwargs)
73
74
75 class FakeN2VC(MagicMock):
76 last_written_values = None
77
78 async def write_app_status_to_db(
79 self,
80 db_dict: dict,
81 status: N2VCDeploymentStatus,
82 detailed_status: str,
83 vca_status: str,
84 entity_type: str,
85 vca_id: str = None,
86 ):
87 """
88 Write application status to database
89
90 :param: db_dict: DB dictionary
91 :param: status: Status of the application
92 :param: detailed_status: Detailed status
93 :param: vca_status: VCA status
94 :param: entity_type: Entity type ("application", "machine, and "action")
95 :param: vca_id: Id of the VCA. If None, the default VCA will be used.
96 """
97 self.last_written_values = Dict(
98 {
99 "n2vc_status": status,
100 "message": detailed_status,
101 "vca_status": vca_status,
102 "entity": entity_type,
103 }
104 )
105
106 osm_status = N2VCConnector.osm_status
107
108
109 class FakeMachine(MagicMock):
110 entity_id = "2"
111 dns_name = "FAKE ENDPOINT"
112 model_name = "FAKE MODEL"
113 entity_type = "machine"
114 safe_data = {"instance-id": "myid"}
115
116 async def destroy(self, force):
117 pass
118
119
120 class FakeManualMachine(MagicMock):
121 entity_id = "2"
122 dns_name = "FAKE ENDPOINT"
123 model_name = "FAKE MODEL"
124 entity_type = "machine"
125 safe_data = {"instance-id": "manual:myid"}
126
127 async def destroy(self, force):
128 pass
129
130
131 class FakeWatcher(AsyncMock):
132
133 delta_to_return = None
134
135 async def Next(self):
136 return Dict({"deltas": self.delta_to_return})
137
138
139 class FakeConnection(MagicMock):
140 endpoint = None
141 is_open = False
142
143
144 class FakeAction(MagicMock):
145 entity_id = "id"
146 status = "ready"
147
148
149 class FakeModel:
150 def __init__(self, applications: dict = {}):
151 self._applications = applications
152
153 @property
154 def applications(self):
155 return self._applications
156
157
158 class FakeUnit(MagicMock):
159 async def is_leader_from_status(self):
160 return True
161
162 async def run_action(self, action_name, **kwargs):
163 return FakeAction()
164
165
166 class FakeApplication(AsyncMock):
167 async def set_config(self, config):
168 pass
169
170 async def add_unit(self, to):
171 pass
172
173 async def get_actions(self):
174 return ["existing_action"]
175
176 async def get_config(self):
177 return ["app_config"]
178
179 async def scale(self, scale):
180 pass
181
182 units = [FakeUnit(), FakeUnit()]
183
184
185 class FakeFile:
186 def __init__(self, content: str = ""):
187 self.content = content
188
189 def read(self, size: int = -1):
190 return self.content
191
192
193 class FakeFileWrapper:
194 def __init__(self, content: str = ""):
195 self.file = FakeFile(content=content)
196
197 def __enter__(self):
198 return self.file
199
200 def __exit__(self, type, value, traceback):
201 pass
202
203
204 FAKE_DELTA_MACHINE_PENDING = Dict(
205 {
206 "deltas": ["machine", "change", {}],
207 "entity": "machine",
208 "type": "change",
209 "data": {
210 "id": "2",
211 "instance-id": "juju-1b5808-2",
212 "agent-status": {"current": "pending", "message": "", "version": ""},
213 "instance-status": {"current": "running", "message": "Running"},
214 },
215 }
216 )
217 FAKE_DELTA_MACHINE_STARTED = Dict(
218 {
219 "deltas": ["machine", "change", {}],
220 "entity": "machine",
221 "type": "change",
222 "data": {
223 "id": "2",
224 "instance-id": "juju-1b5808-2",
225 "agent-status": {"current": "started", "message": "", "version": ""},
226 "instance-status": {"current": "running", "message": "Running"},
227 },
228 }
229 )
230
231 FAKE_DELTA_UNIT_PENDING = Dict(
232 {
233 "deltas": ["unit", "change", {}],
234 "entity": "unit",
235 "type": "change",
236 "data": {
237 "name": "git/0",
238 "application": "git",
239 "machine-id": "6",
240 "workload-status": {"current": "waiting", "message": ""},
241 "agent-status": {"current": "idle", "message": ""},
242 },
243 }
244 )
245
246 FAKE_DELTA_UNIT_STARTED = Dict(
247 {
248 "deltas": ["unit", "change", {}],
249 "entity": "unit",
250 "type": "change",
251 "data": {
252 "name": "git/0",
253 "application": "git",
254 "machine-id": "6",
255 "workload-status": {"current": "active", "message": ""},
256 "agent-status": {"current": "idle", "message": ""},
257 },
258 }
259 )
260
261 FAKE_DELTA_APPLICATION_MAINTENANCE = Dict(
262 {
263 "deltas": ["application", "change", {}],
264 "entity": "application",
265 "type": "change",
266 "data": {
267 "name": "git",
268 "status": {
269 "current": "maintenance",
270 "message": "installing charm software",
271 },
272 },
273 }
274 )
275
276 FAKE_DELTA_APPLICATION_ACTIVE = Dict(
277 {
278 "deltas": ["application", "change", {}],
279 "entity": "application",
280 "type": "change",
281 "data": {"name": "git", "status": {"current": "active", "message": "Ready!"}},
282 }
283 )
284
285 FAKE_DELTA_ACTION_COMPLETED = Dict(
286 {
287 "deltas": ["action", "change", {}],
288 "entity": "action",
289 "type": "change",
290 "data": {
291 "model-uuid": "af19cdd4-374a-4d9f-86b1-bfed7b1b5808",
292 "id": "1",
293 "receiver": "git/0",
294 "name": "add-repo",
295 "status": "completed",
296 "message": "",
297 },
298 }
299 )
300
301 Deltas = [
302 Dict(
303 {
304 "entity": Dict({"id": "2", "type": "machine"}),
305 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
306 "delta": FAKE_DELTA_MACHINE_PENDING,
307 "entity_status": Dict(
308 {"status": "pending", "message": "Running", "vca_status": "running"}
309 ),
310 "db": Dict(
311 {
312 "written": True,
313 "data": Dict(
314 {
315 "message": "Running",
316 "entity": "machine",
317 "vca_status": "running",
318 "n2vc_status": N2VCDeploymentStatus.PENDING,
319 }
320 ),
321 }
322 ),
323 }
324 ),
325 Dict(
326 {
327 "entity": Dict({"id": "2", "type": "machine"}),
328 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
329 "delta": FAKE_DELTA_MACHINE_PENDING,
330 "entity_status": Dict(
331 {"status": "pending", "message": "Running", "vca_status": "running"}
332 ),
333 "db": Dict({"written": False, "data": None}),
334 }
335 ),
336 Dict(
337 {
338 "entity": Dict({"id": "2", "type": "machine"}),
339 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
340 "delta": FAKE_DELTA_MACHINE_STARTED,
341 "entity_status": Dict(
342 {"status": "started", "message": "Running", "vca_status": "running"}
343 ),
344 "db": Dict(
345 {
346 "written": True,
347 "data": Dict(
348 {
349 "message": "Running",
350 "entity": "machine",
351 "vca_status": "running",
352 "n2vc_status": N2VCDeploymentStatus.COMPLETED,
353 }
354 ),
355 }
356 ),
357 }
358 ),
359 Dict(
360 {
361 "entity": Dict({"id": "2", "type": "machine"}),
362 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
363 "delta": FAKE_DELTA_MACHINE_STARTED,
364 "entity_status": Dict(
365 {"status": "started", "message": "Running", "vca_status": "running"}
366 ),
367 "db": Dict({"written": False, "data": None}),
368 }
369 ),
370 Dict(
371 {
372 "entity": Dict({"id": "git/0", "type": "unit"}),
373 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
374 "delta": FAKE_DELTA_UNIT_PENDING,
375 "entity_status": Dict(
376 {"status": "waiting", "message": "", "vca_status": "waiting"}
377 ),
378 "db": Dict(
379 {
380 "written": True,
381 "data": Dict(
382 {
383 "message": "",
384 "entity": "unit",
385 "vca_status": "waiting",
386 "n2vc_status": N2VCDeploymentStatus.RUNNING,
387 }
388 ),
389 }
390 ),
391 }
392 ),
393 Dict(
394 {
395 "entity": Dict({"id": "git/0", "type": "unit"}),
396 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
397 "delta": FAKE_DELTA_UNIT_PENDING,
398 "entity_status": Dict(
399 {"status": "waiting", "message": "", "vca_status": "waiting"}
400 ),
401 "db": Dict({"written": False, "data": None}),
402 }
403 ),
404 Dict(
405 {
406 "entity": Dict({"id": "git/0", "type": "unit"}),
407 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
408 "delta": FAKE_DELTA_UNIT_STARTED,
409 "entity_status": Dict(
410 {"status": "active", "message": "", "vca_status": "active"}
411 ),
412 "db": Dict(
413 {
414 "written": True,
415 "data": Dict(
416 {
417 "message": "",
418 "entity": "unit",
419 "vca_status": "active",
420 "n2vc_status": N2VCDeploymentStatus.COMPLETED,
421 }
422 ),
423 }
424 ),
425 }
426 ),
427 Dict(
428 {
429 "entity": Dict({"id": "git/0", "type": "unit"}),
430 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
431 "delta": FAKE_DELTA_UNIT_STARTED,
432 "entity_status": Dict(
433 {"status": "active", "message": "", "vca_status": "active"}
434 ),
435 "db": Dict({"written": False, "data": None}),
436 }
437 ),
438 Dict(
439 {
440 "entity": Dict({"id": "git", "type": "application"}),
441 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
442 "delta": FAKE_DELTA_APPLICATION_MAINTENANCE,
443 "entity_status": Dict(
444 {
445 "status": "maintenance",
446 "message": "installing charm software",
447 "vca_status": "maintenance",
448 }
449 ),
450 "db": Dict(
451 {
452 "written": True,
453 "data": Dict(
454 {
455 "message": "installing charm software",
456 "entity": "application",
457 "vca_status": "maintenance",
458 "n2vc_status": N2VCDeploymentStatus.RUNNING,
459 }
460 ),
461 }
462 ),
463 }
464 ),
465 Dict(
466 {
467 "entity": Dict({"id": "git", "type": "application"}),
468 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
469 "delta": FAKE_DELTA_APPLICATION_MAINTENANCE,
470 "entity_status": Dict(
471 {
472 "status": "maintenance",
473 "message": "installing charm software",
474 "vca_status": "maintenance",
475 }
476 ),
477 "db": Dict({"written": False, "data": None}),
478 }
479 ),
480 Dict(
481 {
482 "entity": Dict({"id": "git", "type": "application"}),
483 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
484 "delta": FAKE_DELTA_APPLICATION_ACTIVE,
485 "entity_status": Dict(
486 {"status": "active", "message": "Ready!", "vca_status": "active"}
487 ),
488 "db": Dict(
489 {
490 "written": True,
491 "data": Dict(
492 {
493 "message": "Ready!",
494 "entity": "application",
495 "vca_status": "active",
496 "n2vc_status": N2VCDeploymentStatus.COMPLETED,
497 }
498 ),
499 }
500 ),
501 }
502 ),
503 Dict(
504 {
505 "entity": Dict({"id": "git", "type": "application"}),
506 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
507 "delta": FAKE_DELTA_APPLICATION_ACTIVE,
508 "entity_status": Dict(
509 {"status": "active", "message": "Ready!", "vca_status": "active"}
510 ),
511 "db": Dict({"written": False, "data": None}),
512 }
513 ),
514 Dict(
515 {
516 "entity": Dict({"id": "1", "type": "action"}),
517 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
518 "delta": FAKE_DELTA_ACTION_COMPLETED,
519 "entity_status": Dict(
520 {
521 "status": "completed",
522 "message": "completed",
523 "vca_status": "completed",
524 }
525 ),
526 "db": Dict(
527 {
528 "written": True,
529 "data": Dict(
530 {
531 "message": "completed",
532 "entity": "action",
533 "vca_status": "completed",
534 "n2vc_status": N2VCDeploymentStatus.COMPLETED,
535 }
536 ),
537 }
538 ),
539 }
540 ),
541 Dict(
542 {
543 "entity": Dict({"id": "git", "type": "action"}),
544 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
545 "delta": FAKE_DELTA_ACTION_COMPLETED,
546 "entity_status": Dict(
547 {
548 "status": "completed",
549 "message": "completed",
550 "vca_status": "completed",
551 }
552 ),
553 "db": Dict({"written": False, "data": None}),
554 }
555 ),
556 ]