Make sure the customized Ingress resource isn't deleted when the Keycloak deployed by Operator is killed.
Closes #14433
This commit is contained in:
parent
a64f6dcfc2
commit
cb78ea06b0
3 changed files with 115 additions and 2 deletions
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue