Test Driven Deployment – mcollective, puppet, cucumber
With the release of mcollective recently I've been able to work a bit on a deploy problem I've had at a client, I was able to build up the following by combining mcollective, cucumber and the open source mcollective plugins.
The cucumber exploring is of course a result of @auxesis's brilliant cucumber talk at Devops Days recently.
Note: I've updated this from the initial posting, showing how I do filtering with mcollective discovery and put it all into one scenario.
Feature: Update the production systems Background: Given the load balancer has ip address 192.168.1.1 And I want to update hosts with class roles::dev_server And I want to update hosts with fact country=de And I want to pre-discover how many hosts to update Scenario: Update the website When I block the load balancer Then traffic from the load balancer should be blocked When I update the package mywebapp Then the package version for mywebapp should be 4.2.6-3.el5 When I unblock the load balancer Then traffic from the load balancer should be unblocked
This is completely like any other test driven scenario based system, if it fails to block the firewall deploy will bail out. If it fails to update the package it will bail and finally only if those worked will it unblock the firewall.
Thanks to mcollective this is distributed and parallel over large numbers of machines. I can also apply filters to update just certain clusters using mcollective's discovery features.
Everything's outcome is tested and cucumber will only show the all clear when everything worked on all machines in a consistent way.
This is made possible in part because the mcollective plugins use the Puppet providers underneath the hood, so package and service actions are complete idempotent and repeatable, I can rerun this script 100 times and it will do the same thing.
I have other steps not included here to keep things simple but in a real world I would restart the webserver after the update and I would then call NRPE plugins on all the nodes to make sure their load average is in acceptable ranges before the firewall gets opened letting the load balancer in.
This opens up a whole lot of interesting ideas, kudos to @auxesis and his great talk at devopsdays!


November 6th, 2009 - 21:22
This is really cool. So when you run the feature, do you expect each scenario to execute one after another, or would you call a specific scenario from the command line?
Excellent work! I’m really digging the mcollective stuff by the way.
November 6th, 2009 - 21:46
The idea here is top down, with bail out if any step fails, that works well for deploys. Bonus that I can just rerun it top down too cos even my iptables stuff can just be rerun many times with no ill effect.
Cucumber though might not really be the best fit, I don’t like the data redundancy between Scenarios need to spend more time with its docs but another testing framework might be needed. Also of course cucumber scenarios are stand-alone, I need to either build out a huge nasty scenario or find a way to have the previous one bail out the next. Lots of time wit the docs needed.
The real win for me is that I have improved all the various mcollective bits to return true/false or to be able to request their status. This is critical for building actual deploy systems with it. When cucumber says blocking the ip worked I now know it worked without a doubt on every webserver mcollective found.
I think using test frameworks for this is probably a sane idea, I just need the right one
The above scenarios:
3 scenarios (3 passed)
8 steps (8 passed)
0m14.519s
I can speed that up a lot by removing some redundant discoveries. But for that I need a global counter of how many hosts are found in the initial discovery, hard with cucumber.
November 6th, 2009 - 23:10
I’ve learned a few new tricks with Cucumber and have reworked the code a bit, I now discover once and use the discovered count through out.
Also check out the ‘Background’ feature if you want to avoid duplicating data, this wold have helped in our devopsdays session.
With pre-discovery this finishes in:
1 scenario (1 passed)
9 steps (9 passed)
0m8.771s