allows normal reconciliation to continue even if secrets are not present (#22404)
* allows normal reconciliation to continue even if secrets are not present Closes #22170 * adds polling if any secret (in particular optional) is not present Closes #22170
This commit is contained in:
parent
166e2e4c91
commit
ffc6bc497a
5 changed files with 30 additions and 4 deletions
|
@ -38,6 +38,7 @@ public final class Constants {
|
|||
public static final String KEYCLOAK_COMPONENT_LABEL = "operator.keycloak.org/component";
|
||||
public static final String KEYCLOAK_WATCHED_SECRET_HASH_ANNOTATION = "operator.keycloak.org/watched-secret-hash";
|
||||
public static final String KEYCLOAK_WATCHING_ANNOTATION = "operator.keycloak.org/watching-secrets";
|
||||
public static final String KEYCLOAK_MISSING_SECRETS_ANNOTATION = "operator.keycloak.org/missing-secrets";
|
||||
|
||||
public static final String DEFAULT_LABELS_AS_STRING = "app=keycloak,app.kubernetes.io/managed-by=keycloak-operator";
|
||||
|
||||
|
|
|
@ -130,7 +130,9 @@ public class KeycloakController implements Reconciler<Keycloak>, EventSourceInit
|
|||
updateControl = UpdateControl.updateStatus(kc);
|
||||
}
|
||||
|
||||
if (!status.isReady()) {
|
||||
if (!status.isReady() || context.getSecondaryResource(StatefulSet.class)
|
||||
.map(s -> s.getMetadata().getAnnotations().get(Constants.KEYCLOAK_MISSING_SECRETS_ANNOTATION))
|
||||
.filter(Boolean::valueOf).isPresent()) {
|
||||
updateControl.rescheduleAfter(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -103,6 +104,8 @@ public class WatchedSecretsController implements Reconciler<Secret>, EventSource
|
|||
@Override
|
||||
public void annotateDeployment(List<String> desiredWatchedSecretsNames, Keycloak keycloakCR, StatefulSet deployment) {
|
||||
List<Secret> currentSecrets = fetchSecrets(desiredWatchedSecretsNames, keycloakCR.getMetadata().getNamespace());
|
||||
deployment.getMetadata().getAnnotations().put(Constants.KEYCLOAK_MISSING_SECRETS_ANNOTATION,
|
||||
Boolean.valueOf(currentSecrets.size() < desiredWatchedSecretsNames.size()).toString());
|
||||
deployment.getMetadata().getAnnotations().put(Constants.KEYCLOAK_WATCHING_ANNOTATION, desiredWatchedSecretsNames.stream().collect(Collectors.joining(";")));
|
||||
deployment.getSpec().getTemplate().getMetadata().getAnnotations().put(Constants.KEYCLOAK_WATCHED_SECRET_HASH_ANNOTATION, getSecretHash(currentSecrets));
|
||||
}
|
||||
|
@ -110,7 +113,8 @@ public class WatchedSecretsController implements Reconciler<Secret>, EventSource
|
|||
private List<Secret> fetchSecrets(List<String> secretsNames, String namespace) {
|
||||
return secretsNames.stream()
|
||||
.map(n -> Optional.ofNullable(secrets).flatMap(cache -> cache.get(new ResourceID(n, namespace)))
|
||||
.orElseGet(() -> client.secrets().inNamespace(namespace).withName(n).require()))
|
||||
.orElseGet(() -> client.secrets().inNamespace(namespace).withName(n).get()))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import io.fabric8.kubernetes.api.model.ServicePort;
|
|||
import io.fabric8.kubernetes.api.model.apps.StatefulSet;
|
||||
import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder;
|
||||
import io.fabric8.kubernetes.api.model.apps.StatefulSetSpecBuilder;
|
||||
import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
import io.quarkus.logging.Log;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
|
||||
|
@ -94,6 +95,26 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
|
|||
.untilAsserted(() -> assertThat(k8sclient.apps().statefulSets().inNamespace(namespace).withName(deploymentName).get()).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeycloakDeploymentBeforeSecret() {
|
||||
// CR
|
||||
var kc = getTestKeycloakDeployment(true);
|
||||
var deploymentName = kc.getMetadata().getName();
|
||||
deployKeycloak(k8sclient, kc, false, false);
|
||||
|
||||
// Check Operator has deployed Keycloak and the statefulset exists, this allows for the watched secret to be picked up
|
||||
Log.info("Checking Operator has deployed Keycloak deployment");
|
||||
Resource<StatefulSet> stsResource = k8sclient.resources(StatefulSet.class).withName(deploymentName);
|
||||
Resource<Keycloak> keycloakResource = k8sclient.resources(Keycloak.class).withName(deploymentName);
|
||||
// expect no errors and not ready, which means we'll keep reconciling
|
||||
Awaitility.await().untilAsserted(() -> {
|
||||
assertThat(stsResource.get()).isNotNull();
|
||||
Keycloak keycloak = keycloakResource.get();
|
||||
CRAssert.assertKeycloakStatusCondition(keycloak, KeycloakStatusCondition.HAS_ERRORS, false);
|
||||
CRAssert.assertKeycloakStatusCondition(keycloak, KeycloakStatusCondition.READY, false);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCRFields() {
|
||||
var kc = getTestKeycloakDeployment(true);
|
||||
|
|
|
@ -87,8 +87,6 @@ public class WatchedSecretsTest extends BaseOperatorTest {
|
|||
var kc = getTestKeycloakDeployment(false);
|
||||
deployKeycloak(k8sclient, kc, true);
|
||||
|
||||
var prevRevision = getStatefulSet(kc).getStatus().getUpdateRevision();
|
||||
|
||||
var dbSecret = getDbSecret();
|
||||
|
||||
dbSecret.getData().put("username",
|
||||
|
|
Loading…
Reference in a new issue