CFEngine on Mac OS X

Mac OS X Classes | System Configuration | Mixed directories under /Users. | Automatic Updates

Tips and pointers for using CFEngine on Mac OS X. The following subsections cover details of CFEngine particular to major Apple releases, and issues with compiling CFEngine manually.

Mac OS X Classes

CFEngine sets a darwin class, but nothing to distinguish Mac OS X 10.2 from 10.3, nor Mac OS X from Darwin. Maintaining a source code patch to do so would be complex and time consuming; the following shows initial work on identifying the operating systems apart.

groups:
darwin::
macosx = ( FileExists(/System/Library/CoreServices/Finder) )

# TODO pipes not supported, so would need wrapper scripts or other
# means of distinguishing 10.x apart
#macosx_10_2 = ( "/usr/bin/sw_vers | fgrep 10.2" )
#macosx_10_3 = ( "/usr/bin/sw_vers | fgrep 10.3" )

# KLUGE 10.3 first with Postfix, 10.2 had Sendmail. Will need to
# reconsider what to do when 10.4 comes out.
macosx_10_2 = ( FileExists(/System/Library/StartupItems/Sendmail) )
macosx_10_3 = ( FileExists(/System/Library/StartupItems/Postfix) )

import:
macosx::
cf.macosx

System Configuration

Useful configuration commands include pmset, nvram, softwareupdate, and diskutil. Install the Apple Remote Desktop Client software to gain access to the systemsetup and networksetup commands.

control:
ard_dir = ( /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Support )

links:
macosx_10_2::
/usr/sbin/networksetup ->! $(ard_dir)/networksetup-jaguar
/usr/sbin/systemsetup ->! $(ard_dir)/systemsetup-jaguar

macosx_10_3::
/usr/sbin/networksetup ->! $(ard_dir)/networksetup-panther
/usr/sbin/systemsetup ->! $(ard_dir)/systemsetup-panther

Mixed directories under /Users.

Another problem is dealing with user home directories; Apple uses /Users instead of the more common /home used on other systems. Also, Apple mixes /Users/Shared in with the other user home directories, which complicates matters, as all directories under /Users are not actually user directories.

The easiest way to deal with this would be to remove /Users/Shared, and recreate it elsewhere if required. Then, for cross platform needs, use a $localhome variable to track where the local system home directory is.

control:
darwin::
localhome = ( /Users )

openbsd::
localhome = ( /home )

tidy:
# r* services insecure, remove configuration for them
/etc pat=hosts.equiv age=0 r=1
$(localhome)/* pat=.rhosts age=0 r=1

Automatic Updates

Use the softwareupdate command to install updates from the command line. Be sure to set the COMMAND_LINE_INSTALL=1 environment variable to avoid any prompts during the run. Older Mac OS X systems (10.1 and below?) may not have the softwareupdate utility.

#!/bin/sh

export COMMAND_LINE_INSTALL=1

if [ -f /var/log/auto-update.log ]; then
/bin/mv -f /var/log/auto-update.log /var/log/auto-update.log.old
fi

(
/usr/sbin/softwareupdate --install --req
/usr/sbin/diskutil repairPermissions /
) >/var/log/auto-update.log 2>&1

if /usr/bin/grep -q restart /var/log/auto-update.log; then
/sbin/shutdown -r now restart required due to system update
fi

Updates could be installed automatically (via a shellcommands in CFEngine or a cron job), though ideally should be tested first on one or more test systems before general distribution. Automatic reboots may cause data loss, if a user with unsaved data is still logged in when the reboot occurs.

To allow non-administrator users to run updates, create a script with the above command, then allow access to it in the sudoers file. Either use visudo, or edit the sudoers file directly via CFEngine.

ALL ALL=NOPASSWD: /usr/local/sbin/run-sw-updates

Either have the users run the update from the command line, or create a wrapper that the users can click on to call the shell command in question:

-- save as AppleScript command via "Script Editor" application
on run
set theResult to display alert ¬
"Check for updates? This may require a reboot!" as warning ¬
buttons {"Cancel", "Restart"} ¬
giving up after 120

if button returned of theResult is "Restart" and ¬
gave up of theResult is false then

do shell script "/usr/bin/sudo /usr/local/sbin/run-sw-updates"

end if
end run