Skip to content

Commit

Permalink
fix: don't deadlock when starting network service with systemctl (can…
Browse files Browse the repository at this point in the history
  • Loading branch information
holmanb authored Dec 18, 2024
1 parent 179c698 commit bc26e15
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
20 changes: 17 additions & 3 deletions cloudinit/config/cc_set_passwords.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ def get_users_by_type(users_list: list, pw_type: str) -> list:
)


def _restart_ssh_daemon(distro, service):
def _restart_ssh_daemon(distro: Distro, service: str, *extra_args: str):
try:
distro.manage_service("restart", service)
distro.manage_service("restart", service, *extra_args)
LOG.debug("Restarted the SSH daemon.")
except subp.ProcessExecutionError as e:
LOG.warning(
Expand Down Expand Up @@ -104,7 +104,21 @@ def handle_ssh_pwauth(pw_auth, distro: Distro):
]
).stdout.strip()
if state.lower() in ["active", "activating", "reloading"]:
_restart_ssh_daemon(distro, service)
# This module runs Before=sshd.service. What that means is that
# the code can only get to this point if a user manually starts the
# network stage. While this isn't a well-supported use-case, this
# does cause a deadlock if started via systemd directly:
# "systemctl start cloud-init.service". Prevent users from causing
# this deadlock by forcing systemd to ignore dependencies when
# restarting. Note that this deadlock is not possible in newer
# versions of cloud-init, since starting the second service doesn't
# run the second stage in 24.3+. This code therefore exists solely
# for backwards compatibility so that users who think that they
# need to manually start cloud-init (why?) with systemd (again,
# why?) can do so.
_restart_ssh_daemon(
distro, service, "--job-mode=ignore-dependencies"
)
else:
_restart_ssh_daemon(distro, service)

Expand Down
4 changes: 2 additions & 2 deletions cloudinit/distros/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class Distro(persistence.CloudInitPickleMixin, metaclass=abc.ABCMeta):
shadow_empty_locked_passwd_patterns = ["^{username}::", "^{username}:!:"]
tz_zone_dir = "/usr/share/zoneinfo"
default_owner = "root:root"
init_cmd = ["service"] # systemctl, service etc
init_cmd: List[str] = ["service"] # systemctl, service etc
renderer_configs: Mapping[str, MutableMapping[str, Any]] = {}
_preferred_ntp_clients = None
networking_cls: Type[Networking] = LinuxNetworking
Expand Down Expand Up @@ -1369,7 +1369,7 @@ def manage_service(
"try-reload": [service, "restart"],
"status": [service, "status"],
}
cmd = list(init_cmd) + list(cmds[action])
cmd = init_cmd + cmds[action] + list(extra_args)
return subp.subp(cmd, capture=True, rcs=rcs)

def set_keymap(self, layout: str, model: str, variant: str, options: str):
Expand Down
4 changes: 3 additions & 1 deletion tests/unittests/config/test_cc_set_passwords.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
["systemctl", "show", "--property", "ActiveState", "--value", "ssh"]
)
SYSTEMD_RESTART_CALL = mock.call(
["systemctl", "restart", "ssh"], capture=True, rcs=None
["systemctl", "restart", "ssh", "--job-mode=ignore-dependencies"],
capture=True,
rcs=None,
)
SERVICE_RESTART_CALL = mock.call(
["service", "ssh", "restart"], capture=True, rcs=None
Expand Down

0 comments on commit bc26e15

Please sign in to comment.