Skip to content

Commit

Permalink
fix: don't deadlock when starting second stage with systemd
Browse files Browse the repository at this point in the history
  • Loading branch information
holmanb committed Dec 16, 2024
1 parent 179c698 commit 52deab4
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 5 deletions.
18 changes: 16 additions & 2 deletions cloudinit/config/cc_set_passwords.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ 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):
try:
distro.manage_service("restart", service)
distro.manage_service(
"restart", service, "--job-mode='ignore-dependencies'"
)
LOG.debug("Restarted the SSH daemon.")
except subp.ProcessExecutionError as e:
LOG.warning(
Expand Down Expand Up @@ -104,6 +106,18 @@ def handle_ssh_pwauth(pw_auth, distro: Distro):
]
).stdout.strip()
if state.lower() in ["active", "activating", "reloading"]:
# 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)
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
2 changes: 1 addition & 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,7 @@
["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 52deab4

Please sign in to comment.