From 6ffbe4f69368665054abf9bfe6b3cdfb171884b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kinen?= Date: Tue, 17 Dec 2019 14:22:13 +0200 Subject: [PATCH 1/2] Common way of signalling app health --- .../java/org/oskari/status/AppStatus.java | 76 +++++++++++++++++++ .../org/oskari/status/ForceDisableByFile.java | 54 +++++++++++++ .../java/fi/nls/oskari/StatusController.java | 45 +++++++++++ 3 files changed, 175 insertions(+) create mode 100644 service-base/src/main/java/org/oskari/status/AppStatus.java create mode 100644 service-base/src/main/java/org/oskari/status/ForceDisableByFile.java create mode 100644 servlet-map/src/main/java/fi/nls/oskari/StatusController.java diff --git a/service-base/src/main/java/org/oskari/status/AppStatus.java b/service-base/src/main/java/org/oskari/status/AppStatus.java new file mode 100644 index 0000000000..d67b63fe64 --- /dev/null +++ b/service-base/src/main/java/org/oskari/status/AppStatus.java @@ -0,0 +1,76 @@ +package org.oskari.status; + +import fi.nls.oskari.service.OskariComponent; + +/** + * Get status with: + * OskariComponentManager.getComponentsOfType(AppStatus.class) + * + * Usage example: + boolean highSeverityChecksOk = getChecks().stream() + .filter(s -> s.isEnabled()) + .filter(s -> s.getSeverity() == AppStatus.Severity.HIGH) + .allMatch(s -> s.isOk()); + */ +public abstract class AppStatus extends OskariComponent { + + public enum Severity { + // allow app to keep running + LOW, + // app should stop responding if this is not OK + HIGH + }; + + public enum Level { + // all good + OK, + // parts of the feature is working while others are not + PARTIAL, + // not working at all + BROKEN + }; + + /** + * Name for the check that could be shown in a status monitor + * @return + */ + public String getName() { + return this.getClass().getName(); + } + + public boolean isEnabled() { + return true; + } + /** + * Describe what is being checked + * @return + */ + public String getDescription() { + return ""; + } + + /** + * Provide reason for check failing + * @return + */ + public String getReason() { + return ""; + } + + /** + * LOW if the app can run even without this feature working + * HIGH if the app should be stopped when this functionality is not working + * @return + */ + public abstract Severity getSeverity(); + + /** + * Level of functionality: ok, partial, broken == not working + * @return + */ + public abstract Level getLevel(); + + public boolean isOk() { + return Level.OK.equals(getLevel()); + } +} diff --git a/service-base/src/main/java/org/oskari/status/ForceDisableByFile.java b/service-base/src/main/java/org/oskari/status/ForceDisableByFile.java new file mode 100644 index 0000000000..75a6b51261 --- /dev/null +++ b/service-base/src/main/java/org/oskari/status/ForceDisableByFile.java @@ -0,0 +1,54 @@ +package org.oskari.status; + +import fi.nls.oskari.annotation.Oskari; +import fi.nls.oskari.service.OskariComponent; +import fi.nls.oskari.util.PropertyUtil; + +import java.io.File; + +@Oskari +public class ForceDisableByFile extends AppStatus { + + private String fileToCheck; + + public void init() { + fileToCheck = PropertyUtil.get("disablefile.path", null); + } + + public boolean isEnabled() { + return fileToCheck != null; + } + + /** + * File found -> app should be disabled + * not found -> OK + * @return + */ + public Level getLevel() { + File status = new File(fileToCheck); + if(status.exists()) { + return Level.BROKEN; + } + return Level.OK; + } + + public String getDescription() { + return "Checks if file '" + fileToCheck + "' exists."; + } + + /** + * Provide reason for check failing + * @return + */ + public String getReason() { + return fileToCheck + " file exists"; + } + + /** + * This is a manual check for file. If it exists -> the app should be stopped + * @return + */ + public Severity getSeverity() { + return Severity.HIGH; + } +} diff --git a/servlet-map/src/main/java/fi/nls/oskari/StatusController.java b/servlet-map/src/main/java/fi/nls/oskari/StatusController.java new file mode 100644 index 0000000000..f5d23e83a1 --- /dev/null +++ b/servlet-map/src/main/java/fi/nls/oskari/StatusController.java @@ -0,0 +1,45 @@ +package fi.nls.oskari; + +import fi.nls.oskari.control.ActionParameters; +import fi.nls.oskari.service.OskariComponentManager; +import fi.nls.oskari.spring.extension.OskariParam; +import org.oskari.status.AppStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Controller +public class StatusController { + + private Collection getChecks() { + Map statuses = OskariComponentManager.getComponentsOfType(AppStatus.class); + return statuses.values(); + } + + @RequestMapping("/health") + public ResponseEntity health() { + boolean highSeverityChecksOk = getChecks().stream() + .filter(s -> s.isEnabled()) + .filter(s -> s.getSeverity() == AppStatus.Severity.HIGH) + .allMatch(s -> s.isOk()); + if (!highSeverityChecksOk) { + return new ResponseEntity("DISABLED", HttpStatus.SERVICE_UNAVAILABLE); + } + return new ResponseEntity("OK", HttpStatus.OK); + } + + @RequestMapping("/status") + public Collection status(@OskariParam ActionParameters params) { + if (!params.getUser().isAdmin()) { + return null; + } + return getChecks(); + } + +} From b8a7857d68bd71cfa86f4c541b7e28034a70f8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kinen?= Date: Tue, 17 Dec 2019 15:03:04 +0200 Subject: [PATCH 2/2] Move file check to servlet-map --- .../src/main/java/fi/nls/oskari}/ForceDisableByFile.java | 3 ++- .../src/main/java/fi/nls/oskari/StatusController.java | 5 ++++- .../META-INF/services/javax.annotation.processing.Processor | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) rename {service-base/src/main/java/org/oskari/status => servlet-map/src/main/java/fi/nls/oskari}/ForceDisableByFile.java (95%) create mode 100644 servlet-map/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/service-base/src/main/java/org/oskari/status/ForceDisableByFile.java b/servlet-map/src/main/java/fi/nls/oskari/ForceDisableByFile.java similarity index 95% rename from service-base/src/main/java/org/oskari/status/ForceDisableByFile.java rename to servlet-map/src/main/java/fi/nls/oskari/ForceDisableByFile.java index 75a6b51261..704eb09fae 100644 --- a/service-base/src/main/java/org/oskari/status/ForceDisableByFile.java +++ b/servlet-map/src/main/java/fi/nls/oskari/ForceDisableByFile.java @@ -1,8 +1,9 @@ -package org.oskari.status; +package fi.nls.oskari; import fi.nls.oskari.annotation.Oskari; import fi.nls.oskari.service.OskariComponent; import fi.nls.oskari.util.PropertyUtil; +import org.oskari.status.AppStatus; import java.io.File; diff --git a/servlet-map/src/main/java/fi/nls/oskari/StatusController.java b/servlet-map/src/main/java/fi/nls/oskari/StatusController.java index f5d23e83a1..2edac29b47 100644 --- a/servlet-map/src/main/java/fi/nls/oskari/StatusController.java +++ b/servlet-map/src/main/java/fi/nls/oskari/StatusController.java @@ -9,8 +9,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -35,9 +37,10 @@ public ResponseEntity health() { } @RequestMapping("/status") + @ResponseBody public Collection status(@OskariParam ActionParameters params) { if (!params.getUser().isAdmin()) { - return null; + return Collections.emptyList(); } return getChecks(); } diff --git a/servlet-map/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/servlet-map/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000000..3f44ff9330 --- /dev/null +++ b/servlet-map/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +fi.nls.oskari.annotation.OskariComponentAnnotationProcessor