#! /usr/bin/env python # A script to lunch python binaries # usage: ./launch.py heartbeat import os, sys import json import requests import boto3 import traceback # We expect this to run in the docker image. cron runs out of /root # and doesn't want to change, we might create a 'tracker' user and set this # as there home. but for now.... os.chdir('/tracker') sys.path.insert(0, '.') hostname = requests.get('http://169.254.169.254/latest/meta-data/hostname').text instance_id = requests.get('http://169.254.169.254/latest/meta-data/instance-id').text def launch_script(script, this_logger): import importlib import importlib.util as iutil found = iutil.find_spec(script) if not found: this_logger.error( "No script module called {0} is found ({0}.py should exist in this folder)".format(script)) return False from tracker import db db.setup_session(application_name=script[0:30].lower()) this_logger.info("Launching {}, db {}".format(script, db.Session.get_bind())) cronitor_id = os.environ.get('WL_CRONITOR_ID') send_cloudwatch_fail_event = ( # default true: (os.environ.get("WL_SEND_CW_FAIL_EVENT") or 'true').lower() in ['t', 'true', '1', 'on'] ) if not cronitor_id: this_logger.warning("No cronitor setup for {}".format(script)) else: requests.get("https://cronitor.link/{}/run".format(cronitor_id)) try: importlib.import_module(script) except Exception as e: this_logger.exception("Unhandled error in script. {}".format(e), exc=e) if send_cloudwatch_fail_event: cw = boto3.client('events') event_detail = { 'script': script, 'error': str(e), 'traceback': traceback.format_exc(), 'hostname': hostname, 'instance-id': instance_id, } put_attempt = cw.put_events(Entries=[{ 'Source': 'tracker-script', 'DetailType': 'tracker-job-failure', 'Detail': json.dumps(event_detail), }]) this_logger.info("Sent cw event", extra=put_attempt) if cronitor_id: from urllib.parse import quote failmsg = quote(str(e)[:100]) requests.get("https://cronitor.link/{}/fail&msg={}".format(cronitor_id, failmsg)) return False else: if cronitor_id: requests.get("https://cronitor.link/{}/complete".format(cronitor_id)) try: db.Session.remove() except Exception as e: logger.exception("Error removing database session, this could be fatal. {}".format(e)) return True if __name__ == '__main__': try: script = sys.argv[1] except IndexError: print("Script name argument is required.", file=sys.stderr) sys.exit(2) from tracker import logger logger.setup_logging() this_logger = logger.get_logger('launch') print(json.dumps(dict( log_signal="script_starting", script=script ))) success = launch_script(script, this_logger) final_log = json.dumps(dict( log_signal="script_complete", script=script, status="SUCCESSFULLY" if success else "BADLY", human="Task {} completed {}".format(script, "SUCCESSFULLY" if success else "BADLY"), )) print(final_log) sys.exit(0 if success else 5)