From 0f3a2841944186b6076a8c230b98eb8b20d7ae45 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Sat, 20 Dec 2014 12:58:14 +0100 Subject: [PATCH] Cleaning up RM template --- doc/templates/template_rm.py | 183 +++++++++++++++++++++------------ src/nepi/execution/resource.py | 53 ++++++++-- 2 files changed, 158 insertions(+), 78 deletions(-) diff --git a/doc/templates/template_rm.py b/doc/templates/template_rm.py index 8a95124b..6eb02229 100644 --- a/doc/templates/template_rm.py +++ b/doc/templates/template_rm.py @@ -19,111 +19,158 @@ # Julien Tribino - 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 diff --git a/src/nepi/execution/resource.py b/src/nepi/execution/resource.py index f1669d09..16b434fb 100644 --- a/src/nepi/execution/resource.py +++ b/src/nepi/execution/resource.py @@ -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) -- 2.43.0