From 738352611efd6681e17e70017e6a33b6d9ebbe67 Mon Sep 17 00:00:00 2001 From: bruce Date: Mon, 13 Jun 2022 15:15:56 +0800 Subject: [PATCH] sync status of pod Signed-off-by: bruce --- .../customizing-resource-interpreter.md | 1 + .../defaultinterpreter/aggregatestatus.go | 51 +++++ .../aggregatestatus_test.go | 195 ++++++++++++++++++ 3 files changed, 247 insertions(+) diff --git a/docs/userguide/customizing-resource-interpreter.md b/docs/userguide/customizing-resource-interpreter.md index f7d9494b254b..bf16fef1bb67 100644 --- a/docs/userguide/customizing-resource-interpreter.md +++ b/docs/userguide/customizing-resource-interpreter.md @@ -97,6 +97,7 @@ Supported resources: - Job(batch/v1) - DaemonSet(apps/v1) - StatefulSet(apps/v1) +- Pod(v1) ### InterpretStatus diff --git a/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus.go b/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus.go index 4bb5989fee53..709dbcfd244a 100644 --- a/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus.go +++ b/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus.go @@ -27,6 +27,7 @@ func getAllDefaultAggregateStatusInterpreter() map[schema.GroupVersionKind]aggre s[batchv1.SchemeGroupVersion.WithKind(util.JobKind)] = aggregateJobStatus s[appsv1.SchemeGroupVersion.WithKind(util.DaemonSetKind)] = aggregateDaemonSetStatus s[appsv1.SchemeGroupVersion.WithKind(util.StatefulSetKind)] = aggregateStatefulSetStatus + s[corev1.SchemeGroupVersion.WithKind(util.PodKind)] = aggregatePodStatus return s } @@ -269,3 +270,53 @@ func aggregateStatefulSetStatus(object *unstructured.Unstructured, aggregatedSta return helper.ToUnstructured(statefulSet) } + +func aggregatePodStatus(object *unstructured.Unstructured, aggregatedStatusItems []workv1alpha2.AggregatedStatusItem) (*unstructured.Unstructured, error) { + pod, err := helper.ConvertToPod(object) + if err != nil { + return nil, err + } + + newStatus := &corev1.PodStatus{} + newStatus.ContainerStatuses = make([]corev1.ContainerStatus, 0) + runningFlag := true + for _, item := range aggregatedStatusItems { + if item.Status == nil { + runningFlag = false + continue + } + + temp := &corev1.PodStatus{} + if err = json.Unmarshal(item.Status.Raw, temp); err != nil { + return nil, err + } + + if temp.Phase != corev1.PodRunning { + runningFlag = false + } + + for _, containerStatus := range temp.ContainerStatuses { + tempStatus := corev1.ContainerStatus{ + Ready: containerStatus.Ready, + State: containerStatus.State, + } + newStatus.ContainerStatuses = append(newStatus.ContainerStatuses, tempStatus) + } + klog.V(3).Infof("Grab pod(%s/%s) status from cluster(%s), phase: %s", pod.Namespace, + pod.Name, item.ClusterName, temp.Phase) + } + + if runningFlag { + newStatus.Phase = corev1.PodRunning + } else { + newStatus.Phase = corev1.PodPending + } + + if reflect.DeepEqual(pod.Status, *newStatus) { + klog.V(3).Infof("ignore update pod(%s/%s) status as up to date", pod.Namespace, pod.Name) + return object, nil + } + + pod.Status = *newStatus + return helper.ToUnstructured(pod) +} diff --git a/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus_test.go b/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus_test.go index 655e8ea17c74..81b68b33c386 100644 --- a/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus_test.go +++ b/pkg/resourceinterpreter/defaultinterpreter/aggregatestatus_test.go @@ -2,6 +2,7 @@ package defaultinterpreter import ( "testing" + "time" "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" @@ -346,3 +347,197 @@ func cleanUnstructuredJobConditionTime(object *unstructured.Unstructured) *unstr ret, _ := helper.ToUnstructured(job) return ret } + +func TestAggregatePodStatus(t *testing.T) { + startedTrue := true + timeNow := time.Now() + + containerStatuses1 := []corev1.ContainerStatus{ + { + ContainerID: "containerd://6cee0afa333472f672341352e0d", + Image: "nginx:latest", + ImageID: "docker.io/library/import-2022-06-05@sha256:dfb593", + Name: "busybox-2", + Ready: true, + RestartCount: 0, + Started: &startedTrue, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + { + ContainerID: "containerd://b373fb05ebf57020573cdf4a4518a3b2a8", + Image: "nginx:latest", + ImageID: "docker.io/library/import-2022-06-05@sha256:a29d07a75", + Name: "busybox-2", + Ready: true, + RestartCount: 0, + Started: &startedTrue, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + } + + newContainerStatuses1 := []corev1.ContainerStatus{ + { + Ready: true, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + { + Ready: true, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + } + + curObj, _ := helper.ToUnstructured(&corev1.Pod{}) + newObj, _ := helper.ToUnstructured(&corev1.Pod{Status: corev1.PodStatus{ + ContainerStatuses: newContainerStatuses1, + Phase: corev1.PodRunning, + }}) + + statusMap1 := map[string]interface{}{ + "containerStatuses": []corev1.ContainerStatus{containerStatuses1[0]}, + "phase": corev1.PodRunning, + } + raw1, _ := helper.BuildStatusRawExtension(statusMap1) + statusMap2 := map[string]interface{}{ + "containerStatuses": []corev1.ContainerStatus{containerStatuses1[1]}, + "phase": corev1.PodRunning, + } + raw2, _ := helper.BuildStatusRawExtension(statusMap2) + aggregatedStatusItems1 := []workv1alpha2.AggregatedStatusItem{ + {ClusterName: "member1", Status: raw1, Applied: true}, + {ClusterName: "member2", Status: raw2, Applied: true}, + } + + containerStatuses2 := []corev1.ContainerStatus{ + { + ContainerID: "containerd://6cee0afa333472f672341352e0d", + Image: "nginx:latest", + ImageID: "docker.io/library/import-2022-06-05@sha256:dfb593", + Name: "busybox-2", + Ready: true, + RestartCount: 0, + Started: &startedTrue, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + { + ContainerID: "containerd://b373fb05ebf57020573cdf4a4518a3b2a8", + Image: "nginx:latest", + ImageID: "docker.io/library/import-2022-06-05@sha256:a29d07a75", + Name: "busybox-2", + Ready: false, + RestartCount: 0, + Started: &startedTrue, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + } + + statusMap3 := map[string]interface{}{ + "containerStatuses": []corev1.ContainerStatus{containerStatuses2[0]}, + "phase": corev1.PodRunning, + } + raw3, _ := helper.BuildStatusRawExtension(statusMap3) + statusMap4 := map[string]interface{}{ + "containerStatuses": []corev1.ContainerStatus{containerStatuses2[1]}, + "phase": corev1.PodPending, + } + raw4, _ := helper.BuildStatusRawExtension(statusMap4) + aggregatedStatusItems2 := []workv1alpha2.AggregatedStatusItem{ + {ClusterName: "member1", Status: raw3, Applied: true}, + {ClusterName: "member2", Status: raw4, Applied: true}, + } + + newContainerStatuses2 := []corev1.ContainerStatus{ + { + Ready: true, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + { + Ready: false, + State: corev1.ContainerState{ + Running: &corev1.ContainerStateRunning{ + StartedAt: metav1.Time{ + Time: timeNow, + }, + }, + }, + }, + } + + newPodFailed := &corev1.Pod{Status: corev1.PodStatus{ + ContainerStatuses: newContainerStatuses2, + Phase: corev1.PodPending, + }} + newObjFailed, _ := helper.ToUnstructured(newPodFailed) + + tests := []struct { + name string + curObj *unstructured.Unstructured + aggregatedStatusItems []workv1alpha2.AggregatedStatusItem + expectedObj *unstructured.Unstructured + }{ + { + name: "update pod status", + curObj: curObj, + aggregatedStatusItems: aggregatedStatusItems1, + expectedObj: newObj, + }, + { + name: "ignore update pod status as up to date", + curObj: newObj, + aggregatedStatusItems: aggregatedStatusItems1, + expectedObj: newObj, + }, + { + name: "update pod status as one Pod failed", + curObj: newObj, + aggregatedStatusItems: aggregatedStatusItems2, + expectedObj: newObjFailed, + }, + } + + for _, tt := range tests { + actualObj, _ := aggregatePodStatus(tt.curObj, tt.aggregatedStatusItems) + assert.Equal(t, tt.expectedObj, actualObj) + } +}