Пример #1
0
    def test_tempdir_error_suppression(self):
        """test tempdir suppresses errors during directory removal."""

        with self.assertRaises(OSError):
            with tempdir(prefix='cloud-init-dhcp-') as tdir:
                os.rmdir(tdir)
                # As a result, the directory is already gone,
                # so shutil.rmtree should raise OSError

        with tempdir(rmtree_ignore_errors=True,
                     prefix='cloud-init-dhcp-') as tdir:
            os.rmdir(tdir)
Пример #2
0
    def test_tempdir_error_suppression(self):
        """test tempdir suppresses errors during directory removal."""

        with self.assertRaises(OSError):
            with tempdir(prefix='cloud-init-dhcp-') as tdir:
                os.rmdir(tdir)
                # As a result, the directory is already gone,
                # so shutil.rmtree should raise OSError

        with tempdir(rmtree_ignore_errors=True,
                     prefix='cloud-init-dhcp-') as tdir:
            os.rmdir(tdir)
Пример #3
0
def install_puppet_aio(url=AIO_INSTALL_URL,
                       version=None,
                       collection=None,
                       cleanup=True):
    """Install puppet-agent from the puppetlabs repositories using the one-shot
    shell script

    :param url: URL from where to download the install script
    :param version: version to install, blank defaults to latest
    :param collection: collection to install, blank defaults to latest
    :param cleanup: whether to purge the puppetlabs repo after installation
    """
    args = []
    if version is not None:
        args = ['-v', version]
    if collection is not None:
        args += ['-c', collection]

    # Purge puppetlabs repos after installation
    if cleanup:
        args += ['--cleanup']
    content = url_helper.readurl(url=url, retries=5).contents

    # Use tmpdir over tmpfile to avoid 'text file busy' on execute
    with temp_utils.tempdir(needs_exe=True) as tmpd:
        tmpf = os.path.join(tmpd, 'puppet-install')
        util.write_file(tmpf, content, mode=0o700)
        return subp.subp([tmpf] + args, capture=False)
Пример #4
0
def maybe_perform_dhcp_discovery(nic=None):
    """Perform dhcp discovery if nic valid and dhclient command exists.

    If the nic is invalid or undiscoverable or dhclient command is not found,
    skip dhcp_discovery and return an empty dict.

    @param nic: Name of the network interface we want to run dhclient on.
    @return: A list of dicts representing dhcp options for each lease obtained
        from the dhclient discovery if run, otherwise an empty list is
        returned.
    """
    if nic is None:
        nic = find_fallback_nic()
        if nic is None:
            LOG.debug('Skip dhcp_discovery: Unable to find fallback nic.')
            return []
    elif nic not in get_devicelist():
        LOG.debug(
            'Skip dhcp_discovery: nic %s not found in get_devicelist.', nic)
        return []
    dhclient_path = util.which('dhclient')
    if not dhclient_path:
        LOG.debug('Skip dhclient configuration: No dhclient command found.')
        return []
    with temp_utils.tempdir(rmtree_ignore_errors=True,
                            prefix='cloud-init-dhcp-',
                            needs_exe=True) as tdir:
        # Use /var/tmp because /run/cloud-init/tmp is mounted noexec
        return dhcp_discovery(dhclient_path, nic, tdir)
Пример #5
0
    def resize(self, diskdev, partnum, partdev):
        myenv = os.environ.copy()
        myenv["LANG"] = "C"
        before = get_size(partdev)

        # growpart uses tmp dir to store intermediate states
        # and may conflict with systemd-tmpfiles-clean
        with temp_utils.tempdir(needs_exe=True) as tmpd:
            growpart_tmp = os.path.join(tmpd, "growpart")
            if not os.path.exists(growpart_tmp):
                os.mkdir(growpart_tmp, 0o700)
            myenv["TMPDIR"] = growpart_tmp
            try:
                subp.subp(
                    ["growpart", "--dry-run", diskdev, partnum], env=myenv
                )
            except subp.ProcessExecutionError as e:
                if e.exit_code != 1:
                    util.logexc(
                        LOG,
                        "Failed growpart --dry-run for (%s, %s)",
                        diskdev,
                        partnum,
                    )
                    raise ResizeFailedException(e) from e
                return (before, before)

            try:
                subp.subp(["growpart", diskdev, partnum], env=myenv)
            except subp.ProcessExecutionError as e:
                util.logexc(LOG, "Failed: growpart %s %s", diskdev, partnum)
                raise ResizeFailedException(e) from e

        return (before, get_size(partdev))
