changes condition status to be a string, rather than a boolean
Closes #13074
This commit is contained in:
parent
4540ca365c
commit
5701f70157
9 changed files with 169 additions and 132 deletions
|
@ -86,6 +86,10 @@ The previous and now removed WildFly distribution provided a built-in vault prov
|
||||||
|
|
||||||
In relation to the KeyStore Vault news, we also integrated Quarkus's recently released feature called KeyStore Config Source. This means that among the already existing configuration sources (CLI parameters, environment variables and files), you can now configure your Keycloak server via configuration properties stored in a Java keystore file. You can learn more about this feature in the https://www.keycloak.org/server/configuration[Configuration guide].
|
In relation to the KeyStore Vault news, we also integrated Quarkus's recently released feature called KeyStore Config Source. This means that among the already existing configuration sources (CLI parameters, environment variables and files), you can now configure your Keycloak server via configuration properties stored in a Java keystore file. You can learn more about this feature in the https://www.keycloak.org/server/configuration[Configuration guide].
|
||||||
|
|
||||||
|
= k8s.keycloak.org/v2alpha1 changes
|
||||||
|
|
||||||
|
The are additional fields available in the keycloak.status to facilitate keycloak being a scalable resource. There are also additional fields that make the status easier to interpret such as observedGeneration and condition observedGeneration and lastTransitionTime fields. However the condition status field was also changed from a boolean to a string for conformance with standard Kubernetes conditions. Please make sure any of your usage of this field is updated to expect the values "True", "False", or "Unknown", rather than true or false.
|
||||||
|
|
||||||
= Account Console v3 promoted to preview
|
= Account Console v3 promoted to preview
|
||||||
|
|
||||||
In version 21.1.0 of Keycloak the new Account Console (version 3) was introduced as an experimental feature. Starting this version it has been promoted to a preview feature.
|
In version 21.1.0 of Keycloak the new Account Console (version 3) was introduced as an experimental feature. Starting this version it has been promoted to a preview feature.
|
||||||
|
|
|
@ -3,7 +3,7 @@ set -euxo pipefail
|
||||||
|
|
||||||
max_retries=500
|
max_retries=500
|
||||||
c=0
|
c=0
|
||||||
while [[ $(kubectl get keycloaks/example-kc -o jsonpath="{.status.conditions[?(@.type == 'Ready')].status}") != "true" ]]
|
while [[ $(kubectl get keycloaks/example-kc -o jsonpath="{.status.conditions[?(@.type == 'Ready')].status}") != "True" ]]
|
||||||
do
|
do
|
||||||
echo "waiting for Keycloak example-kc status"
|
echo "waiting for Keycloak example-kc status"
|
||||||
((c++)) && ((c==max_retries)) && exit -1
|
((c++)) && ((c==max_retries)) && exit -1
|
||||||
|
@ -11,7 +11,7 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
c=0
|
c=0
|
||||||
while [[ $(kubectl get keycloakrealmimports/example-count0-kc -o jsonpath="{.status.conditions[?(@.type == 'Done')].status}") != "true" ]]
|
while [[ $(kubectl get keycloakrealmimports/example-count0-kc -o jsonpath="{.status.conditions[?(@.type == 'Done')].status}") != "True" ]]
|
||||||
do
|
do
|
||||||
echo "waiting for Keycloak Realm Import example-count0-kc status"
|
echo "waiting for Keycloak Realm Import example-count0-kc status"
|
||||||
((c++)) && ((c==max_retries)) && exit -1
|
((c++)) && ((c==max_retries)) && exit -1
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class KeycloakRealmImportController implements Reconciler<KeycloakRealmIm
|
||||||
if (status
|
if (status
|
||||||
.getConditions()
|
.getConditions()
|
||||||
.stream()
|
.stream()
|
||||||
.anyMatch(c -> c.getType().equals(KeycloakRealmImportStatusCondition.DONE) && !c.getStatus())) {
|
.anyMatch(c -> c.getType().equals(KeycloakRealmImportStatusCondition.DONE) && !Boolean.TRUE.equals(c.getStatus()))) {
|
||||||
updateControl.rescheduleAfter(10, TimeUnit.SECONDS);
|
updateControl.rescheduleAfter(10, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.operator.crds.v2alpha1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class StatusCondition {
|
||||||
|
public enum Status {
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
private String status = Status.Unknown.name();
|
||||||
|
private String message;
|
||||||
|
private String lastTransitionTime;
|
||||||
|
private Long observedGeneration;
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Boolean getStatus() {
|
||||||
|
if (status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// account for the legacy boolean string as well
|
||||||
|
switch (status) {
|
||||||
|
case "false":
|
||||||
|
case "False":
|
||||||
|
return false;
|
||||||
|
case "true":
|
||||||
|
case "True":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("status")
|
||||||
|
public String getStatusString() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("status")
|
||||||
|
public void setStatusString(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public void setStatus(Boolean status) {
|
||||||
|
if (status == null) {
|
||||||
|
this.status = Status.Unknown.name();
|
||||||
|
} else if (status) {
|
||||||
|
this.status = Status.True.name();
|
||||||
|
} else {
|
||||||
|
this.status = Status.False.name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastTransitionTime() {
|
||||||
|
return lastTransitionTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastTransitionTime(String lastTransitionTime) {
|
||||||
|
this.lastTransitionTime = lastTransitionTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getObservedGeneration() {
|
||||||
|
return observedGeneration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObservedGeneration(Long observedGeneration) {
|
||||||
|
this.observedGeneration = observedGeneration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
StatusCondition that = (StatusCondition) o;
|
||||||
|
return Objects.equals(getType(), that.getType()) && Objects.equals(getStatus(), that.getStatus()) && Objects.equals(getMessage(), that.getMessage())
|
||||||
|
&& Objects.equals(getLastTransitionTime(), that.getLastTransitionTime())
|
||||||
|
&& Objects.equals(getObservedGeneration(), that.getObservedGeneration());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getType(), getStatus(), getMessage(), getObservedGeneration(), getLastTransitionTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "{" +
|
||||||
|
"type='" + type + '\'' +
|
||||||
|
", status=" + status +
|
||||||
|
", message='" + message + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,84 +17,13 @@
|
||||||
|
|
||||||
package org.keycloak.operator.crds.v2alpha1.deployment;
|
package org.keycloak.operator.crds.v2alpha1.deployment;
|
||||||
|
|
||||||
import java.util.Objects;
|
import org.keycloak.operator.crds.v2alpha1.StatusCondition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
*/
|
*/
|
||||||
public class KeycloakStatusCondition {
|
public class KeycloakStatusCondition extends StatusCondition {
|
||||||
public static final String READY = "Ready";
|
public static final String READY = "Ready";
|
||||||
public static final String HAS_ERRORS = "HasErrors";
|
public static final String HAS_ERRORS = "HasErrors";
|
||||||
public static final String ROLLING_UPDATE = "RollingUpdate";
|
public static final String ROLLING_UPDATE = "RollingUpdate";
|
||||||
|
|
||||||
// string to avoid enums in CRDs
|
|
||||||
private String type;
|
|
||||||
private Boolean status;
|
|
||||||
private String message;
|
|
||||||
private String lastTransitionTime;
|
|
||||||
private Long observedGeneration;
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(String type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(Boolean status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastTransitionTime() {
|
|
||||||
return lastTransitionTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastTransitionTime(String lastTransitionTime) {
|
|
||||||
this.lastTransitionTime = lastTransitionTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getObservedGeneration() {
|
|
||||||
return observedGeneration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObservedGeneration(Long observedGeneration) {
|
|
||||||
this.observedGeneration = observedGeneration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
KeycloakStatusCondition that = (KeycloakStatusCondition) o;
|
|
||||||
return Objects.equals(getType(), that.getType()) && Objects.equals(getStatus(), that.getStatus()) && Objects.equals(getMessage(), that.getMessage())
|
|
||||||
&& Objects.equals(getLastTransitionTime(), that.getLastTransitionTime())
|
|
||||||
&& Objects.equals(getObservedGeneration(), that.getObservedGeneration());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(getType(), getStatus(), getMessage(), getObservedGeneration(), getLastTransitionTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "KeycloakStatusCondition{" +
|
|
||||||
"type='" + type + '\'' +
|
|
||||||
", status=" + status +
|
|
||||||
", message='" + message + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class KeycloakRealmImportStatus {
|
||||||
public boolean isDone() {
|
public boolean isDone() {
|
||||||
return conditions
|
return conditions
|
||||||
.stream()
|
.stream()
|
||||||
.anyMatch(c -> c.getStatus() && c.getType().equals(DONE));
|
.anyMatch(c -> Boolean.TRUE.equals(c.getStatus()) && c.getType().equals(DONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,61 +17,10 @@
|
||||||
|
|
||||||
package org.keycloak.operator.crds.v2alpha1.realmimport;
|
package org.keycloak.operator.crds.v2alpha1.realmimport;
|
||||||
|
|
||||||
import java.util.Objects;
|
import org.keycloak.operator.crds.v2alpha1.StatusCondition;
|
||||||
|
|
||||||
public class KeycloakRealmImportStatusCondition {
|
public class KeycloakRealmImportStatusCondition extends StatusCondition {
|
||||||
public static final String DONE = "Done";
|
public static final String DONE = "Done";
|
||||||
public static final String STARTED = "Started";
|
public static final String STARTED = "Started";
|
||||||
public static final String HAS_ERRORS = "HasErrors";
|
public static final String HAS_ERRORS = "HasErrors";
|
||||||
|
|
||||||
// string to avoid enums in CRDs
|
|
||||||
private String type;
|
|
||||||
private Boolean status;
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(String type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(Boolean status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
KeycloakRealmImportStatusCondition that = (KeycloakRealmImportStatusCondition) o;
|
|
||||||
return getType() == that.getType() && Objects.equals(getStatus(), that.getStatus()) && Objects.equals(getMessage(), that.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(getType(), getStatus(), getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "KeycloakRealmImportStatusCondition{" +
|
|
||||||
"type='" + type + '\'' +
|
|
||||||
", status=" + status +
|
|
||||||
", message='" + message + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.operator.testsuite.unit;
|
package org.keycloak.operator.testsuite.unit;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.client.utils.Serialization;
|
||||||
|
|
||||||
import org.assertj.core.api.Condition;
|
import org.assertj.core.api.Condition;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
|
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
|
||||||
|
@ -25,6 +27,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
||||||
import org.keycloak.operator.testsuite.utils.CRAssert;
|
import org.keycloak.operator.testsuite.utils.CRAssert;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
|
||||||
public class KeycloakStatusTest {
|
public class KeycloakStatusTest {
|
||||||
|
@ -137,4 +140,16 @@ public class KeycloakStatusTest {
|
||||||
assertEquals(3, status.getInstances());
|
assertEquals(3, status.getInstances());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStatusSerializtion() {
|
||||||
|
KeycloakStatusCondition condition = new KeycloakStatusCondition();
|
||||||
|
condition.setStatus(false);
|
||||||
|
|
||||||
|
String yaml = Serialization.asYaml(condition);
|
||||||
|
assertEquals("---\nstatus: \"False\"\n", yaml);
|
||||||
|
|
||||||
|
var deserialized = Serialization.unmarshal(yaml, KeycloakStatusCondition.class);
|
||||||
|
assertFalse(deserialized.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
|
||||||
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
||||||
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
|
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,8 +72,8 @@ public final class CRAssert {
|
||||||
.noneMatch(c -> c.getMessage().contains(message));
|
.noneMatch(c -> c.getMessage().contains(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertKeycloakRealmImportStatusCondition(KeycloakRealmImport kri, String condition, boolean status) {
|
public static void assertKeycloakRealmImportStatusCondition(KeycloakRealmImport kri, String condition, Boolean status) {
|
||||||
assertThat(kri.getStatus().getConditions())
|
assertThat(kri.getStatus().getConditions())
|
||||||
.anyMatch(c -> c.getType().equals(condition) && c.getStatus() == status);
|
.anyMatch(c -> c.getType().equals(condition) && Objects.equals(c.getStatus(), status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue