diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java new file mode 100644 index 00000000000..08efa23e844 --- /dev/null +++ b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java @@ -0,0 +1,110 @@ +package io.jans.configapi.model.status; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "memoryfree", "swapfree", "hostname", "ipaddress", "uptime", "free_disk_space", "load_average" }) +public class FacterData { + + @JsonProperty("memoryfree") + private String memoryfree; + + @JsonProperty("swapfree") + private String swapfree; + + @JsonProperty("hostname") + private String hostname; + + @JsonProperty("ipaddress") + private String ipaddress; + + @JsonProperty("uptime") + private String uptime; + + @JsonProperty("free_disk_space") + private String freeDiskSpace; + + @JsonProperty("load_average") + private String loadAverage; + + + @JsonProperty("memoryfree") + public String getMemoryfree() { + return memoryfree; + } + + @JsonProperty("memoryfree") + public void setMemoryfree(String memoryfree) { + this.memoryfree = memoryfree; + } + + @JsonProperty("swapfree") + public String getSwapfree() { + return swapfree; + } + + @JsonProperty("swapfree") + public void setSwapfree(String swapfree) { + this.swapfree = swapfree; + } + + @JsonProperty("hostname") + public String getHostname() { + return hostname; + } + + @JsonProperty("hostname") + public void setHostname(String hostname) { + this.hostname = hostname; + } + + @JsonProperty("ipaddress") + public String getIpaddress() { + return ipaddress; + } + + @JsonProperty("ipaddress") + public void setIpaddress(String ipaddress) { + this.ipaddress = ipaddress; + } + + @JsonProperty("uptime") + public String getUptime() { + return uptime; + } + + @JsonProperty("uptime") + public void setUptime(String uptime) { + this.uptime = uptime; + } + + @JsonProperty("free_disk_space") + public String getFreeDiskSpace() { + return freeDiskSpace; + } + + @JsonProperty("free_disk_space") + public void setFreeDiskSpace(String freeDiskSpace) { + this.freeDiskSpace = freeDiskSpace; + } + + @JsonProperty("load_average") + public String getLoadAverage() { + return loadAverage; + } + + @JsonProperty("load_average") + public void setLoadAverage(String loadAverage) { + this.loadAverage = loadAverage; + } + + @Override + public String toString() { + return "FacterData [memoryfree=" + memoryfree + ", swapfree=" + swapfree + ", hostname=" + hostname + + ", ipaddress=" + ipaddress + ", uptime=" + uptime + ", freeDiskSpace=" + freeDiskSpace + + ", loadAverage=" + loadAverage + "]"; + } + +} diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java new file mode 100644 index 00000000000..4f490ecd3a1 --- /dev/null +++ b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java @@ -0,0 +1,51 @@ +package io.jans.configapi.model.status; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +import java.util.Date; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "dbType", "lastUpdate", "facterData", }) +public class StatsData { + + @JsonProperty("dbType") + private String dbType; + + @JsonProperty("lastUpdate") + private Date lastUpdate; + + @JsonProperty("facterData") + private FacterData facterData; + + public String getDbType() { + return dbType; + } + + public void setDbType(String dbType) { + this.dbType = dbType; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public FacterData getFacterData() { + return facterData; + } + + public void setFacterData(FacterData facterData) { + this.facterData = facterData; + } + + @Override + public String toString() { + return "StatsData [dbType=" + dbType + ", lastUpdate=" + lastUpdate + ", facterData=" + facterData + "]"; + } + +} diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java index 12ed4df02f4..4750279214e 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java @@ -72,6 +72,7 @@ private ApiConstants() {} public static final String STATISTICS = "/stat"; public static final String USER = "/user"; public static final String ORG = "/org"; + public static final String SERVER_STAT = "/server-stat"; public static final String LIMIT = "limit"; public static final String START_INDEX = "startIndex"; diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index fc03609f072..979f43deeb4 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -33,6 +33,7 @@ tags: - name: OAuth - Scopes - name: Statistics - User - name: Health - Check + - name: Server Stats - name: SCIM - User Management - name: SCIM - Config Management - name: Organization Configuration @@ -2378,6 +2379,23 @@ paths: $ref: '#/components/schemas/HealthStatusItem' '500': description: Internal Server Error + + /jans-config-api/api/v1/health/server-stat: + get: + summary: Returns application server status. + description: Returns application server status. + operationId: get-server-stat + tags: + - Server Stats + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/StatsData' + '500': + description: Internal Server Error /jans-config-api/scim/user: get: @@ -2807,7 +2825,7 @@ paths: $ref: '#/components/schemas/ErrorResponse' security: - oauth2: [https://jans.io/oauth/config/scim/users.read https://jans.io/scim/users.read] - + /jans-config-api/scim/config: get: summary: Retrieves SCIM App configuration. @@ -2860,7 +2878,7 @@ paths: $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' - + /jans-config-api/api/v1/org: get: summary: Retrieves organization configuration. @@ -2913,7 +2931,7 @@ paths: $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' - + /jans-config-api/api/v1/jans-auth-server/health: get: summary: Returns auth server health status. @@ -6598,7 +6616,7 @@ components: useLocalCache: type: boolean description: Boolean value specifying whether to enable local in-memory cache. - + Organization: type: object properties: @@ -6640,5 +6658,46 @@ components: jsFaviconPath: type: string description: Path to organization favicon image + + + FacterData: + type: object + properties: + memoryfree: + type: string + description: Server free memory + swapfree: + type: string + description: Server swap free + hostname: + type: string + description: Server hostname + ipaddress: + type: string + description: Server ipaddress + uptime: + type: string + description: Server uptime + free_disk_space: + type: string + description: Server free disk space + load_average: + type: string + description: Server average load time + + + StatsData: + type: object + properties: + dbType: + type: string + description: Jans Server DB type + lastUpdate: + type: string + description: Stats update time + facterData: + type: object + $ref: '#/components/schemas/FacterData' + description: Underlying Server stats - + diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index 3109daa325e..7f7fff14b15 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -39,11 +39,11 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/con #test.issuer=https:// pujavs.jans.server3 # jans.server1 -token.endpoint=https://jans.server1/jans-auth/restv1/token -token.grant.type=client_credentials -test.client.id=1800.ba5c72a0-733c-44e9-82fb-9c710e4e7408 -test.client.secret=EcBbZAVoH8gr -test.issuer=https://jans.server1 +#token.endpoint=https://jans.server1/jans-auth/restv1/token +#token.grant.type=client_credentials +#test.client.id=1800.df97feac-c94e-468d-9e22-48946da45403 +#test.client.secret=OL13IYRG0IjV +#test.issuer=https://jans.server1 # jans.server2 #token.endpoint=https://jans.server2/jans-auth/restv1/token @@ -59,3 +59,11 @@ test.issuer=https://jans.server1 #test.client.secret=aDiH4IuuGddZ #test.issuer=https://jans.server3 +# jans.server4 +token.endpoint=https://jans.server4/jans-auth/restv1/token +token.grant.type=client_credentials +test.client.id=1800.7e78990f-fdae-40e9-9433-4fe20645851d +test.client.secret=GfUrIapPM71X +test.issuer=https://jans.server4 + + diff --git a/jans-config-api/server/pom.xml b/jans-config-api/server/pom.xml index cac37a65a17..0211df5ec7d 100644 --- a/jans-config-api/server/pom.xml +++ b/jans-config-api/server/pom.xml @@ -201,6 +201,12 @@ ${jetty.version} + + + org.gluufederation + jython-standalone + + diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java index b718e709869..a5c2d72497e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java @@ -10,6 +10,8 @@ import io.jans.configapi.security.api.ApiProtectionService; import io.jans.configapi.security.service.AuthorizationService; import io.jans.configapi.security.service.OpenIdAuthorizationService; +import io.jans.configapi.service.status.StatusCheckerTimer; +import io.jans.configapi.service.logger.LoggerService; import io.jans.exception.ConfigurationException; import io.jans.exception.OxIntializationException; import io.jans.orm.PersistenceEntryManager; @@ -62,14 +64,20 @@ public class AppInitializer { @Inject private Instance authorizationServiceInstance; - - + + @Inject + StatusCheckerTimer statusCheckerTimer; + + @Inject + private LoggerService loggerService; + @Inject private QuartzSchedulerManager quartzSchedulerManager; public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init) { log.info("========================== Initializing - App ======================================="); log.info("============= STARTING API APPLICATION ========================"); + log.info("init:{}",init); System.setProperty(ResteasyContextParameters.RESTEASY_PATCH_FILTER_DISABLED, "true"); this.configurationFactory.create(); persistenceEntryManagerInstance.get(); @@ -77,7 +85,13 @@ public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init) // Start timer initSchedulerService(); + + // Stats timer + statusCheckerTimer.initTimer(); + // Schedule timer tasks + loggerService.initTimer(); + ResteasyProviderFactory instance = ResteasyProviderFactory.getInstance(); RegisterBuiltin.register(instance); instance.registerProvider(ResteasyJackson2Provider.class); @@ -89,6 +103,7 @@ public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init) public void destroy(@Observes @BeforeDestroyed(ApplicationScoped.class) ServletContext init) { log.info("================================================================"); log.info("=========== API APPLICATION STOPPED =========================="); + log.info("init:{}",init); log.info("================================================================"); } @@ -128,6 +143,7 @@ private AuthorizationService createAuthorizationService() { configurationFactory.getApiClientId()); return authorizationServiceInstance.select(OpenIdAuthorizationService.class).get(); } catch (Exception ex) { + log.error("Failed to create AuthorizationService instance", ex); throw new ConfigurationException("Failed to create AuthorizationService instance", ex); } } @@ -136,8 +152,8 @@ public void recreatePersistanceEntryManager(@Observes @LdapConfigurationReload S closePersistenceEntryManager(); PersistenceEntryManager ldapEntryManager = persistenceEntryManagerInstance.get(); persistenceEntryManagerInstance.destroy(ldapEntryManager); - log.debug("Recreated instance {} with operation service: {}", ldapEntryManager, - ldapEntryManager.getOperationService()); + log.debug("Recreated instance {} with operation service: {} - event:{}", ldapEntryManager, + ldapEntryManager.getOperationService(), event); } private void closePersistenceEntryManager() { @@ -153,6 +169,7 @@ private void closePersistenceEntryManager() { } protected void initSchedulerService() { + log.debug(" \n\n initSchedulerService - Entry \n\n"); quartzSchedulerManager.start(); String disableScheduler = System.getProperties().getProperty("gluu.disable.scheduler"); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java index c89a683b30c..c9ff46d3468 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java @@ -6,6 +6,7 @@ package io.jans.configapi.rest.health; +import io.jans.configapi.model.status.StatsData; import io.jans.configapi.rest.resource.auth.BaseResource; import io.jans.configapi.service.auth.ConfigurationService; import io.jans.configapi.util.ApiConstants; @@ -17,29 +18,32 @@ import org.json.JSONObject; import org.json.JSONArray; + import org.slf4j.Logger; @Path(ApiConstants.HEALTH) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class ApiHealthCheck extends BaseResource { - + @Inject - Logger log; + Logger logger; + private static final String STATUS = "status"; + @Inject ConfigurationService configurationService; @GET - public Response getHealthResponse() throws Exception { - log.debug("ApiHealthCheck::getHealthResponse() - Entry"); + public Response getHealthResponse() { + logger.debug("Api Health Check - Entry"); JSONObject jsonObject = new JSONObject(); - jsonObject.put("status", "UP"); + jsonObject.put(STATUS, "UP"); // liveness JSONObject dataJsonObject = new JSONObject(); dataJsonObject.put("name", "jans-config-api liveness"); - dataJsonObject.put("status", "UP"); + dataJsonObject.put(STATUS, "UP"); JSONArray jsonArray = new JSONArray(); jsonArray.put(0, dataJsonObject); @@ -48,50 +52,60 @@ public Response getHealthResponse() throws Exception { dataJsonObject.put("name", "jans-config-api readiness"); try { checkDatabaseConnection(); - dataJsonObject.put("status", "UP"); + dataJsonObject.put(STATUS, "UP"); } catch (Exception e) { - log.error(e.getMessage(), e); - dataJsonObject.put("status", "DOWN"); + logger.error(e.getMessage(), e); + dataJsonObject.put(STATUS, "DOWN"); dataJsonObject.put("error", "e.getMessage()"); - log.debug("\n\n\n ApiHealthCheck::getHealthResponse() - Error Response = " + jsonObject + "\n\n"); + logger.debug("Api Health Check - Error - jsonObject:{}",jsonObject); } jsonArray.put(1, dataJsonObject); jsonObject.put("checks", jsonArray); - log.debug("\n\n\n ApiHealthCheck::getHealthResponse() - jsonObject = " + jsonObject + "\n\n"); + logger.debug("ApiHealthCheck::getHealthResponse() - jsonObject:{}",jsonObject); return Response.ok(jsonObject.toString()).build(); } @GET @Path(ApiConstants.LIVE) public Response getLivenessResponse() { - log.debug("ApiHealthCheck::getLivenessResponse() - Entry"); + logger.debug("ApiHealthCheck::getLivenessResponse() - Entry"); JSONObject jsonObject = new JSONObject(); jsonObject.put("name", "jans-config-api liveness"); - jsonObject.put("status", "UP"); - log.debug("\n\n\n ApiHealthCheck::getLivenessResponse() - jsonObject = " + jsonObject + "\n\n"); + jsonObject.put(STATUS, "UP"); + logger.debug("ApiHealthCheck::getLivenessResponse() - jsonObject:{}",jsonObject); return Response.ok(jsonObject.toString()).build(); } @GET @Path(ApiConstants.READY) public Response getReadinessResponse() { - log.debug("ApiHealthCheck::getReadinessResponse() - Entry"); + logger.debug("ApiHealthCheck::getReadinessResponse() - Entry"); JSONObject jsonObject = new JSONObject(); jsonObject.put("name", "jans-config-api readiness"); try { checkDatabaseConnection(); - jsonObject.put("status", "UP"); - log.debug("\n\n\n ApiHealthCheck::getReadinessResponse() - Success Response = " + jsonObject + "\n\n"); + jsonObject.put(STATUS, "UP"); + logger.debug("Api Health Readiness - Success - jsonObject:{}",jsonObject); return Response.ok(jsonObject.toString()).build(); } catch (Exception e) { - log.error(e.getMessage(), e); + logger.error(e.getMessage(), e); jsonObject.put("error", "e.getMessage()"); - log.debug("\n\n\n ApiHealthCheck::getReadinessResponse() - Error Response = " + jsonObject + "\n\n"); + logger.debug("Api Health Readiness - Error - jsonObject:{}",jsonObject); return Response.ok(jsonObject.toString()).build(); } } + @GET + @Path(ApiConstants.SERVER_STAT) + public Response getServerStat() { + logger.debug("Server Stat - Entry"); + StatsData statsData = configurationService.getStatsData(); + logger.debug("Server Stat - statsData:{}",statsData); + return Response.ok(statsData).build(); + + } + private void checkDatabaseConnection() { configurationService.findConf(); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java index 06c3cbe8fae..e0adeef7026 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java @@ -11,6 +11,7 @@ import io.jans.as.model.configuration.AppConfiguration; import io.jans.as.persistence.model.configuration.GluuConfiguration; import io.jans.configapi.configuration.ConfigurationFactory; +import io.jans.configapi.model.status.StatsData; import io.jans.orm.PersistenceEntryManager; import io.jans.util.StringHelper; @@ -30,6 +31,8 @@ public class ConfigurationService { @Inject ConfigurationFactory configurationFactory; + + private StatsData statsData; public Conf findConf() { final String dn = configurationFactory.getConfigurationDn(); @@ -61,4 +64,13 @@ public GluuConfiguration findGluuConfiguration() { public String getPersistenceType() { return configurationFactory.getBaseConfiguration().getString("persistence.type"); } + + public StatsData getStatsData() { + return statsData; + } + + public void setStatsData(StatsData statsData) { + this.statsData = statsData; + } + } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java new file mode 100644 index 00000000000..400e51a0f85 --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java @@ -0,0 +1,14 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.service.cdi.event; + +public class StatusCheckerTimerEvent { + + public StatusCheckerTimerEvent() {} + + +} diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java new file mode 100644 index 00000000000..66b9320a27c --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java @@ -0,0 +1,35 @@ +package io.jans.configapi.service.logger; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import io.jans.configapi.model.configuration.ApiAppConfiguration; + +@ApplicationScoped +public class LoggerService extends io.jans.service.logger.LoggerService { + + @Inject + private ApiAppConfiguration appConfiguration; + + @Override + public boolean isDisableJdkLogger() { + return (appConfiguration.getDisableJdkLogger() != null) && appConfiguration.getDisableJdkLogger(); + } + + @Override + public String getLoggingLevel() { + return appConfiguration.getLoggingLevel(); + } + + @Override + public String getExternalLoggerConfiguration() { + return appConfiguration.getExternalLoggerConfiguration(); + } + + @Override + public String getLoggingLayout() { + return appConfiguration.getLoggingLayout(); + } + +} + diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java new file mode 100644 index 00000000000..02b9d70fe21 --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java @@ -0,0 +1,160 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.service.status; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import javax.inject.Named; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.exec.CommandLine; +import io.jans.configapi.model.status.StatsData; +import io.jans.configapi.model.status.FacterData; +import io.jans.util.process.ProcessHelper; + +import io.jans.configapi.configuration.ConfigurationFactory; +import io.jans.configapi.service.auth.ConfigurationService; +import io.jans.configapi.service.cdi.event.StatusCheckerTimerEvent; +import io.jans.service.cdi.async.Asynchronous; +import io.jans.service.cdi.event.BaseConfigurationReload; +import io.jans.service.cdi.event.ConfigurationEvent; +import io.jans.service.cdi.event.ConfigurationUpdate; +import io.jans.service.cdi.event.LdapConfigurationReload; +import io.jans.service.cdi.event.Scheduled; +import io.jans.service.timer.event.TimerEvent; +import io.jans.service.timer.schedule.TimerSchedule; +import io.jans.util.StringHelper; +import io.jans.util.properties.FileConfiguration; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import org.apache.commons.lang.StringUtils; +import org.json.JSONObject; +import org.slf4j.Logger; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@ApplicationScoped +@Named +public class StatusCheckerTimer { + + private static final int DEFAULT_INTERVAL = 5 * 60; // 1 minute + public static final String PROGRAM_FACTER = "facter"; + + @Inject + private Logger log; + + @Inject + private Event timerEvent; + + @Inject + private ConfigurationService configurationService; + + @Inject + private ConfigurationFactory configurationFactory; + + private AtomicBoolean isActive; + + @PostConstruct + public void create() { + log.debug("Creating Status Cheker Timer"); + } + + public void initTimer() { + log.debug("Initializing Status Checker Timer"); + this.isActive = new AtomicBoolean(false); + + final int delay = 1 * 60; + final int interval = DEFAULT_INTERVAL; + + timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new StatusCheckerTimerEvent(), + Scheduled.Literal.INSTANCE)); + } + + @Asynchronous + public void process(@Observes @Scheduled StatusCheckerTimerEvent statusCheckerTimerEvent) { + log.debug("Status Checker Timer Process"); + if (this.isActive.get()) { + return; + } + + if (!this.isActive.compareAndSet(false, true)) { + return; + } + + try { + processInt(); + } finally { + this.isActive.set(false); + } + } + + /** + * Gather periodically site and server status + * + * @param when Date + * @param interval Interval + */ + private void processInt() { + log.debug("Starting update of sever status"); + + StatsData statsData = new StatsData(); + Date currentDateTime = new Date(); + statsData.setLastUpdate(currentDateTime); + statsData.setFacterData(getFacterData()); + statsData.setDbType(configurationService.getPersistenceType()); + + configurationService.setStatsData(statsData); + log.debug("Configuration status update finished"); + } + + private FacterData getFacterData() { + log.debug("Getting Server status"); + FacterData facterData = new FacterData(); + ObjectMapper mapper = new ObjectMapper(); + if (!isLinux()) { + return facterData; + } + CommandLine commandLine = new CommandLine(PROGRAM_FACTER); + commandLine.addArgument("-j"); + String resultOutput; + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);) { + boolean result = ProcessHelper.executeProgram(commandLine, false, 0, bos); + if (!result) { + return facterData; + } + resultOutput = new String(bos.toByteArray(), UTF_8); + facterData = mapper.readValue(resultOutput, FacterData.class); + } catch (UnsupportedEncodingException ex) { + log.error("Failed to parse program {} output", PROGRAM_FACTER, ex); + return facterData; + } catch (IOException e) { + e.printStackTrace(); + } + log.debug("Server status - facterData:{}", facterData); + return facterData; + } + + private boolean isLinux() { + String osName = System.getProperty("os.name"); + return !StringHelper.isEmpty(osName) && osName.toLowerCase().contains("linux"); + } +} diff --git a/jans-config-api/server/src/test/resources/feature/health/server-health.feature b/jans-config-api/server/src/test/resources/feature/health/server-health.feature new file mode 100644 index 00000000000..4b7d44306a7 --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/health/server-health.feature @@ -0,0 +1,14 @@ + +Feature: Verify Server stats + +Background: + * def mainUrl = healthUrl + "/server-stat" + + Scenario: Verify Underlying server stats + Given url mainUrl + When method GET + Then status 200 + And print response + + + \ No newline at end of file