Example #1
0
def _maybe_remove_legacy_eth0(target,
                              path="etc/network/interfaces.d/eth0.cfg"):
    """Ubuntu cloud images previously included a 'eth0.cfg' that had
       hard coded content.  That file would interfere with the rendered
       configuration if it was present.

       if the file does not exist do nothing.
       If the file exists:
         - with known content, remove it and warn
         - with unknown content, leave it and warn
    """

    cfg = util.target_path(target, path=path)
    if not os.path.exists(cfg):
        LOG.warn('Failed to find legacy network conf file %s', cfg)
        return

    bmsg = "Dynamic networking config may not apply."
    try:
        contents = util.load_file(cfg)
        known_contents = ["auto eth0", "iface eth0 inet dhcp"]
        lines = [
            f.strip() for f in contents.splitlines() if not f.startswith("#")
        ]
        if lines == known_contents:
            util.del_file(cfg)
            msg = "removed %s with known contents" % cfg
        else:
            msg = (bmsg + " '%s' exists with user configured content." % cfg)
    except Exception:
        msg = bmsg + " %s exists, but could not be read." % cfg
        LOG.exception(msg)
        raise

    LOG.warn(msg)
Example #2
0
def force_devmapper_symlinks():
    """Check if /dev/mapper/mpath* files are symlinks, if not trigger udev."""
    LOG.debug('Verifying /dev/mapper/mpath* files are symlinks')
    needs_trigger = []
    for mp_id, dm_dev in dmname_to_blkdev_mapping().items():
        if mp_id.startswith('mpath'):
            mapper_path = '/dev/mapper/' + mp_id
            if not os.path.islink(mapper_path):
                LOG.warning(
                    'Found invalid device mapper mp path: %s, removing',
                    mapper_path)
                util.del_file(mapper_path)
                needs_trigger.append((mapper_path, dm_dev))

    if len(needs_trigger):
        for (mapper_path, dm_dev) in needs_trigger:
            LOG.debug('multipath: regenerating symlink for %s (%s)',
                      mapper_path, dm_dev)
            util.subp([
                'udevadm', 'trigger', '--subsystem-match=block',
                '--action=add', '/sys/class/block/' + os.path.basename(dm_dev)
            ])
            udev.udevadm_settle(exists=mapper_path)
            if not os.path.islink(mapper_path):
                LOG.error('Failed to regenerate udev symlink %s', mapper_path)
Example #3
0
def ubuntu_core_curthooks(cfg, target=None):
    """ Ubuntu-Core 16 images cannot execute standard curthooks
        Instead we copy in any cloud-init configuration to
        the 'LABEL=writable' partition mounted at target.
    """

    ubuntu_core_target = os.path.join(target, "system-data")
    cc_target = os.path.join(ubuntu_core_target, 'etc/cloud/cloud.cfg.d')

    cloudconfig = cfg.get('cloudconfig', None)
    if cloudconfig:
        # remove cloud-init.disabled, if found
        cloudinit_disable = os.path.join(ubuntu_core_target,
                                         'etc/cloud/cloud-init.disabled')
        if os.path.exists(cloudinit_disable):
            util.del_file(cloudinit_disable)

        handle_cloudconfig(cloudconfig, base_dir=cc_target)

    netconfig = cfg.get('network', None)
    if netconfig:
        LOG.info('Writing network configuration')
        ubuntu_core_netconfig = os.path.join(cc_target,
                                             "50-curtin-networking.cfg")
        util.write_file(ubuntu_core_netconfig,
                        content=config.dump_config({'network': netconfig}))
Example #4
0
    def load_products(self, path=None, content_id=None, remove=True):
        # overridden from ObjectStoreMirrorWriter
        # the reason is that we have copied here from trunk
        # is bug 1511364 which is not fixed in all ubuntu versions
        if content_id:
            try:
                dpath = self.products_data_path(content_id)
                return sutil.load_content(self.source(dpath).read())
            except IOError as e:
                if e.errno != errno.ENOENT:
                    raise
            except JSONDecodeError:
                jsonfile = os.path.join(self.out_d, dpath)
                sys.stderr.write("Decode error in:\n  "
                                 "content_id=%s\n  "
                                 "JSON filepath=%s\n" % (content_id, jsonfile))
                if remove is True:
                    sys.stderr.write("Removing offending file: %s\n" %
                                     jsonfile)
                    util.del_file(jsonfile)
                    sys.stderr.write("Trying to load products again...\n")
                    sys.stderr.flush()
                    return self.load_products(path=path,
                                              content_id=content_id,
                                              remove=False)
                raise

        if path:
            return {}

        raise TypeError("unable to load_products with no path")
