summaryrefslogtreecommitdiffstats
path: root/aux/anamon.py
diff options
context:
space:
mode:
Diffstat (limited to 'aux/anamon.py')
-rw-r--r--aux/anamon.py263
1 files changed, 263 insertions, 0 deletions
diff --git a/aux/anamon.py b/aux/anamon.py
new file mode 100644
index 00000000..fe4d0eb6
--- /dev/null
+++ b/aux/anamon.py
@@ -0,0 +1,263 @@
+#!/usr/bin/python
+
+"""
+This is a script used to automatically log details from an Anaconda
+install back to a cobbler server.
+
+Copyright 2008, Red Hat, Inc
+various@redhat.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+"""
+
+import os
+import sys
+import string
+import time
+import re
+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
+ self.alias = alias
+ self.reset()
+
+ def reset(self):
+ self.where = 0
+ self.last_size = 0
+ self.lfrag=''
+ self.re_list={}
+ self.seen_line={}
+
+ def exists(self):
+ return os.access(self.fn, os.F_OK)
+
+ def lookfor(self,pattern):
+ self.re_list[pattern] = re.compile(pattern,re.MULTILINE)
+ self.seen_line[pattern] = 0
+
+ def seen(self,pattern):
+ if self.seen_line.has_key(pattern):
+ return self.seen_line[pattern]
+ else:
+ return 0
+
+ def changed(self):
+ if not self.exists():
+ return 0
+ size = os.stat(self.fn)[6]
+ if size > self.last_size:
+ self.last_size = size
+ return 1
+ else:
+ return 0
+
+ def uploadWrapper(self, blocksize = 262144):
+ """upload a file in chunks using the uploadFile call"""
+ retries = 3
+ fo = file(self.fn, "r")
+ totalsize = os.path.getsize(self.fn)
+ ofs = 0
+ while True:
+ lap = time.time()
+ contents = fo.read(blocksize)
+ size = len(contents)
+ data = base64.encodestring(contents)
+ if size == 0:
+ offset = -1
+ sz = ofs
+ else:
+ offset = ofs
+ sz = size
+ del contents
+ tries = 0
+ while tries <= retries:
+ debug("upload_log_data('%s', '%s', %s, %s, ...)\n" % (name, self.alias, sz, offset))
+ if session.upload_log_data(name, self.alias, sz, offset, data):
+ break
+ else:
+ tries = tries + 1
+ if size == 0:
+ break
+ ofs += size
+ fo.close()
+
+ def update(self):
+ if not self.exists():
+ return
+ if not self.changed():
+ return
+ try:
+ self.uploadWrapper()
+ except:
+ raise
+
+class MountWatcher:
+
+ def __init__(self,mp):
+ self.mountpoint = mp
+ self.zero()
+
+ def zero(self):
+ self.line=''
+ self.time = time.time()
+
+ def update(self):
+ fd = open('/proc/mounts')
+ found = 0
+ while 1:
+ line = fd.readline()
+ if not line:
+ break
+ parts = string.split(line)
+ mp = parts[1]
+ if mp == self.mountpoint:
+ found = 1
+ if line != self.line:
+ self.line = line
+ self.time = time.time()
+ if not found:
+ self.zero()
+ fd.close()
+
+ def stable(self):
+ self.update()
+ if self.line and (time.time() - self.time > 60):
+ return 1
+ else:
+ return 0
+
+def anamon_loop():
+ alog = WatchedFile("/tmp/anaconda.log", "anaconda.log")
+ alog.lookfor("step installpackages$")
+
+ slog = WatchedFile("/tmp/syslog", "sys.log")
+ llog = WatchedFile("/tmp/lvmout", "lvmout.log")
+ kcfg = WatchedFile("/tmp/ks.cfg", "ks.cfg")
+ scrlog = WatchedFile("/tmp/ks-script.log", "ks-script.log")
+ dump = WatchedFile("/tmp/anacdump.txt", "anacdump.txt")
+ mod = WatchedFile("/tmp/modprobe.conf", "modprobe.conf")
+ ilog = WatchedFile("/mnt/sysimage/root/install.log", "install.log")
+ ilog2 = WatchedFile("/mnt/sysimage/tmp/install.log", "tmp+install.log")
+ ulog = WatchedFile("/mnt/sysimage/root/upgrade.log", "upgrade.log")
+ ulog2 = WatchedFile("/mnt/sysimage/tmp/upgrade.log", "tmp+upgrade.log")
+ sysimage = MountWatcher("/mnt/sysimage")
+
+ # 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)
+
+ # 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
+
+# Establish some defaults
+name = ""
+server = ""
+port = "80"
+daemon = 1
+debug = lambda x,**y: None
+watchfiles = []
+exit = False
+
+# Process command-line args
+n = 0
+while n < len(sys.argv):
+ arg = sys.argv[n]
+ if arg == '--name':
+ n = n+1
+ name = sys.argv[n]
+ elif arg == '--watchfile':
+ n = n+1
+ watchfiles.extend(shlex.split(sys.argv[n]))
+ elif arg == '--exit':
+ exit = True
+ elif arg == '--server':
+ n = n+1
+ server = sys.argv[n]
+ elif arg == '--port':
+ n = n+1
+ port = sys.argv[n]
+ elif arg == '--debug':
+ debug = lambda x,**y: sys.stderr.write(x % y)
+ elif arg == '--fg':
+ 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(0)
+else:
+ anamon_loop()
+