Blame cloudinit/distros/arch.py

Packit Service a04d08
# Copyright (C) 2014 Rackspace, US Inc.
Packit Service a04d08
#
Packit Service a04d08
# Author: Nate House <nathan.house@rackspace.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
from cloudinit import distros
Packit Service a04d08
from cloudinit import helpers
Packit Service a04d08
from cloudinit import log as logging
Packit Service a04d08
from cloudinit import util
Packit Service 751c4a
from cloudinit import subp
Packit Service a04d08
Packit Service a04d08
from cloudinit.distros import net_util
Packit Service a04d08
from cloudinit.distros.parsers.hostname import HostnameConf
Packit Service a04d08
Packit Service a04d08
from cloudinit.net.renderers import RendererNotFoundError
Packit Service a04d08
Packit Service a04d08
from cloudinit.settings import PER_INSTANCE
Packit Service a04d08
Packit Service a04d08
import os
Packit Service a04d08
Packit Service a04d08
LOG = logging.getLogger(__name__)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class Distro(distros.Distro):
Packit Service a04d08
    locale_conf_fn = "/etc/locale.gen"
Packit Service a04d08
    network_conf_dir = "/etc/netctl"
Packit Service a04d08
    resolve_conf_fn = "/etc/resolv.conf"
Packit Service a04d08
    init_cmd = ['systemctl']  # init scripts
Packit Service a04d08
    renderer_configs = {
Packit Service a04d08
        "netplan": {"netplan_path": "/etc/netplan/50-cloud-init.yaml",
Packit Service a04d08
                    "netplan_header": "# generated by cloud-init\n",
Packit Service a04d08
                    "postcmds": True}
Packit Service a04d08
    }
Packit Service a04d08
Packit Service a04d08
    def __init__(self, name, cfg, paths):
Packit Service a04d08
        distros.Distro.__init__(self, name, cfg, paths)
Packit Service a04d08
        # This will be used to restrict certain
Packit Service a04d08
        # calls from repeatly happening (when they
Packit Service a04d08
        # should only happen say once per instance...)
Packit Service a04d08
        self._runner = helpers.Runners(paths)
Packit Service a04d08
        self.osfamily = 'arch'
Packit Service a04d08
        cfg['ssh_svcname'] = 'sshd'
Packit Service a04d08
Packit Service a04d08
    def apply_locale(self, locale, out_fn=None):
Packit Service a04d08
        if not out_fn:
Packit Service a04d08
            out_fn = self.locale_conf_fn
Packit Service 751c4a
        subp.subp(['locale-gen', '-G', locale], capture=False)
Packit Service a04d08
        # "" provides trailing newline during join
Packit Service a04d08
        lines = [
Packit Service a04d08
            util.make_header(),
Packit Service a04d08
            'LANG="%s"' % (locale),
Packit Service a04d08
            "",
Packit Service a04d08
        ]
Packit Service a04d08
        util.write_file(out_fn, "\n".join(lines))
Packit Service a04d08
Packit Service a04d08
    def install_packages(self, pkglist):
Packit Service a04d08
        self.update_package_sources()
Packit Service a04d08
        self.package_command('', pkgs=pkglist)
Packit Service a04d08
Packit Service a04d08
    def _write_network_config(self, netconfig):
Packit Service a04d08
        try:
Packit Service a04d08
            return self._supported_write_network_config(netconfig)
Packit Service 751c4a
        except RendererNotFoundError as e:
Packit Service a04d08
            # Fall back to old _write_network
Packit Service 751c4a
            raise NotImplementedError from e
Packit Service a04d08
Packit Service a04d08
    def _write_network(self, settings):
Packit Service a04d08
        entries = net_util.translate_network(settings)
Packit Service a04d08
        LOG.debug("Translated ubuntu style network settings %s into %s",
Packit Service a04d08
                  settings, entries)
Packit Service a04d08
        return _render_network(
Packit Service a04d08
            entries, resolv_conf=self.resolve_conf_fn,
Packit Service a04d08
            conf_dir=self.network_conf_dir,
Packit Service a04d08
            enable_func=self._enable_interface)
