Chapter 12. Developing an application for the Karaf image This tutorial shows how to create and deploy an application for the Karaf image. 12.1. Creating a Karaf project using Maven archetype To create a Karaf project using a Maven archetype, follow these steps. Procedure Go to the appropriate directory on your system. Launch the Maven command to create a Karaf project The archetype plug-in switches to interactive mode to prompt you for the remaining fields When prompted, enter org.example.fis for the groupId value and fuse713-karaf-camel-log for the artifactId value. Accept the defaults for the remaining fields. If the above command exited with the BUILD SUCCESS status, you should now have a new Fuse on OpenShift project under the fuse713-karaf-camel-log subdirectory. You are now ready to build and deploy the fuse713-karaf-camel-log project. Assuming you are still logged into OpenShift, change to the directory of the fuse713-karaf-camel-log project, and then build and deploy the project, as follows. Note For the full list of available Karaf archetypes, see Karaf Archetype Catalog . 12.2. Structure of the Camel Karaf application The directory structure of a Camel Karaf application is as follows: Where the following files are important for developing a Karaf application: 1 pom.xml: Includes additional dependencies. You can add dependencies in the pom.xml file, for example for logging you can use SLF4J. <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> 2 src/main/jkube/deployment.yml: Provides additional configuration that is merged with the default OpenShift configuration file generated by the openshift-maven-plugin. Note This file is not used as part of the Karaf application, but it is used in all quickstarts to limit the resources such as CPU and memory usage. 3 org.ops4j.pax.logging.cfg: Demonstrates how to customize log levels, sets logging level to DEBUG instead of the default INFO. 4 camel-log.xml: Contains the source code of the application. 12.3. Karaf archetype catalog The Karaf archetype catalog includes the following examples. Table 12.1. Karaf Maven Archetypes Name Description karaf-camel-amq-archetype Demonstrates how to send and receive messages to an Apache ActiveMQ message broker, using the Camel amq component. karaf-camel-log-archetype Demonstrates a simple Apache Camel application that logs a message to the server log every 5th second. karaf-camel-rest-sql-archetype Demonstrates how to use SQL via JDBC along with Camel's REST DSL to expose a RESTful API. karaf-cxf-rest-archetype Demonstrates how to create a RESTful(JAX-RS) web service using CXF and expose it through the OSGi HTTP Service. 12.4. Using Fabric8 Karaf features Fabric8 provides support for Apache Karaf making it easier to develop OSGi apps for Kubernetes. The important features of Fabric8 are as listed below: Different strategies to resolve placeholders in Blueprint XML files. Environment variables System properties Services Kubernetes ConfigMap Kubernetes Secrets Using Kubernetes configuration maps to dynamically update the OSGi configuration administration. Provides Kubernetes heath checks for OSGi services. 12.4.1. Adding Fabric8 Karaf features To use the features, add fabric8-karaf-features dependency to the project POM file. Procedure Open your project's pom.xml file and add fabric8-karaf-features dependency. <dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-features</artifactId> <version>USD{fabric8.version}</version> <classifier>features</classifier> <type>xml</type> </dependency> The fabric8 karaf features will be installed into the Karaf server. 12.4.2. Adding Fabric8 Karaf Core bundle functionality The bundle fabric8-karaf-core provides the functionalities used by Blueprint and ConfigAdmin extensions. Procedure Open your project's pom.xml and add fabric8-karaf-core to startupFeatures section. <startupFeatures> ... <feature>fabric8-karaf-core</feature> ... </startupFeatures> This will add the fabric8-karaf-core feature in a custom Karaf distribution. 12.4.3. Setting the Property Placeholder service options The bundle fabric8-karaf-core exports a service PlaceholderResolver with the following interface: public interface PlaceholderResolver { /** * Resolve a placeholder using the strategy indicated by the prefix * * @param value the placeholder to resolve * @return the resolved value or null if not resolved */ String resolve(String value); /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source string as a template. * * @param source the string to replace in * @return the result of the replace operation */ String replace(String value); /** * Replaces all the occurrences of variables within the given source builder with their matching values from the resolver. * * @param value the builder to replace in * @rerurn true if altered */ boolean replaceIn(StringBuilder value); /** * Replaces all the occurrences of variables within the given dictionary * * @param dictionary the dictionary to replace in * @rerurn true if altered */ boolean replaceAll(Dictionary<String, Object> dictionary); /** * Replaces all the occurrences of variables within the given dictionary * * @param dictionary the dictionary to replace in * @rerurn true if altered */ boolean replaceAll(Map<String, Object> dictionary); } The PlaceholderResolver service acts as a collector for different property placeholder resolution strategies. The resolution strategies it provides by default are listed in the table Resolution Strategies . To set the property placeholder service options you can use system properties or environment variables or both. Procedure To access ConfigMaps on OpenShift the service account needs view permissions. Add view permissions to the service account. Mount the secret to the Pod as access to secrets through API might be restricted. Secrets, available on the Pod as volume mounts, are mapped to a directory named as the secret, as shown below containers: - env: - name: FABRIC8_K8S_SECRETS_PATH value: /etc/secrets volumeMounts: - name: activemq-secret-volume mountPath: /etc/secrets/activemq readOnly: true - name: postgres-secret-volume mountPath: /etc/secrets/postgres readOnly: true volumes: - name: activemq-secret-volume secret: secretName: activemq - name: postgres-secret-volume secret: secretName: postgres 12.4.4. Adding a custom property placeholder resolver You can add a custom placeholder resolver to support a specific need, such as custom encryption. You can also use the PlaceholderResolver service to make the resolvers available to Blueprint and ConfigAdmin. Procedure Add the following mvn dependency to the project pom.xml . pom.xml --- <dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-core</artifactId> </dependency> --- Implement the PropertiesFunction interface and register it as OSGi service using SCR. import io.fabric8.karaf.core.properties.function.PropertiesFunction; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Service; @Component( immediate = true, policy = ConfigurationPolicy.IGNORE, createPid = false ) @Service(PropertiesFunction.class) public class MyPropertiesFunction implements PropertiesFunction { @Override public String getName() { return "myResolver"; } @Override public String apply(String remainder) { // Parse and resolve remainder return remainder; } } You can reference the resolver in Configuration management as follows. properties 12.4.5. List of resolution strategies The PlaceholderResolver service acts as a collector for different property placeholder resolution strategies. The resolution strategies it provides by default are listed in the table. List of resolution strategies Prefix Example Description env env:JAVA_HOME look up the property from OS environment variables. `sys sys:java.version look up the property from Java JVM system properties. `service service:amq look up the property from OS environment variables using the service naming convention. service.host service.host:amq look up the property from OS environment variables using the service naming convention returning the hostname part only. service.port service.port:amq look up the property from OS environment variables using the service naming convention returning the port part only. k8s:map k8s:map:myMap/myKey look up the property from a Kubernetes ConfigMap (via API) k8s:secret k8s:secret:amq/password look up the property from a Kubernetes Secrets (via API or volume mounts) 12.4.6. List of Property Placeholder service options The property placeholder service supports the following options: List of property placeholder service options Name Default Description fabric8.placeholder.prefix USD[ The prefix for the placeholder fabric8.placeholder.suffix ] The suffix for the placeholder fabric8.k8s.secrets.path null A comma delimited list of paths where secrets are mapped fabric8.k8s.secrets.api.enabled false Enable/Disable consuming secrets via APIs 12.5. Adding Fabric8 Karaf Config admin support 12.5.1. Adding Fabric8 Karaf Config admin support You can add Fabric8 Karaf Config admin support to your custom Karaf distribution. Procedure Open your project's pom.xml and add fabric8-karaf-cm to startupFeatures section. pom.xml <startupFeatures> ... <feature>fabric8-karaf-cm</feature> ... </startupFeatures> 12.5.2. Adding ConfigMap injection The fabric8-karaf-cm provides a ConfigAdmin bridge that inject ConfigMap values in Karaf's ConfigAdmin . Procedure To be added by the ConfigAdmin bridge, a ConfigMap has to be labeled with karaf.pid . The karaf.pid value corresponds to the pid of your component. For example, kind: ConfigMap apiVersion: v1 metadata: name: myconfig labels: karaf.pid: com.mycompany.bundle data: example.property.1: my property one example.property.2: my property two To define your configuration, you can use single property names. Individual properties work for most cases. It is same as the pid file in karaf/etc . For example, kind: ConfigMap apiVersion: v1 metadata: name: myconfig labels: karaf.pid: com.mycompany.bundle data: com.mycompany.bundle.cfg: | example.property.1: my property one example.property.2: my property two 12.5.3. Configuration plugin The fabric8-karaf-cm provides a ConfigurationPlugin which resolves configuration property placeholders. To enable property substitution with the fabric8-karaf-cm plug-in, you must set the Java property, fabric8.config.plugin.enabled to true . For example, you can set this property using the JAVA_OPTIONS environment variable in the Karaf image, as follows: 12.5.4. Config Property Placeholders An example of configuration property placeholders is shown below. my.service.cfg amq.usr = USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/username] amq.pwd = USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/password] amq.url = tcp://USD[env+service:ACTIVEMQ_SERVICE_NAME] my-service.xml <?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd"> <cm:property-placeholder persistent-id="my.service" id="my.service" update-strategy="reload"/> <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> <property name="userName" value="USD{amq.usr}"/> <property name="password" value="USD{amq.pwd}"/> <property name="brokerURL" value="USD{amq.url}"/> </bean> </blueprint> 12.5.5. Fabric8 Karaf Config Admin options Fabric8 Karaf Config Admin supports the following options. Name Default Description fabric8.config.plugin.enabled false Enable ConfigurationPlugin fabric8.cm.bridge.enabled true Enable ConfigAdmin bridge fabric8.config.watch true Enable watching for ConfigMap changes fabric8.config.merge false Enable merge ConfigMap values in ConfigAdmin fabric8.config.meta true Enable injecting ConfigMap meta in ConfigAdmin bridge fabric8.pid.label karaf.pid Define the label the ConfigAdmin bridge looks for (that is, a ConfigMap that needs to be selected must have that label; the value of which determines to what PID it gets associated) fabric8.pid.filters empty Define additional conditions for the ConfigAdmin bridge to select a ConfigMap. The supported syntax is: Conditions on different labels are separated by "," and are intended in AND between each other. Inside a label, semicolons (;) are considered as OR and can be used as separators for conditions on the label value. For example, a filter like -Dfabric8.pid.filters=appName=A;B,database.name=my.oracle.datasource translates to "give me all the ConfigMaps that have a label appName with values A or B and a label database.name equals to my.oracle.datasource". Important ConfigurationPlugin requires Aries Blueprint CM 1.0.9 or above. 12.6. Adding Fabric8 Karaf Blueprint support The fabric8-karaf-blueprint uses Aries PropertyEvaluator and property placeholders resolvers from fabric8-karaf-core to resolve placeholders in your Blueprint XML file. Procedure To include the feature for Blueprint support in your custom Karaf distribution, add fabric8-karaf-blueprint to startupFeatures section in your project pom.xml . <startupFeatures> ... <feature>fabric8-karaf-blueprint</feature> ... </startupFeatures> Example The fabric8 evaluator supports chained evaluators, such as USD{env+service:MY_ENV_VAR} . You need to resolve MY_ENV_VAR variable against environment variables. The result is then resolved using service function. For example, <?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.2.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.3.0 http://aries.apache.org/schemas/blueprint-ext/blueprint-ext-1.3.xsd"> <ext:property-placeholder evaluator="fabric8" placeholder-prefix="USD[" placeholder-suffix="]"/> <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> <property name="userName" value="USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/username]"/> <property name="password" value="USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/password]"/> <property name="brokerURL" value="tcp://USD[env+service:ACTIVEMQ_SERVICE_NAME]"/> </bean> </blueprint> Important Nested property placeholder substitution requires Aries Blueprint Core 1.7.0 or above. 12.7. Enabling Fabric8 Karaf health checks It is recommended to install the fabric8-karaf-checks as a startup feature. Once enabled, your Karaf server can expose these URLs: http://0.0.0.0:8181/readiness-check and http://0.0.0.0:8181/health-check They can be used by Kubernetes for readiness and liveness probes. Note These URLs will only respond with the HTTP 200 status code when the following is true: OSGi Framework is started. All OSGi bundles are started. All boot features are installed. All deployed BluePrint bundles are in the created state. All deployed SCR bundles are in the active, registered or factory state. All web bundles are deployed to the web server. All created Camel contexts are in the started state. Procedure Open you project's pom.xml and add fabric8-karaf-checks feature in the startupFeatures section. pom.xml <startupFeatures> ... <feature>fabric8-karaf-checks</feature> ... </startupFeatures> The oc:resources goal will detect if your using the fabric8-karaf-checks feature and automatically add the Kubernetes for readiness and liveness probes to your container's configuration. 12.7.1. Configuring health checks By default, the fabric8-karaf-checks endpoints are registered into the built-in HTTP server engine (Undertow) running on port 8181 . To avoid the health and readiness check requests being blocked by other long running HTTP processes in the container, the endpoints can be registered into a separate Undertow container. These checks can be configured in the etc/io.fabric8.checks.cfg file by setting the following properties: httpPort : If this property is specified and is a valid port number, the readiness-check and health-check endpoints will be registered into a separate instance of Undertow server readinessCheckPath and healthCheckPath properties allow you to configure the actual URIs that can be used for readiness and health checks. By default these are the same as values. Note These properties may be changed after starting Fuse-Karaf, but may also be specified in etc/io.fabric8.checks.cfg file being part of custom Karaf distro, which is used by customers who want to have fabric8-karaf-checks feature running out of the box. The following example illustrates the configuration of the health and readiness properties in the etc/io.fabric8.checks.cfg file: Example 12.8. Adding custom health checks You can provide additional custom heath checks to prevent the Karaf server from receiving user traffic before it is ready to process the requests. To enable custom health checks you need to implement the io.fabric8.karaf.checks.HealthChecker or io.fabric8.karaf.checks.ReadinessChecker interfaces and register those objects in the OSGi registry. Procedure Add the following mvn dependency to the project pom.xml file. pom.xml <dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-checks</artifactId> </dependency> Note The simplest way to create and registered an object in the OSGi registry is to use SCR. Example An example that performs a health check to make sure you have some free disk space, is shown below: import io.fabric8.karaf.checks.*; import org.apache.felix.scr.annotations.*; import org.apache.commons.io.FileSystemUtils; import java.util.Collections; import java.util.List; @Component( name = "example.DiskChecker", immediate = true, enabled = true, policy = ConfigurationPolicy.IGNORE, createPid = false ) @Service({HealthChecker.class, ReadinessChecker.class}) public class DiskChecker implements HealthChecker, ReadinessChecker { public List<Check> getFailingReadinessChecks() { // lets just use the same checks for both readiness and health return getFailingHeathChecks(); } public List<Check> getFailingHealthChecks() { long free = FileSystemUtils.freeSpaceKb("/"); if (free < 1024 * 500) { return Collections.singletonList(new Check("disk-space-low", "Only " + free + "kb of disk space left.")); } return Collections.emptyList(); } }

