parent
d5ef798cac
commit
d045156ba4
7 changed files with 104 additions and 19 deletions
|
@ -176,7 +176,23 @@ CONDITION: RollingUpdate
|
|||
|
||||
=== Accessing the Keycloak deployment
|
||||
|
||||
The Keycloak deployment is exposed through a basic Ingress and is accessible through the provided hostname.
|
||||
The Keycloak deployment is exposed through a basic Ingress and is accessible through the provided hostname. On installations with multiple default IngressClass instances
|
||||
or when running on OpenShift 4.12+ you should provide an ingressClassName by setting `ingress` spec with `className` property to the desired class name:
|
||||
|
||||
Edit YAML file `example-kc.yaml`:
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: k8s.keycloak.org/v2alpha1
|
||||
kind: Keycloak
|
||||
metadata:
|
||||
name: example-kc
|
||||
spec:
|
||||
...
|
||||
ingress:
|
||||
className: openshift-default
|
||||
----
|
||||
|
||||
If the default ingress does not fit your use case, disable it by setting `ingress` spec with `enabled` property to `false` value:
|
||||
|
||||
Edit YAML file `example-kc.yaml`:
|
||||
|
|
|
@ -72,11 +72,8 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
|
|||
annotations.put("route.openshift.io/termination", "edge");
|
||||
}
|
||||
|
||||
if (keycloak.getSpec().getIngressSpec() != null &&
|
||||
keycloak.getSpec().getIngressSpec().getAnnotations() != null) {
|
||||
annotations.putAll(keycloak.getSpec().getIngressSpec().getAnnotations());
|
||||
|
||||
}
|
||||
var optionalSpec = Optional.ofNullable(keycloak.getSpec().getIngressSpec());
|
||||
optionalSpec.map(IngressSpec::getAnnotations).ifPresent(annotations::putAll);
|
||||
|
||||
Ingress ingress = new IngressBuilder()
|
||||
.withNewMetadata()
|
||||
|
@ -85,6 +82,7 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
|
|||
.addToAnnotations(annotations)
|
||||
.endMetadata()
|
||||
.withNewSpec()
|
||||
.withIngressClassName(optionalSpec.map(IngressSpec::getIngressClassName).orElse(null))
|
||||
.withNewDefaultBackend()
|
||||
.withNewService()
|
||||
.withName(keycloak.getMetadata().getName() + Constants.KEYCLOAK_SERVICE_SUFFIX)
|
||||
|
|
|
@ -27,18 +27,29 @@ import java.util.Map;
|
|||
public class IngressSpec {
|
||||
|
||||
@JsonProperty("enabled")
|
||||
private boolean enabled = true;
|
||||
private boolean ingressEnabled = true;
|
||||
|
||||
@JsonProperty("className")
|
||||
private String ingressClassName;
|
||||
|
||||
@JsonProperty("annotations")
|
||||
@JsonPropertyDescription("Additional annotations to be appended to the Ingress object")
|
||||
Map<String, String> annotations;
|
||||
|
||||
public boolean isIngressEnabled() {
|
||||
return enabled;
|
||||
return ingressEnabled;
|
||||
}
|
||||
|
||||
public void setIngressEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
this.ingressEnabled = enabled;
|
||||
}
|
||||
|
||||
public String getIngressClassName() {
|
||||
return ingressClassName;
|
||||
}
|
||||
|
||||
public void setIngressClassName(String className) {
|
||||
this.ingressClassName = className;
|
||||
}
|
||||
|
||||
public Map<String, String> getAnnotations() {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.keycloak.operator.Constants;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpecBuilder;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
|
||||
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
||||
import org.keycloak.operator.controllers.KeycloakIngress;
|
||||
|
@ -270,6 +271,39 @@ public class KeycloakIngressTest extends BaseOperatorTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomIngressClassName() {
|
||||
var kc = K8sUtils.getDefaultKeycloakDeployment();
|
||||
kc.getSpec().setIngressSpec(new IngressSpecBuilder().withIngressClassName("nginx").build());
|
||||
K8sUtils.deployKeycloak(k8sclient, kc, true);
|
||||
|
||||
var ingress = new KeycloakIngress(k8sclient, kc);
|
||||
var ingressSelector = k8sclient
|
||||
.network()
|
||||
.v1()
|
||||
.ingresses()
|
||||
.inNamespace(namespace)
|
||||
.withName(ingress.getName());
|
||||
|
||||
Awaitility.await()
|
||||
.ignoreExceptions()
|
||||
.untilAsserted(() -> {
|
||||
var i = ingressSelector.get();
|
||||
assertEquals("nginx", i.getSpec().getIngressClassName());
|
||||
});
|
||||
|
||||
// update to a different classname
|
||||
kc.getSpec().setIngressSpec(new IngressSpecBuilder().withIngressClassName("nginx-latest").build());
|
||||
K8sUtils.deployKeycloak(k8sclient, kc, true);
|
||||
|
||||
Awaitility.await()
|
||||
.ignoreExceptions()
|
||||
.untilAsserted(() -> {
|
||||
var i = ingressSelector.get();
|
||||
assertEquals("nginx-latest", i.getSpec().getIngressClassName());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomIngressAnnotations() {
|
||||
var kc = K8sUtils.getDefaultKeycloakDeployment();
|
||||
|
|
|
@ -55,6 +55,7 @@ public class CRSerializationTest {
|
|||
assertEquals("my-image", keycloak.getSpec().getImage());
|
||||
assertEquals("my-tls-secret", keycloak.getSpec().getHttpSpec().getTlsSecret());
|
||||
assertFalse(keycloak.getSpec().getIngressSpec().isIngressEnabled());
|
||||
assertEquals("nginx", keycloak.getSpec().getIngressSpec().getIngressClassName());
|
||||
assertEquals(CUSTOM_INGRESS_ANNOTATION, keycloak.getSpec().getIngressSpec().getAnnotations());
|
||||
|
||||
final TransactionsSpec transactionsSpec = keycloak.getSpec().getTransactionsSpec();
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.keycloak.operator.controllers.KeycloakIngress;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpecBuilder;
|
||||
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
|
@ -35,6 +36,7 @@ import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class IngressLogicTest {
|
||||
|
@ -43,15 +45,11 @@ public class IngressLogicTest {
|
|||
|
||||
static class MockKeycloakIngress extends KeycloakIngress {
|
||||
|
||||
private static Keycloak getKeycloak(Boolean defaultIngressEnabled, boolean ingressSpecDefined, boolean tlsConfigured, Map<String, String> annotations) {
|
||||
private static Keycloak getKeycloak(boolean tlsConfigured, IngressSpec ingressSpec) {
|
||||
var kc = K8sUtils.getDefaultKeycloakDeployment();
|
||||
kc.getMetadata().setUid("this-is-a-fake-uid");
|
||||
if (ingressSpecDefined) {
|
||||
kc.getSpec().setIngressSpec(new IngressSpec());
|
||||
if (defaultIngressEnabled != null) kc.getSpec().getIngressSpec().setIngressEnabled(defaultIngressEnabled);
|
||||
if (annotations != null) {
|
||||
kc.getSpec().getIngressSpec().setAnnotations(annotations);
|
||||
}
|
||||
if (ingressSpec != null) {
|
||||
kc.getSpec().setIngressSpec(ingressSpec);
|
||||
}
|
||||
if (!tlsConfigured) {
|
||||
kc.getSpec().getHttpSpec().setTlsSecret(null);
|
||||
|
@ -69,13 +67,23 @@ public class IngressLogicTest {
|
|||
|
||||
public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined, boolean tlsConfigured, Map<String, String> annotations) {
|
||||
MockKeycloakIngress.ingressExists = ingressExists;
|
||||
return new MockKeycloakIngress(defaultIngressEnabled, ingressSpecDefined, tlsConfigured, annotations);
|
||||
IngressSpec ingressSpec = null;
|
||||
if (ingressSpecDefined) {
|
||||
ingressSpec = new IngressSpec();
|
||||
if (defaultIngressEnabled != null) {
|
||||
ingressSpec.setIngressEnabled(defaultIngressEnabled);
|
||||
}
|
||||
if (annotations != null) {
|
||||
ingressSpec.setAnnotations(annotations);
|
||||
}
|
||||
}
|
||||
return new MockKeycloakIngress(tlsConfigured, ingressSpec);
|
||||
}
|
||||
|
||||
public static boolean ingressExists = false;
|
||||
private boolean deleted = false;
|
||||
public MockKeycloakIngress(Boolean defaultIngressEnabled, boolean ingressSpecDefined, boolean tlsConfigured, Map<String, String> annotations) {
|
||||
super(null, getKeycloak(defaultIngressEnabled, ingressSpecDefined, tlsConfigured, annotations));
|
||||
public MockKeycloakIngress(boolean tlsConfigured, IngressSpec ingressSpec) {
|
||||
super(null, getKeycloak(tlsConfigured, ingressSpec));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -218,4 +226,20 @@ public class IngressLogicTest {
|
|||
assertEquals("passthrough", reconciled.get().getMetadata().getAnnotations().get("route.openshift.io/termination"));
|
||||
assertEquals("another-value", reconciled.get().getMetadata().getAnnotations().get(EXISTING_ANNOTATION_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIngressSpecDefinedWithoutClassName() {
|
||||
var kc = new MockKeycloakIngress(true, new IngressSpec());
|
||||
Optional<HasMetadata> reconciled = kc.getReconciledResource();
|
||||
Ingress ingress = reconciled.map(Ingress.class::cast).orElseThrow();
|
||||
assertNull(ingress.getSpec().getIngressClassName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIngressSpecDefinedWithClassName() {
|
||||
var kc = new MockKeycloakIngress(true, new IngressSpecBuilder().withIngressClassName("my-class").build());
|
||||
Optional<HasMetadata> reconciled = kc.getReconciledResource();
|
||||
Ingress ingress = reconciled.map(Ingress.class::cast).orElseThrow();
|
||||
assertEquals("my-class", ingress.getSpec().getIngressClassName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ spec:
|
|||
poolMaxSize: 3
|
||||
ingress:
|
||||
enabled: false
|
||||
className: nginx
|
||||
annotations:
|
||||
myAnnotation: myValue
|
||||
anotherAnnotation: anotherValue
|
||||
|
|
Loading…
Reference in a new issue