1
16
17 package prune
18
19 import (
20 "fmt"
21 "strings"
22
23 "k8s.io/apimachinery/pkg/api/meta"
24 "k8s.io/apimachinery/pkg/runtime/schema"
25 "k8s.io/klog/v2"
26 )
27
28
29 var defaultNamespacedPruneResources = []Resource{
30 {"", "v1", "ConfigMap", true},
31 {"", "v1", "Endpoints", true},
32 {"", "v1", "PersistentVolumeClaim", true},
33 {"", "v1", "Pod", true},
34 {"", "v1", "ReplicationController", true},
35 {"", "v1", "Secret", true},
36 {"", "v1", "Service", true},
37 {"batch", "v1", "Job", true},
38 {"batch", "v1", "CronJob", true},
39 {"networking.k8s.io", "v1", "Ingress", true},
40 {"apps", "v1", "DaemonSet", true},
41 {"apps", "v1", "Deployment", true},
42 {"apps", "v1", "ReplicaSet", true},
43 {"apps", "v1", "StatefulSet", true},
44 }
45
46
47 var defaultNonNamespacedPruneResources = []Resource{
48 {"", "v1", "Namespace", false},
49 {"", "v1", "PersistentVolume", false},
50 }
51
52 type Resource struct {
53 group string
54 version string
55 kind string
56 namespaced bool
57 }
58
59 func (pr Resource) String() string {
60 return fmt.Sprintf("%v/%v, Kind=%v, Namespaced=%v", pr.group, pr.version, pr.kind, pr.namespaced)
61 }
62
63
64
65 func GetRESTMappings(mapper meta.RESTMapper, pruneResources []Resource, namespaceSpecified bool) (namespaced, nonNamespaced []*meta.RESTMapping, err error) {
66 if len(pruneResources) == 0 {
67 pruneResources = defaultNamespacedPruneResources
68
69 pruneResources = append(pruneResources, defaultNonNamespacedPruneResources...)
70 if namespaceSpecified {
71 klog.Warning("Deprecated: kubectl apply will no longer prune non-namespaced resources by default when used with the --namespace flag in a future release. To preserve the current behaviour, list the resources you want to target explicitly in the --prune-allowlist flag.")
72 }
73 }
74
75 for _, resource := range pruneResources {
76 addedMapping, err := mapper.RESTMapping(schema.GroupKind{Group: resource.group, Kind: resource.kind}, resource.version)
77 if err != nil {
78 return nil, nil, fmt.Errorf("invalid resource %v: %v", resource, err)
79 }
80 if resource.namespaced {
81 namespaced = append(namespaced, addedMapping)
82 } else {
83 nonNamespaced = append(nonNamespaced, addedMapping)
84 }
85 }
86
87 return namespaced, nonNamespaced, nil
88 }
89
90 func ParseResources(mapper meta.RESTMapper, gvks []string) ([]Resource, error) {
91 pruneResources := []Resource{}
92 for _, groupVersionKind := range gvks {
93 gvk := strings.Split(groupVersionKind, "/")
94 if len(gvk) != 3 {
95 return nil, fmt.Errorf("invalid GroupVersionKind format: %v, please follow <group/version/kind>", groupVersionKind)
96 }
97
98 if gvk[0] == "core" {
99 gvk[0] = ""
100 }
101 mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk[0], Kind: gvk[2]}, gvk[1])
102 if err != nil {
103 return pruneResources, err
104 }
105 var namespaced bool
106 namespaceScope := mapping.Scope.Name()
107 switch namespaceScope {
108 case meta.RESTScopeNameNamespace:
109 namespaced = true
110 case meta.RESTScopeNameRoot:
111 namespaced = false
112 default:
113 return pruneResources, fmt.Errorf("Unknown namespace scope: %q", namespaceScope)
114 }
115
116 pruneResources = append(pruneResources, Resource{gvk[0], gvk[1], gvk[2], namespaced})
117 }
118 return pruneResources, nil
119 }
120
View as plain text