From 678349d66f1597deb7764bed79797fc1a27c5626 Mon Sep 17 00:00:00 2001 From: dolearci Date: Wed, 26 Jul 2023 20:57:50 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Add=20redis=20and=20ldap=20system-x?= =?UTF-8?q?=20for=20openshift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ldap/resource/local/LDAPContainer.java | 7 +- .../tnb/ldap/resource/local/LocalLDAP.java | 14 +- .../resource/openshift/OpenshiftLDAP.java | 177 ++++++++++++++++++ .../java/software/tnb/ldap/service/LDAP.java | 18 +- .../tnb/redis/resource/local/LocalRedis.java | 1 - .../resource/openshift/OpenshiftRedis.java | 135 +++++++++++++ .../software/tnb/redis/service/Redis.java | 2 + 7 files changed, 343 insertions(+), 11 deletions(-) create mode 100644 system-x/services/ldap/src/main/java/software/tnb/ldap/resource/openshift/OpenshiftLDAP.java create mode 100644 system-x/services/redis/src/main/java/software/tnb/redis/resource/openshift/OpenshiftRedis.java diff --git a/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LDAPContainer.java b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LDAPContainer.java index 46029f3b7..fd935f777 100644 --- a/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LDAPContainer.java +++ b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LDAPContainer.java @@ -3,11 +3,14 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import java.util.Map; + public class LDAPContainer extends GenericContainer { - public LDAPContainer(String image, int port) { + public LDAPContainer(String image, int port, Map env) { super(image); this.withExposedPorts(port); - this.waitingFor(Wait.forListeningPort()); + this.withEnv(env); + this.waitingFor(Wait.forLogMessage(".*slapd starting.*", 2)); } } diff --git a/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LocalLDAP.java b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LocalLDAP.java index 8e24b5bab..f1dca0582 100644 --- a/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LocalLDAP.java +++ b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/local/LocalLDAP.java @@ -3,7 +3,6 @@ import software.tnb.common.deployment.Deployable; import software.tnb.ldap.service.LDAP; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,13 +15,12 @@ public class LocalLDAP extends LDAP implements Deployable { private static final Logger LOG = LoggerFactory.getLogger(LocalLDAP.class); - private static final int PORT = 389; private LDAPContainer ldapContainer; @Override public void deploy() { LOG.info("Starting LDAP container"); - ldapContainer = new LDAPContainer(defaultImage(), PORT); + ldapContainer = new LDAPContainer(defaultImage(), PORT, environmentVariables()); ldapContainer.start(); LOG.info("LDAP container started"); } @@ -44,17 +42,19 @@ public String url() { public void openResources() { final LDAPConnection ldapConnection = new LDAPConnection(); try { - ldapConnection.connect(StringUtils.substringBetween(url(), "ldap://", ":"), Integer.parseInt(StringUtils.substringAfterLast(url(), ':'))); + ldapConnection.connect(ldapContainer.getHost(), ldapContainer.getMappedPort(PORT), 20000); ldapConnection.bind(account().username(), account().password()); client = new LDAPConnectionPool(ldapConnection, 1); } catch (LDAPException e) { - LOG.error("Error when connecting to LDAP server"); - throw new RuntimeException("Error when connecting to LDAP server"); + LOG.error("Error when connecting to LDAP server: " + e.getMessage()); + throw new RuntimeException("Error when connecting to LDAP server", e); } } @Override public void closeResources() { - client.close(); + if (client != null) { + client.close(); + } } } diff --git a/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/openshift/OpenshiftLDAP.java b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/openshift/OpenshiftLDAP.java new file mode 100644 index 000000000..158453f09 --- /dev/null +++ b/system-x/services/ldap/src/main/java/software/tnb/ldap/resource/openshift/OpenshiftLDAP.java @@ -0,0 +1,177 @@ +package software.tnb.ldap.resource.openshift; + +import software.tnb.common.config.OpenshiftConfiguration; +import software.tnb.common.deployment.ReusableOpenshiftDeployable; +import software.tnb.common.deployment.WithName; +import software.tnb.common.openshift.OpenshiftClient; +import software.tnb.common.utils.IOUtils; +import software.tnb.common.utils.MapUtils; +import software.tnb.common.utils.NetworkUtils; +import software.tnb.common.utils.WaitUtils; +import software.tnb.ldap.service.LDAP; + +import com.google.auto.service.AutoService; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPConnectionPool; +import com.unboundid.ldap.sdk.LDAPException; + +import java.util.function.Predicate; + +import io.fabric8.kubernetes.api.model.IntOrString; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.Probe; +import io.fabric8.kubernetes.api.model.ProbeBuilder; +import io.fabric8.kubernetes.api.model.ServiceAccountBuilder; +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.api.model.TCPSocketActionBuilder; +import io.fabric8.kubernetes.client.PortForward; +import io.fabric8.openshift.api.model.DeploymentConfigBuilder; + +@AutoService(LDAP.class) +public class OpenshiftLDAP extends LDAP implements ReusableOpenshiftDeployable, WithName { + + private PortForward portForward; + private int localPort; + private String sccName; + private String serviceAccountName; + + @Override + public void undeploy() { + OpenshiftClient.get().deploymentConfigs().withName(name()).delete(); + OpenshiftClient.get().services().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).delete(); + WaitUtils.waitFor(() -> servicePod() == null, "Waiting until the pod is removed"); + } + + @Override + public void openResources() { + + localPort = NetworkUtils.getFreePort(); + portForward = OpenshiftClient.get().services().withName(name()).portForward(PORT, localPort); + final LDAPConnection ldapConnection = new LDAPConnection(); + try { + ldapConnection.connect("localhost", localPort, 20000); + ldapConnection.bind(account().username(), account().password()); + client = new LDAPConnectionPool(ldapConnection, 1); + } catch (LDAPException e) { + throw new RuntimeException("Error when connecting to LDAP server: " + e.getMessage()); + } + } + + @Override + public void closeResources() { + + if (client != null) { + client.close(); + } + + if (portForward != null && portForward.isAlive()) { + IOUtils.closeQuietly(portForward); + } + } + + @Override + public void create() { + + sccName = "tnb-ldap-" + OpenshiftClient.get().getNamespace(); + + serviceAccountName = name() + "-sa"; + + OpenshiftClient.get().serviceAccounts() + .createOrReplace(new ServiceAccountBuilder() + .withNewMetadata() + .withName(serviceAccountName) + .endMetadata() + .build() + ); + + OpenshiftClient.get().addUsersToSecurityContext( + OpenshiftClient.get().createSecurityContext(sccName, "anyuid", "SYS_CHROOT"), + OpenshiftClient.get().getServiceAccountRef(serviceAccountName)); + + final Probe probe = new ProbeBuilder() + .withTcpSocket(new TCPSocketActionBuilder().withPort(new IntOrString(PORT)).build()) + .withTimeoutSeconds(15) + .build(); + + OpenshiftClient.get().deploymentConfigs().createOrReplace(new DeploymentConfigBuilder() + .withNewMetadata() + .withName(name()) + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .addToAnnotations("openshift.io/scc", sccName) + .endMetadata() + .editOrNewSpec() + .addToSelector(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .withReplicas(1) + .editOrNewTemplate() + .editOrNewMetadata() + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .endMetadata() + .editOrNewSpec() + .withServiceAccount(serviceAccountName) + .addNewContainer() + .withName(name()) + .withImage(defaultImage()) + .addNewPort() + .withContainerPort(PORT) + .withName(name()) + .endPort() + .editOrNewSecurityContext() + .editOrNewCapabilities() + .addNewAdd("SYS_CHROOT") + .endCapabilities() + .endSecurityContext() + .withEnv(MapUtils.toEnvVars(environmentVariables())) + .withReadinessProbe(probe) + .withLivenessProbe(probe) + .endContainer() + .endSpec() + .endTemplate() + .addNewTrigger() + .withType("ConfigChange") + .endTrigger() + .endSpec() + .build()); + + OpenshiftClient.get().services().createOrReplace(new ServiceBuilder() + .editOrNewMetadata() + .withName(name()) + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .endMetadata() + .editOrNewSpec() + .addToSelector(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .addNewPort() + .withName(name()) + .withProtocol("TCP") + .withPort(PORT) + .withTargetPort(new IntOrString(PORT)) + .endPort() + .endSpec() + .build()); + } + + @Override + public boolean isDeployed() { + return OpenshiftClient.get().apps().deployments().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).list() + .getItems().size() > 0; + } + + @Override + public Predicate podSelector() { + return WithName.super.podSelector(); + } + + @Override + public void cleanup() { + + } + + @Override + public String name() { + return "ldap"; + } + + @Override + public String url() { + return String.format("ldap://%s:%d", name(), PORT); + } +} diff --git a/system-x/services/ldap/src/main/java/software/tnb/ldap/service/LDAP.java b/system-x/services/ldap/src/main/java/software/tnb/ldap/service/LDAP.java index 0deb80224..3737376cd 100644 --- a/system-x/services/ldap/src/main/java/software/tnb/ldap/service/LDAP.java +++ b/system-x/services/ldap/src/main/java/software/tnb/ldap/service/LDAP.java @@ -5,10 +5,16 @@ import software.tnb.ldap.account.LDAPAccount; import software.tnb.ldap.validation.LDAPValidation; +import org.apache.commons.lang3.StringUtils; + import com.unboundid.ldap.sdk.LDAPConnectionPool; +import java.util.Map; + public abstract class LDAP extends Service implements WithDockerImage { + protected static final int PORT = 389; + public abstract String url(); public LDAPValidation validation() { @@ -20,6 +26,16 @@ public LDAPValidation validation() { @Override public String defaultImage() { - return "quay.io/fuse_qe/openldap:1.5.0"; + return "quay.io/fuse_qe/ocp-openldap:latest"; + } + + public Map environmentVariables() { + return Map.of("OPENLDAP_ROOT_DN_SUFFIX" + , StringUtils.substringAfter(account().username(), ",") + , "OPENLDAP_ROOT_DN_PREFIX" + , StringUtils.substringBefore(account().username(), ",") + , "OPENLDAP_ROOT_PASSWORD" + , account().password() + ); } } diff --git a/system-x/services/redis/src/main/java/software/tnb/redis/resource/local/LocalRedis.java b/system-x/services/redis/src/main/java/software/tnb/redis/resource/local/LocalRedis.java index 482a71ce2..d7389c9bf 100644 --- a/system-x/services/redis/src/main/java/software/tnb/redis/resource/local/LocalRedis.java +++ b/system-x/services/redis/src/main/java/software/tnb/redis/resource/local/LocalRedis.java @@ -15,7 +15,6 @@ public class LocalRedis extends Redis implements Deployable { private static final Logger LOG = LoggerFactory.getLogger(LocalRedis.class); - private static final int PORT = 6379; private RedisContainer redisContainer; @Override diff --git a/system-x/services/redis/src/main/java/software/tnb/redis/resource/openshift/OpenshiftRedis.java b/system-x/services/redis/src/main/java/software/tnb/redis/resource/openshift/OpenshiftRedis.java new file mode 100644 index 000000000..935efac7e --- /dev/null +++ b/system-x/services/redis/src/main/java/software/tnb/redis/resource/openshift/OpenshiftRedis.java @@ -0,0 +1,135 @@ +package software.tnb.redis.resource.openshift; + +import software.tnb.common.config.OpenshiftConfiguration; +import software.tnb.common.deployment.ReusableOpenshiftDeployable; +import software.tnb.common.deployment.WithName; +import software.tnb.common.openshift.OpenshiftClient; +import software.tnb.common.utils.IOUtils; +import software.tnb.common.utils.NetworkUtils; +import software.tnb.common.utils.WaitUtils; +import software.tnb.redis.service.Redis; + +import com.google.auto.service.AutoService; + +import java.util.function.Predicate; + +import io.fabric8.kubernetes.api.model.IntOrString; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.client.PortForward; +import io.fabric8.openshift.api.model.DeploymentConfigBuilder; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; + +@AutoService(Redis.class) +public class OpenshiftRedis extends Redis implements ReusableOpenshiftDeployable, WithName { + + private PortForward portForward; + private int localPort; + + @Override + public void undeploy() { + OpenshiftClient.get().deploymentConfigs().withName(name()).delete(); + OpenshiftClient.get().services().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).delete(); + WaitUtils.waitFor(() -> servicePod() == null, "Waiting until the pod is removed"); + } + + @Override + public void openResources() { + localPort = NetworkUtils.getFreePort(); + portForward = OpenshiftClient.get().services().withName(name()).portForward(PORT, localPort); + + client = RedisClient.create(RedisURI.builder() + .withHost("localhost") + .withPort(localPort) + .build()); + + } + + @Override + public void closeResources() { + if (portForward != null && portForward.isAlive()) { + IOUtils.closeQuietly(portForward); + } + } + + @Override + public void create() { + + OpenshiftClient.get().deploymentConfigs().createOrReplace(new DeploymentConfigBuilder() + .withNewMetadata() + .withName(name()) + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .endMetadata() + .editOrNewSpec() + .addToSelector(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .withReplicas(1) + .editOrNewTemplate() + .editOrNewMetadata() + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .endMetadata() + .editOrNewSpec() + .addNewContainer() + .withName(name()) + .withImage(defaultImage()) + .addNewPort() + .withContainerPort(PORT) + .withName(name()) + .endPort() + .endContainer() + .endSpec() + .endTemplate() + .addNewTrigger() + .withType("ConfigChange") + .endTrigger() + .endSpec() + .build()); + + OpenshiftClient.get().services().createOrReplace(new ServiceBuilder() + .editOrNewMetadata() + .withName(name()) + .addToLabels(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .endMetadata() + .editOrNewSpec() + .addToSelector(OpenshiftConfiguration.openshiftDeploymentLabel(), name()) + .addNewPort() + .withName(name()) + .withProtocol("TCP") + .withPort(PORT) + .withTargetPort(new IntOrString(PORT)) + .endPort() + .endSpec() + .build()); + } + + @Override + public boolean isDeployed() { + return OpenshiftClient.get().apps().deployments().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).list() + .getItems().size() > 0; + } + + @Override + public Predicate podSelector() { + return WithName.super.podSelector(); + } + + @Override + public void cleanup() { + + } + + @Override + public String name() { + return "redis"; + } + + @Override + public String host() { + return name(); + } + + @Override + public int port() { + return PORT; + } +} diff --git a/system-x/services/redis/src/main/java/software/tnb/redis/service/Redis.java b/system-x/services/redis/src/main/java/software/tnb/redis/service/Redis.java index 48ed6a593..abb8cf4c1 100644 --- a/system-x/services/redis/src/main/java/software/tnb/redis/service/Redis.java +++ b/system-x/services/redis/src/main/java/software/tnb/redis/service/Redis.java @@ -9,6 +9,8 @@ public abstract class Redis extends Service implements WithDockerImage { + protected static final int PORT = 6379; + public abstract String host(); public abstract int port();