+ def register_condition(self, action, group, state,
+ time = None):
+ """ Registers a condition on the resource manager to allow execution
+ of 'action' only after 'time' has elapsed from the moment all resources
+ in 'group' reached state 'state'
+
+ :param action: Action to restrict to condition (either 'START' or 'STOP')
+ :type action: str
+ :param group: Group of RMs to wait for (list of guids)
+ :type group: int or list of int
+ :param state: State to wait for on all RM in group. (either 'STARTED' or 'STOPPED')
+ :type state: str
+ :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s')
+ :type time: str
+
+ """
+ conditions = self.conditions.get(action)
+ if not conditions:
+ conditions = list()
+ self._conditions[action] = conditions
+
+ # For each condition to register a tuple of (group, state, time) is
+ # added to the 'action' list
+ if not isinstance(group, list):
+ group = [group]
+
+ conditions.append((group, state, time))
+
+ def get_connected(self, rtype):
+ connected = []
+ for guid in self.connections:
+ rm = self.ec.get_resource(guid)
+ if rm.rtype() == rtype:
+ connected.append(rm)
+ return connected
+
+ def _needs_reschedule(self, group, state, time):
+ """ Internal method that verify if 'time' has elapsed since
+ all elements in 'group' have reached state 'state'.
+
+ :param group: Group of RMs to wait for (list of guids)
+ :type group: int or list of int
+ :param state: State to wait for on all RM in group. (either 'STARTED' or 'STOPPED')
+ :type state: str
+ :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s')
+ :type time: str
+
+ .. note : time should be written like "2s" or "3m" with s for seconds, m for minutes, h for hours, ...
+ If for example, you need to wait 2min 30sec, time could be "150s" or "2.5m".
+ For the moment, 2m30s is not a correct syntax.
+
+ """
+ reschedule = False
+ delay = _reschedule_delay
+
+ # check state and time elapsed on all RMs
+ for guid in group:
+ rm = self.ec.get_resource(guid)
+ # 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:
+ reschedule = True
+ break
+
+ # If there is a time restriction, we must verify the
+ # restriction is satisfied
+ if time:
+ if state == ResourceState.DISCOVERED:
+ t = rm.discover_time
+ if state == ResourceState.PROVISIONED:
+ t = rm.provision_time
+ elif state == ResourceState.READY:
+ t = rm.ready_time
+ elif state == ResourceState.STARTED:
+ t = rm.start_time
+ elif state == ResourceState.STOPPED:
+ t = rm.stop_time
+ else:
+ # Only keep time information for START and STOP
+ break
+
+ d = strfdiff(strfnow(), t)
+ wait = strfdiff(strfvalid(time),strfvalid(str(d)+"s"))
+ if wait > 0.001:
+ reschedule = True
+ delay = "%fs" % wait
+ break
+ return reschedule, delay
+
+ def set_with_conditions(self, name, value, group, state, time):
+ """ Set value 'value' on attribute with name 'name' when 'time'
+ has elapsed since all elements in 'group' have reached state
+ 'state'
+
+ :param name: Name of the attribute to set
+ :type name: str
+ :param name: Value of the attribute to set
+ :type name: str
+ :param group: Group of RMs to wait for (list of guids)
+ :type group: int or list of int
+ :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY')
+ :type state: str
+ :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s')
+ :type time: str
+
+ """
+
+ reschedule = False
+ delay = _reschedule_delay
+
+ ## evaluate if set conditions are met
+
+ # only can set with conditions after the RM is started
+ if self.state != ResourceState.STARTED:
+ reschedule = True
+ else:
+ reschedule, delay = self._needs_reschedule(group, state, time)
+
+ if reschedule:
+ callback = functools.partial(self.set_with_conditions,
+ name, value, group, state, time)
+ self.ec.schedule(delay, callback)
+ else:
+ self.set(name, value)
+
+ def start_with_conditions(self):
+ """ Starts RM when all the conditions in self.conditions for
+ action 'START' are satisfied.
+
+ """
+ reschedule = False
+ delay = _reschedule_delay
+
+ ## evaluate if set conditions are met
+
+ # only can start when RM is either STOPPED or READY
+ if self.state not in [ResourceState.STOPPED, ResourceState.READY]:
+ reschedule = True
+ self.debug("---- RESCHEDULING START ---- state %s " % self.state )
+ else:
+ self.debug("---- START CONDITIONS ---- %s" %
+ self.conditions.get(ResourceAction.START))
+
+ # Verify all start conditions are met
+ start_conditions = self.conditions.get(ResourceAction.START, [])
+ for (group, state, time) in start_conditions:
+ reschedule, delay = self._needs_reschedule(group, state, time)
+ if reschedule:
+ break
+
+ if reschedule:
+ self.ec.schedule(delay, self.start_with_conditions)
+ else:
+ self.debug("----- STARTING ---- ")
+ self.start()
+
+ def stop_with_conditions(self):
+ """ Stops RM when all the conditions in self.conditions for
+ action 'STOP' are satisfied.
+
+ """
+ reschedule = False
+ delay = _reschedule_delay
+
+ ## evaluate if set conditions are met
+
+ # only can stop when RM is STARTED
+ if self.state != ResourceState.STARTED:
+ reschedule = True
+ else:
+ self.debug(" ---- STOP CONDITIONS ---- %s" %
+ self.conditions.get(ResourceAction.STOP))
+
+ stop_conditions = self.conditions.get(ResourceAction.STOP, [])
+ for (group, state, time) in stop_conditions:
+ reschedule, delay = self._needs_reschedule(group, state, time)
+ if reschedule:
+ break
+
+ if reschedule:
+ callback = functools.partial(self.stop_with_conditions)
+ self.ec.schedule(delay, callback)
+ else:
+ self.logger.debug(" ----- STOPPING ---- ")
+ self.stop()
+
+ def deploy(self):
+ """ Execute all steps required for the RM to reach the state READY
+
+ """
+ if self._state > ResourceState.READY:
+ self.error("Wrong state %s for deploy" % self.state)
+ return
+
+ self.debug("----- DEPLOYING ---- ")
+ self._ready_time = strfnow()
+ self._state = ResourceState.READY
+
+ def release(self):
+ """Clean the resource at the end of the Experiment and change the status
+
+ """
+ self._release_time = strfnow()
+ self._state = ResourceState.RELEASED
+
+ def valid_connection(self, guid):
+ """Check if the connection is available.
+
+ :param guid: Guid of the current Resource Manager
+ :type guid: int
+ :rtype: Boolean
+
+ """