Sunday, May 24, 2009

Reusable cfengine; modularising cfengine policy files

Cfengine is a great installation, configuration and maintenance tool for running a fleet of machines. It allows you to easily create groups (classes) of machines via a number of methods, then associate actions with each of these classes, allowing fine grained control of each class of host.

However most howtos and examples of cfengine tend to skip over one of its most useful features; the import function. These examples tend to have all actions defined in a single file, which can get pretty unwieldy.

Once you have moved beyond simply installing a system with kickstart or debian preseed and want to move to completely setup a machine for a purpose, you tend to start to restructure your policy files, placing all the actions associated with one component in one area. These component setups often tend to be quite self contained, not interfering with the setup of the rest of the system. Moving the actions for this component into a single file and importing them makes for better readability in the main policy file, but also create an effective “policy module”. Further, if you attempt to use actions most likely to work across multiple OS versions, such as using package commands and API's wherever possible, you end up with reusable content come upgrade time.

Here is a quick example of how we have used this functionality...

cfagent.conf
classes:

ds = ( ags1 ags2 ags3 )
pe1950 = ( agc9 agc10 agc11 agc12 agc13 agc14 ds )
dellopenmanage = ( pe1950 )


cf.main
import:

dellopenmanage:: action/sl4/dell_openmanage.cf
dellopenmanage:: action/sl4/dell_openmanage_frontpanel.cf

This setup installs the Dell openmanage software, and sets the LCD frontpanel of the host to be: ATLAS: hostname

dell_openmanage.cf
copy:

# All yum repos MUST be firstpass for first time boot installation
# processes to work on the first run
firstpass::

any::
$(sl4_files)/dell_openmanage/dell.repo mode=0644 dest=/etc/yum.repos.d/dell.repo server=$(policyhost) type=sum

packages:

any::
srvadmin-all action=install

shellcommands:

any::

# Set disable the web admin service and the seemingly useless shrsvc
"/sbin/chkconfig --level 123456 dsm_om_connsvc off"
"/sbin/chkconfig --level 123456 dsm_om_shrsvc off"
# Enable the dataeng, this seems to actually do stuff
"/sbin/chkconfig --level 345 dataeng on"
# Start the dataeng or all omsa commands will fail
"/etc/init.d/dataeng start"


dell_openmanage_frontpanel.cf
shellcommands:

any::

# Set the frontpanel LCD to the hostname
"/usr/bin/omconfig chassis frontpanel lcdindex=1 config=custom text='ATLAS: $(host)'" umask=022


Using this kind of layout you can completely modularise your cfengine policies, and end up with a single core policy file which is readable. More importantly if you want to setup a new host class with a subset of the available actions you just add the modules you want to the class.