mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
fix: detecting when we can set the serviceName (#40894)
closes: #40890 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
parent
81a7f38a76
commit
919838089f
@ -151,14 +151,18 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
||||
|
||||
var existingDeployment = ContextUtils.getCurrentStatefulSet(context).orElse(null);
|
||||
|
||||
String serviceName = KeycloakDiscoveryServiceDependentResource.getName(primary);
|
||||
if (existingDeployment != null) {
|
||||
// copy the existing annotations to keep the status consistent
|
||||
CRDUtils.findUpdateReason(existingDeployment).ifPresent(r -> baseDeployment.getMetadata().getAnnotations()
|
||||
.put(Constants.KEYCLOAK_UPDATE_REASON_ANNOTATION, r));
|
||||
CRDUtils.fetchIsRecreateUpdate(existingDeployment).ifPresent(b -> baseDeployment.getMetadata()
|
||||
.getAnnotations().put(Constants.KEYCLOAK_RECREATE_UPDATE_ANNOTATION, b.toString()));
|
||||
serviceName = existingDeployment.getSpec().getServiceName();
|
||||
}
|
||||
|
||||
baseDeployment.getSpec().setServiceName(serviceName);
|
||||
|
||||
var updateType = ContextUtils.getUpdateType(context);
|
||||
|
||||
if (existingDeployment == null || updateType.isEmpty()) {
|
||||
@ -287,7 +291,6 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
||||
.editOrNewSpec().withImagePullSecrets(keycloakCR.getSpec().getImagePullSecrets()).endSpec()
|
||||
.endTemplate()
|
||||
.withReplicas(keycloakCR.getSpec().getInstances())
|
||||
.withServiceName(KeycloakDiscoveryServiceDependentResource.getName(keycloakCR))
|
||||
.endSpec();
|
||||
|
||||
var specBuilder = baseDeploymentBuilder.editSpec().editTemplate().editOrNewSpec();
|
||||
|
||||
@ -47,7 +47,6 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.BootstrapAdminSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.ProbeSpec;
|
||||
import org.keycloak.operator.testsuite.apiserver.DisabledIfApiServerTest;
|
||||
import org.keycloak.operator.testsuite.unit.WatchedResourcesTest;
|
||||
import org.keycloak.operator.testsuite.utils.CRAssert;
|
||||
@ -213,6 +212,7 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
|
||||
@Test
|
||||
public void testDeploymentDurability() {
|
||||
var kc = getTestKeycloakDeployment(true);
|
||||
KeycloakDeploymentTest.initCustomBootstrapAdminUser(kc);
|
||||
var deploymentName = kc.getMetadata().getName();
|
||||
|
||||
// create a dummy StatefulSet representing the pre-multiinstance state that we'll be forced to delete
|
||||
@ -395,14 +395,19 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
|
||||
@Test
|
||||
public void testCustomBootstrapAdminUser() {
|
||||
var kc = getTestKeycloakDeployment(true);
|
||||
String secretName = initCustomBootstrapAdminUser(kc);
|
||||
assertInitialAdminUser(secretName, kc, true);
|
||||
}
|
||||
|
||||
static String initCustomBootstrapAdminUser(Keycloak kc) {
|
||||
String secretName = "my-secret";
|
||||
// fluents don't seem to work here because of the inner classes
|
||||
kc.getSpec().setBootstrapAdminSpec(new BootstrapAdminSpec());
|
||||
kc.getSpec().getBootstrapAdminSpec().setUser(new BootstrapAdminSpec.User());
|
||||
kc.getSpec().getBootstrapAdminSpec().getUser().setSecret(secretName);
|
||||
k8sclient.resource(new SecretBuilder().withNewMetadata().withName(secretName).endMetadata()
|
||||
.addToStringData("username", "user").addToStringData("password", "pass20rd").build()).create();
|
||||
assertInitialAdminUser(secretName, kc, true);
|
||||
.addToStringData("username", "user").addToStringData("password", "pass20rd").build()).serverSideApply();
|
||||
return secretName;
|
||||
}
|
||||
|
||||
// Reference curl command:
|
||||
|
||||
@ -22,6 +22,8 @@ import io.fabric8.kubernetes.api.model.LocalObjectReferenceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Secret;
|
||||
import io.fabric8.kubernetes.api.model.apps.StatefulSet;
|
||||
import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder;
|
||||
import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
import io.fabric8.kubernetes.client.utils.Serialization;
|
||||
import io.quarkus.logging.Log;
|
||||
@ -29,16 +31,20 @@ import io.quarkus.test.junit.QuarkusTest;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.operator.Utils;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
import org.keycloak.operator.testsuite.apiserver.DisabledIfApiServerTest;
|
||||
import org.keycloak.operator.testsuite.utils.CRAssert;
|
||||
import org.keycloak.operator.testsuite.utils.K8sUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition.HAS_ERRORS;
|
||||
import static org.keycloak.operator.testsuite.utils.K8sUtils.deployKeycloak;
|
||||
import static org.keycloak.operator.testsuite.utils.K8sUtils.getResourceFromFile;
|
||||
|
||||
@QuarkusTest
|
||||
@ -229,4 +235,31 @@ public class PodTemplateTest extends BaseOperatorTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeploymentUpgrade() {
|
||||
var kc = getTestKeycloakDeployment(true);
|
||||
kc.getSpec().setInstances(2);
|
||||
// all preconditions must be met, otherwise the operator sdk will remove the existing statefulset
|
||||
KeycloakDeploymentTest.initCustomBootstrapAdminUser(kc);
|
||||
|
||||
// create a dummy StatefulSet representing the 26.0 state that we'll be forced to delete
|
||||
StatefulSet statefulSet = new StatefulSetBuilder().withMetadata(kc.getMetadata()).editMetadata()
|
||||
.addToLabels(Utils.allInstanceLabels(kc)).endMetadata().withNewSpec().withNewSelector()
|
||||
.withMatchLabels(Utils.allInstanceLabels(kc)).endSelector().withReplicas(0)
|
||||
.withNewTemplate().withNewMetadata().withLabels(Utils.allInstanceLabels(kc)).endMetadata()
|
||||
.withNewSpec().addNewContainer().withName("pause").withImage("registry.k8s.io/pause:3.1")
|
||||
.endContainer().endSpec().endTemplate().endSpec().build();
|
||||
var ss = k8sclient.resource(statefulSet).create();
|
||||
|
||||
// start will not be successful because the statefulSet is in the way
|
||||
deployKeycloak(k8sclient, kc, false);
|
||||
// once the statefulset is owned by the keycloak it will be picked up by the informer
|
||||
k8sclient.resource(statefulSet).accept(s -> s.addOwnerReference(k8sclient.resource(kc).get()));
|
||||
|
||||
Awaitility.await().atMost(1, TimeUnit.MINUTES).until(() -> k8sclient.resource(statefulSet).get().getSpec().getReplicas() == 2);
|
||||
|
||||
// we don't expect a recreate - that would indicate the operator sdk saw a precondition failing
|
||||
assertEquals(ss.getMetadata().getUid(), k8sclient.resource(statefulSet).get().getMetadata().getUid());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user