Commands:
mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeCatalog=https://maven.repository.redhat.com/ga/io/fabric8/archetypes/archetypes-catalog/2.2.0.fuse-7_13_0-00014-redhat-00001/archetypes-catalog-2.2.0.fuse-7_13_0-00014-redhat-00001-archetype-catalog.xml -DarchetypeGroupId=org.jboss.fuse.fis.archetypes -DarchetypeArtifactId=karaf-camel-log-archetype -DarchetypeVersion=2.2.0.fuse-7_13_0-00014-redhat-00001
Define value for property 'groupId': : org.example.fis Define value for property 'artifactId': : fuse713-karaf-camel-log Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': org.example.fis: : Confirm properties configuration: groupId: org.example.fis artifactId: fuse713-karaf-camel-log version: 1.0-SNAPSHOT package: org.example.fis Y: : Y
cd fuse713-karaf-camel-log mvn oc:deploy -Popenshift
├── pom.xml 1 ├── README.md ├── configuration │ └── settings.xml └── src ├── main │ ├── jkube │ │ └── deployment.yml 2 │ ├── java │ │ └── org │ │ └── example │ │ └── fis │ └── resources │ ├── assembly │ │ └── etc │ │ └── org.ops4j.pax.logging.cfg 3 │ └── OSGI-INF │ └── blueprint │ └── camel-log.xml 4 └── test └── java └── org └── example └── fis
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency>
<dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-features</artifactId> <version>USD{fabric8.version}</version> <classifier>features</classifier> <type>xml</type> </dependency>
<startupFeatures> <feature>fabric8-karaf-core</feature> </startupFeatures>
public interface PlaceholderResolver { /** * Resolve a placeholder using the strategy indicated by the prefix * * @param value the placeholder to resolve * @return the resolved value or null if not resolved */ String resolve(String value); /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source string as a template. * * @param source the string to replace in * @return the result of the replace operation */ String replace(String value); /** * Replaces all the occurrences of variables within the given source builder with their matching values from the resolver. * * @param value the builder to replace in * @rerurn true if altered */ boolean replaceIn(StringBuilder value); /** * Replaces all the occurrences of variables within the given dictionary * * @param dictionary the dictionary to replace in * @rerurn true if altered */ boolean replaceAll(Dictionary<String, Object> dictionary); /** * Replaces all the occurrences of variables within the given dictionary * * @param dictionary the dictionary to replace in * @rerurn true if altered */ boolean replaceAll(Map<String, Object> dictionary); }
policy add-role-to-user view system:serviceaccount:USD(oc project -q):default -n USD(oc project -q)
containers: - env: - name: FABRIC8_K8S_SECRETS_PATH value: /etc/secrets volumeMounts: - name: activemq-secret-volume mountPath: /etc/secrets/activemq readOnly: true - name: postgres-secret-volume mountPath: /etc/secrets/postgres readOnly: true volumes: - name: activemq-secret-volume secret: secretName: activemq - name: postgres-secret-volume secret: secretName: postgres
--- <dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-core</artifactId> </dependency> ---
import io.fabric8.karaf.core.properties.function.PropertiesFunction; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Service; @Component( immediate = true, policy = ConfigurationPolicy.IGNORE, createPid = false ) @Service(PropertiesFunction.class) public class MyPropertiesFunction implements PropertiesFunction { @Override public String getName() { return "myResolver"; } @Override public String apply(String remainder) { // Parse and resolve remainder return remainder; } }
my.property = USD[myResolver:value-to-resolve]
<startupFeatures> <feature>fabric8-karaf-cm</feature> </startupFeatures>
kind: ConfigMap apiVersion: v1 metadata: name: myconfig labels: karaf.pid: com.mycompany.bundle data: example.property.1: my property one example.property.2: my property two
kind: ConfigMap apiVersion: v1 metadata: name: myconfig labels: karaf.pid: com.mycompany.bundle data: com.mycompany.bundle.cfg: | example.property.1: my property one example.property.2: my property two
JAVA_OPTIONS=-Dfabric8.config.plugin.enabled=true
amq.usr = USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/username] amq.pwd = USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/password] amq.url = tcp://USD[env+service:ACTIVEMQ_SERVICE_NAME]
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd"> <cm:property-placeholder persistent-id="my.service" id="my.service" update-strategy="reload"/> <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> <property name="userName" value="USD{amq.usr}"/> <property name="password" value="USD{amq.pwd}"/> <property name="brokerURL" value="USD{amq.url}"/> </bean> </blueprint>
<startupFeatures> <feature>fabric8-karaf-blueprint</feature> </startupFeatures>
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.2.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.3.0 http://aries.apache.org/schemas/blueprint-ext/blueprint-ext-1.3.xsd"> <ext:property-placeholder evaluator="fabric8" placeholder-prefix="USD[" placeholder-suffix="]"/> <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> <property name="userName" value="USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/username]"/> <property name="password" value="USD[k8s:secret:USD[env:ACTIVEMQ_SERVICE_NAME]/password]"/> <property name="brokerURL" value="tcp://USD[env+service:ACTIVEMQ_SERVICE_NAME]"/> </bean> </blueprint>
<startupFeatures> <feature>fabric8-karaf-checks</feature> </startupFeatures>
httpPort = 8182 readinessCheckPath = /readiness-check healthCheckPath = /health-check
<dependency> <groupId>io.fabric8</groupId> <artifactId>fabric8-karaf-checks</artifactId> </dependency>
import io.fabric8.karaf.checks.*; import org.apache.felix.scr.annotations.*; import org.apache.commons.io.FileSystemUtils; import java.util.Collections; import java.util.List; @Component( name = "example.DiskChecker", immediate = true, enabled = true, policy = ConfigurationPolicy.IGNORE, createPid = false ) @Service({HealthChecker.class, ReadinessChecker.class}) public class DiskChecker implements HealthChecker, ReadinessChecker { public List<Check> getFailingReadinessChecks() { // lets just use the same checks for both readiness and health return getFailingHeathChecks(); } public List<Check> getFailingHealthChecks() { long free = FileSystemUtils.freeSpaceKb("/"); if (free < 1024 * 500) { return Collections.singletonList(new Check("disk-space-low", "Only " + free + "kb of disk space left.")); } return Collections.emptyList(); } }