Skip to content

[k8s, k8s multicluster plugin] Implement health state for statefulset#6273

Merged
khanhtc1202 merged 2 commits into
masterfrom
implement-health-state-for-statefulset
Sep 26, 2025
Merged

[k8s, k8s multicluster plugin] Implement health state for statefulset#6273
khanhtc1202 merged 2 commits into
masterfrom
implement-health-state-for-statefulset

Conversation

@ffjlabo
Copy link
Copy Markdown
Member

@ffjlabo ffjlabo commented Sep 25, 2025

What this PR does:

as title

Implemented the health status for statefulset with reference to determineStatefulSetHealth in pipedv0. This is almost all the same logic.

func determineStatefulSetHealth(obj *unstructured.Unstructured) (status model.KubernetesResourceState_HealthStatus, desc string) {
s := &appsv1.StatefulSet{}
err := scheme.Scheme.Convert(obj, s, nil)
if err != nil {
status = model.KubernetesResourceState_OTHER
desc = fmt.Sprintf("Unexpected error while calculating: unable to convert %T to %T: %v", obj, s, err)
return
}
// Referred to:
// https://github.com/kubernetes/kubernetes/blob/7942dca975b7be9386540df3c17e309c3cb2de60/staging/src/k8s.io/kubectl/pkg/polymorphichelpers/rollout_status.go#L130-L149
status = model.KubernetesResourceState_OTHER
if s.Status.ObservedGeneration == 0 || s.Generation > s.Status.ObservedGeneration {
desc = "Waiting for statefulset spec update to be observed"
return
}
if s.Spec.Replicas == nil {
desc = "The number of desired replicas is unspecified"
return
}
if *s.Spec.Replicas != s.Status.ReadyReplicas {
desc = fmt.Sprintf("The number of ready replicas (%d) is different from the desired number (%d)", s.Status.ReadyReplicas, *s.Spec.Replicas)
return
}
// Check if the partitioned roll out is in progress.
if s.Spec.UpdateStrategy.Type == appsv1.RollingUpdateStatefulSetStrategyType && s.Spec.UpdateStrategy.RollingUpdate != nil {
if s.Spec.Replicas != nil && s.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
if s.Status.UpdatedReplicas < (*s.Spec.Replicas - *s.Spec.UpdateStrategy.RollingUpdate.Partition) {
desc = fmt.Sprintf("Waiting for partitioned roll out to finish because %d out of %d new pods have been updated",
s.Status.UpdatedReplicas, (*s.Spec.Replicas - *s.Spec.UpdateStrategy.RollingUpdate.Partition))
return
}
}
status = model.KubernetesResourceState_HEALTHY
return
}
if s.Status.UpdateRevision != s.Status.CurrentRevision {
desc = fmt.Sprintf("Waiting for statefulset rolling update to complete %d pods at revision %s", s.Status.UpdatedReplicas, s.Status.UpdateRevision)
return
}
status = model.KubernetesResourceState_HEALTHY
return
}

Notable policy
The health status in pipedv0 is associated with it in pipedv1, like the table below.

pipedv0 pipedv1
model.KubernetesResourceState_UNKNOWN sdk.ResourceHealthStateUnknown
model.KubernetesResourceState_HEALTHY sdk.ResourceHealthStateHealthy
model.KubernetesResourceState_OTHER sdk.ResourceHealthStateUnhealthy

Why we need it:

We want to support the health status for statefulset

Which issue(s) this PR fixes:

Part of #5764

Does this PR introduce a user-facing change?:

  • How are users affected by this change:
  • Is this breaking change:
  • How to migrate (if breaking change):

Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Sep 25, 2025

Codecov Report

❌ Patch coverage is 78.46154% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 28.78%. Comparing base (b5b1a2d) to head (24cb1ad).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
...ipedv1/plugin/kubernetes/provider/health_status.go 75.86% 7 Missing ⚠️
.../kubernetes_multicluster/provider/health_status.go 75.86% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6273      +/-   ##
==========================================
+ Coverage   28.72%   28.78%   +0.05%     
==========================================
  Files         560      560              
  Lines       59749    59813      +64     
==========================================
+ Hits        17165    17215      +50     
- Misses      41265    41279      +14     
  Partials     1319     1319              
