1
2
3
4
5 package object
6
7 import (
8 "fmt"
9
10 "k8s.io/apimachinery/pkg/api/meta"
11 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12 "k8s.io/apimachinery/pkg/runtime/schema"
13 "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
14 )
15
16 var (
17 namespaceGK = schema.GroupKind{Group: "", Kind: "Namespace"}
18 crdGK = schema.GroupKind{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"}
19 )
20
21
22 func UnstructuredSetToObjMetadataSet(objs UnstructuredSet) ObjMetadataSet {
23 objMetas := make([]ObjMetadata, len(objs))
24 for i, obj := range objs {
25 objMetas[i] = UnstructuredToObjMetadata(obj)
26 }
27 return objMetas
28 }
29
30
31
32 func UnstructuredToObjMetadata(obj *unstructured.Unstructured) ObjMetadata {
33 return ObjMetadata{
34 Namespace: obj.GetNamespace(),
35 Name: obj.GetName(),
36 GroupKind: obj.GroupVersionKind().GroupKind(),
37 }
38 }
39
40
41
42 func IsKindNamespace(u *unstructured.Unstructured) bool {
43 if u == nil {
44 return false
45 }
46 gvk := u.GroupVersionKind()
47 return namespaceGK == gvk.GroupKind()
48 }
49
50
51
52 func IsNamespaced(u *unstructured.Unstructured) bool {
53 if u == nil {
54 return false
55 }
56 return u.GetNamespace() != ""
57 }
58
59
60
61 func IsNamespace(u *unstructured.Unstructured) bool {
62 if u == nil {
63 return false
64 }
65 gvk := u.GroupVersionKind()
66
67 return gvk.Group == "" && gvk.Kind == "Namespace"
68 }
69
70
71
72 func IsCRD(u *unstructured.Unstructured) bool {
73 if u == nil {
74 return false
75 }
76 gvk := u.GroupVersionKind()
77 return crdGK == gvk.GroupKind()
78 }
79
80
81
82
83 func GetCRDGroupKind(u *unstructured.Unstructured) (schema.GroupKind, bool) {
84 emptyGroupKind := schema.GroupKind{Group: "", Kind: ""}
85 if u == nil {
86 return emptyGroupKind, false
87 }
88 group, found, err := unstructured.NestedString(u.Object, "spec", "group")
89 if found && err == nil {
90 kind, found, err := unstructured.NestedString(u.Object, "spec", "names", "kind")
91 if found && err == nil {
92 return schema.GroupKind{Group: group, Kind: kind}, true
93 }
94 }
95 return emptyGroupKind, false
96 }
97
98
99
100 type UnknownTypeError struct {
101 GroupVersionKind schema.GroupVersionKind
102 }
103
104 func (e *UnknownTypeError) Error() string {
105 return fmt.Sprintf("unknown resource type: %q", e.GroupVersionKind.String())
106 }
107
108
109
110
111
112 func LookupResourceScope(u *unstructured.Unstructured, crds []*unstructured.Unstructured, mapper meta.RESTMapper) (meta.RESTScope, error) {
113 gvk := u.GroupVersionKind()
114
115
116 mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
117 if err == nil {
118
119 return mapping.Scope, nil
120 }
121
122
123 if !meta.IsNoMatchError(err) {
124 return nil, err
125 }
126
127
128
129 for _, crd := range crds {
130 group, found, err := NestedField(crd.Object, "spec", "group")
131 if err != nil {
132 return nil, err
133 }
134 if !found || group == "" {
135 return nil, NotFound([]interface{}{"spec", "group"}, group)
136 }
137 kind, found, err := NestedField(crd.Object, "spec", "names", "kind")
138 if err != nil {
139 return nil, err
140 }
141 if !found || kind == "" {
142 return nil, NotFound([]interface{}{"spec", "kind"}, group)
143 }
144 if gvk.Kind != kind || gvk.Group != group {
145 continue
146 }
147 versionDefined, err := crdDefinesVersion(crd, gvk.Version)
148 if err != nil {
149 return nil, err
150 }
151 if !versionDefined {
152 return nil, &UnknownTypeError{
153 GroupVersionKind: gvk,
154 }
155 }
156 scopeName, _, err := NestedField(crd.Object, "spec", "scope")
157 if err != nil {
158 return nil, err
159 }
160 switch scopeName {
161 case "Namespaced":
162 return meta.RESTScopeNamespace, nil
163 case "Cluster":
164 return meta.RESTScopeRoot, nil
165 default:
166 return nil, Invalid([]interface{}{"spec", "scope"}, scopeName,
167 "expected Namespaced or Cluster")
168 }
169 }
170 return nil, &UnknownTypeError{
171 GroupVersionKind: gvk,
172 }
173 }
174
175 func crdDefinesVersion(crd *unstructured.Unstructured, version string) (bool, error) {
176 versions, found, err := NestedField(crd.Object, "spec", "versions")
177 if err != nil {
178 return false, err
179 }
180 if !found {
181 return false, NotFound([]interface{}{"spec", "versions"}, versions)
182 }
183 versionsSlice, ok := versions.([]interface{})
184 if !ok {
185 return false, InvalidType([]interface{}{"spec", "versions"}, versions, "[]interface{}")
186 }
187 if len(versionsSlice) == 0 {
188 return false, Invalid([]interface{}{"spec", "versions"}, versionsSlice, "must not be empty")
189 }
190 for i := range versionsSlice {
191 name, found, err := NestedField(crd.Object, "spec", "versions", i, "name")
192 if err != nil {
193 return false, err
194 }
195 if !found {
196 return false, NotFound([]interface{}{"spec", "versions", i, "name"}, name)
197 }
198 if name == version {
199 return true, nil
200 }
201 }
202 return false, nil
203 }
204
205
206
207 func StripKyamlAnnotations(u *unstructured.Unstructured) {
208 annos := u.GetAnnotations()
209 delete(annos, kioutil.PathAnnotation)
210 delete(annos, kioutil.LegacyPathAnnotation)
211 delete(annos, kioutil.IndexAnnotation)
212 delete(annos, kioutil.LegacyIndexAnnotation)
213 u.SetAnnotations(annos)
214 }
215
View as plain text