Posts Tagged ‘facter’

Facter facts for PCI devices

Friday, June 17th, 2011

We are in the process of building the configuration for our monitoring system from exported resources (more on that in the future). To accomplish one of the checks we needed a way to identify the brand of RAID controller in our physical servers. The best way to do this is facter.

We’ve written some custom facts before, but never facts for hardware. We could have taken the lazy route and use lspci -m | awk -F '" "' '/RAID/ { print $2 }'. But maybe we need more hardware facts in the future. So we built a script that parses the output of lspci -vmmk and builds a multidimensional hash for it.

We then iterate over the hash and add facts for every RAID controller we find. Because we have a hash of all the data from lspci, we can add facts for every type of controller on the PCI bus by adding a regex, a counter (there may be more than one controller of a certain type) and a factname (with embedded counter).

We are releasing this script in the hope that it will be useful to somebody. Installation is breeze: Just add pci_devices.rb to your puppet module in module_name/lib/facter and start using it.

The code is on github. If you have any improvements or questions, send us a pull request or a ticket.

Facter facts for memory in bytes

Tuesday, March 22nd, 2011

By default Facter returns the free and total memory and swap of a machine only in GB or MB:
facter | egrep “mem|swap”
memoryfree => 8.95 GB
memorysize => 11.76 GB
swapfree => 972.68 MB
swapsize => 972.68 MB

As we wanted to let the buffer pool size and cache size of a mysql server depend dynamically on the available memory this information wasn’t enough. To remedy this we rewrote the memory.rb bundled with Puppet to return the numbers in bytes. This file can be put in /lib/facter/ in any module. The new output looks like:
sudo facter –puppet | grep inbytes
memoryfreeinbytes => 9608507392
memorysizeinbytes => 12631347200
swapfreeinbytes => 1019924480
swapsizeinbytes => 1019924480

These new facts can be used in a Puppet template as follows:
key_buffer_size = 64M
innodb_buffer_pool_size = <%= “%.0f” % [memorysizeinbytes.to_f / 2] %>
query_cache_size = <%= “%.0f” % [memorysizeinbytes.to_f / 8] %>

The files:

Puppet Tips&Tricks: Variable variables

Wednesday, September 1st, 2010

Sometimes you want to use variable variables, for instance when you want to iterate over all the ipaddress_* facts that facter found. Using something like ${ipaddress_$if} doesn’t work, though. Inline_template to the rescue! Thanks to Volcane on IRC, this is a possible solution:

$ifs = split($interfaces,",")

define do_this {
	$mule = "ipaddress_${name}"
	$donkey = inline_template("<%= scope.lookupvar(mule) %>")

	notify { "Found interface $donkey":; }

do_this { $ifs:; }

This will output:

$ sudo puppet net.pp 
notice: Found interface
notice: //Do_this[eth0]/Notify[Found interface]/message: defined 'message' as 'Found interface'
notice: Found interface
notice: //Do_this[eth1]/Notify[Found interface]/message: defined 'message' as 'Found interface'

Puppet Tips&Tricks: Getting the version from a package

Monday, March 1st, 2010

Sometimes you need to know the version of a package before you can do anything useful. For example, we need to make sure the augeas-lenses package is 0.6.0 or newer, otherwise it doesn’t include the aptpreferences lens. We need that lens to modify /etc/apt/preferences in a nice way.

It would be very nice if there was some sort of function that could check on the client which version a certain package was, but during the design of puppet it was decided that puppet is not allowed to execute functions on a client, all functions are executed on the puppetmaster. So that’s not a valid option.

Another solution would be to create puppet facts for every package installed containing their version. Although that would help, it would clutter the facts a bit and probably make each puppetd run quite a bit longer. Also, all those facts would have to be stored in the database, if you’re using storeconfigs, which would add a lot of useless data there (although I can imagine setups which would actually appreciate this). So I chose for a simpler way, creating a fact specifically for augeas-lenses.

Getting the version from the commandline is easy on Debian, simply execute dpkg-query -W -f='${Version}' augeas-lenses. Creating a fact from that, is in its turn easy too:

if  FileTest.exists?("/usr/bin/dpkg-query")
	Facter.add("augeas_version") do
		setcode do
			%x{/usr/bin/dpkg-query -W -f='${Version}' augeas-lenses}

I created a file in our common module, lib/facter/augeas_version.rb, since that module is included on every host and the fact isn’t specific for a certain module. Preferably, you should add the fact to the module which uses it, of course, to keep things separated.

Now I can simply do:

# We need to compare the current augeas version, to see if we have the
# aptpreferences lens available. It's only been included since 0.6.0.
if versioncmp($augeas_version, '0.6.0') < 0 {
  # Work with templates and concatenated files
  notify { "Using concatenated files, augeas-lenses version $augeas_version":; }
} else {
  # Work with augeas
  notify { "Using augeas, augeas-lenses version $augeas_version":; }

Awesome puppet! Hope this helps someone.