Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
Create timeouts dynamically based on the number of systems to be proc…
Browse files Browse the repository at this point in the history
…essed. Closes #563. (#566)
  • Loading branch information
chambridge committed Dec 19, 2017
1 parent 1bd1a74 commit 2257755
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 29 deletions.
67 changes: 50 additions & 17 deletions rho/host_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
from collections import defaultdict
import os
import re

from ansible.parsing.utils.addresses import parse_address
from ansible.plugins.inventory import detect_range, expand_hostname_range
from rho import ansible_utils
from rho.translation import _
from rho.utilities import (log, str_to_ascii, PING_INVENTORY_PATH,
from rho.utilities import (log, PING_INVENTORY_PATH,
PING_LOG_PATH,
process_discovery_scan)

Expand Down Expand Up @@ -63,6 +64,34 @@ def process_ping_output(out_lines):
return success_hosts, failed_hosts, unreachable_hosts


def _expand_hostpattern(hostpattern):
"""Expands pattern into list of hosts.
Takes a single host pattern and returns a list of hostnames.
:param hostpattern: a single host pattern
:returns: list of hostnames
"""
# Can the given hostpattern be parsed as a host with an optional port
# specification?

try:
# pylint: disable=unused-variable
(pattern, port) = parse_address(hostpattern, allow_ranges=True)
except: # noqa pylint: disable=bare-except
# not a recognizable host pattern
pattern = hostpattern

# Once we have separated the pattern, we expand it into list of one or
# more hostnames, depending on whether it contains any [x:y] ranges.

if detect_range(pattern):
hostnames = expand_hostname_range(pattern)
else:
hostnames = [pattern]

return hostnames


# Creates the inventory for pinging all hosts and records
# successful auths and the hosts they worked on
# pylint: disable=too-many-statements, too-many-arguments, unused-argument
Expand All @@ -86,6 +115,7 @@ def create_ping_inventory(vault, vault_pass, profile_ranges, profile_port,
"""

# pylint: disable=too-many-locals
all_hosts = []
success_hosts = set()
failed_hosts = set()
unreachable_hosts = set()
Expand All @@ -94,26 +124,30 @@ def create_ping_inventory(vault, vault_pass, profile_ranges, profile_port,
hosts_dict = {}

for profile_range in profile_ranges:
# pylint: disable=anomalous-backslash-in-string
reg = "[0-9]*.[0-9]*.[0-9]*.\[[0-9]*:[0-9]*\]"
profile_range = profile_range.strip(',').strip()
hostname = str_to_ascii(profile_range)
if not re.match(reg, profile_range):
hosts_dict[profile_range] = {'ansible_host': profile_range,
'ansible_port': profile_port}
else:
hosts_dict[hostname] = None
hosts = _expand_hostpattern(profile_range)
all_hosts += hosts

for host in all_hosts:
hosts_dict[host] = {'ansible_host': host,
'ansible_port': profile_port}

vars_dict = ansible_utils.auth_as_ansible_host_vars(credential)

yml_dict = {'alpha': {'hosts': hosts_dict, 'vars': vars_dict}}
vault.dump_as_yaml_to_file(yml_dict, PING_INVENTORY_PATH)
ansible_utils.log_yaml_inventory('Ping inventory', yml_dict)

log.info('Attempting connection discovery with auth "%s".',
credential.get('name'))
print(_('Attempting connection discovery with auth "%s".' %
(credential.get('name'))))
total_hosts_count = len(all_hosts)
rho_discovery_timeout = os.getenv('RHO_DISCOVERY_TIMEOUT', 5)
discovery_timeout = ((total_hosts_count // int(forks)) + 1) \
* rho_discovery_timeout

log.info('Attempting connection discovery to %d systems'
' with auth "%s" using a timeout of %d minutes.',
total_hosts_count, credential.get('name'), discovery_timeout)
print(_('Attempting connection discovery to %d systems'
' with auth "%s" using a timeout of %d minutes.' %
(total_hosts_count, credential.get('name'), discovery_timeout)))

cmd_string = 'ansible alpha -m raw' \
' -i ' + PING_INVENTORY_PATH \
Expand All @@ -133,7 +167,6 @@ def create_ping_inventory(vault, vault_pass, profile_ranges, profile_port,
# verbosity can break our parsing of Ansible's output. This is
# a temporary fix - a better solution would be less-fragile
# output parsing.
rho_discovery_timeout = os.getenv('RHO_DISCOVERY_TIMEOUT', 30 * 60)
try:
ansible_utils.run_with_vault(
cmd_string, vault_pass,
Expand All @@ -142,7 +175,7 @@ def create_ping_inventory(vault, vault_pass, profile_ranges, profile_port,
log_to_stdout=process_discovery_scan,
log_to_stdout_env=log_env,
ansible_verbosity=0,
timeout=rho_discovery_timeout,
timeout=discovery_timeout * 60,
error_on_failure=False)
except ansible_utils.AnsibleTimeoutException:
# If the discovery scan times out, we'll just parse whatever
Expand Down
40 changes: 28 additions & 12 deletions rho/inventory_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,19 @@ def inventory_scan(hosts_yml_path, facts_to_collect, report_path,
my_env["ANSIBLE_HOST_KEY_CHECKING"] = "False"
my_env["ANSIBLE_NOCOLOR"] = "True"

vars_by_host = {}
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}
Expand All @@ -293,15 +300,23 @@ def inventory_scan(hosts_yml_path, facts_to_collect, report_path,
forks=forks,
vars=json.dumps(ansible_vars))

rho_host_scan_timeout = os.getenv('RHO_HOST_SCAN_TIMEOUT', 30 * 60)
rho_host_scan_timeout = os.getenv('RHO_HOST_SCAN_TIMEOUT', 10)
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=rho_host_scan_timeout,
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" +
Expand All @@ -316,28 +331,29 @@ def inventory_scan(hosts_yml_path, facts_to_collect, report_path,

if os.path.isfile(variables_path):
with open(variables_path, 'r') as variables_file:
vars_by_host = {}
update_json = json.load(variables_file)
hosts = host_groups.get(group, [])
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))
utilities.log.info('Completed scanning %d systems.',
len(vars_by_host.keys()))
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(vars_by_host.keys())))
os.remove(variables_path)
group_facts = process_host_vars(facts_to_collect, vars_by_host)
facts_out += group_facts
(len(facts_out)))

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

if vars_by_host == {}:
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"))
Expand Down

0 comments on commit 2257755

Please sign in to comment.