Skip to content

Commit 3c1ebe1

Browse files
committed
chore: refactor raise_on into separate helper functions
1 parent cbb73ef commit 3c1ebe1

2 files changed

Lines changed: 57 additions & 44 deletions

File tree

juju/model/_idle.py

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ class CheckStatus:
2727
units: set[str]
2828
"""All units visible at this point."""
2929
ready_units: set[str]
30-
"""Units in good status (workload, agent, machine?)."""
30+
"""Units with the expected workload status."""
3131
idle_units: set[str]
32-
"""Units with stable agent status (FIXME details)."""
32+
"""Units with stable (idle) agent status."""
3333

3434

3535
class Loop:
@@ -56,10 +56,6 @@ def next(self, status: CheckStatus | None) -> bool:
5656

5757
expected_idle_since = now - self.idle_period
5858

59-
# FIXME there's some confusion about what a "busy" unit is
60-
# are we ready when over the last idle_period, every time sampled:
61-
# a. >=N units were ready (possibly different each time), or
62-
# b. >=N units were ready each time
6359
for name in status.units:
6460
if name in status.idle_units:
6561
self.idle_since[name] = min(
@@ -114,40 +110,66 @@ def check(
114110
logger.info("Waiting for app %r", app_name)
115111
return None
116112

117-
# Order of errors:
118-
#
119-
# Machine error (any unit of any app from apps)
120-
# Agent error (-"-)
121-
# Workload error (-"-)
122-
# App error (any app from apps)
123-
#
124-
# Workload blocked (any unit of any app from apps)
125-
# App blocked (any app from apps)
126113
units: dict[str, UnitStatus] = {}
114+
rv = CheckStatus(set(), set(), set())
115+
116+
for app_name in apps:
117+
units.update(app_units(full_status, app_name))
118+
119+
if raise_on_error:
120+
check_errors(full_status, apps, units)
121+
122+
if raise_on_blocked:
123+
check_blocked(full_status, apps, units)
127124

128125
for app_name in apps:
129-
units.update(_app_units(full_status, app_name))
126+
app = full_status.applications[app_name]
127+
assert isinstance(app, ApplicationStatus)
128+
129+
for unit_name, unit in app_units(full_status, app_name).items():
130+
rv.units.add(unit_name)
131+
assert unit.agent_status
132+
assert unit.workload_status
133+
134+
if unit.agent_status.status == "idle":
135+
rv.idle_units.add(unit_name)
136+
137+
if not status or unit.workload_status.status == status:
138+
rv.ready_units.add(unit_name)
139+
140+
return rv
141+
130142

143+
def check_errors(
144+
full_status: FullStatus, apps: AbstractSet[str], units: dict[str, UnitStatus]
145+
) -> None:
146+
"""Check the full status for error conditions, in this order:
147+
148+
- Machine error (any unit of any app from apps)
149+
- Agent error (-"-)
150+
- Workload error (-"-)
151+
- App error (any app from apps)
152+
"""
131153
for unit_name, unit in units.items():
132154
if unit.machine:
133155
machine = full_status.machines[unit.machine]
134156
assert isinstance(machine, MachineStatus)
135157
assert machine.instance_status
136-
if machine.instance_status.status == "error" and raise_on_error:
158+
if machine.instance_status.status == "error":
137159
raise JujuMachineError(
138160
f"{unit_name!r} machine {unit.machine!r} has errored: {machine.instance_status.info!r}"
139161
)
140162

141163
for unit_name, unit in units.items():
142164
assert unit.agent_status
143-
if unit.agent_status.status == "error" and raise_on_error:
165+
if unit.agent_status.status == "error":
144166
raise JujuAgentError(
145167
f"{unit_name!r} agent has errored: {unit.agent_status.info!r}"
146168
)
147169

148170
for unit_name, unit in units.items():
149171
assert unit.workload_status
150-
if unit.workload_status.status == "error" and raise_on_error:
172+
if unit.workload_status.status == "error":
151173
raise JujuUnitError(
152174
f"{unit_name!r} workload has errored: {unit.workload_status.info!r}"
153175
)
@@ -156,12 +178,21 @@ def check(
156178
app = full_status.applications[app_name]
157179
assert isinstance(app, ApplicationStatus)
158180
assert app.status
159-
if app.status.status == "error" and raise_on_error:
181+
if app.status.status == "error":
160182
raise JujuAppError(f"{app_name!r} has errored: {app.status.info!r}")
161183

184+
185+
def check_blocked(
186+
full_status: FullStatus, apps: AbstractSet[str], units: dict[str, UnitStatus]
187+
) -> None:
188+
"""Check the full status for blocked conditions, in this order:
189+
190+
- Workload blocked (any unit of any app from apps)
191+
- App blocked (any app from apps)
192+
"""
162193
for unit_name, unit in units.items():
163194
assert unit.workload_status
164-
if unit.workload_status.status == "blocked" and raise_on_blocked:
195+
if unit.workload_status.status == "blocked":
165196
raise JujuUnitError(
166197
f"{unit_name!r} workload is blocked: {unit.workload_status.info!r}"
167198
)
@@ -170,29 +201,11 @@ def check(
170201
app = full_status.applications[app_name]
171202
assert isinstance(app, ApplicationStatus)
172203
assert app.status
173-
if app.status.status == "blocked" and raise_on_blocked:
204+
if app.status.status == "blocked":
174205
raise JujuAppError(f"{app_name!r} is blocked: {app.status.info!r}")
175206

176-
rv = CheckStatus(set(), set(), set())
177-
178-
for app_name in apps:
179-
app = full_status.applications[app_name]
180-
assert isinstance(app, ApplicationStatus)
181-
for unit_name, unit in _app_units(full_status, app_name).items():
182-
rv.units.add(unit_name)
183-
assert unit.agent_status
184-
assert unit.workload_status
185-
186-
if unit.agent_status.status == "idle":
187-
rv.idle_units.add(unit_name)
188-
189-
if not status or unit.workload_status.status == status:
190-
rv.ready_units.add(unit_name)
191-
192-
return rv
193-
194207

195-
def _app_units(full_status: FullStatus, app_name: str) -> dict[str, UnitStatus]:
208+
def app_units(full_status: FullStatus, app_name: str) -> dict[str, UnitStatus]:
196209
"""Fish out the app's units' status from a FullStatus response."""
197210
rv: dict[str, UnitStatus] = {}
198211
app = full_status.applications[app_name]

tests/unit/test_idle_check.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@
2020
def test_check_status(full_status: FullStatus, kwargs):
2121
status = check(full_status, **kwargs)
2222
assert status == CheckStatus(
23-
{
23+
units={
2424
"grafana-agent-k8s/0",
2525
"hexanator/0",
2626
"mysql-test-app/0",
2727
"mysql-test-app/1",
2828
},
29-
{
29+
ready_units={
3030
"grafana-agent-k8s/0",
3131
"hexanator/0",
3232
"mysql-test-app/0",
3333
"mysql-test-app/1",
3434
},
35-
{
35+
idle_units={
3636
"grafana-agent-k8s/0",
3737
"hexanator/0",
3838
"mysql-test-app/0",

0 commit comments

Comments
 (0)