Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server-Side Apply: ExtractPod should specify UID #1346

Open
gnuletik opened this issue Apr 4, 2024 · 0 comments
Open

Server-Side Apply: ExtractPod should specify UID #1346

gnuletik opened this issue Apr 4, 2024 · 0 comments

Comments

@gnuletik
Copy link

gnuletik commented Apr 4, 2024

TLDR

When using server side apply with ExtractPod, a controller may recreate a resource that was deleted by attempting to remove a finalizer.

Context

I have a controller that watches pods to remove finalizer using Server-Side Apply (to avoid race condition between controllers as suggested here).

It removes the finalizer in the following way:

podApplyConfig, err := coreac.ExtractPod(pod, fm)
if err != nil {
        return fmt.Errorf("coreac.ExtractPod: %w", err)
}

// updating something
podApplyConfig.Finalizers = nil

_, err = w.client.CoreV1().Pods(ns).Apply(ctx, podApplyConfig, meta.ApplyOptions{FieldManager: smtg})
if err != nil {
        return fmt.Errorf("client.Apply: %w", err)
}

The SharedInformer sometimes sends the event multiple times, which leads to pod being recreated after deletion, given this scenario:

  • api-server: sets deletionTimestamp
  • my-controller: receives Update event: it removes the finalizer with SSA
  • api-server: deleted the pod
  • my-controller: receives a duplicated Update event: it removes the finalizer a second time with SSA
  • api-server: creates a pod instead of updating it

Fix

Kubernetes specs specify that:

Create is blocked on apply if uid is provided link

See KEPS

We can manually call podApply := podApply.WithUID(pod.UID) to workaround this.

However, I think that it would be better that ExtractPod (and similar method for other resources) sets the UID before returning it.

func extractPod(pod *apicorev1.Pod, fieldManager string, subresource string) (*PodApplyConfiguration, error) {
b := &PodApplyConfiguration{}
err := managedfields.ExtractInto(pod, internal.Parser().Type("io.k8s.api.core.v1.Pod"), fieldManager, b, subresource)
if err != nil {
return nil, err
}
b.WithName(pod.Name)
b.WithNamespace(pod.Namespace)
b.WithKind("Pod")
b.WithAPIVersion("v1")
return b, nil
}

WDYT?

I can make a PR if that sounds good to you.
However, this part of the codebase seems to be generated, so I'd need a hint on where to edit that.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant