[haizea-commit] r456 - trunk/src/haizea/resourcemanager

haizea-commit at mailman.cs.uchicago.edu haizea-commit at mailman.cs.uchicago.edu
Mon Aug 4 10:21:55 CDT 2008


Author: borja
Date: 2008-08-04 10:21:55 -0500 (Mon, 04 Aug 2008)
New Revision: 456

Modified:
   trunk/src/haizea/resourcemanager/rm.py
Log:
Allow Haizea to run as a daemon, and include an RPC server

Modified: trunk/src/haizea/resourcemanager/rm.py
===================================================================
--- trunk/src/haizea/resourcemanager/rm.py	2008-08-04 15:20:12 UTC (rev 455)
+++ trunk/src/haizea/resourcemanager/rm.py	2008-08-04 15:21:55 UTC (rev 456)
@@ -35,19 +35,25 @@
 import haizea.common.constants as constants
 from haizea.resourcemanager.frontends.tracefile import TracefileFrontend
 from haizea.resourcemanager.frontends.opennebula import OpenNebulaFrontend
+from haizea.resourcemanager.frontends.rpc import RPCFrontend
 from haizea.resourcemanager.datastruct import ARLease, BestEffortLease, ImmediateLease 
 from haizea.resourcemanager.resourcepool import ResourcePool
 from haizea.resourcemanager.scheduler import Scheduler
+from haizea.resourcemanager.rpcserver import RPCServer
 from haizea.resourcemanager.log import Logger
 from haizea.common.utils import abstract, roundDateTime
 
 import operator
 import signal
-import sys
+import sys, os
 from time import sleep
 from math import ceil
 from mx.DateTime import now, TimeDelta
 
+DAEMON_STDOUT = DAEMON_STDIN = "/dev/null"
+DAEMON_STDERR = "/var/tmp/haizea.err"
+DEFAULT_LOGFILE = "/var/tmp/haizea.log"
+
 class ResourceManager(object):
     """The resource manager
     
@@ -57,58 +63,115 @@
     
     """
     
-    def __init__(self, config):
+    def __init__(self, config, daemon=False, pidfile=None):
         """Initializes the resource manager.
         
         Argument:
         config -- a populated instance of haizea.common.config.RMConfig
-        
+        daemon -- True if Haizea must run as a daemon, False if it must
+                  run in the foreground
+        pidfile -- When running as a daemon, file to save pid to
         """
         self.config = config
         
         # Create the RM components
-
-        # Common components
-        self.logger = Logger(self)
         
-        # Mode-specific components
         mode = config.getMode()
+        clock = config.getClock()
 
-        if mode == "simulated":
+        if mode == "simulated" and clock == constants.CLOCK_SIMULATED:
+            # Simulations always run in the foreground
+            self.daemon = False
+            # Logger
+            self.logger = Logger(self)
             # The clock
             starttime = config.getInitialTime()
             self.clock = SimulatedClock(self, starttime)
+            self.rpc_server = None
+        elif mode == "opennebula" or (mode == "simulated" and clock == constants.CLOCK_REAL):
+            self.daemon = daemon
+            self.pidfile = pidfile
+            # Logger
+            if daemon:
+                self.logger = Logger(self, DEFAULT_LOGFILE)
+            else:
+                self.logger = Logger(self)
 
-            # Resource pool
-            self.resourcepool = ResourcePool(self)
-        
-            # Scheduler
-            self.scheduler = Scheduler(self)
-    
-            # Lease request frontends
-            # In simulation, we can only use the tracefile frontend
-            self.frontends = [TracefileFrontend(self, self.clock.get_start_time())]
-        elif mode == "opennebula":
-            
             # The clock
             wakeup_interval = config.get_wakeup_interval()
             non_sched = config.get_non_schedulable_interval()
             self.clock = RealClock(self, wakeup_interval, non_sched)
+            
+            # RPC server
+            self.rpc_server = RPCServer(self)
+
+        # Resource pool
+        self.resourcepool = ResourcePool(self)
     
