Only restart services which are enabled.
[mom.git] / swapmon.py
index b25d57f..e2215b2 100755 (executable)
@@ -22,10 +22,6 @@ import pickle
 import socket
 import time
 
-# util-vserver/python/vserver.py allows us to control slices directly
-# from Python
-from vserver import VServer
-
 # bwlimit exports a few useful functions like run(), get_xid(), and get_slice()
 import bwlimit
 
@@ -50,15 +46,6 @@ reset_thresh = 80
 # Swap utilization at which the machine is rebooted
 reboot_thresh = 95
 
-# Time to wait before checking slice again after reset
-reset_timeout = 25
-
-# Number of strikes before killing (strike, strike, kill)
-kill_thresh = 2
-
-# Time to wait before removing slice from kill queue (probation) 
-kill_timeout = 120 
-
 # Don't email the same message more than once in the same emailtimeout interval
 email_timeout = 1800
 
@@ -84,28 +71,6 @@ statistics are not entirely accurate due to threading.
 %(date)s %(hostname)s reboot
 """.lstrip()
 
-# Message sent after a hog is reset
-reset_subject = "pl_mom reset slice %(slice)s on %(hostname)s"
-reset_body = \
-"""
-Sometime before %(date)s, swap space was
-nearly exhausted on %(hostname)s.
-
-Slice %(slice)s was reset since it was the largest consumer of
-physical memory at %(rss)s (%(percent)4.1f%%) (%(sz)s writable).
-
-Please reply to this message explaining the nature of your experiment,
-and what you are doing to address the problem.
-
-http://summer.cs.princeton.edu/status/tabulator.cgi?table=slices/table_%(slice)s
-
-%(slice)s processes prior to reset:
-
-%(table)s
-
-%(date)s %(hostname)s reset %(slice)s
-""".lstrip()
-
 # Message sent to system slices that should not be reset
 alarm_subject = "pl_mom alarm slice %(slice)s on %(hostname)s"
 alarm_body = \
@@ -145,111 +110,10 @@ and what you are doing to address the problem.
 %(date)s %(hostname)s reset %(slice)s
 """.lstrip()
 
