Greetings,
The attached patches address several fixes to the anaconda monitoring (anamon) support in cobbler. Several features have also been added, including:
* Adding post_anamon snippet to standard kickstart templates (sample.ks and sample_end.ks) * Adding a anamon.init used to provide post-install boot notification
Comments welcome.
Thanks, James
--- cobbler/action_sync.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index 1ba9165..4ebe027 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -163,7 +163,7 @@ class BootSync: if not x.endswith(".py"): utils.rmfile(path,verbose=self.verbose) if os.path.isdir(path): - if not x in ["web", "webui", "localmirror","repo_mirror","ks_mirror","images","links","repo_profile","repo_system","svc","rendered"] : + if not x in ["aux", "web", "webui", "localmirror","repo_mirror","ks_mirror","images","links","repo_profile","repo_system","svc","rendered"] : # delete directories that shouldn't exist utils.rmtree(path,verbose=self.verbose) if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles","repo_profile","repo_system","rendered"]:
--- aux/anamon.py | 52 +++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/aux/anamon.py b/aux/anamon.py index cd1d4ef..f782b9a 100644 --- a/aux/anamon.py +++ b/aux/anamon.py @@ -30,18 +30,23 @@ import time import re import md5 import base64 +import shlex
# on older installers (EL 2) we might not have xmlrpclib # and can't do logging, however this is more widely # supported than remote syslog and also provides more # detail. - try: import xmlrpclib except ImportError, e: print "xmlrpclib not available, exiting" sys.exit(0)
+# shlex.split support arrived in python-2.3, the following will provide some +# accomodation for older distros (e.g. RHEL3) +if not hasattr(shlex, "split"): + shlex.split = lambda s: s.split(" ") + class WatchedFile: def __init__(self, fn, alias): self.fn = fn @@ -172,33 +177,45 @@ def anamon_loop(): ulog = WatchedFile("/mnt/sysimage/root/upgrade.log", "upgrade.log") ulog2 = WatchedFile("/mnt/sysimage/tmp/upgrade.log", "tmp+upgrade.log") sysimage = MountWatcher("/mnt/sysimage") - watchlist = [alog, slog, dump, scrlog, mod, llog, kcfg] - waitlist = [ilog, ilog2, ulog, ulog2]
+ # Were we asked to watch specific files? if watchfiles: watchlist = [] + waitlist = [] + + # Create WatchedFile objects for each requested file for watchfile in watchfiles: if os.path.exists(watchfile): watchfilebase = os.path.basename(watchfile) watchlog = WatchedFile(watchfile, watchfilebase) watchlist.append(watchlog)
+ # Use the default watchlist and waitlist + else: + watchlist = [alog, slog, dump, scrlog, mod, llog, kcfg] + waitlist = [ilog, ilog2, ulog, ulog2] + + # Monitor loop while 1: time.sleep(5)
- if not watchfiles: - for watch in waitlist: - if alog.seen("step installpackages$") or (sysimage.stable() and watch.exists()): - print "Adding %s to watch list" % watch.alias - watchlist.append(watch) - waitlist.remove(watch) - + # Not all log files are available at the start, we'll loop through the + # waitlist to determine when each file can be added to the watchlist + for watch in waitlist: + if alog.seen("step installpackages$") or (sysimage.stable() and watch.exists()): + debug("Adding %s to watch list\n" % watch.alias) + watchlist.append(watch) + waitlist.remove(watch) + + # Send any updates for wf in watchlist: wf.update() + + # If asked to run_once, exit now if exit: break
-# process args +# Establish some defaults name = "" server = "" port = "80" @@ -207,6 +224,7 @@ debug = lambda x,**y: None watchfiles = [] exit = False
+# Process command-line args n = 0 while n < len(sys.argv): arg = sys.argv[n] @@ -215,7 +233,7 @@ while n < len(sys.argv): name = sys.argv[n] elif arg == '--watchfile': n = n+1 - watchfiles.append(sys.argv[n]) + watchfiles.extend(shlex.split(sys.argv[n])) elif arg == '--exit': exit = True elif arg == '--server': @@ -230,12 +248,20 @@ while n < len(sys.argv): daemon = 0 n = n+1
+# Create an xmlrpc session handle session = xmlrpclib.Server("http://%s:%s/cobbler_api" % (server, port))
+# Fork and loop if daemon: if not os.fork(): + # Redirect the standard I/O file descriptors to the specified file. + DEVNULL = getattr(os, "devnull", "/dev/null") + os.open(DEVNULL, os.O_RDWR) # standard input (0) + os.dup2(0, 1) # Duplicate standard input to standard output (1) + os.dup2(0, 2) # Duplicate standard input to standard error (2) + anamon_loop() - sys._exit(1) + sys.exit(1) sys.exit(0) else: anamon_loop()
--- aux/anamon.init | 101 ++++++++++++++++++++++++++++++++++++ cobbler.spec | 2 + setup.py | 5 +- triggers/clear_anamon_logs.trigger | 39 ++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 aux/anamon.init create mode 100755 triggers/clear_anamon_logs.trigger
diff --git a/aux/anamon.init b/aux/anamon.init new file mode 100644 index 0000000..b2fd982 --- /dev/null +++ b/aux/anamon.init @@ -0,0 +1,101 @@ +#!/bin/bash +## BEGIN INIT INFO +# Provides: anamon +# Default-Start: 3 5 +# Default-Stop: 0 1 2 4 6 +# Required-Start: +# Should-Start: $network +# Short-Description: Starts the cobbler anamon boot notification program +# Description: anamon runs the first time a machine is booted after +# installation. +## END INIT INFO + +# +# anamon: Starts the cobbler post-install boot notification program +# +# chkconfig: 35 99 95 +# +# description: anamon runs the first time a machine is booted after +# installation. +# + +LOCKFILE="/var/lock/subsys/anamon" +CFGFILE="/etc/sysconfig/anamon" + +# Source function library. +. /etc/init.d/functions + +# Source anamon config +. $CFGFILE + +LOGFILES=${LOGFILES:-/var/log/boot.log} + +# FIXME - can we rely on the koan snippet to update /etc/profile.d/cobbler.sh? +if [ -z "$COBBLER_SERVER" ]; then + echo "No COBBLER_SERVER defined in $CFGFILE" + exit 1 +fi + +if [ -z "$COBBLER_NAME" ]; then + echo "No COBBLER_NAME defined in $CFGFILE" + exit 1 +fi + +if [ -z "$LOGFILES" ]; then + echo "No LOGFILES defined in $CFGFILE" + exit 1 +fi + +start() { + echo -n $"Starting anamon: " + daemon /usr/local/sbin/anamon.py --watchfile "$LOGFILES" --name $COBBLER_NAME --server $COBBLER_SERVER --port ${COBBLER_PORT:-80} --exit + RETVAL=$? + [ $RETVAL -eq 0 ] && touch $LOCKFILE + echo + + # Disable service start + chkconfig anamon off + + return $RETVAL +} + +stop () { + echo -n $"Shutting down anamon: " + killproc /usr/local/sbin/anamon.py + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f $LOCKFILE + echo + return $RETVAL +} + +restart() { + stop + start +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + condrestart) + if [ -f $LOCKFILE ]; then + restart + fi + ;; + status) + status anamon.py + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart}" + RETVAL=2 + ;; +esac + +exit $RETVAL diff --git a/cobbler.spec b/cobbler.spec index 4b2b351..0f5ac05 100644 --- a/cobbler.spec +++ b/cobbler.spec @@ -250,6 +250,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT %defattr(744,root,root) %config(noreplace) /var/lib/cobbler/triggers/sync/post/restart-services.trigger %config(noreplace) /var/lib/cobbler/triggers/install/pre/status_pre.trigger +%config(noreplace) /var/lib/cobbler/triggers/install/pre/clear_anamon_logs.trigger %config(noreplace) /var/lib/cobbler/triggers/install/post/status_post.trigger
%defattr(664,root,root) @@ -267,6 +268,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT %config(noreplace) /var/lib/cobbler/snippets/download_config_files %config(noreplace) /var/lib/cobbler/snippets/koan_environment %config(noreplace) /var/lib/cobbler/snippets/pre_anamon +%config(noreplace) /var/lib/cobbler/snippets/post_anamon %config(noreplace) /var/lib/cobbler/snippets/redhat_register /var/lib/cobbler/elilo-3.8-ia64.efi /var/lib/cobbler/menu.c32 diff --git a/setup.py b/setup.py index 45cd5ea..3adaca1 100644 --- a/setup.py +++ b/setup.py @@ -262,6 +262,7 @@ if __name__ == "__main__": (snippetpath, ['snippets/download_config_files']), (snippetpath, ['snippets/koan_environment']), (snippetpath, ['snippets/pre_anamon']), + (snippetpath, ['snippets/post_anamon']), (snippetpath, ['snippets/redhat_register']),
# documentation @@ -347,7 +348,7 @@ if __name__ == "__main__": (wwwcon, ['webui_content/cobblerweb.css']),
# Anamon script - (vw_aux, ['aux/anamon.py']), + (vw_aux, ['aux/anamon.py', 'aux/anamon.init']),
# Directories to hold cobbler triggers ("%s/add/distro/pre" % trigpath, []), @@ -367,7 +368,7 @@ if __name__ == "__main__": ("%s/delete/repo/pre" % trigpath, []), ("%s/delete/repo/post" % trigpath, []), ("%s/delete/repo/post" % trigpath, []), - ("%s/install/pre" % trigpath, [ "triggers/status_pre.trigger"]), + ("%s/install/pre" % trigpath, [ "triggers/status_pre.trigger", "triggers/clear_anamon_logs.trigger"]), ("%s/install/post" % trigpath, [ "triggers/status_post.trigger"]), ("%s/sync/pre" % trigpath, []), ("%s/sync/post" % trigpath, [ "triggers/restart-services.trigger" ]) diff --git a/triggers/clear_anamon_logs.trigger b/triggers/clear_anamon_logs.trigger new file mode 100755 index 0000000..1c5da65 --- /dev/null +++ b/triggers/clear_anamon_logs.trigger @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import os +import glob +import sys +import cobbler.api as capi + +if len(sys.argv) < 3: + print "Missing required arguments" + sys.exit(1) + +objtype = sys.argv[1] # "system" or "profile" +name = sys.argv[2] # name of system or profile +ip = sys.argv[3] # ip or "?" + +# TODO - check if anamon is enabled first +bootapi = capi.BootAPI() +settings = bootapi.settings() +anamon_enabled = settings.anamon_enabled +print "anamon_enabled = %s" % anamon_enabled + +# Remove any files matched with the given glob pattern +def unlink_files(globex): + for f in glob.glob(globex): + if os.path.isfile(f): + try: + print "unlinking '%s'" % f + os.unlink(f) + except OSError, e: + print "failed to unlink '%s'" % f + pass + +if anamon_enabled in [True, 1, "1"]: + dirname = "/var/log/cobbler/anamon/%s" % name + if os.path.isdir(dirname): + unlink_files(os.path.join(dirname, "*")) + +# TODO - log somewhere that we cleared a systems anamon logs +sys.exit(0)
--- snippets/pre_anamon | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/snippets/pre_anamon b/snippets/pre_anamon index 2e16209..636dc1b 100644 --- a/snippets/pre_anamon +++ b/snippets/pre_anamon @@ -1,5 +1,4 @@ #if $str($getVar('anamon_enabled','')) == "1" -cd /tmp -wget "http://$server/cobbler/aux/anamon.py" -python anamon.py --name "$name" --server "$server" --port "$http_port" +wget -O /tmp/anamon.py "http://$server/cobbler/aux/anamon.py" +python /tmp/anamon.py --name "$name" --server "$server" --port "$http_port" #end if
--- snippets/post_anamon | 30 +++++++++++++++++++----------- 1 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/snippets/post_anamon b/snippets/post_anamon index 0996cde..3f7405c 100644 --- a/snippets/post_anamon +++ b/snippets/post_anamon @@ -1,16 +1,24 @@ #if $str($getVar('anamon_enabled','')) == "1" -cat << __EOT__ > /etc/rc.anamon -cd /tmp || exit 1 -wget "http://$server/cobbler/aux/anamon.py" -./anamon.py --watchfile /var/log/boot.log --name "$name" --server "$server" --port "$http_port" --exit --fg -chmod a-x /etc/rc.anamon -__EOT__
-chmod 755 /etc/rc.anamon +## install anamon script +wget -O /usr/local/sbin/anamon.py "http://$server/cobbler/aux/anamon.py" +chmod +x /usr/local/sbin/anamon.py + +wget -O /etc/rc.d/init.d/anamon "http://$server/cobbler/aux/anamon.init" +chmod +x /usr/local/sbin/anamon.py + +## establish permissions +chmod 755 /etc/rc.d/init.d/anamon
-cat << __EOT__ >> /etc/rc.local -if [ -x "/etc/rc.anamon" ]; then - /etc/rc.anamon -fi +## enable the script +chkconfig --add anamon + +## configure anamon server +cat << __EOT__ > /etc/sysconfig/anamon +COBBLER_SERVER="$server" +COBBLER_PORT="$http_port" +COBBLER_NAME="$name" +LOGFILES="/var/log/boot.log /var/log/messages /var/log/dmesg" __EOT__ + #end if
--- kickstarts/sample.ks | 3 +++ kickstarts/sample_end.ks | 3 +++ 2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/kickstarts/sample.ks b/kickstarts/sample.ks index e167a32..b253f8b 100644 --- a/kickstarts/sample.ks +++ b/kickstarts/sample.ks @@ -43,6 +43,7 @@ autopart %pre $kickstart_start $SNIPPET('pre_install_network_config') +# Enable installation monitoring $SNIPPET('pre_anamon')
%packages @@ -59,6 +60,8 @@ $SNIPPET('func_register_if_enabled') $SNIPPET('download_config_files') $SNIPPET('koan_environment') $SNIPPET('redhat_register') +# Enable post-install boot notification +$SNIPPET('post_anamon') # Start final steps $kickstart_done # End final steps diff --git a/kickstarts/sample_end.ks b/kickstarts/sample_end.ks index 7c5464f..0e31823 100644 --- a/kickstarts/sample_end.ks +++ b/kickstarts/sample_end.ks @@ -46,6 +46,7 @@ autopart %pre $kickstart_start $SNIPPET('pre_install_network_config') +# Enable installation monitoring $SNIPPET('pre_anamon') %end
@@ -63,6 +64,8 @@ $SNIPPET('func_register_if_enabled') $SNIPPET('download_config_files') $SNIPPET('koan_environment') $SNIPPET('redhat_register') +# Enable post-install boot notification +$SNIPPET('post_anamon') # Start final steps $kickstart_done # End final steps
Patches merged into devel per request from mdehaan.
Thanks, James
On Thu, 2009-01-22 at 12:16 -0500, James Laska wrote:
Greetings,
The attached patches address several fixes to the anaconda monitoring (anamon) support in cobbler. Several features have also been added, including:
- Adding post_anamon snippet to standard kickstart templates (sample.ks and sample_end.ks)
- Adding a anamon.init used to provide post-install boot notification
Comments welcome.
Thanks, James
cobbler@lists.fedorahosted.org