Skip to content

Commit

Permalink
Merge pull request #143 from recht/alltrue
Browse files Browse the repository at this point in the history
  • Loading branch information
phisco authored Dec 10, 2023
2 parents c4761ba + e77639e commit f89244d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 1 deletion.
6 changes: 5 additions & 1 deletion apis/object/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ const (
// ReadinessPolicyDeriveFromObject means the object is marked as ready if and only if the underlying
// external resource is considered ready.
ReadinessPolicyDeriveFromObject ReadinessPolicy = "DeriveFromObject"

// ReadinessPolicyAllTrue means that all conditions have status true on the object.
// There must be at least one condition.
ReadinessPolicyAllTrue ReadinessPolicy = "AllTrue"
)

// Readiness defines how the object's readiness condition should be computed,
Expand All @@ -144,7 +148,7 @@ const (
type Readiness struct {
// Policy defines how the Object's readiness condition should be computed.
// +optional
// +kubebuilder:validation:Enum=SuccessfulCreate;DeriveFromObject
// +kubebuilder:validation:Enum=SuccessfulCreate;DeriveFromObject;AllTrue
// +kubebuilder:default=SuccessfulCreate
Policy ReadinessPolicy `json:"policy,omitempty"`
}
Expand Down
20 changes: 20 additions & 0 deletions internal/controller/object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,26 @@ func (c *external) updateConditionFromObserved(obj *v1alpha1.Object, observed *u
return nil
}
obj.SetConditions(xpv1.Available())
case v1alpha1.ReadinessPolicyAllTrue:
conditioned := xpv1.ConditionedStatus{}
err := fieldpath.Pave(observed.Object).GetValueInto("status", &conditioned)
if err != nil {
c.logger.Debug("Got error while getting conditions from observed object, setting it as Unavailable", "error", err, "observed", observed)
obj.SetConditions(xpv1.Unavailable())
return nil
}
allTrue := len(conditioned.Conditions) > 0
for _, condition := range conditioned.Conditions {
if condition.Status != v1.ConditionTrue {
allTrue = false
break
}
}
if allTrue {
obj.SetConditions(xpv1.Available())
} else {
obj.SetConditions(xpv1.Unavailable())
}
case v1alpha1.ReadinessPolicySuccessfulCreate, "":
// do nothing, will be handled by c.handleLastApplied method
// "" should never happen, but just in case we will treat it as SuccessfulCreate for backward compatibility
Expand Down
122 changes: 122 additions & 0 deletions internal/controller/object/object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1809,6 +1809,128 @@ func Test_updateConditionFromObserved(t *testing.T) {
},
},
},
"UnavailableIfAllTrueWithoutConditions": {
args: args{
obj: &v1alpha1.Object{
Spec: v1alpha1.ObjectSpec{
Readiness: v1alpha1.Readiness{
Policy: v1alpha1.ReadinessPolicyAllTrue,
},
},
},
observed: &unstructured.Unstructured{
Object: map[string]interface{}{
"status": xpv1.ConditionedStatus{},
},
},
},
want: want{
conditions: []xpv1.Condition{
{
Type: xpv1.TypeReady,
Status: corev1.ConditionFalse,
Reason: xpv1.ReasonUnavailable,
},
},
},
},
"UnavailableIfAllTrueAndCantParse": {
args: args{
obj: &v1alpha1.Object{
Spec: v1alpha1.ObjectSpec{
Readiness: v1alpha1.Readiness{
Policy: v1alpha1.ReadinessPolicyAllTrue,
},
},
},
observed: &unstructured.Unstructured{
Object: map[string]interface{}{
"status": "not a conditioned status",
},
},
},
want: want{
conditions: []xpv1.Condition{
{
Type: xpv1.TypeReady,
Status: corev1.ConditionFalse,
Reason: xpv1.ReasonUnavailable,
},
},
},
},
"UnavailableIfAllTrueAndAnyConditionFalse": {
args: args{
obj: &v1alpha1.Object{
Spec: v1alpha1.ObjectSpec{
Readiness: v1alpha1.Readiness{
Policy: v1alpha1.ReadinessPolicyAllTrue,
},
},
},
observed: &unstructured.Unstructured{
Object: map[string]interface{}{
"status": xpv1.ConditionedStatus{
Conditions: []xpv1.Condition{
{
Type: "condition1",
Status: corev1.ConditionFalse,
},
{
Type: xpv1.TypeReady,
Status: corev1.ConditionTrue,
},
},
},
},
},
},
want: want{
conditions: []xpv1.Condition{
{
Type: xpv1.TypeReady,
Status: corev1.ConditionFalse,
Reason: xpv1.ReasonUnavailable,
},
},
},
},
"AvailableIfAllTrueAndAllConditionsTrue": {
args: args{
obj: &v1alpha1.Object{
Spec: v1alpha1.ObjectSpec{
Readiness: v1alpha1.Readiness{
Policy: v1alpha1.ReadinessPolicyAllTrue,
},
},
},
observed: &unstructured.Unstructured{
Object: map[string]interface{}{
"status": xpv1.ConditionedStatus{
Conditions: []xpv1.Condition{
{
Type: "condition1",
Status: corev1.ConditionTrue,
},
{
Type: xpv1.TypeReady,
Status: corev1.ConditionTrue,
},
},
},
},
},
},
want: want{
conditions: []xpv1.Condition{
{
Type: xpv1.TypeReady,
Status: corev1.ConditionTrue,
Reason: xpv1.ReasonAvailable,
},
},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions package/crds/kubernetes.crossplane.io_objects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ spec:
enum:
- SuccessfulCreate
- DeriveFromObject
- AllTrue
type: string
type: object
references:
Expand Down

0 comments on commit f89244d

Please sign in to comment.