def log_yaml_inventory(label, inventory): """Log yaml inventory but mask passwords :param inventory: A dictionary of the ansible inventory """ alpha = inventory.get('alpha') hosts_dict = alpha.get('hosts') vars_dict = alpha.get('vars') redact_key_list = ['ansible_become_pass', 'ansible_ssh_pass'] # pylint: disable=unused-variable for host, host_dict in iteritems(hosts_dict): host_dict = redact_dict(redact_key_list, host_dict) vars_dict = redact_dict(redact_key_list, vars_dict) log.debug('%s:\n%s', label, yaml.dump(inventory)) return inventory
def process_ping_output(out_lines): """Find successful hosts from the output of a ping command. Use this function by using ansible to run echo "Hello" on remote hosts, then sending the output to this function. :param out_lines: an iterator returning lines of Ansible output. :returns: the hosts that pinged successfully, as a set and those that failed, as a set. """ success_hosts = set() failed_hosts = set() # Ansible output has the format # host | UNREACHABLE! => { # "changed": false, # "msg": "Failed to connect to the host via ssh ...", # "unreachable": true # } # hostname | SUCCESS | rc=0 >> # Hello # with the above two lines repeated for each host for line in out_lines: ansi_escape = re.compile(r'\x1b[^m]*m') line = ansi_escape.sub('', line) pieces = line.split('|') if len(pieces) == 3 and pieces[1].strip() == 'SUCCESS': success_hosts.add(pieces[0].strip()) elif len(pieces) == 3 and pieces[1].strip() == 'FAILED': failed_hosts.add(pieces[0].strip()) elif len(pieces) == 2 and pieces[1].strip().startswith('UNREACHABLE'): failed_hosts.add(pieces[0].strip()) log.debug('Ping log reached hosts: %s', success_hosts) log.debug('Ping log did not reached hosts: %s', failed_hosts) return success_hosts, failed_hosts
def run_ansible_with_vault(cmd_string, vault_pass, env=None, log_path=None, log_to_stdout=True, ansible_verbosity=0): """ Runs ansible command allowing for password to be provided after process triggered. Returns after the process completes. :param cmd_string: the command to run. :param vault_pass: the password to the user's Ansible Vault. :param env: the environment to run the subprocess in. :param log_path: a path to write the process's log to. Defaults to 'XDG_DATA_HOME/rho/ansible_log'. :param log_to_stdout: if True, write Ansible's log to stdout. Defaults to True. :param ansible_verbosity: the number of v's of Ansible verbosity. :returns: the popen.spawn object for the process. """ # pexpect provides the ability to send the process's output to a # single Python file object. We want to send it to a file and # maybe also stdout. The solution is to have pexpect log to the # file and then use 'tail -f' to copy that to stdout. if not log_path: log_path = ANSIBLE_LOG_PATH if ansible_verbosity: cmd_string = cmd_string + ' -' + 'v' * ansible_verbosity result = None try: utilities.ensure_data_dir_exists() with open(log_path, 'wb') as logfile: pass with open(log_path, 'r+b') as logfile: log.debug('Running Ansible: %s', cmd_string) child = pexpect.spawn(cmd_string, timeout=None, env=env) if log_to_stdout: utilities.threaded_tailing(log_path, ansible_verbosity) result = child.expect('Vault password:'******'s Vault # password to Ansible, so we don't log the password. child.logfile = logfile last_pos = logfile.tell() i = child.expect([pexpect.EOF, 'Enter passphrase for key .*:', 'you want to continue connecting (yes/no)?']) while i: new_pos = logfile.tell() logfile.seek(last_pos) logfile_lines = logfile.readlines() log.info(logfile_lines) print(logfile_lines[-1].replace('\r\n', '')) logfile.seek(new_pos) last_pos = new_pos child.logfile = None # Ansible has already printed a prompt; it would be # confusing if getpass printed another one. child.sendline(getpass('')) child.logfile = logfile i = child.expect([pexpect.EOF, 'Enter passphrase for key .*:', 'you want to continue connecting (yes/no)?']) if child.isalive(): child.wait() if log_to_stdout: time.sleep(2) return child except pexpect.EOF: print(str(result)) print('pexpect unexpected EOF') except pexpect.TIMEOUT: print(str(result)) print('pexpect timed out')