diff options
author | Jan Dittberner <jandd@cacert.org> | 2018-04-14 20:07:19 +0200 |
---|---|---|
committer | Jan Dittberner <jandd@cacert.org> | 2018-04-14 20:07:19 +0200 |
commit | 29f04d915c04547500c9cbf906d6a501e203aa6f (patch) | |
tree | 66a48fd034a997974713495bb26a02fec761dcb2 /sitemodules/profiles/files/puppet_server/git-pull-hook | |
parent | 9be8e28751a0aa2d577d3e3f019173f00de97a2c (diff) | |
download | cacert-puppet-29f04d915c04547500c9cbf906d6a501e203aa6f.tar.gz cacert-puppet-29f04d915c04547500c9cbf906d6a501e203aa6f.tar.xz cacert-puppet-29f04d915c04547500c9cbf906d6a501e203aa6f.zip |
Add an HTTP hook for updating code on the puppet server
Diffstat (limited to 'sitemodules/profiles/files/puppet_server/git-pull-hook')
-rwxr-xr-x | sitemodules/profiles/files/puppet_server/git-pull-hook | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/sitemodules/profiles/files/puppet_server/git-pull-hook b/sitemodules/profiles/files/puppet_server/git-pull-hook new file mode 100755 index 0000000..d8761f5 --- /dev/null +++ b/sitemodules/profiles/files/puppet_server/git-pull-hook @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +""" +This script takes care of updating the code in a directory by performing +git pull when triggered via an HTTP request to port 8000. + +The script needs the sshpass and git packages installed. + +Configuration is read from /etc/git-pull-hook.ini, ~/.git-pull-hook.ini and +a git-pull-hook.ini in the working directory in that order. +""" + +from configparser import ConfigParser +from http import HTTPStatus +from http.server import HTTPServer, BaseHTTPRequestHandler +import os +from subprocess import Popen, PIPE + +ENV_FOR_GIT = { + 'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', +} + +TOKENS = [] +GIT_DIRECTORY = "" + + +def read_ini(): + global ENV_FOR_GIT, TOKENS, GIT_DIRECTORY + config = ConfigParser() + config.read(['/etc/git-pull-hook.ini', + os.path.expanduser('~/.git-pull-hook.ini'), + 'git-pull-hook.ini']) + ENV_FOR_GIT['SSHPASS'] = config['git-pull-hook']['ssh_passphrase'] + TOKENS = [token.strip() for token in + config['git-pull-hook']['tokens'].split(',')] + GIT_DIRECTORY = config['git-pull-hook']['git_directory'] + + +class GitHookRequestHandler(BaseHTTPRequestHandler): + """ + Custom HTTP request handler for updating a git repository when called + with a known authentication token in an "Authentication" HTTP header. + """ + + def _handle_pull(self): + try: + git_proc = Popen( + ['sshpass', '-e', '-P', 'passphrase', 'git', 'pull'], + env=ENV_FOR_GIT, cwd=GIT_DIRECTORY, stdout=PIPE, stderr=PIPE) + stdout, stderr = git_proc.communicate() + for line in stderr.decode('UTF-8').splitlines(): + self.log_error('git: %s', line) + for line in stdout.decode('UTF-8').splitlines(): + self.log_message('git: %s', line) + except Exception as e: + self.log_error("Could not pull changes for %s: %s", + GIT_DIRECTORY, e) + self.send_response(HTTPStatus.OK) + self.send_header('Content-Type', 'text/plain; charset=utf8') + self.flush_headers() + self.wfile.write(("updated %s" % GIT_DIRECTORY).encode('UTF-8')) + + # noinspection PyPep8Naming + def do_GET(self): + """ + Handle GET requests, requests to /health are allowed for every caller, + requests to / need a valid token in the "Authentication" HTTP header + and trigger a git pull in the configured directory. + """ + if self.path == '/': + if self.headers['Authentication'] in [token for token in TOKENS]: + self._handle_pull() + else: + self.send_response(HTTPStatus.UNAUTHORIZED) + self.flush_headers() + elif self.path == '/health': + self.send_response(HTTPStatus.OK) + self.flush_headers() + self.wfile.write(b"I'm healthy!") + else: + self.send_error(HTTPStatus.BAD_REQUEST) + self.flush_headers() + self.wfile.write(b"You requested something I do not understand") + + +def run(server_class=HTTPServer, handler_class=GitHookRequestHandler): + server_address = ('', 8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() + + +if __name__ == '__main__': + read_ini() + run() |