src/nepi/execution/resource.py
[nepi.git] / src / nepi / execution / resource.py
index 0f75e9a..adcb438 100644 (file)
@@ -31,8 +31,6 @@ import sys
 import threading
 import weakref
 
-reschedule_delay = "0.5s"
-
 class ResourceAction:
     """ Action that a user can order to a Resource Manager
    
@@ -47,16 +45,18 @@ class ResourceState:
     """
     NEW = 0
     DISCOVERED = 1
-    PROVISIONED = 2
-    READY = 3
-    STARTED = 4
-    STOPPED = 5
-    FAILED = 6
-    RELEASED = 7
+    RESERVED = 2
+    PROVISIONED = 3
+    READY = 4
+    STARTED = 5
+    STOPPED = 6
+    FAILED = 7
+    RELEASED = 8
 
 ResourceState2str = dict({
     ResourceState.NEW : "NEW",
     ResourceState.DISCOVERED : "DISCOVERED",
+    ResourceState.RESERVED : "RESERVED",
     ResourceState.PROVISIONED : "PROVISIONED",
     ResourceState.READY : "READY",
     ResourceState.STARTED : "STARTED",
@@ -83,7 +83,7 @@ def clsinit(cls):
 
 def clsinit_copy(cls):
     """ Initializes template information (i.e. attributes and traces)
-    on classes direved from the ResourceManager class.
+    on classes derived from the ResourceManager class.
     It differs from the clsinit method in that it forces inheritance
     of attributes and traces from the parent class.
 
@@ -106,7 +106,7 @@ def clsinit_copy(cls):
 def failtrap(func):
     """ Decorator function for instance methods that should set the 
     RM state to FAILED when an error is raised. The methods that must be
-    decorated are: discover, provision, deploy, start, stop.
+    decorated are: discover, reserved, provision, deploy, start, stop.
 
     """
     def wrapped(self, *args, **kwargs):
@@ -129,19 +129,20 @@ class ResourceManager(Logger):
     """ Base clase for all ResourceManagers. 
     
     A ResourceManger is specific to a resource type (e.g. Node, 
-    Switch, Application, etc) on a specific backend (e.g. PlanetLab, 
+    Switch, Application, etc) on a specific platform (e.g. PlanetLab, 
     OMF, etc).
 
     The ResourceManager instances are responsible for interacting with
     and controlling concrete (physical or virtual) resources in the 
-    experimental backends.
+    experimental platforms.
     
     """
     _rtype = "Resource"
     _attributes = None
     _traces = None
     _help = None
-    _backend = None
+    _platform = None
+    _reschedule_delay = "0.5s"
 
     @classmethod
     def _register_attribute(cls, attr):
@@ -212,7 +213,7 @@ class ResourceManager(Logger):
         """ Resource subclasses will invoke this method to register
         resource traces
 
-        This method should be overriden in the RMs that define traces.
+        This method should be overridden in the RMs that define traces.
         
         """
         
@@ -291,12 +292,12 @@ class ResourceManager(Logger):
         return cls._help
 
     @classmethod
-    def get_backend(cls):
-        """ Returns the identified of the backend (i.e. testbed, environment)
+    def get_platform(cls):
+        """ Returns the identified of the platform (i.e. testbed type)
         for the Resource
 
         """
-        return cls._backend
+        return cls._platform
 
     @classmethod
     def get_global(cls, name):
@@ -345,6 +346,7 @@ class ResourceManager(Logger):
         self._start_time = None
         self._stop_time = None
         self._discover_time = None
+        self._reserved_time = None
         self._provision_time = None
         self._ready_time = None
         self._release_time = None
@@ -397,6 +399,11 @@ class ResourceManager(Logger):
         """ Returns the discover time of the RM as a timestamp """
         return self._discover_time
 
+    @property
+    def reserved_time(self):
+        """ Returns the reserved time of the RM as a timestamp """
+        return self._reserved_time
+
     @property
     def provision_time(self):
         """ Returns the provision time of the RM as a timestamp """
@@ -414,7 +421,7 @@ class ResourceManager(Logger):
 
     @property
     def failed_time(self):
-        """ Returns the time failure occured for the RM as a timestamp """
+        """ Returns the time failure occurred for the RM as a timestamp """
         return self._failed_time
 
     @property
@@ -422,6 +429,11 @@ class ResourceManager(Logger):
         """ Get the current state of the RM """
         return self._state
 
+    @property
+    def reschedule_delay(self):
+        """ Returns default reschedule delay """
+        return self._reschedule_delay
+
     def log_message(self, msg):
         """ Returns the log message formatted with added information.
 
@@ -435,7 +447,7 @@ class ResourceManager(Logger):
     def register_connection(self, guid):
         """ Registers a connection to the RM identified by guid
 
-        This method should not be overriden. Specific functionality
+        This method should not be overridden. Specific functionality
         should be added in the do_connect method.
 
         :param guid: Global unique identified of the RM to connect to
@@ -449,7 +461,7 @@ class ResourceManager(Logger):
     def unregister_connection(self, guid):
         """ Removes a registered connection to the RM identified by guid
         
-        This method should not be overriden. Specific functionality
+        This method should not be overridden. Specific functionality
         should be added in the do_disconnect method.
 
         :param guid: Global unique identified of the RM to connect to
@@ -467,7 +479,7 @@ class ResourceManager(Logger):
         This  method is responsible for selecting an individual resource
         matching user requirements.
 
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_discover method.
 
         """
@@ -475,6 +487,21 @@ class ResourceManager(Logger):
             if self._state != ResourceState.RELEASED:
                 self.do_discover()
 
+    @failtrap
+    def reserve(self):
+        """ Performs resource reserve.
+        
+        This  method is responsible for reserving an individual resource
+        matching user requirements.
+
+        This method should not be overridden directly. Specific functionality
+        should be added in the do_reserved method.
+
+        """
+        with self._release_lock:
+            if self._state != ResourceState.RELEASED:
+                self.do_reserve()
+
     @failtrap
     def provision(self):
         """ Performs resource provisioning.
@@ -483,7 +510,7 @@ class ResourceManager(Logger):
         After this method has been successfully invoked, the resource
         should be accessible/controllable by the RM.
 
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_provision method.
 
         """
@@ -491,6 +518,22 @@ class ResourceManager(Logger):
             if self._state != ResourceState.RELEASED:
                 self.do_provision()
 
+    @failtrap
+    def configure(self):
+        """ Performs resource configuration.
+
+        This  method is responsible for configuring one resource.
+        After this method has been successfully invoked, the resource
+        should be set up to start the experimentation.
+
+        This method should not be overridden directly. Specific functionality
+        should be added in the do_configure method.
+
+        """
+        with self._release_lock:
+            if self._state != ResourceState.RELEASED:
+                self.do_configure()
+
     @failtrap
     def start(self):
         """ Starts the RM (e.g. launch remote process).
@@ -498,7 +541,7 @@ class ResourceManager(Logger):
         There is no standard start behavior. Some RMs will not need to perform
         any actions upon start.
 
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_start method.
 
         """
@@ -518,7 +561,7 @@ class ResourceManager(Logger):
         There is no standard stop behavior. Some RMs will not need to perform
         any actions upon stop.
     
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_stop method.
       
         """
@@ -536,7 +579,7 @@ class ResourceManager(Logger):
         This method is responsible for deploying the resource (and invoking 
         the discover and provision methods).
  
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_deploy method.
        
         """
@@ -554,7 +597,7 @@ class ResourceManager(Logger):
         This  method is responsible for releasing resources that were
         used during the experiment by the RM.
 
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_release method.
       
         """
@@ -574,7 +617,7 @@ class ResourceManager(Logger):
     def fail(self):
         """ Sets the RM to state FAILED.
 
-        This method should not be overriden directly. Specific functionality
+        This method should not be overridden directly. Specific functionality
         should be added in the do_fail method.
 
         """
@@ -784,7 +827,7 @@ class ResourceManager(Logger):
 
         """
         reschedule = False
-        delay = reschedule_delay 
+        delay = self.reschedule_delay 
 
         # check state and time elapsed on all RMs
         for guid in group:
@@ -809,7 +852,9 @@ class ResourceManager(Logger):
             if time:
                 if state == ResourceState.DISCOVERED:
                     t = rm.discover_time
-                if state == ResourceState.PROVISIONED:
+                elif state == ResourceState.RESERVED:
+                    t = rm.reserved_time
+                elif state == ResourceState.PROVISIONED:
                     t = rm.provision_time
                 elif state == ResourceState.READY:
                     t = rm.ready_time
@@ -853,7 +898,7 @@ class ResourceManager(Logger):
         """
 
         reschedule = False
-        delay = reschedule_delay 
+        delay = self.reschedule_delay 
 
         ## evaluate if set conditions are met
 
@@ -878,7 +923,7 @@ class ResourceManager(Logger):
         #import pdb;pdb.set_trace()
 
         reschedule = False
-        delay = reschedule_delay 
+        delay = self.reschedule_delay 
 
 
         ## evaluate if conditions to start are met
@@ -920,7 +965,7 @@ class ResourceManager(Logger):
 
         """
         reschedule = False
-        delay = reschedule_delay 
+        delay = self.reschedule_delay 
 
         ## evaluate if conditions to stop are met
         if self.ec.abort:
@@ -953,15 +998,15 @@ class ResourceManager(Logger):
 
         """
         reschedule = False
-        delay = reschedule_delay 
+        delay = self.reschedule_delay 
 
         ## evaluate if conditions to deploy are met
         if self.ec.abort:
             return 
 
         # only can deploy when RM is either NEW, DISCOVERED or PROVISIONED 
-        if self.state not in [ResourceState.NEW, ResourceState.DISCOVERED, 
-                ResourceState.PROVISIONED]:
+        if self.state not in [ResourceState.NEW, ResourceState.DISCOVERED,
+                ResourceState.RESERVED, ResourceState.PROVISIONED]:
             #### XXX: A.Q. IT SHOULD FAIL IF DEPLOY IS CALLED IN OTHER STATES!
             reschedule = True
             self.debug("---- RESCHEDULING DEPLOY ---- state %s " % self.state )
@@ -1018,9 +1063,15 @@ class ResourceManager(Logger):
     def do_discover(self):
         self.set_discovered()
 
+    def do_reserve(self):
+        self.set_reserved()
+
     def do_provision(self):
         self.set_provisioned()
 
+    def do_configure(self):
+        pass
+
     def do_start(self):
         self.set_started()
 
@@ -1073,6 +1124,11 @@ class ResourceManager(Logger):
         self.set_state(ResourceState.DISCOVERED, "_discover_time", time)
         self.debug("----- DISCOVERED ---- ")
 
+    def set_reserved(self, time = None):
+        """ Mark ResourceManager as RESERVED """
+        self.set_state(ResourceState.RESERVED, "_reserved_time", time)
+        self.debug("----- RESERVED ---- ")
+
     def set_provisioned(self, time = None):
         """ Mark ResourceManager as PROVISIONED """
         self.set_state(ResourceState.PROVISIONED, "_provision_time", time)