Last active
June 23, 2017 16:28
-
-
Save thash/4e748569ef9bc37249ef5970873a2bc0 to your computer and use it in GitHub Desktop.
from /opt/aws/bin/cfn-hup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python2.7 | |
#============================================================================== | |
# Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
#============================================================================== | |
import signal | |
import cfnbootstrap | |
# update_hooks: https://github.com/mesosphere/aws-cfn-bootstrap/blob/master/cfnbootstrap/update_hooks.py | |
from cfnbootstrap import update_hooks, util | |
from optparse import OptionParser | |
import logging | |
import os | |
import threading | |
import datetime | |
import sys | |
try: | |
import simplejson as json | |
except ImportError: | |
import json | |
if os.name == 'nt': | |
default_confdir = os.path.expandvars('${SystemDrive}\cfn') | |
else: | |
default_confdir = '/etc/cfn' | |
parser = OptionParser() | |
parser.add_option("-c", "--config", help="The configuration directory (default: %s)" % default_confdir, | |
type="string", dest="config_path", default=default_confdir) | |
parser.add_option("", "--no-daemon", help="Do not daemonize", | |
dest="no_daemon", action="store_true") | |
parser.add_option("-v", "--verbose", help="Enables verbose logging", | |
action="store_true", dest="verbose") | |
(options, args) = parser.parse_args() | |
fatal_event = threading.Event() | |
def main(): | |
cfnbootstrap.configureLogging("DEBUG", filename='cfn-hup.log') | |
if not options.config_path: | |
logging.error("Error: A configuration path must be specified") | |
parser.print_help(sys.stderr) | |
sys.exit(1) | |
if not os.path.isdir(options.config_path): | |
logging.error("Error: Could not find configuration at %s", options.config_path) | |
sys.exit(1) | |
try: | |
main_config, processor, cmd_processor = update_hooks.parse_config(options.config_path) | |
except ValueError, e: | |
logging.error("Error: %s", str(e)) | |
sys.exit(1) | |
verbose = options.verbose or main_config.has_option('main', 'verbose') and main_config.getboolean('main', 'verbose') | |
cfnbootstrap.configureLogging("DEBUG" if verbose else "INFO", filename='cfn-hup.log') | |
if options.no_daemon: | |
if processor: | |
processor.process() | |
if cmd_processor: | |
cmd_processor.register() | |
cmd_processor.process() | |
else: | |
interval = 15 | |
if main_config.has_option('main', 'interval'): | |
interval = main_config.getint('main', 'interval') | |
if interval < 1: | |
logging.error("Invalid interval (must be 1 minute or greater): %s", interval) | |
sys.exit(1) | |
timers = [None, None] | |
timer_lock = threading.Lock() | |
def do_process(last_log=datetime.datetime.utcnow()): | |
if fatal_event.isSet(): | |
return | |
if datetime.datetime.utcnow() - last_log > datetime.timedelta(minutes=5): | |
last_log = datetime.datetime.utcnow() | |
logging.info("cfn-hup processing is alive.") | |
try: | |
processor.process() | |
except update_hooks.FatalUpdateError, e: | |
logging.exception("Fatal exception") | |
fatal_event.set() | |
except Exception, e: | |
logging.exception("Unhandled exception") | |
with timer_lock: | |
if fatal_event.isSet(): | |
timers[0] = None | |
return | |
last_timer = threading.Timer(interval * 60, do_process, (), {'last_log' : last_log}) | |
last_timer.start() | |
timers[0] = last_timer | |
def do_cmd_process(last_log=datetime.datetime.utcnow()): | |
if fatal_event.isSet(): | |
return | |
if datetime.datetime.utcnow() - last_log > datetime.timedelta(minutes=5): | |
last_log = datetime.datetime.utcnow() | |
logging.info("command processing is alive.") | |
delay = 0 | |
try: | |
if not cmd_processor.is_registered(): | |
cmd_processor.register() | |
if cmd_processor.creds_expired(): | |
logging.error("Expired credentials found; skipping process") | |
delay = 20 | |
else: | |
cmd_processor.process() | |
except update_hooks.FatalUpdateError, e: | |
logging.exception("Fatal exception") | |
fatal_event.set() | |
except Exception, e: | |
logging.exception("Unhandled exception") | |
with timer_lock: | |
if fatal_event.isSet(): | |
timers[1] = None | |
return | |
if delay > 0: | |
last_cmd_timer = threading.Timer(delay, do_cmd_process, (), {'last_log' : last_log}) | |
last_cmd_timer.start() | |
timers[1] = last_cmd_timer | |
else: | |
threading.Thread(target=do_cmd_process, args=(), kwargs={'last_log' : last_log}).start() | |
timers[1] = None | |
if processor: | |
do_process() | |
if cmd_processor: | |
do_cmd_process() | |
while not fatal_event.isSet(): | |
fatal_event.wait(1) # Allow signals | |
with timer_lock: | |
if timers[0] is not None: | |
timers[0].cancel() | |
if timers[1] is not None: | |
timers[1].cancel() | |
sys.exit(0) | |
if options.no_daemon: | |
main() | |
elif os.name == 'nt': | |
logging.error("Error: cfn-hup cannot be run directly in daemon mode on Windows") | |
sys.exit(1) | |
else: | |
try: | |
import daemon | |
except ImportError: | |
print >> sys.stderr, "Daemon library was not installed; please install python-daemon" | |
sys.exit(1) | |
try: | |
from daemon import pidlockfile | |
except ImportError: | |
from daemon import pidfile as pidlockfile | |
def kill(signal_num, stack_frame): | |
logging.info("Shutting down cfn-hup") | |
fatal_event.set() | |
with daemon.DaemonContext(pidfile=pidlockfile.TimeoutPIDLockFile('/var/run/cfn-hup.pid', 300), | |
signal_map={signal.SIGTERM : kill}): | |
try: | |
main() | |
except Exception, e: | |
logging.exception("Unhandled exception: %s", str(e)) | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment