11package validatingroundtripper
22
33import (
4+ "bytes"
45 "fmt"
6+ "io"
57 "net/http"
68 "os"
79
10+ "k8s.io/apimachinery/pkg/runtime"
11+ "k8s.io/apimachinery/pkg/runtime/serializer"
12+
813 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
914 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1015 "k8s.io/apimachinery/pkg/util/yaml"
@@ -13,23 +18,73 @@ import (
1318
1419type validatingRoundTripper struct {
1520 delegate http.RoundTripper
21+ codecs serializer.CodecFactory
22+ }
23+
24+ func (rt * validatingRoundTripper ) decodeYAMLOrJSON (data []byte ) (* unstructured.Unstructured , error ) {
25+ bodyBuffer := bytes .NewBuffer (data )
26+ dec := yaml .NewYAMLOrJSONDecoder (bodyBuffer , 10 )
27+ unstructuredObject := & unstructured.Unstructured {}
28+ if err := dec .Decode (unstructuredObject ); err != nil {
29+ return nil , fmt .Errorf ("error decoding yaml/json object to an unstructured object: %w: %+v" , err , string (data ))
30+ }
31+ return unstructuredObject , nil
32+ }
33+
34+ func (rt * validatingRoundTripper ) decodeProtobuf (data []byte ) (* unstructured.Unstructured , error ) {
35+ // Decode Protobuf
36+ decoder := rt .codecs .UniversalDeserializer ()
37+ obj , _ , err := decoder .Decode (data , nil , nil )
38+ if err != nil {
39+ return nil , fmt .Errorf ("failed to decode protobuf data: %w" , err )
40+ }
41+
42+ // Convert to Unstructured for further processing
43+ unstructuredObj , err := runtime .DefaultUnstructuredConverter .ToUnstructured (obj )
44+ if err != nil {
45+ return nil , fmt .Errorf ("failed to convert object to unstructured: %w" , err )
46+ }
47+
48+ return & unstructured.Unstructured {Object : unstructuredObj }, nil
49+ }
50+
51+ func (rt * validatingRoundTripper ) decodeRequestBody (req * http.Request ) * unstructured.Unstructured {
52+ b , err := req .GetBody ()
53+ if err != nil {
54+ panic (fmt .Errorf ("failed to get request body: %w" , err ))
55+ }
56+ defer b .Close ()
57+
58+ data , err := io .ReadAll (b )
59+ if err != nil {
60+ panic (fmt .Errorf ("failed to read request body: %w" , err ))
61+ }
62+
63+ var unstructuredObject * unstructured.Unstructured
64+ switch req .Header .Get ("Content-Type" ) {
65+ case "application/vnd.kubernetes.protobuf" :
66+ unstructuredObject , err = rt .decodeProtobuf (data )
67+ default :
68+ unstructuredObject , err = rt .decodeYAMLOrJSON (data )
69+ }
70+
71+ if err != nil {
72+ panic (fmt .Errorf ("failed to decode request body: %w" , err ))
73+ }
74+ return unstructuredObject
1675}
1776
1877func (rt * validatingRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1978 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- }
79+ unstructuredObject := rt .decodeRequestBody (req )
2980 gvk := unstructuredObject .GroupVersionKind ()
3081 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 ))
82+ labels := unstructuredObject .GetLabels ()
83+ if labels [install .OLMManagedLabelKey ] != install .OLMManagedLabelValue {
84+ panic (fmt .Errorf ("%s.%s/%v %s/%s does not have labels[%s]=%s" ,
85+ gvk .Kind , gvk .Group , gvk .Version ,
86+ unstructuredObject .GetNamespace (), unstructuredObject .GetName (),
87+ install .OLMManagedLabelKey , install .OLMManagedLabelValue ))
3388 }
3489 }
3590 }
@@ -40,14 +95,17 @@ var _ http.RoundTripper = (*validatingRoundTripper)(nil)
4095
4196// Wrap is meant to be used in developer environments and CI to make it easy to find places
4297// where we accidentally create Kubernetes objects without our management label.
43- func Wrap (cfg * rest.Config ) * rest.Config {
98+ func Wrap (cfg * rest.Config , scheme * runtime. Scheme ) * rest.Config {
4499 if _ , set := os .LookupEnv ("CI" ); ! set {
45100 return cfg
46101 }
47102
48103 cfgCopy := * cfg
49104 cfgCopy .Wrap (func (rt http.RoundTripper ) http.RoundTripper {
50- return & validatingRoundTripper {delegate : rt }
105+ return & validatingRoundTripper {
106+ delegate : rt ,
107+ codecs : serializer .NewCodecFactory (scheme ),
108+ }
51109 })
52110 return & cfgCopy
53111}
0 commit comments