diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
index 7cf863c7b8449..54b1535575b8a 100644
--- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
+++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
@@ -1359,6 +1359,7 @@ To enable Service Binding for supported extensions, add the `quarkus-kubernetes-
* `quarkus-reactive-mysql-client`
* `quarkus-reactive-oracle-client`
* `quarkus-reactive-pg-client`
+* `quarkus-infinispan-client`
====
diff --git a/extensions/infinispan-client/deployment/pom.xml b/extensions/infinispan-client/deployment/pom.xml
index a294e6da65c47..fba0493740e4b 100644
--- a/extensions/infinispan-client/deployment/pom.xml
+++ b/extensions/infinispan-client/deployment/pom.xml
@@ -56,6 +56,11 @@
quarkus-smallrye-health-spi
+
+ io.quarkus
+ quarkus-kubernetes-service-binding-spi
+
+
org.infinispan
infinispan-server-testdriver-core
diff --git a/extensions/infinispan-client/deployment/src/main/java/io/quarkus/infinispan/client/deployment/InfinispanClientProcessor.java b/extensions/infinispan-client/deployment/src/main/java/io/quarkus/infinispan/client/deployment/InfinispanClientProcessor.java
index e296c85041099..c7303ec6ace33 100644
--- a/extensions/infinispan-client/deployment/src/main/java/io/quarkus/infinispan/client/deployment/InfinispanClientProcessor.java
+++ b/extensions/infinispan-client/deployment/src/main/java/io/quarkus/infinispan/client/deployment/InfinispanClientProcessor.java
@@ -39,6 +39,8 @@
import io.quarkus.arc.deployment.BeanContainerListenerBuildItem;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
import io.quarkus.deployment.ApplicationArchive;
+import io.quarkus.deployment.Capabilities;
+import io.quarkus.deployment.Capability;
import io.quarkus.deployment.Feature;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
@@ -54,10 +56,12 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSecurityProviderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.infinispan.client.runtime.InfinispanClientBuildTimeConfig;
import io.quarkus.infinispan.client.runtime.InfinispanClientProducer;
import io.quarkus.infinispan.client.runtime.InfinispanRecorder;
+import io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter;
import io.quarkus.infinispan.client.runtime.cache.CacheInvalidateAllInterceptor;
import io.quarkus.infinispan.client.runtime.cache.CacheInvalidateInterceptor;
import io.quarkus.infinispan.client.runtime.cache.CacheResultInterceptor;
@@ -68,6 +72,7 @@
class InfinispanClientProcessor {
private static final Log log = LogFactory.getLog(InfinispanClientProcessor.class);
+ private static final String SERVICE_BINDING_INTERFACE_NAME = "io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConverter";
private static final String META_INF = "META-INF";
private static final String HOTROD_CLIENT_PROPERTIES = "hotrod-client.properties";
private static final String PROTO_EXTENSION = ".proto";
@@ -260,4 +265,13 @@ HealthBuildItem addHealthCheck(InfinispanClientBuildTimeConfig buildTimeConfig)
buildTimeConfig.healthEnabled);
}
+ @BuildStep
+ void registerServiceBinding(Capabilities capabilities, BuildProducer buildProducer) {
+ if (capabilities.isPresent(Capability.KUBERNETES_SERVICE_BINDING)) {
+ buildProducer.produce(
+ new ServiceProviderBuildItem(SERVICE_BINDING_INTERFACE_NAME,
+ InfinispanServiceBindingConverter.class.getName()));
+ }
+ }
+
}
diff --git a/extensions/infinispan-client/runtime/pom.xml b/extensions/infinispan-client/runtime/pom.xml
index f1d52a34bc7a2..d938542910d32 100644
--- a/extensions/infinispan-client/runtime/pom.xml
+++ b/extensions/infinispan-client/runtime/pom.xml
@@ -132,6 +132,21 @@
quarkus-smallrye-health
true
+
+ io.quarkus
+ quarkus-kubernetes-service-binding
+ true
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
diff --git a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverter.java b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverter.java
new file mode 100644
index 0000000000000..c5f1d213be727
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverter.java
@@ -0,0 +1,112 @@
+package io.quarkus.infinispan.client.runtime;
+
+import static java.lang.String.format;
+import static org.apache.sshd.common.util.GenericUtils.isBlank;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.jboss.logging.Logger;
+
+import io.quarkus.kubernetes.service.binding.runtime.ServiceBinding;
+import io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConfigSource;
+import io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConverter;
+
+/**
+ * ServiceBindingConverter for Infinispan to support SBO (Service Binding Operator) in Quarkus.
+ *
+ *
+ *
+ * Following individual properties are supported to make the connection:
+ *
+ * - uri
+ * - hosts(host information can be provided in this property separated by : sign, e.g. localhost:11222
)
+ * - useauth
+ * - username
+ * - password
+ *
+ * if uri is provided, all the other properties are ignored
+ * if uri is not provided, hosts is mandatory and all other properties are optional
+ *
+ *
+ *
+ * The Quarkus properties set by this class are:
+ *
+ * - quarkus.infinispan-client.uri (if uri is provided)
+ * - quarkus.infinispan-client.hosts (if hosts is provided and uri is not provided)
+ * - quarkus.infinispan-client.use-auth (if useauth is provided and uri is not provided)
+ * - quarkus.infinispan-client.username (if username is provided and uri is not provided)
+ * - quarkus.infinispan-client.password (if password is provided and uri is not provided)
+ *
+ */
+public class InfinispanServiceBindingConverter implements ServiceBindingConverter {
+
+ private static final Logger LOGGER = Logger.getLogger(InfinispanServiceBindingConverter.class);
+ private static final String BINDING_TYPE = "infinispan";
+ public static final String BINDING_CONFIG_SOURCE_NAME = BINDING_TYPE + "-k8s-service-binding-source";
+
+ // Connection properties
+ public static final String INFINISPAN_URI = "uri";
+ public static final String INFINISPAN_HOSTS = "hosts";
+ public static final String INFINISPAN_USE_AUTH = "useauth";
+ public static final String INFINISPAN_USERNAME = "username";
+ public static final String INFINISPAN_PASSWORD = "password";
+
+ // Infinispan Quarkus properties
+ public static final String INFINISPAN_CLIENT_URI = "quarkus.infinispan-client.uri";
+ public static final String INFINISPAN_CLIENT_HOSTS = "quarkus.infinispan-client.hosts";
+ public static final String INFINISPAN_CLIENT_USE_AUTH = "quarkus.infinispan-client.use-auth";
+ public static final String INFINISPAN_CLIENT_AUTH_USERNAME = "quarkus.infinispan-client.username";
+ public static final String INFINISPAN_CLIENT_AUTH_PASSWORD = "quarkus.infinispan-client.password";
+
+ @Override
+ public Optional convert(List serviceBindings) {
+ Optional matchingByType = ServiceBinding.singleMatchingByType(BINDING_TYPE, serviceBindings);
+ if (matchingByType.isEmpty()) {
+ return Optional.empty();
+ }
+
+ ServiceBinding binding = matchingByType.get();
+ Map properties = new HashMap<>();
+
+ setUri(binding, properties);
+ setConnection(binding, properties);
+ setUseAuth(binding, properties);
+ setUsername(binding, properties);
+ setPassword(binding, properties);
+
+ return Optional.of(new ServiceBindingConfigSource(BINDING_CONFIG_SOURCE_NAME, properties));
+ }
+
+ private void setUri(ServiceBinding binding, Map properties) {
+ properties.put(INFINISPAN_CLIENT_URI, getInfinispanProperty(binding, INFINISPAN_URI));
+ }
+
+ private void setConnection(ServiceBinding binding, Map properties) {
+ properties.put(INFINISPAN_CLIENT_HOSTS, getInfinispanProperty(binding, INFINISPAN_HOSTS));
+ }
+
+ private void setUseAuth(ServiceBinding binding, Map properties) {
+ properties.put(INFINISPAN_CLIENT_USE_AUTH, getInfinispanProperty(binding, INFINISPAN_USE_AUTH));
+ }
+
+ private void setUsername(ServiceBinding binding, Map properties) {
+ properties.put(INFINISPAN_CLIENT_AUTH_USERNAME, getInfinispanProperty(binding, INFINISPAN_USERNAME));
+ }
+
+ private void setPassword(ServiceBinding binding, Map properties) {
+ properties.put(INFINISPAN_CLIENT_AUTH_PASSWORD, getInfinispanProperty(binding, INFINISPAN_PASSWORD));
+ }
+
+ private String getInfinispanProperty(ServiceBinding binding, String infinispanPropertyKey) {
+ String infinispanPropertyValue = binding.getProperties().get(infinispanPropertyKey);
+ if (isBlank(infinispanPropertyValue)) {
+ LOGGER.debug(format("Property '%s' not found", infinispanPropertyKey));
+ }
+
+ return infinispanPropertyValue;
+ }
+
+}
diff --git a/extensions/infinispan-client/runtime/src/main/resources/META-INF/services/io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConverter b/extensions/infinispan-client/runtime/src/main/resources/META-INF/services/io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConverter
new file mode 100644
index 0000000000000..1eb49bc4aca88
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/main/resources/META-INF/services/io.quarkus.kubernetes.service.binding.runtime.ServiceBindingConverter
@@ -0,0 +1 @@
+io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter
diff --git a/extensions/infinispan-client/runtime/src/test/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverterTest.java b/extensions/infinispan-client/runtime/src/test/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverterTest.java
new file mode 100644
index 0000000000000..f97dc27e22f7b
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/java/io/quarkus/infinispan/client/runtime/InfinispanServiceBindingConverterTest.java
@@ -0,0 +1,53 @@
+package io.quarkus.infinispan.client.runtime;
+
+import static io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter.INFINISPAN_HOSTS;
+import static io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter.INFINISPAN_PASSWORD;
+import static io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter.INFINISPAN_URI;
+import static io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter.INFINISPAN_USERNAME;
+import static io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter.INFINISPAN_USE_AUTH;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.kubernetes.service.binding.runtime.ServiceBinding;
+
+public class InfinispanServiceBindingConverterTest {
+ private final static Path rootPath = Paths.get("src/test/resources/service-binding");
+ private final static String BINDING_DIRECTORY_ALL_PROPS = "all-props";
+ private final static String BINDING_DIRECTORY_NO_PROPS = "no-props";
+ private static final String EXPECTED_USERNAME = "someadmin";
+ private static final String EXPECTED_PASSWORD = "infiniforever";
+ private static final String EXPECTED_HOSTS = "infinispan.forever.com:11222";
+ private static final String EXPECTED_URI = "hotrod://admin:password@infinispan.forever.com:11222";
+
+ @Test
+ public void testBindingWithAllProperties() {
+ String bindingDirectory = BINDING_DIRECTORY_ALL_PROPS;
+ ServiceBinding serviceBinding = new ServiceBinding(rootPath.resolve(bindingDirectory));
+ assertThat(serviceBinding.getName()).isEqualTo(bindingDirectory);
+ assertThat(serviceBinding.getType()).isEqualTo("infinispan");
+ assertThat(serviceBinding.getProvider()).isEqualTo("coco");
+ assertThat(serviceBinding.getProperties().get(INFINISPAN_USE_AUTH)).isEqualTo("true");
+ assertThat(serviceBinding.getProperties().get(INFINISPAN_USERNAME)).isEqualTo(EXPECTED_USERNAME);
+ assertThat(serviceBinding.getProperties().get(INFINISPAN_PASSWORD)).isEqualTo(EXPECTED_PASSWORD);
+ assertThat(serviceBinding.getProperties().get(INFINISPAN_HOSTS)).isEqualTo(EXPECTED_HOSTS);
+ assertThat(serviceBinding.getProperties().get(INFINISPAN_URI)).isEqualTo(EXPECTED_URI);
+ }
+
+ @Test
+ public void testBindingWithMissingProperties() {
+ String bindingDirectory = BINDING_DIRECTORY_NO_PROPS;
+ ServiceBinding serviceBinding = new ServiceBinding(rootPath.resolve(bindingDirectory));
+ assertThat(serviceBinding.getName()).isEqualTo(bindingDirectory);
+ assertThat(serviceBinding.getType()).isEqualTo("infinispan");
+ assertThat(serviceBinding.getProvider()).isNull();
+ assertThat(serviceBinding.getProperties().containsKey(INFINISPAN_USE_AUTH)).isFalse();
+ assertThat(serviceBinding.getProperties().containsKey(INFINISPAN_USERNAME)).isFalse();
+ assertThat(serviceBinding.getProperties().containsKey(INFINISPAN_PASSWORD)).isFalse();
+ assertThat(serviceBinding.getProperties().containsKey(INFINISPAN_HOSTS)).isFalse();
+ assertThat(serviceBinding.getProperties().containsKey(INFINISPAN_URI)).isFalse();
+ }
+}
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/hosts b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/hosts
new file mode 100644
index 0000000000000..5c311ffe8b92f
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/hosts
@@ -0,0 +1 @@
+infinispan.forever.com:11222
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/password b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/password
new file mode 100644
index 0000000000000..8f2c4674476ac
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/password
@@ -0,0 +1 @@
+infiniforever
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/provider b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/provider
new file mode 100644
index 0000000000000..164b286104ce6
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/provider
@@ -0,0 +1 @@
+coco
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/type b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/type
new file mode 100644
index 0000000000000..45f7580c77695
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/type
@@ -0,0 +1 @@
+infinispan
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/uri b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/uri
new file mode 100644
index 0000000000000..a0734c96ece0c
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/uri
@@ -0,0 +1 @@
+hotrod://admin:password@infinispan.forever.com:11222
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/useauth b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/useauth
new file mode 100644
index 0000000000000..f32a5804e292d
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/useauth
@@ -0,0 +1 @@
+true
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/username b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/username
new file mode 100644
index 0000000000000..5eabebd8bc0fc
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/all-props/username
@@ -0,0 +1 @@
+someadmin
\ No newline at end of file
diff --git a/extensions/infinispan-client/runtime/src/test/resources/service-binding/no-props/type b/extensions/infinispan-client/runtime/src/test/resources/service-binding/no-props/type
new file mode 100644
index 0000000000000..45f7580c77695
--- /dev/null
+++ b/extensions/infinispan-client/runtime/src/test/resources/service-binding/no-props/type
@@ -0,0 +1 @@
+infinispan
\ No newline at end of file