-
Notifications
You must be signed in to change notification settings - Fork 38.8k
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
Adding cascading deletion support to federated namespaces #34648
Conversation
I am working on updating our e2e test |
88c9e29
to
71397d2
Compare
Updated the PR to include e2e changes. Verified that test/e2e/federated-namespace passes |
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.
Sorry, I'm not familiar with the federation code base. I asked two question, they might be silly. I'll take another pass tomorrow.
// removeFinalizerFunc | ||
func(obj runtime.Object, finalizer string) (runtime.Object, error) { | ||
namespace := obj.(*api_v1.Namespace) | ||
finalizerSet := sets.NewString() |
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.
I don't get why you need to make the Set. Why not just make []api_v1.FinalizerName directly?
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.
Fixed, thx
@@ -371,6 +416,13 @@ func (nc *NamespaceController) delete(namespace *api_v1.Namespace) error { | |||
return fmt.Errorf("failed to delete events list from namespace: %v", err) | |||
} | |||
|
|||
// Delete the namespace from all underlying clusters. | |||
updatedNamespaceObj, err := nc.deletionHelper.ProcessDeletion(updatedNamespace) |
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.
I thought ProcessDeletion should take a fed_v1.Namespace
, why is it taking a regular namespace?
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.
There is no special fed_v1.Namespace
. We use the same v1.Namespace object in federation
Updated the code as per comments. Ready for another look |
return err | ||
} | ||
|
||
// Remove kube_api.FinalizerKubernetes |
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.
The federated namespace is deleted before the underlying cluster namespaces are deleted from etcd, right? This is consistent with the mode of the garbage collector, i.e., asynchronous, but different from deletion of a cluster namespace, which is synchronous. I'm not sure if this is what you want.
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.
No. federated namespace will not be deleted unless the namespaces have been deleted in all underlying clusters.
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.
Where is it blocked? It seems the UpdateOnError is not blocking.
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.
Yes it was blocked until the Delete request succeeded for all clusters but it wasnt waiting for all resources to go away. Updated the code to wait.
Updated the controller to add a DeleteFederatedDependents finalizer before creating any dependent resources in sub clusters. This now ensures that the federation resource is not deleted unless all dependents have been removed. |
fcbc2c6
to
46c082d
Compare
Updated the code as discussed. I am now creating the finalizer in ObjectMeta.Finalizers instead of putting it in NamespaceSpec.Finalizers. |
Retrying unit test |
1 similar comment
Retrying unit test |
84dba9d
to
3ee605d
Compare
@@ -255,6 +350,21 @@ func (nc *NamespaceController) reconcileNamespace(namespace string) { | |||
return | |||
} | |||
|
|||
glog.V(3).Infof("Ensuring delete dependents finalizer for namespace: %s", baseNamespace.Name) | |||
// Add the DeleteFederatedDependents finalizer before creating a namespace in |
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.
Just ideas: DeleteUnderlyingClusterObjects, DeleteDependentsInUnderlyingClusters. Not sure if DeleteFederatedDependents
is intuitive. Your call.
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.
Renamed to DeleteFromUnderlyingClusters
} | ||
|
||
updatedNamespace = updatedNamespaceObj.(*api_v1.Namespace) | ||
err = nc.federatedApiClient.Core().Namespaces().Delete(updatedNamespace.Name, &api_v1.DeleteOptions{}) |
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.
Do you need to pass an empty deleteOptions? Can it be nil?
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.
Yes nil should work as well. Will try :)
// Right now there is just 5 types of objects: ReplicaSet, Secret, Ingress, Events and Service. | ||
if nc.hasFinalizerFuncInSpec(updatedNamespace, api_v1.FinalizerKubernetes) { | ||
// Delete resources in this namespace. | ||
updatedNamespace, err = nc.removeKubernetesFinalizer(updatedNamespace) |
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.
This function is deleteNamespaceResourcesAndRemoveNamespaceSpecFinalizer :) Maybe split it to two functions? "KubernetesFinalizer" is not clear.
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.
Yes, I can rename it to deleteNamespaceResourcesAndRemoveNamespaceSpecFinalizer but thats a bit long ;)
I think the current name is fine (its a private func).
I dont want to change that code much.
There is a TODO to make it consistent with the kubernetes code. We should be able to reuse the same code in kubernetes and federation to delete namespace resources.
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.
Ok. I still think "NamespaceSpecFinalizer" is more clear than "KubernetesFinalizer". Your call, as it's a private func.
There is a TODO to make it consistent with the kubernetes code. We should be able to reuse the same code in kubernetes and federation to delete namespace resources.
Not sure I follow this part. What kubernetes code are you referring to?
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.
To clarify, I named it removeKubernetesFinalizer because it removes the finalizer called FinalizerKubernetes.
Not sure I follow this part. What kubernetes code are you referring to?
kubernetes namespace controller also has the same code that deletes all resources in a namespace before removing the finalizer - same as what this function does.
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.
To clarify, I named it removeKubernetesFinalizer because it removes the finalizer called FinalizerKubernetes.
I think FinalizerKubernetes
is a bad name :)
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.
Yes now it is. It is clear now that we should have been more specific. I guess the thinking at that time was that this is the finalizer that kubernetes is adding to do its work. Now we have so many so its better to be specific.
@@ -108,11 +114,19 @@ func TestNamespaceController(t *testing.T) { | |||
|
|||
// Test add federated namespace. | |||
namespaceWatch.Add(&ns1) | |||
// Verify that the DeleteFederatedDependents finalizer is added to the namespace. | |||
// Note: finalize invokes the create action in Fake client. |
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.
That does sound like a bug? Could you open an issue?
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.
Fixing in #35478
} | ||
if len(operations) > 0 { | ||
// We have deleted a bunch of resources. | ||
// Wait for the store to observe all the deletions. |
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.
Where is the "wait" is implemented?
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.
Wait is implemented by not returning success here.
Since len(operations) > 0
we return here without removing the finalizer. Next time this function is called, we will again first compute if we want to do any operations in underlying clusters. If at any time, len(operation) = 0, then we proceed. Else we wait till len(operations) == 0.
Caller is expected to keep calling HandleObjectInUnderlyingClusters until it returns success (err == nil).
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.
I see. I didn't notice you called deliverNamespace
to process the namespace again in the future. So it looks good.
@@ -36,12 +36,13 @@ const ( | |||
) | |||
|
|||
// Create/delete ingress api objects | |||
var _ = framework.KubeDescribe("Federation namespace [Feature:Federation]", func() { | |||
var _ = framework.KubeDescribe("Federation namespace [Feature:Federation12]", func() { |
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.
What is Federation12?
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.
Will fix before committing.
@@ -2210,6 +2210,7 @@ func DumpEventsInNamespace(eventsLister EventsLister, namespace string) { | |||
events, err := eventsLister(v1.ListOptions{}, namespace) | |||
Expect(err).NotTo(HaveOccurred()) | |||
|
|||
By(fmt.Sprintf("Found %d events.", len(events.Items))) |
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.
Do you want to check in this code?
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.
Yes helps in debugging.
return obj, nil | ||
} | ||
namespace.ObjectMeta.Finalizers = newFinalizers | ||
namespace, err := nc.federatedApiClient.Core().Namespaces().Finalize(namespace) |
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.
Why not just call Update? Calling Finalize
looks like it's delete the namespace.spec.finalizer
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.
Why?
My expectation is that if only the list of finalizers are being modified, then we should use Finalize(). Else use update().
Is that not correct?
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.
No. Finalize
is a special method that only exists in the namespace client. So I think we should call Finalize()
only when we update the namespace.spec.finalizer
.
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.
oh ok. Hadnt realized the spec.Finalizer and ObjectMeta.Finalizer difference. You are right. Will update
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.
Fixed
} | ||
// Remove kube_api.FinalizerKubernetes | ||
if len(namespace.Spec.Finalizers) != 0 { | ||
return nc.removeFinalizerFromSpec(namespace, api_v1.FinalizerKubernetes) |
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.
I think you should check if all resources are actually deleted to make the deletion synchronous. Cluster namespace deletion will wait for all resources are deleted. Perhaps this will be easier to implement after you apply the deleteHelper pattern to other resources?
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.
I think you should check if all resources are actually deleted to make the deletion synchronous.
Yes this is not required right now since all deletions are immediate (there is no cascading deletion). Will need to update this before enabling cascading deletion for any of these resources.
The plan is to refactor kubernetes namespace controller code to make the namespace deletion code reusable and then use it here.
Leaving as is in this PR.
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.
Ok. Thanks for the explanation.
) | ||
|
||
const ( | ||
FinalizerDeleteFederatedDependents string = "federation.kubernetes.io/delete-federated-dependents" |
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.
Add a comment? Also mention the OrphanFinalizer will take precedence.
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.
done, thx
Verified that federation namespace e2e test is passing |
c286004
to
b95fac1
Compare
Replaced Finalize() by Update() as per the comment above and squashed commits. |
LGTM. Thanks @nikhiljindal ! |
Jenkins verification failed for commit b95fac161531a5df07b034d52047b2351b0bf5f9. Full PR test history. The magic incantation to run this job again is |
b95fac1
to
ae376a3
Compare
Trying to satisfy bazel and fix unit tests |
ae376a3
to
ebbbd02
Compare
Jenkins GCE e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins Kubemark GCE e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins GKE smoke e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins GCI GKE smoke e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins GCI GCE e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins GCE etcd3 e2e failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
Jenkins unit/integration failed for commit ebbbd02abc6ef6b4da535e39fc1493444771cb7d. Full PR test history. The magic incantation to run this job again is |
ebbbd02
to
f955d55
Compare
All tests passed. Adding back LGTM |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
Automatic merge from submit-queue |
Ref #33612
With this change, whenever a federated namespace is deleted with
DeleteOptions.OrphanDependents = false
, then federation namespace controller first deletes the corresponding namespaces from all underlying clusters before deleting the federated namespace.cc @kubernetes/sig-cluster-federation @caesarxuchao
This change is![Reviewable](https://camo.githubusercontent.com/2d899f4291d07d3cd2fa4aaae1e3b243f164c23fce87d30a589ace0d496a444c/68747470733a2f2f72657669657761626c652e6b756265726e657465732e696f2f7265766965775f627574746f6e2e737667)