Merge pull request #9653 from BassinD/bugfix/nil-check-for-service-health-check-node-port-in-last-applied-config
Run the E2E test on kind / get-go-version (push) Failing after 47s
Run the E2E test on kind / build (push) Has been skipped
Run the E2E test on kind / setup-test-matrix (push) Successful in 2s
Run the E2E test on kind / run-e2e-test (push) Has been skipped
Main CI / get-go-version (push) Successful in 10s
Main CI / Build (push) Failing after 24s

Fix service restore with null healthCheckNodePort in last-applied-configuration label
This commit is contained in:
Xun Jiang/Bruce Jiang
2026-04-07 16:41:23 +08:00
committed by GitHub
3 changed files with 40 additions and 12 deletions
+1
View File
@@ -0,0 +1 @@
Fix service restore with null healthCheckNodePort in last-applied-configuration label
+9 -12
View File
@@ -94,21 +94,18 @@ func deleteHealthCheckNodePort(service *corev1api.Service) error {
// Search HealthCheckNodePort from server's last-applied-configuration
// annotation(HealthCheckNodePort is specified by `kubectl apply` command)
lastAppliedConfig, ok := service.Annotations[annotationLastAppliedConfig]
if ok {
appliedServiceUnstructured := new(map[string]any)
if err := json.Unmarshal([]byte(lastAppliedConfig), appliedServiceUnstructured); err != nil {
if lastAppliedConfig, ok := service.Annotations[annotationLastAppliedConfig]; ok {
var appliedConfig struct {
Spec struct {
HealthCheckNodePort *int32 `json:"healthCheckNodePort"`
} `json:"spec"`
}
if err := json.Unmarshal([]byte(lastAppliedConfig), &appliedConfig); err != nil {
return errors.WithStack(err)
}
healthCheckNodePort, exist, err := unstructured.NestedFloat64(*appliedServiceUnstructured, "spec", "healthCheckNodePort")
if err != nil {
return errors.WithStack(err)
}
// Found healthCheckNodePort in lastAppliedConfig annotation,
// and the value is not 0. No need to delete, return.
if exist && healthCheckNodePort != 0 {
if appliedConfig.Spec.HealthCheckNodePort != nil && *appliedConfig.Spec.HealthCheckNodePort != 0 {
return nil
}
}
@@ -644,6 +644,36 @@ func TestServiceActionExecute(t *testing.T) {
},
},
},
{
name: "If PreserveNodePorts is false and HealthCheckNodePort is null in last-applied-configuration, it should not crash and the port should be cleared.",
obj: corev1api.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "svc-1",
Annotations: map[string]string{
"kubectl.kubernetes.io/last-applied-configuration": `{"spec":{"healthCheckNodePort":null}}`,
},
},
Spec: corev1api.ServiceSpec{
HealthCheckNodePort: 8080,
ExternalTrafficPolicy: corev1api.ServiceExternalTrafficPolicyTypeLocal,
Type: corev1api.ServiceTypeLoadBalancer,
},
},
restore: builder.ForRestore(api.DefaultNamespace, "").PreserveNodePorts(false).Result(),
expectedRes: corev1api.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "svc-1",
Annotations: map[string]string{
"kubectl.kubernetes.io/last-applied-configuration": `{"spec":{"healthCheckNodePort":null}}`,
},
},
Spec: corev1api.ServiceSpec{
HealthCheckNodePort: 0,
ExternalTrafficPolicy: corev1api.ServiceExternalTrafficPolicyTypeLocal,
Type: corev1api.ServiceTypeLoadBalancer,
},
},
},
}
for _, test := range tests {