Skip to content

Commit b1747d6

Browse files
authored
store the actuation/reconcile status in the inventory object (#2819)
In the Store() function, it saves the actuation and reconcile status in the InventoryResourceGroup object. In the GetObject() function, it constructs the unstructured object of the ResourceGroup CR with .status.resourceStatuses assigned. Updated the unit test to cover this change.
1 parent 9c3ce89 commit b1747d6

File tree

2 files changed

+101
-12
lines changed

2 files changed

+101
-12
lines changed

pkg/live/inventoryrg.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ var ResourceGroupGVK = schema.GroupVersionKind{
6060
// the Inventory and InventoryInfo interface. This wrapper loads and stores the
6161
// object metadata (inventory) to and from the wrapped ResourceGroup.
6262
type InventoryResourceGroup struct {
63-
inv *unstructured.Unstructured
64-
objMetas []object.ObjMetadata
63+
inv *unstructured.Unstructured
64+
objMetas []object.ObjMetadata
65+
objStatus []actuation.ObjectStatus
6566
}
6667

6768
func (icm *InventoryResourceGroup) Strategy() inventory.Strategy {
@@ -171,6 +172,7 @@ func (icm *InventoryResourceGroup) Load() (object.ObjMetadataSet, error) {
171172
// happens in "GetObject".
172173
func (icm *InventoryResourceGroup) Store(objMetas object.ObjMetadataSet, status []actuation.ObjectStatus) error {
173174
icm.objMetas = objMetas
175+
icm.objStatus = status
174176
return nil
175177
}
176178

@@ -180,6 +182,10 @@ func (icm *InventoryResourceGroup) GetObject() (*unstructured.Unstructured, erro
180182
if icm.inv == nil {
181183
return nil, fmt.Errorf("inventory info is nil")
182184
}
185+
objStatusMap := map[object.ObjMetadata]actuation.ObjectStatus{}
186+
for _, s := range icm.objStatus {
187+
objStatusMap[inventory.ObjMetadataFromObjectReference(s.ObjectReference)] = s
188+
}
183189
klog.V(4).Infof("getting inventory resource group")
184190
// Create a slice of Resources as empty Interface
185191
klog.V(4).Infof("Creating list of %d resources", len(icm.objMetas))
@@ -193,20 +199,52 @@ func (icm *InventoryResourceGroup) GetObject() (*unstructured.Unstructured, erro
193199
"name": objMeta.Name,
194200
})
195201
}
202+
klog.V(4).Infof("Creating list of %d resources status", len(icm.objMetas))
203+
var objStatus []interface{}
204+
for _, objMeta := range icm.objMetas {
205+
status, found := objStatusMap[objMeta]
206+
if found {
207+
klog.V(4).Infof("storing inventory obj refercence and its status: %s/%s", objMeta.Namespace, objMeta.Name)
208+
objStatus = append(objStatus, map[string]interface{}{
209+
"group": objMeta.GroupKind.Group,
210+
"kind": objMeta.GroupKind.Kind,
211+
"namespace": objMeta.Namespace,
212+
"name": objMeta.Name,
213+
"status": "Unknown",
214+
"strategy": status.Strategy.String(),
215+
"actuation": status.Actuation.String(),
216+
"reconcile": status.Reconcile.String(),
217+
})
218+
}
219+
}
220+
196221
// Create the inventory object by copying the template.
197222
invCopy := icm.inv.DeepCopy()
198223
// Adds or clears the inventory ObjMetadata to the ResourceGroup "spec.resources" section
199224
if len(objs) == 0 {
200225
klog.V(4).Infoln("clearing inventory resources")
201226
unstructured.RemoveNestedField(invCopy.UnstructuredContent(),
202227
"spec", "resources")
228+
unstructured.RemoveNestedField(invCopy.UnstructuredContent(),
229+
"status", "resourceStatuses")
203230
} else {
204231
klog.V(4).Infof("storing inventory (%d) resources", len(objs))
205232
err := unstructured.SetNestedSlice(invCopy.UnstructuredContent(),
206233
objs, "spec", "resources")
207234
if err != nil {
208235
return nil, err
209236
}
237+
err = unstructured.SetNestedSlice(invCopy.UnstructuredContent(),
238+
objStatus, "status", "resourceStatuses")
239+
if err != nil {
240+
return nil, err
241+
}
242+
generation := invCopy.GetGeneration()
243+
err = unstructured.SetNestedField(invCopy.UnstructuredContent(),
244+
generation, "status", "observedGeneration")
245+
if err != nil {
246+
return nil, err
247+
}
210248
}
211249
return invCopy, nil
212250
}

pkg/live/inventoryrg_test.go

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"k8s.io/apimachinery/pkg/runtime/schema"
2222
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
2323
"sigs.k8s.io/cli-utils/pkg/common"
24+
"sigs.k8s.io/cli-utils/pkg/inventory"
2425
"sigs.k8s.io/cli-utils/pkg/object"
2526
)
2627

@@ -74,9 +75,10 @@ var testPod = object.ObjMetadata{
7475

7576
func TestLoadStore(t *testing.T) {
7677
tests := map[string]struct {
77-
inv *unstructured.Unstructured
78-
objs []object.ObjMetadata
79-
isError bool
78+
inv *unstructured.Unstructured
79+
objs []object.ObjMetadata
80+
objStatus []actuation.ObjectStatus
81+
isError bool
8082
}{
8183
"Nil inventory is error": {
8284
inv: nil,
@@ -89,26 +91,68 @@ func TestLoadStore(t *testing.T) {
8991
isError: false,
9092
},
9193
"Simple test": {
92-
inv: inventoryObj,
93-
objs: []object.ObjMetadata{testPod},
94+
inv: inventoryObj,
95+
objs: []object.ObjMetadata{testPod},
96+
objStatus: []actuation.ObjectStatus{
97+
{
98+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testPod),
99+
Strategy: actuation.ActuationStrategyApply,
100+
Actuation: actuation.ActuationPending,
101+
Reconcile: actuation.ReconcilePending,
102+
},
103+
},
94104
isError: false,
95105
},
96106
"Test two objects": {
97-
inv: inventoryObj,
98-
objs: []object.ObjMetadata{testDeployment, testService},
107+
inv: inventoryObj,
108+
objs: []object.ObjMetadata{testDeployment, testService},
109+
objStatus: []actuation.ObjectStatus{
110+
{
111+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment),
112+
Strategy: actuation.ActuationStrategyApply,
113+
Actuation: actuation.ActuationSucceeded,
114+
Reconcile: actuation.ReconcileSucceeded,
115+
},
116+
{
117+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testService),
118+
Strategy: actuation.ActuationStrategyApply,
119+
Actuation: actuation.ActuationSucceeded,
120+
Reconcile: actuation.ReconcileSucceeded,
121+
},
122+
},
99123
isError: false,
100124
},
101125
"Test three objects": {
102-
inv: inventoryObj,
103-
objs: []object.ObjMetadata{testDeployment, testService, testPod},
126+
inv: inventoryObj,
127+
objs: []object.ObjMetadata{testDeployment, testService, testPod},
128+
objStatus: []actuation.ObjectStatus{
129+
{
130+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment),
131+
Strategy: actuation.ActuationStrategyApply,
132+
Actuation: actuation.ActuationSucceeded,
133+
Reconcile: actuation.ReconcileSucceeded,
134+
},
135+
{
136+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testService),
137+
Strategy: actuation.ActuationStrategyApply,
138+
Actuation: actuation.ActuationSucceeded,
139+
Reconcile: actuation.ReconcileSucceeded,
140+
},
141+
{
142+
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testPod),
143+
Strategy: actuation.ActuationStrategyApply,
144+
Actuation: actuation.ActuationPending,
145+
Reconcile: actuation.ReconcilePending,
146+
},
147+
},
104148
isError: false,
105149
},
106150
}
107151

108152
for name, tc := range tests {
109153
t.Run(name, func(t *testing.T) {
110154
wrapped := WrapInventoryObj(tc.inv)
111-
_ = wrapped.Store(tc.objs, []actuation.ObjectStatus{})
155+
_ = wrapped.Store(tc.objs, tc.objStatus)
112156
invStored, err := wrapped.GetObject()
113157
if tc.isError {
114158
if err == nil {
@@ -129,6 +173,13 @@ func TestLoadStore(t *testing.T) {
129173
if !objs.Equal(tc.objs) {
130174
t.Fatalf("expected inventory objs (%v), got (%v)", tc.objs, objs)
131175
}
176+
resourceStatus, _, err := unstructured.NestedSlice(invStored.Object, "status", "resourceStatuses")
177+
if err != nil {
178+
t.Fatalf("unexpected error %v received", err)
179+
}
180+
if len(resourceStatus) != len(tc.objStatus) {
181+
t.Fatalf("expected %d resource status but got %d", len(tc.objStatus), len(resourceStatus))
182+
}
132183
})
133184
}
134185
}

0 commit comments

Comments
 (0)