summaryrefslogtreecommitdiff
path: root/cloudinit
diff options
context:
space:
mode:
authorEmmanuel Thomé <Emmanuel.Thome@inria.fr>2020-09-15 21:51:52 +0200
committerGitHub <noreply@github.com>2020-09-15 15:51:52 -0400
commit6d332e5c8dbfb6521a530b1fa49d73da51efff96 (patch)
tree501e0dfcead71b501f1a1be1fc08df7c988975d4 /cloudinit
parent839016e3014d783354bc380799d914ff81ee4efa (diff)
downloadvyos-cloud-init-6d332e5c8dbfb6521a530b1fa49d73da51efff96.tar.gz
vyos-cloud-init-6d332e5c8dbfb6521a530b1fa49d73da51efff96.zip
create a shutdown_command method in distro classes (#567)
Under FreeBSD, we want to use "shutdown -p" for poweroff. Alpine Linux also has some specificities. We choose to define a method that returns the shutdown command line to use, rather than a method that actually does the shutdown. This makes it easier to have the tests in test_handler_power_state do their verifications. Two tests are added for the special behaviours that are known so far.
Diffstat (limited to 'cloudinit')
-rw-r--r--cloudinit/config/cc_power_state_change.py56
-rwxr-xr-xcloudinit/distros/__init__.py19
-rw-r--r--cloudinit/distros/alpine.py26
-rw-r--r--cloudinit/distros/bsd.py4
4 files changed, 57 insertions, 48 deletions
diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py
index 6fcb8a7d..b0cfafcd 100644
--- a/cloudinit/config/cc_power_state_change.py
+++ b/cloudinit/config/cc_power_state_change.py
@@ -117,7 +117,7 @@ def check_condition(cond, log=None):
def handle(_name, cfg, cloud, log, _args):
try:
- (args, timeout, condition) = load_power_state(cfg, cloud.distro.name)
+ (args, timeout, condition) = load_power_state(cfg, cloud.distro)
if args is None:
log.debug("no power_state provided. doing nothing")
return
@@ -144,19 +144,7 @@ def handle(_name, cfg, cloud, log, _args):
condition, execmd, [args, devnull_fp])
-def convert_delay(delay, fmt=None, scale=None):
- if not fmt:
- fmt = "+%s"
- if not scale:
- scale = 1
-
- if delay != "now":
- delay = fmt % int(int(delay) * int(scale))
-
- return delay
-
-
-def load_power_state(cfg, distro_name):
+def load_power_state(cfg, distro):
# returns a tuple of shutdown_command, timeout
# shutdown_command is None if no config found
pstate = cfg.get('power_state')
@@ -167,44 +155,16 @@ def load_power_state(cfg, distro_name):
if not isinstance(pstate, dict):
raise TypeError("power_state is not a dict.")
- opt_map = {'halt': '-H', 'poweroff': '-P', 'reboot': '-r'}
-
+ modes_ok = ['halt', 'poweroff', 'reboot']
mode = pstate.get("mode")
- if mode not in opt_map:
+ if mode not in distro.shutdown_options_map:
raise TypeError(
"power_state[mode] required, must be one of: %s. found: '%s'." %
- (','.join(opt_map.keys()), mode))
-
- delay = pstate.get("delay", "now")
- message = pstate.get("message")
- scale = 1
- fmt = "+%s"
- command = ["shutdown", opt_map[mode]]
-
- if distro_name == 'alpine':
- # Convert integer 30 or string '30' to '1800' (seconds) as Alpine's
- # halt/poweroff/reboot commands take seconds rather than minutes.
- scale = 60
- # No "+" in front of delay value as not supported by Alpine's commands.
- fmt = "%s"
- if delay == "now":
- # Alpine's commands do not understand "now".
- delay = "0"
- command = [mode, "-d"]
- # Alpine's commands don't support a message.
- message = None
-
- try:
- delay = convert_delay(delay, fmt=fmt, scale=scale)
- except ValueError as e:
- raise TypeError(
- "power_state[delay] must be 'now' or '+m' (minutes)."
- " found '%s'." % delay
- ) from e
+ (','.join(modes_ok), mode))
- args = command + [delay]
- if message:
- args.append(message)
+ args = distro.shutdown_command(mode=mode,
+ delay=pstate.get("delay", "now"),
+ message=pstate.get("message"))
try:
timeout = float(pstate.get('timeout', 30.0))
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 2bd9bae8..fac8cf67 100755
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -73,6 +73,9 @@ class Distro(metaclass=abc.ABCMeta):
renderer_configs = {}
_preferred_ntp_clients = None
networking_cls = LinuxNetworking
+ # This is used by self.shutdown_command(), and can be overridden in
+ # subclasses
+ shutdown_options_map = {'halt': '-H', 'poweroff': '-P', 'reboot': '-r'}
def __init__(self, name, cfg, paths):
self._paths = paths
@@ -750,6 +753,22 @@ class Distro(metaclass=abc.ABCMeta):
subp.subp(['usermod', '-a', '-G', name, member])
LOG.info("Added user '%s' to group '%s'", member, name)
+ def shutdown_command(self, *, mode, delay, message):
+ # called from cc_power_state_change.load_power_state
+ command = ["shutdown", self.shutdown_options_map[mode]]
+ try:
+ if delay != "now":
+ delay = "+%d" % int(delay)
+ except ValueError as e:
+ raise TypeError(
+ "power_state[delay] must be 'now' or '+m' (minutes)."
+ " found '%s'." % (delay,)
+ ) from e
+ args = command + [delay]
+ if message:
+ args.append(message)
+ return args
+
def _apply_hostname_transformations_to_url(url: str, transformations: list):
"""
diff --git a/cloudinit/distros/alpine.py b/cloudinit/distros/alpine.py
index e42443fc..e92ff3fb 100644
--- a/cloudinit/distros/alpine.py
+++ b/cloudinit/distros/alpine.py
@@ -162,4 +162,30 @@ class Distro(distros.Distro):
return self._preferred_ntp_clients
+ def shutdown_command(self, mode='poweroff', delay='now', message=None):
+ # called from cc_power_state_change.load_power_state
+ # Alpine has halt/poweroff/reboot, with the following specifics:
+ # - we use them rather than the generic "shutdown"
+ # - delay is given with "-d [integer]"
+ # - the integer is in seconds, cannot be "now", and takes no "+"
+ # - no message is supported (argument ignored, here)
+
+ command = [mode, "-d"]
+
+ # Convert delay from minutes to seconds, as Alpine's
+ # halt/poweroff/reboot commands take seconds rather than minutes.
+ if delay == "now":
+ # Alpine's commands do not understand "now".
+ command += ['0']
+ else:
+ try:
+ command.append(str(int(delay) * 60))
+ except ValueError as e:
+ raise TypeError(
+ "power_state[delay] must be 'now' or '+m' (minutes)."
+ " found '%s'." % (delay,)
+ ) from e
+
+ return command
+
# vi: ts=4 expandtab
diff --git a/cloudinit/distros/bsd.py b/cloudinit/distros/bsd.py
index 2ed7a7d5..f717a667 100644
--- a/cloudinit/distros/bsd.py
+++ b/cloudinit/distros/bsd.py
@@ -17,6 +17,10 @@ class BSD(distros.Distro):
hostname_conf_fn = '/etc/rc.conf'
rc_conf_fn = "/etc/rc.conf"
+ # This differs from the parent Distro class, which has -P for
+ # poweroff.
+ shutdown_options_map = {'halt': '-H', 'poweroff': '-p', 'reboot': '-r'}
+
# Set in BSD distro subclasses
group_add_cmd_prefix = []
pkg_cmd_install_prefix = []