added `database` health_check
This commit is contained in:
parent
ed7d1e36da
commit
faffb42483
|
@ -1,15 +1,17 @@
|
||||||
package org.gcube.application.geoportal.service;
|
package org.gcube.application.geoportal.service;
|
||||||
|
|
||||||
|
|
||||||
public class ServiceConstants {
|
public class ServiceConstants {
|
||||||
|
|
||||||
public static final String SE_GNA_DB_FLAG="GNA_DB";
|
// SE DB flagName
|
||||||
public static final String SE_GNA_DB_CATEGORY="Database";
|
public static final String SE_GNA_DB_FLAGNAME = "GNA_DB";
|
||||||
|
// SE DB flagValue
|
||||||
public static final String MONGO_SE_PLATFORM="mongodb";
|
public static final String SE_GNA_DB_FLAGVALUE = "Concessioni";
|
||||||
public static final String MONGO_SE_GNA_FLAG="internal-db";
|
// SE DB category
|
||||||
|
public static final String SE_GNA_DB_CATEGORY = "Database";
|
||||||
|
// SE DB platform
|
||||||
|
public static final String SE_GNA_DB_PLATFORM = "postgis";
|
||||||
|
|
||||||
|
public static final String MONGO_SE_PLATFORM = "mongodb";
|
||||||
|
public static final String MONGO_SE_GNA_FLAG = "internal-db";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class MongoClientProvider extends AbstractScopedMap<Mongo> {
|
||||||
getProvidedObjectByClass(ISInterface.class),
|
getProvidedObjectByClass(ISInterface.class),
|
||||||
ServiceConstants.SE_GNA_DB_CATEGORY,
|
ServiceConstants.SE_GNA_DB_CATEGORY,
|
||||||
ServiceConstants.MONGO_SE_PLATFORM,
|
ServiceConstants.MONGO_SE_PLATFORM,
|
||||||
ServiceConstants.SE_GNA_DB_FLAG,
|
ServiceConstants.SE_GNA_DB_FLAGNAME,
|
||||||
ServiceConstants.MONGO_SE_GNA_FLAG);
|
ServiceConstants.MONGO_SE_GNA_FLAG);
|
||||||
|
|
||||||
log.debug("Connecting to "+conn);
|
log.debug("Connecting to "+conn);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import javax.ws.rs.core.Response.ResponseBuilder;
|
||||||
|
|
||||||
import org.eclipse.microprofile.health.HealthCheckResponse;
|
import org.eclipse.microprofile.health.HealthCheckResponse;
|
||||||
import org.eclipse.microprofile.health.HealthCheckResponse.State;
|
import org.eclipse.microprofile.health.HealthCheckResponse.State;
|
||||||
|
import org.gcube.application.geoportal.service.rest.health.DatabaseHealthCheck;
|
||||||
import org.gcube.application.geoportal.service.rest.health.GeoportalHealthCheck;
|
import org.gcube.application.geoportal.service.rest.health.GeoportalHealthCheck;
|
||||||
import org.gcube.application.geoportal.service.rest.health.HealthCheckResponseSerializer;
|
import org.gcube.application.geoportal.service.rest.health.HealthCheckResponseSerializer;
|
||||||
import org.gcube.application.geoportal.service.rest.health.MongoHealthCheck;
|
import org.gcube.application.geoportal.service.rest.health.MongoHealthCheck;
|
||||||
|
@ -25,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
*
|
*
|
||||||
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
|
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
|
||||||
*
|
*
|
||||||
* Oct 22, 2024
|
* Oct 22, 2024
|
||||||
*/
|
*/
|
||||||
@Path("/health")
|
@Path("/health")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -45,7 +46,8 @@ public class GeoportalHealth {
|
||||||
/**
|
/**
|
||||||
* Service check.
|
* Service check.
|
||||||
*
|
*
|
||||||
* @return the response compliant to `microprofile-health` specification. 200 if is OK. Otherwise it fails.
|
* @return the response compliant to `microprofile-health` specification. 200 if
|
||||||
|
* is OK. Otherwise it fails.
|
||||||
* @throws JsonProcessingException the json processing exception
|
* @throws JsonProcessingException the json processing exception
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
|
@ -60,17 +62,50 @@ public class GeoportalHealth {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database check.
|
* Mongo check.
|
||||||
*
|
*
|
||||||
* @param context the gcube context
|
* @param context the gcube context
|
||||||
* @param include_collections if the check has to include the mongo collections in the response
|
* @param include_collections if the check has to include the mongo collections
|
||||||
|
* in the response
|
||||||
* @return the response compliant to `microprofile-health` specification
|
* @return the response compliant to `microprofile-health` specification
|
||||||
* @throws JsonProcessingException the json processing exception
|
* @throws JsonProcessingException the json processing exception
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/mongo")
|
@Path("/mongo")
|
||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public Response databaseCheck(@QueryParam("context") String context, @QueryParam("include_collections") Boolean includeCollections) throws JsonProcessingException {
|
public Response mongoCheck(@QueryParam("context") String context,
|
||||||
|
@QueryParam("include_collections") Boolean includeCollections) throws JsonProcessingException {
|
||||||
|
log.debug("mongoCheck called in the context {}", context);
|
||||||
|
if (context == null) {
|
||||||
|
HealthCheckResponse response = HealthCheckResponse.named(MongoHealthCheck.SERVICE_NAME)
|
||||||
|
.withData("context", "is required parameter (e.g. context=/gcube/devsec/devVRE)").down().build();
|
||||||
|
String json = healthCheckSerializer(response);
|
||||||
|
log.info("mongoCheck error response is {}", json);
|
||||||
|
// Bad request
|
||||||
|
return Response.status(400).entity(json).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
HealthCheckResponse response = new MongoHealthCheck(context, includeCollections).call();
|
||||||
|
ResponseBuilder responseBuilder = Response.ok();
|
||||||
|
if (response.getState().equals(State.DOWN)) {
|
||||||
|
responseBuilder = responseBuilder.status(503);
|
||||||
|
}
|
||||||
|
String json = healthCheckSerializer(response);
|
||||||
|
log.info("mongoCheck response is {}", json);
|
||||||
|
return responseBuilder.entity(json).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database check.
|
||||||
|
*
|
||||||
|
* @param context the gcube context
|
||||||
|
* @return the response compliant to `microprofile-health` specification
|
||||||
|
* @throws JsonProcessingException the json processing exception
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/database")
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public Response databaseCheck(@QueryParam("context") String context) throws JsonProcessingException {
|
||||||
log.debug("databaseCheck called in the context {}", context);
|
log.debug("databaseCheck called in the context {}", context);
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
HealthCheckResponse response = HealthCheckResponse.named(MongoHealthCheck.SERVICE_NAME)
|
HealthCheckResponse response = HealthCheckResponse.named(MongoHealthCheck.SERVICE_NAME)
|
||||||
|
@ -81,7 +116,7 @@ public class GeoportalHealth {
|
||||||
return Response.status(400).entity(json).build();
|
return Response.status(400).entity(json).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
HealthCheckResponse response = new MongoHealthCheck(context, includeCollections).call();
|
HealthCheckResponse response = new DatabaseHealthCheck(context).call();
|
||||||
ResponseBuilder responseBuilder = Response.ok();
|
ResponseBuilder responseBuilder = Response.ok();
|
||||||
if (response.getState().equals(State.DOWN)) {
|
if (response.getState().equals(State.DOWN)) {
|
||||||
responseBuilder = responseBuilder.status(503);
|
responseBuilder = responseBuilder.status(503);
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
package org.gcube.application.geoportal.service.rest.health;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.health.HealthCheck;
|
||||||
|
import org.eclipse.microprofile.health.HealthCheckResponse;
|
||||||
|
import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
|
||||||
|
import org.eclipse.microprofile.health.Liveness;
|
||||||
|
import org.eclipse.microprofile.health.Readiness;
|
||||||
|
import org.gcube.application.cms.implementations.ISInterface;
|
||||||
|
import org.gcube.application.cms.implementations.ImplementationProvider;
|
||||||
|
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
||||||
|
import org.gcube.application.geoportal.common.model.rest.DatabaseConnection;
|
||||||
|
import org.gcube.application.geoportal.service.ServiceConstants;
|
||||||
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class DatabaseHealthCheck.
|
||||||
|
*
|
||||||
|
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
|
||||||
|
*
|
||||||
|
* Oct 23, 2024
|
||||||
|
*/
|
||||||
|
@Readiness
|
||||||
|
@Liveness
|
||||||
|
@Slf4j
|
||||||
|
public class DatabaseHealthCheck implements HealthCheck {
|
||||||
|
|
||||||
|
private String context;
|
||||||
|
public static final String SERVICE_NAME = "database";
|
||||||
|
|
||||||
|
private static final int CONNECTION_TIMEOUT = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call.
|
||||||
|
*
|
||||||
|
* @return the health check response
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public HealthCheckResponse call() {
|
||||||
|
return checkDatabase(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new database health check.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
public DatabaseHealthCheck(String context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check database.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @return the health check response
|
||||||
|
*/
|
||||||
|
private HealthCheckResponse checkDatabase(String context) {
|
||||||
|
log.debug("checkMongo in the context: {}", context);
|
||||||
|
HealthCheckResponseBuilder buildHCRBuilder = HealthCheckResponse.named(SERVICE_NAME);
|
||||||
|
|
||||||
|
ScopeProvider.instance.set(context);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
DatabaseConnection databaseConnection = null;
|
||||||
|
ISInterface isInterface = ImplementationProvider.get().getProvidedObjectByClass(ISInterface.class);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isInterface == null)
|
||||||
|
throw new Exception(ISInterface.class.getSimpleName() + " configuration is null for "
|
||||||
|
+ DatabaseConnection.class.getSimpleName());
|
||||||
|
|
||||||
|
databaseConnection = isInterface.queryForDatabase(ServiceConstants.SE_GNA_DB_CATEGORY,
|
||||||
|
ServiceConstants.SE_GNA_DB_PLATFORM, ServiceConstants.SE_GNA_DB_FLAGNAME,
|
||||||
|
ServiceConstants.SE_GNA_DB_FLAGVALUE);
|
||||||
|
|
||||||
|
if (databaseConnection == null)
|
||||||
|
throw new Exception(DatabaseConnection.class.getSimpleName() + " configuration is null");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error on checking DB configuration: ", e);
|
||||||
|
buildHCRBuilder.state(false);
|
||||||
|
return buildHCRBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean connectionStatus = checkDatabaseConnection(databaseConnection);
|
||||||
|
buildHCRBuilder = appendDBInfo(buildHCRBuilder, databaseConnection);
|
||||||
|
buildHCRBuilder.state(connectionStatus);
|
||||||
|
log.info("checkDatabase is OK in the context: {}. State is {}", context, connectionStatus);
|
||||||
|
return buildHCRBuilder.build();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error on checkDatabase: ", e);
|
||||||
|
log.warn("checkDatabase is KO in the context: {}", context);
|
||||||
|
buildHCRBuilder.state(false);
|
||||||
|
return buildHCRBuilder.build();
|
||||||
|
} finally {
|
||||||
|
ScopeProvider.instance.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append DB info.
|
||||||
|
*
|
||||||
|
* @param buildHCRBuilder the build HCR builder
|
||||||
|
* @param connection the connection
|
||||||
|
* @return the health check response builder
|
||||||
|
*/
|
||||||
|
private HealthCheckResponseBuilder appendDBInfo(HealthCheckResponseBuilder buildHCRBuilder,
|
||||||
|
DatabaseConnection connection) {
|
||||||
|
buildHCRBuilder.withData("host", connection.getUrl() + "");
|
||||||
|
buildHCRBuilder.withData("user ", connection.getUser());
|
||||||
|
buildHCRBuilder.withData("pwd ", "****");
|
||||||
|
return buildHCRBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check database connection.
|
||||||
|
*
|
||||||
|
* @param connectionParameters the connection parameters
|
||||||
|
* @return true, if successful
|
||||||
|
*/
|
||||||
|
private boolean checkDatabaseConnection(DatabaseConnection connectionParameters) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (connectionParameters == null)
|
||||||
|
throw new ConfigurationException("connectionParameters is null");
|
||||||
|
|
||||||
|
// Getting connection
|
||||||
|
Connection connection = DriverManager.getConnection(connectionParameters.getUrl(),
|
||||||
|
connectionParameters.getUser(), connectionParameters.getPwd());
|
||||||
|
// Check if the connection is valid (timeout 30 seconds)
|
||||||
|
if (connection != null && connection.isValid(CONNECTION_TIMEOUT)) {
|
||||||
|
log.debug("Connection to DB " + connectionParameters.getUrl() + " is OK!");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.debug("Connection to DB " + connectionParameters.getUrl() + " is KO!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warn("Error on connecting to DB: " + connectionParameters, e);
|
||||||
|
return false;
|
||||||
|
} catch (ConfigurationException e1) {
|
||||||
|
log.warn("Error on reading connection configuration: " + connectionParameters, e1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
# Changelog for org.gcube.application.cms.sdi-plugins
|
# Changelog for org.gcube.application.cms.sdi-plugins
|
||||||
|
|
||||||
## [v1.1.4]
|
## [v1.1.4-SNAPSHOT]
|
||||||
- Improved logs
|
- Improved logs
|
||||||
- Added fallback on /geoserver/rest path [#28150#note-8]
|
- Added fallback on /geoserver/rest path [#28150#note-8]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>sdi-plugins</artifactId>
|
<artifactId>sdi-plugins</artifactId>
|
||||||
<version>1.1.4</version>
|
<version>1.1.4-SNAPSHOT</version>
|
||||||
<name>gCube CMS - SDI Plugins</name>
|
<name>gCube CMS - SDI Plugins</name>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -23,7 +23,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class SDIAbstractPlugin extends AbstractPlugin implements InitializablePlugin {
|
public abstract class SDIAbstractPlugin extends AbstractPlugin implements InitializablePlugin {
|
||||||
|
|
||||||
protected static AbstractScopedMap<SDIManagerWrapper> sdiCache;
|
public static final String POSTGIS_CREDENTIALS = "POSTGIS-CREDENTIALS";
|
||||||
|
|
||||||
|
public static final String SDI_CACHE = "SDI-CACHE";
|
||||||
|
|
||||||
|
protected static AbstractScopedMap<SDIManagerWrapper> sdiCache;
|
||||||
|
|
||||||
protected static AbstractScopedMap<DatabaseConnection> postgisCache;
|
protected static AbstractScopedMap<DatabaseConnection> postgisCache;
|
||||||
|
|
||||||
|
@ -31,7 +35,7 @@ public abstract class SDIAbstractPlugin extends AbstractPlugin implements Initia
|
||||||
private static void initCache(){
|
private static void initCache(){
|
||||||
if(sdiCache==null) {
|
if(sdiCache==null) {
|
||||||
log.info("Creating internal caches.. ");
|
log.info("Creating internal caches.. ");
|
||||||
sdiCache = new AbstractScopedMap<SDIManagerWrapper>("SDI-CACHE") {
|
sdiCache = new AbstractScopedMap<SDIManagerWrapper>(SDI_CACHE) {
|
||||||
@Override
|
@Override
|
||||||
protected SDIManagerWrapper retrieveObject(String context) throws ConfigurationException {
|
protected SDIManagerWrapper retrieveObject(String context) throws ConfigurationException {
|
||||||
try {
|
try {
|
||||||
|
@ -44,7 +48,7 @@ public abstract class SDIAbstractPlugin extends AbstractPlugin implements Initia
|
||||||
sdiCache.setTTL(Duration.of(10, ChronoUnit.MINUTES));
|
sdiCache.setTTL(Duration.of(10, ChronoUnit.MINUTES));
|
||||||
}
|
}
|
||||||
if(postgisCache==null) {
|
if(postgisCache==null) {
|
||||||
postgisCache = new AbstractScopedMap<DatabaseConnection>("POSTGIS-CREDENTIALS") {
|
postgisCache = new AbstractScopedMap<DatabaseConnection>(POSTGIS_CREDENTIALS) {
|
||||||
@Override
|
@Override
|
||||||
protected DatabaseConnection retrieveObject(String context) throws ConfigurationException {
|
protected DatabaseConnection retrieveObject(String context) throws ConfigurationException {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -463,6 +463,10 @@ public class SDIIndexerPlugin extends SDIAbstractPlugin implements IndexerPlugin
|
||||||
DatabaseConnection connectionParameters = null;
|
DatabaseConnection connectionParameters = null;
|
||||||
try {
|
try {
|
||||||
connectionParameters = postgisCache.getObject();
|
connectionParameters = postgisCache.getObject();
|
||||||
|
|
||||||
|
if(connectionParameters==null)
|
||||||
|
throw new ConfigurationException("connectionParameters is null");
|
||||||
|
|
||||||
// Getting connection
|
// Getting connection
|
||||||
Connection connection = DriverManager.getConnection(connectionParameters.getUrl(),
|
Connection connection = DriverManager.getConnection(connectionParameters.getUrl(),
|
||||||
connectionParameters.getUser(), connectionParameters.getPwd());
|
connectionParameters.getUser(), connectionParameters.getPwd());
|
||||||
|
|
Loading…
Reference in New Issue