Beispiel #1
0
def vault_json_list(value):
    """Run code with a new Vault-protected JSON list.

    After the code is finished, read back the value of the file and
    store it in `value`.

    :param value: the starting value of the Vault-protected JSON
    list. The final value will be written to this.
    """

    with tempfile.NamedTemporaryFile(delete=False) as temp_list:
        # Write the value to the temporary file
        this_vault = vault.Vault(TEST_VAULT_PASSWORD)
        this_vault.dump_as_json(value, stream=temp_list)
        temp_list.flush()

        # Run the code, making the file path available
        try:
            yield temp_list.name
        finally:
            # Read the (potentially modified) list file
            if os.path.isfile(temp_list.name):
                value[:] = this_vault.load_as_json(temp_list.name)
                os.unlink(temp_list.name)
            else:
                # The code might have deleted the file
                value[:] = []
Beispiel #2
0
def inventory_scan(hosts_yml_path,
                   facts_to_collect,
                   report_path,
                   vault_pass,
                   base_name,
                   forks=None,
                   scan_dirs=None,
                   log_path=None,
                   verbosity=0):
    """Run an inventory scan.

    :param hosts_yml_path: path to an Ansible inventory file to scan.
    :param facts_to_collect: a list of facts to collect.
    :param report_path: the path to write a report to.
    :param vault_pass: the vault password used to protect user data
    :param base_name: the base name of the output files
    :param forks: the number of Ansible forks, or None for default.
    :param scan_dirs: the directories on the remote host to scan, or None for
        default.
    :param log_path: path to log to, or None for default.
    :param verbosity: number of v's of Ansible verbosity.

    :returns: True if scan completed successfully, False if not.
    """
    hosts_yml = base_name + utilities.PROFILE_HOSTS_SUFIX
    hosts_yml_path = utilities.get_config_path(hosts_yml)

    vault = vault_module.Vault(vault_pass)
    hosts_dict = vault.load_as_yaml(hosts_yml_path)
    host_groups = hosts_by_group(hosts_dict)

    variables_prefix = os.path.join(tempfile.gettempdir(),
                                    'rho-fact-temp-' + str(time.time()) + '-')

    if os.path.isfile(utilities.PLAYBOOK_DEV_PATH):
        playbook = utilities.PLAYBOOK_DEV_PATH
    elif os.path.isfile(utilities.PLAYBOOK_RPM_PATH):
        playbook = utilities.PLAYBOOK_RPM_PATH
    else:
        print(t("rho scan playbook not found locally or in '%s'") % playbook)
        sys.exit(1)

    log_path = log_path or utilities.SCAN_LOG_PATH

    my_env = os.environ.copy()
    my_env["ANSIBLE_HOST_KEY_CHECKING"] = "False"
    my_env["ANSIBLE_NOCOLOR"] = "True"

    facts_out = []
    total_hosts_count = 0
    for group in host_groups.keys():
        hosts = host_groups.get(group, [])
        total_hosts_count += len(hosts)

    utilities.log.info('Starting scan of %d systems broken into %d groups.',
                       total_hosts_count, len(host_groups.keys()))
    print('\nStarting scan of %d systems broken into %d groups.' %
          (total_hosts_count, len(host_groups.keys())))
    for group in host_groups.keys():
        variables_path = variables_prefix + group
        hosts = host_groups.get(group, [])
        ansible_vars = {
            'facts_to_collect': list(facts_to_collect),
            'scan_dirs': ' '.join(scan_dirs or []),
            'variables_path': variables_path
        }

        cmd_string = ('ansible-playbook {playbook} '
                      '--limit {group},localhost '
                      '-i {inventory} -f {forks} '
                      '--ask-vault-pass '
                      '--extra-vars \'{vars}\'').format(
                          group=group,
                          playbook=playbook,
                          inventory=hosts_yml_path,
                          forks=forks,
                          vars=json.dumps(ansible_vars))

        rho_host_scan_timeout = os.getenv('RHO_HOST_SCAN_TIMEOUT',
                                          DEFAULT_HOST_SCAN_TIMEOUT)

        try:
            rho_host_scan_timeout = int(rho_host_scan_timeout)
        except ValueError:
            rho_host_scan_timeout = DEFAULT_HOST_SCAN_TIMEOUT

        host_scan_timeout = ((len(hosts) // int(forks)) + 1) \
            * rho_host_scan_timeout
        utilities.log.info(
            'Starting scan for group "%s" with %d systems'
            ' with timeout of %d minutes.', group, len(hosts),
            host_scan_timeout)
        print('\nStarting scan for group "%s" with %d systems'
              ' with timeout of %d minutes.\n' %
              (group, len(hosts), host_scan_timeout))
        try:
            ansible_utils.run_with_vault(
                cmd_string,
                vault_pass,
                env=my_env,
                log_path=log_path,
                log_to_stdout=utilities.process_host_scan,
                ansible_verbosity=verbosity,
                timeout=host_scan_timeout * 60,
                print_before_run=True)
        except ansible_utils.AnsibleProcessException as ex:
            print(
                t("An error has occurred during the scan. Please review" +
                  " the output to resolve the given issue: %s" % str(ex)))
            sys.exit(1)
        except ansible_utils.AnsibleTimeoutException as ex:
            utilities.log.warning(
                'Scan for group "%s" timed out. Hosts \n'
                '%s\nwill be skipped. The rest of the scan '
                'is not affected.', group, host_groups[group])
            continue

        if os.path.isfile(variables_path):
            with open(variables_path, 'r') as variables_file:
                vars_by_host = {}
                update_json = json.load(variables_file)
                for host in hosts:
                    host_facts = update_json.get(host, {})
                    vars_by_host[host] = host_facts
                os.remove(variables_path)
                utilities.log.info('Processing scan data for %d more systems.',
                                   len(hosts))
                print('\nProcessing scan data for %d more systems.' %
                      (len(hosts)))
                group_facts = process_host_vars(facts_to_collect, vars_by_host)
                facts_out += group_facts
                utilities.log.info('Completed scanning %d systems.',
                                   len(facts_out))
                print('Completed scanning %d systems.\n' % (len(facts_out)))

        else:
            utilities.log.error(
                'Error collecting data for group %s.'
                'output file %s not found.', group, variables_path)

    if facts_out == []:
        print(
            t("An error has occurred during the scan. " +
              "No data was collected for any groups. " +
              "Please review the output to resolve the given issues"))
        sys.exit(1)

    write_fact_report(facts_to_collect, facts_out, report_path)