-            # Resource pool
-            self.resourcepool = ResourcePool(self)
+        # Scheduler
+        self.scheduler = Scheduler(self)
     
-            # Scheduler
-            self.scheduler = Scheduler(self)
-
-            # Lease request frontends
-            # TODO: Get this from config file
+        # Lease request frontends
+        if mode == "simulated" and clock == constants.CLOCK_SIMULATED:
+            # In pure simulation, we can only use the tracefile frontend
+            self.frontends = [TracefileFrontend(self, self.clock.get_start_time())]
+        elif mode == "simulated" and clock == constants.CLOCK_REAL:
+            # In simulation with a real clock, only the RPC frontend can be used
+            self.frontends = [RPCFrontend(self)]
+        elif mode == "opennebula":
             self.frontends = [OpenNebulaFrontend(self)]
-
+            
         # Statistics collection 
         self.stats = stats.StatsCollection(self, self.config.getDataFile())
 
+    def daemonize(self):
+        """Daemonizes the Haizea process.
         
+        Based on code in:  http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
+        
+        """
+        # First fork
+        try:
+            pid = os.fork()
+            if pid > 0: 
+                # Exit first parent
+                sys.exit(0) 
+        except OSError, e:
+            sys.stderr.write("Failed to daemonize Haizea: (%d) %s\n" % (e.errno, e.strerror))
+            sys.exit(1)
+    
+        # Decouple from parent environment.
+        os.chdir(".")
+        os.umask(0)
+        os.setsid()
+    
+        # Second fork
+        try:
+            pid = os.fork()
+            if pid > 0: 
+                # Exit second parent.
+                sys.exit(0) 
+        except OSError, e:
+            sys.stderr.write("Failed to daemonize Haizea: (%d) %s\n" % (e.errno, e.strerror))
+            sys.exit(2)
+            
+        # Open file descriptors and print start message
+        si = file(DAEMON_STDIN, 'r')
+        so = file(DAEMON_STDOUT, 'a+')
+        se = file(DAEMON_STDERR, 'a+', 0)
+        pid = os.getpid()
+        sys.stderr.write("\nStarted Haizea daemon with pid %i\n\n" % pid)
+        sys.stderr.flush()
+        file(self.pidfile,'w+').write("%i\n" % pid)
+        
+        # Redirect standard file descriptors.
+        os.close(sys.stdin.fileno())
+        os.close(sys.stdout.fileno())
+        os.close(sys.stderr.fileno())
+        os.dup2(si.fileno(), sys.stdin.fileno())
+        os.dup2(so.fileno(), sys.stdout.fileno())
+        os.dup2(se.fileno(), sys.stderr.fileno())
+
     def start(self):
         """Starts the resource manager"""
         self.logger.status("Starting resource manager", constants.RM)
@@ -123,6 +186,10 @@
         self.stats.create_counter(constants.COUNTER_DISKUSAGE, constants.AVERAGE_NONE)
         self.stats.create_counter(constants.COUNTER_CPUUTILIZATION, constants.AVERAGE_TIMEWEIGHTED)
         
+        if self.daemon:
+            self.daemonize()
+        if self.rpc_server:
+            self.rpc_server.start()
         # Start the clock
         self.clock.run()
         
@@ -244,18 +311,9 @@
         """Return True if there are any leases still "in the system" """
         return self.scheduler.exists_scheduled_leases() or not self.scheduler.is_queue_empty()
     
-    # TODO: Replace this with a more general event handling system
-    def notify_end_vm(self, lease, rr):
-        """Notifies the resource manager that a VM has ended prematurely.
-        
-        This message is passed along to the scheduler.
-        
-        Arguments:
-        lease -- Lease the VM belongs to
-        rr    -- Resource reservations where the premature end happened"""
-        self.scheduler.notify_premature_end_vm(lease, rr)
+    def notify_event(self, lease, event):
+        pass
 
-
     def cancel_lease(self, lease):
         """Cancels a lease.
         



More information about the Haizea-commit mailing list