add a new rpm package for monitor-runlevelagent that packages RunlevelAgent.py
authorStephen Soltesz <soltesz@cs.princeton.edu>
Wed, 18 Feb 2009 18:39:52 +0000 (18:39 +0000)
committerStephen Soltesz <soltesz@cs.princeton.edu>
Wed, 18 Feb 2009 18:39:52 +0000 (18:39 +0000)
in the root context, and with which the bootmanager build script can pull in
the script to run at boot time.

Monitor.spec
RunlevelAgent.py [new file with mode: 0644]
monitor-runlevel.init [new file with mode: 0644]

index efca5fe..192c10b 100644 (file)
@@ -77,15 +77,26 @@ as Zabbix DB.
 ######################################## PCU Control
 
 %package pcucontrol
-Summary: PCU Controls for Monitor and PLCAPI
-Group: Applications/System
-Requires: python
+summary: pcu controls for monitor and plcapi
+group: applications/system
+requires: python
 
 %description pcucontrol
-Both Monitor and the PLCAPI use a set of common commands to reboot machines
-using their external or internal PCUs.  This package is a library of several
+both monitor and the plcapi use a set of common commands to reboot machines
+using their external or internal pcus.  this package is a library of several
 supported models.
 
+####################################### RunlevelAgent
+%package runlevelagent
+summary: the RunlevelAgent that reports node runlevels
+group: applications/system
+requires: python
+
+%description runlevelagent
+The RunlevelAgent starts as early as possible during boot-up and production
+mode to actively report the observed runlevel to PLC and update the
+'last_contact' field.
+
 %prep
 %setup -q
 
@@ -141,6 +152,11 @@ chmod 777 $RPM_BUILD_ROOT/var/www/cgi-bin/monitor/monitorconfig.php
 #install -D -m 755 monitor-default.conf $RPM_BUILD_ROOT/etc/monitor.conf
 #cp $RPM_BUILD_ROOT/usr/share/%{name}/monitorconfig-default.py $RPM_BUILD_ROOT/usr/share/%{name}/monitorconfig.py
 
+#################### RunlevelAgent
+install -D -m 755 RunlevelAgent.py $RPM_BUILD_ROOT/usr/bin/RunlevelAgent.py
+install -D -m 755 monitor-runlevelagent.init $RPM_BUILD_ROOT/%{_initrddir}/monitor-runlevelagent
+
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -167,6 +183,10 @@ rm -rf $RPM_BUILD_ROOT
 %files pcucontrol
 %{python_sitearch}/pcucontrol
 
+%files runlevelagent
+/usr/bin/RunlevelAgent.py
+/%{_initrddir}/monitor-runlevelagent
+
 %post server
 # TODO: this will be nice when we have a web-based service running., such as
 #              an API server or so on.
@@ -189,6 +209,10 @@ patch -d /var/www/html/zabbix/ -p0 < /usr/share/%{name}/zabbix/zabbix-auto-login
 chkconfig --add monitor
 chkconfig monitor on
 
+%post runlevelagent
+chkconfig --add monitor-runlevelagent
+chkconfig monitor-runlevelagent on
+
 %changelog
 * Mon Jan 05 2009 Stephen Soltesz <soltesz@cs.princeton.edu> - Monitor-2.0-0
 - new changes are significantly different, that I'm upping the number for clarity.
