Merge pull request #5165 from whitewindmills/ds-generation
Align federated DaemonSet's observedGeneration semantics with its native
This commit is contained in:
commit
d3adcf68ef
|
@ -26,6 +26,7 @@ import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
policyv1 "k8s.io/api/policy/v1"
|
policyv1 "k8s.io/api/policy/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
@ -279,39 +280,44 @@ func aggregateDaemonSetStatus(object *unstructured.Unstructured, aggregatedStatu
|
||||||
|
|
||||||
oldStatus := &daemonSet.Status
|
oldStatus := &daemonSet.Status
|
||||||
newStatus := &appsv1.DaemonSetStatus{}
|
newStatus := &appsv1.DaemonSetStatus{}
|
||||||
|
observedLatestResourceTemplateGenerationCount := 0
|
||||||
for _, item := range aggregatedStatusItems {
|
for _, item := range aggregatedStatusItems {
|
||||||
if item.Status == nil {
|
if item.Status == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
temp := &appsv1.DaemonSetStatus{}
|
member := &WrappedDaemonSetStatus{}
|
||||||
if err = json.Unmarshal(item.Status.Raw, temp); err != nil {
|
if err = json.Unmarshal(item.Status.Raw, member); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
klog.V(3).Infof("Grab daemonSet(%s/%s) status from cluster(%s), currentNumberScheduled: %d, desiredNumberScheduled: %d, numberAvailable: %d, numberMisscheduled: %d, numberReady: %d, updatedNumberScheduled: %d, numberUnavailable: %d",
|
klog.V(3).Infof("Grab daemonSet(%s/%s) status from cluster(%s), currentNumberScheduled: %d, desiredNumberScheduled: %d, numberAvailable: %d, numberMisscheduled: %d, numberReady: %d, updatedNumberScheduled: %d, numberUnavailable: %d",
|
||||||
daemonSet.Namespace, daemonSet.Name, item.ClusterName, temp.CurrentNumberScheduled, temp.DesiredNumberScheduled, temp.NumberAvailable, temp.NumberMisscheduled, temp.NumberReady, temp.UpdatedNumberScheduled, temp.NumberUnavailable)
|
daemonSet.Namespace, daemonSet.Name, item.ClusterName, member.CurrentNumberScheduled, member.DesiredNumberScheduled, member.NumberAvailable, member.NumberMisscheduled, member.NumberReady, member.UpdatedNumberScheduled, member.NumberUnavailable)
|
||||||
|
|
||||||
// always set 'observedGeneration' with current generation(.metadata.generation)
|
// `memberStatus.ObservedGeneration >= memberStatus.Generation` means the member's status corresponds the latest spec revision of the member DaemonSet.
|
||||||
// which is the generation Karmada 'observed'.
|
// `memberStatus.ResourceTemplateGeneration >= daemonSet.Generation` means the member DaemonSet has been aligned with the latest spec revision of federated DaemonSet.
|
||||||
// The 'observedGeneration' is mainly used by GitOps tools(like 'Argo CD') to assess the health status.
|
// If both conditions are met, we consider the member's status corresponds the latest spec revision of federated DaemonSet.
|
||||||
// For more details, please refer to https://argo-cd.readthedocs.io/en/stable/operator-manual/health/.
|
if member.ObservedGeneration >= member.Generation &&
|
||||||
newStatus.ObservedGeneration = daemonSet.Generation
|
member.ResourceTemplateGeneration >= daemonSet.Generation {
|
||||||
newStatus.CurrentNumberScheduled += temp.CurrentNumberScheduled
|
observedLatestResourceTemplateGenerationCount++
|
||||||
newStatus.DesiredNumberScheduled += temp.DesiredNumberScheduled
|
}
|
||||||
newStatus.NumberAvailable += temp.NumberAvailable
|
|
||||||
newStatus.NumberMisscheduled += temp.NumberMisscheduled
|
newStatus.CurrentNumberScheduled += member.CurrentNumberScheduled
|
||||||
newStatus.NumberReady += temp.NumberReady
|
newStatus.DesiredNumberScheduled += member.DesiredNumberScheduled
|
||||||
newStatus.UpdatedNumberScheduled += temp.UpdatedNumberScheduled
|
newStatus.NumberAvailable += member.NumberAvailable
|
||||||
newStatus.NumberUnavailable += temp.NumberUnavailable
|
newStatus.NumberMisscheduled += member.NumberMisscheduled
|
||||||
|
newStatus.NumberReady += member.NumberReady
|
||||||
|
newStatus.UpdatedNumberScheduled += member.UpdatedNumberScheduled
|
||||||
|
newStatus.NumberUnavailable += member.NumberUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldStatus.ObservedGeneration == newStatus.ObservedGeneration &&
|
// The 'observedGeneration' is mainly used by GitOps tools(like 'Argo CD') to assess the health status.
|
||||||
oldStatus.CurrentNumberScheduled == newStatus.CurrentNumberScheduled &&
|
// For more details, please refer to https://argo-cd.readthedocs.io/en/stable/operator-manual/health/.
|
||||||
oldStatus.DesiredNumberScheduled == newStatus.DesiredNumberScheduled &&
|
if observedLatestResourceTemplateGenerationCount == len(aggregatedStatusItems) {
|
||||||
oldStatus.NumberAvailable == newStatus.NumberAvailable &&
|
newStatus.ObservedGeneration = daemonSet.Generation
|
||||||
oldStatus.NumberMisscheduled == newStatus.NumberMisscheduled &&
|
} else {
|
||||||
oldStatus.NumberReady == newStatus.NumberReady &&
|
newStatus.ObservedGeneration = oldStatus.ObservedGeneration
|
||||||
oldStatus.UpdatedNumberScheduled == newStatus.UpdatedNumberScheduled &&
|
}
|
||||||
oldStatus.NumberUnavailable == newStatus.NumberUnavailable {
|
|
||||||
|
if equality.Semantic.DeepEqual(oldStatus, newStatus) {
|
||||||
klog.V(3).Infof("Ignore update daemonSet(%s/%s) status as up to date", daemonSet.Namespace, daemonSet.Name)
|
klog.V(3).Infof("Ignore update daemonSet(%s/%s) status as up to date", daemonSet.Namespace, daemonSet.Name)
|
||||||
return object, nil
|
return object, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,8 +78,10 @@ func reflectDeploymentStatus(object *unstructured.Unstructured) (*runtime.RawExt
|
||||||
}
|
}
|
||||||
|
|
||||||
grabStatus := &WrappedDeploymentStatus{
|
grabStatus := &WrappedDeploymentStatus{
|
||||||
Generation: object.GetGeneration(),
|
FederatedGeneration: FederatedGeneration{
|
||||||
ResourceTemplateGeneration: resourceTemplateGenerationInt,
|
Generation: object.GetGeneration(),
|
||||||
|
ResourceTemplateGeneration: resourceTemplateGenerationInt,
|
||||||
|
},
|
||||||
DeploymentStatus: appsv1.DeploymentStatus{
|
DeploymentStatus: appsv1.DeploymentStatus{
|
||||||
Replicas: deploymentStatus.Replicas,
|
Replicas: deploymentStatus.Replicas,
|
||||||
UpdatedReplicas: deploymentStatus.UpdatedReplicas,
|
UpdatedReplicas: deploymentStatus.UpdatedReplicas,
|
||||||
|
@ -194,15 +196,31 @@ func reflectDaemonSetStatus(object *unstructured.Unstructured) (*runtime.RawExte
|
||||||
return nil, fmt.Errorf("failed to convert DaemonSetStatus from map[string]interface{}: %v", err)
|
return nil, fmt.Errorf("failed to convert DaemonSetStatus from map[string]interface{}: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
grabStatus := appsv1.DaemonSetStatus{
|
resourceTemplateGenerationInt := int64(0)
|
||||||
CurrentNumberScheduled: daemonSetStatus.CurrentNumberScheduled,
|
resourceTemplateGenerationStr := util.GetAnnotationValue(object.GetAnnotations(), v1alpha2.ResourceTemplateGenerationAnnotationKey)
|
||||||
DesiredNumberScheduled: daemonSetStatus.DesiredNumberScheduled,
|
err = runtime.Convert_string_To_int64(&resourceTemplateGenerationStr, &resourceTemplateGenerationInt, nil)
|
||||||
NumberAvailable: daemonSetStatus.NumberAvailable,
|
if err != nil {
|
||||||
NumberMisscheduled: daemonSetStatus.NumberMisscheduled,
|
klog.Errorf("Failed to parse DaemonSet(%s/%s) generation from annotation(%s:%s): %v", object.GetNamespace(), object.GetName(), v1alpha2.ResourceTemplateGenerationAnnotationKey, resourceTemplateGenerationStr, err)
|
||||||
NumberReady: daemonSetStatus.NumberReady,
|
return nil, err
|
||||||
UpdatedNumberScheduled: daemonSetStatus.UpdatedNumberScheduled,
|
|
||||||
NumberUnavailable: daemonSetStatus.NumberUnavailable,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grabStatus := &WrappedDaemonSetStatus{
|
||||||
|
FederatedGeneration: FederatedGeneration{
|
||||||
|
Generation: object.GetGeneration(),
|
||||||
|
ResourceTemplateGeneration: resourceTemplateGenerationInt,
|
||||||
|
},
|
||||||
|
DaemonSetStatus: appsv1.DaemonSetStatus{
|
||||||
|
CurrentNumberScheduled: daemonSetStatus.CurrentNumberScheduled,
|
||||||
|
DesiredNumberScheduled: daemonSetStatus.DesiredNumberScheduled,
|
||||||
|
NumberAvailable: daemonSetStatus.NumberAvailable,
|
||||||
|
NumberMisscheduled: daemonSetStatus.NumberMisscheduled,
|
||||||
|
NumberReady: daemonSetStatus.NumberReady,
|
||||||
|
UpdatedNumberScheduled: daemonSetStatus.UpdatedNumberScheduled,
|
||||||
|
NumberUnavailable: daemonSetStatus.NumberUnavailable,
|
||||||
|
ObservedGeneration: daemonSetStatus.ObservedGeneration,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return helper.BuildStatusRawExtension(grabStatus)
|
return helper.BuildStatusRawExtension(grabStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,24 @@ package native
|
||||||
|
|
||||||
import appsv1 "k8s.io/api/apps/v1"
|
import appsv1 "k8s.io/api/apps/v1"
|
||||||
|
|
||||||
// WrappedDeploymentStatus is a wrapper for appsv1.DeploymentStatus.
|
// FederatedGeneration holds the generation of the same resource in the member cluster and the Karmada control plane.
|
||||||
type WrappedDeploymentStatus struct {
|
type FederatedGeneration struct {
|
||||||
appsv1.DeploymentStatus `json:",inline"`
|
|
||||||
|
|
||||||
// Generation holds the generation(.metadata.generation) of resource running on member cluster.
|
// Generation holds the generation(.metadata.generation) of resource running on member cluster.
|
||||||
Generation int64 `json:"generation,omitempty"`
|
Generation int64 `json:"generation,omitempty"`
|
||||||
|
|
||||||
// ResourceTemplateGeneration holds the value of annotation resourcetemplate.karmada.io/generation grabbed
|
// ResourceTemplateGeneration holds the value of annotation resourcetemplate.karmada.io/generation grabbed
|
||||||
// from resource running on member cluster.
|
// from resource running on member cluster.
|
||||||
ResourceTemplateGeneration int64 `json:"resourceTemplateGeneration,omitempty"`
|
ResourceTemplateGeneration int64 `json:"resourceTemplateGeneration,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrappedDeploymentStatus is a wrapper for appsv1.DeploymentStatus.
|
||||||
|
type WrappedDeploymentStatus struct {
|
||||||
|
FederatedGeneration `json:",inline"`
|
||||||
|
appsv1.DeploymentStatus `json:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrappedDaemonSetStatus is a wrapper for appsv1.DaemonSetStatus.
|
||||||
|
type WrappedDaemonSetStatus struct {
|
||||||
|
FederatedGeneration `json:",inline"`
|
||||||
|
appsv1.DaemonSetStatus `json:",inline"`
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue