fixed deletion logic. ..this is sloppy but it works. Also fixed network shares.
[nodemanager.git] / bwmon.py
index c3fe1d5..ad860be 100644 (file)
--- a/bwmon.py
+++ b/bwmon.py
@@ -32,26 +32,22 @@ import database
 
 from sets import Set
 
+# Defaults
+debug = False
+verbose = False
+datafile = "/var/lib/misc/bwmon.dat"
+
 try:
     sys.path.append("/etc/planetlab")
     from plc_config import *
 except:
     logger.log("bwmon:  Warning: Configuration file /etc/planetlab/plc_config.py not found")
-    PLC_NAME = "PlanetLab"
-    PLC_SLICE_PREFIX = "pl"
-    PLC_MAIL_SUPPORT_ADDRESS = "support@planet-lab.org"
-    PLC_MAIL_SLICE_ADDRESS = "SLICE@slices.planet-lab.org"
+    logger.log("bwmon:  Running in DEBUG mode.  Logging to file and not emailing.")
 
 # Constants
 seconds_per_day = 24 * 60 * 60
 bits_per_byte = 8
 
-# Defaults
-debug = True
-verbose = False
-datafile = "/var/lib/misc/bwmon.dat"
-#nm = None
-
 # Burst to line rate (or node cap).  Set by NM. in KBit/s
 default_MaxRate = int(bwlimit.get_bwcap() / 1000)
 default_Maxi2Rate = int(bwlimit.bwmax / 1000)
@@ -133,11 +129,8 @@ def slicemail(slice, subject, body):
 
     sendmail = os.popen("/usr/sbin/sendmail -N never -t -f%s" % PLC_MAIL_SUPPORT_ADDRESS, "w")
 
-    # PLC has a separate list for pl_mom messages
-    if PLC_MAIL_SUPPORT_ADDRESS == "support@planet-lab.org":
-        to = ["pl-mom@planet-lab.org"]
-    else:
-        to = [PLC_MAIL_SUPPORT_ADDRESS]
+    # Parsed from MyPLC config
+    to = [PLC_MAIL_MOM_LIST_ADDRESS]
 
     if slice is not None and slice != "root":
         to.append(PLC_MAIL_SLICE_ADDRESS.replace("SLICE", slice))
@@ -197,9 +190,9 @@ class Slice:
         self.Maxi2Rate = default_Maxi2Rate
         self.Mini2Rate = default_Mini2Rate
         self.MaxKByte = default_MaxKByte
-        self.ThreshKByte = default_ThreshKByte
+        self.ThreshKByte = (.8 * self.MaxKByte)
         self.Maxi2KByte = default_Maxi2KByte
-        self.Threshi2KByte = default_Threshi2KByte
+        self.Threshi2KByte = (.8 * self.Maxi2KByte)
         self.Share = default_Share
         self.Sharei2 = default_Share
         self.emailed = False
@@ -312,7 +305,7 @@ class Slice:
                 minexemptrate = self.Mini2Rate * 1000,
                 share = self.Share)
 
-    def notify(self, new_maxrate, new_maxexemptrate, usedbytes, usedi2bytes)
+    def notify(self, new_maxrate, new_maxexemptrate, usedbytes, usedi2bytes):
         """
         Notify the slice it's being capped.
         """
@@ -322,8 +315,9 @@ class Slice:
                   'since': time.asctime(time.gmtime(self.time)) + " GMT",
                   'until': time.asctime(time.gmtime(self.time + period)) + " GMT",
                   'date': time.asctime(time.gmtime()) + " GMT",
-                  'period': format_period(period)} 
-        if new_maxrate ! = self.MaxRate:
+                  'period': format_period(period)}
+
+        if new_maxrate != self.MaxRate:
             # Format template parameters for low bandwidth message
             params['class'] = "low bandwidth"
             params['bytes'] = format_bytes(usedbytes - self.bytes)
@@ -355,7 +349,7 @@ class Slice:
                 slicemail(self.name, subject, message + (footer % params))
 
 
-    def update(self, runningmaxrate, runningmaxi2rate, usedbytes, usedi2bytes, rspec):
+    def update(self, runningmaxrate, runningmaxi2rate, usedbytes, usedi2bytes, runningshare, rspec):
         """
         Update byte counts and check if byte thresholds have been
         exceeded. If exceeded, cap to  remaining bytes in limit over remaining in period.  
@@ -364,7 +358,17 @@ class Slice:
     
         # Query Node Manager for max rate overrides
         self.updateSliceAttributes(rspec)    
-     
+
+        # Check shares for Sirius loans.
+        if runningshare != self.Share:
+            logger.log("bwmon:  Updating share to %s" % self.share)
+            bwlimit.set(xid = self.xid, 
+                minrate = self.MinRate * 1000, 
+                maxrate = self.MaxRate * 1000, 
+                maxexemptrate = self.Maxi2Rate * 1000,
+                minexemptrate = self.Mini2Rate * 1000,
+                share = self.Share)
+
         # Prepare message parameters from the template
         #message = ""
         #params = {'slice': self.name, 'hostname': socket.gethostname(),
@@ -555,15 +559,22 @@ def sync(nmdbcopy):
     for nohtbslice in nohtbslices:
         if live.has_key(nohtbslice): 
             slices[nohtbslice].reset( 0, 0, 0, 0, live[nohtbslice]['_rspec'] )
+        else:
+            logger.log("bwmon:  Removing abondoned slice %s from dat." % nohtbslice)
+            del slices[nohtbslice]
 
-    # The dat file doesnt have HTB for the slice, but slice is running and
-    # HTB exists
+    # The dat file doesnt have HTB for the slice but kern has HTB
     slicesnodat = Set(kernelhtbs.keys()) - Set(slices.keys())
     logger.log( "bwmon: Found %s slices with HTBs but not in dat" % slicesnodat.__len__() )
     for slicenodat in slicesnodat:
-        slices[slicenodat] = Slice(slicenodat, 
-                                   live[slicenodat]['name'], 
-                                   live[slicenodat]['_rspec'])
+        # But slice is running 
+        if live.has_key(slicenodat): 
+            # init the slice.  which means start accounting over since kernel
+            # htb was already there.
+            slices[slicenodat] = Slice(slicenodat, 
+                live[slicenodat]['name'], 
+                live[slicenodat]['_rspec'])
+        else: bwlimit.off(slicenodat) # Abandoned.  it doesnt exist at PLC or the dat
 
     # Get new slices.
     # Slices in GetSlivers but not running HTBs
@@ -599,35 +610,36 @@ def sync(nmdbcopy):
                                     deadslice['slice'].Maxi2Rate, 
                                     deadslice['htb']['usedbytes'], 
                                     deadslice['htb']['usedi2bytes'], 
+                                    deadslice['htb']['share'], 
                                     live[newslice]['_rspec'])
                 # Since the slice has been reinitialed, remove from dead database.
-                del deaddb[deadslice]
+                del deaddb[deadslice['slice'].name]
         else:
-            logger.log("bwmon  Slice %s doesn't have xid.  Must be delegated."\
-                       "Skipping." % live[newslice]['name'])
+            logger.log("bwmon  Slice %s doesn't have xid.  Skipping." % live[newslice]['name'])
 
     # Move dead slices that exist in the pickle file, but
     # aren't instantiated by PLC into the dead dict until
     # recording period is over.  This is to avoid the case where a slice is dynamically created
     # and destroyed then recreated to get around byte limits.
     deadxids = Set(slices.keys()) - Set(live.keys())
-    logger.log("bwmon:  Found %s dead slices" % (dead.__len__() - 2))
+    logger.log("bwmon:  Found %s dead slices" % (deadxids.__len__() - 2))
     for deadxid in deadxids:
         if deadxid == root_xid or deadxid == default_xid:
             continue
-        logger.log("bwmon:  removing dead slice  %s " % deadxid)
-        if slices.has_key(deadxid):
+        logger.log("bwmon:  removing dead slice %s " % deadxid)
+        if slices.has_key(deadxid) and kernelhtbs.has_key(deadxid):
             # add slice (by name) to deaddb
+            logger.log("bwmon:  Saving bandwidth totals for %s." % slices[deadxid].name)
             deaddb[slices[deadxid].name] = {'slice': slices[deadxid], 'htb': kernelhtbs[deadxid]}
             del slices[deadxid]
         if kernelhtbs.has_key(deadxid): 
-            bwlimit.off(xid)
+            bwlimit.off(deadxid)
        
        # Clean up deaddb
-       for (deadslice, deadhtb) in deaddb.iteritems():
-               if (time.time() >= (deadslice.time() + period)):
+       for deadslice in deaddb.itervalues():
+               if (time.time() >= (deadslice['slice'].time + period)):
                        logger.log("bwmon: Removing dead slice %s from dat." % deadslice.name)
-                       del deaddb[deadslice.name]
+                       del deaddb[deadslice['slice'].name]
 
     # Get actual running values from tc since we've added and removed buckets.
     # Update slice totals and bandwidth. {xid: {values}}
@@ -659,6 +671,7 @@ def sync(nmdbcopy):
                 kernelhtbs[xid]['maxexemptrate'], \
                 kernelhtbs[xid]['usedbytes'], \
                 kernelhtbs[xid]['usedi2bytes'], \
+                kernelhtbs[xid]['share'],
                 live[xid]['_rspec'])
 
     logger.log("bwmon:  Saving %s slices in %s" % (slices.keys().__len__(),datafile))