# 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
import threading
import weakref
-reschedule_delay = "0.5s"
-
class ResourceAction:
""" Action that a user can order to a Resource Manager
"""
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",
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.
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
""" 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):
""" 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.
"""
""" 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):
""" Returns a copy of the traces
"""
- return copy.deepcopy(cls._traces.values())
+ return copy.deepcopy(list(cls._traces.values()))
@classmethod
def get_help(cls):
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):
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
""" 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 """
@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
""" 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.
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
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
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.
"""
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.
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.
"""
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).
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.
"""
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.
"""
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.
"""
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.
"""
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.
"""
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
"""
reschedule = False
- delay = reschedule_delay
+ delay = self.reschedule_delay
# check state and time elapsed on all RMs
for guid in group:
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).
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
"""
reschedule = False
- delay = reschedule_delay
+ delay = self.reschedule_delay
## evaluate if set conditions are met
#import pdb;pdb.set_trace()
reschedule = False
- delay = reschedule_delay
+ delay = self.reschedule_delay
## evaluate if conditions to start are met
"""
reschedule = False
- delay = reschedule_delay
+ delay = self.reschedule_delay
## evaluate if conditions to stop are met
if self.ec.abort:
"""
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 )
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()
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)