From cd28ae6b1aecb974713c841667bb0b00acfbdf39 Mon Sep 17 00:00:00 2001 From: yackob03 Date: Thu, 24 Oct 2013 00:05:58 -0400 Subject: [PATCH] First stab at a buildserver that will puppet docker to build dockerfiles remotely. --- buildserver/Readme.md | 1 + buildserver/buildserver.py | 115 +++++++++++++++++++++++++++++ buildserver/requirements-nover.txt | 2 + buildserver/test.html | 8 ++ 4 files changed, 126 insertions(+) create mode 100644 buildserver/Readme.md create mode 100644 buildserver/buildserver.py create mode 100644 buildserver/requirements-nover.txt create mode 100644 buildserver/test.html diff --git a/buildserver/Readme.md b/buildserver/Readme.md new file mode 100644 index 000000000..8cc88d12d --- /dev/null +++ b/buildserver/Readme.md @@ -0,0 +1 @@ +This must be run on Python version 2.7.4 or later (Ubuntu 13.04) for security reasons. \ No newline at end of file diff --git a/buildserver/buildserver.py b/buildserver/buildserver.py new file mode 100644 index 000000000..f9eba8416 --- /dev/null +++ b/buildserver/buildserver.py @@ -0,0 +1,115 @@ +import docker +import logging +import shutil +import os +import re + +from flask import Flask, request, send_file, make_response, jsonify +from zipfile import ZipFile +from tempfile import TemporaryFile, mkdtemp + + +BUFFER_SIZE = 8 * 1024 +LOG_FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \ + '%(funcName)s - %(message)s' + +app = Flask(__name__) +logger = logging.getLogger(__name__) + + +def count_steps(dockerfileobj): + steps = 0 + for line in dockerfileobj.readlines(): + stripped = line.strip() + if stripped and stripped[0] is not '#': + steps += 1 + return steps + +@app.route('/') +def index(): + return send_file('test.html') + + +@app.route('/start/zip/', methods=['POST']) +def start_build(tag_name): + docker_zip = request.files['dockerfile'] + + build_dir = mkdtemp(prefix='docker-build-') + + # Save the zip file to temp somewhere + with TemporaryFile() as zip_file: + docker_zip.save(zip_file) + to_extract = ZipFile(zip_file) + to_extract.extractall(build_dir) + + docker_cl = docker.Client(version='1.5') + + build_status = docker_cl.build(path=build_dir, tag=tag_name) + + dockerfile_path = os.path.join(build_dir, "Dockerfile") + with open(dockerfile_path, 'r') as dockerfileobj: + num_steps = count_steps(dockerfileobj) + logger.debug('Dockerfile had %s steps' % num_steps) + + current_step = 0 + built_image = None + for status in build_status: + step_increment = re.search(r'Step ([0-9]+) :', status) + if step_increment: + current_step = int(step_increment.group(1)) + logger.debug('Step now: %s/%s' % (current_step, num_steps)) + continue + + complete = re.match(r'Successfully built ([a-z0-9]+)', status) + if complete: + built_image = complete.group(1) + logger.debug('Final image ID is: %s' % built_image) + continue + + shutil.rmtree(build_dir) + + # Get the image count + if not built_image: + abort(500) + + history = docker_cl.history(built_image) + num_images = len(history) + + logger.debug('Pushing to tag name: %s' % tag_name) + resp = docker_cl.push(tag_name) + + current_image = 0 + image_progress = 0 + for status in resp: + if u'status' in status: + status_msg = status[u'status'] + + next_image = r'(Pushing:|Image) [a-z0-9]+( already pushed, skipping)?' + match = re.match(next_image, status_msg) + if match: + current_image += 1 + image_progress = 0 + logger.debug('Now pushing image %s/%s' % (current_image, num_images)) + continue + + if status_msg == u'Pushing' and u'progress' in status: + percent = r'\(([0-9]+)%\)' + match = re.search(percent, status[u'progress']) + if match: + image_progress = int(match.group(1)) + continue + + return jsonify({ + 'images_pushed': num_images, + 'commands_run': num_steps, + }) + + +@app.route('/status') +def get_status(): + return 'building' + + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) + app.run(host='0.0.0.0', port=5002, debug=True) \ No newline at end of file diff --git a/buildserver/requirements-nover.txt b/buildserver/requirements-nover.txt new file mode 100644 index 000000000..7a7ebd121 --- /dev/null +++ b/buildserver/requirements-nover.txt @@ -0,0 +1,2 @@ +flask +-e git+git://github.com/dotcloud/docker-py.git#egg=docker-py \ No newline at end of file diff --git a/buildserver/test.html b/buildserver/test.html new file mode 100644 index 000000000..472f4dd6d --- /dev/null +++ b/buildserver/test.html @@ -0,0 +1,8 @@ + + +
+ + +
+ + \ No newline at end of file