@@ -21,17 +21,41 @@ package apiutil
21
21
22
22
import (
23
23
"fmt"
24
+ "sync"
24
25
25
26
"k8s.io/apimachinery/pkg/api/meta"
26
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
28
"k8s.io/apimachinery/pkg/runtime"
28
29
"k8s.io/apimachinery/pkg/runtime/schema"
29
30
"k8s.io/apimachinery/pkg/runtime/serializer"
30
31
"k8s.io/client-go/discovery"
32
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
31
33
"k8s.io/client-go/rest"
32
34
"k8s.io/client-go/restmapper"
33
35
)
34
36
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 (builder runtime.SchemeBuilder ) error {
54
+ protobufSchemeLock .Lock ()
55
+ defer protobufSchemeLock .Unlock ()
56
+ return builder .AddToScheme (protobufScheme )
57
+ }
58
+
35
59
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
36
60
// information fetched by a new client with the given config.
37
61
func NewDiscoveryRESTMapper (c * rest.Config ) (meta.RESTMapper , error ) {
@@ -93,16 +117,16 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
93
117
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
94
118
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
95
119
// baseConfig, if set, otherwise a default serializer will be set.
96
- func RESTClientForGVK (gvk schema.GroupVersionKind , baseConfig * rest.Config , codecs serializer.CodecFactory ) (rest.Interface , error ) {
97
- cfg := createRestConfig (gvk , baseConfig )
120
+ func RESTClientForGVK (gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config , codecs serializer.CodecFactory ) (rest.Interface , error ) {
121
+ cfg := createRestConfig (gvk , isUnstructured , baseConfig )
98
122
if cfg .NegotiatedSerializer == nil {
99
123
cfg .NegotiatedSerializer = serializer.WithoutConversionCodecFactory {CodecFactory : codecs }
100
124
}
101
125
return rest .RESTClientFor (cfg )
102
126
}
103
127
104
128
//createRestConfig copies the base config and updates needed fields for a new rest config
105
- func createRestConfig (gvk schema.GroupVersionKind , baseConfig * rest.Config ) * rest.Config {
129
+ func createRestConfig (gvk schema.GroupVersionKind , isUnstructured bool , baseConfig * rest.Config ) * rest.Config {
106
130
gv := gvk .GroupVersion ()
107
131
108
132
cfg := rest .CopyConfig (baseConfig )
@@ -115,5 +139,13 @@ func createRestConfig(gvk schema.GroupVersionKind, baseConfig *rest.Config) *res
115
139
if cfg .UserAgent == "" {
116
140
cfg .UserAgent = rest .DefaultKubernetesUserAgent ()
117
141
}
142
+ // TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true.
143
+ if cfg .ContentType == "" && ! isUnstructured {
144
+ protobufSchemeLock .RLock ()
145
+ if protobufScheme .Recognizes (gvk ) {
146
+ cfg .ContentType = runtime .ContentTypeProtobuf
147
+ }
148
+ protobufSchemeLock .RUnlock ()
149
+ }
118
150
return cfg
119
151
}
0 commit comments