Packit Service a04d08
Packit Service a04d08
    def _enable_interface(self, device_name):
Packit Service a04d08
        cmd = ['netctl', 'reenable', device_name]
Packit Service a04d08
        try:
Packit Service 751c4a
            (_out, err) = subp.subp(cmd)
Packit Service a04d08
            if len(err):
Packit Service a04d08
                LOG.warning("Running %s resulted in stderr output: %s",
Packit Service a04d08
                            cmd, err)
Packit Service 751c4a
        except subp.ProcessExecutionError:
Packit Service a04d08
            util.logexc(LOG, "Running interface command %s failed", cmd)
Packit Service a04d08
Packit Service a04d08
    def _bring_up_interface(self, device_name):
Packit Service a04d08
        cmd = ['netctl', 'restart', device_name]
Packit Service a04d08
        LOG.debug("Attempting to run bring up interface %s using command %s",
Packit Service a04d08
                  device_name, cmd)
Packit Service a04d08
        try:
Packit Service 751c4a
            (_out, err) = subp.subp(cmd)
Packit Service a04d08
            if len(err):
Packit Service a04d08
                LOG.warning("Running %s resulted in stderr output: %s",
Packit Service a04d08
                            cmd, err)
Packit Service a04d08
            return True
Packit Service 751c4a
        except subp.ProcessExecutionError:
Packit Service a04d08
            util.logexc(LOG, "Running interface command %s failed", cmd)
Packit Service a04d08
            return False
Packit Service a04d08
Packit Service a04d08
    def _bring_up_interfaces(self, device_names):
Packit Service a04d08
        for d in device_names:
Packit Service a04d08
            if not self._bring_up_interface(d):
Packit Service a04d08
                return False
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    def _write_hostname(self, your_hostname, out_fn):
Packit Service a04d08
        conf = None
Packit Service a04d08
        try:
Packit Service a04d08
            # Try to update the previous one
Packit Service a04d08
            # so lets see if we can read it first.
Packit Service a04d08
            conf = self._read_hostname_conf(out_fn)
Packit Service a04d08
        except IOError:
Packit Service a04d08
            pass
Packit Service a04d08
        if not conf:
Packit Service a04d08
            conf = HostnameConf('')
Packit Service a04d08
        conf.set_hostname(your_hostname)
Packit Service a04d08
        util.write_file(out_fn, str(conf), omode="w", mode=0o644)
Packit Service a04d08
Packit Service a04d08
    def _read_system_hostname(self):
Packit Service a04d08
        sys_hostname = self._read_hostname(self.hostname_conf_fn)
Packit Service a04d08
        return (self.hostname_conf_fn, sys_hostname)
Packit Service a04d08
Packit Service a04d08
    def _read_hostname_conf(self, filename):
Packit Service a04d08
        conf = HostnameConf(util.load_file(filename))
Packit Service a04d08
        conf.parse()
Packit Service a04d08
        return conf
Packit Service a04d08
Packit Service a04d08
    def _read_hostname(self, filename, default=None):
Packit Service a04d08
        hostname = None
Packit Service a04d08
        try:
Packit Service a04d08
            conf = self._read_hostname_conf(filename)
Packit Service a04d08
            hostname = conf.hostname
Packit Service a04d08
        except IOError:
Packit Service a04d08
            pass
Packit Service a04d08
        if not hostname:
Packit Service a04d08
            return default
Packit Service a04d08
        return hostname
Packit Service a04d08
Packit Service a04d08
    def set_timezone(self, tz):
Packit Service a04d08
        distros.set_etc_timezone(tz=tz, tz_file=self._find_tz_file(tz))
Packit Service a04d08
Packit Service a04d08
    def package_command(self, command, args=None, pkgs=None):
Packit Service a04d08
        if pkgs is None:
Packit Service a04d08
            pkgs = []
Packit Service a04d08
Packit Service a04d08
        cmd = ['pacman', "-Sy", "--quiet", "--noconfirm"]
Packit Service a04d08
        # Redirect output
Packit Service a04d08
Packit Service a04d08
        if args and isinstance(args, str):
Packit Service a04d08
            cmd.append(args)
Packit Service a04d08
        elif args and isinstance(args, list):