Пример #6
0
def maybe_perform_dhcp_discovery(nic=None):
    """Perform dhcp discovery if nic valid and dhclient command exists.

    If the nic is invalid or undiscoverable or dhclient command is not found,
    skip dhcp_discovery and return an empty dict.

    @param nic: Name of the network interface we want to run dhclient on.
    @return: A list of dicts representing dhcp options for each lease obtained
        from the dhclient discovery if run, otherwise an empty list is
        returned.
    """
    if nic is None:
        nic = find_fallback_nic()
        if nic is None:
            LOG.debug('Skip dhcp_discovery: Unable to find fallback nic.')
            return []
    elif nic not in get_devicelist():
        LOG.debug(
            'Skip dhcp_discovery: nic %s not found in get_devicelist.', nic)
        return []
    dhclient_path = util.which('dhclient')
    if not dhclient_path:
        LOG.debug('Skip dhclient configuration: No dhclient command found.')
        return []
    with temp_utils.tempdir(rmtree_ignore_errors=True,
                            prefix='cloud-init-dhcp-',
                            needs_exe=True) as tdir:
        # Use /var/tmp because /run/cloud-init/tmp is mounted noexec
        return dhcp_discovery(dhclient_path, nic, tdir)
Пример #7
0
def maybe_perform_dhcp_discovery(nic=None, dhcp_log_func=None):
    """Perform dhcp discovery if nic valid and dhclient command exists.

    If the nic is invalid or undiscoverable or dhclient command is not found,
    skip dhcp_discovery and return an empty dict.

    @param nic: Name of the network interface we want to run dhclient on.
    @param dhcp_log_func: A callable accepting the dhclient output and error
        streams.
    @return: A list of dicts representing dhcp options for each lease obtained
        from the dhclient discovery if run, otherwise an empty list is
        returned.
    """
    if nic is None:
        nic = find_fallback_nic()
        if nic is None:
            LOG.debug("Skip dhcp_discovery: Unable to find fallback nic.")
            raise NoDHCPLeaseInterfaceError()
    elif nic not in get_devicelist():
        LOG.debug("Skip dhcp_discovery: nic %s not found in get_devicelist.",
                  nic)
        raise NoDHCPLeaseInterfaceError()
    dhclient_path = subp.which("dhclient")
    if not dhclient_path:
        LOG.debug("Skip dhclient configuration: No dhclient command found.")
        raise NoDHCPLeaseMissingDhclientError()
    with temp_utils.tempdir(rmtree_ignore_errors=True,
                            prefix="cloud-init-dhcp-",
                            needs_exe=True) as tdir:
        # Use /var/tmp because /run/cloud-init/tmp is mounted noexec
        return dhcp_discovery(dhclient_path, nic, tdir, dhcp_log_func)
Пример #8
0
def collect_logs(tarfile, include_userdata):
    """Collect all cloud-init logs and tar them up into the provided tarfile.

    @param tarfile: The path of the tar-gzipped file to create.
    @param include_userdata: Boolean, true means include user-data.
    """
    tarfile = os.path.abspath(tarfile)
    date = datetime.utcnow().date().strftime('%Y-%m-%d')
    log_dir = 'cloud-init-logs-{0}'.format(date)
    with tempdir(dir='/tmp') as tmp_dir:
        log_dir = os.path.join(tmp_dir, log_dir)
        _write_command_output_to_file(
            ['dpkg-query', '--show', "-f=${Version}\n", 'cloud-init'],
            os.path.join(log_dir, 'version'))
        _write_command_output_to_file(['dmesg'],
                                      os.path.join(log_dir, 'dmesg.txt'))
        _write_command_output_to_file(['journalctl', '-o', 'short-precise'],
                                      os.path.join(log_dir, 'journal.txt'))
        for log in CLOUDINIT_LOGS:
            copy(log, log_dir)
        if include_userdata:
            copy(USER_DATA_FILE, log_dir)
        run_dir = os.path.join(log_dir, 'run')
        ensure_dir(run_dir)
        shutil.copytree(CLOUDINIT_RUN_DIR, os.path.join(run_dir, 'cloud-init'))
        with chdir(tmp_dir):
            subp(['tar', 'czvf', tarfile, log_dir.replace(tmp_dir + '/', '')])
