Skip to content

Commit

Permalink
store the actuation/reconcile status in the inventory object (#2819)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Liujingfang1 committed Feb 23, 2022
1 parent 9c3ce89 commit b1747d6
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 12 deletions.
42 changes: 40 additions & 2 deletions pkg/live/inventoryrg.go
Expand Up @@ -60,8 +60,9 @@ var ResourceGroupGVK = schema.GroupVersionKind{
// the Inventory and InventoryInfo interface. This wrapper loads and stores the
// object metadata (inventory) to and from the wrapped ResourceGroup.
type InventoryResourceGroup struct {
inv *unstructured.Unstructured
objMetas []object.ObjMetadata
inv *unstructured.Unstructured
objMetas []object.ObjMetadata
objStatus []actuation.ObjectStatus
}

func (icm *InventoryResourceGroup) Strategy() inventory.Strategy {
Expand Down Expand Up @@ -171,6 +172,7 @@ func (icm *InventoryResourceGroup) Load() (object.ObjMetadataSet, error) {
// happens in "GetObject".
func (icm *InventoryResourceGroup) Store(objMetas object.ObjMetadataSet, status []actuation.ObjectStatus) error {
icm.objMetas = objMetas
icm.objStatus = status
return nil
}

Expand All @@ -180,6 +182,10 @@ func (icm *InventoryResourceGroup) GetObject() (*unstructured.Unstructured, erro
if icm.inv == nil {
return nil, fmt.Errorf("inventory info is nil")
}
objStatusMap := map[object.ObjMetadata]actuation.ObjectStatus{}
for _, s := range icm.objStatus {
objStatusMap[inventory.ObjMetadataFromObjectReference(s.ObjectReference)] = s
}
klog.V(4).Infof("getting inventory resource group")
// Create a slice of Resources as empty Interface
klog.V(4).Infof("Creating list of %d resources", len(icm.objMetas))
Expand All @@ -193,20 +199,52 @@ func (icm *InventoryResourceGroup) GetObject() (*unstructured.Unstructured, erro
"name": objMeta.Name,
})
}
klog.V(4).Infof("Creating list of %d resources status", len(icm.objMetas))
var objStatus []interface{}
for _, objMeta := range icm.objMetas {
status, found := objStatusMap[objMeta]
if found {
klog.V(4).Infof("storing inventory obj refercence and its status: %s/%s", objMeta.Namespace, objMeta.Name)
objStatus = append(objStatus, map[string]interface{}{
"group": objMeta.GroupKind.Group,
"kind": objMeta.GroupKind.Kind,
"namespace": objMeta.Namespace,
"name": objMeta.Name,
"status": "Unknown",
"strategy": status.Strategy.String(),
"actuation": status.Actuation.String(),
"reconcile": status.Reconcile.String(),
})
}
}

// Create the inventory object by copying the template.
invCopy := icm.inv.DeepCopy()
// Adds or clears the inventory ObjMetadata to the ResourceGroup "spec.resources" section
if len(objs) == 0 {
klog.V(4).Infoln("clearing inventory resources")
unstructured.RemoveNestedField(invCopy.UnstructuredContent(),
"spec", "resources")
unstructured.RemoveNestedField(invCopy.UnstructuredContent(),
"status", "resourceStatuses")
} else {
klog.V(4).Infof("storing inventory (%d) resources", len(objs))
err := unstructured.SetNestedSlice(invCopy.UnstructuredContent(),
objs, "spec", "resources")
if err != nil {
return nil, err
}
err = unstructured.SetNestedSlice(invCopy.UnstructuredContent(),
objStatus, "status", "resourceStatuses")
if err != nil {
return nil, err
}
generation := invCopy.GetGeneration()
err = unstructured.SetNestedField(invCopy.UnstructuredContent(),
generation, "status", "observedGeneration")
if err != nil {
return nil, err
}
}
return invCopy, nil
}
Expand Down
71 changes: 61 additions & 10 deletions pkg/live/inventoryrg_test.go
Expand Up @@ -21,6 +21,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
"sigs.k8s.io/cli-utils/pkg/object"
)

Expand Down Expand Up @@ -74,9 +75,10 @@ var testPod = object.ObjMetadata{

func TestLoadStore(t *testing.T) {
tests := map[string]struct {
inv *unstructured.Unstructured
objs []object.ObjMetadata
isError bool
inv *unstructured.Unstructured
objs []object.ObjMetadata
objStatus []actuation.ObjectStatus
isError bool
}{
"Nil inventory is error": {
inv: nil,
Expand All @@ -89,26 +91,68 @@ func TestLoadStore(t *testing.T) {
isError: false,
},
"Simple test": {
inv: inventoryObj,
objs: []object.ObjMetadata{testPod},
inv: inventoryObj,
objs: []object.ObjMetadata{testPod},
objStatus: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testPod),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationPending,
Reconcile: actuation.ReconcilePending,
},
},
isError: false,
},
"Test two objects": {
inv: inventoryObj,
objs: []object.ObjMetadata{testDeployment, testService},
inv: inventoryObj,
objs: []object.ObjMetadata{testDeployment, testService},
objStatus: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testService),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
},
},
isError: false,
},
"Test three objects": {
inv: inventoryObj,
objs: []object.ObjMetadata{testDeployment, testService, testPod},
inv: inventoryObj,
objs: []object.ObjMetadata{testDeployment, testService, testPod},
objStatus: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testService),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testPod),
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationPending,
Reconcile: actuation.ReconcilePending,
},
},
isError: false,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
wrapped := WrapInventoryObj(tc.inv)
_ = wrapped.Store(tc.objs, []actuation.ObjectStatus{})
_ = wrapped.Store(tc.objs, tc.objStatus)
invStored, err := wrapped.GetObject()
if tc.isError {
if err == nil {
Expand All @@ -129,6 +173,13 @@ func TestLoadStore(t *testing.T) {
if !objs.Equal(tc.objs) {
t.Fatalf("expected inventory objs (%v), got (%v)", tc.objs, objs)
}
resourceStatus, _, err := unstructured.NestedSlice(invStored.Object, "status", "resourceStatuses")
if err != nil {
t.Fatalf("unexpected error %v received", err)
}
if len(resourceStatus) != len(tc.objStatus) {
t.Fatalf("expected %d resource status but got %d", len(tc.objStatus), len(resourceStatus))
}
})
}
}
Expand Down

0 comments on commit b1747d6

Please sign in to comment.