Fixing tickets: http://nepi.pl.sophia.inria.fr/trac/ticket/66 (TAP device fails to...
[nepi.git] / src / nepi / execution / resource.py
index ed16e08..be80329 100644 (file)
@@ -51,9 +51,8 @@ class ResourceState:
     READY = 3
     STARTED = 4
     STOPPED = 5
-    FINISHED = 6
-    FAILED = 7
-    RELEASED = 8
+    FAILED = 6
+    RELEASED = 7
 
 ResourceState2str = dict({
     ResourceState.NEW : "NEW",
@@ -62,7 +61,6 @@ ResourceState2str = dict({
     ResourceState.READY : "READY",
     ResourceState.STARTED : "STARTED",
     ResourceState.STOPPED : "STOPPED",
-    ResourceState.FINISHED : "FINISHED",
     ResourceState.FAILED : "FAILED",
     ResourceState.RELEASED : "RELEASED",
     })
@@ -108,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 and finish.
+    decorated are: discover, provision, deploy, start, stop.
 
     """
     def wrapped(self, *args, **kwargs):
@@ -248,7 +246,7 @@ class ResourceManager(Logger):
         cls._register_traces()
 
     @classmethod
-    def rtype(cls):
+    def get_rtype(cls):
         """ Returns the type of the Resource Manager
 
         """
@@ -261,6 +259,14 @@ class ResourceManager(Logger):
         """
         return copy.deepcopy(cls._attributes.values())
 
+    @classmethod
+    def get_attribute(cls, name):
+        """ Returns a copy of the attribute with name 'name'
+
+        """
+        return copy.deepcopy(cls._attributes[name])
+
+
     @classmethod
     def get_traces(cls):
         """ Returns a copy of the traces
@@ -284,7 +290,7 @@ class ResourceManager(Logger):
         return cls._backend
 
     def __init__(self, ec, guid):
-        super(ResourceManager, self).__init__(self.rtype())
+        super(ResourceManager, self).__init__(self.get_rtype())
         
         self._guid = guid
         self._ec = weakref.ref(ec)
@@ -307,7 +313,6 @@ class ResourceManager(Logger):
         self._provision_time = None
         self._ready_time = None
         self._release_time = None
-        self._finish_time = None
         self._failed_time = None
 
         self._state = ResourceState.NEW
@@ -372,11 +377,6 @@ class ResourceManager(Logger):
         """ Returns the release time of the RM as a timestamp """
         return self._release_time
 
-    @property
-    def finish_time(self):
-        """ Returns the finalization time of the RM as a timestamp """
-        return self._finish_time
-
     @property
     def failed_time(self):
         """ Returns the time failure occured for the RM as a timestamp """
@@ -467,6 +467,7 @@ class ResourceManager(Logger):
         should be added in the do_start method.
 
         """
+
         if not self.state in [ResourceState.READY, ResourceState.STOPPED]:
             self.error("Wrong state %s for start" % self.state)
             return
@@ -534,23 +535,6 @@ class ResourceManager(Logger):
             self.set_released()
             self.debug("----- RELEASED ---- ")
 
-    @failtrap
-    def finish(self):
-        """ Sets the RM to state FINISHED. 
-     
-        The FINISHED state is different from STOPPED state in that it 
-        should not be directly invoked by the user.
-        STOPPED indicates that the user interrupted the RM, FINISHED means
-        that the RM concluded normally the actions it was supposed to perform.
-    
-        This method should not be overriden directly. Specific functionality
-        should be added in the do_finish method.
-        
-        """
-        with self._release_lock:
-            if self._state != ResourceState.RELEASED:
-                self.do_finish()
-
     def fail(self):
         """ Sets the RM to state FAILED.
 
@@ -698,6 +682,7 @@ class ResourceManager(Logger):
                 connected.append(rm)
         return connected
 
+    @failtrap
     def _needs_reschedule(self, group, state, time):
         """ Internal method that verify if 'time' has elapsed since 
         all elements in 'group' have reached state 'state'.
@@ -720,6 +705,13 @@ class ResourceManager(Logger):
         # check state and time elapsed on all RMs
         for guid in group:
             rm = self.ec.get_resource(guid)
+            
+            # If one of the RMs this resource needs to wait for has FAILED
+            # we raise an exception
+            if rm.state == ResourceState.FAILED:
+                msg = "Resource can not wait for FAILED RM %d. Setting Resource to FAILED"
+                raise RuntimeError, msg
+
             # If the RM state is lower than the requested state we must
             # reschedule (e.g. if RM is READY but we required STARTED).
             if rm.state < state:
@@ -739,6 +731,8 @@ class ResourceManager(Logger):
                     t = rm.start_time
                 elif state == ResourceState.STOPPED:
                     t = rm.stop_time
+                elif state == ResourceState.RELEASED:
+                    t = rm.release_time
                 else:
                     break
 
@@ -795,9 +789,12 @@ class ResourceManager(Logger):
         action 'START' are satisfied.
 
         """
+        #import pdb;pdb.set_trace()
+
         reschedule = False
         delay = reschedule_delay 
 
+
         ## evaluate if conditions to start are met
         if self.ec.abort:
             return 
@@ -814,12 +811,12 @@ class ResourceManager(Logger):
             # Verify all start conditions are met
             for (group, state, time) in start_conditions:
                 # Uncomment for debug
-                #unmet = []
-                #for guid in group:
-                #    rm = self.ec.get_resource(guid)
-                #    unmet.append((guid, rm._state))
-                #
-                #self.debug("---- WAITED STATES ---- %s" % unmet )
+                unmet = []
+                for guid in group:
+                    rm = self.ec.get_resource(guid)
+                    unmet.append((guid, rm._state))
+                
+                self.debug("---- WAITED STATES ---- %s" % unmet )
 
                 reschedule, delay = self._needs_reschedule(group, state, time)
                 if reschedule:
@@ -903,7 +900,7 @@ class ResourceManager(Logger):
         if reschedule:
             self.ec.schedule(delay, self.deploy_with_conditions)
         else:
-            self.debug("----- STARTING ---- ")
+            self.debug("----- DEPLOYING ---- ")
             self.deploy()
 
     def do_connect(self, guid):
@@ -949,9 +946,6 @@ class ResourceManager(Logger):
     def do_release(self):
         pass
 
-    def do_finish(self):
-        self.set_finished()
-
     def do_fail(self):
         self.set_failed()
 
@@ -971,10 +965,6 @@ class ResourceManager(Logger):
         """ Mark ResourceManager as REALEASED """
         self.set_state(ResourceState.RELEASED, "_release_time")
 
-    def set_finished(self):
-        """ Mark ResourceManager as FINISHED """
-        self.set_state(ResourceState.FINISHED, "_finish_time")
-
     def set_failed(self):
         """ Mark ResourceManager as FAILED """
         self.set_state(ResourceState.FAILED, "_failed_time")
@@ -1011,7 +1001,7 @@ class ResourceFactory(object):
     @classmethod
     def register_type(cls, rclass):
         """Register a new Ressource Manager"""
-        cls._resource_types[rclass.rtype()] = rclass
+        cls._resource_types[rclass.get_rtype()] = rclass
 
     @classmethod
     def create(cls, rtype, ec, guid):