Пример #9
0
def collect_logs(tarfile, include_userdata, verbosity=0):
    """Collect all cloud-init logs and tar them up into the provided tarfile.

    @param tarfile: The path of the tar-gzipped file to create.
    @param include_userdata: Boolean, true means include user-data.
    """
    if include_userdata and os.getuid() != 0:
        sys.stderr.write("To include userdata, root user is required."
                         " Try sudo cloud-init collect-logs\n")
        return 1
    tarfile = os.path.abspath(tarfile)
    date = datetime.utcnow().date().strftime('%Y-%m-%d')
    log_dir = 'cloud-init-logs-{0}'.format(date)
    with tempdir(dir='/tmp') as tmp_dir:
        log_dir = os.path.join(tmp_dir, log_dir)
        version = _write_command_output_to_file(['cloud-init', '--version'],
                                                os.path.join(
                                                    log_dir, 'version'),
                                                "cloud-init --version",
                                                verbosity)
        dpkg_ver = _write_command_output_to_file(
            ['dpkg-query', '--show', "-f=${Version}\n", 'cloud-init'],
            os.path.join(log_dir, 'dpkg-version'), "dpkg version", verbosity)
        if not version:
            version = dpkg_ver if dpkg_ver else "not-available"
        _debug("collected cloud-init version: %s\n" % version, 1, verbosity)
        _write_command_output_to_file(['dmesg'],
                                      os.path.join(log_dir, 'dmesg.txt'),
                                      "dmesg output", verbosity)
        _write_command_output_to_file(
            ['journalctl', '--boot=0', '-o', 'short-precise'],
            os.path.join(log_dir, 'journal.txt'),
            "systemd journal of current boot", verbosity)

        for log in CLOUDINIT_LOGS:
            _collect_file(log, log_dir, verbosity)
        if include_userdata:
            _collect_file(USER_DATA_FILE, log_dir, verbosity)
        run_dir = os.path.join(log_dir, 'run')
        ensure_dir(run_dir)
        if os.path.exists(CLOUDINIT_RUN_DIR):
            try:
                shutil.copytree(CLOUDINIT_RUN_DIR,
                                os.path.join(run_dir, 'cloud-init'),
                                ignore=_copytree_rundir_ignore_files)
            except shutil.Error as e:
                sys.stderr.write("Failed collecting file(s) due to error:\n")
                sys.stderr.write(str(e) + '\n')
            _debug("collected dir %s\n" % CLOUDINIT_RUN_DIR, 1, verbosity)
        else:
            _debug("directory '%s' did not exist\n" % CLOUDINIT_RUN_DIR, 1,
                   verbosity)
        with chdir(tmp_dir):
            subp(['tar', 'czvf', tarfile, log_dir.replace(tmp_dir + '/', '')])
    sys.stderr.write("Wrote %s\n" % tarfile)
    return 0
Пример #10
0
def collect_logs(tarfile, include_userdata, verbosity=0):
    """Collect all cloud-init logs and tar them up into the provided tarfile.

    @param tarfile: The path of the tar-gzipped file to create.
    @param include_userdata: Boolean, true means include user-data.
    """
    if include_userdata and os.getuid() != 0:
        sys.stderr.write(
            "To include userdata, root user is required."
            " Try sudo cloud-init collect-logs\n")
        return 1
    tarfile = os.path.abspath(tarfile)
    date = datetime.utcnow().date().strftime('%Y-%m-%d')
    log_dir = 'cloud-init-logs-{0}'.format(date)
    with tempdir(dir='/tmp') as tmp_dir:
        log_dir = os.path.join(tmp_dir, log_dir)
        version = _write_command_output_to_file(
            ['cloud-init', '--version'],
            os.path.join(log_dir, 'version'),
            "cloud-init --version", verbosity)
        dpkg_ver = _write_command_output_to_file(
            ['dpkg-query', '--show', "-f=${Version}\n", 'cloud-init'],
            os.path.join(log_dir, 'dpkg-version'),
            "dpkg version", verbosity)
        if not version:
            version = dpkg_ver if dpkg_ver else "not-available"
        _debug("collected cloud-init version: %s\n" % version, 1, verbosity)
        _write_command_output_to_file(
            ['dmesg'], os.path.join(log_dir, 'dmesg.txt'),
            "dmesg output", verbosity)
        _write_command_output_to_file(
            ['journalctl', '--boot=0', '-o', 'short-precise'],
            os.path.join(log_dir, 'journal.txt'),
            "systemd journal of current boot", verbosity)

        for log in CLOUDINIT_LOGS:
            _collect_file(log, log_dir, verbosity)
        if include_userdata:
            _collect_file(USER_DATA_FILE, log_dir, verbosity)
        run_dir = os.path.join(log_dir, 'run')
        ensure_dir(run_dir)
        if os.path.exists(CLOUDINIT_RUN_DIR):
            shutil.copytree(CLOUDINIT_RUN_DIR,
                            os.path.join(run_dir, 'cloud-init'),
                            ignore=_copytree_ignore_sensitive_files)
            _debug("collected dir %s\n" % CLOUDINIT_RUN_DIR, 1, verbosity)
        else:
            _debug("directory '%s' did not exist\n" % CLOUDINIT_RUN_DIR, 1,
                   verbosity)
        with chdir(tmp_dir):
            subp(['tar', 'czvf', tarfile, log_dir.replace(tmp_dir + '/', '')])
    sys.stderr.write("Wrote %s\n" % tarfile)
    return 0
