Skip to content

Commit 05f8991

Browse files
Derive the application status
With changes to juju, the application status was changed for the CLI to use the model cache to derive the status of the application from the unit status. Unfortunately the logic didn't reach the all watcher and in doing so always reports the last application status. Unfortunately the facade version wasn't bumped, which makes facade checking for old and new logic almost impossible. Instead the solution here is to always query the unit status, BUT add the application status in to the derive_status() call so that we always buble the most relavant serverity to the top. This should happily work in a backwards compatibility way, so if the application is blocked and any units are waiting, then the application status will always win. Similarly if the units are blocked and the application status is waiting, then blocked will be shown. The one caveat is, that if the older juju didn't bubble up the worst serverity to the application status, then you could end up with a missmatch. For example; unit sets to error, but the application status is waiting. Then juju CLI would show waiting, but pylibjuju would show error. I'm unsure if that is actually a fundamental problem, as I don't believe it should happen, but in theory it should be at least known.
1 parent 839a99f commit 05f8991

2 files changed

Lines changed: 23 additions & 10 deletions

File tree

juju/application.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,16 @@ def is_us(ep):
7474

7575
@property
7676
def status(self):
77-
"""Get the application status, as set by the charm's leader.
77+
"""Get the application status.
7878
79+
If the application is unknown it will attempt to derive the unit
80+
workload status and highlight the most relevant (severity).
7981
"""
8082
status = self.safe_data['status']['current']
81-
if status == 'unset':
82-
unit_status = []
83-
for unit in self.units:
84-
unit_status.append(unit.workload_status)
85-
return derive_status(unit_status)
86-
87-
return status
83+
unit_status = [status]
84+
for unit in self.units:
85+
unit_status.append(unit.workload_status)
86+
return derive_status(unit_status)
8887

8988
@property
9089
def status_message(self):

tests/integration/test_application.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ async def test_action(event_loop):
4747

4848
@base.bootstrapped
4949
@pytest.mark.asyncio
50-
async def test_status(event_loop):
51-
50+
async def test_status_is_not_unset(event_loop):
5251
async with base.CleanModel() as model:
5352
app = await model.deploy(
5453
'ubuntu-0',
@@ -60,6 +59,21 @@ async def test_status(event_loop):
6059
assert app.status != 'unset'
6160

6261

62+
@base.bootstrapped
63+
@pytest.mark.asyncio
64+
async def test_status(event_loop):
65+
async with base.CleanModel() as model:
66+
app = await model.deploy('cs:~juju-qa/blocked-0')
67+
68+
def app_ready():
69+
if not app.units:
70+
return False
71+
return app.status == 'blocked'
72+
73+
await asyncio.wait_for(model.block_until(app_ready), timeout=480)
74+
assert app.status == 'blocked'
75+
76+
6377
@base.bootstrapped
6478
@pytest.mark.asyncio
6579
async def test_add_units(event_loop):

0 commit comments

Comments
 (0)