parent
d5ef798cac
commit
d045156ba4
7 changed files with 104 additions and 19 deletions
|
@ -176,7 +176,23 @@ CONDITION: RollingUpdate
|
||||||
|
|
||||||
=== Accessing the Keycloak deployment
|
=== 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:
|
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`:
|
Edit YAML file `example-kc.yaml`:
|
||||||
|
|
|
@ -72,11 +72,8 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
|
||||||
annotations.put("route.openshift.io/termination", "edge");
|
annotations.put("route.openshift.io/termination", "edge");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keycloak.getSpec().getIngressSpec() != null &&
|
var optionalSpec = Optional.ofNullable(keycloak.getSpec().getIngressSpec());
|
||||||
keycloak.getSpec().getIngressSpec().getAnnotations() != null) {
|
optionalSpec.map(IngressSpec::getAnnotations).ifPresent(annotations::putAll);
|
||||||
annotations.putAll(keycloak.getSpec().getIngressSpec().getAnnotations());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Ingress ingress = new IngressBuilder()
|
Ingress ingress = new IngressBuilder()
|
||||||
.withNewMetadata()
|
.withNewMetadata()
|
||||||
|
@ -85,6 +82,7 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
|
||||||
.addToAnnotations(annotations)
|
.addToAnnotations(annotations)
|
||||||
.endMetadata()
|
.endMetadata()
|
||||||
.withNewSpec()
|
.withNewSpec()
|
||||||
|
.withIngressClassName(optionalSpec.map(IngressSpec::getIngressClassName).orElse(null))
|
||||||
.withNewDefaultBackend()
|
.withNewDefaultBackend()
|
||||||
.withNewService()
|
.withNewService()
|
||||||
.withName(keycloak.getMetadata().getName() + Constants.KEYCLOAK_SERVICE_SUFFIX)
|
.withName(keycloak.getMetadata().getName() + Constants.KEYCLOAK_SERVICE_SUFFIX)
|
||||||
|
|
|
@ -27,18 +27,29 @@ import java.util.Map;
|
||||||
public class IngressSpec {
|
public class IngressSpec {
|
||||||
|
|
||||||
@JsonProperty("enabled")
|
@JsonProperty("enabled")
|
||||||
private boolean enabled = true;
|
private boolean ingressEnabled = true;
|
||||||
|
|
||||||
|
@JsonProperty("className")
|
||||||
|
private String ingressClassName;
|
||||||
|
|
||||||
@JsonProperty("annotations")
|
@JsonProperty("annotations")
|
||||||
@JsonPropertyDescription("Additional annotations to be appended to the Ingress object")
|
@JsonPropertyDescription("Additional annotations to be appended to the Ingress object")
|
||||||
Map<String, String> annotations;
|
Map<String, String> annotations;
|
||||||
|
|
||||||
public boolean isIngressEnabled() {
|
public boolean isIngressEnabled() {
|
||||||
return enabled;
|
return ingressEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIngressEnabled(boolean enabled) {
|
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() {
|
public Map<String, String> getAnnotations() {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.keycloak.operator.Constants;
|
import org.keycloak.operator.Constants;
|
||||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
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.IngressSpec;
|
||||||
|
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpecBuilder;
|
||||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
|
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
|
||||||
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
||||||
import org.keycloak.operator.controllers.KeycloakIngress;
|
import org.keycloak.operator.controllers.KeycloakIngress;
|
||||||
|
@ -269,6 +270,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
|
@Test
|
||||||
public void testCustomIngressAnnotations() {
|
public void testCustomIngressAnnotations() {
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class CRSerializationTest {
|
||||||
assertEquals("my-image", keycloak.getSpec().getImage());
|
assertEquals("my-image", keycloak.getSpec().getImage());
|
||||||
assertEquals("my-tls-secret", keycloak.getSpec().getHttpSpec().getTlsSecret());
|
assertEquals("my-tls-secret", keycloak.getSpec().getHttpSpec().getTlsSecret());
|
||||||
assertFalse(keycloak.getSpec().getIngressSpec().isIngressEnabled());
|
assertFalse(keycloak.getSpec().getIngressSpec().isIngressEnabled());
|
||||||
|
assertEquals("nginx", keycloak.getSpec().getIngressSpec().getIngressClassName());
|
||||||
assertEquals(CUSTOM_INGRESS_ANNOTATION, keycloak.getSpec().getIngressSpec().getAnnotations());
|
assertEquals(CUSTOM_INGRESS_ANNOTATION, keycloak.getSpec().getIngressSpec().getAnnotations());
|
||||||
|
|
||||||
final TransactionsSpec transactionsSpec = keycloak.getSpec().getTransactionsSpec();
|
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.controllers.KeycloakIngress;
|
||||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
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.IngressSpec;
|
||||||
|
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpecBuilder;
|
||||||
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
||||||
|
|
||||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class IngressLogicTest {
|
public class IngressLogicTest {
|
||||||
|
@ -43,15 +45,11 @@ public class IngressLogicTest {
|
||||||
|
|
||||||
static class MockKeycloakIngress extends KeycloakIngress {
|
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();
|
var kc = K8sUtils.getDefaultKeycloakDeployment();
|
||||||
kc.getMetadata().setUid("this-is-a-fake-uid");
|
kc.getMetadata().setUid("this-is-a-fake-uid");
|
||||||
if (ingressSpecDefined) {
|
if (ingressSpec != null) {
|
||||||
kc.getSpec().setIngressSpec(new IngressSpec());
|
kc.getSpec().setIngressSpec(ingressSpec);
|
||||||
if (defaultIngressEnabled != null) kc.getSpec().getIngressSpec().setIngressEnabled(defaultIngressEnabled);
|
|
||||||
if (annotations != null) {
|
|
||||||
kc.getSpec().getIngressSpec().setAnnotations(annotations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!tlsConfigured) {
|
if (!tlsConfigured) {
|
||||||
kc.getSpec().getHttpSpec().setTlsSecret(null);
|
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) {
|
public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined, boolean tlsConfigured, Map<String, String> annotations) {
|
||||||
MockKeycloakIngress.ingressExists = ingressExists;
|
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;
|
public static boolean ingressExists = false;
|
||||||
private boolean deleted = false;
|
private boolean deleted = false;
|
||||||
public MockKeycloakIngress(Boolean defaultIngressEnabled, boolean ingressSpecDefined, boolean tlsConfigured, Map<String, String> annotations) {
|
public MockKeycloakIngress(boolean tlsConfigured, IngressSpec ingressSpec) {
|
||||||
super(null, getKeycloak(defaultIngressEnabled, ingressSpecDefined, tlsConfigured, annotations));
|
super(null, getKeycloak(tlsConfigured, ingressSpec));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -218,4 +226,20 @@ public class IngressLogicTest {
|
||||||
assertEquals("passthrough", reconciled.get().getMetadata().getAnnotations().get("route.openshift.io/termination"));
|
assertEquals("passthrough", reconciled.get().getMetadata().getAnnotations().get("route.openshift.io/termination"));
|
||||||
assertEquals("another-value", reconciled.get().getMetadata().getAnnotations().get(EXISTING_ANNOTATION_KEY));
|
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
|
poolMaxSize: 3
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
myAnnotation: myValue
|
myAnnotation: myValue
|
||||||
anotherAnnotation: anotherValue
|
anotherAnnotation: anotherValue
|
||||||
|
|
Loading…
Reference in a new issue