Packit Service a04d08
            cmd.extend(args)
Packit Service a04d08
Packit Service a04d08
        if command:
Packit Service a04d08
            cmd.append(command)
Packit Service a04d08
Packit Service a04d08
        pkglist = util.expand_package_list('%s-%s', pkgs)
Packit Service a04d08
        cmd.extend(pkglist)
Packit Service a04d08
Packit Service a04d08
        # Allow the output of this to flow outwards (ie not be captured)
Packit Service 751c4a
        subp.subp(cmd, capture=False)
Packit Service a04d08
Packit Service a04d08
    def update_package_sources(self):
Packit Service a04d08
        self._runner.run("update-sources", self.package_command,
Packit Service a04d08
                         ["-y"], freq=PER_INSTANCE)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def _render_network(entries, target="/", conf_dir="etc/netctl",
Packit Service a04d08
                    resolv_conf="etc/resolv.conf", enable_func=None):
Packit Service a04d08
    """Render the translate_network format into netctl files in target.
Packit Service a04d08
    Paths will be rendered under target.
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    devs = []
Packit Service a04d08
    nameservers = []
Packit Service 751c4a
    resolv_conf = subp.target_path(target, resolv_conf)
Packit Service 751c4a
    conf_dir = subp.target_path(target, conf_dir)
Packit Service a04d08
Packit Service a04d08
    for (dev, info) in entries.items():
Packit Service a04d08
        if dev == 'lo':
Packit Service a04d08
            # no configuration should be rendered for 'lo'
Packit Service a04d08
            continue
Packit Service a04d08
        devs.append(dev)
Packit Service a04d08
        net_fn = os.path.join(conf_dir, dev)
Packit Service a04d08
        net_cfg = {
Packit Service a04d08
            'Connection': 'ethernet',
Packit Service a04d08
            'Interface': dev,
Packit Service a04d08
            'IP': info.get('bootproto'),
Packit Service a04d08
            'Address': "%s/%s" % (info.get('address'),
Packit Service a04d08
                                  info.get('netmask')),
Packit Service a04d08
            'Gateway': info.get('gateway'),
Packit Service a04d08
            'DNS': info.get('dns-nameservers', []),
Packit Service a04d08
        }
Packit Service a04d08
        util.write_file(net_fn, convert_netctl(net_cfg))
Packit Service a04d08
        if enable_func and info.get('auto'):
Packit Service a04d08
            enable_func(dev)
Packit Service a04d08
        if 'dns-nameservers' in info:
Packit Service a04d08
            nameservers.extend(info['dns-nameservers'])
Packit Service a04d08
Packit Service a04d08
    if nameservers:
Packit Service a04d08
        util.write_file(resolv_conf,
Packit Service a04d08
                        convert_resolv_conf(nameservers))
Packit Service a04d08
    return devs
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def convert_netctl(settings):
Packit Service a04d08
    """Given a dictionary, returns a string in netctl profile format.
Packit Service a04d08
Packit Service a04d08
    netctl profile is described at:
Packit Service a04d08
    https://git.archlinux.org/netctl.git/tree/docs/netctl.profile.5.txt
Packit Service a04d08
Packit Service a04d08
    Note that the 'Special Quoting Rules' are not handled here."""
Packit Service a04d08
    result = []
Packit Service a04d08
    for key in sorted(settings):
Packit Service a04d08
        val = settings[key]
Packit Service a04d08
        if val is None:
Packit Service a04d08
            val = ""
Packit Service a04d08
        elif isinstance(val, (tuple, list)):
Packit Service a04d08
            val = "(" + ' '.join("'%s'" % v for v in val) + ")"
Packit Service a04d08
        result.append("%s=%s\n" % (key, val))
Packit Service a04d08
    return ''.join(result)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def convert_resolv_conf(settings):
Packit Service a04d08
    """Returns a settings string formatted for resolv.conf."""
Packit Service a04d08
    result = ''
Packit Service a04d08
    if isinstance(settings, list):
Packit Service a04d08
        for ns in settings:
Packit Service a04d08
            result = result + 'nameserver %s\n' % ns
Packit Service a04d08
    return result
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab