/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.proactive.scheduler.resourcemanager.nodesource.policy;
import java.util.HashMap;
import java.util.Map.Entry;
import org.objectweb.proactive.core.util.wrapper.BooleanWrapper;
import org.objectweb.proactive.extensions.annotation.ActiveObject;
import org.ow2.proactive.resourcemanager.common.NodeState;
import org.ow2.proactive.resourcemanager.common.event.RMNodeEvent;
/**
*
* NodeSource Policy for Amazon EC2
* <p>
* Acquires resources according to the current load of the Scheduler as
* specified by {@link SchedulerLoadingPolicy}
* <p>
* Releases resources only on the last 10 minutes of the last paid hour to
* minimize costs
*
* @author The ProActive Team
* @since ProActive Scheduling 1.0
*
*/
@ActiveObject
public class EC2Policy extends SchedulerLoadingPolicy {
{
// 40 mn
nodeDeploymentTimeout = 40 * 60 * 1000;
}
/**
* Paid instance duration in Milliseconds: time after which the instance has
* to be paid again. For AWS EC2, one hour
*/
private final static int releaseDelay = 60 * 60 * 1000; // 1 hour
/**
* Nodes can be released if t = [releaseDelay - threshold, releasDelay]
*/
private final static int threshold = 10 * 60 * 1000; // 10 minutes
/**
* associates a Node URL with a acquisition time the time (as return by
* System.currentTimeMillis()) is actually when it was registered in the RM,
* not the VM startup in AWS accounting, which probably occurred ~2mn sooner
*/
private HashMap<String, Long> nodes = new HashMap<>();
/**
* EC2Policy AO empty non-arg constructor
*/
public EC2Policy() {
}
@Override
public BooleanWrapper configure(Object... policyParameters) {
super.configure(policyParameters);
return new BooleanWrapper(true);
}
@Override
protected void removeNode() {
String bestFree = null;
String bestBusy = null;
String bestDown = null;
long t = System.currentTimeMillis();
/*
* A Node can be removed only if (minutes_since_acquisisiont % 60 < 10),
* ie. we are in the last 10 minutes of the last paid hour Down nodes
* are removed in priority, then free nodes, then busy nodes
*/
for (Entry<String, Long> node : nodes.entrySet()) {
long rt = releaseDelay - ((t - node.getValue()) % releaseDelay);
NodeState state = null;
try {
state = nodeSource.getRMCore().getNodeState(node.getKey());
} catch (Throwable exc) {
// pending / configuring
continue;
}
switch (state) {
case BUSY:
case CONFIGURING:
case DEPLOYING:
if (rt < threshold) {
bestBusy = node.getKey();
}
break;
case LOST:
case DOWN:
if (rt < threshold) {
bestDown = node.getKey();
}
break;
case FREE:
if (rt < threshold) {
bestFree = node.getKey();
}
break;
}
}
if (bestDown != null) {
removeNode(bestDown, false);
this.nodes.remove(bestDown);
} else if (bestFree != null) {
removeNode(bestFree, false);
this.nodes.remove(bestFree);
} else if (bestBusy != null) {
removeNode(bestBusy, false);
this.nodes.remove(bestBusy);
} else {
// no node can be removed, cancel request
timeStamp = 0;
}
}
/*
* Store the time at which EC2 instances register to the RM The actual
* starting time in EC2 accounting might have been a couple minutes sooner
*
* (non-Javadoc)
*
* @see org.ow2.proactive.scheduler.resourcemanager.nodesource.policy.
* SchedulerLoadingPolicy
* #nodeEvent(org.ow2.proactive.resourcemanager.common.event.RMNodeEvent)
*/
@Override
public void nodeEvent(RMNodeEvent event) {
switch (event.getEventType()) {
case NODE_ADDED:
this.nodes.put(event.getNodeUrl(), System.currentTimeMillis());
break;
case NODE_REMOVED:
this.nodes.remove(event.getNodeUrl());
}
super.nodeEvent(event);
}
}