Automating Puppet at scale with Bolt and the node_manager module
As a systems engineer, I find that spending time automating a repetitive or annoying task is worth the time saved in the long run. Automation gives you and your team the ability to take on even bigger tasks and spend time developing in other areas.
Recently, I automated inducting new compile masters into our infrastructure using Bolt plans. To make this completely hands off I had to figure out a way to automate a part of the process which requires pinning these new compile masters to the PE – Master node group on the console. To find a tool that could accomplish this, I turned to the Forge (why reinvent the wheel?). This is where I discovered the node_manager module.
node_manager module interacts with the node classifier API. One of the things that attracted me to this module was the fact that it could list node group information, pin and unpin nodes from a group, show classification information. It was exactly what I was looking for! Now all I had to do was figure out a way to iterate the
puppet node_manager pin subcommand for every new compile master specified when kicking off the Bolt plan. For more information about the
puppet node_manager, either check out the module’s page on the Forge, or run
puppet man node_manager on applicable systems.
Utilizing Puppet language in Bolt
Originally, I was trying to pass each node as an argument to the command, each one separated by a single space. After I discovered that the node_manager module can only do one node per command, I turned to the #bolt channel in the Puppet community Slack, a great source of information on basic to advanced Bolt techniques. This is where I discovered iteration and heredocs in Puppet language.
Brief introduction to
Heredoc is basically a way of writing strings and text without having to escape characters. A basic example of heredoc use is this:
@() starts the heredoc tag, and
END ends it. Anything in between the tags is interpreted verbatim. To deal with two problems with heredoc, trailing new lines and text that appears indented, you can use
|- to trim the last new line, as well as define where the left margin is. The below example shows you how to do this:
Here’s a demonstration
In my plan, I specified
TargetSpec $nodes, which can either have targets fed to it via
bolt plan run <plan> nodes=<nodes>… or
bolt plan run <plan> --email@example.com … , @hosts.txt being a file with a list of FQDNs, one per line. I then create a variable,
$pins = $nodes.split(“\n”).join(“ “), which takes the arguments passed as nodes at the plan kickoff, and joins them together with only a single space separating each one. When it comes down to the part of the plan where I am pinning the nodes to the
PE – Master node group, this is where iteration comes in handy:
@(“CMD”) indicates the start of the text to have Puppet’s DSL read what comes after it, and
|-CMD matches the end of the heredoc tag that it is a part of, with
|- marking the left margin and trims the last new line. Basically, this block of code runs
puppet node_manager pin … on the server running the Puppet console, once for each node supplied to
TargetSpec , pinning each node given to the GroupID provided (the node_manager module can even get that ID for you, if you don’t want to go to the console to get the ID).
Blake Smreker is a Linux Engineer at Walmart responsible for maintaining the Puppet infrastructure. His daily duties include developing modules, getting new teams started with stateful management of their applications with Puppet, and automating support with Bolt.
Using Bolt plans, we were able to fully automate adding new compile masters to our Puppet infrastructure. Use these links to check out Bolt and the node_manager module on the Puppet Forge.