/*
* 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_grid_cloud_portal.rm;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.security.auth.login.LoginException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.annotations.GZIP;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import org.objectweb.proactive.ActiveObjectCreationException;
import org.objectweb.proactive.api.PAFuture;
import org.objectweb.proactive.core.node.Node;
import org.objectweb.proactive.core.node.NodeException;
import org.objectweb.proactive.core.node.NodeFactory;
import org.ow2.proactive.authentication.crypto.CredData;
import org.ow2.proactive.authentication.crypto.Credentials;
import org.ow2.proactive.resourcemanager.common.RMState;
import org.ow2.proactive.resourcemanager.common.event.RMInitialState;
import org.ow2.proactive.resourcemanager.common.event.RMNodeSourceEvent;
import org.ow2.proactive.resourcemanager.common.util.RMProxyUserInterface;
import org.ow2.proactive.resourcemanager.core.jmx.RMJMXBeans;
import org.ow2.proactive.resourcemanager.exception.RMException;
import org.ow2.proactive.resourcemanager.frontend.ResourceManager;
import org.ow2.proactive.resourcemanager.frontend.topology.Topology;
import org.ow2.proactive.resourcemanager.nodesource.common.ConfigurableField;
import org.ow2.proactive.resourcemanager.nodesource.common.PluginDescriptor;
import org.ow2.proactive.resourcemanager.utils.TargetType;
import org.ow2.proactive.scheduler.common.exception.NotConnectedException;
import org.ow2.proactive.scripting.ScriptResult;
import org.ow2.proactive_grid_cloud_portal.common.Session;
import org.ow2.proactive_grid_cloud_portal.common.SessionStore;
import org.ow2.proactive_grid_cloud_portal.common.SharedSessionStore;
import org.ow2.proactive_grid_cloud_portal.common.StatHistoryCaching;
import org.ow2.proactive_grid_cloud_portal.common.StatHistoryCaching.StatHistoryCacheEntry;
import org.ow2.proactive_grid_cloud_portal.common.dto.LoginForm;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.FetchRequest;
import org.rrd4j.core.RrdDb;
@Path("/rm")
public class RMRest implements RMRestInterface {
protected static final String[] dataSources = { //
// "AverageInactivity", // redundant with AverageActivity
// "ToBeReleasedNodesCo", // useless info
"BusyNodesCount", //
"FreeNodesCount", //
"DownNodesCount", //
"AvailableNodesCount", //
"AverageActivity", //
// "MaxFreeNodes" // redundant with AvailableNodesCount
};
private SessionStore sessionStore = SharedSessionStore.getInstance();
private RMProxyUserInterface checkAccess(String sessionId) throws NotConnectedException {
Session session = sessionStore.get(sessionId);
if (session == null) {
throw new NotConnectedException("you are not connected to the scheduler, you should log on first");
}
RMProxyUserInterface s = session.getRM();
if (s == null) {
throw new NotConnectedException("you are not connected to the scheduler, you should log on first");
}
return session.getRM();
}
/**
* Log into the resource manager using an form containing 2 fields
* @return the sessionid of the user if succeed
* @throws RMException
* @throws LoginException
* @throws KeyException
* @throws NodeException
* @throws ActiveObjectCreationException
*/
@Override
@POST
@Path("login")
@Produces("application/json")
public String rmConnect(@FormParam("username") String username, @FormParam("password") String password)
throws KeyException, LoginException, RMException, ActiveObjectCreationException, NodeException {
Session session = sessionStore.create(username);
session.connectToRM(new CredData(CredData.parseLogin(username), CredData.parseDomain(username), password));
return session.getSessionId();
}
/**
* Disconnects from resource manager and releases all the nodes taken by
* user for computations.
*
* @param sessionId
* a valid session id
* @throws NotConnectedException
*/
@Override
@POST
@Path("disconnect")
@Produces("application/json")
public void rmDisconnect(@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
RMProxyUserInterface rm = checkAccess(sessionId);
rm.disconnect();
sessionStore.terminate(sessionId);
}
/*
* (non-Javadoc)
*
* @see org.ow2.proactive_grid_cloud_portal.SchedulerRestInterface#loginWithCredential(org.ow2.
* proactive_grid_cloud_portal.LoginForm)
*/
@Override
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("login")
@Produces("application/json")
public String loginWithCredential(@MultipartForm LoginForm multipart) throws ActiveObjectCreationException,
NodeException, KeyException, IOException, LoginException, RMException {
Session session;
if (multipart.getCredential() != null) {
session = sessionStore.createUnnamedSession();
Credentials credentials = Credentials.getCredentials(multipart.getCredential());
session.connectToRM(credentials);
} else {
session = sessionStore.create(multipart.getUsername());
CredData credData = new CredData(CredData.parseLogin(multipart.getUsername()),
CredData.parseDomain(multipart.getUsername()),
multipart.getPassword(),
multipart.getSshKey());
session.connectToRM(credData);
}
return session.getSessionId();
}
@Override
public String getLoginFromSessionId(String sessionId) {
if (sessionId != null && sessionStore.exists(sessionId)) {
return sessionStore.get(sessionId).getUserName();
}
return "";
}
/**
* Returns the state of the Resource Manager
* @param sessionId a valid session id
* @return Returns the state of the scheduler
* @throws NotConnectedException
*/
@Override
@GET
@Path("state")
@Produces("application/json")
public RMState getState(@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return PAFuture.getFutureValue(rm.getState());
}
/**
* Returns the initial state of the resource manager
* @param sessionId a valid session id
* @return the initial state of the resource manager
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Path("monitoring")
@Produces("application/json")
public RMInitialState getInitialState(@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
checkAccess(sessionId);
return RMStateCaching.getRMInitialState();
}
/**
* Returns true if the resource manager is operational.
*
* @param sessionId
* a valid session id
* @return true if the resource manager is operational.
* @throws NotConnectedException
*/
@Override
@GET
@Path("isactive")
@Produces("application/json")
public boolean isActive(@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.isActive().getBooleanValue();
}
/**
* Adds an existing node to the particular node source.
*
* @param sessionId
* a valid session id
* @param url
* the url of the node
* @param nodesource
* the node source, can be null
* @return true if new node is added successfully, runtime exception
* otherwise
* @throws NotConnectedException
*/
@Override
@POST
@Path("node")
@Produces("application/json")
public boolean addNode(@HeaderParam("sessionid") String sessionId, @FormParam("nodeurl") String url,
@FormParam("nodesource") String nodesource) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
if (nodesource == null) {
return rm.addNode(url).getBooleanValue();
} else {
return rm.addNode(url, nodesource).getBooleanValue();
}
}
/**
* Returns true if the node nodeUrl is registered (i.e. known by the RM) and
* not down.
*
* @param sessionId
* a valid session id
* @param url
* the url of the node
* @return true if the node nodeUrl is registered and not down
* @throws NotConnectedException
*/
@Override
@GET
@Path("node/isavailable")
@Produces("application/json")
public boolean nodeIsAvailable(@HeaderParam("sessionid") String sessionId, @QueryParam("nodeurl") String url)
throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.nodeIsAvailable(url).getBooleanValue();
}
/**
* Gives list of existing Node Sources
* @return list of existing Node Sources
*/
@Override
@GET
@GZIP
@Path("nodesource")
@Produces("application/json")
public List<RMNodeSourceEvent> getExistingNodeSources(@HeaderParam("sessionid") String sessionId)
throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.getExistingNodeSourcesList();
}
/**
* Create a NodeSource
* <p>
*
* @param sessionId
* current session id
* @param nodeSourceName
* name of the node source to create
* @param infrastructureType
* fully qualified class name of the infrastructure to create
* @param infrastructureParameters
* String parameters of the infrastructure, without the
* parameters containing files or credentials
* @param infrastructureFileParameters
* File or credential parameters
* @param policyType
* fully qualified class name of the policy to create
* @param policyParameters
* String parameters of the policy, without the parameters
* containing files or credentials
* @param policyFileParameters
* File or credential parameters
* @return true if a node source has been created
* @throws NotConnectedException
*/
@Override
@POST
@Path("nodesource/create")
@Produces("application/json")
public boolean createNodeSource(@HeaderParam("sessionid") String sessionId,
@FormParam("nodeSourceName") String nodeSourceName,
@FormParam("infrastructureType") String infrastructureType,
@FormParam("infrastructureParameters") String[] infrastructureParameters,
@FormParam("infrastructureFileParameters") String[] infrastructureFileParameters,
@FormParam("policyType") String policyType, @FormParam("policyParameters") String[] policyParameters,
@FormParam("policyFileParameters") String[] policyFileParameters) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
Object[] infraParams = new Object[infrastructureParameters.length + infrastructureFileParameters.length];
Object[] policyParams = new Object[policyParameters.length + policyFileParameters.length];
/*
* we need to merge both infrastructureParameters and infrastructureFileParameters into one
* to do so we need the infrastructure parameter order from the RM
*/
for (PluginDescriptor infra : rm.getSupportedNodeSourceInfrastructures()) {
if (infra.getPluginName().equals(infrastructureType)) {
int i = 0, j = 0, k = 0;
for (ConfigurableField field : infra.getConfigurableFields()) {
if (field.getMeta().credential() || field.getMeta().fileBrowser()) {
// file parameter : insert from the other array, convert
// to byte[]
infraParams[i] = infrastructureFileParameters[k].getBytes();
k++;
} else {
infraParams[i] = infrastructureParameters[j];
j++;
}
i++;
}
}
}
for (PluginDescriptor pol : rm.getSupportedNodeSourcePolicies()) {
if (pol.getPluginName().equals(policyType)) {
int i = 0, j = 0, k = 0;
for (ConfigurableField
field : pol.getConfigurableFields()) {
if (field.getMeta().credential() || field.getMeta().password()) {
// file parameter : insert from the other array, convert
// to byte[]
policyParams[i] = policyFileParameters[k].getBytes();
k++;
} else {
policyParams[i] = policyParameters[j];
j++;
}
i++;
}
}
}
return rm.createNodeSource(nodeSourceName, infrastructureType, infraParams, policyType, policyParams)
.getBooleanValue();
}
/**
* Returns the ping frequency of a node source
*
* @param sessionId a valid session id
* @param sourceName a node source
* @return the ping frequency
* @throws NotConnectedException
*/
@Override
@POST
@Path("nodesource/pingfrequency")
@Produces("application/json")
public int getNodeSourcePingFrequency(@HeaderParam("sessionid") String sessionId,
@FormParam("sourcename") String sourceName) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.getNodeSourcePingFrequency(sourceName).getIntValue();
}
/**
* Release a node
*
* @param sessionId a valid session id
* @param url node's URL
* @return true of the node has been released
* @throws NodeException
* @throws NotConnectedException
*/
@Override
@POST
@Path("node/release")
@Produces("application/json")
public boolean releaseNode(@HeaderParam("sessionid") String sessionId, @FormParam("url") String url)
throws NodeException, NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
Node n;
n = NodeFactory.getNode(url);
return rm.releaseNode(n).getBooleanValue();
}
/**
* Delete a node
*
* @param sessionId a valid session id
* @param nodeUrl node's URL
* @param preempt if true remove node source immediatly whithout waiting for nodes to be freed
* @return true if the node is removed successfully, false or exception otherwise
* @throws NotConnectedException
*/
@Override
@POST
@Path("node/remove")
@Produces("application/json")
public boolean removeNode(@HeaderParam("sessionid") String sessionId, @FormParam("url") String nodeUrl,
@FormParam("preempt") boolean preempt) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.removeNode(nodeUrl, preempt).getBooleanValue();
}
/**
* Delete a nodesource
*
* @param sessionId a valid session id
* @param sourceName a node source
* @param preempt if true remove node source immediatly whithout waiting for nodes to be freed
* @return true if the node is removed successfully, false or exception otherwise
* @throws NotConnectedException
*/
@Override
@POST
@Path("nodesource/remove")
@Produces("application/json")
public boolean removeNodeSource(@HeaderParam("sessionid") String sessionId, @FormParam("name") String sourceName,
@FormParam("preempt") boolean preempt) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.removeNodeSource(sourceName, preempt).getBooleanValue();
}
/**
* prevent other users from using a set of locked nodes
*
* @param sessionId
* current session
* @param nodeUrls
* set of node urls to lock
* @return true when all nodes were free and have been locked
* @throws NotConnectedException
*/
@Override
@POST
@Path("node/lock")
@Produces("application/json")
public boolean lockNodes(@HeaderParam("sessionid") String sessionId, @FormParam("nodeurls") Set<String> nodeUrls)
throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.lockNodes(nodeUrls).getBooleanValue();
}
/**
* allow other users to use a set of previously locked nodes
*
* @param sessionId
* current session
* @param nodeUrls
* set of node urls to unlock
* @return true when all nodes were locked and have been unlocked
* @throws NotConnectedException
*/
@Override
@POST
@Path("node/unlock")
@Produces("application/json")
public boolean unlockNodes(@HeaderParam("sessionid") String sessionId, @FormParam("nodeurls") Set<String> nodeUrls)
throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.unlockNodes(nodeUrls).getBooleanValue();
}
/**
* Retrieves attributes of the specified mbean.
*
* @param sessionId current session
* @param nodeJmxUrl mbean server url
* @param objectName name of mbean
* @param attrs set of mbean attributes
*
* @return mbean attributes values
*/
@Override
@GET
@GZIP
@Produces("application/json")
@Path("node/mbean")
public Object getNodeMBeanInfo(@HeaderParam("sessionid") String sessionId,
@QueryParam("nodejmxurl") String nodeJmxUrl, @QueryParam("objectname") String objectName,
@QueryParam("attrs") List<String> attrs)
throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException,
NotConnectedException, MalformedObjectNameException, NullPointerException {
// checking that still connected to the RM
RMProxyUserInterface rmProxy = checkAccess(sessionId);
return rmProxy.getNodeMBeanInfo(nodeJmxUrl, objectName, attrs);
}
/**
* Return the statistic history contained in the node RRD database,
* without redundancy, in a friendly JSON format.
*
* @param sessionId a valid session
* @param range a String of 5 chars, one for each stat history source, indicating the time range to fetch
* for each source. Each char can be:<ul>
* <li>'a' 1 minute
* <li>'m' 10 minutes
* <li>'h' 1 hour
* <li>'H' 8 hours
* <li>'d' 1 day
* <li>'w' 1 week
* <li>'M' 1 month
* <li>'y' 1 year</ul>
* @return a JSON object containing a key for each source
* @throws InstanceNotFoundException
* @throws IntrospectionException
* @throws ReflectionException
* @throws IOException
* @throws MalformedObjectNameException
* @throws NullPointerException
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Produces("application/json")
@Path("node/mbean/history")
public String getNodeMBeanHistory(@HeaderParam("sessionid") String sessionId,
@QueryParam("nodejmxurl") String nodeJmxUrl, @QueryParam("objectname") String objectName,
@QueryParam("attrs") List<String> attrs, @QueryParam("range") String range)
throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException,
NotConnectedException, MalformedObjectNameException, NullPointerException, MBeanException {
// checking that still connected to the RM
RMProxyUserInterface rmProxy = checkAccess(sessionId);
return rmProxy.getNodeMBeanHistory(nodeJmxUrl, objectName, attrs, range);
}
/**
* Retrieves attributes of the specified mbeans.
*
* @param sessionId current session
* @param objectNames mbean names (@see ObjectName format)
* @param nodeJmxUrl mbean server url
* @param attrs set of mbean attributes
*
* @return mbean attributes values
*/
@Override
@GET
@GZIP
@Produces("application/json")
@Path("node/mbeans")
public Object getNodeMBeansInfo(@HeaderParam("sessionid") String sessionId,
@QueryParam("nodejmxurl") String nodeJmxUrl, @QueryParam("objectname") String objectNames,
@QueryParam("attrs") List<String> attrs)
throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException,
NotConnectedException, MalformedObjectNameException, NullPointerException {
// checking that still connected to the RM
RMProxyUserInterface rmProxy = checkAccess(sessionId);
return rmProxy.getNodeMBeansInfo(nodeJmxUrl, objectNames, attrs);
}
@Override
@GET
@GZIP
@Produces("application/json")
@Path("node/mbeans/history")
public Object getNodeMBeansHistory(@HeaderParam("sessionid") String sessionId,
@QueryParam("nodejmxurl") String nodeJmxUrl, @QueryParam("objectname") String objectNames,
@QueryParam("attrs") List<String> attrs, @QueryParam("range") String range)
throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException,
NotConnectedException, MalformedObjectNameException, NullPointerException, MBeanException {
// checking that still connected to the RM
RMProxyUserInterface rmProxy = checkAccess(sessionId);
return rmProxy.getNodeMBeansHistory(nodeJmxUrl, objectNames, attrs, range);
}
/**
* Initiate the shutdowns the resource manager. During the shutdown resource
* manager removed all the nodes and kills them if necessary.
* RMEvent(SHUTDOWN) will be send when the shutdown is finished.
*
* @param sessionId a valid session
* @param preempt if true shutdown immediatly whithout waiting for nodes to be freed, default value is false
* @return true if the shutdown process is successfully triggered, runtime exception otherwise
* @throws NotConnectedException
*/
@Override
@GET
@Path("shutdown")
@Produces("application/json")
public boolean shutdown(@HeaderParam("sessionid") String sessionId,
@QueryParam("preempt") @DefaultValue("false") boolean preempt) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.shutdown(preempt).getBooleanValue();
}
@Override
@GET
@Path("topology")
@Produces("application/json")
public Topology getTopology(@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return PAFuture.getFutureValue(rm.getTopology());
}
/**
* Returns the list of supported node source infrastructures descriptors.
*
* @param sessionId a valid session
* @return the list of supported node source infrastructures descriptors
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Path("infrastructures")
@Produces("application/json")
public Collection<PluginDescriptor> getSupportedNodeSourceInfrastructures(
@HeaderParam("sessionid") String sessionId) throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.getSupportedNodeSourceInfrastructures();
}
/**
* Returns the list of supported node source policies descriptors.
*
* @param sessionId a valid session
* @return the list of supported node source policies descriptors
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Path("policies")
@Produces("application/json")
public Collection<PluginDescriptor> getSupportedNodeSourcePolicies(@HeaderParam("sessionid") String sessionId)
throws NotConnectedException {
ResourceManager rm = checkAccess(sessionId);
return rm.getSupportedNodeSourcePolicies();
}
/**
* Returns the attributes <code>attr</code> of the mbean
* registered as <code>name</code>.
* @param sessionId a valid session
* @param name mbean's object name
* @param attrs attributes to enumerate
* @return returns the attributes of the mbean
* @throws InstanceNotFoundException
* @throws IntrospectionException
* @throws ReflectionException
* @throws IOException
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Path("info/{name}")
@Produces("application/json")
public Object getMBeanInfo(@HeaderParam("sessionid") String sessionId, @PathParam("name") ObjectName name,
@QueryParam("attr") List<String> attrs) throws InstanceNotFoundException, IntrospectionException,
ReflectionException, IOException, NotConnectedException {
RMProxyUserInterface rm = checkAccess(sessionId);
if ((attrs == null) || (attrs.size() == 0)) {
// no attribute is requested, we return
// the description of the mbean
return rm.getMBeanInfo(name);
} else {
return rm.getMBeanAttributes(name, attrs.toArray(new String[attrs.size()]));
}
}
/**
* Return the statistic history contained in the RM's RRD database,
* without redundancy, in a friendly JSON format.
*
* The following sources will be queried from the RRD DB :<pre>
* { "BusyNodesCount",
* "FreeNodesCount",
* "DownNodesCount",
* "AvailableNodesCount",
* "AverageActivity" }</pre>
*
*
* @param sessionId a valid session
* @param range a String of 5 chars, one for each stat history source, indicating the time range to fetch
* for each source. Each char can be:<ul>
* <li>'a' 1 minute
* <li>'m' 10 minutes
* <li>'h' 1 hour
* <li>'H' 8 hours
* <li>'d' 1 day
* <li>'w' 1 week
* <li>'M' 1 month
* <li>'y' 1 year</ul>
* @return a JSON object containing a key for each source
* @throws InstanceNotFoundException
* @throws IntrospectionException
* @throws ReflectionException
* @throws IOException
* @throws MalformedObjectNameException
* @throws NullPointerException
* @throws InterruptedException
* @throws NotConnectedException
*/
@Override
@GET
@GZIP
@Path("stathistory")
@Produces("application/json")
public String getStatHistory(@HeaderParam("sessionid") String sessionId, @QueryParam("range") String range)
throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException,
MalformedObjectNameException, NullPointerException, InterruptedException, NotConnectedException {
RMProxyUserInterface rm = checkAccess(sessionId);
// if range String is too large, shorten it
// to make it recognizable by StatHistoryCaching
if (range.length() > dataSources.length) {
range = range.substring(0, dataSources.length);
}
// complete range if too short
while (range.length() < dataSources.length) {
range += 'a';
}
StatHistoryCacheEntry cache = StatHistoryCaching.getInstance().getEntry(range);
// found unexpired cache entry matching the parameters: return it immediately
if (cache != null) {
return cache.getValue();
}
long l1 = System.currentTimeMillis();
ObjectName on = new ObjectName(RMJMXBeans.RUNTIMEDATA_MBEAN_NAME);
AttributeList attrs = rm.getMBeanAttributes(on, new String[] { "StatisticHistory" });
Attribute attr = (Attribute) attrs.get(0);
// content of the RRD4J database backing file
byte[] rrd4j = (byte[]) attr.getValue();
File rrd4jDb = File.createTempFile("database", "rr4dj");
rrd4jDb.deleteOnExit();
OutputStream out = new FileOutputStream(rrd4jDb);
out.write(rrd4j);
out.close();
// create RRD4J DB, should be identical to the one held by the RM
RrdDb db = new RrdDb(rrd4jDb.getAbsolutePath(), true);
long timeEnd = db.getLastUpdateTime();
// force float separator for JSON parsing
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
otherSymbols.setDecimalSeparator('.');
// formatting will greatly reduce response size
DecimalFormat formatter = new DecimalFormat("###.###", otherSymbols);
// construct the JSON response directly in a String
StringBuilder result = new StringBuilder();
result.append("{");
for (int i = 0; i < dataSources.length; i++) {
String dataSource = dataSources[i];
char zone = range.charAt(i);
long timeStart;
switch (zone) {
default:
case 'a': // 1 minute
timeStart = timeEnd - 60;
break;
case 'm': // 10 minute
timeStart = timeEnd - 60 * 10;
break;
case 'h': // 1 hours
timeStart = timeEnd - 60 * 60;
break;
case 'H': // 8 hours
timeStart = timeEnd - 60 * 60 * 8;
break;
case 'd': // 1 day
timeStart = timeEnd - 60 * 60 * 24;
break;
case 'w': // 1 week
timeStart = timeEnd - 60 * 60 * 24 * 7;
break;
case 'M': // 1 month
timeStart = timeEnd - 60 * 60 * 24 * 28;
break;
case 'y': // 1 year
timeStart = timeEnd - 60 * 60 * 24 * 365;
break;
}
FetchRequest req = db.createFetchRequest(ConsolFun.AVERAGE, timeStart, timeEnd);
req.setFilter(dataSource);
FetchData fetchData = req.fetchData();
result.append("\"").append(dataSource).append("\":[");
double[] values = fetchData.getValues(dataSource);
for (int j = 0; j < values.length; j++) {
if (Double.compare(Double.NaN, values[j]) == 0) {
result.append("null");
} else {
result.append(formatter.format(values[j]));
}
if (j < values.length - 1)
result.append(',');
}
result.append(']');
if (i < dataSources.length - 1)
result.append(',');
}
result.append("}");
db.close();
rrd4jDb.delete();
String ret = result.toString();
StatHistoryCaching.getInstance().addEntry(range, l1, ret);
return ret;
}
/**
* Returns the version of the rest api
* @return returns the version of the rest api
*/
@Override
@GET
@Path("version")
public String getVersion() {
return "{ " + "\"rm\" : \"" + RMRest.class.getPackage().getSpecificationVersion() + "\", " + "\"rest\" : \"" +
RMRest.class.getPackage().getImplementationVersion() + "\"" + "}";
}
@Override
@POST
@GZIP
@Path("node/script")
@Produces("application/json")
public ScriptResult<Object> executeNodeScript(@HeaderParam("sessionid") String sessionId,
@FormParam("nodeurl") String nodeUrl, @FormParam("script") String script,
@FormParam("scriptEngine") String scriptEngine) throws Throwable {
RMProxyUserInterface rm = checkAccess(sessionId);
List<ScriptResult<Object>> results = rm.executeScript(script,
scriptEngine,
TargetType.NODE_URL.name(),
Collections.singleton(nodeUrl));
if (results.isEmpty()) {
throw new IllegalStateException("Empty results from script execution");
}
return results.get(0);
}
@Override
@POST
@GZIP
@Path("nodesource/script")
@Produces("application/json")
public List<ScriptResult<Object>> executeNodeSourceScript(@HeaderParam("sessionid") String sessionId,
@FormParam("nodesource") String nodeSource, @FormParam("script") String script,
@FormParam("scriptEngine") String scriptEngine) throws Throwable {
RMProxyUserInterface rm = checkAccess(sessionId);
return rm.executeScript(script,
scriptEngine,
TargetType.NODESOURCE_NAME.name(),
Collections.singleton(nodeSource));
}
@Override
@POST
@GZIP
@Path("host/script")
@Produces("application/json")
public List<ScriptResult<Object>> executeHostScript(@HeaderParam("sessionid") String sessionId,
@FormParam("host") String host, @FormParam("script") String script,
@FormParam("scriptEngine") String scriptEngine) throws Throwable {
RMProxyUserInterface rm = checkAccess(sessionId);
return rm.executeScript(script, scriptEngine, TargetType.HOSTNAME.name(), Collections.singleton(host));
}
@GET
@Path("/")
public Response index() throws URISyntaxException {
return Response.seeOther(new URI("doc/jaxrsdocs/rm/index.html")).build();
}
}