Making cfengine cooperate with boottime service scripts

How do you make cfengine ensure the correct services are running on your system? Now how do you make sure the scripts run at boot time know that too? Jamie Wilkinson shows you a nifty trick to ensure that the operating system knows what cfengine knows.

In the last article on cfengine I described a short program that could be used on a machine that needed SSH running on it.

That program was somewhat limited in its use -- while it would have ensured the service got restarted on the machine, it's only going to do that every time cfengine runs, which at Anchor means once every half hour. That in itself doesn't seem like a problem, but take into consideration the following gem: Package installation on Red Hat doesn't necessarily mean that the service will be running; the chkconfig tool enables and disables services. If the machine is rebooted, and SSH is not configured to start at boot time (which may be slightly contrived, but this applies equally to PostgreSQL or Apache) then there is a period of up to half an hour in which the service may be down, which is not cool.

The trick then is to have cfengine instruct the operating system to start up the services that need to be started at boot time. On Red Hat, that's done with the chkconfig tool.

cfengine has a section shellcommands for running external commands, possibly acting on the results of those commands. We can leverage that to synergise cfengine's notion of the ideal server with the operating system's scripts like so:

The processes section is fairly straightforward:

processes:

    sshd_server::

      "sshd" restart "/sbin/service sshd restart"
        elsedefine=sshd_chkconfig

The elsedefine defines a class if no sshd was found running. In shellcommands, we can write a few commands to complement this processes block:

shellcommands:

    sshd_chkconfig.redhat::
      "/sbin/chkconfig sshd on" useshell=false

So if sshd wasn't running, then we'll restart it, and then tell Red Hat to make sure it will be next time the machine reboots.

Additionally, we can query chkconfig directly:

shellcommands:

    sshd_server.redhat::
        "/sbin/chkconfig --list sshd | grep 3:off" useshell=true
        inform=false
        define=sshd_chkconfig

The grep 3:off command just matches the output of chkconfig on that service; I'd suggest checking with a manual run of chkconfig --list to see what sort of output you should expect. Services that run from xinetd do not contain a runlevel in their chkconfig output, so you may wish to grep off instead.

inform=false just asks cfengine to ignore the output, because we're not terribly interested in the output of chkconfig every time cfengine runs.

useshell=true instructs cfengine that we're using some shell magic, in this case pipes, so it needs to launch a shell to execute the command. Normally cfengine will attempt to run the command directly to protect against potential security risks from tainted environments.

We define the sshd_chkconfig if the command succeeded, i.e. grep found a match in the output. Then as above we'll run chkconfig and turn the service on.

The complete processes and shellcommands section for Debian and Red Hat systems looks like:

processes:

    sshd_server.redhat::

        "sshd"
            restart "/sbin/service sshd restart"
            elsedefine=sshd_chkconfig

    sshd_server.debian::

        "sshd"
            restart "/etc/init.d/sshd restart"

shellcommands:

    sshd_restart.debian::

        # debian's init script doesn't set PATH, so use a shell
        "/etc/init.d/ssh restart" useshell=dumb

    sshd_restart.redhat::

        "/etc/init.d/sshd restart" useshell=false

    sshd_server.redhat::

        "/sbin/chkconfig --list sshd | grep 3:off"
            useshell=false
            inform=false

    sshd_chkconfig.redhat::

        "/sbin/chkconfig sshd on"
            useshell=false

Finally, we need to add shellcommands to the actionsequence in main.cf:

    actionsequence = (
        files
        processes
        shellcommands
    )

Keywords : cfengine examples processes chkconfig service daemon Author : Jamie Wilkinson

Related links