+def killsliverprocs(xid):
+    bwlimit.run("/usr/sbin/vkill -s 9 -c %s 0" % xid)    
 
 
-class Reset:
-    """
-    Keeps track of state information for resets and kills
-
-    resettimeleft - timeout before checking for next reset
-    resetcount - number of strikes 
-    killtimeleft - time out before removing from kill queue
-    {kill,reset}mail - Time of last email
-    kill - State of kill.  If slice is already being killed, wait before retry.
-    """
-
-    def __init__(self,name):
-        self.name = name
-        self.resettimeleft = reset_timeout
-        self.resetcount = 0 
-        self.resetmail = 0
-        self.killtimeleft = kill_timeout
-        self.killmail = 0
-
-    def __repr__(self):
-        return self.name
-    
-    def update(self):
-        # Count down for next check of reset slice.
-        if self.resettimeleft > 0:
-           self.resettimeleft -= 1
-           if debug and verbose:  print "%s has %s seconds in probation" \
-                                    %(self.name, self.killtimeleft)
-        if self.killtimeleft > 0:
-            # Count down kill probation timer (killtimeleft)
-            self.killtimeleft -= 1
-            if self.killtimeleft == 1:
-                print "%s is out of probation" % self.name
-        else:
-            # Once out of probation period (killtimeleft), remove strikes
-            self.resetcount = 0
-
-
-    # Check to see if a slice needs to be killed.  If it has been killed more 
-    # than kill_thresh in the probation period (kill_timeout) send an email, kill the slice.
-    def checkkill(self,params):
-        if self.killtimeleft > 0 and self.resetcount >= kill_thresh:
-            if debug:
-                print kill_subject % params
-                print kill_body % params
-            try:
-                pid = os.fork()
-                if pid == 0:
-                   print "Slice %s is being killed." % self.name   
-                   vserver = VServer(self.name)
-                   vserver.stop()
-                   # ignore initscripts.  Don't run anything at start.
-                   vserver.INITSCRIPTS = []
-                   vserver.start()
-                   os._exit(0)
-                else:
-                    os.waitpid(pid,0)
-            except Exception, err:
-                print "Warning: Exception received while killing slice %s: %s" \
-                   % (self.name, err)
-            if (time.time() - self.killmail) > email_timeout:
-                slicemail(self.name, kill_subject % params, kill_body % params)
-                print "Sending KILL email for slice %s" % self.name
-                self.killmail = time.time() 
-            return True
-        return False 
-
-    # Reset slice after checking to see if slice is out of timeout.
-    # Increment resetcount, check to see if larger than kill_thresh.
-    def reset(self, params):
-        # If its the first reset (came back after kill)
-        # or if its been reset before
-        # and we are out of the reset timeout.
-        if self.resetcount == 0 or self.resettimeleft == 0:
-            # Do we need to kill this slice?  Check history first.
-            if self.checkkill(params):  return
-            # Update counters
-            self.resetcount += 1
-            self.killtimeleft = kill_timeout
-            self.resettimeleft = reset_timeout
-            print "%s has %s seconds to die and has been reset %s times" \
-                %(self.name, self.resettimeleft, self.resetcount)
-            if debug:
-                print reset_subject % params
-                print reset_body % params
-            try:
-                pid = os.fork()
-                if pid == 0:  
-                    print "Resetting slice " + self.name 
-                    vserver = VServer(self.name)
-                    vserver.stop()
-                    vserver.start()
-                    os._exit(0)
-                else:
-                    os.waitpid(pid,0)
-            except Exception, err:
-                print "Warning: Exception received while resetting slice %s:" \
-                        % self.name, err
-            if (time.time() - self.resetmail) > email_timeout:
-                slicemail(self.name, reset_subject % params, reset_body % params)
-                print "Sending Reset email for slice %s" % self.name
-                self.resetmail = time.time() 
-
 def usage():
     print """
 Usage: %s [OPTIONS]...
@@ -356,8 +220,10 @@ def slicestat(names = None):
         proc['rss'] += 12
 
         # Include additional page table overhead
-        if proc['vsize'] > 4096:
-            proc['rss'] += 4 * ((proc['vsize'] - 1) / 4096)
+        try:
+            if proc['vsize'] > 4096:
+                proc['rss'] += 4 * ((proc['vsize'] - 1) / 4096)
+        except: pass
 
         if slices.has_key(proc['xid']):
             slice = slices[proc['xid']]
@@ -512,6 +378,11 @@ def main():
     global period, change_thresh, reset_thresh, reboot_thresh, rss_min, system_slices
     # All slices
     names = []
+    timer = period
+    last_used = None
+    used = None
+    warned = []
+    emailed = {}
 
     try:
         longopts = ["debug", "verbose", "file=", "slice=", "status", "help"]
@@ -567,28 +438,11 @@ def main():
 
     # Query process table every 30 seconds, or when a large change in
     # swap utilization is detected.
-    timer = period
-    last_used = None
-    used = None
-
-    # System slices that we have warned but could not reset
-    warned = []
-
-    # Slices that were reset
-    resetlist = {}
 
     while True:
         used = swap_used()
         if last_used is None:  last_used = used
-        
-        # If we've reset you recently, update timers.
-        for resetslice in resetlist.keys(): 
-            resetlist[resetslice].update()
-            # If you've been good, remove you from our list.
-            if resetlist[resetslice].killtimeleft == 0 and \
-            resetlist[resetslice].resettimeleft == 0:
-                del resetlist[resetslice]
-    
+   
         if used >= reboot_thresh:
             # Dump slice state before rebooting
             writedat(slices)    
@@ -628,11 +482,17 @@ def main():
                               alarm_body % params)
                 else:
                     # Reset slice
-                    if not resetlist.has_key(slice['name']):
-                        resetlist[slice['name']] = Reset(slice['name'])
-                    resetlist[slice['name']].reset(params)
-
-        # wait period vefore recalculating swap.  If in danger, recalc.
+                    if not debug:
+                        if emailed.get(slice['name'], (time.time() + email_timeout + 1)) > (time.time() + email_timeout): 
+                            slicemail(slice['name'], kill_subject % params, kill_body % params)
+                            emailed[slice['name']] = time.time()
+                    else:
+                        print kill_subject % params
+                        print kill_body % params
+                    print "Killing procs in %s" % slice['name']
+                    killsliverprocs(slice['xid'])
+
+        # wait period before recalculating swap.  If in danger, recalc.
         if timer <= 0 or used >= (last_used + change_thresh):
             if used >= (last_used + change_thresh):
                 print "%d%% swap consumed, %d%% in last %d seconds" % \