@@ -17,8 +17,6 @@ limitations under the License.
17
17
package rest
18
18
19
19
import (
20
- "fmt"
21
- "mime"
22
20
"net/http"
23
21
"net/url"
24
22
"os"
@@ -51,6 +49,28 @@ type Interface interface {
51
49
APIVersion () schema.GroupVersion
52
50
}
53
51
52
+ // ClientContentConfig controls how RESTClient communicates with the server.
53
+ //
54
+ // TODO: ContentConfig will be updated to accept a Negotiator instead of a
55
+ // NegotiatedSerializer and NegotiatedSerializer will be removed.
56
+ type ClientContentConfig struct {
57
+ // AcceptContentTypes specifies the types the client will accept and is optional.
58
+ // If not set, ContentType will be used to define the Accept header
59
+ AcceptContentTypes string
60
+ // ContentType specifies the wire format used to communicate with the server.
61
+ // This value will be set as the Accept header on requests made to the server if
62
+ // AcceptContentTypes is not set, and as the default content type on any object
63
+ // sent to the server. If not set, "application/json" is used.
64
+ ContentType string
65
+ // GroupVersion is the API version to talk to. Must be provided when initializing
66
+ // a RESTClient directly. When initializing a Client, will be set with the default
67
+ // code version. This is used as the default group version for VersionedParams.
68
+ GroupVersion schema.GroupVersion
69
+ // Negotiator is used for obtaining encoders and decoders for multiple
70
+ // supported media types.
71
+ Negotiator runtime.ClientNegotiator
72
+ }
73
+
54
74
// RESTClient imposes common Kubernetes API conventions on a set of resource paths.
55
75
// The baseURL is expected to point to an HTTP or HTTPS path that is the parent
56
76
// of one or more resources. The server should return a decodable API resource
@@ -64,66 +84,42 @@ type RESTClient struct {
64
84
// versionedAPIPath is a path segment connecting the base URL to the resource root
65
85
versionedAPIPath string
66
86
67
- // contentConfig is the information used to communicate with the server.
68
- contentConfig ContentConfig
69
-
70
- // serializers contain all serializers for underlying content type.
71
- serializers Serializers
87
+ // content describes how a RESTClient encodes and decodes responses.
88
+ content ClientContentConfig
72
89
73
90
// creates BackoffManager that is passed to requests.
74
91
createBackoffMgr func () BackoffManager
75
92
76
- // TODO extract this into a wrapper interface via the RESTClient interface in kubectl.
77
- Throttle flowcontrol.RateLimiter
93
+ // rateLimiter is shared among all requests created by this client unless specifically
94
+ // overridden.
95
+ rateLimiter flowcontrol.RateLimiter
78
96
79
97
// Set specific behavior of the client. If not set http.DefaultClient will be used.
80
98
Client * http.Client
81
99
}
82
100
83
- type Serializers struct {
84
- Encoder runtime.Encoder
85
- Decoder runtime.Decoder
86
- StreamingSerializer runtime.Serializer
87
- Framer runtime.Framer
88
- RenegotiatedDecoder func (contentType string , params map [string ]string ) (runtime.Decoder , error )
89
- }
90
-
91
101
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
92
- // such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and
93
- // decoding of responses from the server.
94
- func NewRESTClient (baseURL * url.URL , versionedAPIPath string , config ContentConfig , maxQPS float32 , maxBurst int , rateLimiter flowcontrol.RateLimiter , client * http.Client ) (* RESTClient , error ) {
102
+ // such as Get, Put, Post, and Delete on specified paths.
103
+ func NewRESTClient (baseURL * url.URL , versionedAPIPath string , config ClientContentConfig , rateLimiter flowcontrol.RateLimiter , client * http.Client ) (* RESTClient , error ) {
104
+ if len (config .ContentType ) == 0 {
105
+ config .ContentType = "application/json"
106
+ }
107
+
95
108
base := * baseURL
96
109
if ! strings .HasSuffix (base .Path , "/" ) {
97
110
base .Path += "/"
98
111
}
99
112
base .RawQuery = ""
100
113
base .Fragment = ""
101
114
102
- if config .GroupVersion == nil {
103
- config .GroupVersion = & schema.GroupVersion {}
104
- }
105
- if len (config .ContentType ) == 0 {
106
- config .ContentType = "application/json"
107
- }
108
- serializers , err := createSerializers (config )
109
- if err != nil {
110
- return nil , err
111
- }
112
-
113
- var throttle flowcontrol.RateLimiter
114
- if maxQPS > 0 && rateLimiter == nil {
115
- throttle = flowcontrol .NewTokenBucketRateLimiter (maxQPS , maxBurst )
116
- } else if rateLimiter != nil {
117
- throttle = rateLimiter
118
- }
119
115
return & RESTClient {
120
116
base : & base ,
121
117
versionedAPIPath : versionedAPIPath ,
122
- contentConfig : config ,
123
- serializers : * serializers ,
118
+ content : config ,
124
119
createBackoffMgr : readExpBackoffConfig ,
125
- Throttle : throttle ,
126
- Client : client ,
120
+ rateLimiter : rateLimiter ,
121
+
122
+ Client : client ,
127
123
}, nil
128
124
}
129
125
@@ -132,7 +128,7 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
132
128
if c == nil {
133
129
return nil
134
130
}
135
- return c .Throttle
131
+ return c .rateLimiter
136
132
}
137
133
138
134
// readExpBackoffConfig handles the internal logic of determining what the
@@ -153,58 +149,6 @@ func readExpBackoffConfig() BackoffManager {
153
149
time .Duration (backoffDurationInt )* time .Second )}
154
150
}
155
151
156
- // createSerializers creates all necessary serializers for given contentType.
157
- // TODO: the negotiated serializer passed to this method should probably return
158
- // serializers that control decoding and versioning without this package
159
- // being aware of the types. Depends on whether RESTClient must deal with
160
- // generic infrastructure.
161
- func createSerializers (config ContentConfig ) (* Serializers , error ) {
162
- mediaTypes := config .NegotiatedSerializer .SupportedMediaTypes ()
163
- contentType := config .ContentType
164
- mediaType , _ , err := mime .ParseMediaType (contentType )
165
- if err != nil {
166
- return nil , fmt .Errorf ("the content type specified in the client configuration is not recognized: %v" , err )
167
- }
168
- info , ok := runtime .SerializerInfoForMediaType (mediaTypes , mediaType )
169
- if ! ok {
170
- if len (contentType ) != 0 || len (mediaTypes ) == 0 {
171
- return nil , fmt .Errorf ("no serializers registered for %s" , contentType )
172
- }
173
- info = mediaTypes [0 ]
174
- }
175
-
176
- internalGV := schema.GroupVersions {
177
- {
178
- Group : config .GroupVersion .Group ,
179
- Version : runtime .APIVersionInternal ,
180
- },
181
- // always include the legacy group as a decoding target to handle non-error `Status` return types
182
- {
183
- Group : "" ,
184
- Version : runtime .APIVersionInternal ,
185
- },
186
- }
187
-
188
- s := & Serializers {
189
- Encoder : config .NegotiatedSerializer .EncoderForVersion (info .Serializer , * config .GroupVersion ),
190
- Decoder : config .NegotiatedSerializer .DecoderToVersion (info .Serializer , internalGV ),
191
-
192
- RenegotiatedDecoder : func (contentType string , params map [string ]string ) (runtime.Decoder , error ) {
193
- info , ok := runtime .SerializerInfoForMediaType (mediaTypes , contentType )
194
- if ! ok {
195
- return nil , fmt .Errorf ("serializer for %s not registered" , contentType )
196
- }
197
- return config .NegotiatedSerializer .DecoderToVersion (info .Serializer , internalGV ), nil
198
- },
199
- }
200
- if info .StreamSerializer != nil {
201
- s .StreamingSerializer = info .StreamSerializer .Serializer
202
- s .Framer = info .StreamSerializer .Framer
203
- }
204
-
205
- return s , nil
206
- }
207
-
208
152
// Verb begins a request with a verb (GET, POST, PUT, DELETE).
209
153
//
210
154
// Example usage of RESTClient's request building interface:
@@ -219,12 +163,7 @@ func createSerializers(config ContentConfig) (*Serializers, error) {
219
163
// list, ok := resp.(*api.PodList)
220
164
//
221
165
func (c * RESTClient ) Verb (verb string ) * Request {
222
- backoff := c .createBackoffMgr ()
223
-
224
- if c .Client == nil {
225
- return NewRequest (nil , verb , c .base , c .versionedAPIPath , c .contentConfig , c .serializers , backoff , c .Throttle , 0 )
226
- }
227
- return NewRequest (c .Client , verb , c .base , c .versionedAPIPath , c .contentConfig , c .serializers , backoff , c .Throttle , c .Client .Timeout )
166
+ return NewRequest (c ).Verb (verb )
228
167
}
229
168
230
169
// Post begins a POST request. Short for c.Verb("POST").
@@ -254,5 +193,5 @@ func (c *RESTClient) Delete() *Request {
254
193
255
194
// APIVersion returns the APIVersion this RESTClient is expected to use.
256
195
func (c * RESTClient ) APIVersion () schema.GroupVersion {
257
- return * c . contentConfig .GroupVersion
196
+ return c . content .GroupVersion
258
197
}
0 commit comments