Flag Coverage Δ
. 23.22% <ø> (ø)
.-pkg-app-pipedv1-plugin-analysis 32.64% <ø> (ø)
.-pkg-app-pipedv1-plugin-kubernetes 58.35% <78.78%> (+0.16%) ⬆️
.-pkg-app-pipedv1-plugin-kubernetes_multicluster 67.63% <78.12%> (+0.14%) ⬆️
.-pkg-app-pipedv1-plugin-scriptrun 54.83% <ø> (ø)
.-pkg-app-pipedv1-plugin-terraform 39.56% <ø> (ø)
.-pkg-app-pipedv1-plugin-wait 35.51% <ø> (ø)
.-pkg-app-pipedv1-plugin-waitapproval 55.73% <ø> (ø)
.-pkg-plugin-sdk 50.47% <ø> (ø)
.-tool-actions-gh-release 19.23% <ø> (ø)
.-tool-actions-plan-preview 25.51% <ø> (ø)
.-tool-codegen-protoc-gen-auth 0.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +76 to +106
func statefulSetHealthStatus(obj *appsv1.StatefulSet) (sdk.ResourceHealthStatus, string) {
// Referred to:
// https://github.com/kubernetes/kubernetes/blob/7942dca975b7be9386540df3c17e309c3cb2de60/staging/src/k8s.io/kubectl/pkg/polymorphichelpers/rollout_status.go#L130-L149
if obj.Status.ObservedGeneration == 0 || obj.Generation > obj.Status.ObservedGeneration {
return sdk.ResourceHealthStateUnhealthy, "Waiting for statefulset spec update to be observed"
}

if obj.Spec.Replicas == nil {
return sdk.ResourceHealthStateUnhealthy, "The number of desired replicas is unspecified"
}
if *obj.Spec.Replicas != obj.Status.ReadyReplicas {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("The number of ready replicas (%d) is different from the desired number (%d)", obj.Status.ReadyReplicas, *obj.Spec.Replicas)
}

// Check if the partitioned roll out is in progress.
if obj.Spec.UpdateStrategy.Type == appsv1.RollingUpdateStatefulSetStrategyType && obj.Spec.UpdateStrategy.RollingUpdate != nil {
if obj.Spec.Replicas != nil && obj.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
if obj.Status.UpdatedReplicas < (*obj.Spec.Replicas - *obj.Spec.UpdateStrategy.RollingUpdate.Partition) {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("Waiting for partitioned roll out to finish because %d out of %d new pods have been updated",
obj.Status.UpdatedReplicas, (*obj.Spec.Replicas - *obj.Spec.UpdateStrategy.RollingUpdate.Partition))
}
}
return sdk.ResourceHealthStateHealthy, ""
}

if obj.Status.UpdateRevision != obj.Status.CurrentRevision {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("Waiting for statefulset rolling update to complete %d pods at revision %s", obj.Status.UpdatedReplicas, obj.Status.UpdateRevision)
}

return sdk.ResourceHealthStateHealthy, ""
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reference implementation:

func determineStatefulSetHealth(obj *unstructured.Unstructured) (status model.KubernetesResourceState_HealthStatus, desc string) {
s := &appsv1.StatefulSet{}
err := scheme.Scheme.Convert(obj, s, nil)
if err != nil {
status = model.KubernetesResourceState_OTHER
desc = fmt.Sprintf("Unexpected error while calculating: unable to convert %T to %T: %v", obj, s, err)
return
}
// Referred to:
// https://github.com/kubernetes/kubernetes/blob/7942dca975b7be9386540df3c17e309c3cb2de60/staging/src/k8s.io/kubectl/pkg/polymorphichelpers/rollout_status.go#L130-L149
status = model.KubernetesResourceState_OTHER
if s.Status.ObservedGeneration == 0 || s.Generation > s.Status.ObservedGeneration {
desc = "Waiting for statefulset spec update to be observed"
return
}
if s.Spec.Replicas == nil {
desc = "The number of desired replicas is unspecified"
return
}
if *s.Spec.Replicas != s.Status.ReadyReplicas {
desc = fmt.Sprintf("The number of ready replicas (%d) is different from the desired number (%d)", s.Status.ReadyReplicas, *s.Spec.Replicas)
return
}
// Check if the partitioned roll out is in progress.
if s.Spec.UpdateStrategy.Type == appsv1.RollingUpdateStatefulSetStrategyType && s.Spec.UpdateStrategy.RollingUpdate != nil {
if s.Spec.Replicas != nil && s.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
if s.Status.UpdatedReplicas < (*s.Spec.Replicas - *s.Spec.UpdateStrategy.RollingUpdate.Partition) {
desc = fmt.Sprintf("Waiting for partitioned roll out to finish because %d out of %d new pods have been updated",
s.Status.UpdatedReplicas, (*s.Spec.Replicas - *s.Spec.UpdateStrategy.RollingUpdate.Partition))
return
}
}
status = model.KubernetesResourceState_HEALTHY
return
}
if s.Status.UpdateRevision != s.Status.CurrentRevision {
desc = fmt.Sprintf("Waiting for statefulset rolling update to complete %d pods at revision %s", s.Status.UpdatedReplicas, s.Status.UpdateRevision)
return
}
status = model.KubernetesResourceState_HEALTHY
return
}

Copy link
Copy Markdown
Member

@khanhtc1202 khanhtc1202 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@khanhtc1202 khanhtc1202 merged commit e4beafb into master Sep 26, 2025
46 checks passed
@khanhtc1202 khanhtc1202 deleted the implement-health-state-for-statefulset branch September 26, 2025 02:49
This was referenced Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants