-
Notifications
You must be signed in to change notification settings - Fork 45
fix: Resolve ServiceAccount deletion race condition (thanks @nss10!) #1421
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
Changes from 5 commits
d2e910b
0a8117a
7a5616f
fdc9b71
7c134e7
d413aa4
d496921
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,6 +86,14 @@ func TestTaskSubmission(t *testing.T) { | |
| // Create a fake Kubernetes client | ||
| fakeClient := fake.NewSimpleClientset() | ||
|
|
||
| // Inject a deterministic UID on every Job create so ownerRef propagation can be verified. | ||
| const testJobUID = "test-job-uid-1234" | ||
| fakeClient.PrependReactor("create", "jobs", func(action k8stesting.Action) (bool, runtime.Object, error) { | ||
| obj := action.(k8stesting.CreateAction).GetObject().(*batchv1.Job) | ||
| obj.UID = testJobUID | ||
| return false, obj, nil | ||
| }) | ||
|
|
||
| // Create a mock configuration | ||
| conf := config.DefaultConfig() | ||
| conf.Kubernetes.Namespace = "test-namespace" | ||
|
|
@@ -155,12 +163,18 @@ spec: | |
| t.Errorf("expected Job name '%s', got '%s'", task.Id, job.Name) | ||
| } | ||
|
|
||
| // Verify that the ConfigMap was created | ||
| // Verify that the ConfigMap was created with the Job's UID in its ownerRef. | ||
| configMapName := "funnel-worker-config-" + task.Id | ||
| _, err = fakeClient.CoreV1().ConfigMaps(conf.Kubernetes.JobsNamespace).Get(context.Background(), configMapName, metav1.GetOptions{}) | ||
| cm, err := fakeClient.CoreV1().ConfigMaps(conf.Kubernetes.JobsNamespace).Get(context.Background(), configMapName, metav1.GetOptions{}) | ||
| if err != nil { | ||
| t.Fatalf("failed to get ConfigMap: %v", err) | ||
| } | ||
| if len(cm.OwnerReferences) == 0 { | ||
| t.Fatal("expected ConfigMap to have an ownerReference, but got none") | ||
| } | ||
| if got := cm.OwnerReferences[0].UID; got != testJobUID { | ||
| t.Errorf("expected ConfigMap ownerRef UID %q, got %q", testJobUID, got) | ||
| } | ||
|
|
||
| // Clean up resources | ||
| err = backend.cleanResources(context.Background(), task.Id) | ||
|
|
@@ -174,11 +188,9 @@ spec: | |
| t.Error("expected Job to be deleted, but it still exists") | ||
| } | ||
|
|
||
| // Verify that the ConfigMap was deleted | ||
| _, err = fakeClient.CoreV1().ConfigMaps(conf.Kubernetes.JobsNamespace).Get(context.Background(), configMapName, metav1.GetOptions{}) | ||
| if err == nil { | ||
| t.Error("expected ConfigMap to be deleted, but it still exists") | ||
| } | ||
| // ConfigMap deletion is handled by Kubernetes garbage collection via ownerReferences, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of Configmap, look for a resource which is actually being cleaned up by
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in PR #1423! |
||
| // not explicitly by cleanResources. The fake clientset does not simulate cascading GC, | ||
| // so we only verify the ownerRef is set correctly (asserted above). | ||
|
|
||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lbeckman314 — Deferring the deletion of these resources to Kubernetes using ownerReferences sounds good. However, we should handle that transition in a separate PR.
It also just occurred to me: what happens to cleanOrphanedResources? If there are any pending resources left behind by older server runs or due to previous deletion errors, our logic might track them but never actually clean them up.
Kubernetes garbage collection will continuously retry deleting these resources until they are gone, so we don't need to worry about transient API errors or rate limiting.
Given this, we should do one of two things:
cleanOrphanedResourcesmethod so it no longer looks for these specific resources as "orphaned," since Kubernetes will handle the cleanup natively.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in PR #1423!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @lbeckman314 , I was suggesting #1423 to be a PR pointed to
develop, such that it includes all changes related to resource cleanup. Keep #1421 only about handling Service Account deletion race condition. All logic regarding resource cleanup should be handled in #1423 only.