Example #5
0
def _disable_ipv6_privacy_extensions(target,
                                     path="etc/sysctl.d/10-ipv6-privacy.conf"):
    """Ubuntu server image sets a preference to use IPv6 privacy extensions
       by default; this races with the cloud-image desire to disable them.
       Resolve this by allowing the cloud-image setting to win. """

    LOG.debug('Attempting to remove ipv6 privacy extensions')
    cfg = util.target_path(target, path=path)
    if not os.path.exists(cfg):
        LOG.warn('Failed to find ipv6 privacy conf file %s', cfg)
        return

    bmsg = "Disabling IPv6 privacy extensions config may not apply."
    try:
        contents = util.load_file(cfg)
        known_contents = [
            "net.ipv6.conf.all.use_tempaddr = 2",
            "net.ipv6.conf.default.use_tempaddr = 2"
        ]
        lines = [
            f.strip() for f in contents.splitlines() if not f.startswith("#")
        ]
        if lines == known_contents:
            LOG.info('Removing ipv6 privacy extension config file: %s', cfg)
            util.del_file(cfg)
            msg = "removed %s with known contents" % cfg
            curtin_contents = '\n'.join([
                "# IPv6 Privacy Extensions (RFC 4941)", "# Disabled by curtin",
                "# net.ipv6.conf.all.use_tempaddr = 2",
                "# net.ipv6.conf.default.use_tempaddr = 2"
            ])
            util.write_file(cfg, curtin_contents)
        else:
            LOG.debug('skipping removal of %s, expected content not found',
                      cfg)
            LOG.debug("Found content in file %s:\n%s", cfg, lines)
            LOG.debug("Expected contents in file %s:\n%s", cfg, known_contents)
            msg = (bmsg + " '%s' exists with user configured content." % cfg)
    except Exception as e:
        msg = bmsg + " %s exists, but could not be read. %s" % (cfg, e)
        LOG.exception(msg)
        raise
Example #6
0
def apply_apt_proxy_config(cfg, proxy_fname, config_fname):
    """apply_apt_proxy_config
       Applies any apt*proxy config from if specified
    """
    # Set up any apt proxy
    cfgs = (('proxy', 'Acquire::http::Proxy "%s";'),
            ('http_proxy', 'Acquire::http::Proxy "%s";'),
            ('ftp_proxy', 'Acquire::ftp::Proxy "%s";'),
            ('https_proxy', 'Acquire::https::Proxy "%s";'))

    proxies = [fmt % cfg.get(name) for (name, fmt) in cfgs if cfg.get(name)]
    if len(proxies):
        LOG.debug("write apt proxy info to %s", proxy_fname)
        util.write_file(proxy_fname, '\n'.join(proxies) + '\n')
    elif os.path.isfile(proxy_fname):
        util.del_file(proxy_fname)
        LOG.debug("no apt proxy configured, removed %s", proxy_fname)

    if cfg.get('conf', None):
        LOG.debug("write apt config info to %s", config_fname)
        util.write_file(config_fname, cfg.get('conf'))
    elif os.path.isfile(config_fname):
        util.del_file(config_fname)
        LOG.debug("no apt config configured, removed %s", config_fname)
Example #7
0
def centos_apply_network_config(netcfg, target=None):
    """ CentOS images execute built-in curthooks which only supports
        simple networking configuration.  This hook enables advanced
        network configuration via config passthrough to the target.
    """
    def cloud_init_repo(version):
        if not version:
            raise ValueError('Missing required version parameter')

        return CLOUD_INIT_YUM_REPO_TEMPLATE % version

    if netcfg:
        LOG.info('Removing embedded network configuration (if present)')
        ifcfgs = glob.glob(
            util.target_path(target, 'etc/sysconfig/network-scripts') +
            '/ifcfg-*')
        # remove ifcfg-* (except ifcfg-lo)
        for ifcfg in ifcfgs:
            if os.path.basename(ifcfg) != "ifcfg-lo":
                util.del_file(ifcfg)

        LOG.info(
            'Checking cloud-init in target [%s] for network '
            'configuration passthrough support.', target)
        passthrough = net.netconfig_passthrough_available(target)
        LOG.debug('passthrough available via in-target: %s', passthrough)

        # if in-target cloud-init is not updated, upgrade via cloud-init repo
        if not passthrough:
            cloud_init_yum_repo = (util.target_path(
                target, 'etc/yum.repos.d/curtin-cloud-init.repo'))
            # Inject cloud-init daily yum repo
            util.write_file(cloud_init_yum_repo,
                            content=cloud_init_repo(rpm_get_dist_id(target)))

            # we separate the installation of repository packages (epel,
            # cloud-init-el-release) as we need a new invocation of yum
            # to read the newly installed repo files.
            YUM_CMD = ['yum', '-y', '--noplugins', 'install']
            retries = [1] * 30
            with util.ChrootableTarget(target) as in_chroot:
                # ensure up-to-date ca-certificates to handle https mirror
                # connections
                in_chroot.subp(YUM_CMD + ['ca-certificates'],
                               capture=True,
                               log_captured=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['epel-release'],
                               capture=True,
                               log_captured=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['cloud-init-el-release'],
                               log_captured=True,
                               capture=True,
                               retries=retries)
                in_chroot.subp(YUM_CMD + ['cloud-init'],
                               capture=True,
                               log_captured=True,
                               retries=retries)

            # remove cloud-init el-stable bootstrap repo config as the
            # cloud-init-el-release package points to the correct repo
            util.del_file(cloud_init_yum_repo)

            # install bridge-utils if needed
            with util.ChrootableTarget(target) as in_chroot:
                try:
                    in_chroot.subp(['rpm', '-q', 'bridge-utils'],
                                   capture=False,
                                   rcs=[0])
                except util.ProcessExecutionError:
                    LOG.debug('Image missing bridge-utils package, installing')
                    in_chroot.subp(YUM_CMD + ['bridge-utils'],
                                   capture=True,
                                   log_captured=True,
                                   retries=retries)

    LOG.info('Passing network configuration through to target')
    net.render_netconfig_passthrough(target, netconfig={'network': netcfg})