Managing git repos with gitosis and puppet

In git update hook to mcollective I described pushing to multiple nodes via a git push by using a hook that pushed a repository artifact to s3 and then used mcollective to tell target nodes to download and deploy that artifact.

That’s all great, but I still needed a way to manage the git repositories. The usual candidates for git are gitosis and gitolite. There were a few hurdles to get this working so that repos could be managed out of puppet with all node and user information kept in couchdb. I earlier described Keeping puppet node definitions in CouchDB.

First of all, git should be managed through puppet. In addition, the update hook needed to get pushes out via mcollective needs to set as a template. An easy way to do this is just by having puppet manage the file at /usr/share/git-core/templates/hooks/post-update.

Managing gitosis through puppet was not a whole lot of fun. I start here with the module definition for puppet. Here be dragons:

Here is the config file for gitosis. User information, and which nodes they control is also kept in CouchDB and this gitosis config is generated by Puppet.

So… what on earth does that gitosis.pp do?

Well, apart from installing gitosis (after simply package managing it failed repeatedly) it does these things:

  • Setup the gitosis user and keys;
  • Initialise the admin replository;
  • Manage the public keys for users in gitosis;
  • Update the admin repo as new users and nodes are added

The last two items on that list might need explanation.

This is quite possibly one of the most diabolical things I’ve ever written:

  exec { "update_gitosis_admin":
    cwd => "/usr/share/src/gitosis-admin",
    command => "git add .; git commit -m 'Pushed from puppet master'; git push"

The admin repo in gitosis is a bare repository. That’s fine when you want to manage it by pusing into it remotely but I want to manage it with puppet. The workaround was to use puppet to update a clone of the gitosis admin repository and then get puppet to run a command that actually causes a push into the bare repo. Yes, it actually works. Would I recommend it? Probably not.

Finally, the user public keys are also kept in CouchDB… How to get those keys onto the node thats running gitosis? Like this:

define generate_key_files {
    file { "/usr/share/src/gitosis-admin/keydir/$":
      content => template("git/pub_key.erb"),
      notify => Exec["update_gitosis_admin"]

  $pub_key_names_array = split($pub_key_names, ',')
  generate_key_files { $pub_key_names_array: }

That’s right. The key files are all generated by puppet by taking the public key as plain text and the name of the file from CouchDB. Abandon your posts…. fear, fear for your lives.

That’s it. With this in place it’s possible to update the user and node information in CouchDB, issue a refresh on the puppet master and immediately have users doing a git push and having their code deployed to dedicated nodes.

CoffeeScript in Action

CoffeeScript in Action book cover

I'm the author. Get it from Manning.