...

Source file src/k8s.io/kubectl/pkg/cmd/apply/prune.go

Documentation: k8s.io/kubectl/pkg/cmd/apply

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package apply
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/meta"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/apimachinery/pkg/util/sets"
    29  	"k8s.io/cli-runtime/pkg/printers"
    30  	"k8s.io/client-go/dynamic"
    31  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    32  	"k8s.io/kubectl/pkg/util/prune"
    33  )
    34  
    35  type pruner struct {
    36  	mapper        meta.RESTMapper
    37  	dynamicClient dynamic.Interface
    38  
    39  	visitedUids       sets.Set[types.UID]
    40  	visitedNamespaces sets.Set[string]
    41  	labelSelector     string
    42  	fieldSelector     string
    43  
    44  	cascadingStrategy metav1.DeletionPropagation
    45  	dryRunStrategy    cmdutil.DryRunStrategy
    46  	gracePeriod       int
    47  
    48  	toPrinter func(string) (printers.ResourcePrinter, error)
    49  
    50  	out io.Writer
    51  }
    52  
    53  func newPruner(o *ApplyOptions) pruner {
    54  	return pruner{
    55  		mapper:        o.Mapper,
    56  		dynamicClient: o.DynamicClient,
    57  
    58  		labelSelector:     o.Selector,
    59  		visitedUids:       o.VisitedUids,
    60  		visitedNamespaces: o.VisitedNamespaces,
    61  
    62  		cascadingStrategy: o.DeleteOptions.CascadingStrategy,
    63  		dryRunStrategy:    o.DryRunStrategy,
    64  		gracePeriod:       o.DeleteOptions.GracePeriod,
    65  
    66  		toPrinter: o.ToPrinter,
    67  
    68  		out: o.Out,
    69  	}
    70  }
    71  
    72  func (p *pruner) pruneAll(o *ApplyOptions) error {
    73  
    74  	namespacedRESTMappings, nonNamespacedRESTMappings, err := prune.GetRESTMappings(o.Mapper, o.PruneResources, o.Namespace != "")
    75  	if err != nil {
    76  		return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
    77  	}
    78  
    79  	for n := range p.visitedNamespaces {
    80  		for _, m := range namespacedRESTMappings {
    81  			if err := p.prune(n, m); err != nil {
    82  				return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
    83  			}
    84  		}
    85  	}
    86  
    87  	for _, m := range nonNamespacedRESTMappings {
    88  		if err := p.prune(metav1.NamespaceNone, m); err != nil {
    89  			return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
    90  		}
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  func (p *pruner) prune(namespace string, mapping *meta.RESTMapping) error {
    97  	objList, err := p.dynamicClient.Resource(mapping.Resource).
    98  		Namespace(namespace).
    99  		List(context.TODO(), metav1.ListOptions{
   100  			LabelSelector: p.labelSelector,
   101  			FieldSelector: p.fieldSelector,
   102  		})
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	objs, err := meta.ExtractList(objList)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	for _, obj := range objs {
   113  		metadata, err := meta.Accessor(obj)
   114  		if err != nil {
   115  			return err
   116  		}
   117  		annots := metadata.GetAnnotations()
   118  		if _, ok := annots[corev1.LastAppliedConfigAnnotation]; !ok {
   119  			// don't prune resources not created with apply
   120  			continue
   121  		}
   122  		uid := metadata.GetUID()
   123  		if p.visitedUids.Has(uid) {
   124  			continue
   125  		}
   126  		name := metadata.GetName()
   127  		if p.dryRunStrategy != cmdutil.DryRunClient {
   128  			if err := p.delete(namespace, name, mapping); err != nil {
   129  				return err
   130  			}
   131  		}
   132  
   133  		printer, err := p.toPrinter("pruned")
   134  		if err != nil {
   135  			return err
   136  		}
   137  		printer.PrintObj(obj, p.out)
   138  	}
   139  	return nil
   140  }
   141  
   142  func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
   143  	ctx := context.TODO()
   144  	return runDelete(ctx, namespace, name, mapping, p.dynamicClient, p.cascadingStrategy, p.gracePeriod, p.dryRunStrategy == cmdutil.DryRunServer)
   145  }
   146  
   147  func runDelete(ctx context.Context, namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascadingStrategy metav1.DeletionPropagation, gracePeriod int, serverDryRun bool) error {
   148  	options := asDeleteOptions(cascadingStrategy, gracePeriod)
   149  	if serverDryRun {
   150  		options.DryRun = []string{metav1.DryRunAll}
   151  	}
   152  	return c.Resource(mapping.Resource).Namespace(namespace).Delete(ctx, name, options)
   153  }
   154  
   155  func asDeleteOptions(cascadingStrategy metav1.DeletionPropagation, gracePeriod int) metav1.DeleteOptions {
   156  	options := metav1.DeleteOptions{}
   157  	if gracePeriod >= 0 {
   158  		options = *metav1.NewDeleteOptions(int64(gracePeriod))
   159  	}
   160  	options.PropagationPolicy = &cascadingStrategy
   161  	return options
   162  }
   163  

View as plain text