Make sure the customized Ingress resource isn't deleted when the Keycloak deployed by Operator is killed.

Closes #14433
This commit is contained in:
Andre Nascimento 2023-02-07 17:58:22 +01:00 committed by Václav Muzikář
parent a64f6dcfc2
commit cb78ea06b0
3 changed files with 115 additions and 2 deletions

View file

@ -45,7 +45,7 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
protected Optional<HasMetadata> getReconciledResource() {
IngressSpec ingressSpec = keycloak.getSpec().getIngressSpec();
if (ingressSpec != null && !ingressSpec.isIngressEnabled()) {
if (existingIngress != null) {
if (existingIngress != null && isExistingIngressFromSameOwnerReference()) {
deleteExistingIngress();
}
return Optional.empty();
@ -114,6 +114,16 @@ public class KeycloakIngress extends OperatorManagedResource implements StatusUp
client.network().v1().ingresses().inNamespace(getNamespace()).delete(existingIngress);
}
private boolean isExistingIngressFromSameOwnerReference() {
return existingIngress
.getMetadata()
.getOwnerReferences()
.stream()
.anyMatch(oneOwnerRef -> oneOwnerRef.getUid().equalsIgnoreCase(keycloak.getMetadata().getUid()));
}
protected Ingress fetchExistingIngress() {
return client
.network()

View file

@ -17,13 +17,17 @@
package org.keycloak.operator.testsuite.integration;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
import io.fabric8.kubernetes.api.model.networking.v1.ServiceBackendPortBuilder;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.quarkus.logging.Log;
import io.quarkus.test.junit.QuarkusTest;
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.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
import org.keycloak.operator.testsuite.utils.K8sUtils;
@ -31,6 +35,7 @@ import org.keycloak.operator.controllers.KeycloakIngress;
import java.util.Map;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -188,4 +193,81 @@ public class KeycloakIngressTest extends BaseOperatorTest {
assertThat(k8sclient.network().v1().ingresses().inNamespace(namespace).list().getItems().size()).isEqualTo(0);
});
}
@Test
public void testCustomIngressDeletion() {
Keycloak defaultKeycloakDeployment = K8sUtils.getDefaultKeycloakDeployment();
String kcDeploymentName = defaultKeycloakDeployment.getMetadata().getName();
Resource<Ingress> customIngressDeployedManuallySelector = null;
Ingress customIngressCreatedManually;
try {
customIngressCreatedManually = createCustomIngress(kcDeploymentName, namespace, 8443);
customIngressDeployedManuallySelector = k8sclient
.network()
.v1()
.ingresses()
.inNamespace(namespace)
.withName(customIngressCreatedManually.getMetadata().getName());
Awaitility.await().atMost(1, MINUTES).untilAsserted(() -> {
assertThat(k8sclient.network().v1().ingresses().inNamespace(namespace).list().getItems().size()).isEqualTo(1);
});
Log.info("Redeploying the Keycloak CR with default Ingress disabled");
defaultKeycloakDeployment.getSpec().setIngressSpec(new IngressSpec());
defaultKeycloakDeployment.getSpec().getIngressSpec().setIngressEnabled(false);
K8sUtils.deployKeycloak(k8sclient, defaultKeycloakDeployment, true);
Awaitility.await().untilAsserted(() -> {
Log.info("Make sure the Custom Ingress still remains");
assertThat(k8sclient.network().v1().ingresses().inNamespace(namespace).list().getItems().size()).isEqualTo(1);
});
} catch (Exception e) {
savePodLogs();
throw e;
} finally {
Log.info("Destroying the Custom Ingress created manually to avoid errors in others Tests methods");
if (customIngressDeployedManuallySelector != null && customIngressDeployedManuallySelector.isReady()) {
assertThat(customIngressDeployedManuallySelector.delete()).isTrue();
Awaitility.await().untilAsserted(() -> {
assertThat(k8sclient.network().v1().ingresses().inNamespace(namespace).list().getItems().size()).isEqualTo(0);
});
}
}
}
private Ingress createCustomIngress(String baseResourceName, String targetNamespace, int portNumber) {
Ingress customIngressCreated;
customIngressCreated = new IngressBuilder()
.withNewMetadata()
.withName(baseResourceName + Constants.KEYCLOAK_INGRESS_SUFFIX)
.withNamespace(targetNamespace)
.addToAnnotations("nginx.ingress.kubernetes.io/backend-protocol", "HTTPS")
.addToAnnotations("route.openshift.io/termination", "passthrough")
.endMetadata()
.withNewSpec()
.withNewDefaultBackend()
.withNewService()
.withName(baseResourceName + Constants.KEYCLOAK_SERVICE_SUFFIX)
.withNewPort()
.withNumber(portNumber)
.endPort()
.endService()
.endDefaultBackend()
.endSpec()
.build();
customIngressCreated = k8sclient.network().v1().ingresses().inNamespace(targetNamespace).create(customIngressCreated);
return customIngressCreated;
}
}

View file

@ -17,9 +17,13 @@
package org.keycloak.operator.testsuite.unit;
import java.util.Collections;
import java.util.Optional;
import io.fabric8.kubernetes.api.model.OwnerReference;
import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder;
import org.junit.jupiter.api.Test;
import org.keycloak.operator.Constants;
import org.keycloak.operator.controllers.KeycloakIngress;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
@ -39,6 +43,7 @@ public class IngressLogicTest {
private static Keycloak getKeycloak(Boolean defaultIngressEnabled, boolean ingressSpecDefined, boolean tlsConfigured) {
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);
@ -80,7 +85,23 @@ public class IngressLogicTest {
@Override
protected Ingress fetchExistingIngress() {
if (ingressExists) {
return new IngressBuilder().withNewMetadata().endMetadata().build();
OwnerReference sameCROwnerRef = new OwnerReferenceBuilder()
.withApiVersion(cr.getApiVersion())
.withKind(cr.getKind())
.withName(cr.getMetadata().getName())
.withUid(cr.getMetadata().getUid())
.withBlockOwnerDeletion(true)
.withController(true)
.build();
return new IngressBuilder()
.withNewMetadata()
.withName(getName())
.withNamespace(cr.getMetadata().getNamespace())
.withOwnerReferences(Collections.singletonList(sameCROwnerRef))
.endMetadata()
.build();
} else {
return null;
}