Skip to content

Commit

Permalink
Merge pull request #30268 from karesti/infinispan-service-binding
Browse files Browse the repository at this point in the history
Infinispan Service Binding
  • Loading branch information
geoand authored Jan 10, 2023
2 parents 9ecc659 + d321252 commit fbbb5e8
Show file tree
Hide file tree
Showing 15 changed files with 209 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/deploying-to-kubernetes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`
====


Expand Down
5 changes: 5 additions & 0 deletions extensions/infinispan-client/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<artifactId>quarkus-smallrye-health-spi</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-service-binding-spi</artifactId>
</dependency>

<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-server-testdriver-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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";
Expand Down Expand Up @@ -260,4 +265,13 @@ HealthBuildItem addHealthCheck(InfinispanClientBuildTimeConfig buildTimeConfig)
buildTimeConfig.healthEnabled);
}

@BuildStep
void registerServiceBinding(Capabilities capabilities, BuildProducer<ServiceProviderBuildItem> buildProducer) {
if (capabilities.isPresent(Capability.KUBERNETES_SERVICE_BINDING)) {
buildProducer.produce(
new ServiceProviderBuildItem(SERVICE_BINDING_INTERFACE_NAME,
InfinispanServiceBindingConverter.class.getName()));
}
}

}
15 changes: 15 additions & 0 deletions extensions/infinispan-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@
<artifactId>quarkus-smallrye-health</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-service-binding</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*
* <br>
* <br>
* Following individual properties are supported to make the connection:
* <ul>
* <li>uri</li>
* <li>hosts(<i>host information can be provided in this property separated by : sign</i>, e.g. localhost:11222</li>)
* <li>useauth</li>
* <li>username</li>
* <li>password</li>
* </ul>
* <i>if uri is provided, all the other properties are ignored</i>
* <i>if uri is not provided, hosts is mandatory and all other properties are optional</i>
*
* <br>
* <br>
* The Quarkus properties set by this class are:
* <ul>
* <li>quarkus.infinispan-client.uri (<i>if uri is provided</i>)</li>
* <li>quarkus.infinispan-client.hosts (<i>if hosts is provided and uri is not provided</i>)</li>
* <li>quarkus.infinispan-client.use-auth (<i>if useauth is provided and uri is not provided</i>)</li>
* <li>quarkus.infinispan-client.username (<i>if username is provided and uri is not provided</i>)</li>
* <li>quarkus.infinispan-client.password (<i>if password is provided and uri is not provided</i>)</li>
* </ul>
*/
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<ServiceBindingConfigSource> convert(List<ServiceBinding> serviceBindings) {
Optional<ServiceBinding> matchingByType = ServiceBinding.singleMatchingByType(BINDING_TYPE, serviceBindings);
if (matchingByType.isEmpty()) {
return Optional.empty();
}

ServiceBinding binding = matchingByType.get();
Map<String, String> 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<String, String> properties) {
properties.put(INFINISPAN_CLIENT_URI, getInfinispanProperty(binding, INFINISPAN_URI));
}

private void setConnection(ServiceBinding binding, Map<String, String> properties) {
properties.put(INFINISPAN_CLIENT_HOSTS, getInfinispanProperty(binding, INFINISPAN_HOSTS));
}

private void setUseAuth(ServiceBinding binding, Map<String, String> properties) {
properties.put(INFINISPAN_CLIENT_USE_AUTH, getInfinispanProperty(binding, INFINISPAN_USE_AUTH));
}

private void setUsername(ServiceBinding binding, Map<String, String> properties) {
properties.put(INFINISPAN_CLIENT_AUTH_USERNAME, getInfinispanProperty(binding, INFINISPAN_USERNAME));
}

private void setPassword(ServiceBinding binding, Map<String, String> 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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.quarkus.infinispan.client.runtime.InfinispanServiceBindingConverter
Original file line number Diff line number Diff line change
@@ -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:[email protected]: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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
infinispan.forever.com:11222
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
infiniforever
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coco
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
infinispan
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hotrod://admin:[email protected]:11222
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
true
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
someadmin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
infinispan

0 comments on commit fbbb5e8

Please sign in to comment.