|
|
|
@@ -43,13 +43,13 @@ type NamespacedResourcesDeleterInterface interface {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewNamespacedResourcesDeleter(nsClient v1clientset.NamespaceInterface,
|
|
|
|
|
clientPool dynamic.ClientPool, podsGetter v1clientset.PodsGetter,
|
|
|
|
|
dynamicClient dynamic.DynamicInterface, podsGetter v1clientset.PodsGetter,
|
|
|
|
|
discoverResourcesFn func() ([]*metav1.APIResourceList, error),
|
|
|
|
|
finalizerToken v1.FinalizerName, deleteNamespaceWhenDone bool) NamespacedResourcesDeleterInterface {
|
|
|
|
|
d := &namespacedResourcesDeleter{
|
|
|
|
|
nsClient: nsClient,
|
|
|
|
|
clientPool: clientPool,
|
|
|
|
|
podsGetter: podsGetter,
|
|
|
|
|
nsClient: nsClient,
|
|
|
|
|
dynamicClient: dynamicClient,
|
|
|
|
|
podsGetter: podsGetter,
|
|
|
|
|
opCache: &operationNotSupportedCache{
|
|
|
|
|
m: make(map[operationKey]bool),
|
|
|
|
|
},
|
|
|
|
@@ -68,7 +68,7 @@ type namespacedResourcesDeleter struct {
|
|
|
|
|
// Client to manipulate the namespace.
|
|
|
|
|
nsClient v1clientset.NamespaceInterface
|
|
|
|
|
// Dynamic client to list and delete all namespaced resources.
|
|
|
|
|
clientPool dynamic.ClientPool
|
|
|
|
|
dynamicClient dynamic.DynamicInterface
|
|
|
|
|
// Interface to get PodInterface.
|
|
|
|
|
podsGetter v1clientset.PodsGetter
|
|
|
|
|
// Cache of what operations are not supported on each group version resource.
|
|
|
|
@@ -328,9 +328,7 @@ func (d *namespacedResourcesDeleter) finalizeNamespace(namespace *v1.Namespace)
|
|
|
|
|
// deleteCollection is a helper function that will delete the collection of resources
|
|
|
|
|
// it returns true if the operation was supported on the server.
|
|
|
|
|
// it returns an error if the operation was supported on the server but was unable to complete.
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteCollection(
|
|
|
|
|
dynamicClient dynamic.Interface, gvr schema.GroupVersionResource,
|
|
|
|
|
namespace string) (bool, error) {
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteCollection(gvr schema.GroupVersionResource, namespace string) (bool, error) {
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteCollection - namespace: %s, gvr: %v", namespace, gvr)
|
|
|
|
|
|
|
|
|
|
key := operationKey{operation: operationDeleteCollection, gvr: gvr}
|
|
|
|
@@ -339,14 +337,12 @@ func (d *namespacedResourcesDeleter) deleteCollection(
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apiResource := metav1.APIResource{Name: gvr.Resource, Namespaced: true}
|
|
|
|
|
|
|
|
|
|
// namespace controller does not want the garbage collector to insert the orphan finalizer since it calls
|
|
|
|
|
// resource deletions generically. it will ensure all resources in the namespace are purged prior to releasing
|
|
|
|
|
// namespace itself.
|
|
|
|
|
background := metav1.DeletePropagationBackground
|
|
|
|
|
opts := &metav1.DeleteOptions{PropagationPolicy: &background}
|
|
|
|
|
err := dynamicClient.Resource(&apiResource, namespace).DeleteCollection(opts, metav1.ListOptions{})
|
|
|
|
|
err := d.dynamicClient.NamespacedResource(gvr, namespace).DeleteCollection(opts, metav1.ListOptions{})
|
|
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
return true, nil
|
|
|
|
@@ -373,8 +369,7 @@ func (d *namespacedResourcesDeleter) deleteCollection(
|
|
|
|
|
// the list of items in the collection (if found)
|
|
|
|
|
// a boolean if the operation is supported
|
|
|
|
|
// an error if the operation is supported but could not be completed.
|
|
|
|
|
func (d *namespacedResourcesDeleter) listCollection(
|
|
|
|
|
dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) (*unstructured.UnstructuredList, bool, error) {
|
|
|
|
|
func (d *namespacedResourcesDeleter) listCollection(gvr schema.GroupVersionResource, namespace string) (*unstructured.UnstructuredList, bool, error) {
|
|
|
|
|
glog.V(5).Infof("namespace controller - listCollection - namespace: %s, gvr: %v", namespace, gvr)
|
|
|
|
|
|
|
|
|
|
key := operationKey{operation: operationList, gvr: gvr}
|
|
|
|
@@ -383,13 +378,8 @@ func (d *namespacedResourcesDeleter) listCollection(
|
|
|
|
|
return nil, false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apiResource := metav1.APIResource{Name: gvr.Resource, Namespaced: true}
|
|
|
|
|
obj, err := dynamicClient.Resource(&apiResource, namespace).List(metav1.ListOptions{IncludeUninitialized: true})
|
|
|
|
|
unstructuredList, err := d.dynamicClient.NamespacedResource(gvr, namespace).List(metav1.ListOptions{IncludeUninitialized: true})
|
|
|
|
|
if err == nil {
|
|
|
|
|
unstructuredList, ok := obj.(*unstructured.UnstructuredList)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, false, fmt.Errorf("resource: %s, expected *unstructured.UnstructuredList, got %#v", apiResource.Name, obj)
|
|
|
|
|
}
|
|
|
|
|
return unstructuredList, true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -409,22 +399,20 @@ func (d *namespacedResourcesDeleter) listCollection(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deleteEachItem is a helper function that will list the collection of resources and delete each item 1 by 1.
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteEachItem(
|
|
|
|
|
dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) error {
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteEachItem(gvr schema.GroupVersionResource, namespace string) error {
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteEachItem - namespace: %s, gvr: %v", namespace, gvr)
|
|
|
|
|
|
|
|
|
|
unstructuredList, listSupported, err := d.listCollection(dynamicClient, gvr, namespace)
|
|
|
|
|
unstructuredList, listSupported, err := d.listCollection(gvr, namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if !listSupported {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
apiResource := metav1.APIResource{Name: gvr.Resource, Namespaced: true}
|
|
|
|
|
for _, item := range unstructuredList.Items {
|
|
|
|
|
background := metav1.DeletePropagationBackground
|
|
|
|
|
opts := &metav1.DeleteOptions{PropagationPolicy: &background}
|
|
|
|
|
if err = dynamicClient.Resource(&apiResource, namespace).Delete(item.GetName(), opts); err != nil && !errors.IsNotFound(err) && !errors.IsMethodNotSupported(err) {
|
|
|
|
|
if err = d.dynamicClient.NamespacedResource(gvr, namespace).Delete(item.GetName(), opts); err != nil && !errors.IsNotFound(err) && !errors.IsMethodNotSupported(err) {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -447,22 +435,15 @@ func (d *namespacedResourcesDeleter) deleteAllContentForGroupVersionResource(
|
|
|
|
|
}
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - estimate - namespace: %s, gvr: %v, estimate: %v", namespace, gvr, estimate)
|
|
|
|
|
|
|
|
|
|
// get a client for this group version...
|
|
|
|
|
dynamicClient, err := d.clientPool.ClientForGroupVersionResource(gvr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - unable to get client - namespace: %s, gvr: %v, err: %v", namespace, gvr, err)
|
|
|
|
|
return estimate, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// first try to delete the entire collection
|
|
|
|
|
deleteCollectionSupported, err := d.deleteCollection(dynamicClient, gvr, namespace)
|
|
|
|
|
deleteCollectionSupported, err := d.deleteCollection(gvr, namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return estimate, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete collection was not supported, so we list and delete each item...
|
|
|
|
|
if !deleteCollectionSupported {
|
|
|
|
|
err = d.deleteEachItem(dynamicClient, gvr, namespace)
|
|
|
|
|
err = d.deleteEachItem(gvr, namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return estimate, err
|
|
|
|
|
}
|
|
|
|
@@ -471,7 +452,7 @@ func (d *namespacedResourcesDeleter) deleteAllContentForGroupVersionResource(
|
|
|
|
|
// verify there are no more remaining items
|
|
|
|
|
// it is not an error condition for there to be remaining items if local estimate is non-zero
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - checking for no more items in namespace: %s, gvr: %v", namespace, gvr)
|
|
|
|
|
unstructuredList, listSupported, err := d.listCollection(dynamicClient, gvr, namespace)
|
|
|
|
|
unstructuredList, listSupported, err := d.listCollection(gvr, namespace)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - error verifying no items in namespace: %s, gvr: %v, err: %v", namespace, gvr, err)
|
|
|
|
|
return estimate, err
|
|
|
|
@@ -497,8 +478,7 @@ func (d *namespacedResourcesDeleter) deleteAllContentForGroupVersionResource(
|
|
|
|
|
// deleteAllContent will use the dynamic client to delete each resource identified in groupVersionResources.
|
|
|
|
|
// It returns an estimate of the time remaining before the remaining resources are deleted.
|
|
|
|
|
// If estimate > 0, not all resources are guaranteed to be gone.
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteAllContent(
|
|
|
|
|
namespace string, namespaceDeletedAt metav1.Time) (int64, error) {
|
|
|
|
|
func (d *namespacedResourcesDeleter) deleteAllContent(namespace string, namespaceDeletedAt metav1.Time) (int64, error) {
|
|
|
|
|
estimate := int64(0)
|
|
|
|
|
glog.V(4).Infof("namespace controller - deleteAllContent - namespace: %s", namespace)
|
|
|
|
|
resources, err := d.discoverResourcesFn()
|
|
|
|
|