My cfengine policies explained – part 3

One good thing in cfengine 3 is the enhanced ability to create reusable snippets of code containing promises (bundles) or parameters (bodies); plus, you can make them parametric for added flexibility. The cfengine standard library, also known as Community Open Promise Body Library (COPBL), is a comprehensive collection of reusable bodies and bundles that can simplify the task of writing policies. However, although comprehensive, it can't fit all possible needs. But there is good news: you can write your own libraries, too, with either completely new bodies/bundles, or by modifying those already available in the standard library!

As promised, we are about to see a library called opera-lib.cf that complements the standard library, addressing needs specific to our installation. It's quite small however, which is a a further demonstration that the standard library covers almost everything.

Rather than listing the whole file, we'll either examine each the library's body/bundle separately, or in small groups. … Continue reading

Know your tools: adjtimex

Cosimo was one of the speakers at Velocity Europe 2012 last week. He gave a nice talk, and he even dared to show my face in his presentation (slide 32 if you're curious).

However, what caught my attention was the very next slide, where it was evident that he was blindly installing adjtimex on all his puppet-managed nodes. I warned him that it could be a bad idea, and he seemed to be quite surprised. Sadly, I was proved to be correct just a few hours later: they had an handful of virtual machines whose clocks were going crazy in all possible ways, and the root cause was tracked down to be the installation of the adjtimex package.

But let's take a step back: what is adjtimex, and why it can switch from a useful tool to an evil rapist of system clocks?
Continue reading

How to be a timelord, or rather not

I think it's quite ironic that someone considers me an NTP guru. Because I am not. I am just a sysadmin who, once upon a time, had an NTP service to rebuild and wanted to get it right.

What happened then is: instead of doing what a bunch of the sysadmins out there did and still do (use the default configurations of the OS, or trust one of the misleading sources you can find with google), I downloaded the RFC and read most of it. And then, I downloaded the (then) two Sun blueprints about NTP and read them too. Only when I understood how a good architecture ought to be, I started with the design and the implementation.

I must say that I didn't get the architecture right the first time, but at least I learnt what was wrong with it. I kept studying on the subject, doing experiments, and discussing with people who had a much better understanding of the internals (how ntpd really works) and… externals 🙂 (all the electronics engineering theory behind the algorithms used in ntpd). And I ended up building a (hopefully) decent NTP infrastructure for all the employers I worked for.

As you see, I am just a person who tackled a problem more seriously than the average. That was enough to stand out compared to "the mass" and make me look like a guru… not being it!

When Cosimo asked for a photo of mine for his talk at Velocity Europe 2012, and he was going to talk about last July's leapocalypse, I spent one hour with my wife to get some nice photos with the right amount of irony in them. In the end, we selected two photos and sent them to Cosimo.

Of course, Cosimo chose for his presentation the one I liked less, that's why I'm doing justice to my favourite by publishing it here:


If there is as much irony as clocks in the photos, the goal is achieved 😉

My cfengine policies explained – part 1

As announced on twitter, my cfengine policies are now in production. It's a few dozen servers, so not a big installation, but it saved me a lot of headache already. I thought it would be nice to give back to the community some of the help I got from it, so I'll publish and comment some of the code here. Some of the policies, I'll show in whole; others, I'll have to cut and obfuscate things here and there; there are also a few I cannot publish, sorry about that.

Some may think: why I didn't put this stuff in the design center? Well, some of them are rather rough and not really ready for the prime time. I'll do that eventually, when I feel they're nice enough.

But before we start, let me make a quick note about the design.

I massively took advantage of the "methods" promises, which provided me some interesting features.

First and foremost: they allow me to organise my policies in "layers":

  • promises.cf, the topmost set of promises, is just a collection of generic requests to the agent: print this, check that, configure here, install there…
  • one level down, you have more specific bundles which, in turn, may either perform an action, or be another level of abstraction, with specific actions bundled into other method calls
  • at the low level, you only have those bundles that actually perform actions on the system

Besides:

  • specific functionalities are encapsulated in small, reusable bundles, possibly parametric bundles
  • each layer offers a different level of complexity: the higher layers are the simpler ones, and don't require a lot of cfengine knowledge to be written; every time you go down one level, you get closer to the actions performed directly on the system
  • it should be easier to distribute the task of writing a policy across people with different levels of knowledge (if I am not left alone in this effort 🙂
  • enforcing a specific order to the actions you want to perform is much easier if you encapsulate related actions in separate bundles, and then you invoke them sequentially; the order of execution is not always important, but when it is, it's nice to be able to enforce it.

Enough talk, let's roll! … Continue reading

It just needs an OFFSET

Running through numbers in a spreadsheet again, and a problem to solve with it.

Suppose you have a set of measurements for several days, one per hour. That means 24 samples per day (guessed that?): so far, so good.

Getting the maximum for each day is not difficult either. For example, one could select the cell at the right of the first sample, say D2, and input something like "=MAX(C2:C25)" to get the maximum for the first day of data. That's simple, too. And if one wants to do that for each day, he can select the cells D2:D25, and paste them down from cell D26 on.

Now, and that was my problem, what if you want to make a new sheet where, in a column, you have only those maximums, one after the other? Of course, you could just make, say, cell B2 as "=D2", cell B3 as "=D26" and so forth, but that's not quite practical. I needed a way to make the row number after D parametric, so that I could say that B(i)=D(24*(i-2)+2) — just try with a few values for i, and you'll see it works. Getting the right value for that "i" is easy, there's the ROW function for that, but… how can one use it as "the row number after D"?

Well, after some research, I found out that there is a way, and it's a function called "OFFSET":

Returns the value of a cell offset by a certain number of rows and columns from a given reference point.
Syntax

OFFSET(Reference; Rows; Columns; Height; Width)

So, to make B2=D2, B3=D26 and so forth? Just use "=OFFSET($D$2;(24*(ROW()-2));0)", and then drag it down to the desired cell. Done!

Enjoy!

Dates from UNIX timestamps in OpenOffice/LibreOffice

This is not something I discovered myself, rather it's something that I'll need every now and then when doing extemporary reports of UNIX-timestamped data. The problem is: you have a time series of data in a spreadsheet, and the time is expressed as UNIX timestamps (seconds since the epoch, 1970-01-01 00:00:00 UTC, and not taking into account leap seconds): how can you convert those timestamps in a readable date like, e.g., "01/07/2012 01:00:00"?Continue reading

Turning the wireless ESSID into a class

I think it could be handy to have a class in cfengine that tells us something about the ESSID of the wireless network we are connected to. Unfortunately, cfengine doesn't define one by default, and I thought it could be a good idea to make a module for that. It has been buzzing in my head for a while, and tonight I took some 30 minutes to make it happen.

On Linux, we have the command iwgetid that tells us the ESSID of the wireless networks we are connected to. However, ESSIDs may contain characters that are not allowed in a class name, so we need to "escape" them. The following, tiny bash script reads the output of iwgetid and returns the corresponding class names to be defined:

#!/bin/bash

PATH="/sbin:/usr/sbin:/usr/bin:/bin"

for ESSID in $( iwgetid --raw )
do
  CESSID=$( echo $ESSID | tr -c "a-zA-Z0-9_" "_" | sed -e 's/_*$//' )
  CLASS="essid_${CESSID}"

  echo "+${CLASS}"
done

exit 0

On the laptop I am currently using, it returns:

root@cooper:/var/cfengine/inputs# modules/essid.sh 
+essid_WiFiOslo

And here it is! When we use this script as a module in cfengine, it will define a class named essid_WiFiOslo.

For more information about cfengine's module protocol, see the reference.

When “bulk” is just too much…

Managing software packages with cfengine is, normally, no problem: you have "packages" promises, and you have pre-canned bodies for a number of package managers, plus the ubiquitous "generic" that should help you on almost all systems where cfengine can run. However, I hit one of those corner cases where you have to build your own package_method body — although stealing almost everything from one in the standard library 😉 … Continue reading