pengtao 8e0fb41973 1
2021-06-23 14:49:35 +08:00

160 lines
6.1 KiB
Python

import os
from tempfile import NamedTemporaryFile
from ansible.inventory import Inventory
from ansible.vars import VariableManager
from ansible.parsing.dataloader import DataLoader
from ansible.executor import playbook_executor
from ansible.utils.display import Display
class Options(object):
"""
Options class to replace Ansible OptParser
"""
def __init__(self, verbosity=None, inventory=None, listhosts=None, subset=None, module_paths=None, extra_vars=None,
forks=None, ask_vault_pass=None, vault_password_files=None, new_vault_password_file=None,
output_file=None, tags=None, skip_tags=None, one_line=None, tree=None, ask_sudo_pass=None, ask_su_pass=None,
sudo=None, sudo_user=None, become=None, become_method=None, become_user=None, become_ask_pass=None,
ask_pass=None, private_key_file=None, remote_user=None, connection=None, timeout=None, ssh_common_args=None,
sftp_extra_args=None, scp_extra_args=None, ssh_extra_args=None, poll_interval=None, seconds=None, check=None,
syntax=None, diff=None, force_handlers=None, flush_cache=None, listtasks=None, listtags=None, module_path=None):
self.verbosity = verbosity
self.inventory = inventory
self.listhosts = listhosts
self.subset = subset
self.module_paths = module_paths
self.extra_vars = extra_vars
self.forks = forks
self.ask_vault_pass = ask_vault_pass
self.vault_password_files = vault_password_files
self.new_vault_password_file = new_vault_password_file
self.output_file = output_file
self.tags = tags
self.skip_tags = skip_tags
self.one_line = one_line
self.tree = tree
self.ask_sudo_pass = ask_sudo_pass
self.ask_su_pass = ask_su_pass
self.sudo = sudo
self.sudo_user = sudo_user
self.become = become
self.become_method = become_method
self.become_user = become_user
self.become_ask_pass = become_ask_pass
self.ask_pass = ask_pass
self.private_key_file = private_key_file
self.remote_user = remote_user
self.connection = connection
self.timeout = timeout
self.ssh_common_args = ssh_common_args
self.sftp_extra_args = sftp_extra_args
self.scp_extra_args = scp_extra_args
self.ssh_extra_args = ssh_extra_args
self.poll_interval = poll_interval
self.seconds = seconds
self.check = check
self.syntax = syntax
self.diff = diff
self.force_handlers = force_handlers
self.flush_cache = flush_cache
self.listtasks = listtasks
self.listtags = listtags
self.module_path = module_path
class Runner(object):
def __init__(self, hostnames, playbook, private_key_file, run_data, become_pass, verbosity=0):
self.run_data = run_data
self.options = Options()
self.options.private_key_file = private_key_file
self.options.verbosity = verbosity
self.options.connection = 'ssh' # Need a connection type "smart" or "ssh"
self.options.become = True
self.options.become_method = 'sudo'
self.options.become_user = 'root'
# Set global verbosity
self.display = Display()
self.display.verbosity = self.options.verbosity
# Executor appears to have it's own
# verbosity object/setting as well
playbook_executor.verbosity = self.options.verbosity
# Become Pass Needed if not logging in as user root
passwords = {'become_pass': become_pass}
# Gets data from YAML/JSON files
self.loader = DataLoader()
self.loader.set_vault_password(os.environ['VAULT_PASS'])
# All the variables from all the various places
self.variable_manager = VariableManager()
self.variable_manager.extra_vars = self.run_data
# Parse hosts, I haven't found a good way to
# pass hosts in without using a parsed template :(
# (Maybe you know how?)
self.hosts = NamedTemporaryFile(delete=False)
self.hosts.write("""[run_hosts]
%s
""" % hostnames)
self.hosts.close()
# This was my attempt to pass in hosts directly.
#
# Also Note: In py2.7, "isinstance(foo, str)" is valid for
# latin chars only. Luckily, hostnames are
# ascii-only, which overlaps latin charset
## if isinstance(hostnames, str):
## hostnames = {"customers": {"hosts": [hostnames]}}
# Set inventory, using most of above objects
self.inventory = Inventory(
loader=self.loader, variable_manager=self.variable_manager, host_list=self.hosts.name)
self.variable_manager.set_inventory(self.inventory)
# Playbook to run. Assumes it is
# local to this python file
pb_dir = os.path.dirname(__file__)
playbook = "%s/%s" % (pb_dir, playbook)
# Setup playbook executor, but don't run until run() called
self.pbex = playbook_executor.PlaybookExecutor(
playbooks=[playbook],
inventory=self.inventory,
variable_manager=self.variable_manager,
loader=self.loader,
options=self.options,
passwords=passwords)
def run(self):
# Results of PlaybookExecutor
self.pbex.run()
stats = self.pbex._tqm._stats
# Test if success for record_logs
run_success = True
hosts = sorted(stats.processed.keys())
for h in hosts:
t = stats.summarize(h)
if t['unreachable'] > 0 or t['failures'] > 0:
run_success = False
# Dirty hack to send callback to save logs with data we want
# Note that function "record_logs" is one I created and put into
# the playbook callback file
self.pbex._tqm.send_callback(
'record_logs',
user_id=self.run_data['user_id'],
success=run_success
)
# Remove created temporary files
os.remove(self.hosts.name)
return stats