Select Page

What does Puppet manage on a node?

Last year I wrote a tool to parse the localconfig.yaml from Puppet 0.24 and display a list of resources and classes. This script failed when 0.25 came out, I’ve updated it for 0.25 support.

The yaml cache has some added features in 0.25 so now I can also show the list of tags on a node, output would be:

# parselocalconfig.rb /var/lib/puppet/client_yaml/catalog/fqdn.yaml
Classes included on this node:
        fqdn
        common::linux
        <snip>
 
Tags for this node:
        fqdn
        common::linux
        <snip>
 
Resources managed by puppet on this node:
        yumrepo{centos-base: }
                defined in common/modules/yum/manifests/init.pp:24
 
        file{/root/.ssh: }
                defined in common/modules/users/manifests/root.pp:20
 
        <snip>

You can get the script that supports both 0.24 and 0.25 here.

London Devops Night Venue Sponsor

Tomorrow is our first public London DevOps meetup, it’s looking like there will be a lot of people given the activity on Twitter, hopefully it will be a great night.

In the mean time The Guardian has offered us a regular venue at their big auditorium where the London Scale Camp was held. This is an excellent venue setup with projectors and everything. We could get it every month but I figured we’ll keep the talks bi-monthly and do drinks night or just something social on the other nights. There are several pubs around the Guardian so we’ll do drinks after the 1 or 2 talks a night.

The upcoming dates – excluding the pure pub nights are then:

02/03/2010 7pm โ€“ Agile Systems Administration at London Geek Nights โ€“ thanks to Thoughtworks
28/04/2010 7pm โ€“ Topic TBA โ€“ thanks to The Guardian for the venue
30/06/2010 7pm โ€“ Topic TBA โ€“ thanks to The Guardian for the venue
27/10/2010 6pm โ€“ Topic TBA โ€“ thanks to The Guardian for the venue
29/12/2010 6pm โ€“ Topic TBA โ€“ thanks to The Guardian for the venue

Put them in your calendars and again massive thanks to The Guardian for sponsoring us.

Building files from fragments with Puppet

While building up complex configs with Puppet you often need to build up one file from many fragments. This is useful for files like older sysctl.conf files and maybe named.conf files.

The basic pattern is you want to manage a file, but want the contents to be very different from node to node. A fragment based system lets you register different contents into a file on different nodes. It’s exactly like the conf.d directory you’d find in Apache but for daemons that does not support this construct on their own.

I’ve had an older version of this floating around but had to clean it up for a client today so thought I might as well do a proper job, release it and get some more eye balls on it. This version is specific to Puppet 0.25.x, I will soon make a >= 0.24.8 version too since that is what my client is on.

An example says more than words, so lets create something to manage sysctl.conf:

# Initial setup
class sysctl {
   include concat::setup
 
   exec{"reload-sysctl":
      refreshonly => true,
      command => "/sbin/sysctl -p"
   }
 
   concat{"/etc/sysctl.conf":
      notify => Exec["reload-sysctl"],
   }
}
 
# use this to set values
define sysctl::setting($value) {
   concat::fragment{"sysctl_${name}": 
      target => "/etc/sysctl.conf",
      content => "${name} = ${value}\n",
   }
}

The above sets up a class that will create an empty sysctl.conf and provides an utility for setting individual values. Whenever the sysctl.conf file gets changed the changes will be made live using the refreshonly exec.

Lets see how we might use it:

node "your.example.com" {
   include sysctl
 
   sysctl::setting{"net.ipv4.ip_forward":
      value => 1
   }
}

You can see this looks and feels a lot like a native type but without a lot of the hassle it would take to write one, you can really get a lot of mileage out of this pattern. The concat is clever enough to unregister the setting should you remove lines 4 to 6 in the above node block.

A cleaner approach would be to just make classes like sysctl::ipv4_forward that you can include on the nodes that need it.

You can grab the current code here.

Custom deployer using MCollective

One of the goals of building the SimpleRPC framework and the overall speed of MCollective is to create interactive tools to manage your infrastructure in a way that it all just seems like a single point of entry with one machine. I’ve blogged a bit about this before with how I manage Exim clusters.

I’ve recently built a deployer for a client that does some very specific things with their FastCGI, packages and monitoring in a way that is safe for developers to use. I’ve made a sanitized demo of it that you can see below. It’s sanitized in that the hostnames are replaced with hashes and some monitoring details removed but you’ll get the idea.

As usual it’s best to just look at the video on youtube in it’s HD mode.

Few Rubyisms

While looking at some bits of other peoples Ruby code I came across a few shortcuts and interesting structures worth mentioning.

Exception handling shortcut

First up a shortcut to catch exceptions thrown by a method:

def say_foo
   puts "foo" if doit
rescue Exception
   puts "#fail"
end

So since we didn’t define doit this will raise an exception, which will be handled. Nice shortcut to avoid an extra inner begin / rescue block.

sprintf equivelant

Ruby supports sprintf style string building in a handy little shortcut:

puts "%2.6f\n%d" % [1, 1]

This produces:

$ ruby test.rb
1.000000
1

Get a value from a hash with default for non existing

This is really nice, I’ve written way too many constructs like this:

foo.include?(:bar) ? bar = foo[:bar] : bar = "unknown"

One option that I was told about was this:

bar = foo[:bar] || "unknown"

But that does not work if you had false in the hash, or maybe even nil.

Turns out there’s an awesome shortcut for this:

bar = foo.fetch(:bar, "unknown")

Reloading a class

Sometimes you want to reload a class you previously loaded with require. I have the need in my plugin manager for mcollective. There’s a simple fix by simply using Kernel#load to load the .rb file, each time you load it the file will be reloaded from disk.

irb(main):001:0> load "test.rb"
=> true
irb(main):002:0> Foo.doit
foo
irb(main):003:0* load "test.rb"
=> true
irb(main):004:0> Foo.doit
foo foo

In between lines 2 and 3 I edited the file test.rb and just reloaded it, the changes on disk reflected in the current session. The main difference is that you need to supply the full file name and not just test like you would with require.