Skip to content

Instantly share code, notes, and snippets.

@lazypower
Last active August 29, 2015 14:19
Show Gist options
  • Save lazypower/dc8998499603f2789856 to your computer and use it in GitHub Desktop.
Save lazypower/dc8998499603f2789856 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# A build hook for managing a build-pipeline on a system running docker
# containers. This python script is inteded to be run in tandem with the
# `hooked` python module, to provide a post-commit hook to build your app
# from a Dockerfile, and cycle the running container with the freshly built
# image.
#
# This script does nothing with 'container management' - meaning you *will*
# flood your server with old container images. Cleanup is expected to be
# run by hand.
#
# Monitor the logs if you wish to know of any failures, at present this only
# pipes output to STDOUT/STDERR.
#
# Example usage: build-hook.py -r $HOME/myrepo -t myrepo -v
import argparse
from docker import Client
import logging
import shlex
from subprocess import check_call
logger = logging.getLogger('build-hook')
logger.setLevel(logging.INFO)
def setup_logging(verbose=None, debug=None):
logger = logging.getLogger('build-hook')
logger.setLevel(logging.INFO)
if debug:
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
if verbose:
f = '%(asctime)s %(levelname)s %(name)s: %(message)s'
else:
f = '%(levelname)s %(name)s: %(message)s'
formatter = logging.Formatter(f)
ch.setFormatter(formatter)
if verbose is None:
ch = logging.NullHandler()
logger.addHandler(ch)
return logger
def setup_parser():
p = argparse.ArgumentParser(prog='build-hook',
description='A build hook intended to run'
' Docker container builds on'
' a live system')
p.add_argument('-r', '--repo', required=True,
help='Repository warehousing a Dockerfile')
p.add_argument('-t','--tag', required=True,
help='Docker tag to apply to the build')
p.add_argument('--no-kill', action='store_true',
help='Do not kill existing container')
p.add_argument('-s', '--script', help="path to start script")
p.add_argument('-v', '--verbose', action='store_true')
p.add_argument('--debug', action='store_true')
return p
def setup_docker_client():
cli = Client(base_url='unix://var/run/docker.sock')
return cli
def find_running_container(cli, tag, log):
containers = cli.containers()
for c in containers:
if c['Image'] == "{}:latest".format(tag):
log.warn("Container {} scheduled for nuking "
"after build".format(c['Id']))
return c['Id']
log.info("No container found... continuing build")
def build(cli, repo, tag, log):
log.info("Starting build... please wait, this can take some time")
try:
response = [line for line in cli.build(path=repo, nocache=True,
rm=True, tag=tag)]
except:
log.critical("Build failed, dumping response")
for line in response:
log.critical(line)
return False
log.info("Build Succeeded!")
return True
def main(args=None):
parser = setup_parser()
known, unknown = parser.parse_known_args(args)
log = setup_logging(verbose=known.verbose, debug=known.debug)
cli = setup_docker_client()
if not known.no_kill:
running_container = find_running_container(cli, known.tag, log)
build_status = build(cli, known.repo, known.tag, log)
if not build_status:
log.warn('Known build failure. Exiting prematurely')
return
if not known.no_kill and running_container:
log.warn("Killing existing container {}".format(running_container))
cli.kill(running_container)
if known.script:
log.info("Calling startup script: {}".format(known.script))
check_call(known.script)
else:
cmd = "docker run -d {}".format(known.tag)
log.info("Calling startup with generated default: {}".format(cmd))
check_call(shlex.split(cmd))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment