Add support for health checks to the Service Configuration API.
diff --git a/containers-api/src/main/java/org/apache/aries/containers/HealthCheck.java b/containers-api/src/main/java/org/apache/aries/containers/HealthCheck.java
new file mode 100644
index 0000000..5d492f8
--- /dev/null
+++ b/containers-api/src/main/java/org/apache/aries/containers/HealthCheck.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.aries.containers;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Define a health check. Most container system support health checks of some
+ * sort. Health checks are provided to a Service Manager via the Service Configuration.
+ *
+ * @see ServiceConfig
+ */
+@ProviderType
+public class HealthCheck {
+ /**
+ * Supported health check types, The parameters for health checks are
+ * specified in the parameters member.
+ */
+ public enum Type {
+ /**
+ * Health check defined as a HTTP request. The request should return
+ * a return code between 200 and 399. {@link HealthCheck#getParameters()}
+ * provides the URL for the HTTP request.
+ */
+ HTTP,
+
+ /**
+ * Health check defined as a HTTPS request. The request should return
+ * a return code between 200 and 399. {@link HealthCheck#getParameters()}
+ * provides the URL for the HTTP request.
+ */
+ HTTPS,
+
+ /**
+ * Health check defined as a TCP port connection. If opening a TCP port to
+ * succeeds the health check passes. The port to connect to is specified
+ * via {@link HealthCheck#getParameters()}. An port index is specified via
+ * {@code $PORT0}, {@code $PORT1} etc. An actual port is specified as a number,
+ * e.g. {@code 8080}.
+ */
+ TCP,
+
+ /**
+ * Health check defined as a command to be executed locally in the container to
+ * determine that the container is healthy. The command should have return {@code 0}
+ * to indicate that its healthy. The actual command to execute is
+ * available from {@link HealthCheck#getParameters()}.
+ */
+ COMMAND,
+
+ /**
+ * This type of health check can be used for proprietary health checks that are not
+ * covered by other types.
+ */
+ OTHER };
+
+ private final String parameters;
+ private final Type type;
+ private final int gracePeriod;
+ private final int interval;
+ private final int timeout;
+ private final int maxFailures;
+
+ private HealthCheck(String parameters, Type type, int gracePeriod, int interval,
+ int timeout, int maxFailures) {
+ this.parameters = parameters;
+ this.type = type;
+ this.gracePeriod = gracePeriod;
+ this.interval = interval;
+ this.timeout = timeout;
+ this.maxFailures = maxFailures;
+ }
+
+ /**
+ * @return The health check type.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * @return The grace period in seconds. Health checks are ignored for the duration of the grace
+ * period until the container is healthy.
+ */
+ public int getGracePeriod() {
+ return gracePeriod;
+ }
+
+ /**
+ * @return The interval at which health checks are evaluated, specified in seconds.
+ */
+ public int getInterval() {
+ return interval;
+ }
+
+ /**
+ * @return The number of failed health check after which a task will be killed.
+ */
+ public int getMaxFailures() {
+ return maxFailures;
+ }
+
+ /**
+ * @return The parameters for a given health check, such as the HTTP URL or command line.
+ */
+ public String getParameters() {
+ return parameters;
+ }
+
+ /**
+ * @return The number of seconds after which a health check is considered a failure, regardless
+ * of the obtained result.
+ */
+ public int getTimeout() {
+ return timeout;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
+ result = prime * result + gracePeriod;
+ result = prime * result + interval;
+ result = prime * result + maxFailures;
+ result = prime * result + timeout;
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ HealthCheck other = (HealthCheck) obj;
+ if (parameters == null) {
+ if (other.parameters != null)
+ return false;
+ } else if (!parameters.equals(other.parameters))
+ return false;
+ if (gracePeriod != other.gracePeriod)
+ return false;
+ if (interval != other.interval)
+ return false;
+ if (maxFailures != other.maxFailures)
+ return false;
+ if (timeout != other.timeout)
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ /**
+ * Create a health check builder.
+ * @param type The type of health check.
+ * @return A health check builder.
+ */
+ public static Builder builder(Type type) {
+ return new Builder(type);
+ }
+
+ /**
+ * A builder for health checks.
+ */
+ public static class Builder {
+ private String parameters;
+ private final Type type;
+ private int gracePeriod = 300;
+ private int interval = 60;
+ private int timeout = 20;
+ private int maxFailures = 3;
+
+ Builder(Type type) {
+ this.type = type;
+ }
+
+ /**
+ * Specify the parameters for the health check, such as the HTTP URL.
+ * @param parameters The parameters for this health check.
+ * @return the current builder for further building.
+ */
+ public Builder parameters(String parameters) {
+ this.parameters = parameters;
+ return this;
+ }
+
+ /**
+ * Specify the grace period to use.
+ * @param gp The grace period in seconds.
+ * @return the current builder for further building.
+ */
+ public Builder gracePeriod(int gp) {
+ this.gracePeriod = gp;
+ return this;
+ }
+
+ /**
+ * Specify the interval to use.
+ * @param iv The interval in seconds.
+ * @return the current builder for further building.
+ */
+ public Builder interval(int iv) {
+ this.interval = iv;
+ return this;
+ }
+
+ /**
+ * Specify the maximum number of failures.
+ * @param max The maximum number of failures.
+ * @return the current builder for further building.
+ */
+ public Builder maxFailures(int max) {
+ this.maxFailures = max;
+ return this;
+ }
+
+ /**
+ * Specify the timeout.
+ * @param t The timout in seconds.
+ * @return the current builder for further building.
+ */
+ public Builder timeout(int t) {
+ this.timeout = t;
+ return this;
+ }
+
+ public HealthCheck build() {
+ return new HealthCheck(parameters, type, gracePeriod, interval, timeout, maxFailures);
+ }
+ }
+}
diff --git a/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java b/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java
index bf48d57..85ca8f0 100644
--- a/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java
+++ b/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java
@@ -43,20 +43,21 @@
private final List<Integer> containerPorts;
private final String entryPoint;
private final Map<String, String> envVars;
-// private final List<HealthCheck> healthChecks; TODO add these!
+ private final List<HealthCheck> healthChecks;
private final double requestedCPUunits;
private final int requestedInstances;
private final double requestedMemory; // in MiB
private final String serviceName;
private ServiceConfig(String[] commandLine, String containerImage, List<Integer> containerPorts, String entryPoint,
- Map<String, String> envVars, double requestedCPUunits, int requestedInstances, double requestedMemory,
- String serviceName) {
+ Map<String, String> envVars, List<HealthCheck> healtChecks, double requestedCPUunits, int requestedInstances,
+ double requestedMemory, String serviceName) {
this.commandLine = commandLine;
this.containerImage = containerImage;
this.containerPorts = Collections.unmodifiableList(containerPorts);
this.entryPoint = entryPoint;
this.envVars = Collections.unmodifiableMap(envVars);
+ this.healthChecks = Collections.unmodifiableList(healtChecks);
this.requestedCPUunits = requestedCPUunits;
this.requestedInstances = requestedInstances;
this.requestedMemory = requestedMemory;
@@ -93,6 +94,13 @@
}
/**
+ * @return The health checks to be configured for this service.
+ */
+ public List<HealthCheck> getHealthChecks() {
+ return healthChecks;
+ }
+
+ /**
* @return A map containing all the environment variables to be set.
*/
public Map<String, String> getEnvVars() {
@@ -129,8 +137,6 @@
return serviceName;
}
-
-
@Override
public int hashCode() {
final int prime = 31;
@@ -140,6 +146,7 @@
result = prime * result + ((containerPorts == null) ? 0 : containerPorts.hashCode());
result = prime * result + ((entryPoint == null) ? 0 : entryPoint.hashCode());
result = prime * result + ((envVars == null) ? 0 : envVars.hashCode());
+ result = prime * result + ((healthChecks == null) ? 0 : healthChecks.hashCode());
long temp;
temp = Double.doubleToLongBits(requestedCPUunits);
result = prime * result + (int) (temp ^ (temp >>> 32));
@@ -181,6 +188,11 @@
return false;
} else if (!envVars.equals(other.envVars))
return false;
+ if (healthChecks == null) {
+ if (other.healthChecks != null)
+ return false;
+ } else if (!healthChecks.equals(other.healthChecks))
+ return false;
if (Double.doubleToLongBits(requestedCPUunits) != Double.doubleToLongBits(other.requestedCPUunits))
return false;
if (requestedInstances != other.requestedInstances)
@@ -210,15 +222,16 @@
/** A builder for service configurations */
@ProviderType
public static class Builder {
- private String containerImage;
+ private final String containerImage;
private String[] commandLine = new String [] {};
private Map<String, String> envMap = new HashMap<>();
private String entryPoint;
+ private List<HealthCheck> healthChecks = new ArrayList<>();
private double requestedCpuUnits = 0.5;
private int requestedInstances = 1;
private double requestedMemory = 64;
private List<Integer> ports = new ArrayList<>();
- private String serviceName;
+ private final String serviceName;
Builder(String serviceName, String containerImage) {
this.serviceName = serviceName;
@@ -299,6 +312,18 @@
}
/**
+ * Specify a health check to use for the service. This method
+ * may be called multiple times to specify multiple health
+ * checks.
+ * @param hc The health to add.
+ * @return the current builder for further building.
+ */
+ public Builder healthCheck(HealthCheck hc) {
+ this.healthChecks.add(hc);
+ return this;
+ }
+
+ /**
* Specify the required amount of memory in million bytes (MiB).
*
* @param requestedMemory The amount of memory required of a container.
@@ -328,7 +353,7 @@
*/
public ServiceConfig build() {
return new ServiceConfig(commandLine, containerImage, ports, entryPoint,
- envMap, requestedCpuUnits, requestedInstances, requestedMemory,
+ envMap, healthChecks, requestedCpuUnits, requestedInstances, requestedMemory,
serviceName);
}
}
diff --git a/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java b/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java
index c21519a..934ec4c 100644
--- a/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java
+++ b/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java
@@ -22,6 +22,7 @@
import java.util.HashMap;
import java.util.Map;
+import org.apache.aries.containers.HealthCheck;
import org.apache.aries.containers.ServiceConfig;
import org.junit.Test;
@@ -74,4 +75,14 @@
assertEquals(env, sc.getEnvVars());
}
+ @Test
+ public void testHealthCheck() {
+ HealthCheck hc = HealthCheck.builder(HealthCheck.Type.HTTP).
+ parameters("/index.html").build();
+ ServiceConfig sc = ServiceConfig.builder("mysvc", "animg").
+ healthCheck(hc).build();
+
+ assertEquals(1, sc.getHealthChecks().size());
+ assertEquals(hc, sc.getHealthChecks().get(0));
+ }
}