Пример #11
0
def subp_blob_in_tempfile(blob, *args, **kwargs):
    """Write blob to a tempfile, and call subp with args, kwargs. Then cleanup.

    'basename' as a kwarg allows providing the basename for the file.
    The 'args' argument to subp will be updated with the full path to the
    filename as the first argument.
    """
    basename = kwargs.pop('basename', "subp_blob")

    if len(args) == 0 and 'args' not in kwargs:
        args = [tuple()]

    # Use tmpdir over tmpfile to avoid 'text file busy' on execute
    with temp_utils.tempdir(needs_exe=True) as tmpd:
        tmpf = os.path.join(tmpd, basename)
        if 'args' in kwargs:
            kwargs['args'] = [tmpf] + list(kwargs['args'])
        else:
            args = list(args)
            args[0] = [tmpf] + args[0]

        util.write_file(tmpf, blob, mode=0o700)
        return subp.subp(*args, **kwargs)
Пример #12
0
def collect_logs(tarfile, include_userdata: bool, verbosity=0):
    """Collect all cloud-init logs and tar them up into the provided tarfile.

    @param tarfile: The path of the tar-gzipped file to create.
    @param include_userdata: Boolean, true means include user-data.
    """
    if include_userdata and os.getuid() != 0:
        sys.stderr.write("To include userdata, root user is required."
                         " Try sudo cloud-init collect-logs\n")
        return 1
    tarfile = os.path.abspath(tarfile)
    date = datetime.utcnow().date().strftime("%Y-%m-%d")
    log_dir = "cloud-init-logs-{0}".format(date)
    with tempdir(dir="/tmp") as tmp_dir:
        log_dir = os.path.join(tmp_dir, log_dir)
        version = _write_command_output_to_file(
            ["cloud-init", "--version"],
            os.path.join(log_dir, "version"),
            "cloud-init --version",
            verbosity,
        )
        dpkg_ver = _write_command_output_to_file(
            ["dpkg-query", "--show", "-f=${Version}\n", "cloud-init"],
            os.path.join(log_dir, "dpkg-version"),
            "dpkg version",
            verbosity,
        )
        if not version:
            version = dpkg_ver if dpkg_ver else "not-available"
        _debug("collected cloud-init version: %s\n" % version, 1, verbosity)
        _write_command_output_to_file(
            ["dmesg"],
            os.path.join(log_dir, "dmesg.txt"),
            "dmesg output",
            verbosity,
        )
        _write_command_output_to_file(
            ["journalctl", "--boot=0", "-o", "short-precise"],
            os.path.join(log_dir, "journal.txt"),
            "systemd journal of current boot",
            verbosity,
        )

        for log in CLOUDINIT_LOGS:
            _collect_file(log, log_dir, verbosity)
        if include_userdata:
            user_data_file = _get_user_data_file()
            _collect_file(user_data_file, log_dir, verbosity)
        run_dir = os.path.join(log_dir, "run")
        ensure_dir(run_dir)
        if os.path.exists(CLOUDINIT_RUN_DIR):
            try:
                shutil.copytree(
                    CLOUDINIT_RUN_DIR,
                    os.path.join(run_dir, "cloud-init"),
                    ignore=_copytree_rundir_ignore_files,
                )
            except shutil.Error as e:
                sys.stderr.write("Failed collecting file(s) due to error:\n")
                sys.stderr.write(str(e) + "\n")
            _debug("collected dir %s\n" % CLOUDINIT_RUN_DIR, 1, verbosity)
        else:
            _debug(
                "directory '%s' did not exist\n" % CLOUDINIT_RUN_DIR,
                1,
                verbosity,
            )
        with chdir(tmp_dir):
            subp(["tar", "czvf", tarfile, log_dir.replace(tmp_dir + "/", "")])
    sys.stderr.write("Wrote %s\n" % tarfile)
    return 0