Cleaning up RM template
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Sat, 20 Dec 2014 11:58:14 +0000 (12:58 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Sat, 20 Dec 2014 11:58:14 +0000 (12:58 +0100)
doc/templates/template_rm.py
src/nepi/execution/resource.py

index 8a95124..6eb0222 100644 (file)
 #          Julien Tribino <julien.tribino@inria.fr>
 
 
-
 from nepi.execution.attribute import Attribute, Flags, Types
 from nepi.execution.resource import ResourceManager, clsinit_copy, \
-        ResourceState, reschedule_delay
-
-#import time
-#import threading
+        ResourceState
 
-#clsinit_copy is used to copy the attirbute from parent class
+#clsinit_copy is used to inherit attributes from the parent class
 @clsinit_copy
-class RMName(ResourceManager):
-        
-    _rtype = "RMName" # Name that will be used in the Experiment Description Script 
-    _help = "Help that describe the RM"
-    _backend_type = "backend" # Name of the platform this RM is attached. 
-    _authorized_connections = ["RMName1" , "RMName2"] # list of valid connection for this RM
-
+class RMClass(ResourceManager):
+    # Name that will be used in the NEPI script to identify the resource type
+    _rtype = "platform::RMType" 
+    # User friendly description of the RM 
+    _help = "Describes what this RM does"
+    # Name of the platform this RM belongs to 
+    _platform = "platform" 
+    # list of valid connection for this RM
+    _authorized_connections = ["platform::AnotherRMType1" , "platform::AnotherRMType2"] 
 
     @classmethod
     def _register_attributes(cls):
-    '''
+        """
         This method is used to register all the attribute of this RM. Check the
         file src/execution/attribute.py to see all the fields of this class
-    '''
+        """
 
-        attribute1 = Attribute("nameOfAttribute1", "Description of the Attribute 1",
+        attribute1 = Attribute("nameOfAttribute1", "Description of Attribute 1",
                 flags = Flags.Design)
 
-        attribute2 = Attribute("nameOfAttribute2", "Description of the Attribute 2",
+        attribute2 = Attribute("nameOfAttribute2", "Description of Attribute 2",
                 flags = Flags.Design)
 
         cls._register_attribute(attribute1)
         cls._register_attribute(attribute2)
 
     def __init__(self, ec, guid):
-    '''
-        In the init, we usually intialize the variable of the RM that are not attribute
-    '''
-
-        super(RMName, self).__init__(ec, guid)
-
-        self.var1 = None
-
+        """
+        Declares and initializes variables of the RM that are not Attributes.
+        Attributes represent resource configuration exposed to the user, 
+        other class variables can declared here for RM internal use.
+        """
+        
+        super(RMClass, self).__init__(ec, guid)
     
     def log_message(self, msg):
-    '''
-        In some particular cases, it is required to redefined the log of the RM.
-        The default log require the name of the node, but sometimes, 
-        it does not mean something.
-    '''
-        return " guid %d - host %s - %s " % (self.guid, 
-                self.get("hostname"), msg)
+        """
+        Prints a log message adding a identification prefix.
 
+        The log message for the RMClass can be redefined here. 
+        It can be used to add information about related resources such as
+        the hostname of the node RM associated to an application RM.
+        """
+        
+        return " %s guid %d - %s " % (self._rtype, self.guid, msg)
 
     def valid_connection(self, guid):
-    '''
-        Check if the connection is valide or not, depending on the list povided in the parameter
-        _authorized_connection described above
-    '''
+        """
+        Checks whether the RMClass instance can be connected to the 
+        other RM corresponding to the given guid.
+        """
+        
+        rm = self.ec.get_resource(guid)
+
+        if rm.get_rtype() not in self._authorized_connections:
+            msg = ("Connection between %s %s and %s %s refused: "
+                    "An Application can be connected only to a Node" ) % \
+                (self.get_rtype(), self._guid, rm.get_rtype(), guid)
+
+            return False
+
+        elif len(self.connections) != 0 :
+            msg = ("Connection between %s %s and %s %s refused: "
+                    "This Application is already connected" ) % \
+                (self.get_rtype(), self._guid, rm.get_rtype(), guid)
+            self.debug(msg)
+
+            return False
+
         return True
 
-    # This one is not mandatory
     def do_discover(self):
-    '''
-        Do anything required to discover the resource.The meaning of discover
-        is different for each RM 
-    '''
-        super(RMName, self).do_discover()
+        """
+        Perform actions required to discover resources matching some criteria
+        specified by the user through the configuration of Attributes. 
+        """
+        
+        super(RMClass, self).do_discover()
+
+    def do_reserve(self):
+        """
+        Perform actions required to reserve resources matching some criteria
+        specified by the user through the configuration of Attributes. 
+        """
+        
+        super(RMClass, self).do_reserve()
 
-    # This one is not mandatory
     def do_provision(self):
-    '''
-        Do anything required to provision the resource.The meaning of provision
-        is different for each RM 
-    '''
-        super(RMName, self).do_provision()
+        """
+        Perform actions required to provision a resource in the platform,
+        matching the criteria specified by the user.
+        """
+
+        super(RMClass, self).do_provision()
 
     def do_deploy(self):
-    '''
-        Do anything required to deploy the resource.The meaning of deploy 
-        is different for each RM 
-    '''
-        super(RMName, self).do_deploy()
+        """
+        Perform actions required to deploy a resource in the platform.
+        
+        Deploying a resource most frequently involves invoking the 
+        do_discover and do_provision methods. In order to deploy a
+        resource it might be necessary wait until other associated
+        resource is in a given state, as in the following example:
+
+        other_rm_list = self.get_connected(OtherRMClass.get_rtype())
+        other_rm = other_rm_list[0]
 
+        if other_rm.state < ResourceState.READY:
+            self.ec.schedule(self.reschedule_delay, self.deploy)
+        else:
+            self.do_discover()
+            self.do_provision()
+
+            super(RMClass, self).do_deploy()
+        """
+
+        super(RMClass, self).do_deploy()
 
     def do_start(self):
-    '''
-        Do anything required to start the resource.The meaning of start 
-        is different for each RM 
-    '''
-        super(RMName, self).do_release()
+        """
+        Perform actions required to start a resource in the platform.
+        """
 
+        super(RMClass, self).do_start()
 
     def do_stop(self):
-    '''
-        Do anything required to stop the resource.The meaning of stop 
-        is different for each RM 
-    '''
-        super(RMName, self).do_release()
+        """
+        Perform actions required to stop a resource in the platform.
+        """
+
+        super(RMClass, self).do_stop()
 
     def do_release(self):
-    '''
-        Do anything required to release the resource.The meaning of release 
-        is different for each RM 
-    '''
-        super(RMName, self).do_release()
+        """
+        Perform actions required to release a resource in the platform.
+        """
+
+        super(RMClass, self).do_release()
+
+    @property
+    def state(self):
+        """ 
+        Returns the state of the RM.
+        """
+
+        return super(RMClass, self).state
 
 
index f1669d0..16b434f 100644 (file)
@@ -45,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",
@@ -104,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):
@@ -344,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
@@ -396,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 resreved 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 """
@@ -479,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 overriden 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.
@@ -813,7 +836,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
@@ -964,8 +989,8 @@ class ResourceManager(Logger):
             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 )
@@ -1022,6 +1047,9 @@ class ResourceManager(Logger):
     def do_discover(self):
         self.set_discovered()
 
+    def do_reserve(self):
+        self.set_reserved()
+
     def do_provision(self):
         self.set_provisioned()
 
@@ -1077,6 +1105,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)