Costantino Perciante 2017-04-13 14:56:38 +00:00
commit 8acd0735d1
16 changed files with 1116 additions and 0 deletions

26
.classpath Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>resource-checker-se-plugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,5 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

126
pom.xml Normal file
View File

@ -0,0 +1,126 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.gcube.tools</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0.0</version>
</parent>
<groupId>org.gcube.information-system</groupId>
<artifactId>resource-checker-se-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Resource Checker Smart Executor Plugin</name>
<description>Resource Checker Smart Executor Plugin</description>
<scm>
<connection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/${serviceClass}/${project.artifactId}</connection>
<developerConnection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/${serviceClass}/${project.artifactId}</developerConnection>
<url>https://svn.d4science.research-infrastructures.eu/gcube/trunk/${serviceClass}/${project.artifactId}</url>
</scm>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-smartgears-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<metaInfDirectory>src/main/resources/META-INF/services</metaInfDirectory>
<distroDirectory>distro</distroDirectory>
<serviceClass>social-networking</serviceClass>
<elasticSearchVersion>2.2.0</elasticSearchVersion>
<guavaVersion>18.0</guavaVersion>
<apache.http.version>4.3</apache.http.version>
<astyanaxVersion>2.0.2</astyanaxVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>ic-client</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.vremanagement</groupId>
<artifactId>smart-executor-api</artifactId>
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[4.0.0,)</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${apache.http.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,160 @@
/**
*
*/
package org.gcube.informationsystem.resource_checker;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.resources.gcore.GenericResource;
import org.gcube.common.resources.gcore.HostingNode;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.Software;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.informationsystem.resource_checker.utils.BasicFunctionalitiesMandatoryReader;
import org.gcube.informationsystem.resource_checker.utils.BasicFunctionalityBean;
import org.gcube.informationsystem.resource_checker.utils.RetrieveContextsList;
import org.gcube.informationsystem.resource_checker.utils.SendNotification;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.resources.discovery.icclient.ICFactory;
import org.gcube.vremanagement.executor.plugin.Plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The resource-checker-se-plugin implementation class.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@SuppressWarnings("rawtypes")
public class ResourceCheckerPlugin extends Plugin<ResourceCheckerPluginDeclaration>{
private static final int SECONDS2WAIT = 1; // seconds to wait among IS requests
private static final String INITIAL_ERRORS_STATEMENT = "Other errors: ";
public static final String ROLE_TO_NOTIFY = "role";
private static final Logger logger = LoggerFactory.getLogger(ResourceCheckerPlugin.class);
public ResourceCheckerPlugin(ResourceCheckerPluginDeclaration pluginDeclaration){
super(pluginDeclaration);
logger.info("Constructor invoked");
}
/**{@inheritDoc}
* @throws Exception */
@Override
public void launch(Map<String, Object> inputs) throws Exception{
logger.info("Starting plugin with inputs: " + inputs);
Map<String, List<BasicFunctionalityBean>> missingResourcesPerContext = new HashMap<String, List<BasicFunctionalityBean>>();
List<BasicFunctionalityBean> mandatoryFunctionalities = new BasicFunctionalitiesMandatoryReader().getMandatoryFunctionalities();
List<String> contexts = RetrieveContextsList.getContexts();
logger.info("Contexts are " + contexts);
logger.info("Mandatory functionalities are " + mandatoryFunctionalities);
String otherFailures = INITIAL_ERRORS_STATEMENT;
DiscoveryClient client = ICFactory.client();
for (String context : contexts) {
// switch context
ScopeProvider.instance.set(context);
for (BasicFunctionalityBean service : mandatoryFunctionalities) {
try{
if(!isServicePresent(service, client)){
List<BasicFunctionalityBean> missingServices = null;
if(missingResourcesPerContext.containsKey(context))
missingServices = missingResourcesPerContext.get(context);
else
missingServices = new ArrayList<BasicFunctionalityBean>();
missingServices.add(service);
missingResourcesPerContext.put(context, missingServices);
}
Thread.sleep(1000 * SECONDS2WAIT);
}catch(Exception e){
if(!(e instanceof InterruptedException)){
logger.warn("An error arose when checking for resource " + service + " into context " + context);
otherFailures += "\nAn error arose while checking for resource with name/category "
+ service.getName() + "/" + service.getCategory() + " into context " + context + "(stack trace is : " + e.getMessage() + ")";
}
}
}
}
if(otherFailures.equals(INITIAL_ERRORS_STATEMENT))
otherFailures += "none\n";
else
otherFailures += "\n";
// if there are missing resources, notify administrators via mail
if(!missingResourcesPerContext.isEmpty())
SendNotification.sendMessage(missingResourcesPerContext, otherFailures, (String)inputs.get(ROLE_TO_NOTIFY));
logger.info("Plugin's execution ended. Map of not available services per scope is the following: \n" + missingResourcesPerContext);
}
/**
* Check if a given resource is present or is missing.
* @param service
* @param client
* @return
* @throws Exception
*/
private boolean isServicePresent(BasicFunctionalityBean service, DiscoveryClient client) throws Exception {
Class classFor = service.getType() == null? ServiceEndpoint.class : service.getType(); // default is service end point
SimpleQuery q = ICFactory.queryFor(classFor);
if(classFor.equals(ServiceEndpoint.class)){
q.addCondition("$resource/Profile/Name/text() eq '"+ service.getName() +"'");
q.addCondition("$resource/Profile/Category/text() eq '"+ service.getCategory() +"'");
}else if(classFor.equals(GCoreEndpoint.class)){
// TODO
logger.error("There is no implementation yet to check for GCoreEndpoint");
throw new Exception("There is no implementation yet to check for GCoreEndpoint");
}else if(classFor.equals(GenericResource.class)){
// TODO
logger.error("There is no implementation yet to check for GenericResource");
throw new Exception("There is no implementation yet to check for GenericResource");
}else if(classFor.equals(HostingNode.class)){
// TODO
logger.error("There is no implementation yet to check for HostingNode");
throw new Exception("There is no implementation yet to check for HostingNode");
}else if(classFor.equals(Software.class)){
// TODO
logger.error("There is no implementation yet to check for Software");
throw new Exception("There is no implementation yet to check for Software");
}else
throw new Exception("Unable to check resource because its type is missing " + service);
List result = client.submit(q);
return result != null && result.size() > 0;
}
/**{@inheritDoc}*/
@Override
protected void onStop() throws Exception {
logger.debug("onStop() invoked");
Thread.currentThread().interrupt();
}
}

View File

@ -0,0 +1,80 @@
/**
*
*/
package org.gcube.informationsystem.resource_checker;
import java.util.HashMap;
import java.util.Map;
import org.gcube.vremanagement.executor.plugin.Plugin;
import org.gcube.vremanagement.executor.plugin.PluginDeclaration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The resource-checker-se-plugin declaration class.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ResourceCheckerPluginDeclaration implements PluginDeclaration {
/**
* Logger
*/
private static Logger logger = LoggerFactory.getLogger(ResourceCheckerPluginDeclaration.class);
/**
* Plugin name used by the Executor to retrieve this class
*/
public static final String NAME = "resource-checker-se-plugin";
public static final String DESCRIPTION = "The resource-checker-plugin has the role to check the existence of some resources in all Infrastructure's contexts.";
public static final String VERSION = "1.0.0";
/**{@inheritDoc}*/
@Override
public void init() {
logger.debug(String.format("%s initialized", ResourceCheckerPluginDeclaration.class.getSimpleName()));
}
/**{@inheritDoc}*/
@Override
public String getName() {
return NAME;
}
/**{@inheritDoc}*/
@Override
public String getDescription() {
return DESCRIPTION;
}
/**{@inheritDoc}*/
@Override
public String getVersion() {
return VERSION;
}
/**{@inheritDoc}*/
@Override
public Map<String, String> getSupportedCapabilities() {
Map<String, String> discoveredCapabilities = new HashMap<String, String>();
// No capabilities to discover
return discoveredCapabilities;
}
/**{@inheritDoc}*/
@Override
public Class<? extends Plugin<? extends PluginDeclaration>> getPluginImplementation() {
return ResourceCheckerPlugin.class;
}
@Override
public String toString(){
return String.format("%s : %s - %s - %s - %s - %s",
this.getClass().getSimpleName(),
getName(), getVersion(), getDescription(),
getSupportedCapabilities(),
getPluginImplementation().getClass().getSimpleName());
}
}

View File

@ -0,0 +1,82 @@
package org.gcube.informationsystem.resource_checker.utils;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Parse the generic resource containing the basic functionalities and retrieve them.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class BasicFunctionalitiesMandatoryReader {
private static Logger logger = LoggerFactory.getLogger(BasicFunctionalitiesMandatoryReader.class);
private List<BasicFunctionalityBean> mandatoryFunctionalities = null;
private static final String FILE_PROPRETIES_LOCATION_PATH = "/META-INF/plugin_resources/resources_to_fetch.properties";
private static final String SERVICE_NAME_KEY = "ServiceNames";
private static final String CATEGORY_NAME_KEY = "CategoryNames";
private static final String TYPES = "Types";
private static final String SEPARATOR = ",";
public BasicFunctionalitiesMandatoryReader() throws Exception{
readFromLocalFile();
}
/**
* Read it from the fallback file
* @return
* @throws FileNotFoundException
*/
private void readFromLocalFile() throws Exception {
Properties prop = new Properties();
prop.load(getClass().getResourceAsStream(FILE_PROPRETIES_LOCATION_PATH));
String serviceNames = prop.getProperty(SERVICE_NAME_KEY);
String serviceCategories = prop.getProperty(CATEGORY_NAME_KEY);
String types = prop.getProperty(TYPES);
if(serviceNames == null || serviceCategories == null)
throw new Exception("Service names or categories are missing in file " + FILE_PROPRETIES_LOCATION_PATH);
String[] serviceNamesSplitted = serviceNames.split(SEPARATOR);
String[] serviceCategoriesSplitted = serviceCategories.split(SEPARATOR);
String[] typesSplitted = null;
if(types != null)
typesSplitted = types.split(SEPARATOR);
// build the java objects
if(serviceNamesSplitted.length != serviceCategoriesSplitted.length)
throw new Exception("The file at " + FILE_PROPRETIES_LOCATION_PATH + " seems to be malformed (service names and categories number do not match)!");
if(typesSplitted != null && serviceNamesSplitted.length != typesSplitted.length)
throw new Exception("The file at " + FILE_PROPRETIES_LOCATION_PATH + " seems to be malformed (types lenght doesn't match the other properties)!");
// Build the objects
mandatoryFunctionalities = new ArrayList<BasicFunctionalityBean>();
for (int i = 0; i < serviceCategoriesSplitted.length; i++) {
mandatoryFunctionalities.add(new BasicFunctionalityBean(serviceCategoriesSplitted[i], serviceNamesSplitted[i], typesSplitted != null ? typesSplitted[i] : null));
}
logger.info("Built list is " + mandatoryFunctionalities);
}
/**
* Retrieve the list of mandatory service endpoints
* @return a list of mandatory service endpoints
*/
public List<BasicFunctionalityBean> getMandatoryFunctionalities() {
return mandatoryFunctionalities;
}
}

View File

@ -0,0 +1,81 @@
package org.gcube.informationsystem.resource_checker.utils;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.resources.gcore.GenericResource;
import org.gcube.common.resources.gcore.HostingNode;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.Resource.Type;
import org.gcube.common.resources.gcore.Software;
/**
* A basic functionality bean with name, category and type
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@SuppressWarnings("rawtypes")
public class BasicFunctionalityBean {
private String category;
private String name;
private Class type; // service endpoint only for now
/**
* @param category
* @param name
* @param type
*/
public BasicFunctionalityBean(String category, String name, String type) {
super();
this.category = category;
this.name = name;
if(type == null)
this.type = ServiceEndpoint.class;
else{
Type extractedType = Type.valueOf(type);
switch(extractedType){
case ENDPOINT:
this.type = ServiceEndpoint.class;
break;
case GCOREENDPOINT:
this.type = GCoreEndpoint.class;
break;
case GENERIC:
this.type = GenericResource.class;
break;
case NODE:
this.type = HostingNode.class;
break;
case SOFTWARE:
this.type = Software.class;
break;
default:
this.type = ServiceEndpoint.class;
}
}
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class getType() {
return type;
}
public void Class(Class type) {
this.type = type;
}
@Override
public String toString() {
return "BasicFunctionalityBean [category=" + category + ", name="
+ name + ", type=" + type + "]";
}
}

View File

@ -0,0 +1,91 @@
package org.gcube.informationsystem.resource_checker.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.gcube.common.resources.gcore.GenericResource;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.resources.discovery.icclient.ICFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Retrieve the list of contexts in which resources must be found
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@SuppressWarnings({"unchecked","rawtypes"})
public class RetrieveContextsList {
private static final String VO_SCOPES_FILE_PATH = "/META-INF/plugin_resources/VoScopes.xml";
private static Logger logger = LoggerFactory.getLogger(RetrieveContextsList.class);
public static final List<String> getContexts() throws ParserConfigurationException, SAXException, IOException{
List<String> contexts = new ArrayList<String>();
// load vos from file
loadVOs(contexts);
// load vres
loadVREs(contexts);
return contexts;
}
private static void loadVREs(List<String> voContexts) throws SAXException, IOException, ParserConfigurationException {
SimpleQuery queryVRE = ICFactory.queryFor(GenericResource.class);
queryVRE.addCondition("$resource/Profile/SecondaryType/text() = 'VRE'");
queryVRE.setResult("$resource/Profile/Body/Scope/string()");
DiscoveryClient vREScopeClient = ICFactory.client();
List<String> vres = new ArrayList<String>();
for (String vo: voContexts){
ScopeProvider.instance.set(vo);
List<String> vresScopes = vREScopeClient.submit(queryVRE);
logger.debug("vres found " + vresScopes.size() + " in " + vo);
vres.addAll(vresScopes);
}
voContexts.addAll(vres);
logger.info("List of all contexts is " + voContexts);
}
private static void loadVOs(List<String> contexts) throws ParserConfigurationException, SAXException, IOException {
String infrastructureRoot = "/" + ScopeProvider.instance.get().split("/")[1];
logger.debug("Infrastructure root is " + infrastructureRoot);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(RetrieveContextsList.class.getResourceAsStream(VO_SCOPES_FILE_PATH));
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("scope");
for (int i = 0; i < nList.getLength(); i++){
Node nNode = nList.item(i);
String context = nNode.getTextContent();
if(context.startsWith(infrastructureRoot))
contexts.add(context);
}
logger.info("List of VOs is " + contexts);
}
}

View File

@ -0,0 +1,328 @@
package org.gcube.informationsystem.resource_checker.utils;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.informationsystem.resource_checker.ResourceCheckerPluginDeclaration;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.vremanagement.executor.plugin.PluginStateEvolution;
import org.gcube.vremanagement.executor.plugin.PluginStateNotification;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Send a notification to the interested person or people.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@SuppressWarnings("unchecked")
public class SendNotification extends PluginStateNotification {
private Map<String, String> pluginInputs;
private static Logger logger = LoggerFactory.getLogger(SendNotification.class);
// JOB STATUS NOTIFICATIONS
private static final String NOTIFY_METHOD_JOB_STATUS = "2/notifications/notify-job-status";
// FETCH USERS HAVING ROLE METHOD
private static final String USERS_METHOD_HAVING_ROLE = "2/users/get-usernames-by-global-role";
// SEND MESSAGE TO USERS
private static final String NOTIFY_METHOD_MESSAGE = "2/messages/write-message";
// SNL INFORMATIONs
private static final String RESOURE_SN = "jersey-servlet";
private static final String SERVICE_NAME_SN = "SocialNetworking";
private static final String SERVICE_CLASSE_SN = "Portal";
// user to contact on exception via social-networking ws
public final static String RECIPIENT_KEY = "recipient";
// service name on job notifications
private final static String SERVICE_NAME = "Smart-Executor";
public SendNotification(Map<String, String> inputs) {
super(inputs);
this.pluginInputs = inputs;
}
@Override
/**
* This is sent on failures.
*/
public void pluginStateEvolution(PluginStateEvolution pluginStateEvolution, Exception exception) throws Exception {
switch(pluginStateEvolution.getPluginState()){
case STOPPED:
case FAILED:
case DISCARDED:
// check what happened
String recipient = pluginInputs.get(RECIPIENT_KEY);
String basePath = discoverEndPoint();
logger.info("Recipient of the notification is " + recipient + ". Base path found for the notification service is " + basePath);
if(basePath != null && recipient != null){
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
basePath += NOTIFY_METHOD_JOB_STATUS + "?gcube-token=" + SecurityTokenProvider.instance.get();
basePath = basePath.trim();
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()){
JSONObject obj = new JSONObject();
obj.put("job_id", pluginStateEvolution.getUuid().toString());
obj.put("recipient", recipient);
obj.put("job_name", pluginStateEvolution.getPluginDeclaration().getName());
obj.put("service_name", SERVICE_NAME);
obj.put("status", "FAILED");
obj.put("status_message", "original status reported by " + SERVICE_NAME + " was " + pluginStateEvolution.getPluginState()
+ ". Exception is " + exception != null ? exception.getMessage() : null);
// }
logger.debug("Request json is going to be " + obj.toString());
HttpResponse response = performRequestPost(httpClient, basePath, obj.toString());
logger.info(response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
int status = response.getStatusLine().getStatusCode();
if(status == HttpURLConnection.HTTP_OK){
logger.info("Notification sent");
}
else if(status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER){
// redirect -> fetch new location
Header[] locations = response.getHeaders("Location");
Header lastLocation = locations[locations.length - 1];
String realLocation = lastLocation.getValue();
logger.info("New location is " + realLocation);
response = performRequestPost(httpClient, realLocation, obj.toString());
logger.info(" " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
}else
logger.warn(" " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
}catch (Exception e) {
logger.warn("Something failed when trying to notify the user", e);
}
}else
logger.error("No notification is going to be sent, because social service is missing or recipient is not specified");
break;
default:
logger.info("No notification is going to be sent, because the status of the plugin execution is " + pluginStateEvolution.getPluginState().name());
}
}
/**
* Send a message to the portal administrators via social-networking-service
* @param missingResourcesPerContext
* @param otherFailures
* @param role
*/
public static void sendMessage(Map<String, List<BasicFunctionalityBean>> missingResourcesPerContext, String otherFailures, String role) {
String basePath = discoverEndPoint();
logger.debug("Sending notification to users having role = " + role + " using social service at path " + basePath);
if(basePath != null && role != null){
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
basePath = basePath.trim();
String fetchUsersPath = basePath + USERS_METHOD_HAVING_ROLE + "?gcube-token=" + SecurityTokenProvider.instance.get() + "&role-name=" + role;
String sendMessagePath = basePath + NOTIFY_METHOD_MESSAGE + "?gcube-token=" + SecurityTokenProvider.instance.get();
// fetch these users
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()){
HttpResponse response = performRequestGet(httpClient, fetchUsersPath);
int status = response.getStatusLine().getStatusCode();
logger.debug("Status code is " + status + " and response message is " + response.getStatusLine().getReasonPhrase());
if(status == HttpURLConnection.HTTP_OK){
String resultUsers = EntityUtils.toString(response.getEntity());
JSONParser parser = new JSONParser();
JSONObject resultJson = (JSONObject) parser.parse(resultUsers);
JSONArray array = (JSONArray)resultJson.get("result");
logger.info("list of users to notify is " + array);
if(array.isEmpty()){
logger.warn("No one has role " + role + " .. exiting");
return;
}
JSONArray arrayRecipients = new JSONArray();
for (int i = 0; i < array.size(); i++) {
String user = (String) array.get(i);
JSONObject objR = new JSONObject();
objR.put("id", user);
arrayRecipients.add(objR);
}
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("dd/MM/yy HH:mm:ss");
String dataStr = sdf.format(new Date());
StringBuilder sb = new StringBuilder();
sb.append("Dear ");
sb.append(role).append(",").append("\n");
sb.append("this is the report of the last running of the " + ResourceCheckerPluginDeclaration.NAME.toUpperCase() + " (" + dataStr + ").\nThe following missing resources have been found:");
Iterator<Entry<String, List<BasicFunctionalityBean>>> iterator = missingResourcesPerContext.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<java.lang.String, java.util.List<org.gcube.informationsystem.resource_checker.utils.BasicFunctionalityBean>> entry = (Map.Entry<java.lang.String, java.util.List<org.gcube.informationsystem.resource_checker.utils.BasicFunctionalityBean>>) iterator
.next();
sb.append("\n");
List<BasicFunctionalityBean> list = entry.getValue();
for (BasicFunctionalityBean basicFunctionalityBean : list) {
sb.append("- resource's name ");
sb.append(basicFunctionalityBean.getName());
sb.append(" and resource's class/category ");
sb.append(basicFunctionalityBean.getCategory());
sb.append(" (in context " + entry.getKey() + ")");
}
if(iterator.hasNext())
sb.append(";");
else
sb.append(".");
}
sb.append("\n\n");
sb.append(otherFailures + ".\n");
sb.append("Best,\n" + ResourceCheckerPluginDeclaration.NAME);
String message = sb.toString();
logger.debug("Going to send this message \n" + message);
// send message
JSONObject obj = new JSONObject();
obj.put("body", message);
obj.put("subject", "Resource Checker SE - Report (" + dataStr + ")");
obj.put("recipients", arrayRecipients);
logger.debug("Request json is going to be " + obj.toString());
response = performRequestPost(httpClient, sendMessagePath, obj.toString());
logger.info(response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
status = response.getStatusLine().getStatusCode();
if(status == HttpURLConnection.HTTP_OK){
logger.info("Message sent");
}
else if(status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER){
// redirect -> fetch new location
Header[] locations = response.getHeaders("Location");
Header lastLocation = locations[locations.length - 1];
String realLocation = lastLocation.getValue();
logger.info("New location is " + realLocation);
response = performRequestPost(httpClient, realLocation, obj.toString());
}
}
}catch (Exception e) {
logger.warn("Failed to notify users...", e);
}
}
}
/**
* Perform the post/json request
* @param httpClient
* @param path
* @param params
* @return
* @throws ClientProtocolException
* @throws IOException
*/
private static HttpResponse performRequestPost(CloseableHttpClient httpClient, String path, String params) throws ClientProtocolException, IOException{
HttpPost request = new HttpPost(path);
StringEntity paramsEntity = new StringEntity(params, ContentType.APPLICATION_JSON);
request.setEntity(paramsEntity);
return httpClient.execute(request);
}
/**
* Perform the get request
* @param httpClient
* @param path
* @param params
* @return
* @throws ClientProtocolException
* @throws IOException
*/
private static HttpResponse performRequestGet(CloseableHttpClient httpClient, String path) throws ClientProtocolException, IOException{
HttpGet request = new HttpGet(path);
return httpClient.execute(request);
}
/**
* Discover the social networking service base path.
* @return base path of the service.
*/
private static String discoverEndPoint(){
String context = ScopeProvider.instance.get();
String basePath = null;
try{
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'",SERVICE_CLASSE_SN));
query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'");
query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'",SERVICE_NAME_SN));
query.setResult("$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""+RESOURE_SN+"\"]/text()");
DiscoveryClient<String> client = client();
List<String> endpoints = client.submit(query);
if (endpoints == null || endpoints.isEmpty())
throw new Exception("Cannot retrieve the GCoreEndpoint serviceName: "+SERVICE_NAME_SN +", serviceClass: " +SERVICE_CLASSE_SN +", in scope: "+context);
basePath = endpoints.get(0);
if(basePath==null)
throw new Exception("Endpoint:"+RESOURE_SN+", is null for serviceName: "+SERVICE_NAME_SN +", serviceClass: " +SERVICE_CLASSE_SN +", in scope: "+context);
logger.info("found entryname "+basePath+" for ckanResource: "+RESOURE_SN);
}catch(Exception e){
logger.error("Unable to retrieve such service endpoint information!", e);
}
return basePath;
}
}

View File

@ -0,0 +1,75 @@
<infrastructures>
<infrastructure>
<name>d4science</name>
<vos>
<vo>
<name>d4science</name>
<src>ServiceMap_d4science.research-infrastructures.eu.xml</src>
<scope>/d4science.research-infrastructures.eu</scope>
</vo>
<vo>
<name>d4science/D4Research</name>
<src>ServiceMap_D4Research.xml</src>
<scope>/d4science.research-infrastructures.eu/D4Research</scope>
</vo>
<vo>
<name>d4science/Edison</name>
<src>ServiceMap_Edison.xml</src>
<scope>/d4science.research-infrastructures.eu/Edison</scope>
</vo>
<vo>
<name>d4science/FARM</name>
<src>ServiceMap_FARM.xml</src>
<scope>/d4science.research-infrastructures.eu/FARM</scope>
</vo>
<vo>
<name>d4science/gCubeApps</name>
<src>ServiceMap_gCubeApps.xml</src>
<scope>/d4science.research-infrastructures.eu/gCubeApps</scope>
</vo>
<vo>
<name>d4science/OpenAIRE</name>
<src>ServiceMap_OpenAIRE.xml</src>
<scope>/d4science.research-infrastructures.eu/OpenAIRE</scope>
</vo>
<vo>
<name>d4science/SmartArea</name>
<src>ServiceMap_SmartArea.xml</src>
<scope>/d4science.research-infrastructures.eu/SmartArea</scope>
</vo>
<vo>
<name>d4science/SoBigData</name>
<src>ServiceMap_SoBigData.xml</src>
<scope>/d4science.research-infrastructures.eu/SoBigData</scope>
</vo>
</vos>
</infrastructure>
<infrastructure>
<name>gcube</name>
<vos>
<vo>
<name>gcube</name>
<src>ServiceMap_gcube.xml</src>
<scope>/gcube</scope>
</vo>
<vo>
<name>gcube/devsec</name>
<src>ServiceMap_devsec.xml</src>
<scope>/gcube/devsec</scope>
</vo>
<vo>
<name>gcube/devNext</name>
<src>ServiceMap_devNext.xml</src>
<scope>/gcube/devNext</scope>
</vo>
<vo>
<name>gcube/preprod</name>
<src>ServiceMap_preprod.xml</src>
<scope>/gcube/preprod</scope>
</vo>
</vos>
</infrastructure>
</infrastructures>

View File

@ -0,0 +1,5 @@
#Resources to fetch are reported here. It can be read as follows
# check for resource having (ServiceName = ServiceNames[i], CategoryName = CategoryNames[i])
# where i stands for the i-th position
ServiceNames=HTTP-URI-Resolver,Persistence,StorageManager
CategoryNames=Service,Accounting,DataStorage

View File

@ -0,0 +1 @@
org.gcube.common.resource_checker.ResourceCheckerPluginDeclaration

View File

@ -0,0 +1,24 @@
package org.gcube.informationsystem.resource_checker;
import java.util.HashMap;
import java.util.Map;
import org.gcube.informationsystem.resource_checker.ResourceCheckerPlugin;
import org.gcube.informationsystem.resource_checker.utils.SendNotification;
public class TestResourceChecker{
//@Test
public void launchPlugin() throws Exception{
// ScopeProvider.instance.set(....);
// SecurityTokenProvider.instance.set(....);
ResourceCheckerPlugin checker = new ResourceCheckerPlugin(null);
Map<String, Object> inputs = new HashMap<String, Object>();
inputs.put(SendNotification.RECIPIENT_KEY, null);
inputs.put(ResourceCheckerPlugin.ROLE_TO_NOTIFY, null);
checker.launch(inputs);
}
}