#!/usr/bin/python # (c) 2012, Michael DeHaan , and others # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . # try: import json except ImportError: import simplejson as json import shlex import os import subprocess import sys import datetime import traceback import signal import time if len(sys.argv) < 3: print json.dumps({ "failed" : True, "msg" : "usage: async_wrapper . Humans, do not call directly!" }) sys.exit(1) print sys.argv jid = sys.argv[1] time_limit = sys.argv[2] wrapped_module = sys.argv[3] args = sys.argv[4:] cmd = "%s %s" % (wrapped_module, " ".join(args)) # setup logging directory logdir = os.path.expanduser("~/.ansible_async") log_path = os.path.join(logdir, jid) if not os.path.exists(logdir): try: os.makedirs(logdir) except: print json.dumps({ "failed" : 1, "msg" : "could not create: %s" % logdir }) def _run_command(wrapped_cmd, jid, log_path): logfile = open(log_path, "w+") logfile.write(json.dumps({ "started" : 1, "ansible_job_id" : jid })) result = {} try: cmd = shlex.split(wrapped_cmd) script = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = script.communicate() result = json.loads(out) except (OSError, IOError), e: result = { "failed": 1, "cmd" : wrapped_cmd, "msg": str(e), } except: result = { "failed" : 1, "cmd" : wrapped_cmd, "msg" : traceback.format_exc() } result['ansible_job_id'] = jid logfile = open(log_path, "w+") logfile.write(json.dumps(result)) logfile.close() # immediately exit this process, leaving an orphaned process # running which immediately forks a supervisory timing process pid = os.fork() if pid == 0: # "RETURNING SUCCESS IN UNO" print json.dumps({ "started" : 1, "ansible_job_id" : jid }) sys.exit(0) else: # "DAEMONIZED DOS" sub_pid = os.fork() if sub_pid == 0: # "RUNNING IN KID A" _run_command(cmd, jid, log_path) sys.exit(0) else: # "WATCHING IN KID B" remaining = int(time_limit) if os.path.exists("/proc/%s" % sub_pid): # "STILL RUNNING" time.sleep(1) remaining = remaining - 1 else: # "DONE IN KID B" sys.exit(0) if remaining == 0: # "SLAYING IN KID B" os.kill(sub_pid, signals.SIGKILL) sys.exit(1) sys.exit(0)