Distributed Cfengine
Pages: 1, 2, 3
Actually Doing Something
Whew! Now we should be successfully distributing our empty
cfagent.conf
, so we can move on to doing something within this
configuration. Remember that the update.conf
file is purely for
updating the cfengine configuration, so we must start within
cfagent.conf
for anything else.
We've already added our sudo.cf
file to CVS, so now let's import that file into our configuration:
# cfagent.conf
groups:
# the name of our server is 'server'
cfengine_server = ( server )
control:
domain = ( ExecResult(/bin/domainname) )
workdir = ( /var/cfengine )
configroot = ( /cfengine )
server = ( server.domain.com )
import:
cfengine_server::
cvs.cf
any::
sudo.cf
Hmmm, that's annoying, we seem to have duplicate definitions of variables
here. update.conf
is completely separate from the rest of the
cfengine configuration. This is intentional; if you break any other aspect of
your cfengine configuration, you can fix it by updating from the central copy,
but if you break update.conf
, you've broken the update process
itself. Keep this file as simple as possible; all information collected in
this file is expunged before the normal configuration is executed. You may not
consider this a feature, but the author of cfengine certainly does.
When this script runs on the cfengine server, it imports two files. For the
clients all we do initially is import our sudo
configuration. We
need to modify our sudo.cf
file to make it copy the
sudoers
file from the central server, rather than just enforcing
permissions. This is the whole purpose of our article.
# sudo.cf
control:
actionsequence = ( files copy )
files:
/usr/local/bin/sudo owner=root group=root mode=4111
checksum=md5 action=fixall
copy:
${configroot}/config/sudo/sudoers dest=/etc/sudoers
server=${server}
owner=root
group=root
mode=0440
This is almost exactly the sudo.cf
file we built in the first
article in this series, but our files
action has become a
copy
action. Now instead of verifying only the permissions of the
sudoers
file, we're updating it from a central, version-controlled
location. This is not much different, but is much more functional (and
requires just a bit more setup) than our original version. We still
verify permissions on both the binary and the configuration file, but we now
have the ability to commit modifications to our sudoers
file into
CVS and have those changes distributed to all of our clients.
Note that you can also configure CVS to verify the syntax of the
sudoers
file so that you never accidentally distribute an invalid
file. This is done entirely within CVS, though, so it's left as an exercise
for the reader. You could also use the above script to distribute the
sudo
binary itself, but the assumption here is that you've already
installed the package when the system was built. Copying binaries quickly gets
complicated if you're dealing with multiple platforms.
Updating CVS
Now that we have our complete sudo
configuration and we are
successfully updating it from the checked out copy on the server, it's time to
see how the server gets the most recent version of the file. As your
configurations get more complicated, this simple setup will likely not suffice,
but this works well for getting started:
# cvs.cf
control:
actionsequence = ( shellcommands )
shellcommands:
"/bin/sh -c 'cd /cfengine; cvs update -d >/dev/null 2>/dev/null'"
This file, imported by the cfengine server from within
cfagent.conf
, introduces the shellcommands
action.
As you can see, this is a very simple action. There are some other options you
can use, but this is how shellcommands
instances usually look.
Notice that we had to use an explicit subshell to use cd
; when
cfengine runs a shell for you, it never interprets shell metacharacters, so if
you want the shell to interpret characters such as >
,
;
, or |
, you have to launch a subshell explicitly, as
above.
Figure 1 shows how data travels from your CVS sandbox to remote servers. Assuming that cfengine runs every 30 minutes, the potential delays mean that it can take up to 90 minutes for a CVS change to propagate completely.
Figure 1. How data travels from your CVS sandbox to remote servers.
This is a simple method of having cfengine use cvs
to update
its files. A more sophisticated and less error prone form of this would use a
cfengine module that did error checking. As this stands, any errors go to
/dev/null
(because cvs
produces output on
STDOUT
and STDERR
) which means you are not likely to
notice a problem quickly. If you did not redirect the output of
cvs
here, you would get an email every time cfengine ran, which
would quickly cause you to ignore all cfengine emails.
Finishing Touches
While that may have seemed like a lot of work, we now have a solid
groundwork for using cfengine as the automation harness for the rest of our
network tasks. It's now as simple as modifying files and committing them to
CVS. Cfengine might not be able to do everything we need it to, but it can at
least function as the logic and initiation engine for most everything else. If
you have recreated this configuration on your own site, you should now be able
to use cfengine to distribute newly committed versions of the
sudoers
file and to verify that sudo
is always set up
correctly. All you need to do for this to work all the time is add a cron job
to execute it periodically.
Although cfengine is perfectly capable of adding that cron job for you,
there are some subtle and complicated issues in doing so, which makes it the
perfect topic for the next article in this series. Next time we'll cover
inline editing of files using cfengine and how to monitor and restart processes
based on changes that cfengine makes. We'll also introduce the use of
cfexecd
to wrap our call to cfagent
in order to get
some handling of cfagent
output. In the meantime, you can find these examples
in CVS at cvs.madstop.com, and you can find multiple examples on how to add a cron job using cfengine at the Cfengine Homepage.
Luke A. Kanies is an independent consultant and researcher specializing in Unix automation and configuration management.
Return to ONLamp.com.
