@@ -21,41 +21,18 @@ package apiutil
21
21
22
22
import (
23
23
"fmt"
24
- "sync "
24
+ "reflect "
25
25
26
26
"k8s.io/apimachinery/pkg/api/meta"
27
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
28
"k8s.io/apimachinery/pkg/runtime"
29
29
"k8s.io/apimachinery/pkg/runtime/schema"
30
30
"k8s.io/apimachinery/pkg/runtime/serializer"
31
31
"k8s.io/client-go/discovery"
32
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
33
32
"k8s.io/client-go/rest"
34
33
"k8s.io/client-go/restmapper"
35
34
)
36
35
37
- var (
38
- protobufScheme = runtime .NewScheme ()
39
- protobufSchemeLock sync.RWMutex
40
- )
41
-
42
- func init () {
43
- // Currently only enabled for built-in resources which are guaranteed to implement Protocol Buffers.
44
- // For custom resources, CRDs can not support Protocol Buffers but Aggregated API can.
45
- // See doc: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
46
- if err := clientgoscheme .AddToScheme (protobufScheme ); err != nil {
47
- panic (err )
48
- }
49
- }
50
-
51
- // AddToProtobufScheme add the given SchemeBuilder into protobufScheme, which should
52
- // be additional types that do support protobuf.
53
- func AddToProtobufScheme (addToScheme func (* runtime.Scheme ) error ) error {
54
- protobufSchemeLock .Lock ()
55
- defer protobufSchemeLock .Unlock ()
56
- return addToScheme (protobufScheme )
57
- }
58
-
59
36
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
60
37
// information fetched by a new client with the given config.
61
38
func NewDiscoveryRESTMapper (c * rest.Config ) (meta.RESTMapper , error ) {
@@ -117,8 +94,8 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
117
94
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
118
95
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
119
96
// baseConfig, if set, otherwise a default serializer will be set.
120
- func RESTClientForGVK (gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config , codecs serializer.CodecFactory ) (rest.Interface , error ) {
121
- return rest .RESTClientFor (createRestConfig (gvk , isUnstructured , baseConfig , codecs ))
97
+ func RESTClientForGVK (scheme * runtime. Scheme , gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config , codecs serializer.CodecFactory ) (rest.Interface , error ) {
98
+ return rest .RESTClientFor (createRestConfig (scheme , gvk , isUnstructured , baseConfig , codecs ))
122
99
}
123
100
124
101
// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory
@@ -135,7 +112,7 @@ func (f serializerWithDecodedGVK) DecoderToVersion(serializer runtime.Decoder, _
135
112
}
136
113
137
114
// createRestConfig copies the base config and updates needed fields for a new rest config.
138
- func createRestConfig (gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config , codecs serializer.CodecFactory ) * rest.Config {
115
+ func createRestConfig (scheme * runtime. Scheme , gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config , codecs serializer.CodecFactory ) * rest.Config {
139
116
gv := gvk .GroupVersion ()
140
117
141
118
cfg := rest .CopyConfig (baseConfig )
@@ -150,11 +127,9 @@ func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConf
150
127
}
151
128
// TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true.
152
129
if cfg .ContentType == "" && ! isUnstructured {
153
- protobufSchemeLock .RLock ()
154
- if protobufScheme .Recognizes (gvk ) {
130
+ if haveProtoDefinition (scheme , gvk ) {
155
131
cfg .ContentType = runtime .ContentTypeProtobuf
156
132
}
157
- protobufSchemeLock .RUnlock ()
158
133
}
159
134
160
135
if cfg .NegotiatedSerializer == nil {
@@ -169,3 +144,23 @@ func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConf
169
144
170
145
return cfg
171
146
}
147
+
148
+ // protoMessage is implemented by protobuf messages (of all libraries)
149
+ type protoMessage interface {
150
+ ProtoMessage ()
151
+ }
152
+
153
+ var protoMessageType = reflect .TypeOf (new (protoMessage )).Elem ()
154
+
155
+ // haveProtoDefinition returns true if the go type for the specified gvk support protobuf encoding.
156
+ func haveProtoDefinition (scheme * runtime.Scheme , gvk schema.GroupVersionKind ) bool {
157
+ gvkType , found := scheme .AllKnownTypes ()[gvk ]
158
+ if ! found {
159
+ return false
160
+ }
161
+ // We normally get the raw struct e.g. v1.Pod, not &v1.Pod
162
+ if gvkType .Kind () == reflect .Struct {
163
+ gvkType = reflect .PtrTo (gvkType )
164
+ }
165
+ return gvkType .Implements (protoMessageType )
166
+ }
0 commit comments