Refine Ingress settings in Keycloak CR

Closes Keycloak#14407

Signed-off-by: Peter Zaoral <pzaoral@redhat.com>
This commit is contained in:
Peter Zaoral 2022-10-15 21:14:58 +02:00 committed by Václav Muzikář
parent 76d9125c3f
commit 4dfbb42680
8 changed files with 102 additions and 34 deletions

View file

@ -164,7 +164,7 @@ CONDITION: RollingUpdate
=== Accessing the Keycloak Deployment
The Keycloak deployment is, by default, exposed through a basic nginx ingress and it will be accessible through the provided hostname.
If the default ingress doesn't fit your use-case you can disable it by setting `disableDefaultIngress: true`:
If the default ingress doesn't fit your use-case, disable it by setting `ingress` spec with `enabled` property to `false` value:
[source,bash]
----
@ -175,7 +175,8 @@ metadata:
name: example-kc
spec:
...
disableDefaultIngress: true
ingress:
enabled: false
EOF
kubectl apply -f example-kc.yaml
----

View file

@ -21,6 +21,7 @@ import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusBuilder;
@ -42,7 +43,8 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
@Override
protected Optional<HasMetadata> getReconciledResource() {
if (keycloak.getSpec().isDisableDefaultIngress()) {
IngressSpec ingressSpec = keycloak.getSpec().getIngressSpec();
if (ingressSpec != null && !ingressSpec.isIngressEnabled()) {
if (existingIngress != null) {
deleteExistingIngress();
}
@ -121,9 +123,13 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
}
public void updateStatus(KeycloakStatusBuilder status) {
if (!keycloak.getSpec().isDisableDefaultIngress() && existingIngress == null) {
IngressSpec ingressSpec = keycloak.getSpec().getIngressSpec();
if (ingressSpec == null) {
ingressSpec = new IngressSpec();
ingressSpec.setIngressEnabled(true);
}
if (ingressSpec.isIngressEnabled() && existingIngress == null) {
status.addNotReadyMessage("No existing Keycloak Ingress found, waiting for creating a new one");
return;
}
}

View file

@ -25,6 +25,7 @@ import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.FeatureSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UnsupportedSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.TransactionsSpec;
import javax.validation.constraints.NotNull;
@ -54,14 +55,16 @@ public class KeycloakSpec {
@JsonPropertyDescription("In this section you can configure Keycloak features related to HTTP and HTTPS")
private HttpSpec httpSpec;
@JsonPropertyDescription("Disable the default ingress.")
private boolean disableDefaultIngress;
@JsonPropertyDescription(
"In this section you can configure podTemplate advanced features, not production-ready, and not supported settings.\n" +
"Use at your own risk and open an issue with your use-case if you don't find an alternative way.")
private UnsupportedSpec unsupported;
@JsonProperty("ingress")
@JsonPropertyDescription("The deployment is, by default, exposed through a basic ingress.\n" +
"You can change this behaviour by setting the enabled property to false.")
private IngressSpec ingressSpec;
@JsonProperty("features")
@JsonPropertyDescription("In this section you can configure Keycloak features, which should be enabled/disabled.")
private FeatureSpec featureSpec;
@ -91,14 +94,6 @@ public class KeycloakSpec {
this.httpSpec = httpSpec;
}
public void setDisableDefaultIngress(boolean value) {
this.disableDefaultIngress = value;
}
public boolean isDisableDefaultIngress() {
return this.disableDefaultIngress;
}
public UnsupportedSpec getUnsupported() {
return unsupported;
}
@ -123,6 +118,14 @@ public class KeycloakSpec {
this.transactionsSpec = transactionsSpec;
}
public IngressSpec getIngressSpec() {
return ingressSpec;
}
public void setIngressSpec(IngressSpec ingressSpec) {
this.ingressSpec = ingressSpec;
}
public int getInstances() {
return instances;
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.operator.crds.v2alpha1.deployment.spec;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.sundr.builder.annotations.Buildable;
@Buildable(editableEnabled = false, builderPackage = "io.fabric8.kubernetes.api.builder")
public class IngressSpec {
@JsonProperty("enabled")
private boolean enabled = true;
public boolean isIngressEnabled() {
return enabled;
}
public void setIngressEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View file

@ -24,6 +24,7 @@ import io.restassured.RestAssured;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;
import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.testsuite.utils.K8sUtils;
import org.keycloak.operator.controllers.KeycloakIngress;
@ -126,6 +127,8 @@ public class KeycloakIngressTest extends BaseOperatorTest {
@Test
public void testMainIngressDurability() {
var kc = K8sUtils.getDefaultKeycloakDeployment();
kc.getSpec().setIngressSpec(new IngressSpec());
kc.getSpec().getIngressSpec().setIngressEnabled(true);
K8sUtils.deployKeycloak(k8sclient, kc, true);
var ingress = new KeycloakIngress(k8sclient, kc);
@ -165,7 +168,7 @@ public class KeycloakIngressTest extends BaseOperatorTest {
});
// Delete the ingress
kc.getSpec().setDisableDefaultIngress(true);
kc.getSpec().getIngressSpec().setIngressEnabled(false);
K8sUtils.deployKeycloak(k8sclient, kc, true);
Awaitility.await()

View file

@ -29,7 +29,7 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class CRSerializationTest {
@ -40,7 +40,7 @@ public class CRSerializationTest {
assertEquals("my-hostname", keycloak.getSpec().getHostname());
assertEquals("my-image", keycloak.getSpec().getImage());
assertEquals("my-tls-secret", keycloak.getSpec().getHttpSpec().getTlsSecret());
assertTrue(keycloak.getSpec().isDisableDefaultIngress());
assertFalse(keycloak.getSpec().getIngressSpec().isIngressEnabled());
final TransactionsSpec transactionsSpec = keycloak.getSpec().getTransactionsSpec();
assertThat(transactionsSpec, notNullValue());

View file

@ -21,6 +21,7 @@ import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
import org.junit.jupiter.api.Test;
import org.keycloak.operator.controllers.KeycloakIngress;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.testsuite.utils.K8sUtils;
@ -31,21 +32,24 @@ public class IngressLogicTest {
static class MockKeycloakIngress extends KeycloakIngress {
private static Keycloak getKeycloak(boolean defaultIngressDisabled) {
private static Keycloak getKeycloak(Boolean defaultIngressEnabled, boolean ingressSpecDefined) {
var kc = K8sUtils.getDefaultKeycloakDeployment();
kc.getSpec().setDisableDefaultIngress(defaultIngressDisabled);
if (ingressSpecDefined) {
kc.getSpec().setIngressSpec(new IngressSpec());
if (defaultIngressEnabled != null) kc.getSpec().getIngressSpec().setIngressEnabled(defaultIngressEnabled);
}
return kc;
}
public static MockKeycloakIngress build(boolean defaultIngressDisabled, boolean ingressExists) {
public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined) {
MockKeycloakIngress.ingressExists = ingressExists;
return new MockKeycloakIngress(defaultIngressDisabled);
return new MockKeycloakIngress(defaultIngressEnabled, ingressSpecDefined);
}
public static boolean ingressExists = false;
private boolean deleted = false;
public MockKeycloakIngress(boolean defaultIngressDisabled) {
super(null, getKeycloak(defaultIngressDisabled));
public MockKeycloakIngress(Boolean defaultIngressEnabled, boolean ingressSpecDefined) {
super(null, getKeycloak(defaultIngressEnabled, ingressSpecDefined));
}
public boolean reconciled() {
@ -72,29 +76,43 @@ public class IngressLogicTest {
}
@Test
public void testIngressEnabledExisting() {
var kc = MockKeycloakIngress.build(true, true);
public void testIngressDisabledExisting() {
var kc = MockKeycloakIngress.build(false, true, true);
assertFalse(kc.reconciled());
assertTrue(kc.deleted());
}
@Test
public void testIngressEnabledNotExisting() {
var kc = MockKeycloakIngress.build(true, false);
public void testIngressDisabledNotExisting() {
var kc = MockKeycloakIngress.build(false, false, true);
assertFalse(kc.reconciled());
assertFalse(kc.deleted());
}
@Test
public void testIngressDisabledExisting() {
var kc = MockKeycloakIngress.build(false, true);
public void testIngressEnabledExisting() {
var kc = MockKeycloakIngress.build(true, true, true);
assertTrue(kc.reconciled());
assertFalse(kc.deleted());
}
@Test
public void testIngressDisabledNotExisting() {
var kc = MockKeycloakIngress.build(false, false);
public void testIngressEnabledNotExisting() {
var kc = MockKeycloakIngress.build(true, false, true);
assertTrue(kc.reconciled());
assertFalse(kc.deleted());
}
@Test
public void testIngressEnabledNotSpecified() {
var kc = MockKeycloakIngress.build(true, false, false);
assertTrue(kc.reconciled());
assertFalse(kc.deleted());
}
@Test
public void testIngressSpecDefinedWithoutProperty() {
var kc = MockKeycloakIngress.build(null, false, true);
assertTrue(kc.reconciled());
assertFalse(kc.deleted());
}

View file

@ -11,6 +11,8 @@ spec:
- name: features
value: docker
hostname: my-hostname
ingress:
enabled: false
http:
httpEnabled: true
httpPort: 123
@ -23,7 +25,6 @@ spec:
disabled:
- admin
- step-up-authentication
disableDefaultIngress: true
transaction:
xaEnabled: false
unsupported: