X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fexecution%2Fresource.py;h=4394130d75f820bc6b404f11f876b44689c244a2;hb=58a2b493f8df1072a1faa653c8abb6a3f9ba21fa;hp=e82ced043a006ebc4ba0b32a7de5e42388a4573f;hpb=6be239a7c874733f31bd0d1085f5d52072ee411d;p=nepi.git diff --git a/src/nepi/execution/resource.py b/src/nepi/execution/resource.py index e82ced04..4394130d 100644 --- a/src/nepi/execution/resource.py +++ b/src/nepi/execution/resource.py @@ -3,9 +3,8 @@ # Copyright (C) 2013 INRIA # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,8 +30,6 @@ import sys import threading import weakref -reschedule_delay = "1s" - class ResourceAction: """ Action that a user can order to a Resource Manager @@ -47,16 +44,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 +82,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,18 +105,20 @@ 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): try: return func(self, *args, **kwargs) except: + self.fail() + import traceback err = traceback.format_exc() - self.error(err) - self.debug("SETTING guid %d to state FAILED" % self.guid) - self.fail() + logger = Logger(self._rtype) + logger.error(err) + logger.error("SETTING guid %d to state FAILED" % self.guid) raise return wrapped @@ -127,19 +128,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): @@ -210,7 +212,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. """ @@ -265,7 +267,7 @@ class ResourceManager(Logger): """ Returns a copy of the attributes """ - return copy.deepcopy(cls._attributes.values()) + return copy.deepcopy(list(cls._attributes.values())) @classmethod def get_attribute(cls, name): @@ -279,7 +281,7 @@ class ResourceManager(Logger): """ Returns a copy of the traces """ - return copy.deepcopy(cls._traces.values()) + return copy.deepcopy(list(cls._traces.values())) @classmethod def get_help(cls): @@ -289,12 +291,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): @@ -343,6 +345,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 @@ -395,6 +398,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 """ @@ -412,7 +420,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 @@ -420,6 +428,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. @@ -433,7 +446,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 @@ -447,7 +460,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 @@ -465,7 +478,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. """ @@ -473,6 +486,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. @@ -481,7 +509,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. """ @@ -489,6 +517,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). @@ -496,7 +540,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. """ @@ -516,7 +560,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. """ @@ -534,7 +578,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. """ @@ -552,7 +596,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. """ @@ -560,16 +604,19 @@ class ResourceManager(Logger): try: self.do_release() except: + self.set_released() + import traceback err = traceback.format_exc() - self.error(err) - - self.set_released() + msg = " %s guid %d ----- FAILED TO RELEASE ----- \n %s " % ( + self._rtype, self.guid, err) + logger = Logger(self._rtype) + logger.debug(msg) 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. """ @@ -615,7 +662,7 @@ class ResourceManager(Logger): :rtype: str """ attr = self._attrs[name] - return attr.has_changed() + return attr.has_changed def has_flag(self, name, flag): """ Returns true if the attribute has the flag 'flag' @@ -718,7 +765,7 @@ class ResourceManager(Logger): if not isinstance(group, list): group = [group] - for act, conditions in self.conditions.iteritems(): + for act, conditions in self.conditions.items(): if action and act != action: continue @@ -749,6 +796,18 @@ class ResourceManager(Logger): connected.append(rm) return connected + def is_rm_instance(self, rtype): + """ Returns True if the RM is instance of 'rtype' + + :param rtype: Type of the RM we look for + :type rtype: str + :return: True|False + """ + rclass = ResourceFactory.get_resource_type(rtype) + if isinstance(self, rclass): + return True + return False + @failtrap def _needs_reschedule(self, group, state, time): """ Internal method that verify if 'time' has elapsed since @@ -767,7 +826,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: @@ -779,7 +838,7 @@ class ResourceManager(Logger): if not rm.get('critical'): continue msg = "Resource can not wait for FAILED RM %d. Setting Resource to FAILED" - raise RuntimeError, msg + 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). @@ -792,7 +851,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 @@ -836,7 +897,7 @@ class ResourceManager(Logger): """ reschedule = False - delay = reschedule_delay + delay = self.reschedule_delay ## evaluate if set conditions are met @@ -861,7 +922,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 @@ -903,7 +964,7 @@ class ResourceManager(Logger): """ reschedule = False - delay = reschedule_delay + delay = self.reschedule_delay ## evaluate if conditions to stop are met if self.ec.abort: @@ -936,15 +997,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 ) @@ -1001,9 +1062,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() @@ -1038,18 +1105,29 @@ class ResourceManager(Logger): def set_released(self, time = None): """ Mark ResourceManager as REALEASED """ self.set_state(ResourceState.RELEASED, "_release_time", time) - self.debug("----- RELEASED ---- ") + + msg = " %s guid %d ----- RELEASED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) def set_failed(self, time = None): """ Mark ResourceManager as FAILED """ self.set_state(ResourceState.FAILED, "_failed_time", time) - self.debug("----- FAILED ---- ") + + msg = " %s guid %d ----- FAILED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) def set_discovered(self, time = None): """ Mark ResourceManager as DISCOVERED """ 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)