Skip to content

Commit

Permalink
Status condition from unstructured object
Browse files Browse the repository at this point in the history
  • Loading branch information
jigisha620 committed Jun 14, 2024
1 parent 85fe6a9 commit e1c5851
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
62 changes: 62 additions & 0 deletions status/condition_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ package status

import (
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/json"
"reflect"
"sort"
"strconv"
"strings"

"github.com/samber/lo"
Expand Down Expand Up @@ -237,3 +240,62 @@ func (c ConditionSet) findUnhealthyDependents() []Condition {
})
return conditions
}

// unstructuredAdapter is an embedded struct type that embeds the upstream type. unstructuredAdapter makes the assumption
// that the status conditions in unstructured.Unstructured can be found on status.conditions path.
type unstructuredAdapter struct {
*unstructured.Unstructured
}

// FromUnstructured makes the assumption that the status conditions in unstructured.Unstructured can be found on status.conditions
// path. If it is not found then we return nil.
func FromUnstructured(u *unstructured.Unstructured) Object {
_, found, err := unstructured.NestedSlice(u.Object, "status", "conditions")
if err != nil || !found {
return nil
}
return &unstructuredAdapter{Unstructured: u}
}

func (u *unstructuredAdapter) GetConditions() []Condition {
var conditions []Condition
c, _, _ := unstructured.NestedSlice(u.Object, "status", "conditions")
for _, condition := range c {
var newCondition Condition
cond := condition.(map[string]interface{})
jsonStr, err := json.Marshal(cond)
if err != nil {
continue
}
if err = json.Unmarshal(jsonStr, &newCondition); err != nil {
continue
}
conditions = append(conditions, newCondition)
}
return conditions
}

func (u *unstructuredAdapter) SetConditions(conditions []Condition) {
uc, _, _ := unstructured.NestedSlice(u.Object, "status", "conditions")
lo.Map(conditions, func(condition Condition, _ int) []interface{} {
uc = append(uc, map[string]interface{}{
"type": condition.Type,
"status": string(condition.Status),
"message": condition.Message,
"reason": condition.Reason,
"observedGeneration": strconv.Itoa(int(condition.ObservedGeneration)),
"lastTransitionTime": condition.LastTransitionTime.Time.String(),
})
return uc
})
unstructured.SetNestedSlice(u.Object, uc, "status", "conditions")
}

func (u *unstructuredAdapter) StatusConditions() ConditionSet {
var conditionType []string
lo.Map(u.GetConditions(), func(condition Condition, _ int) []string {
conditionType = append(conditionType, condition.Type)
return conditionType
})
return NewReadyConditions(conditionType...).For(u)
}
51 changes: 51 additions & 0 deletions status/condition_set_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package status_test

import (
"github.com/awslabs/operatorpkg/status"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"time"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -105,4 +107,53 @@ var _ = Describe("Conditions", func() {
Expect(testObject.StatusConditions().IsTrue(ConditionTypeFoo, ConditionTypeBaz)).To(BeTrue())
Expect(testObject.StatusConditions().IsTrue(ConditionTypeFoo, ConditionTypeBar, ConditionTypeBaz)).To(BeTrue())
})
It("should return nil when status conditions are not found on the expected path", func() {
testObject := &unstructured.Unstructured{Object: map[string]interface{}{
"invalid": map[string]interface{}{
"invalid": "invalid",
},
}}
Expect(status.FromUnstructured(testObject)).To(BeNil())
})
It("should validate status condition on unstructured object status is false", func() {
unstructuredAdapter := status.FromUnstructured(createUnstructuredStatusConditions("False"))
Expect(unstructuredAdapter).To(Not(BeNil()))
Expect(unstructuredAdapter.StatusConditions().IsTrue(status.ConditionReady)).To(BeFalse())
})
It("should validate status condition on unstructured object status is true", func() {
unstructuredAdapter := status.FromUnstructured(createUnstructuredStatusConditions("True"))
Expect(unstructuredAdapter).To(Not(BeNil()))
Expect(unstructuredAdapter.StatusConditions().IsTrue(status.ConditionReady)).To(BeTrue())
})
It("should set condition on unstructured object", func() {
testObject := createUnstructuredStatusConditions("True")
conditions := []status.Condition{
{
Type: status.ConditionReady,
Status: metav1.ConditionFalse,
Reason: "reason",
Message: "message",
},
}
status.FromUnstructured(testObject).SetConditions(conditions)
c, found, err := unstructured.NestedSlice(testObject.Object, "status", "conditions")
Expect(err).To(BeNil())
Expect(found).To(BeTrue())
Expect(len(c)).To(BeEquivalentTo(2))
})
})

func createUnstructuredStatusConditions(status string) *unstructured.Unstructured {
return &unstructured.Unstructured{Object: map[string]interface{}{
"status": map[string]interface{}{
"conditions": []interface{}{
map[string]interface{}{
"type": "Ready",
"status": status,
"message": "message",
"reason": "reason",
},
},
},
}}
}

0 comments on commit e1c5851

Please sign in to comment.