For (almost) as long as we’ve had a pupet installation at work, we’ve had it in Subversion to track changes. This has changed/evolved a few times, but has always remained in subversion in one way or another. Recently we starting tracking other bits (documentation, scripts, etc) in git, and the idea of being on 2 different revision systems didn’t really sit well with me. Most of the team has taken up git very well, so the choice was made to move our puppet manifests etc to git. Once i started loking into it, also found the very cool “Dynamic Environments w/ git branches” trick, talked about here and here, and thought the move to git would be the perfect time to move to this.
I’m going to skip the testing/waiting I had to do (making sure our git server and puppet amster could talk ssh to each other, setting up the ssh keys for git to use to push and puppet to pull, etc), and jump right into the implementation and transition, which took about 15 minutes total yesterday.
So, first, To get the lions share of the data shifting done, I used svn2git to get the svnrepo sync’d to a git repo. our svn repo, while it used to have a few branches, prior to this had been compacted to just a trunk (which wasn’t called “trunk”) and no tags etc. So, I ran:
$> svn2git --username matt --nobranches --notags --rootistrunk -v https://puppet.server/svn/puppet/
And let that chug along for a while.
Once that was done I could add the remote git server as an origin:
$> git remote add origin git@git.server:puppet.git
$> git push
Now, the puppet svn repo is in git and on the git server. I had to sync a few times due to some quick changes going into the svn repo, so that was a simple
$> svn2git --rebase
$> git push
Okay, finally it was go time. Step 1, make the svn repo readonly. How? Thisis served with apache, so, a simple pre-commit hook did the job:
#!/bin/sh
echo "This svn repo is now read-only! No Commits accepted!"
exit 1
See what I did there? The pre-commit never DOES anything with the commit, so the commit is never acepted by the svnserver!
Okay, on to the transition. On our puppet master, everything lived in /etc/puppet which was an svn repo. Lets stop the puppet master for a moment (clients will go about their merry way) move that aside, and setup the new location:
$>service httpd stop (we run puppet via passenger)
$>cd /etc
$>mv puppet puppet.svn.backup
$>mkdir -p puppet/environments
$>chown -R puppet:apache puppet
$>chmod -R g+w puppet
Okay. Now, lets get into the weeds for a second here. So, using the dynamic environments, our git server will, with a post-receive hook I’ll show in a second, ssh to our puppet master, and checkout the branch (master or otherwise) to /etc/puppet/environments/$BRANCH. Now, we tend to use “master” for most of our small edits (adding a node, etc), so “master” => “production”. I didn’t want a puppet environment called “master”, so a tiny bit extra logic was added to the post-receive to change the location of the branch checkout to “production” if the master branch was change, but otherwise use the branchname, such as “matts_new_feature”. Okay here is the post-receive:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
This, paired with a nice pre-receive server side syntax check, and we’re looking pretty good and automatic (I’ll share that in another post) Okay, so thats in place. Now, svn2git works great, btu i want to use a clean, clean git-only checkout of the new puppet repo to finish this off with, so, on my local system:
$> mv puppet puppet.svn-git
$> git clone git@git.server:puppet.git puppet.git
$> cd puppet.git
$> vi puppet.conf
Now, in puppet.conf, I setup the dynamic environments:
environment = production
manifest = $confdir/environments/$environment/manifests/site.pp
modulepath = $confdir/environments/$environment/modules
Now lets commit/push:
$> gits
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: puppet.conf
#
no changes added to commit (use "git add" and/or "git commit -a")
$> git commit -a
[master d846620] change to puppet.conf for the environments change
1 files changed, 7 insertions(+), 7 deletions(-)
$> git push
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 383 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Updating remote branch /etc/puppet/environments/production
remote: Cloning into production...
To git@git.server:puppet.git
73f5405..d846620 master -> master
Ta Da! Now, lets look on the puppet master:
$>pwd
/etc/puppet/
$>ls environments
production
So, its there, lets start puppet back up:
$>service httpd start
Get on a client of two, run puppet agent -t, all is well, and its great success! This litterally (of course, with testing, setting up keys, etc out o the way) took about 15 minutes yesterday. Nothing like pulling the rug out from under 1800+ systems/14000 cores and putting it back without them noticing!
Now, the really cool part is:
$>git checkout -b matts_test
$>vim somefiles.pp
$>git commit -a
$>git push
Will make a new branch/environment in /etc/puppet/environments/matts_test, which clients can use like puppet agent -t --environment=matts_test! Want it to go away after changes have merged? Simple!
$> git checkout master
$> git merge matts_test
$> git push origin :matts_test
$> git branch -d matts_test
$> git push
Ta da! The branch/environment is no longer valid, and as been removed form /etc/puppet/environments/!