IOT-3211 healthcheck for components 31/27231/1
authorOndrej <ondrej.tomcik@kistler.com>
Mon, 3 Sep 2018 11:31:24 +0000 (13:31 +0200)
committerPeter Rafaj <peter.rafaj@kistler.com>
Mon, 15 Oct 2018 11:54:09 +0000 (13:54 +0200)
Change-Id: I07a0f2e0d68d77a2cb0603ccc708d8e2b59a373c
Signed-off-by: Peter Rafaj <peter.rafaj@kistler.com>
cloud/account/Dockerfile
cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServer.java
cloud/resourcedirectory/Dockerfile
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/ResourceDirectoryServer.java
cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/HealthHolder.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/SimpleHealthHolder.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/http/SimpleHttpHandler.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/resource/CloudPingResource.java
cloud/stack/src/main/java/org/iotivity/cloud/base/resource/Resource.java
cloud/stack/src/main/java/org/iotivity/cloud/base/server/SimpleHttpServer.java [new file with mode: 0644]

index a70de02..e20c9bd 100644 (file)
@@ -1,5 +1,9 @@
 FROM openjdk:8-jre-alpine
 
+RUN apk add --update \
+    curl \
+    && rm -rf /var/cache/apk/*
+
 ADD ./target/CloudAccount-0.0.1-SNAPSHOT.jar iotivity/AccountServer.jar
 ADD ./target/lib/* iotivity/lib/
 ADD ./properties/* iotivity/properties/
@@ -7,6 +11,7 @@ ADD ./properties/* iotivity/properties/
 WORKDIR iotivity/
 
 ENV COAP_PORT 5685
+ENV HEALTH_CHECK_ENABLED 1
 ENV TLS_MODE 0
 ENV MONGODB_ADDRESS mongodb
 ENV MONGODB_PORT 27017
@@ -26,3 +31,4 @@ ENV JAVA_JMX_OPTS "-Dcom.sun.management.jmxremote \
 EXPOSE 9002
 
 ENTRYPOINT exec java $JAVA_JMX_OPTS $JAVA_MEMORY_OPTS -jar AccountServer.jar
+HEALTHCHECK --interval=30s --timeout=2s --retries=3    CMD curl -f http://localhost/api/healthcheck || exit 1
index 22048db..d4318ac 100644 (file)
@@ -23,7 +23,11 @@ package org.iotivity.cloud.accountserver;
 
 import java.net.InetSocketAddress;
 import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
 
+import org.iotivity.cloud.base.healthcheck.HealthHolder;
+import org.iotivity.cloud.base.healthcheck.SimpleHealthHolder;
+import org.iotivity.cloud.base.server.SimpleHttpServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.iotivity.cloud.accountserver.db.AccountDBManager;
@@ -51,6 +55,7 @@ public class AccountServer {
     private static boolean          tlsMode;
     private static String           databaseHost;
     private static String           webLogHost;
+    private static boolean          healthCheckEnabled;
 
     public static void main(String[] args) throws Exception {
         Log.info("Starting Account Server");
@@ -63,10 +68,9 @@ public class AccountServer {
         }
 
         AccountDBManager.createInstance(databaseHost);
-
+        HealthHolder healthHolder =  new SimpleHealthHolder(TimeUnit.SECONDS,100);
         ServerSystem serverSystem = new ServerSystem();
-
-        serverSystem.addResource(new CloudPingResource());
+        serverSystem.addResource(new CloudPingResource(healthHolder));
         serverSystem.addResource(new AccountResource());
         serverSystem.addResource(new SessionResource());
         serverSystem.addResource(new TokenRefreshResource());
@@ -81,6 +85,10 @@ public class AccountServer {
         serverSystem.addServer(
                 new CoapServer(new InetSocketAddress(coapServerPort)));
 
+        if(healthCheckEnabled){
+            serverSystem.addServer(new SimpleHttpServer(new InetSocketAddress(80),healthHolder));
+        }
+
         serverSystem.startSystem(tlsMode);
 
         Scanner in = new Scanner(System.in, "UTF-8");
@@ -104,6 +112,7 @@ public class AccountServer {
             coapServerPort = Integer.parseInt(args[0]);
             databaseHost = args[1] + ":" + args[2];
             tlsMode = Integer.parseInt(args[3]) == 1;
+            healthCheckEnabled = false;
             return true;
         }
         // configuration provided by docker env
@@ -113,6 +122,7 @@ public class AccountServer {
             databaseHost = System.getenv("MONGODB_ADDRESS") + ":"
                     + System.getenv("MONGODB_PORT");
             tlsMode = Integer.parseInt(tlsModeEnv) == 1;
+            healthCheckEnabled = Integer.parseInt(System.getenv("HEALTH_CHECK_ENABLED")) == 1;
             return true;
         }
         return false;
index 63ef5a9..1fddd08 100644 (file)
@@ -1,11 +1,16 @@
 FROM openjdk:8-jre-alpine
 
+RUN apk add --update \
+    curl \
+    && rm -rf /var/cache/apk/*
+
 ADD ./target/CloudResourceDirectory-0.0.1-SNAPSHOT.jar iotivity/ResourceDirectory.jar
 ADD ./target/lib/* iotivity/lib/
 
 WORKDIR iotivity/
 
 ENV COAP_PORT 5684
+ENV HEALTH_CHECK_ENABLED 1
 ENV TLS_MODE 0
 ENV MONGODB_ADDRESS mongodb
 ENV MONGODB_PORT 27017
@@ -24,3 +29,4 @@ ENV JAVA_JMX_OPTS "-Dcom.sun.management.jmxremote \
 EXPOSE 9004
 
 ENTRYPOINT exec java $JAVA_JMX_OPTS $JAVA_MEMORY_OPTS -jar ResourceDirectory.jar
+HEALTHCHECK --interval=30s --timeout=2s --retries=3    CMD curl -f http://localhost/api/healthcheck || exit 1
index dcf4e0e..0f99c35 100644 (file)
@@ -23,7 +23,11 @@ package org.iotivity.cloud.rdserver;
 
 import java.net.InetSocketAddress;
 import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
 
+import org.iotivity.cloud.base.healthcheck.HealthHolder;
+import org.iotivity.cloud.base.healthcheck.SimpleHealthHolder;
+import org.iotivity.cloud.base.server.SimpleHttpServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.iotivity.cloud.base.ServerSystem;
@@ -45,6 +49,7 @@ public class ResourceDirectoryServer {
     private static int              coapServerPort;
     private static boolean          tlsMode;
     private static String           databaseHost;
+    private static boolean healthCheckEnabled;
 
     public static void main(String[] args) throws Exception {
         Log.info("Starting Resource Directory Server");
@@ -57,10 +62,9 @@ public class ResourceDirectoryServer {
         }
 
         DBManager.createInstance(databaseHost);
-
+        HealthHolder healthHolder =  new SimpleHealthHolder(TimeUnit.SECONDS,100);
         ServerSystem serverSystem = new ServerSystem();
-
-        serverSystem.addResource(new CloudPingResource());
+        serverSystem.addResource(new CloudPingResource(healthHolder));
         serverSystem.addResource(new ResourceDirectoryResource());
         serverSystem.addResource(new DiscoveryResource());
         serverSystem.addResource(new DevicePresenceResource());
@@ -69,6 +73,10 @@ public class ResourceDirectoryServer {
         serverSystem.addServer(
                 new CoapServer(new InetSocketAddress(coapServerPort)));
 
+        if(healthCheckEnabled){
+            serverSystem.addServer(new SimpleHttpServer(new InetSocketAddress(80),healthHolder));
+        }
+
         serverSystem.startSystem(tlsMode);
 
         Scanner in = new Scanner(System.in);
@@ -92,6 +100,7 @@ public class ResourceDirectoryServer {
             coapServerPort = Integer.parseInt(args[0]);
             databaseHost = args[1] + ":" + args[2];
             tlsMode = Integer.parseInt(args[3]) == 1;
+            healthCheckEnabled = false;
             return true;
         }
         // configuration provided by docker env
@@ -101,6 +110,7 @@ public class ResourceDirectoryServer {
             databaseHost = System.getenv("MONGODB_ADDRESS") + ":"
                     + System.getenv("MONGODB_PORT");
             tlsMode = Integer.parseInt(tlsModeEnv) == 1;
+            healthCheckEnabled = Integer.parseInt(System.getenv("HEALTH_CHECK_ENABLED")) == 1;
             return true;
         }
         return false;
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/HealthHolder.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/HealthHolder.java
new file mode 100644 (file)
index 0000000..fda252e
--- /dev/null
@@ -0,0 +1,9 @@
+package org.iotivity.cloud.base.healthcheck;
+
+public interface HealthHolder {
+
+    boolean isHealthy();
+
+    void pingAccepted();
+
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/SimpleHealthHolder.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/healthcheck/SimpleHealthHolder.java
new file mode 100644 (file)
index 0000000..d7a087e
--- /dev/null
@@ -0,0 +1,26 @@
+package org.iotivity.cloud.base.healthcheck;
+
+import java.util.concurrent.TimeUnit;
+
+public class SimpleHealthHolder implements HealthHolder {
+
+
+    private final Long intervalMs;
+
+    private Long pingAccepted;
+
+    public SimpleHealthHolder(TimeUnit timeUnit, Integer interval) {
+        this.intervalMs = timeUnit.toMillis(interval);
+        pingAccepted();
+    }
+
+    @Override
+    public synchronized boolean isHealthy() {
+        return (System.currentTimeMillis() - pingAccepted) < intervalMs;
+    }
+
+    @Override
+    public synchronized void pingAccepted() {
+        pingAccepted = System.currentTimeMillis();
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/http/SimpleHttpHandler.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/http/SimpleHttpHandler.java
new file mode 100644 (file)
index 0000000..ba27db1
--- /dev/null
@@ -0,0 +1,53 @@
+package org.iotivity.cloud.base.protocols.http;
+
+import io.netty.channel.*;
+import io.netty.handler.codec.http.*;
+import io.netty.util.CharsetUtil;
+import org.iotivity.cloud.base.healthcheck.HealthHolder;
+import org.iotivity.cloud.base.protocols.IResponse;
+import org.iotivity.cloud.base.protocols.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SimpleHttpHandler extends SimpleChannelInboundHandler<HttpObject> {
+
+    private final static Logger Log             = LoggerFactory.getLogger(SimpleHttpHandler.class);
+
+    private final HealthHolder healthHolder;
+
+    public SimpleHttpHandler(HealthHolder healthHolder) {
+        this.healthHolder = healthHolder;
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
+
+        if (msg instanceof HttpRequest) {
+            final HttpRequest request = (HttpRequest) msg;
+            Log.debug("HTTP uri: {}",request.uri());
+            if(request.uri().compareTo("/api/healthcheck") == 0){
+                if(healthHolder.isHealthy()){
+                    ctx.writeAndFlush(createResponse(HttpResponseStatus.OK)).addListener(ChannelFutureListener.CLOSE);
+                }else {
+                    ctx.writeAndFlush(createResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR)).addListener(ChannelFutureListener.CLOSE);
+                }
+            }else {
+                ctx.writeAndFlush(createResponse(HttpResponseStatus.NOT_FOUND)).addListener(ChannelFutureListener.CLOSE);
+            }
+        }
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+        ctx.flush();
+    }
+
+    private HttpResponse createResponse(final HttpResponseStatus status){
+        return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status);
+    }
+
+
+
+}
index bee2f04..96ee43e 100644 (file)
@@ -3,6 +3,7 @@ package org.iotivity.cloud.base.resource;
 import org.iotivity.cloud.base.OICConstants;
 import org.iotivity.cloud.base.device.Device;
 import org.iotivity.cloud.base.exception.ServerException;
+import org.iotivity.cloud.base.healthcheck.HealthHolder;
 import org.iotivity.cloud.base.protocols.IRequest;
 import org.iotivity.cloud.base.protocols.IResponse;
 import org.iotivity.cloud.base.protocols.MessageBuilder;
@@ -11,8 +12,17 @@ import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
 import java.util.Arrays;
 
 public class CloudPingResource extends Resource {
+
+    private final HealthHolder healthHolder;
+
     public CloudPingResource() {
         super(Arrays.asList(OICConstants.PREFIX_OIC, OICConstants.KEEP_ALIVE_URI));
+        this.healthHolder = null;
+    }
+
+    public CloudPingResource(final HealthHolder healthHolder) {
+        super(Arrays.asList(OICConstants.PREFIX_OIC, OICConstants.KEEP_ALIVE_URI));
+        this.healthHolder = healthHolder;
     }
 
     @Override
@@ -23,6 +33,9 @@ public class CloudPingResource extends Resource {
         switch (request.getMethod()) {
             case PUT:
                 response = MessageBuilder.createResponse(request, ResponseStatus.VALID);
+                if(healthHolder != null){
+                    healthHolder.pingAccepted();
+                }
                 break;
 
             default:
index 9fe4326..b45b816 100644 (file)
@@ -120,7 +120,7 @@ public class Resource implements IRequestEventHandler {
         for (String property : propertyList) {
             if (!payloadData.containsKey(property))
                 throw new PreconditionFailedException(
-                        "payload does not contain" + property + " property");
+                        "payload does not contain " + property + " property");
             if (payloadData.get(property) == null)
                 throw new PreconditionFailedException(
                         property + " param is null in the payload");
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/server/SimpleHttpServer.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/server/SimpleHttpServer.java
new file mode 100644 (file)
index 0000000..74503aa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2016 Samsung Electronics All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * //      http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+package org.iotivity.cloud.base.server;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.iotivity.cloud.base.healthcheck.HealthHolder;
+import org.iotivity.cloud.base.protocols.http.SimpleHttpHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+
+public class SimpleHttpServer extends Server {
+    private final static Logger Log = LoggerFactory.getLogger(SimpleHttpServer.class);
+
+    private final HealthHolder healthHolder;
+
+    public SimpleHttpServer(InetSocketAddress inetSocketAddress, HealthHolder healthHolder) {
+        super(inetSocketAddress);
+        this.healthHolder = healthHolder;
+        Log.info("HTTP server listening on {}",inetSocketAddress);
+    }
+
+    @Override
+    protected ChannelHandler[] onQueryDefaultHandler() {
+
+        return new ChannelHandler[] { new HttpRequestDecoder(),
+                new HttpResponseEncoder(),
+                new SimpleHttpHandler(healthHolder) };
+    }
+}