|
1 | 1 | package k8s
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "fmt" |
5 |
| - "strings" |
6 |
| - |
7 |
| - "github.com/Jeffail/gabs/v2" |
8 |
| - json "github.com/json-iterator/go" |
9 | 4 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
10 | 5 | )
|
11 | 6 |
|
12 | 7 | // SecretSelectedFields is the list of fields sent from Secret objects to the
|
13 | 8 | // backend
|
14 |
| -var SecretSelectedFields = []string{ |
15 |
| - "kind", |
16 |
| - "apiVersion", |
17 |
| - "metadata.annotations", |
18 |
| - "metadata.labels", |
19 |
| - "metadata.name", |
20 |
| - "metadata.namespace", |
21 |
| - "metadata.ownerReferences", |
22 |
| - "metadata.selfLink", |
23 |
| - "metadata.uid", |
24 |
| - "type", |
25 |
| - "/data/tls.crt", |
26 |
| - "/data/ca.crt", |
| 9 | +var SecretSelectedFields = []FieldPath{ |
| 10 | + {"kind"}, |
| 11 | + {"apiVersion"}, |
| 12 | + {"metadata", "annotations"}, |
| 13 | + {"metadata", "labels"}, |
| 14 | + {"metadata", "name"}, |
| 15 | + {"metadata", "namespace"}, |
| 16 | + {"metadata", "ownerReferences"}, |
| 17 | + {"metadata", "selfLink"}, |
| 18 | + {"metadata", "uid"}, |
| 19 | + |
| 20 | + {"type"}, |
| 21 | + {"data", "tls.crt"}, |
| 22 | + {"data", "ca.crt"}, |
27 | 23 | }
|
28 | 24 |
|
29 | 25 | // RouteSelectedFields is the list of fields sent from OpenShift Route objects to the
|
30 | 26 | // backend
|
31 |
| -var RouteSelectedFields = []string{ |
32 |
| - "kind", |
33 |
| - "apiVersion", |
34 |
| - "metadata.annotations", |
35 |
| - "metadata.name", |
36 |
| - "metadata.namespace", |
37 |
| - "metadata.ownerReferences", |
38 |
| - "metadata.selfLink", |
39 |
| - "metadata.uid", |
40 |
| - "spec.host", |
41 |
| - "spec.to.kind", |
42 |
| - "spec.to.port", |
43 |
| - "spec.to.name", |
44 |
| - "spec.to.weight", |
45 |
| - "spec.tls.termination", |
46 |
| - "spec.tls.certificate", |
47 |
| - "spec.tls.caCertificate", |
48 |
| - "spec.tls.destinationCACertificate", |
49 |
| - "spec.tls.insecureEdgeTerminationPolicy", |
50 |
| - "spec.wildcardPolicy", |
51 |
| - "status", |
| 27 | +var RouteSelectedFields = []FieldPath{ |
| 28 | + {"kind"}, |
| 29 | + {"apiVersion"}, |
| 30 | + {"metadata", "annotations"}, |
| 31 | + {"metadata", "name"}, |
| 32 | + {"metadata", "namespace"}, |
| 33 | + {"metadata", "ownerReferences"}, |
| 34 | + {"metadata", "selfLink"}, |
| 35 | + {"metadata", "uid"}, |
| 36 | + |
| 37 | + {"spec", "host"}, |
| 38 | + {"spec", "to", "kind"}, |
| 39 | + {"spec", "to", "name"}, |
| 40 | + {"spec", "to", "weight"}, |
| 41 | + {"spec", "tls", "termination"}, |
| 42 | + {"spec", "tls", "certificate"}, |
| 43 | + {"spec", "tls", "caCertificate"}, |
| 44 | + {"spec", "tls", "destinationCACertificate"}, |
| 45 | + {"spec", "tls", "insecureEdgeTerminationPolicy"}, |
| 46 | + {"spec", "wildcardPolicy"}, |
| 47 | + {"status"}, |
52 | 48 | }
|
53 | 49 |
|
54 | 50 | // RedactFields are removed from all objects
|
55 |
| -var RedactFields = []string{ |
56 |
| - "metadata.managedFields", |
57 |
| - "/metadata/annotations/kubectl.kubernetes.io~1last-applied-configuration", |
| 51 | +var RedactFields = []FieldPath{ |
| 52 | + {"metadata", "managedFields"}, |
| 53 | + {"metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration"}, |
58 | 54 | }
|
59 | 55 |
|
60 |
| -// Select removes all but the supplied fields from the resource |
61 |
| -func Select(fields []string, resource *unstructured.Unstructured) error { |
62 |
| - // convert the object to JSON for field filtering |
63 |
| - asJSON, err := json.Marshal(resource) |
64 |
| - if err != nil { |
65 |
| - return fmt.Errorf("failed to marshal json for resource: %s", err) |
66 |
| - } |
| 56 | +type FieldPath []string |
67 | 57 |
|
68 |
| - // parse the JSON for processing in gabs |
69 |
| - jsonParsed, err := gabs.ParseJSON(asJSON) |
70 |
| - if err != nil { |
71 |
| - return fmt.Errorf("failed to parse generated json for resource: %s", err) |
| 58 | +// Select removes all but the supplied fields from the resource |
| 59 | +func Select(fields []FieldPath, resource *unstructured.Unstructured) error { |
| 60 | + newResource := unstructured.Unstructured{ |
| 61 | + Object: map[string]interface{}{}, |
72 | 62 | }
|
73 | 63 |
|
74 |
| - // craft a new object containing only selected fields |
75 |
| - filteredObject := gabs.New() |
76 |
| - for _, v := range fields { |
77 |
| - // also support JSONPointers for keys containing '.' chars |
78 |
| - if strings.HasPrefix(v, "/") { |
79 |
| - gObject, err := jsonParsed.JSONPointer(v) |
80 |
| - if err != nil { |
81 |
| - // fail to select field if missing, just continue |
82 |
| - continue |
83 |
| - } |
84 |
| - pathComponents, err := gabs.JSONPointerToSlice(v) |
85 |
| - if err != nil { |
86 |
| - return fmt.Errorf("invalid JSONPointer: %s", v) |
87 |
| - } |
88 |
| - filteredObject.Set(gObject.Data(), pathComponents...) |
89 |
| - } else { |
90 |
| - if jsonParsed.ExistsP(v) { |
91 |
| - filteredObject.SetP(jsonParsed.Path(v).Data(), v) |
92 |
| - } |
| 64 | + for _, field := range fields { |
| 65 | + value, found, err := unstructured.NestedFieldNoCopy(resource.Object, field...) |
| 66 | + if err != nil { |
| 67 | + return err |
| 68 | + } |
| 69 | + if !found { |
| 70 | + continue |
| 71 | + } |
| 72 | + if err := unstructured.SetNestedField(newResource.Object, value, field...); err != nil { |
| 73 | + return err |
93 | 74 | }
|
94 | 75 | }
|
95 | 76 |
|
96 |
| - // load the filtered JSON back into the resource |
97 |
| - err = json.Unmarshal(filteredObject.Bytes(), resource) |
98 |
| - if err != nil { |
99 |
| - return fmt.Errorf("failed to update resource: %s", err) |
100 |
| - } |
| 77 | + resource.Object = newResource.Object |
101 | 78 |
|
102 | 79 | return nil
|
103 | 80 | }
|
104 | 81 |
|
105 | 82 | // Redact removes the supplied fields from the resource
|
106 |
| -func Redact(fields []string, resource *unstructured.Unstructured) error { |
107 |
| - // convert the object to JSON for field filtering |
108 |
| - asJSON, err := json.Marshal(resource) |
109 |
| - if err != nil { |
110 |
| - return fmt.Errorf("failed to marshal json for resource: %s", err) |
111 |
| - } |
112 |
| - |
113 |
| - // parse the JSON for processing in gabs |
114 |
| - jsonParsed, err := gabs.ParseJSON(asJSON) |
115 |
| - if err != nil { |
116 |
| - return fmt.Errorf("failed to parse generated json for resource: %s", err) |
117 |
| - } |
118 |
| - |
119 |
| - // craft a new object excluding redacted fields |
120 |
| - for _, v := range fields { |
121 |
| - // also support JSONPointers for keys containing '.' chars |
122 |
| - if strings.HasPrefix(v, "/") { |
123 |
| - pathComponents, err := gabs.JSONPointerToSlice(v) |
124 |
| - if err != nil { |
125 |
| - return fmt.Errorf("invalid JSONPointer: %s", v) |
126 |
| - } |
127 |
| - if jsonParsed.Exists(pathComponents...) { |
128 |
| - jsonParsed.Delete(pathComponents...) |
129 |
| - } |
130 |
| - } else { |
131 |
| - if jsonParsed.ExistsP(v) { |
132 |
| - jsonParsed.DeleteP(v) |
133 |
| - } |
134 |
| - } |
135 |
| - } |
136 |
| - |
137 |
| - // load the filtered JSON back into the resource |
138 |
| - err = json.Unmarshal(jsonParsed.Bytes(), resource) |
139 |
| - if err != nil { |
140 |
| - return fmt.Errorf("failed to update resource: %s", err) |
| 83 | +func Redact(fields []FieldPath, resource *unstructured.Unstructured) error { |
| 84 | + for _, field := range fields { |
| 85 | + unstructured.RemoveNestedField(resource.Object, field...) |
141 | 86 | }
|
142 | 87 |
|
143 | 88 | return nil
|
|
0 commit comments