Respect http-relative-path
with probes
This commit is contained in:
parent
c31d37ddf1
commit
f9c6ea84ad
4 changed files with 126 additions and 21 deletions
|
@ -51,4 +51,6 @@ public final class Constants {
|
|||
|
||||
public static final String INSECURE_DISABLE = "INSECURE-DISABLE";
|
||||
public static final String CERTIFICATES_FOLDER = "/mnt/certificates";
|
||||
|
||||
public static String KEYCLOAK_HTTP_RELATIVE_PATH_KEY = "http-relative-path";
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import io.fabric8.kubernetes.api.model.Container;
|
|||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarSourceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ExecActionBuilder;
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
|
||||
import io.fabric8.kubernetes.api.model.ResourceRequirements;
|
||||
|
@ -36,7 +37,9 @@ import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
|||
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusBuilder;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -347,6 +350,7 @@ public class KeycloakDeployment extends OperatorManagedResource implements Statu
|
|||
var kcContainer = deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
|
||||
var tlsSecret = this.keycloakCR.getSpec().getTlsSecret();
|
||||
var envVars = kcContainer.getEnv();
|
||||
|
||||
if (this.keycloakCR.getSpec().isHttp()) {
|
||||
var disableTls = List.of(
|
||||
new EnvVarBuilder()
|
||||
|
@ -363,11 +367,6 @@ public class KeycloakDeployment extends OperatorManagedResource implements Statu
|
|||
.build());
|
||||
|
||||
envVars.addAll(disableTls);
|
||||
|
||||
kcContainer.getReadinessProbe().getExec().setCommand(
|
||||
List.of("curl", "--head", "--fail", "--silent", "http://127.0.0.1:" + Constants.KEYCLOAK_HTTP_PORT + "/health/ready"));
|
||||
kcContainer.getLivenessProbe().getExec().setCommand(
|
||||
List.of("curl", "--head", "--fail", "--silent", "http://127.0.0.1:" + Constants.KEYCLOAK_HTTP_PORT + "/health/live"));
|
||||
} else {
|
||||
var enabledTls = List.of(
|
||||
new EnvVarBuilder()
|
||||
|
@ -401,6 +400,66 @@ public class KeycloakDeployment extends OperatorManagedResource implements Statu
|
|||
deployment.getSpec().getTemplate().getSpec().getVolumes().add(volume);
|
||||
kcContainer.getVolumeMounts().add(volumeMount);
|
||||
}
|
||||
|
||||
var userRelativePath = readConfigurationValue(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY);
|
||||
var kcRelativePath = (userRelativePath == null) ? "/" : userRelativePath;
|
||||
var protocol = (this.keycloakCR.getSpec().isHttp()) ? "http" : "https";
|
||||
var kcPort = (this.keycloakCR.getSpec().isHttp()) ? Constants.KEYCLOAK_HTTP_PORT : Constants.KEYCLOAK_HTTPS_PORT;
|
||||
|
||||
var baseProbe = new ArrayList<>(List.of("curl", "--head", "--fail", "--silent"));
|
||||
|
||||
if (!this.keycloakCR.getSpec().isHttp()) {
|
||||
baseProbe.add("--insecure");
|
||||
}
|
||||
|
||||
var readyProbe = new ArrayList<>(baseProbe);
|
||||
readyProbe.add(protocol + "://127.0.0.1:" + kcPort + kcRelativePath + "/health/ready");
|
||||
var liveProbe = new ArrayList<>(baseProbe);
|
||||
liveProbe.add(protocol + "://127.0.0.1:" + kcPort + kcRelativePath + "/health/live");
|
||||
|
||||
kcContainer
|
||||
.getReadinessProbe()
|
||||
.setExec(new ExecActionBuilder().withCommand(readyProbe).build());
|
||||
kcContainer
|
||||
.getLivenessProbe()
|
||||
.setExec(new ExecActionBuilder().withCommand(liveProbe).build());
|
||||
}
|
||||
|
||||
public String readConfigurationValue(String key) {
|
||||
if (this.keycloakCR != null &&
|
||||
this.keycloakCR.getSpec() != null &&
|
||||
this.keycloakCR.getSpec().getServerConfiguration() != null
|
||||
) {
|
||||
var serverConfigValue = this.keycloakCR
|
||||
.getSpec()
|
||||
.getServerConfiguration()
|
||||
.stream()
|
||||
.filter(sc -> sc.getName().equals(key))
|
||||
.findFirst();
|
||||
if (serverConfigValue.isPresent()) {
|
||||
if (serverConfigValue.get().getValue() != null) {
|
||||
return serverConfigValue.get().getValue();
|
||||
} else {
|
||||
var secretSelector = serverConfigValue.get().getSecret();
|
||||
if (secretSelector == null) {
|
||||
throw new IllegalStateException("Secret " + serverConfigValue.get().getName() + " not defined");
|
||||
}
|
||||
var secret = client.secrets().inNamespace(getNamespace()).withName(secretSelector.getName()).get();
|
||||
if (secret == null) {
|
||||
throw new IllegalStateException("Secret " + secretSelector.getName() + " not found in cluster");
|
||||
}
|
||||
if (secret.getData().containsKey(secretSelector.getKey())) {
|
||||
return new String(Base64.getDecoder().decode(secret.getData().get(secretSelector.getKey())), StandardCharsets.UTF_8);
|
||||
} else {
|
||||
throw new IllegalStateException("Secret " + secretSelector.getName() + " doesn't contain the expected key " + secretSelector.getKey());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Deployment createBaseDeployment() {
|
||||
|
|
|
@ -27,26 +27,10 @@ spec:
|
|||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- curl
|
||||
- --insecure
|
||||
- --head
|
||||
- --fail
|
||||
- --silent
|
||||
- https://127.0.0.1:8443/health/live
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 2
|
||||
failureThreshold: 150
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- curl
|
||||
- --insecure
|
||||
- --head
|
||||
- --fail
|
||||
- --silent
|
||||
- https://127.0.0.1:8443/health/ready
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 2
|
||||
failureThreshold: 250
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.keycloak.operator;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.SecretBuilder;
|
||||
import io.fabric8.kubernetes.api.model.SecretKeySelectorBuilder;
|
||||
import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
|
||||
import io.quarkus.logging.Log;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
|
@ -20,6 +22,7 @@ import java.util.Base64;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
@ -354,4 +357,61 @@ public class KeycloakDeploymentE2EIT extends ClusterOperatorTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpRelativePathWithPlainValue() {
|
||||
try {
|
||||
var kc = getDefaultKeycloakDeployment();
|
||||
kc.getSpec().getServerConfiguration().add(new ValueOrSecret(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY, "/foobar"));
|
||||
deployKeycloak(k8sclient, kc, true);
|
||||
|
||||
var pods = k8sclient
|
||||
.pods()
|
||||
.inNamespace(namespace)
|
||||
.withLabels(Constants.DEFAULT_LABELS)
|
||||
.list()
|
||||
.getItems();
|
||||
|
||||
assertTrue(pods.get(0).getSpec().getContainers().get(0).getReadinessProbe().getExec().getCommand().stream().collect(Collectors.joining()).contains("foobar"));
|
||||
} catch (Exception e) {
|
||||
savePodLogs();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpRelativePathWithSecretValue() {
|
||||
try {
|
||||
var kc = getDefaultKeycloakDeployment();
|
||||
var secretName = "my-http-relative-path";
|
||||
var keyName = "rel-path";
|
||||
var httpRelativePathSecret = new SecretBuilder()
|
||||
.withNewMetadata()
|
||||
.withName(secretName)
|
||||
.withNamespace(namespace)
|
||||
.endMetadata()
|
||||
.addToStringData(keyName, "/barfoo")
|
||||
.build();
|
||||
k8sclient.secrets().inNamespace(namespace).createOrReplace(httpRelativePathSecret);
|
||||
|
||||
kc.getSpec().getServerConfiguration().add(new ValueOrSecret(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY,
|
||||
new SecretKeySelectorBuilder()
|
||||
.withName(secretName)
|
||||
.withKey(keyName)
|
||||
.build()));
|
||||
deployKeycloak(k8sclient, kc, true);
|
||||
|
||||
var pods = k8sclient
|
||||
.pods()
|
||||
.inNamespace(namespace)
|
||||
.withLabels(Constants.DEFAULT_LABELS)
|
||||
.list()
|
||||
.getItems();
|
||||
|
||||
assertTrue(pods.get(0).getSpec().getContainers().get(0).getReadinessProbe().getExec().getCommand().stream().collect(Collectors.joining()).contains("barfoo"));
|
||||
} catch (Exception e) {
|
||||
savePodLogs();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue