1 # Copyright 2020 Canonical Ltd.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 from n2vc
.utils
import Dict
, N2VCDeploymentStatus
18 from n2vc
.n2vc_conn
import N2VCConnector
19 from unittest
.mock
import MagicMock
22 kubeconfig
= """apiVersion: v1
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
53 cluster: microk8s-cluster
56 current-context: microk8s
62 token: clhkRExRem5Xd1dCdnFEVXdvRGtDRGE5b1F3WnNrZk5qeHFCOU10bHBZRT0K
66 async def AsyncMockFunc():
67 await asyncio
.sleep(1)
70 class AsyncMock(MagicMock
):
71 async def __call__(self
, *args
, **kwargs
):
72 return super(AsyncMock
, self
).__call
__(*args
, **kwargs
)
75 class FakeN2VC(MagicMock
):
76 last_written_values
= None
78 async def write_app_status_to_db(
81 status
: N2VCDeploymentStatus
,
88 Write application status to database
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.
97 self
.last_written_values
= Dict(
99 "n2vc_status": status
,
100 "message": detailed_status
,
101 "vca_status": vca_status
,
102 "entity": entity_type
,
106 osm_status
= N2VCConnector
.osm_status
109 class FakeMachine(MagicMock
):
111 dns_name
= "FAKE ENDPOINT"
112 model_name
= "FAKE MODEL"
113 entity_type
= "machine"
114 safe_data
= {"instance-id": "myid"}
116 async def destroy(self
, force
):
120 class FakeManualMachine(MagicMock
):
122 dns_name
= "FAKE ENDPOINT"
123 model_name
= "FAKE MODEL"
124 entity_type
= "machine"
125 safe_data
= {"instance-id": "manual:myid"}
126 series
= "FAKE SERIES"
128 async def destroy(self
, force
):
132 class FakeWatcher(AsyncMock
):
134 delta_to_return
= None
136 async def Next(self
):
137 return Dict({"deltas": self
.delta_to_return
})
140 class FakeConnection(MagicMock
):
145 class FakeAction(MagicMock
):
151 def __init__(self
, applications
: dict = {}):
152 self
._applications
= applications
155 def applications(self
):
156 return self
._applications
159 class FakeUnit(MagicMock
):
160 async def is_leader_from_status(self
):
163 async def run_action(self
, action_name
, **kwargs
):
167 def machine_id(self
):
168 return "existing_machine_id"
170 name
= "existing_unit"
173 class FakeApplication(AsyncMock
):
174 async def set_config(self
, config
):
177 async def add_unit(self
, to
):
180 async def destroy_unit(self
, unit_name
):
183 async def get_actions(self
):
184 return ["existing_action"]
186 async def get_config(self
):
187 return ["app_config"]
189 async def scale(self
, scale
):
192 units
= [FakeUnit(), FakeUnit()]
196 def __init__(self
, content
: str = ""):
197 self
.content
= content
199 def read(self
, size
: int = -1):
203 class FakeFileWrapper
:
204 def __init__(self
, content
: str = ""):
205 self
.file = FakeFile(content
=content
)
210 def __exit__(self
, type, value
, traceback
):
214 FAKE_DELTA_MACHINE_PENDING
= Dict(
216 "deltas": ["machine", "change", {}],
221 "instance-id": "juju-1b5808-2",
222 "agent-status": {"current": "pending", "message": "", "version": ""},
223 "instance-status": {"current": "running", "message": "Running"},
227 FAKE_DELTA_MACHINE_STARTED
= Dict(
229 "deltas": ["machine", "change", {}],
234 "instance-id": "juju-1b5808-2",
235 "agent-status": {"current": "started", "message": "", "version": ""},
236 "instance-status": {"current": "running", "message": "Running"},
241 FAKE_DELTA_UNIT_PENDING
= Dict(
243 "deltas": ["unit", "change", {}],
248 "application": "git",
250 "workload-status": {"current": "waiting", "message": ""},
251 "agent-status": {"current": "idle", "message": ""},
256 FAKE_DELTA_UNIT_STARTED
= Dict(
258 "deltas": ["unit", "change", {}],
263 "application": "git",
265 "workload-status": {"current": "active", "message": ""},
266 "agent-status": {"current": "idle", "message": ""},
271 FAKE_DELTA_APPLICATION_MAINTENANCE
= Dict(
273 "deltas": ["application", "change", {}],
274 "entity": "application",
279 "current": "maintenance",
280 "message": "installing charm software",
286 FAKE_DELTA_APPLICATION_ACTIVE
= Dict(
288 "deltas": ["application", "change", {}],
289 "entity": "application",
291 "data": {"name": "git", "status": {"current": "active", "message": "Ready!"}},
295 FAKE_DELTA_ACTION_COMPLETED
= Dict(
297 "deltas": ["action", "change", {}],
301 "model-uuid": "af19cdd4-374a-4d9f-86b1-bfed7b1b5808",
305 "status": "completed",
314 "entity": Dict({"id": "2", "type": "machine"}),
315 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
316 "delta": FAKE_DELTA_MACHINE_PENDING
,
317 "entity_status": Dict(
318 {"status": "pending", "message": "Running", "vca_status": "running"}
325 "message": "Running",
327 "vca_status": "running",
328 "n2vc_status": N2VCDeploymentStatus
.PENDING
,
337 "entity": Dict({"id": "2", "type": "machine"}),
338 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
339 "delta": FAKE_DELTA_MACHINE_PENDING
,
340 "entity_status": Dict(
341 {"status": "pending", "message": "Running", "vca_status": "running"}
343 "db": Dict({"written": False, "data": None}),
348 "entity": Dict({"id": "2", "type": "machine"}),
349 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
350 "delta": FAKE_DELTA_MACHINE_STARTED
,
351 "entity_status": Dict(
352 {"status": "started", "message": "Running", "vca_status": "running"}
359 "message": "Running",
361 "vca_status": "running",
362 "n2vc_status": N2VCDeploymentStatus
.COMPLETED
,
371 "entity": Dict({"id": "2", "type": "machine"}),
372 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
373 "delta": FAKE_DELTA_MACHINE_STARTED
,
374 "entity_status": Dict(
375 {"status": "started", "message": "Running", "vca_status": "running"}
377 "db": Dict({"written": False, "data": None}),
382 "entity": Dict({"id": "git/0", "type": "unit"}),
383 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
384 "delta": FAKE_DELTA_UNIT_PENDING
,
385 "entity_status": Dict(
386 {"status": "waiting", "message": "", "vca_status": "waiting"}
395 "vca_status": "waiting",
396 "n2vc_status": N2VCDeploymentStatus
.RUNNING
,
405 "entity": Dict({"id": "git/0", "type": "unit"}),
406 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
407 "delta": FAKE_DELTA_UNIT_PENDING
,
408 "entity_status": Dict(
409 {"status": "waiting", "message": "", "vca_status": "waiting"}
411 "db": Dict({"written": False, "data": None}),
416 "entity": Dict({"id": "git/0", "type": "unit"}),
417 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
418 "delta": FAKE_DELTA_UNIT_STARTED
,
419 "entity_status": Dict(
420 {"status": "active", "message": "", "vca_status": "active"}
429 "vca_status": "active",
430 "n2vc_status": N2VCDeploymentStatus
.COMPLETED
,
439 "entity": Dict({"id": "git/0", "type": "unit"}),
440 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
441 "delta": FAKE_DELTA_UNIT_STARTED
,
442 "entity_status": Dict(
443 {"status": "active", "message": "", "vca_status": "active"}
445 "db": Dict({"written": False, "data": None}),
450 "entity": Dict({"id": "git", "type": "application"}),
451 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
452 "delta": FAKE_DELTA_APPLICATION_MAINTENANCE
,
453 "entity_status": Dict(
455 "status": "maintenance",
456 "message": "installing charm software",
457 "vca_status": "maintenance",
465 "message": "installing charm software",
466 "entity": "application",
467 "vca_status": "maintenance",
468 "n2vc_status": N2VCDeploymentStatus
.RUNNING
,
477 "entity": Dict({"id": "git", "type": "application"}),
478 "filter": Dict({"entity_id": "2", "entity_type": "machine"}),
479 "delta": FAKE_DELTA_APPLICATION_MAINTENANCE
,
480 "entity_status": Dict(
482 "status": "maintenance",
483 "message": "installing charm software",
484 "vca_status": "maintenance",
487 "db": Dict({"written": False, "data": None}),
492 "entity": Dict({"id": "git", "type": "application"}),
493 "filter": Dict({"entity_id": "git", "entity_type": "application"}),
494 "delta": FAKE_DELTA_APPLICATION_ACTIVE
,
495 "entity_status": Dict(
496 {"status": "active", "message": "Ready!", "vca_status": "active"}
504 "entity": "application",
505 "vca_status": "active",
506 "n2vc_status": N2VCDeploymentStatus
.COMPLETED
,
515 "entity": Dict({"id": "git", "type": "application"}),
516 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
517 "delta": FAKE_DELTA_APPLICATION_ACTIVE
,
518 "entity_status": Dict(
519 {"status": "active", "message": "Ready!", "vca_status": "active"}
521 "db": Dict({"written": False, "data": None}),
526 "entity": Dict({"id": "1", "type": "action"}),
527 "filter": Dict({"entity_id": "1", "entity_type": "action"}),
528 "delta": FAKE_DELTA_ACTION_COMPLETED
,
529 "entity_status": Dict(
531 "status": "completed",
532 "message": "completed",
533 "vca_status": "completed",
541 "message": "completed",
543 "vca_status": "completed",
544 "n2vc_status": N2VCDeploymentStatus
.COMPLETED
,
553 "entity": Dict({"id": "git", "type": "action"}),
554 "filter": Dict({"entity_id": "1", "entity_type": "machine"}),
555 "delta": FAKE_DELTA_ACTION_COMPLETED
,
556 "entity_status": Dict(
558 "status": "completed",
559 "message": "completed",
560 "vca_status": "completed",
563 "db": Dict({"written": False, "data": None}),