blob: a00fca8b31272e0326d3fcf3ee3091fbb8d6f045 [file] [log] [blame]
#!/usr/bin/env python
import os
import sys
import pdb
import json
import uuid
from ansible import constants
constants = reload(constants)
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
from ansible.plugins.callback import CallbackBase
from xos.logger import observer_logger as logger
class ResultCallback(CallbackBase):
CALLBACK_VERSION = 2.0
CALLBACK_NAME = 'resultcallback'
CALLBACK_TYPE = 'programmatic'
def __init__(self):
super(ResultCallback, self).__init__()
self.results = []
self.uuid = str(uuid.uuid1())
self.playbook_status = 'OK'
def v2_playbook_on_start(self, playbook):
self.playbook = playbook._file_name
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "playbook start",
'ansible_status': "OK",
'ansible_playbook': self.playbook
}
logger.info("PLAYBOOK START [%s]" % self.playbook, extra=log_extra)
def v2_playbook_on_stats(self, stats):
host_stats = {}
for host in stats.processed.keys():
host_stats[host] = stats.summarize(host)
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "playbook stats",
'ansible_status': self.playbook_status,
'ansible_playbook': self.playbook,
'ansible_result': json.dumps(host_stats)
}
if self.playbook_status == 'OK':
logger.info("PLAYBOOK END [%s]" % self.playbook, extra=log_extra)
else:
logger.error("PLAYBOOK END [%s]" % self.playbook, extra=log_extra)
def v2_playbook_on_play_start(self, play):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "play start",
'ansible_status': self.playbook_status,
'ansible_playbook': self.playbook
}
logger.debug("PLAY START [%s]" % play.name, extra=log_extra)
def v2_runner_on_ok(self, result, **kwargs):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "OK",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.debug("OK [%s]" % str(result._task), extra=log_extra)
self.results.append(result)
def v2_runner_on_failed(self, result, **kwargs):
self.playbook_status = "FAILED"
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "FAILED",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.error("FAILED [%s]" % str(result._task), extra=log_extra)
self.results.append(result)
def v2_runner_on_async_failed(self, result, **kwargs):
self.playbook_status = "FAILED"
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "ASYNC FAILED",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.error("ASYNC FAILED [%s]" % str(result._task), extra=log_extra)
def v2_runner_on_skipped(self, result, **kwargs):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "SKIPPED",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.debug("SKIPPED [%s]" % str(result._task), extra=log_extra)
self.results.append(result)
def v2_runner_on_unreachable(self, result, **kwargs):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "UNREACHABLE",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.error("UNREACHABLE [%s]" % str(result._task), extra=log_extra)
self.results.append(result)
def v2_runner_retry(self, result, **kwargs):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "RETRY",
'ansible_result': json.dumps(result._result),
'ansible_task': result._task,
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.warning("RETRYING [%s] - attempt %d" % (str(result._task), result._result['attempts']), extra=log_extra)
self.results.append(result)
def v2_playbook_on_handler_task_start(self, task, **kwargs):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "task",
'ansible_status': "HANDLER",
'ansible_task': task.get_name().strip(),
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.debug("HANDLER [%s]" % task.get_name().strip(), extra=log_extra)
def v2_playbook_on_import_for_host(self, result, imported_file):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "import",
'ansible_status': "IMPORT",
'ansible_result': json.dumps(result._result),
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.debug("IMPORT [%s]" % imported_file, extra=log_extra)
self.results.append(result)
def v2_playbook_on_not_import_for_host(self, result, missing_file):
log_extra = {
'xos_type': "ansible",
'ansible_uuid': self.uuid,
'ansible_type': "import",
'ansible_status': "MISSING IMPORT",
'ansible_result': json.dumps(result._result),
'ansible_playbook': self.playbook,
'ansible_host': result._host.get_name()
}
logger.debug("MISSING IMPORT [%s]" % missing_file, extra=log_extra)
self.results.append(result)
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, playbook, run_data, private_key_file=None, verbosity=0, host_file=None):
self.playbook = playbook
self.run_data = run_data
self.options = Options()
self.options.output_file = playbook + '.result'
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()
try:
self.loader.set_vault_password(os.environ['VAULT_PASS'])
except KeyError:
pass
# All the variables from all the various places
self.variable_manager = VariableManager()
self.variable_manager.extra_vars = {} # self.run_data
# Set inventory, using most of above objects
if (host_file):
self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list = host_file)
else:
self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager)
self.variable_manager.set_inventory(self.inventory)
# 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={})
def run(self):
os.environ['REQUESTS_CA_BUNDLE'] = '/usr/local/share/ca-certificates/local_certs.crt'
callback = ResultCallback()
self.pbex._tqm._stdout_callback = callback
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
#os.remove(self.hosts.name)
return stats,callback.results