Skip to content

Commit

Permalink
comments
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRealFalcon committed Feb 22, 2024
1 parent bf5e547 commit 04b62bf
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 54 deletions.
75 changes: 39 additions & 36 deletions cloudinit/cmd/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,10 @@ def query_systemctl(
while True:
try:
return subp.subp(["systemctl", *systemctl_args]).stdout.strip()
except subp.ProcessExecutionError as e:
last_exception = e
if wait:
sleep(0.25)
else:
break
print(
"Failed to get status from systemd. "
"Cloud-init status may be inaccurate. ",
f"Error from systemctl: {last_exception.stderr}",
file=sys.stderr,
)
return ""
except subp.ProcessExecutionError:
if not wait:
raise
sleep(0.25)


def get_parser(parser=None):
Expand Down Expand Up @@ -161,13 +152,13 @@ def translate_status(
"""
# If we're done and have errors, we're in an error state
if condition == ConditionStatus.ERROR:
return ("error", f"{condition.value} - {running.value}")
return "error", f"{condition.value} - {running.value}"
# Handle the "degraded done" and "degraded running" states
elif condition == ConditionStatus.DEGRADED and running in [
RunningStatus.DONE,
RunningStatus.RUNNING,
]:
return (running.value, f"{condition.value} {running.value}")
return running.value, f"{condition.value} {running.value}"
return running.value, running.value


Expand Down Expand Up @@ -264,6 +255,15 @@ def handle_status_args(name, args) -> int:
return 0


def _disabled_via_environment(wait) -> bool:
"""Return whether cloud-init is disabled via environment variable."""
try:
env = query_systemctl(["show-environment"], wait=wait)
except subp.ProcessExecutionError:
env = ""
return "cloud-init=disabled" in env


def get_bootstatus(disable_file, paths, wait) -> Tuple[EnabledStatus, str]:
"""Report whether cloud-init current boot status
Expand All @@ -287,9 +287,7 @@ def get_bootstatus(disable_file, paths, wait) -> Tuple[EnabledStatus, str]:
bootstatus_code = EnabledStatus.DISABLED_BY_KERNEL_CMDLINE
reason = "Cloud-init disabled by kernel parameter cloud-init=disabled"
elif "cloud-init=disabled" in os.environ.get("KERNEL_CMDLINE", "") or (
uses_systemd()
and "cloud-init=disabled"
in query_systemctl(["show-environment"], wait=wait)
uses_systemd() and _disabled_via_environment(wait=wait)
):
bootstatus_code = EnabledStatus.DISABLED_BY_ENV_VARIABLE
reason = (
Expand Down Expand Up @@ -323,16 +321,23 @@ def systemd_failed(wait: bool) -> bool:
"cloud-init.service",
"cloud-init-local.service",
]:
stdout = query_systemctl(
[
"show",
"--property=ActiveState,UnitFileState,SubState,MainPID",
service,
],
wait=wait,
)
if not stdout:
try:
stdout = query_systemctl(
[
"show",
"--property=ActiveState,UnitFileState,SubState,MainPID",
service,
],
wait=wait,
)
except subp.ProcessExecutionError as e:
# Systemd isn't ready, assume the same state
print(
"Failed to get status from systemd. "
"Cloud-init status may be inaccurate. "
f"Error from systemctl: {e.stderr}",
file=sys.stderr,
)
return False
states = dict(
[[x.strip() for x in r.split("=")] for r in stdout.splitlines()]
Expand Down Expand Up @@ -375,16 +380,14 @@ def get_running_status(
status_file, result_file, boot_status_code, latest_event
) -> RunningStatus:
"""Return the running status of cloud-init."""
if is_running(status_file, result_file):
return RunningStatus.RUNNING
elif boot_status_code in DISABLED_BOOT_CODES:
if boot_status_code in DISABLED_BOOT_CODES:
return RunningStatus.DISABLED
elif is_running(status_file, result_file):
return RunningStatus.RUNNING
elif latest_event > 0:
return RunningStatus.DONE
else:
return (
RunningStatus.DONE
if latest_event > 0
else RunningStatus.NOT_STARTED
)
return RunningStatus.NOT_STARTED


def get_datasource(status_v1) -> str:
Expand Down Expand Up @@ -501,7 +504,7 @@ def get_status_details(
condition_status = ConditionStatus.ERROR
description = "Failed due to systemd unit failure"
errors.append(
"Failed due to sysetmd unit failure. Ensure all cloud-init "
"Failed due to systemd unit failure. Ensure all cloud-init "
"services are enabled, and check 'systemctl' or 'journalctl' "
"for more information."
)
Expand Down
55 changes: 45 additions & 10 deletions doc/rtd/howto/status.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,59 @@ subcommand under the ``extended_status`` key.
$ cloud-init status --format json
{
"boot_status_code": "enabled-by-generator",
"datasource": "",
"detail": "Cloud-init enabled by systemd cloud-init-generator",
"errors": [],
"extended_status": "degraded done",
"last_update": "",
"recoverable_errors": {},
"status": "done"
"boot_status_code": "enabled-by-generator",
"datasource": "lxd",
"detail": "DataSourceLXD",
"errors": [],
"extended_status": "degraded done",
"init": {
"errors": [],
"finished": 1708550839.1837437,
"recoverable_errors": {},
"start": 1708550838.6881146
},
"init-local": {
"errors": [],
"finished": 1708550838.0196638,
"recoverable_errors": {},
"start": 1708550837.7719762
},
"last_update": "Wed, 21 Feb 2024 21:27:24 +0000",
"modules-config": {
"errors": [],
"finished": 1708550843.8297973,
"recoverable_errors": {
"WARNING": [
"Removing /etc/apt/sources.list to favor deb822 source format"
]
},
"start": 1708550843.7163966
},
"modules-final": {
"errors": [],
"finished": 1708550844.0884337,
"recoverable_errors": {},
"start": 1708550844.029698
},
"recoverable_errors": {
"WARNING": [
"Removing /etc/apt/sources.list to favor deb822 source format"
]
},
"stage": null,
"status": "done"
}
See the list of all possible reported statuses:

.. code-block:: shell-session
"not running"
"not started"
"running"
"done"
"error"
"error - done"
"error - running"
"degraded done"
"degraded running"
"disabled"
Expand Down
4 changes: 2 additions & 2 deletions tests/unittests/cmd/test_cloud_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"",
{},
)
STATUS_DETAILS_NOT_RUN = status.StatusDetails(
STATUS_DETAILS_NOT_STARTED = status.StatusDetails(
status.RunningStatus.NOT_STARTED,
status.ConditionStatus.PEACHY,
status.EnabledStatus.UNKNOWN,
Expand Down Expand Up @@ -226,7 +226,7 @@ def test_cloud_id_lookup_json_instance_data_adds_cloud_id_to_json(
"details, exit_code",
(
(STATUS_DETAILS_DISABLED, 2),
(STATUS_DETAILS_NOT_RUN, 3),
(STATUS_DETAILS_NOT_STARTED, 3),
(STATUS_DETAILS_RUNNING, 0),
(STATUS_DETAILS_RUNNING_DS_NONE, 0),
),
Expand Down
16 changes: 10 additions & 6 deletions tests/unittests/cmd/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_get_status_systemd_failure(
assert details.condition_status == status.ConditionStatus.ERROR
assert details.description == "Failed due to systemd unit failure"
assert details.errors == [
"Failed due to sysetmd unit failure. Ensure all cloud-init "
"Failed due to systemd unit failure. Ensure all cloud-init "
"services are enabled, and check 'systemctl' or 'journalctl' "
"for more information."
]
Expand Down Expand Up @@ -1003,16 +1003,20 @@ def test_retry_no_wait(self, mocker, capsys):
m_subp = mocker.patch(
f"{M_PATH}subp.subp",
side_effect=subp.ProcessExecutionError(
"Message recipient disconnected from message bus without"
" replying"
stderr=(
"Message recipient disconnected from message bus without "
"replying"
),
),
)
mocker.patch("time.time", side_effect=[1, 2, 50])
assert status.systemd_failed(wait=False) is False
assert 1 == m_subp.call_count
assert (
"Failed to get status from systemd. "
"Cloud-init status may be inaccurate."
"Cloud-init status may be inaccurate. "
"Error from systemctl: Message recipient disconnected from "
"message bus without replying"
) in capsys.readouterr().err


Expand All @@ -1032,9 +1036,9 @@ def test_query_systemctl_with_exception(self, mocker, capsys):
"Message recipient disconnected", stderr="oh noes!"
),
)
assert status.query_systemctl(["some", "args"], wait=False) == ""
with pytest.raises(subp.ProcessExecutionError):
status.query_systemctl(["some", "args"], wait=False)
m_subp.assert_called_once_with(["systemctl", "some", "args"])
assert "Error from systemctl: oh noes!" in capsys.readouterr().err

def test_query_systemctl_wait_with_exception(self, mocker):
m_sleep = mocker.patch(f"{M_PATH}sleep")
Expand Down

0 comments on commit 04b62bf

Please sign in to comment.