+
Skip to content

fix: detecting when we can set the serviceName (#40894) #40943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,18 @@ public StatefulSet desired(Keycloak primary, Context<Keycloak> context) {

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()) {
Expand Down Expand Up @@ -287,7 +291,6 @@ private StatefulSet createBaseDeployment(Keycloak keycloakCR, Context<Keycloak>
.editOrNewSpec().withImagePullSecrets(keycloakCR.getSpec().getImagePullSecrets()).endSpec()
.endTemplate()
.withReplicas(keycloakCR.getSpec().getInstances())
.withServiceName(KeycloakDiscoveryServiceDependentResource.getName(keycloakCR))
.endSpec();

var specBuilder = baseDeploymentBuilder.editSpec().editTemplate().editOrNewSpec();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
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;
Expand Down Expand Up @@ -213,6 +212,7 @@ public void testConfigInCRTakesPrecedence() {
@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
Expand Down Expand Up @@ -395,14 +395,19 @@ public void testInitialAdminUser() {
@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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,29 @@
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;
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
Expand Down Expand Up @@ -229,4 +235,31 @@ public void testPodTemplateIncorrectImagePullSecretsConfig() {
});
}

@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
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载