Big Bubbles (no troubles)

What sucks, who sucks and you suck

Automated Software Update With Cfengine

Here’s a Cfengine module written in Perl called module:tools, that creates a Cfengine policy file for updating software packages. If you’ve been wondering how to do this, it may point you in the right direction. Read on for the gory details and the necessary glue.

This module assumes that you’ve adopted a sensible system for the installation of third party open source utilities, something like the software depot described by Limoncelli and Hogan. I.e. Each package in its own self-contained, versioned directory, with the components symlinked into common directories for PATHs, etc. So OpenSSH might be in /tools/openssh-4.0p1, which contains bin, lib, man and so forth, and the contents of those directories are symlinked under /tools/bin, /tools/man, etc.

The module takes a colon-separated list of package directories as an argument (to work around argument limits in Cfengine), and generates a Cfengine rules file that can be imported into your existing policy. The rules specify how to update the package files from a master server and create the necessary symlinks. There are also rules to simply check that the listed packages are installed and generate warnings if any are not found. Define the Check and/or Update classes to decide what actions are taken.

Here are the Cfengine rules to incorporate the module and rule file:

control:
    AllowRedefinitionOf = ( tools )
    workdir = ( /var/cfengine )
    moduledirectory = ( $(workdir)/modules )
    pkginstall = ( $(workdir)/inputs/cf.pkgsinstall )
    depot = ( /tools )    # location for all s/w
    mainserver = ( fileserver )    # master software server
classes:
    PolicyServer = ( name of Cfengine master policy host )
    Hr00::
        Check = ( any )    # check packages on all hosts daily
    Sunday.Hr00::
        Update = ( hosts to update weekly )
    !PolicyServer::
        pkgcfexists = ( IsPlain($\{pkginstall\}) )    # exclude policy server
import:
    (Check|Update).pkgcfexists::
        $(pkginstall)
control:
    # define package lists for each group of hosts
    any::
        tools = ( "openssh-4.0p1:openssl-0.9.7e:grep-2.4.2" )    # common
    internal::
        tools = ( "$(tools):samba-3.4" )
    development::
        tools = ( "$(tools):gcc-3.4:make-3.79" )
    # create toolsinstall rules
    (Check|Update).!PolicyServer::
        actionsequence = ( "module:tools $(tools)" )

Hints

  • The generated rules assume the use of Graft to manage the symbolic links. You can replace this with another system, such as GNU Stow, or even some suitable Cfengine link actions.
  • If Cfengine, Perl and Graft are among the packages managed by these rules, then clearly you will have a bootstrap issue to resolve!
  • Edit the module, enable $DEBUG and run it manually from the command line with a short list of packages to see the resulting rules file (cf.test):
    $ env CFINPUTS=. ./module:tools foo-1.3:bar-2.1.10:snarf-6.4a
  • Edit the text of the rules in the module (added to the $output string) to adapt the generated rules for your own needs.
  • Begin by running the module with one or two non-essential packages against a single test host. You could also add action=warn to the generated rules to see what would occur without any changes being made. It is extremely important to test this module carefully before widespread deployment. As usual, if it breaks you get to keep the pieces (but please tell me about it).
  • Note that the pkginstall rules file must not be created on the policy server itself, otherwise it will overwrite the locally generated versions on each Cfengine client during the policy update. This file should be unique to each host.
  • You can create package-specific rule files under a tools/ subdirectory of your Cfengine inputs directory. The module automatically checks for these and adds the appropriate import line to the rules if found. E.g. For restarting daemons.

The Practice of System and Network Administration, Thomas A. Limoncelli and Christine Hogan.

This module and technique was based on work by Luke Kanies, which is gratefully acknowledged.