Spacer http://macenterprise.org MacResource.org - Mac OS X enterprise deployment project Spacer
Site Map Contact Us Top Background
 
Search
 
 
Rice University OS X Deployment E-mail
Written by Lance Ogletree   
Friday, 15 October 2004
What I've described in this guide is how we initially deployed and maintained OS X here at Rice University. Mac OS X Deployment at Rice University

I. Introduction

Beginning around the Fall of 2002 I began to work on our deployment plans for OS X to our public computing labs and our classroom technology podiums. The total number of machines that I was dealing with numbered around one hundred. The model of systems I had ranged from PowerMac G4 400mhz iMac G3 500mhz PowerMac G4 867mhz and 1.4ghz. All systems had a base ram of at least 640mb. My goal in working out the deployment plans for OS X not only included how to get the initial image out but once it was out how to maintain the system with as little interaction as possible. Coming from an OS 9 only background and very little unix knowledge I was accustomed to the ease of use offered by assimilator. My long-term goal was to be able to develop a similar setup for OS X. This was accomplished through the use of tools such as NetRestore Radmind iHook and both custom and borrowed perl and shell scripts. The following sections will go into more detail as to how I chose to deploy OS X.

A copy of this text along with the accompanying scripts can be found here: http://homepage.mac.com/lanceo/.Public/osx_deploymentRice_Univ.dmg

II. Initial Image