diff --git a/RunlevelAgent.py b/RunlevelAgent.py
new file mode 100644 (file)
index 0000000..49fa631
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+import xml, xmlrpclib
+import logging
+import time
+import traceback
+import sys
+import os
+import string
+
+CONFIG_FILE="/tmp/source/configuration"
+SESSION_FILE="/etc/planetlab/session"
+
+def read_config_file(filename):
+    ## NOTE: text copied from BootManager.py 
+       # TODO: unify this code to make it common. i.e. use ConfigParser module
+    vars = {}
+    vars_file= file(filename,'r')
+    validConfFile = True
+    for line in vars_file:
+        # if its a comment or a whitespace line, ignore
+        if line[:1] == "#" or string.strip(line) == "":
+            continue
+
+        parts= string.split(line,"=")
+        if len(parts) != 2:
+            print "Invalid line in vars file: %s" % line
+            validConfFile = False
+            break
+
+        name= string.strip(parts[0])
+        value= string.strip(parts[1])
+        vars[name]= value
+
+    vars_file.close()
+    if not validConfFile:
+        print "Unable to read configuration vars."
+
+    return vars
+
+try:
+    sys.path = ['/etc/planetlab'] + sys.path
+    import plc_config
+    api_server_url = "https://" + plc_config.PLC_API_HOST + plc_config.PLC_API_PATH
+except:
+    filename=CONFIG_FILE
+    vars = read_config_file(filename)
+    api_server_url = vars['BOOT_API_SERVER']
+
+
+class Auth:
+       def __init__(self, username=None, password=None, **kwargs):
+               if 'session' in kwargs:
+                       self.auth= { 'AuthMethod' : 'session',
+                                       'session' : kwargs['session'] }
+               else:
+                       if username==None and password==None:
+                               self.auth = {'AuthMethod': "anonymous"}
+                       else:
+                               self.auth = {'Username' : username,
+                                                       'AuthMethod' : 'password',
+                                                       'AuthString' : password}
+class PLC:
+       def __init__(self, auth, url):
+               self.auth = auth
+               self.url = url
+               self.api = xmlrpclib.Server(self.url, verbose=False, allow_none=True)
+
+       def __getattr__(self, name):
+               method = getattr(self.api, name)
+               if method is None:
+                       raise AssertionError("method does not exist")
+
+               return lambda *params : method(self.auth.auth, *params)
+
+       def __repr__(self):
+               return self.api.__repr__()
+
+def main():
+
+    f=open(SESSION_FILE,'r')
+    session_str=f.read().strip()
+    api = PLC(Auth(session=session_str), api_server_url)
+    # NOTE: should we rely on bootmanager for this functionality?
+    api.AuthCheck()
+
+    while True:
+        print "reporting status: ", os.popen("uptime").read().strip()
+        try:
+            # NOTE: alternately, check other stuff in the environment to infer
+            # run_level
+            #     is BootManager running?
+            #     what is the boot_state at PLC?
+            #     does /vservers exist?
+            #     what about /tmp/source?
+            #     is BootManager in /tmp/source?
+            #     is /tmp/mnt/sysimg mounted?
+            #     how long have we been running?  if we were in safeboot and
+            #       still running, we're likely in failboot now.
+            #     length of runtime increases the certainty of inferred state.
+            #     
+            api.ReportRunlevel({'run_level' : 'safeboot'})
+        except:
+            traceback.print_exc()
+        time.sleep(30)
+
+if __name__ == "__main__":
+    main()
diff --git a/monitor-runlevel.init b/monitor-runlevel.init
new file mode 100644 (file)
index 0000000..f22d587
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# monitor-runlevelagent starts the RunlevelAgent in production mode.
+#
+# Load before nm, vcached, and vservers, vserver-reference
+# chkconfig: 3 14 85
+# description: Start RunlevelAgent to report the current Runlevel to PLC at
+#              periodic intervals.
+#
+# Stephen Soltesz <soltesz@cs.princeton.edu>
+# Copyright (C) 2008 The Trustees of Princeton University
+#
+# $Id$
+#
+
+case "$1" in
+    start|restart|reload)
+       ;;
+    stop|status)
+       exit 0
+       ;;
+    *)
+       echo $"Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+
+# NOTE: If user already exists, this just exists with status 9.  I think it's
+# ok to simply let this command check and error out.
+# Parse PLC configuration
+if [ -r /etc/planetlab/plc_config ] ; then
+    . /etc/planetlab/plc_config
+else
+    PLC_NAME="PlanetLab"
+    PLC_SLICE_PREFIX="pl"
+    PLC_BOOT_HOST="boot.planet-lab.org"
+fi
+
+USER="${PLC_SLICE_PREFIX}_monitor"
+/usr/sbin/useradd -p "" -m $USER &> /dev/null || : 
+
+if [ ! -d /home/$USER/.ssh ] ; then
+       mkdir /home/$USER/.ssh
+       chmod 700 /home/$USER/.ssh
+       chown $USER.$USER /home/$USER/.ssh
+fi
+
+URL="http://${PLC_BOOT_HOST}/PlanetLabConf/keys.php?$USER"
+curl -s "$URL" > /home/$USER/.ssh/authorized_keys
+chown $USER.$USER /home/$USER/.ssh/authorized_keys