@@ -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,69 @@ 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+ return nil , 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 , error ) {
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+ switch req .Header .Get ("Content-Type" ) {
60+ case "application/vnd.kubernetes.protobuf" :
61+ return rt .decodeProtobuf (b )
62+ default :
63+ return rt .decodeYAMLOrJSON (b )
64+ }
1665}
1766
1867func (rt * validatingRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1968 if req .Method == "POST" {
20- b , err := req .GetBody ()
69+ unstructuredObject , err := rt .decodeRequestBody (req )
70+
2171 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 ))
72+ return nil , err
2873 }
74+
2975 gvk := unstructuredObject .GroupVersionKind ()
3076 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 ))
77+ labels := unstructuredObject .GetLabels ()
78+ if labels [install .OLMManagedLabelKey ] != install .OLMManagedLabelValue {
79+ panic (fmt .Errorf ("%s.%s/%v %s/%s does not have labels[%s]=%s" ,
80+ gvk .Kind , gvk .Group , gvk .Version ,
81+ unstructuredObject .GetNamespace (), unstructuredObject .GetName (),
82+ install .OLMManagedLabelKey , install .OLMManagedLabelValue ))
3383 }
3484 }
3585 }
@@ -40,14 +90,17 @@ var _ http.RoundTripper = (*validatingRoundTripper)(nil)
4090
4191// Wrap is meant to be used in developer environments and CI to make it easy to find places
4292// where we accidentally create Kubernetes objects without our management label.
43- func Wrap (cfg * rest.Config ) * rest.Config {
93+ func Wrap (cfg * rest.Config , scheme * runtime. Scheme ) * rest.Config {
4494 if _ , set := os .LookupEnv ("CI" ); ! set {
4595 return cfg
4696 }
4797
4898 cfgCopy := * cfg
4999 cfgCopy .Wrap (func (rt http.RoundTripper ) http.RoundTripper {
50- return & validatingRoundTripper {delegate : rt }
100+ return & validatingRoundTripper {
101+ delegate : rt ,
102+ codecs : serializer .NewCodecFactory (scheme ),
103+ }
51104 })
52105 return & cfgCopy
53106}
0 commit comments