mCollective is a funny tool. The idea behind it is obvious and great: a message bus for node orchestration. But the API and underpinnings are often a black box for many Puppet noobs and even other automation professionals. They mostly stick to the Puppet Enterprise Live Management console to interact with the mCollective back-end, never
su peadmin and running a few
mco $some_application -F $some_fact.
The truth is, MCO is a powerful backend for orchestration. It gets a bad name because the performance isn’t there sometimes, especially at scale. Not to dive into a rabbit hole, but that’s often due to user error: 1 broker running over 1000’s of nodes; the ActiveMQ JVM being improperly tuned; bad layer 1 (yup, it can be that simple).
One thing about MCO that is true is the API is hard to get through. It makes sense once you get under the hood, and especially after reading through other agents and DDl’s but what if all you want is a simple way to run an arbitrary commandline argument on some remote node with MCO? If you don’t know what you’re doing that could take a while; if you know what you’re doing, you still have the write the code.
Well, since MCO runs through an API we can actually architect templates for this exact task, for both the data description language file and the agent ruby script.
Let’s start with a basic DDL that will inform an agent running this arbitary command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Just a quick shout out to Jeremy Adams who wrote this very ERB template for his Runyer module which does what this rake task does but in Puppet code.
So we’ve templated out the basic DDL for the agent. We’ve included some metadata and output - arbitary commands usually just need to be ran without input, for instance
df -h and returns the mounted volumes and data about them. That could be handy in orchestration. If we wanted to we could add some inputs here, for example, if we wanted to pass in an arbitrary input to a command. I’m not interested in that here, just basic output from a command.
Let’s build out the ruby script to run this command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Our arbitary command only has 1 action. It’s that simple. We run the command and push our output to the ouputs in the command.
Now let’s look at the Rakefile that actually runs this. For me, I store most of my Rakefiles as
~/.rake so I can run them anywhere with
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
As you can see, I wrote my Class into the Rakefile itself. It wasn’t long and let me have some clarity, so there wasn’t a need to break it out.
The McoAgent Class accepts two attributes, command and template. Pass it a command and a template, for me I have a couple of def’s that do this for the agent and ddl respectavely, and it builds out the ERB for us. My init def just declares the variables that we want available to our templates and we’re good to go - the rest is accomplished via the ERB library.
The entire project repo is available here