...

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

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

     1  /*
     2  Copyright 2021 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 diff
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	corev1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/apimachinery/pkg/util/sets"
    29  	"k8s.io/cli-runtime/pkg/resource"
    30  	"k8s.io/client-go/dynamic"
    31  	"k8s.io/kubectl/pkg/util/prune"
    32  )
    33  
    34  type tracker struct {
    35  	visitedUids       sets.Set[types.UID]
    36  	visitedNamespaces sets.Set[string]
    37  }
    38  
    39  func newTracker() *tracker {
    40  	return &tracker{
    41  		visitedUids:       sets.New[types.UID](),
    42  		visitedNamespaces: sets.New[string](),
    43  	}
    44  }
    45  
    46  type pruner struct {
    47  	mapper        meta.RESTMapper
    48  	dynamicClient dynamic.Interface
    49  
    50  	labelSelector string
    51  	resources     []prune.Resource
    52  }
    53  
    54  func newPruner(dc dynamic.Interface, m meta.RESTMapper, r []prune.Resource, selector string) *pruner {
    55  	return &pruner{
    56  		dynamicClient: dc,
    57  		mapper:        m,
    58  		resources:     r,
    59  		labelSelector: selector,
    60  	}
    61  }
    62  
    63  func (p *pruner) pruneAll(tracker *tracker, namespaceSpecified bool) ([]runtime.Object, error) {
    64  	var allPruned []runtime.Object
    65  	namespacedRESTMappings, nonNamespacedRESTMappings, err := prune.GetRESTMappings(p.mapper, p.resources, namespaceSpecified)
    66  	if err != nil {
    67  		return allPruned, fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
    68  	}
    69  
    70  	for n := range tracker.visitedNamespaces {
    71  		for _, m := range namespacedRESTMappings {
    72  			if pobjs, err := p.prune(tracker, n, m); err != nil {
    73  				return pobjs, fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
    74  			} else {
    75  				allPruned = append(allPruned, pobjs...)
    76  			}
    77  		}
    78  	}
    79  	for _, m := range nonNamespacedRESTMappings {
    80  		if pobjs, err := p.prune(tracker, metav1.NamespaceNone, m); err != nil {
    81  			return allPruned, fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
    82  		} else {
    83  			allPruned = append(allPruned, pobjs...)
    84  		}
    85  	}
    86  
    87  	return allPruned, nil
    88  }
    89  
    90  func (p *pruner) prune(tracker *tracker, namespace string, mapping *meta.RESTMapping) ([]runtime.Object, error) {
    91  	objList, err := p.dynamicClient.Resource(mapping.Resource).
    92  		Namespace(namespace).
    93  		List(context.TODO(), metav1.ListOptions{
    94  			LabelSelector: p.labelSelector,
    95  		})
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	objs, err := meta.ExtractList(objList)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	var pobjs []runtime.Object
   106  	for _, obj := range objs {
   107  		metadata, err := meta.Accessor(obj)
   108  		if err != nil {
   109  			return pobjs, err
   110  		}
   111  		annots := metadata.GetAnnotations()
   112  		if _, ok := annots[corev1.LastAppliedConfigAnnotation]; !ok {
   113  			continue
   114  		}
   115  		uid := metadata.GetUID()
   116  		if tracker.visitedUids.Has(uid) {
   117  			continue
   118  		}
   119  
   120  		pobjs = append(pobjs, obj)
   121  	}
   122  	return pobjs, nil
   123  }
   124  
   125  // MarkVisited marks visited namespaces and uids
   126  func (t *tracker) MarkVisited(info *resource.Info) {
   127  	if info.Namespaced() {
   128  		t.visitedNamespaces.Insert(info.Namespace)
   129  	}
   130  
   131  	metadata, err := meta.Accessor(info.Object)
   132  	if err != nil {
   133  		return
   134  	}
   135  	t.visitedUids.Insert(metadata.GetUID())
   136  }
   137  

View as plain text