|
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