@@ -2,9 +2,13 @@ package validatingroundtripper
2
2
3
3
import (
4
4
"fmt"
5
+ "io"
5
6
"net/http"
6
7
"os"
7
8
9
+ "k8s.io/apimachinery/pkg/runtime"
10
+ "k8s.io/apimachinery/pkg/runtime/serializer"
11
+
8
12
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
9
13
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
10
14
"k8s.io/apimachinery/pkg/util/yaml"
@@ -13,23 +17,71 @@ import (
13
17
14
18
type validatingRoundTripper struct {
15
19
delegate http.RoundTripper
20
+ codecs serializer.CodecFactory
21
+ }
22
+
23
+ func (rt * validatingRoundTripper ) decodeYAMLOrJSON (body io.Reader ) (* unstructured.Unstructured , error ) {
24
+ dec := yaml .NewYAMLOrJSONDecoder (body , 10 )
25
+ unstructuredObject := & unstructured.Unstructured {}
26
+ if err := dec .Decode (unstructuredObject ); err != nil {
27
+ return nil , fmt .Errorf ("error decoding yaml/json object to an unstructured object: %w" , err )
28
+ }
29
+ return unstructuredObject , nil
30
+ }
31
+
32
+ func (rt * validatingRoundTripper ) decodeProtobuf (body io.Reader ) (* unstructured.Unstructured , error ) {
33
+ data , err := io .ReadAll (body )
34
+ if err != nil {
35
+ panic (fmt .Errorf ("failed to read request body: %w" , err ))
36
+ }
37
+
38
+ decoder := rt .codecs .UniversalDeserializer ()
39
+ obj , _ , err := decoder .Decode (data , nil , nil )
40
+ if err != nil {
41
+ return nil , fmt .Errorf ("failed to decode protobuf data: %w" , err )
42
+ }
43
+
44
+ unstructuredObj , err := runtime .DefaultUnstructuredConverter .ToUnstructured (obj )
45
+ if err != nil {
46
+ return nil , fmt .Errorf ("failed to convert object to unstructured: %w" , err )
47
+ }
48
+
49
+ return & unstructured.Unstructured {Object : unstructuredObj }, nil
50
+ }
51
+
52
+ func (rt * validatingRoundTripper ) decodeRequestBody (req * http.Request ) * unstructured.Unstructured {
53
+ b , err := req .GetBody ()
54
+ if err != nil {
55
+ panic (fmt .Errorf ("failed to get request body: %w" , err ))
56
+ }
57
+ defer b .Close ()
58
+
59
+ var unstructuredObject * unstructured.Unstructured
60
+ switch req .Header .Get ("Content-Type" ) {
61
+ case "application/vnd.kubernetes.protobuf" :
62
+ unstructuredObject , err = rt .decodeProtobuf (b )
63
+ default :
64
+ unstructuredObject , err = rt .decodeYAMLOrJSON (b )
65
+ }
66
+
67
+ if err != nil {
68
+ panic (fmt .Errorf ("failed to decode request body: %w" , err ))
69
+ }
70
+
71
+ return unstructuredObject
16
72
}
17
73
18
74
func (rt * validatingRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
19
75
if req .Method == "POST" {
20
- b , err := req .GetBody ()
21
- if err != nil {
22
- panic (err )
23
- }
24
- dec := yaml .NewYAMLOrJSONDecoder (b , 10 )
25
- unstructuredObject := & unstructured.Unstructured {}
26
- if err := dec .Decode (unstructuredObject ); err != nil {
27
- panic (fmt .Errorf ("error decoding object to an unstructured object: %w" , err ))
28
- }
76
+ unstructuredObject := rt .decodeRequestBody (req )
29
77
gvk := unstructuredObject .GroupVersionKind ()
30
78
if gvk .Kind != "Event" {
31
- if labels := unstructuredObject .GetLabels (); labels [install .OLMManagedLabelKey ] != install .OLMManagedLabelValue {
32
- panic (fmt .Errorf ("%s.%s/%v %s/%s does not have labels[%s]=%s" , gvk .Kind , gvk .Group , gvk .Version , unstructuredObject .GetNamespace (), unstructuredObject .GetName (), install .OLMManagedLabelKey , install .OLMManagedLabelValue ))
79
+ labels := unstructuredObject .GetLabels ()
80
+ if labels [install .OLMManagedLabelKey ] != install .OLMManagedLabelValue {
81
+ panic (fmt .Errorf ("%s.%s/%v %s/%s does not have labels[%s]=%s" ,
82
+ gvk .Kind , gvk .Group , gvk .Version ,
83
+ unstructuredObject .GetNamespace (), unstructuredObject .GetName (),
84
+ install .OLMManagedLabelKey , install .OLMManagedLabelValue ))
33
85
}
34
86
}
35
87
}
@@ -40,14 +92,17 @@ var _ http.RoundTripper = (*validatingRoundTripper)(nil)
40
92
41
93
// Wrap is meant to be used in developer environments and CI to make it easy to find places
42
94
// where we accidentally create Kubernetes objects without our management label.
43
- func Wrap (cfg * rest.Config ) * rest.Config {
95
+ func Wrap (cfg * rest.Config , scheme * runtime. Scheme ) * rest.Config {
44
96
if _ , set := os .LookupEnv ("CI" ); ! set {
45
97
return cfg
46
98
}
47
99
48
100
cfgCopy := * cfg
49
101
cfgCopy .Wrap (func (rt http.RoundTripper ) http.RoundTripper {
50
- return & validatingRoundTripper {delegate : rt }
102
+ return & validatingRoundTripper {
103
+ delegate : rt ,
104
+ codecs : serializer .NewCodecFactory (scheme ),
105
+ }
51
106
})
52
107
return & cfgCopy
53
108
}
0 commit comments