Quick Links
Calendar
| | Sun | Mon | Tue | Wed | Thu | Fri | Sat
|
Categories
Archives
XML/RSS Feed
Links
Statistics
Total entries in this blog:
Total entries in this category:
Published On: May 22, 2004 11:46 PM
|
Sat
- May 22, 2004
Web access to radmind data (updated)
It's useful to be able to quickly view radmind data
via a webpage. Kris Steinhoff has written a radmind management
module for Webmin. This module allows one to perform many common
radmind management tasks via a webpage. We wrote a standalone CGI that gives us
read-only access to radmind data. (With the help of Chris Buskirk, I've added
some files the CGI depends on and updated the script to fix the viewing of
check-ins in domains other than .com - you should be able to get this up and
running very easily on a Mac OS X radmind/web server)
In our organization, only a few people are
authorized to edit radmind data, but it was useful to provide quick read-only
access so that a tech could verify what applications a user had assigned to him
or her in his/her command file. We also wanted code that could do some sanity
checking for us - if a command file was referenced in the config file - did that
command file actually exist? If a hostname was referenced in the config file,
was that hostname actually in DNS? Did the transcripts referenced in a command
file actually exist? This data helps any tech quickly determine the source of
many radmind errors.Our CGI allows the
user to view the config file, command files, and transcripts. These are all
hyperlinked, so if you are viewing the config file, you can click on a command
filename to view it. When viewing a command file, you can click on a transcript
to view its contents. Any item that doesn't exist is flagged in red and not
clickable, so you know there is a
problem.Additionally, the CGI knows
about the /var/radmind/client/updated directory that is managed by the
radmindCheckin cgi we use to report successful radmind runs. It can display the
last time any given machine successfully ran radmind, sorting by hostname,
command file name , or date.Without
further ado, here are the files needed to implement the CGI on Mac OS X (I'd
include the CGI in the text of this post, but iBlog insists on rendering the
HTML that is embedded in the script) :
radmind cgi.zip
And some screen
shots:Main menu: (note an additional
option that is not in the script provided here. It's an option to view our
Makefile, which we use to build our command files from "base" command
files.) View
Config
file: View
command file
list: View
transcript list. The script also looks to see how many command files reference
each transcript. This way you can figure out which transcripts may no longer be
needed: Viewing
an individual
transcript: Viewing
the Check-in report. You can click any column heading to resort the list by
hostname, command file name, or
date.
Posted at 11:41 PM
Read More
Mon - May 10, 2004
Running radmind via cron (by way of periodic) and on-demand
Here are some more of the scripts I use to automate
radmind...
Rather than editing crontab files, I put a script in
/private/etc/periodic/daily, called
900.autoradmind: 900.autoradmindThis
script checks to see the last time radmind ran; sees if there are any needed
updates on the server (via ktcheck), and checks to see if anyone is logged in at
the console.If no-one is logged in, it runs
a radmind session via a script at
/usr/local/radmind/scripts/radmindNowIf
someone is logged in and there are updates on the server, or it has been more
than seven days since the last radmind session, it attempts to log the user out
gracefully. If there are any unsaved documents, this will
fail.If it fails to run radmind and it's
been more than seven days since the last run, it notifies the admin and alerts
the user. I'll share this alert app at a later date (once I've made it easily
customizable...)When the
900.autoradmind script does run radmind, it calls this
script: radmindNow#!/bin/shradmindTriggerFile="/var/radmind/client/.radmindOnLogout"restartCheckFile="/usr/local/radmind/tmp/restartCheck.T"touch
$radmindTriggerFile/usr/local/radmind/scripts/logoutHookexit
0Which as you can see, simply
calls the
logoutHook: logoutHook#!/bin/shradmindTriggerFile="/var/radmind/client/.radmindOnLogout"restartCheckFile="/usr/local/radmind/tmp/restartCheck.T"if
[ -f $radmindTriggerFile ];
then rm
$radmindTriggerFile rm
-f
$restartCheckFile /Applications/Utilities/radmind/iHook.app/Contents/MacOS/iHook
--no-titlebar
--script=/usr/local/radmind/scripts/run_radmind.pl if
[ -s $restartCheckFile ];
then shutdown
-r
now fifiexit
0Which in turn calls iHook
and my run_radmind script, which is detailed
elsewhere.This arrangement gives me a
lot of flexibility. I can ssh in and run the run_radmind script if I want to
see the output, but it's not important (or desirable) for the user at the
machine to see the output. (Typically I'll do this if I know no-one is logged
in and no-one is likely to log in.) Or, if I want iHook to come up and give the
user some indication of what is going on, I can run the "radmindNow" script.
Finally, since I am using a logoutHook script, I can let the user trigger a
radmind session by running this
app: Update this Mac.zip
Which is just an AppleScript
applet:
activate
set
theMessage
to
"Warning: update this machine?" &
return
&
return
& "You will be logged out and software on this machine will be updated.
This may take several minutes and may require a restart. Are you sure you want
to continue?"
display
dialog
theMessage
buttons
{"No", "Yes"} default
button "Yes"
giving up
after 15
with icon
caution
if
(button
returned
of
result
is
equal
to "Yes")
then
try
do
shell script "touch
/var/radmind/client/.radmindOnLogout"
ignoring
application responses
tell
application
"loginwindow"
to
«event
aevtrlgo»
end
ignoring
on
error
theError
display
dialog "Error: " &
theError
giving up
after 60
end
try
end
if
If
the user launches this application and clicks yes, they will be logged out and a
radmind session will run.
Posted at 10:10 PM
Read More
run_radmind script (updated)
Here is the run_radmind script I use. It's called
on demand at logout, and as a periodic task nightly.
First the script
itself: run_radmind.plNow,
some commentary (in
blue):#!/usr/bin/perl#################################################################################
run_radmind##
This script runs
radmind.##
Requires the radmind client tools (and a running server
obviously).# (See
http://rsug.itd.umich.edu/software/radmind)##
Can also be used with iHook# (See
http://rsug.itd.umich.edu/software/ihook)#This
script started out as a light edit of University of Utah's run_radmind script,
and I've added my own tweaks and changes. Of particular coolness was UofU's
execute_command subroutine, which allowed the output of the radmind tools to
appear in iHook's drawer AND be captured to a file, which is invaluable for
troubleshooting.# Copyright (c) 2002
University of Utah Student Computing
Labs.# All Rights
Reserved.##
Many, many modifications by Greg Neagle, Walt Disney Feature
Animation##
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.##################################################################################################################################################################
change these to match your
installation$rserver = "-h
radmind";$cksum =
"";$fsdiffpath =
"/";$ktcheckoutput =
"/usr/local/radmind/tmp/ktcheck_output.log";$ktcheckoutput_backup_number
= 5;$fsdiffoutput =
"/usr/local/radmind/tmp/fsdiff_output.log";$fsdiffoutput_backup_number
= 5;$ignoreList =
"/usr/local/radmind/etc/ignore";$lapplyinput
=
"/usr/local/radmind/tmp/diff.T";$lapplyoutput
=
"/usr/local/radmind/tmp/lapply_output.log";$lapplyoutput_backup_number
= 5;$max_tries =
1;This next bit of
code lets me use the same script when it is run at logout and when it is run by
cron overnight. In the first instance, I run without checksums so fsdiff is
faster. In the second instance, I can turn checksums on and presumably no-one
will be around to complain how long fsdiff
takes.# if the checksum trigger file
exists, run with checksumming
on$checksumTriggerFile =
"/var/radmind/client/.radmindWithChecksums";if
(-f $checksumTriggerFile)
{ $cksum = "-c
sha1"; unlink
$checksumTriggerFile;}$radmind_error
=
"/usr/local/radmind/tmp/radmind_error";$radmind_log
=
"/var/log/run_radmind.log";$errorlog
=
"/usr/local/radmind/tmp/radmind_error.log";$ktcheck
= "/usr/local/bin/ktcheck -c sha1 $rserver 2>
\"$errorlog\"";The
fsdiffCommand variable below takes advantage of a new fsdiff feature (-v) which
gives percent-done
feedback:$fsdiffCommand =
"/usr/local/bin/fsdiff -A $cksum -o $fsdiffoutput -v $fsdiffpath 2>
\"$errorlog\"";$lapply =
"/usr/local/bin/lapply -F $cksum $rserver $lapplyinput 2>
\"$errorlog\"";$restartCheckFile
=
"/usr/local/radmind/tmp/restartCheck.T";$rebootList
=
"/usr/local/radmind/etc/rebootList";$rebootIgnoreList
=
"/usr/local/radmind/etc/rebootIgnoreList";$updatesNeededFile
=
"/var/radmind/client/.updatesNeeded";$extensionsCheckFile
=
"/usr/local/radmind/tmp/extensionsCheck.T";$prefsPanesCheckFile
=
"/usr/local/radmind/tmp/prefsPanesCheck.T";$ktcheck_pic
=
"/usr/local/radmind/images/ktcheck.tif";$fsdiff_pic
=
"/usr/local/radmind/images/fsdiff.tif";$lapply_pic
=
"/usr/local/radmind/images/lapply.tif";I
discovered that when using radmind to upgrade a machine from 10.2.x to 10.3,
that sometimes it locked up during the lapply. Since (for me at least),
upgrading from 10.2.x to 10.3 via radmind takes over an hour, and I have cron
set to run tasks every 15 minutes, I thought perhaps something cron ran was
crashing as libraries and code was swapped out from under it. So I added code
in the run_radmind script to turn cron off. This seems to have improved the
reliability of the upgrade from 10.2.x to
10.3.#################################################################################
Stop cron so it doesn't call stuff we don't want to run during
radmind#$cronMsg
= `/System/Library/StartupItems/Cron/Cron
stop`;print
"$cronMsg\n";I can't
really tell if this next bit is doing anything: I still see the output from
fsdiff and lapply come in chunks with pauses in between, which looks like
buffering to
me...#################################################################################
Turn buffering
off#$|++;$oldhandle
= select( STDERR
);$|++;select(
$oldhandle );print "%UIMODE
AUTOCRATIC\n"; # iHook directive (This removes the menu bar in Panther - which
appears even when no-one is logged
in!)print "%BACKGROUND
$ktcheck_pic\n"; # iHook
directive.print "%BEGINPOLE\n"; #
iHook directive.Note
the indeterminant progress bar, since there's really no way to tell how far
along ktcheck
is.#################################################################################
Keep track of time, write to
log#$rightnow
= time; # keep track of timesystem
"echo \"--------------------------------\" >>
$radmind_log";system "date >>
$radmind_log";system "echo
\"run_radmind started\" >>
$radmind_log";#################################################################################
Roll
logs#&roll_log($ktcheckoutput,
$ktcheckoutput_backup_number);&roll_log($fsdiffoutput,
$fsdiffoutput_backup_number);&roll_log($lapplyoutput,
$lapplyoutput_backup_number);#################################################################################
prep stuffchdir
("/");# radmind loop$current_try = 1;while (1) { ################################################################################ # run ktcheck # print "Task 1 of 3: Checking for updates on the server\n"; $result = execute_command ("$ktcheck", $ktcheckoutput); if ($result == 0) { print "No updates from server\n"; } elsif ($result == 1) { print "Updates found\n"; system
"/usr/bin/touch
$updatesNeededFile"; } else { print "ktcheck encountered a fatal error: $result\n"; system "echo \"ktcheck encountered a fatal error: $result\" >> $radmind_log"; &radmindFailed; } print "%1\n"; # iHook directive. ################################################################################ # run fsdiff # print "Task 2 of 3: Examining the filesystem for differences\n"; print "%BACKGROUND $fsdiff_pic\n"; # iHook directive. $result = system "$fsdiffCommand"; if ($result != 0) { print "fsdiff encountered a fatal error: $result\n"; system "echo \"fsdiff encountered a fatal error: $result\" >> $radmind_log"; &radmindFailed; } This
next bit filters out any lines you don't want in the final lapply. I originally
used it to filter out .DS_Store files. The problem came when later you needed
to remove a directory. If that directory had any .DS_Store files within, they
had been removed from lapply's transcript and therefore lapply would try to
remove a directory that wasn't empty and it then failed. I planned to try to
write some code to work around that issue, but never got around to
it. ################################################################################ #
filter output from
fsdiff # system
"cat $fsdiffoutput | fgrep -v -f $ignoreList >
$lapplyinput";
print "%1\n";
# iHook directive. We
reset the progress bar to 1% (Setting it to 0% removes it from the window, which
is visually jarring!Now
we run lapply.
################################################################################ #
run
lapply # print
"Task 3 of 3: Applying
changes\n"; print
"%BACKGROUND $lapply_pic\n"; # iHook
directive. $fsdsize
= ( stat( $lapplyinput ))[ 7
]; if (
$fsdsize > 0 )
{We get the number
of lines in the applicable transcript so we can calculate (roughly) how far done
we are. See the execute_lapply subroutine for more of
this. $lapplyLineCount = int `wc -l $lapplyinput`; $result = execute_lapply ("$lapply", $lapplyoutput, $lapplyLineCount, "1"); if ($result == 0) { &radmindSuccessful; last; } elsif ($result == 1) { if ($current_try >= $max_tries) { print "lapply failed too many times: $result\n"; system "echo \"lapply failed too many times: $result\" >> $radmind_log"; &radmindFailed; } else { print "lapply failed, trying again: $result\n"; system "echo \"lapply failed, trying again: $result\" >> $radmind_log"; next; } } else { print "lapply encountered a fatal error - see log for errors.\n"; system "echo \"lapply failed: $result\" >> $radmind_log"; &radmindFailed; } } else { print "No changes found!\n"; system "echo \"No changes found\" >> $radmind_log"; &radmindSuccessful; last; } $current_try++;}This
is UofUtah's subroutine. I had never figured out pipe handles in Perl, so this
was an education for
me:################################################################################# This subroutine executes the radmind commands and saves the output to a log,# prints it to stdout, and saves stderr to a log as well.#sub execute_command { local ($thecommand, $path_to_log) = @_; open (COMMAND, "$thecommand |"); open (LOG, ">>$path_to_log"); while (<COMMAND>) { print STDERR; print LOG; } close (LOG); close (COMMAND); return $? >> 8;}This
subroutine, based on execute_command, has the changes needed to give
percent-done feedback to the
user:#################################################################################
This subroutine executes lapply and saves the output to a
log,# prints it to stdout, and saves
stderr to a log as well.# It also
provides percent-done feedback for use by
iHook.#sub
execute_lapply
{ local
($thecommand, $path_to_log, $fsdiff_line_count, $startPercent) =
@_; open
(COMMAND, "$thecommand
|"); open
(LOG,
">>$path_to_log"); $lapply_line_count
= 0; while
(<COMMAND>) {
print
STDERR; print
LOG;For each line
that comes back from lapply, we increment our counter. Since we know how many
lines are in the applicable transcript, and lapply returns one line of output
for (basically) each line in the applicable transcript, we have a pretty good
idea how far along we
are. $lapply_line_count++; if
( int ($lapply_line_count/10) == ($lapply_line_count/10) ) (This way we only
update every ten files or
so) { $ratio
=
$lapply_line_count/$fsdiff_line_count; if
( $ratio > 1 ) { $ratio = 1;
} $percentDone
= $startPercent + int
($ratio*(99-$startPercent)); print
"%$percentDone\n";Or you
can get fancy and do this: print "%percentDone Updated item $lapply_line_count
of
$fsdiff_line_count\n"; } } close
(LOG); close
(COMMAND); return
$? >>
8;}#################################################################################
If radmind was successful, do these
things#sub
radmindSuccessful
{ print
"Finishing
up\n"; #print
"%99\n"; # iHook directive
# How long
did radmind
take? $rightnowwer
=
time; $radmindtime
= $rightnowwer - $rightnow;
$message =
"Radmind successful and took $radmindtime
seconds"; system
"echo \"$message\" >>
$radmind_log"; print
"%100\n"; # iHook
directiveIn Jaguar,
we'd delete /System/Library/Extensions.kextcache and
/System/Library/Extensions.mkext to get the OS to rebuild its extensions cache
on restart. I've found that method to be unreliable with Panther. A method that
seems to work is to touch the /System/Library/Extensions directory. So we grep
the applicable transcript for "/System/Library/Extensions/", which would catch
any changes to the directory. It's important to grep for
"/System/Library/Extensions/", and not "/System/Library/Extensions" - since we
are touching /System/Library/Extensions, on the next radmind run, fsdiff will
notice that /System/Library/Extensions has changed, and will change it back.
Then our script would see /System/Library/Extensions in the transcript, touch
it, and so
on... #do we
need to update extensions
cache? #were
any kernel extensions added, removed, or
changed? system
"grep /System/Library/Extensions/ $lapplyinput >
$extensionsCheckFile"; #check
the extensionsCheckFile filesize. If it's greater than zero, touch
/System/Library/Extensions $extcfsize
= ( stat( $extensionsCheckFile ))[ 7
]; if (
$extcfsize > 0 )
{ system
"/usr/bin/touch
/System/Library/Extensions"; }We
do something similar with Preference Panes. The OS keeps a cache of Pref Panes.
When radmind adds or deletes a pane from either /System/Library/PreferencePanes
or /Library/PreferencePanes we need to touch /System/Library/PreferencePanes to
signal to the OS to update its cache. (Preference panes can also go in
~/Library/PreferencePanes. By grepping for "/Library/PreferencePanes/" we
actually catch all possible locations, though in practice we don't manage user
space) #do we
need to invalidate Preferences Panes
cache? #were
any prefs panes added, removed, or
changed? system
"grep /Library/PreferencePanes/ $lapplyinput >
$prefsPanesCheckFile"; #check
the prefsPanesCheckFile filesize. If it's greater than zero, touch
/System/Library/PreferencePanes $ppcfsize
= ( stat( $prefsPanesCheckFile ))[ 7
]; if (
$ppcfsize > 0 )
{ system
"/usr/bin/touch
/System/Library/PreferencePanes"; }I
don't like to restart after a radmind run unless it is needed. But how to tell
if it's needed? I grep through the applicable transcript and look for items
that trigger a restart. First we find all the items in the $rebootList, then
eliminate the items in the
$rebootIgnoreList.Here's
my current
$rebootList:/mach_kernel/System/Library//Library/StartupItems//Library/Preferences/DirectoryService//Library/Application\bSupport/Norton\bSolutions\bSupport/Here's
my current
$rebootIgnoreList/Library/Application\bSupport/Norton\bSolutions\bSupport/Scheduler/SymSecondaryLaunch.app/Contents/MacOS/SymSecondaryLaunch/Library/Application\bSupport/Norton\bSolutions\bSupport/Scheduler/schedLauncher/Library/Preferences/DirectoryService/.DSRunningSP/Library/StartupItems/NortonMissedTasks/NortonMissedTasks/System/Library/CoreServices/.disk_labelThe
idea here is to reboot if anything in the rebootList has changed, unless it is
in the rebootIgnoreList.So if
radmind just installs an application with all its files under /Applications, the
machine will not reboot. But if stuff in /System/Library/ changes, it generally
will reboot.
#check to see
if we need a
restart system
"fgrep -f $rebootList $lapplyinput | fgrep -v -f $rebootIgnoreList >
$restartCheckFile"; #check
the restartCheckFile filesize. If it's greater than zero,
restart $rscfsize
= ( stat( $restartCheckFile ))[ 7
]; if (
$rscfsize > 0 )
{ print
"Items installed require a restart. Restarting
now...\n"; system
"sleep 2";Note that
I don't actually restart in this script - instead I let the calling script
restart. This allows me to run this script manually remotely via SSH and not
get kicked off at the
end. #
we'll just fall through and exit normally and let the logout hook
script #
notice that the restartCheckFile exists and actually do the
restart. }
else
{ #if
we are not restarting we should restart
cron $cronmsg
= `/System/Library/StartupItems/Cron/Cron
start`; print
"$cronmsg\n"; }Since
we were successful, we can remove the trigger file that tells us updates were
needed. If the update failed, the file would not be
removed. if
(-e $updatesNeededFile) { unlink $updatesNeededFile
}I use a simple CGI
to report success to a webserver. I can then see when the last successful
radmind was for a given host. You can find details about this CGI elsewhere on
this website.
#check in
with the radmind check-in
cgi system
"curl
http://radmind/cgi-bin/radmindCheckIn"; exit
0;}#################################################################################
If radmind died, this is the cleanup
subroutine.#sub radmindFailed { # print error log to stdout open (LOGGY, "<$errorlog"); while (<LOGGY>) { print; } close (LOGGY); #system "touch $radmind_error"; # How long did radmind take? $rightnowwer = time; $radmindtime = $rightnowwer - $rightnow; # $message = "Radmind failed and took $radmindtime seconds"; system "echo \"$message\" >> $radmind_log"; system "cat \"$errorlog\" >> $radmind_log";We're
not restarting, so we should start cron back
up: # restart
cron $cronmsg
= `/System/Library/StartupItems/Cron/Cron
start`; print
"$cronmsg\n";If
radmind fails, I send mail to root - you may (probably will) want to send it
elsewhere. Of course this means sendmail/postfix must be properly configured on
the system. #
notify the
authorities $hostname
=
`hostname`; chomp
$hostname; system
"cat $errorlog | mail -s \"Radmind failed on $hostname.\"
root";
exit
1;}Unchanged
from
UofUtah:################################################################################# This script renames $path_to_log so that the lowest number is always the# newest. The oldest that is greater than $number_of_backups is deleted.#sub roll_log { local ($path_to_log, $number_of_backups) = @_; if (-e $path_to_log) { if (-e $path_to_log.".bak$number_of_backups") { unlink $path_to_log.".bak$number_of_backups"; } for ($i = $number_of_backups ; $i > 1 ; $i-- ) { if (-f $path_to_log.".bak".($i-1)) { system "/bin/mv -f \"$path_to_log".".bak".($i-1)."\" \"$path_to_log".".bak$i\""; } } system "/bin/mv -f \"$path_to_log\" \"$path_to_log".".bak1\""; }} Here's
the pictures referenced by the script, which because they are TIFFs with
transparency, look awful on a web page, but quite nice in
iHook: images.zip
Posted at 09:22 PM
Read More
Fri - May 7, 2004
Monitoring radmind (updated)
(Updated 5/7/04) Once you have set up some sort of
automation for radmind, so that it runs automatically every night, for example,
it becomes important to be able to monitor the machines you manage to see if
they are running radmind regularly and to be notified if there are any
problems.
The run_radmind script we use emails us if there is
a failure. But what if the failure is that the script never runs at all? Do
you want to assume that because you haven't been notified of a problem, that
everything is fine? So we have the script also perform an action on success.
Since the vast majority of our machines are successful, and a large chunk of
them run radmind every night, we don' t want to be buried in emails telling us
everything is OK.
So on success, our
run_radmind script calls a web CGI like so (in
Perl):
#check in with the radmind
check-in cgi system "curl
http://radmind/cgi-bin/radmindCheckin";
and
here's the
CGI:
#!/usr/bin/perl
#
Radmind checkin
CGI # #
this simple CGI touches a file in
$UPDATE_DIR # with the hostname of the
the machine reporting in (This
assumes # your machine's hostnames are
in DNS and reverse lookup works) #
otherwise it touches a file named the same as the IP address
of # the machine reporting
in. # #
Copyright 2003 Walt Disney Feature
Animation # Permission granted to use
this code
freely. # #
this CGI can be called from a script like
so: # curl
"http://your.webserver.tld/cgi-bin/radmindCheckin" # #
Original Script by Greg Neagle,
WDFA. # #
02/11/2004 Modification of the original code to support running on Panther
Server # - Lance Ogletree ,
Rice
University # #
05/06/2004 Modification to deal with Apache sometimes returning the remote IP in
# $ENV{SERVER_ADDR} and
sometimes in $ENV{HTTP_PC_REMOTE_ADDR},
# depending on the server
configuration. # This
should make the script more portable.
# Thanks to Josh Burker,
Mercer Island School District for helping debug
# this
issue. # - Greg Neagle,
WDFA # #
05/06/2004 Added ability to pass in a custom hostname; this might make this
script # usable in
environments where useful hostnames are not in
DNS. # You could then have
the machine grab a name from a file or by
using # `scutil --get
LocalHostName` or `scutil --get
ComputerName` # You'd then
call the CGI like so: #
curl
"http://your.webserver.tld/cgi-bin/radmindCheckIn?mycustomhostname #
- Greg Neagle,
WDFA #
print
"Content-type: text/plain\n"; print
"\n";
print "Radmind
check-in\n"; print
"\n";
$UPDATE_DIR =
"/var/radmind/client/updated/"; # be
sure the directory pointed to by $UPDATE_DIR
exists # and that it's writable by the
web server
$hostname =
$ENV{QUERY_STRING};
if
($hostname eq "")
{ #no custom
hostname passed in, so let's generate
one $IP =
$ENV{HTTP_PC_REMOTE_ADDR}; if
($IP eq "")
{ #
depending on Apache
config/environment #
we need to use $ENV{REMOTE_ADDR}
instead $IP
=
$ENV{REMOTE_ADDR}; }
$hostoutput
= `host $IP`; unless
($hostoutput =~ /not found/)
{ #
parse out the
hostname @hostoutput
= split /\s+/,
$hostoutput; $hostname
= pop
@hostoutput; $hostname
=~ s/\.$//; } else
{ #
use the IP as the
hostname $hostname
=
$IP; } } print
"$hostname successfully checked
in.\n"; $cmd = "/usr/bin/touch
$UPDATE_DIR$hostname"; `$cmd`;
The
CGI is very simple. All it does is take the IP address of the incoming
connection, look up the DNS hostname of that IP address, and then "touches" a
file with the name of the host in a directory we've created to hold these (We
used "/var/radmind/client/updated/"). The
"touch" command creates an empty file if one does not exist, or updates the
modification date on the file if it already
exists. If there is no hostname associated
with the IP address, it touches a file named after the IP address
("192.168.1.1"). Finally, you can pass the
CGI a hostname - this could be useful if the machine has a file it can use to
come up with a unique name (like a radmind certificate), or you've set the
"Computer Name" or Rendezvous name. In this case, you'd call the CGI like so
(again in Perl):
system "curl
http://radmind/cgi-bin/radmindCheckin?customhostname";
You
can then tell the last time a machine successfully ran radmind by looking at the
modification date of the file with its name. We have another CGI which presents
this info in a nice web page. Details in anther entry on this
site.
Since I originally posted this
script last December, Lance Ogletree contributed a modification that lets it run
properly under Panther, Josh Berker surfaced an issue (and helped me debug it)
with some configurations of Apache, and I added the custom hostname
feature.
Enjoy.
Posted at 10:46 PM
Read More
Sat
- January 17, 2004
Using radmind to upgrade from 10.2.x to 10.3.x - UPDATE
One of the main reasons I started this blog was to
communicate my adventures in using radmind to upgrade machines from 10.2.x to
10.3.x. It turned out not to be trivial, so I wanted to share my experiences so
others could benefit.
It's far past
time for an update on my progress.
So
far I have successfully upgraded about 85 machines from 10.2.6 to 10.3.1 or
10.3.2 using radmind. I continue to upgrade a few each week. I will have moved
most of our OS X boxes to Panther before the end of January.
The key
findings:
1) Make sure your command
files are good! If the update fails because of a problem with a command file
you can end up with a non-bootable
disk.
2) Make sure your run_radmind
script turns off the cron daemon while it runs. See the run_radmind script
posted elsewhere on this weblog for details. If cron tries to run a task during
the update, you can get a segment fault or
worse.
3) Make sure your command files
are free of any pre-Panther stuff - in other words, don't have a 10.3.x base
with an old Safari overload or a (10.2) Developer tools overload, etc, etc. I
haven't seen any problems with including overloads of non-Apple applications
created on top of Jaguar, but your mileage may
vary.
4) Don't try to do this update
using the Radmind Assistant or by manually running the radmind tools from a
shell prompt. Do it as part of a logout hook script or a script run by cron
when no-one is logged in, or a StartupItem. And then leave the machine alone
while it updates. At Feature Animation, a radmind-ed update from 10.2.6 to
10.3.1 took about 60-90 minutes. I haven't timed a 10.2.6 to 10.3.2 update,
which is what we are doing now, but I see no reason to believe the times
wouldn't be similar.
5) Even if
everything goes well, at the end of my run_radmind script, it attempts to
restart but fails, usually with a segment fault. If you then just do a hard
restart (via the restart button or power button) it comes up fine in
Panther.
Posted at 05:38 PM
Read More
Wed - November 12, 2003
Creating new System users for Panther and Postfix
If you use radmind to upgrade a machine from 10.2.x
to 10.3, several system users will not be created (unless the NetInfo database
is not in your negative transcript). Without these users, postfix (the new mail
transfer agent - it replaces sendmail) will not work. Other services may also
be affected. Here's how you can automate creating those needed users and
groups.
This fix was made easier by poking around on the
Panther Install disk 1, looking at the Install packages, and looking at the
scripts buried in the Resources. There is one called CreateSystemUsers that
served as the basis for this script. Again, I run this as part of a custom
StartupItem.
################################################################## # check for and create system users needed by 10.3 when # upgraded from 10.2 ################################################################## ConsoleMessage "Validating System Users"
# Add cyrus user nicl . -read /users/cyrus >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /users/cyrus nicl . -createprop /users/cyrus uid 77 nicl . -createprop /users/cyrus gid 6 nicl . -createprop /users/cyrus passwd '*' nicl . -createprop /users/cyrus change 0 nicl . -createprop /users/cyrus expire 0 nicl . -createprop /users/cyrus realname 'Cyrus IMAP User' nicl . -createprop /users/cyrus home '/var/imap' nicl . -createprop /users/cyrus shell '/usr/bin/false' nicl . -createprop /users/cyrus _writers_passwd 'cyrus' echo "niutil: User 'eppc' added." fi
# add the eppc user nicl . -read /users/eppc >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /users/eppc nicl . -createprop /users/eppc uid 71 nicl . -createprop /users/eppc gid 71 nicl . -createprop /users/eppc passwd '*' nicl . -createprop /users/eppc change 0 nicl . -createprop /users/eppc expire 0 nicl . -createprop /users/eppc realname 'Apple Events User' nicl . -createprop /users/eppc home '/var/empty' nicl . -createprop /users/eppc shell '/usr/bin/false' nicl . -createprop /users/eppc _writers_passwd 'eppc' echo "niutil: User 'eppc' added." fi
# add the lp user nicl . -read /users/lp >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /users/lp nicl . -createprop /users/lp uid 26 nicl . -createprop /users/lp gid 26 nicl . -createprop /users/lp passwd '*' nicl . -createprop /users/lp change 0 nicl . -createprop /users/lp expire 0 nicl . -createprop /users/lp realname 'Printing Services' nicl . -createprop /users/lp home '/var/spool/cups' nicl . -createprop /users/lp shell '/usr/bin/false' nicl . -createprop /users/lp _writers_passwd 'lp' echo "niutil: User 'lp' added." fi
# add the lp group nicl . -read /groups/lp >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /groups/lp nicl . -createprop /groups/lp gid 26 nicl . -createprop /groups/lp passwd '*' echo "niutil: Group 'lp' added." fi
# add the mailman user nicl . -read /users/mailman >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /users/mailman nicl . -createprop /users/mailman uid 78 nicl . -createprop /users/mailman gid 78 nicl . -createprop /users/mailman passwd '*' nicl . -createprop /users/mailman change 0 nicl . -createprop /users/mailman expire 0 nicl . -createprop /users/mailman realname 'Mailman user' nicl . -createprop /users/mailman home '/var/empty' nicl . -createprop /users/mailman shell '/usr/bin/false' nicl . -createprop /users/mailman _writers_passwd 'mailman' echo "niutil: User 'mailman' added." fi
# add the mailman group nicl . -read /groups/mailman >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /groups/mailman nicl . -createprop /groups/mailman gid 78 nicl . -createprop /groups/mailman passwd '*' echo "niutil: Group 'mailman' added." fi
# add the postfix user nicl . -read /users/postfix >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /users/postfix nicl . -createprop /users/postfix uid 27 nicl . -createprop /users/postfix gid 27 nicl . -createprop /users/postfix passwd '*' nicl . -createprop /users/postfix change 0 nicl . -createprop /users/postfix expire 0 nicl . -createprop /users/postfix realname 'Postfix User' nicl . -createprop /users/postfix home '/var/spool/postfix' nicl . -createprop /users/postfix shell '/usr/bin/false' nicl . -createprop /users/postfix _writers_passwd 'postfix' echo "niutil: User 'postfix' added." fi
# add the postfix group nicl . -read /groups/postfix >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /groups/postfix nicl . -createprop /groups/postfix gid 27 nicl . -createprop /groups/postfix passwd '*' echo "niutil: Group 'postfix' added." fi
# add the postdrop group nicl . -read /groups/postdrop >/dev/null 2>&1 if [ $? != 0 ] ; then nicl . -create /groups/postdrop nicl . -createprop /groups/postdrop gid 28 nicl . -createprop /groups/postdrop passwd '*' echo "niutil: Group 'postdrop' added." fi
This last bit is not strictly related to the creation of missing system users, but if you want Postfix to operate as a way for processes to send outgoing mail to an external mailserver, you'll need to make a change to the /etc/hostconfig file:
################################################################## # turn on postfix-on-demand in the hostconfig file ################################################################## if [ "${MAILSERVER:=-NO-}" = "-NO-" ]; then echo "Starting
Postfix" cp /etc/hostconfig /etc/hostconfig.bak grep -v MAILSERVER /etc/hostconfig.bak > /etc/hostconfig echo "MAILSERVER=-AUTOMATIC-" >> /etc/hostconfig # start postfix to create the needed directories and pipes in /private/var/spool/postfix /usr/sbin/postfix start # now we can stop postfix /usr/sbin/postfix stop # finally start the mail queue watcher /usr/sbin/postfix-watch fi
Posted at 10:25 PM
Read More
Fixing empty SSH keys
If you put the ssh_host* keys into your negative
transcript (and you should), make sure they are stored as empty files on the
server, or you may end of with lots of machines sharing the same keys. On the
other hand, you run a risk of empty ssh_host* keys being delivered to your
machines, which prevents SSH from starting. Here's a fix.
Once again, I run this script as part of a custom
StartupItem. It simply looks for zero-length ssh_host* keys and generates valid
replacements.
################################################################## # SSH ##################################################################
# fix empty ssh host keys echo "Checking ssh host keys" if [ -f /etc/ssh_host_key ]; then if [ ! -s /etc/ssh_host_key ]; then rm /etc/ssh_host_key echo "Generating ssh host RSA1 key..." ssh-keygen -t rsa1 -f /etc/ssh_host_key -N "" -C "$(hostname)" fi fi if [ -f /etc/ssh_host_rsa_key ]; then if [ ! -s /etc/ssh_host_rsa_key ]; then rm /etc/ssh_host_rsa_key echo "Generating ssh host RSA key..." ssh-keygen -t rsa -f /etc/ssh_host_rsa_key -N "" -C "$(hostname)" fi fi if [ -f /etc/ssh_host_dsa_key ]; then if [ ! -s /etc/ssh_host_dsa_key ]; then rm /etc/ssh_host_dsa_key ]; echo "Generating ssh host DSA key..." ssh-keygen -t dsa -f /etc/ssh_host_dsa_key -N "" -C "$(hostname)" fi fi
Posted at 10:17 PM
Read More
Tue - November 11, 2003
Panther global config files changes
Apple has moved the location of some global
preference files, notably the files that stored Locations, Network
Configuration, and Power Management settings.
Previously, these were
in /private/var/db/
and
/private/var/db/SystemConfiguration/ Now
they are in
/Library/Preferences/SystemConfiguration/
This
location is more in keeping with Apple's other global preferences, but if you
weren't managing those files under 10.1 and 10.2, you'll need to
add
d
/Library/Preferences/SystemConfiguration 0755 0
80
to your negative file for
Panther to keep from managing them now.
Posted at 07:55 AM
Read More
Mon - November 10, 2003
Using radmind to upgrade from 10.2 to 10.3
Using radmind to upgrade a machine from 10.1.5 to
10.2.x worked well. It took a long time, but it worked. Unfortunately (at
least in this context), Apple has made many more under-the-hood changes in
Panther that make using radmind to upgrade a machine from Jaguar to Panther more
difficult.
Here are some of the issues and challenges I've
discovered so far:
• Since so
much of the OS is changing out from under itself when radmind is upgrading a
machine from 10.2 to 10.3, it impossible to completely automate the process.
Even when everything goes perfectly, the machine hangs on reboot, requiring
manual intervention.
• Apple's
Panther installer does more than install files. It makes other configuration
changes to the machine that may not be captured by radmind, depending on what
you manage. For example, it makes changes to the NetInfo database - adding
several new users and groups needed by processes such as Postfix (the new mail
transfer agent, replacing sendmail). If you do not manage the NetInfo database,
you'll need to create these users yourself. Fortunately, Apple has provided a
script to do just that, and I'll later present my modified version of
it.
• Another part of the Postfix
transition is a change to the /etc/hostconfig file. Under 10.2 and earlier, it
typically had an entry of MAILSERVER=-NO-. It needs to be changed to
MAILSERVER=-AUTOMATIC- for Postfix to fire up when there is outgoing mail to be
delivered, typically by system processes (I have my main radmind script mail me
when there is a problem). Also, Apple's new Fax functionality makes use of
Postfix to mail out received faxes. Again, a script can help you with this
reconfiguration. I'll present it
later.
...more to come.
Posted at 11:17 PM
Read More
|