Apply puppet automatically

— 2013-01-03 —

I recently started using github web interface as editor for my puppet configuration. I wanted to be able to push a new configuration without doing it manually, as I do not have a puppet master I wanted to try using Github hooks as in the Github lamp code. I have the puppet-repo cloned to /puppet/ and the main manifest is in /puppet/manifests/site.pp. The code below is the web.py script. It checks the payload from Github and will only apply the configuration if changes are pushed to the master branch. A GET request would simply get a 404.

from fabric.api import local, lcd
import web, json
 
urls = (
    '/', 'GithubHook',
)
 
render = web.template.render('.')
 
class GithubHook:
    def POST(self):
        data = json.loads(web.input().payload)
        if 'ref' in data:
            if data['ref'] == 'refs/heads/master':
              with lcd('/puppet/'):
                    local('git pull origin master')
                    local('puppet apply /puppet/manifests/site.pp')
                    print "applied puppet"
        else:
            print "ref: %s" % data['ref']
  else:
            print "no ref"
        return ""
 
    def GET(self):
        raise web.notfound()
 
 
if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()
 
application = web.application(urls, globals(), True).wsgifunc()

I running this with uWSGI and Nginx in front. To make the setup a little more secure I added deny all and allow to Github's IP-addresses.

server {
    listen 80;
    server_name puppet.example.com;

    access_log /var/log/nginx/puppet_apply.access.log;
    error_log /var/log/nginx/puppet_apply.error.log;

    location / {
        allow 207.97.227.253;
        allow 50.57.128.197;
        allow 108.171.174.178;
        deny all;
        
        proxy_pass         http://127.0.0.1:9060;
        proxy_redirect     off;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }

    location = /favicon.ico {
        access_log off;
        log_not_found off;
        return 204;
    }
}

The web.py script is in /home/web/puppet_apply/puppet_apply.py. The ini-file used by uWSGI is below.

[uwsgi]
chdir = /home/web/puppet_apply
virtualenv = /home/web/puppet_apply/venv
pythonpath = /home/web/puppet_apply
procname-prefix = puppet_apply
daemonize=/var/log/uwsgi/puppet_apply.log
wsgi-file = /home/web/puppet_apply/puppet_apply.py
http-socket = 0.0.0.0:9060
master = True
processes = 1
    puppet
    web.py
    nginx
    uwsgi
    github
    github-hooks