diff options
Diffstat (limited to 'cloudinit/distros/opensuse.py')
-rw-r--r-- | cloudinit/distros/opensuse.py | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/cloudinit/distros/opensuse.py b/cloudinit/distros/opensuse.py index 00ed1514..38307c91 100644 --- a/cloudinit/distros/opensuse.py +++ b/cloudinit/distros/opensuse.py @@ -8,11 +8,17 @@ # # This file is part of cloud-init. See LICENSE file for license information. -from cloudinit import distros, helpers, subp, util +import os + +from cloudinit import distros, helpers +from cloudinit import log as logging +from cloudinit import subp, util from cloudinit.distros import rhel_util as rhutil from cloudinit.distros.parsers.hostname import HostnameConf from cloudinit.settings import PER_INSTANCE +LOG = logging.getLogger(__name__) + class Distro(distros.Distro): clock_conf_fn = "/etc/sysconfig/clock" @@ -44,6 +50,8 @@ class Distro(distros.Distro): distros.Distro.__init__(self, name, cfg, paths) self._runner = helpers.Runners(paths) self.osfamily = "suse" + self.update_method = None + self.read_only_root = False cfg["ssh_svcname"] = "sshd" if self.uses_systemd(): self.init_cmd = ["systemctl"] @@ -69,12 +77,44 @@ class Distro(distros.Distro): if pkgs is None: pkgs = [] + self._set_update_method() + if self.read_only_root and not self.update_method == "transactional": + LOG.error( + "Package operation requested but read only root " + "without btrfs and transactional-updata" + ) + return + # No user interaction possible, enable non-interactive mode - cmd = ["zypper", "--non-interactive"] + if self.update_method == "zypper": + cmd = ["zypper", "--non-interactive"] + else: + cmd = [ + "transactional-update", + "--non-interactive", + "--drop-if-no-change", + "pkg", + ] # Command is the operation, such as install if command == "upgrade": command = "update" + if ( + not pkgs + and self.update_method == "transactional" + and command == "update" + ): + command = "up" + cmd = [ + "transactional-update", + "--non-interactive", + "--drop-if-no-change", + ] + # Repo refresh only modifies data in the read-write path, + # always uses zypper + if command == "refresh": + # Repo refresh is a zypper only option, ignore the t-u setting + cmd = ["zypper", "--non-interactive"] cmd.append(command) # args are the arguments to the command, not global options @@ -89,6 +129,11 @@ class Distro(distros.Distro): # Allow the output of this to flow outwards (ie not be captured) subp.subp(cmd, capture=False) + if self.update_method == "transactional": + LOG.info( + "To use/activate the installed packages reboot the system" + ) + def set_timezone(self, tz): tz_file = self._find_tz_file(tz) if self.uses_systemd(): @@ -147,6 +192,34 @@ class Distro(distros.Distro): host_fn = self.hostname_conf_fn return (host_fn, self._read_hostname(host_fn)) + def _set_update_method(self): + """Decide if we want to use transactional-update or zypper""" + if self.update_method is None: + result = util.get_mount_info("/") + fs_type = "" + if result: + (devpth, fs_type, mount_point) = result + # Check if the file system is read only + mounts = util.load_file("/proc/mounts").split("\n") + for mount in mounts: + if mount.startswith(devpth): + mount_info = mount.split() + if mount_info[1] != mount_point: + continue + self.read_only_root = mount_info[3].startswith("ro") + break + if fs_type.lower() == "btrfs" and os.path.exists( + "/usr/sbin/transactional-update" + ): + self.update_method = "transactional" + else: + self.update_method = "zypper" + else: + LOG.info( + "Could not determine filesystem type of '/' using zypper" + ) + self.update_method = "zypper" + def _write_hostname(self, hostname, filename): if self.uses_systemd() and filename.endswith("/previous-hostname"): util.write_file(filename, hostname) |