mirror of https://github.com/k3s-io/k3s
162 lines
5.0 KiB
Go
162 lines
5.0 KiB
Go
/*
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package unversioned
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"k8s.io/kubernetes/pkg/api"
|
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
"k8s.io/kubernetes/pkg/runtime"
|
|
"k8s.io/kubernetes/pkg/util"
|
|
)
|
|
|
|
const (
|
|
// Environment variables: Note that the duration should be long enough that the backoff
|
|
// persists for some reasonable time (i.e. 120 seconds). The typical base might be "1".
|
|
envBackoffBase = "KUBE_CLIENT_BACKOFF_BASE"
|
|
envBackoffDuration = "KUBE_CLIENT_BACKOFF_DURATION"
|
|
)
|
|
|
|
// RESTClient imposes common Kubernetes API conventions on a set of resource paths.
|
|
// The baseURL is expected to point to an HTTP or HTTPS path that is the parent
|
|
// of one or more resources. The server should return a decodable API resource
|
|
// object, or an api.Status object which contains information about the reason for
|
|
// any failure.
|
|
//
|
|
// Most consumers should use client.New() to get a Kubernetes API client.
|
|
type RESTClient struct {
|
|
baseURL *url.URL
|
|
versionedAPIPath string
|
|
// A string identifying the version of the API this client is expected to use.
|
|
groupVersion unversioned.GroupVersion
|
|
|
|
// Codec is the encoding and decoding scheme that applies to a particular set of
|
|
// REST resources.
|
|
Codec runtime.Codec
|
|
|
|
// Set specific behavior of the client. If not set http.DefaultClient will be
|
|
// used.
|
|
Client *http.Client
|
|
|
|
// TODO extract this into a wrapper interface via the RESTClient interface in kubectl.
|
|
Throttle util.RateLimiter
|
|
}
|
|
|
|
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
|
|
// such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and
|
|
// decoding of responses from the server.
|
|
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, groupVersion unversioned.GroupVersion, c runtime.Codec, maxQPS float32, maxBurst int) *RESTClient {
|
|
base := *baseURL
|
|
if !strings.HasSuffix(base.Path, "/") {
|
|
base.Path += "/"
|
|
}
|
|
base.RawQuery = ""
|
|
base.Fragment = ""
|
|
|
|
var throttle util.RateLimiter
|
|
if maxQPS > 0 {
|
|
throttle = util.NewTokenBucketRateLimiter(maxQPS, maxBurst)
|
|
}
|
|
return &RESTClient{
|
|
baseURL: &base,
|
|
versionedAPIPath: versionedAPIPath,
|
|
groupVersion: groupVersion,
|
|
Codec: c,
|
|
Throttle: throttle,
|
|
}
|
|
}
|
|
|
|
// readExpBackoffConfig handles the internal logic of determining what the
|
|
// backoff policy is. By default if no information is available, NoBackoff.
|
|
// TODO Generalize this see #17727 .
|
|
func readExpBackoffConfig() BackoffManager {
|
|
backoffBase := os.Getenv(envBackoffBase)
|
|
backoffDuration := os.Getenv(envBackoffDuration)
|
|
|
|
backoffBaseInt, errBase := strconv.ParseInt(backoffBase, 10, 64)
|
|
backoffDurationInt, errDuration := strconv.ParseInt(backoffDuration, 10, 64)
|
|
if errBase != nil || errDuration != nil {
|
|
return &NoBackoff{}
|
|
} else {
|
|
return &URLBackoff{
|
|
Backoff: util.NewBackOff(
|
|
time.Duration(backoffBaseInt)*time.Second,
|
|
time.Duration(backoffDurationInt)*time.Second)}
|
|
}
|
|
}
|
|
|
|
// Verb begins a request with a verb (GET, POST, PUT, DELETE).
|
|
//
|
|
// Example usage of RESTClient's request building interface:
|
|
// c := NewRESTClient(url, codec)
|
|
// resp, err := c.Verb("GET").
|
|
// Path("pods").
|
|
// SelectorParam("labels", "area=staging").
|
|
// Timeout(10*time.Second).
|
|
// Do()
|
|
// if err != nil { ... }
|
|
// list, ok := resp.(*api.PodList)
|
|
//
|
|
func (c *RESTClient) Verb(verb string) *Request {
|
|
if c.Throttle != nil {
|
|
c.Throttle.Accept()
|
|
}
|
|
|
|
backoff := readExpBackoffConfig()
|
|
|
|
if c.Client == nil {
|
|
return NewRequest(nil, verb, c.baseURL, c.versionedAPIPath, c.groupVersion, c.Codec, backoff)
|
|
}
|
|
return NewRequest(c.Client, verb, c.baseURL, c.versionedAPIPath, c.groupVersion, c.Codec, backoff)
|
|
}
|
|
|
|
// Post begins a POST request. Short for c.Verb("POST").
|
|
func (c *RESTClient) Post() *Request {
|
|
return c.Verb("POST")
|
|
}
|
|
|
|
// Put begins a PUT request. Short for c.Verb("PUT").
|
|
func (c *RESTClient) Put() *Request {
|
|
return c.Verb("PUT")
|
|
}
|
|
|
|
// Patch begins a PATCH request. Short for c.Verb("Patch").
|
|
func (c *RESTClient) Patch(pt api.PatchType) *Request {
|
|
return c.Verb("PATCH").SetHeader("Content-Type", string(pt))
|
|
}
|
|
|
|
// Get begins a GET request. Short for c.Verb("GET").
|
|
func (c *RESTClient) Get() *Request {
|
|
return c.Verb("GET")
|
|
}
|
|
|
|
// Delete begins a DELETE request. Short for c.Verb("DELETE").
|
|
func (c *RESTClient) Delete() *Request {
|
|
return c.Verb("DELETE")
|
|
}
|
|
|
|
// APIVersion returns the APIVersion this RESTClient is expected to use.
|
|
func (c *RESTClient) APIVersion() unversioned.GroupVersion {
|
|
return c.groupVersion
|
|
}
|