I won’t go into detail about NetRestore(http://www.bombich.com). It’s pretty straight forward. Nor will I go into detail about NetBoot since current documentation covers that fairly well. I used NetRestore to create my Netinstall image image for me. Why Netinstall? At the time under Jaguar NetBoot created temp shadow files on the local hard drive of the computer that was netbooted thus making it impossible to erase the drive. A Netinstall image didn’t have this restriction. Netrestore made it easy by creating the netinstall image that when netbooted from would automatically launch into NetRestore.
I setup NetRestore to run in automatic mode. It would erase the hard drive image the hard drive from another Xserve via http ( for load balancing) set the startup disk to the internal hard drive then reboot. My image that I used was created by disk copy at the time Jaguar OS X. During this process I had modified NetRestore to show a custom image. Credit goes out to the University of Utah team for providing me with the template for this image. It is also the image I use for other processes that will be described later on.

Once NetRestore had finished the computer would be rebooted. When the machine rebooted my startup scripts would then kick in and radmind along with iHook would be the next tools to be used in the imaging process. This step can also be done using firewire drives or bootable DVD’s.

III. Image Overview

To have a better understanding of my setup description I need to first describe some of the modifications I make to my image.
Log files –
All log files get stored in /private/var/log . I copy everything from /Library/Logs to /var/log and then delete the /Library/Logs directory.
I then create a symlink to /var/log
ln –s /private/var/log Logs
This way all newly created log files get stored in the proper location.
In /var/log I create two new directories called admin and radmind. The admin directory is a storage spot for log files for admin related tasks and the radmind directory s the storage spot for radmind related log files.
In the admin dir I create the following log files
admin_tasks.log
console_access.log

In the radmind dir. I create these log files. The radmind scripts from Univ. of Utah will look for these logfiles by default unless you change the names or comment them out.
I do recommend using the log files sice they are a good reference point as to when things go wrong.

fsdiff_output.T
ktcheck_output.log
lapply_output.log
radmind_error.log
radmind_log

When you go to view many of my scripts I use you’ll see these log files being referenced.

I created an Admin directory in /Library which I use to hold certain scripts or files which get called on during user logins.

I create a directory in /private/ called .scripts . This is where all my administrative scripts gets stored and called on by login/logout hooks or by cron.

The local admin account gets moved to /private/localadminaccount because I didn’t want anything being stored in /Users on the local machines. I also create within the local admin account a PreferencePanes directory in localadmin/Library/PreferencePanes/

I then move certain System PreferencePanes from /System/Library/PreferencePanes/ to this location/. The reason being is that the pref panes I move can only be used by a local admin so there’s no need for the user to even see them. When I log in as the local admin those prefs are available and end up being updated by system updates.

The pref panes I move are the following:

ARDPref.prefPane
Accounts.prefPane
Classic.prefPane
EnergySaver.prefPane
FruitMenu.prefPane
MyAccount.prefPane
Network.prefPane
ScreenSaver.prefPane
SharingPref.prefPane
SoftwareUpdate.prefPane
StartupDisk.prefPane

I create another account called radmind and move it’s home dir location to /private/radmind
I modify it’s netinfo entry and make it’s shell /dev/null
This is so a remote login via ssh would not be possible.
The use of this account will get described later during the Login/Logout section

I create a world writable directory /Temporary_Storage. Since our home directories are mounted via NFS and have a 100 mb quota I provided a temp storage location for students to use. This directory gets deleted every night via cron.

All of these modifications are apart of my base image that gets put down during the NetRestore process.
SSH remote login is turned on via the sharing pref. Pane and is made part of my base image.
The latest copy of the developer tools is also installed as part of my base image.

I also setup paswordless ssh host keys on the clients to allow me to connect from my Admin server to each of the client machines without entering an ssh password.

http://www.arches.uga.edu/~pkeck/ssh/

IV. The Update Process

The update process occurs in a couple of forms. One is right after a machine has been imaged with NetRestore the other is when it’s done either via cron executed by myself manually by logging in with the radmind account or by myself executing it remotely via ssh.
All but one of the forms the radmind account login make sure of a startup script looking for triggerfiles on the client machine to know what script to execute upon startup.

To understand how to create your own startup script here’s a couple of resources to look at.
http://www.macosxlabs.org

http://www.macosxlabs.org/tools_and_scripts/script_archive/script_archive.html#startup

http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/index.html?http/developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Tasks/CreatingStartupItems.html

For radmind and iHook resources:

http://rsug.itd.umich.edu/software/radmind/

http://rsug.itd.umich.edu/software/ihook/
iHook is a GUI front end for running scripts. It allows one to display custom messages/graphics while a script is executed.

Here’s a look at the startup script I use.

#!/usr/bin/perl

################################################################################
# startupScript
#
# This script launches a script if a file is present
#
# Copyright (c) 2002 University of Utah Student Computing Labs.
# All Rights Reserved.
#
# Permission to use copy modify and distribute this software and
# its documentation for any purpose and without fee is hereby granted
# provided that the above copyright notice appears in all copies and
# that both that copyright notice and this permission notice appear
# in supporting documentation and that the name of The University
# of Utah not be used in advertising or publicity pertaining to
# distribution of the software without specific written prior
# permission. This software is supplied as is without expressed or
# implied warranties of any kind.
#
################################################################################
$cron_force_run_file = "/private/.scripts/.writable/cron_runRM"
$force_run_file = "/private/.scripts/.writable/runRM"
$run_radmind = "/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/radmind_startup.
pl"
$cron_run_radmind = "/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/run_radmind
.pl"
$podium = "/private/.scripts/.writable/podium_notice"
$clean = "/private/.scripts/.writable/cleanme"
$p_cron_force_run_file = "/private/.scripts/.writable/p_cron_runRM"
$p_force_run_file = "/private/.scripts/.writable/p_runRM"
$p_run_radmind = "/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/p_radmind_star
tup.pl"
$p_cron_run_radmind = "/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/p_run_rad
mind.pl"

#
#
if ( -e $clean) {
system "/private/.scripts/admin_cleanup.sh"
}
if ( -e $podium) {
system "/bin/rm $podium"
}
if ( -e $force_run_file) {
system $run_radmind
unlink $force_run_file # remove just in case.
system "/sbin/reboot"
}
if ( -e $p_force_run_file) {
system $p_run_radmind
unlink $p_force_run_file # remove just in case.
system "/sbin/reboot"
}
if ( -e $cron_force_run_file) {
system $cron_run_radmind
unlink $cron_force_run_file
system "/sbin/reboot"
}
if ( -e $p_cron_force_run_file) {
system $p_cron_run_radmind
unlink $p_cron_force_run_file
system "/sbin/reboot"

Don’t copy and paste this directly. Some lines are getting cutoff and dropped to a following line. Instead I’ve provided the scripts on the .dmg that can be used.

Since I have two different categories of machines public lab and classroom podium I separate out certain routines to allow for a bit of flexibility and customization.
I use two different scripts for radmind depending upon when they get used.

The file itself can be found at
http://www.macosxlabs.org/tools_and_scripts/script_archive/script_archive.html#radmind
It’s the run_radmind script. The first script that gets used after a machine is imaged by Netrestore and is rebooted is my radmind_startup.pl
This script is modified from the original in that it uses iHook to display a series of custom images as such:

My run_radmind.pl script which gets called by cron uses a different series of images:

Notice the difference??
The different images are supplied to iHook from the scripts:

$iHookBackground1 = "/private/.scripts/radmind_images/performing_update1_rice.png" # ktcheck graphic

$iHookBackground2 = "/private/.scripts/radmind_images/performing_update2_rice.png" # fsdiff graphic

$iHookBackground3 = "/private/.scripts/radmind_images/performing_update3_rice.png" # lapply graphic

# run fsdiff
#
print "Scanning File Systemn"
print "%BACKGROUND $iHookBackground2n"

The rest of the scripts can be examine on the .dmg

And for my classroom podium machines I use those same scripts but have re-named them to p_run_radmind.pl and p_radmind_startup.pl They’re exactly the same except that they use a different IP address to access the radmind server.

My automation primarily works off the use of triggerfiles. Triggerfiles are just empty named files which by their existence or non-existence will cause my scripts to perform an action.

Looking back at my startup script you’ll see that it’s checking for the presence of certain triggerfiles.
In my base image from Netrestore I start out with one triggerfile being present. It’s the runRM file. With it being in /private/.scripts/.writable my startup script will launch iHook and passes a certain script to it. In this case it runs my radmind_startup.pl script

$run_radmind = "/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/radmind_startup.
pl"

if ( -e $force_run_file) {
system $run_radmind
unlink $force_run_file # remove just in case.
system "/sbin/reboot"
}

The rest should be fairly clear as to the triggerfiles the script is looking for and the resulting action that is taken when that triggerfile is found.
Both of the run_radmind.pl and radmind_startup.pl and the corresponding radmind scripts for the classroom podium machines keep the triggerfile in place until the script is successfully finishes or fails. The reason for this is two fold. If a user comes up and decides to just reboot the machine thinking they’ll be able to use it the triggerfile is still in place and will get caught by the startup script thus repeating the whole process. On the other hand if the update fails then the triggerfile is deleted prior to rebooting so as to not stay in a loop failing each time.
Both scripts reboot the machine after they are done whether they finished or failed.

During the event of a radmind failure the radmind scripts writes the failure out to a log file in /var/log/radmind/radmind_error.log
The script also will execute a failure script that will email the resulting failure:

#!/bin/sh
#
#
#
PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH
location_log="/var/log/admin/admin_tasks.log"
RIGHTNOW=`date`
host=`hostname`
#
#
err=/var/log/radmind/radmind_error.log

cat $err | mail -s "RE:FAILED - $host – radmind_startup.pl failed to execute properly" This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
exit 0

The above is for when the radmind_startup.pl script is run. Mostly only when I do a full wipe.

If the failure occurred when the run_radmind.pl script was called from cron then it executes a separate but almost identical script:

#!/bin/sh
#
#
#
PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH
location_log="/var/log/admin/admin_tasks.log"
RIGHTNOW=`date`
host=`hostname`
#
#
err=/var/log/radmind/radmind_error.log

cat $err | mail -s "RE:FAILED - $host - Cron_radmind.sh failed to execute properly" This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
exit 0

V. Login/Logout

The login/logout hooks I use are pretty simple. In case you’re not sure what a login/logout hook is then let me give a brief explanation. It’s basically a script that gets called from loginwindow when there is a successful login or logout. For sh scripts the argument used for the user logging in is given by $1. Whenever you see the $1 in any of the scripts it refers to the current user logging in.
Under 10.3 the easiest way to setup the login/logout hooks is to modify the file
/Library/Preferences/com.apple.loginwindow.plist

You’ll want to add in some additional lines to it that may look like the following:

<key>LoginHook</key>
<string>/private/.scripts/lab_loginhook.sh</string>
<key>LogoutHook</key>
<string>/private/.scripts/lab_logouthook.sh</string>

The string portion tells loginwindow where to find the script so you’re location will probably be different. For all my system level admin scripts I put them all in /private/.scripts

Make sure you’re scripts are executable or they won’t run. You’ll also want to reboot the machine after setting up the hooks entry..

My login/logout hooks I use are pretty basic. They’re included in the osx_deployment .dmg. They’re called lab_loginhook.sh and lab_logouthook.sh..
I’ll first speak about the lab_loginhook.

The first thing that I check for when someone tries to login is whether or not iHook is already running. If it is this means that I am probably running an update on the machine.
When iHook is running one of the radmind update scripts the images it’s displaying covers up the loginwindow panel. Most people would just think that login is disabled when this occurs but iHook doesn’t disable one’s ability to login. Someone could blindly type in username/password and the machine would log them in. iHook would continue running the script in the foreground. Even though the chance of this happening is remote I still put in the following check:

# Check to see if someone is trying to login while iHook is running and reboot if they are.
ihookpid=`/bin/ps xcO command | /usr/bin/grep -v grep | /usr/bin/grep iHook | /usr/bin/awk '{ print $1 }'`
if test "$ihookpid" then
lwpid=`/bin/ps xcO command | /usr/bin/grep -v grep | /usr/bin/grep loginwindow | /usr/bin/awk '{ print $1 }'`
kill $lwpid
/sbin/reboot
exit 0
fi

Since all my updates are done off the use of triggerfiles and since those triggerfiles do not get deleted until the radmind scripts successfully updates or fails I go ahead and reboot the machine if someone logs in while iHook is running. When the machine starts back up it will start the update process all over again.

The next two checks I make are for certain user accounts.
If the radmind account logs in then I want to automatically launch my update process. This is useful if you want to quickly update a single machine or allow for someone else to manually update your machines without giving them access to your admin accounts on those machines.

if [ $1 = "radmind" ] then
/private/.scripts/iHook.app/Contents/MacOS/iHook --script=/private/.scripts/run_radmind.pl
fi
# Reboot if root tries to log in.
if [ $1 = "root" ] then
/sbin/reboot
fi

I also check to make sure that someone doesn’t try and login with the root account. If they do then I reboot the machine.

A successful login by a user gets logged to an log file..
# Log user to log file
echo "LOGIN $NODENAME $LOGINNAME $RIGHTNOW">>/var/log/admin/console_access.log

And if that user logging in is not the local admin account then I run two additional scripts.
One is a user setup script the other is a script to modify the byhost pref files in the user’s home directory.

If it is the local admin account then I have a separate byhost script that I run for that user that is tied directly to the admin account.

# Run the User setup script as long as we are not logging in as the Radmind user or the Admin
# User.

#
# Making sure local admin acct. is not logging in.
if [ "$1" != "etsadmin" ] then
cd /
su $1 -c "/Library/Admin/user_setup.sh $1"
su $1 -c "/Library/Admin/byhost_user.sh $1"
cp /Library/Admin/printer_defaults/printers.conf /etc/cups/printers.conf
exit 0
fi
## If local admin acct. logs in run a diff. byhost script.
if [ $1 = "etsadmin" ] then
cd /
/private/.scripts/byhost_admin.sh
cp /Library/Admin/printer_defaults/printers.conf /etc/cups/printers.conf
fi
exit 0
#

The user setup script I wrote deals more with specifics to our installation and our use of network home directories. All home directories are served up via NFS. When someone logs in I make some initial checks and based on what I found the script will perform certain actions. If someone has never logged in before OS X will by default create automatically their Desktop and Library directories.
The first part of my script checks to make sure that the person also has a Documents folder. The reason for this is that I noticed a fairly decent delay when trying to save a document and not having a Documents fodler. OS X wants you to save a documents by default in the documents folder of your home directory. Without one you can experience a delay.

mkdir -p /tmp/$1/Caches
CpMac /Library/Admin/printer_defaults/.lpoptions_nullps /home/$1/.lpoptions
if [ ! -d /home/$1/Documents ] then
mkdir Documents
chmod 0755 Documents
fi
if [ -d /home/$1/Library/Caches/ ] then
rm -r /home/$1/Library/Caches
ln -s /tmp/$1/Caches/ /home/$1/Library/Caches
fi

Another thing I do is to create a tmp location for the user’s Cache directory on the local hard drive. There’s no need to have reads/writes of cache files across the network. A sym-link gets created in the user’s Library for the Cache directory pointing it to a location on the local drive.

# Deal with Library
if [ -d /home/$1/Library/Preferences/ByHost/ ] then
rm -R /home/$1/Library/Preferences/ByHost/
fi
if [ ! -d /home/$1/Library/ ] then
CpMac -r /Library/Admin/user_preferences/Library /home/$1/
CpMac /Library/Admin/user_preferences/com.apple.dock.plist /home/$1/Library/Preferences/
ln -s /tmp/$1/Caches/ /home/$1/Library/Caches
fi
if [ ! -d /home/$1/Library/Preferences/ ] then
CpMac -r /Library/Admin/user_preferences/Library/Preferences /home/$1/Library/
fi
if [ -d /home/$1/Library/Preferences/ ] then
CpMac -r /Library/Admin/user_preferences/Library/Preferences/ /home/$1/Library/
fi
if [ ! -f /home/$1/Library/Preferences/com.apple.dock.plist ] then
CpMac /Library/Admin/user_preferences/com.apple.dock.plist /home/$1/Library/Preferences/
fi

If a user has a byhost directory then I remove it and always copy over a new set of my byhost files. If you don’t know what byhost pref files are they’re just pref files that are machine specific based on the Ethernet address of the machine. A good example is the screensaver pref files.
The next check is to check if the user has a Library directory. If not then I copy one over for them. This directory has includes some pre-set pref files for certain apps plus a pre-built dock pref file.
The next check is to see if the Preferences directory is missing. If it is copy a new one over.
If it’s not then copy my Preferences directory over which will update certain pref files if needed.
The last is to see if the user is missing their dock.plist file all together if so then copy the default one over. This keeps the user from seeing all those question marks in the dock since I don’t include some of the default apps in my image.

After this script gets run then the byhost script runs. It simply goes into the ByHost folder and modifies each file to include the Ethernet address of the current machine in the filename for each file in that directory.

My logout hook is even simpler.
# Clean out the /tmp dir.
rm -r /tmp/*
if [ -f /private/.scripts/.writable/cron_runRM ] then
/sbin/reboot
fi

The first thing I do is clean out the /tmp dir to get rid of the locally stored user cache files.
The next I do is to check to see if I have a radmind update triggerfile present. If so then reboot and let the startup script catch it. The reason for this check will be explained in the next section on Administrative scripts…

VI. Administrative Scripts

Let’s first take a look at the scripts that I run via cron. Here’s a look at my crontab file on my lab machines. Incidentally a good app to use for modifying the crontab file if you don’t want to use the command line is an app called CronniX (http://www.koch-schmidt.de/cronnix/)

15 3 * * * root periodic daily
30 4 * * 6 root periodic weekly
30 5 1 * * root periodic monthly
0 0 * * * root /private/.scripts/roll_logs.pl
5 0 * * * root /private/.scripts/admin_cleanup.sh
15 0 * * 1 3 root /private/.scripts/cron_radmind_labs.sh
1 0 * * * daemon /private/stat/fixwtmp.sh

At midnight every night I execute a perl script that handles my custom log files. That script is located on the .dmg and is called roll_logs.pl

The next script I run is the admin_cleanup.sh The basic premise for it is to clean out all files that a user might have stored within the world-writable /Temporary_Storage directory I have set up.
It first starts by checking to make sure that iHook is not running a radmind update. If it is then I write a triggerfile so that my startup script will execute the clean script upon reboot.
This way I don’t run the risk of having a reboot interrupt the execution of this script.
I then check to make sure that no one is logged in prior to running. If they are then I exit out and just let the script run next time.. This way I don’t worry about deleting something that a user is currently working with.
I suppose I could have it write another triggerfile if a user is logged in and apply a check for it within the logout hook..
The last of the cron jobs that I’ll discuss is the cron_radmind_labs.sh

I run this job on Monday and Wednesday every week. Since I don’t do application updates that often there’s no need for me to run my updates everyday of the week. So for my labs I run on M/W and my classroom podium macs are run on T/Thurs
It all depends on how much checking you want to take place. Radmind is not only useful for providing software updates/installation but is also extremely useful running as a tripwire to check for malicious activity on the computer.

location_log="/var/log/admin/admin_tasks.log"
RIGHTNOW=`date`
LOGINNAME=`/usr/bin/who | /usr/bin/grep console | /usr/bin/awk '{ print $1 }'`
host=`hostname`
touch /private/.scripts/.writable/cron_runRM
SLEEPTIME=`perl -e 'print int(rand(14400)) '`
sleep $SLEEPTIME
###############################################
if [ "$LOGINNAME" = "" ] then
/sbin/reboot
else
echo "---------------------------------------------">>$location_log
echo "$RIGHTNOW">>$location_log
echo "$LOGINNAME is currently logged in. Aborting cron run of radmind. Sending mail to Admin.">>$location_log
cat /private/.scripts/holding/cron_text | mail -s "Cron_radmind.sh did not run on $host because $LOGINNAME was logged in." This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
exit 0
fi
exit 0

This script will first write my triggerfile cron_runRM. Then it calculates a random time value from 0 to 14400 seconds or 4 hours. The script then sleeps for that calculated value. I do this to so not all of my lab machines kick off at the same time and flood the network and the server.
When the script wakes if first will check to see if no one is logged in if no one is it reboots and that startup script picks up the triggerfile check. If someone is logged in then the script writes some info to a logfile sends me an email with the body of the message being the cron_text file (located on the .dmg) and the quits out. Since the script wrote its triggerfile
the machine will automatically kick off the update if the user reboots the machine or just simply logs out.

I have some additional scripts that get called from the running of the radmind_startup.pl and run_radmind.pl scripts.
The first is name_machine.sh. This script gets run on a successful run.
Here’s the snipet of the run_radmind.pl script that shows the variable setting for the name_machine.sh script.

$SetHostNames_script = "/private/.scripts/name_machine.sh"
$runRadmindTriggerFile = "/private/.scripts/.writable/cron_runRM"
$notify_success = "/private/.scripts/cron_radmind_success.sh"
$notify_failed = "/private/.scripts/cron_radmind_failed.sh"

Here’s the sub routine where it’s gets called from:

# If radmind was successful do these things
#
sub radmindSuccessful {
print "radmind finished doing other tasks.n"

system "touch $radmind_finished"

# iHook directive. Uncomment if you want to use it
print "%80n"

# How long did radmind take?
$rightnowwer = time
$radmindtime = $rightnowwer - $rightnow

system "$radmind_successful_script"
system "$SetHostNames_script"

# How long did script take?
$rightnowest = time
$totaltime = $rightnowest - $rightnow

$remote_logger_message = "Radmind successful and took $radmindtime. run_radmind.pl script time is $totaltime seconds"
system "$remote_logger Radmind "$remote_logger_message""
system "echo "$remote_logger_message" >> $radmind_log"
# check in with the radmind check-in cgi
system "curl http://128.42.19.197/cgi-bin/radmindCheckIn"
print "%100n"
system "echo "run_radmind.pl script successful now restarting" >> $radmind_log"
sleep 5
system "/sbin/reboot"

exit 0

}

The name_machine.sh script uses curl to grab a file on a remote server. This file is in a comma separated form and looks like this:

ah117-mac 003065c04ede
bb102-mac 003065a80c1a
bb116-mac 003065a7ff04
bh180-mac 0003936fa482
bl123-mac 003065a0f6f4
bl131-mac 0003936fa4aa

This script is dependent upon the ncutil binary. It can be obtained freely here:
http://deaddog.duch.udel.edu/~frey/darwin/ncutil.php
The script pulls down the comma separated file from the remote server and parses it to find a matching Ethernet address of the machine it’s running. It uses ncutil to set the computer name and rendezvous name to the name found in the list. If a match is not found then it sets both of those names as the Ethernet address.

The script can be viewed from the .dmg
The next script that gets run and is shown in bold in the snippet above is the radmindCheckin
This script is actually a cgi on a remote os x server that gets curled by the computer. The cgi takes the IP address of the machine issuing the remote curl cmd and looks up the hostname for that IP address. It then touches a file in a specified directory with the name being the hostname. What this allows for is an easy way to see when the last successful raqdmind update was.
This scriptis located in the dirwrap directory on the .dmg I’ve included also a modified cgi called dirwrap that allows for you to see that directory from a url.
Here’s a snippet of what the weboage view is like:

Setup instruction for both the radmindCheckin and the dirwrap cgi are in the dirwrap directory.. Read the Readme.

Another script that gets called in both of the radmind update scripts is the cron_radmind_failed.sh
It’s provided in the .dmg for your viewing.

When I want to remotely kick off an update I do so from my Radmind server.
Since I setup passwordless ssh host keys for my clients I can execute a script on the server which can then connect via ssh to my client machines and execute a script on that machine.

The radmind_kickoff script that is run from the server will first examine a text file for all the IP listings. The textfile in the example script I provided is called mudd101_set.
This file just contains an IP listing for the machines in that particular lab. One entry per line as such:
128.x.x.x
128.x.x.x
128.x.x.x

I then use scanssh (can be obtained and installed via fink) to check that the machine is responding to ssh. Why not use ping? Well if a machine is hung up during the boot process there’s a chance that it could respond to a ping but the ssh daemon might not have been loaded yet. This way I know I should be able to ssh into the machine.
If the scanssh comes back with an ssh timeout then I email myself the contains of the file kick_failed.(on the .dmg)
If the scan reports the machine is alive then I go ahead and issue the ssh command to execute the script kickoff_radmind.sh on the remote client.
Radmind_kickoff will go through each IP address listed in the file performing this same action until all the IP’s have been tried.
The kickoff_radmind.sh script on the remote client is almost identical to the cron_radmind_labs.sh script that gets run by cron. The difference being is that the kickoff_radmind.sh script doesn’t have the sleep delay. It still retains though the check for a user being logged in and will write the triggerfile to be picked up on logout.

VII. Conclusion

There are many different ways that one can Administer OS X clients. What I’ve outlined here is just the way I do it here at Rice University using open sourced or free Unix and OS X tools. It doesn’t take that much Unix experience to be able to use a solution like I’ve outlined. The nice part about everything I’ve shown is that all the tools are free.
One thing to remember is that there is not one way of doing all this that I’ve shown. This is just how I do it and depending upon someone’s comfort level with Unix they may or may not implement everything shown.

Macosxlabs.org (http://www.macosxlabs.org) is an excellent resource to use. Many of the scripts I use were posted at that site for others to benefit from. They also contain additional resource links which have proven to be very useful.
When in doubt don’t hesitate to post questions to mailing lists.
Macosxlabs has a good forum discussion board for posting as well as informative monthly webcasts covering a wide range of subjects.

I hope that this document(or rambling whichever way you see it) has helped in some way.
I know there are probably mistakes in this document or maybe even in the scripts so please look over everything prior to implementing it. There are certain customizations to every script that will need to be made before it will work in your institution.

Feel free to contact me if you have any questions.
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it

Lance Ogletree
Sr. Macintosh System’s Administrator
Rice Unviersity

Last Updated ( Tuesday, 12 April 2005 )
 
< Prev