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,74 @@ 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+
75+ return unstructuredObject
1676}
1777
1878func (rt * validatingRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1979 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- }
80+ unstructuredObject := rt .decodeRequestBody (req )
2981 gvk := unstructuredObject .GroupVersionKind ()
3082 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 ))
83+ labels := unstructuredObject .GetLabels ()
84+ if labels [install .OLMManagedLabelKey ] != install .OLMManagedLabelValue {
85+ panic (fmt .Errorf ("%s.%s/%v %s/%s does not have labels[%s]=%s" ,
86+ gvk .Kind , gvk .Group , gvk .Version ,
87+ unstructuredObject .GetNamespace (), unstructuredObject .GetName (),
88+ install .OLMManagedLabelKey , install .OLMManagedLabelValue ))
3389 }
3490 }
3591 }
@@ -40,14 +96,17 @@ var _ http.RoundTripper = (*validatingRoundTripper)(nil)
4096
4197// Wrap is meant to be used in developer environments and CI to make it easy to find places
4298// where we accidentally create Kubernetes objects without our management label.
43- func Wrap (cfg * rest.Config ) * rest.Config {
99+ func Wrap (cfg * rest.Config , scheme * runtime. Scheme ) * rest.Config {
44100 if _ , set := os .LookupEnv ("CI" ); ! set {
45101 return cfg
46102 }
47103
48104 cfgCopy := * cfg
49105 cfgCopy .Wrap (func (rt http.RoundTripper ) http.RoundTripper {
50- return & validatingRoundTripper {delegate : rt }
106+ return & validatingRoundTripper {
107+ delegate : rt ,
108+ codecs : serializer .NewCodecFactory (scheme ),
109+ }
51110 })
52111 return & cfgCopy
53112}
0 commit comments