Coherent Ramblings

2010/05/24

Spiritual Safety Tip

Filed under: Around The Web — Tags: — plathrop @ 11:24 am

Spiritual Safety Tip

clusto do-my-dishes

Filed under: Clusto, Digg, Systems Engineering — Tags: , — plathrop @ 10:50 am

While discussing the proper class hierarchy for adding our Netscalers to Clusto, we decided that Appliance was the proper name for the base class.

This of course led to the idea of coding up a driver for a dishwasher. clusto do-my-dishes FTW!

2010/05/19

Empire Parody

Filed under: Around The Web — plathrop @ 3:31 pm

2010/05/18

Weirdest Mail Ever

Filed under: Uncategorized — Tags: — plathrop @ 11:10 am
  • UPDATE #2: Mystery solved! They are replacement stickies for our rain chimes, ordered by my lovely partner!
  • UPDATE: I just realized the envelope was folded in thirds; perhaps it was mailed inside another envelope to Seattle?

This morning I received the weirdest piece of (snail) mail I’ve ever seen. The envelope has what appear to be St. Jude style address labels with my info printed on them (I use these labels myself all the time). Both the “To” and return address labels have my name and address on them. The envelope is postmarked Seattle, and has a Forever stamp on it. Here’s the envelope:

Inside was nothing but six machine-cut blank white sticky labels on a yellow backing:

Does anybody have any clue what this is all about?

2010/05/11

Git Hooks: Branch ACLs and more.

Filed under: Git, Tools — Tags: , — plathrop @ 1:47 pm

Recently at Digg, we wanted to open up the git repository containing our Puppet manifests so that our developers could work with it. However, we wanted to maintain some control over which branches they could push to, in order to prevent accidental commits to the production manifests. In addition to this fine-grained authorization, we wanted the ability to force their development branch to track ours; we always want them working from the latest code we’ve committed.

There are some heavier-weight options we could use to accomplish this sort of thing, but we aren’t yet ready to move to a more complicated tool chain for this sort of thing. I was pretty sure we could accomplish this with git hooks. I was right:

#!/usr/bin/env python
 
import os
import re
 
from sys import argv, exit
from subprocess import Popen, PIPE
 
 
def blank(line):
    regex = re.compile('^\s*$')
    if regex.search(line):
        return True
    else:
        return False
 
 
def uncomment(line):
    return line.partition('#')[0]
 
 
def cleanup(lines):
    # Remove full-line comments.
    lines = [line for line in lines if not line.startswith('#')]
    # Remove blank lines.
    lines = [line for line in lines if not blank(line)]
    # Remove comments from line ends.
    lines = [uncomment(line) for line in lines]
 
    return lines
 
def parse_acl():
    try:
        fh = open('acl')
    except IOError:
        print "Could not open ACL file. Exiting."
        exit(1)
 
    # Read and close ACL file.
    lines = fh.readlines()
    fh.close()
    lines = cleanup(lines)
 
    # The ACL lines are whitespace separated. The first field is the
    # username, the second field is a regex describing the refs the
    # user is allowed to update.
    access = {}
    for line in lines:
        record = line.split()
        r_user = record[0]
        r_ref = record[1]
        if r_user in access:
            access[r_user] = access[r_user] + [r_ref]
        else:
            access[r_user] = [r_ref]
 
    return access
 
 
def authorize(refname='', user='', access={}):
    if not user in access:
        return False
 
    allowed_refs = access[user]
    for a_ref in allowed_refs:
        regex = re.compile("^%s$" % a_ref)
        if regex.search(refname):
            return True
 
    return False
 
 
def parse_git_config(config_entry):
    output = Popen(["git", "config", "--bool", config_entry], stdout=PIPE).communicate()[0]
    if output.strip() == 'true':
        return True
    else:
        return False
 
 
def parse_branch_tracking():
    try:
        fh = open('branch_tracking')
    except IOError:
        print "Could not open branch tracking file. Exiting."
        exit(1)
 
    # Read and close branch tracking file.
    lines = fh.readlines()
    fh.close()
    lines = cleanup(lines)
 
    # Branch tracking lines are whitespace separated. The first field
    # is the branch that must track the branch specified in the second
    # field.
    tracking = {}
    for line in lines:
        record = line.split()
        r_branch = record[0]
        r_track = record[1]
        tracking[r_branch] = r_track
 
    return tracking
 
 
def get_tracked_branch(refname):
    track = parse_branch_tracking()
    try:
        return track[refname]
    except KeyError:
        return None
 
 
def get_missing_refs(ref, base_ref):
    # git rev-list gives us the commits reachable from base_ref that
    # are NOT reachable from ref.
    output = Popen(["git", "rev-list", '%s..%s' % (ref, base_ref)], stdout=PIPE).communicate()[0]
    return output.splitlines()
 
 
def main():
    # The args are passed in by git.
    refname = argv[1]
    old_rev = argv[2]
    new_rev = argv[3]
    user = os.environ['USER']
 
    # Check if 'push acl' is enabled.
    push_acl = parse_git_config('hooks.pushacl')
 
    if push_acl:
        # Check the user's authorization to update these git refs.
        access = parse_acl()
        if not authorize(refname=refname, user=user, access=access):
            print "Could not update %s, permission denied by ACL." % refname
            exit(1)
 
    # Check if 'forced branch tracking' is enabled.
    force_tracking = parse_git_config('hooks.forcebranchtracking')
 
    if force_tracking:
        tbranch = get_tracked_branch(refname)
        if tbranch:
            # Get the refs that are reachable from our tracked branch
            # but NOT reachable from our new revision.
            missed_refs = get_missing_refs(new_rev, tbranch)
 
            if len(missed_refs) > 0:
                print "Could not update %s, you need to merge %s." % (refname, tbranch)
                exit(1)
 
 
if __name__ == '__main__':
    main()

This implements two git config options:

git config --bool hooks.pushacl
git config --bool hooks.forcebranchtracking

They are both meant to be set on a bare git repository (git init --bare). The first option causes the update hook to look for a file called ‘acl’ in the root of the bare repo. Here is the ACL file I’m using for our puppet configs right now:

plathrop refs/.*/.*
ron refs/.*/.*
synack refs/.*/.*
wfrancis refs/.*/.*
kad refs/.*/.*
mike refs/.*/.*
rcoli refs/heads/(development|(rcoli/.*)){1}
goffinet refs/heads/experimental
rich refs/heads/experimental
kelvin refs/heads/experimental

The entries are regular expressions matching git “refs”. So, I have full access, rcoli can push to the development branch or any branch starting with “rcoli/” (but cannot create tags), and goffinet and his fellow developers can push to the experimental branch (but cannot create tags).

The second option is probably badly named. It looks for a file called branch_tracking in the root of the bare repo. That file looks like this:

refs/heads/experimental refs/heads/development

When hooks.forcebranchtracking is set, the hook will enforce that the branch on the left contain all the commits from the branch on the right before it will accept any updates. Essentially this forces the experimental branch to track the development branch, and requires
regular runs of git pull to stay in sync.

2010/05/07

Good for a laugh

Filed under: Around The Web — Tags: — plathrop @ 2:06 pm

This totally cracks me up.

2010/05/03

Debian Packaging Puppet Manifests

Filed under: Puppet — Tags: , , — plathrop @ 5:57 pm

With the (new?) ability for Puppet to have multiple module_dirs, the idea occurred to me: why not package a module as a Debian package?

The packaging process was relatively easy. Check out the results on GitHub.

Enjoy!

Powered by WordPress