@@ -2,9 +2,13 @@ package validatingroundtripper
22
33import (
44 "fmt"
5+ "io"
56 "net/http"
67 "os"
78
9+ "k8s.io/apimachinery/pkg/runtime"
10+ "k8s.io/apimachinery/pkg/runtime/serializer"
11+
812 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
913 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1014 "k8s.io/apimachinery/pkg/util/yaml"
@@ -13,23 +17,71 @@ import (
1317
1418type validatingRoundTripper struct {
1519 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
1672}
1773
1874func (rt * validatingRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1975 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 )
2977 gvk := unstructuredObject .GroupVersionKind ()
3078 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 ))
3385 }
3486 }
3587 }
@@ -40,14 +92,17 @@ var _ http.RoundTripper = (*validatingRoundTripper)(nil)
4092
4193// Wrap is meant to be used in developer environments and CI to make it easy to find places
4294// 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 {
4496 if _ , set := os .LookupEnv ("CI" ); ! set {
4597 return cfg
4698 }
4799
48100 cfgCopy := * cfg
49101 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+ }
51106 })
52107 return & cfgCopy
53108}
0 commit comments