Update godeps
This commit is contained in:
parent
423433bc5f
commit
701c5a0e30
482 changed files with 86915 additions and 19741 deletions
23
vendor/k8s.io/kubernetes/pkg/util/crypto/crypto.go
generated
vendored
23
vendor/k8s.io/kubernetes/pkg/util/crypto/crypto.go
generated
vendored
|
|
@ -33,6 +33,29 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// ShouldGenSelfSignedCerts returns false if the certificate or key files already exists,
|
||||
// otherwise returns true.
|
||||
func ShouldGenSelfSignedCerts(certPath, keyPath string) bool {
|
||||
if canReadFile(certPath) || canReadFile(keyPath) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// If the file represented by path exists and
|
||||
// readable, returns true otherwise returns false.
|
||||
func canReadFile(path string) bool {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GenerateSelfSignedCert creates a self-signed certificate and key for the given host.
|
||||
// Host may be an IP or a DNS name
|
||||
// You may also specify additional subject alt names (either ip or dns names) for the certificate
|
||||
|
|
|
|||
159
vendor/k8s.io/kubernetes/pkg/util/deployment/deployment.go
generated
vendored
159
vendor/k8s.io/kubernetes/pkg/util/deployment/deployment.go
generated
vendored
|
|
@ -34,6 +34,7 @@ import (
|
|||
intstrutil "k8s.io/kubernetes/pkg/util/intstr"
|
||||
labelsutil "k8s.io/kubernetes/pkg/util/labels"
|
||||
podutil "k8s.io/kubernetes/pkg/util/pod"
|
||||
rsutil "k8s.io/kubernetes/pkg/util/replicaset"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
|
|
@ -47,23 +48,39 @@ const (
|
|||
RollbackDone = "DeploymentRollback"
|
||||
)
|
||||
|
||||
// GetAllReplicaSets returns the old and new replica sets targeted by the given Deployment. It gets PodList and ReplicaSetList from client interface.
|
||||
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
|
||||
// The third returned value is the new replica set, and it may be nil if it doesn't exist yet.
|
||||
func GetAllReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, *extensions.ReplicaSet, error) {
|
||||
rsList, err := listReplicaSets(deployment, c)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
podList, err := listPods(deployment, c)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
oldRSes, allOldRSes, err := FindOldReplicaSets(deployment, rsList, podList)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
newRS, err := FindNewReplicaSet(deployment, rsList)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return oldRSes, allOldRSes, newRS, nil
|
||||
}
|
||||
|
||||
// GetOldReplicaSets returns the old replica sets targeted by the given Deployment; get PodList and ReplicaSetList from client interface.
|
||||
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
|
||||
func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) {
|
||||
rsList, err := ListReplicaSets(deployment,
|
||||
func(namespace string, options api.ListOptions) ([]extensions.ReplicaSet, error) {
|
||||
rsList, err := c.Extensions().ReplicaSets(namespace).List(options)
|
||||
return rsList.Items, err
|
||||
})
|
||||
rsList, err := listReplicaSets(deployment, c)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error listing ReplicaSets: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
podList, err := ListPods(deployment,
|
||||
func(namespace string, options api.ListOptions) (*api.PodList, error) {
|
||||
return c.Core().Pods(namespace).List(options)
|
||||
})
|
||||
podList, err := listPods(deployment, c)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error listing Pods: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
return FindOldReplicaSets(deployment, rsList, podList)
|
||||
}
|
||||
|
|
@ -71,15 +88,28 @@ func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface)
|
|||
// GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface.
|
||||
// Returns nil if the new replica set doesn't exist yet.
|
||||
func GetNewReplicaSet(deployment *extensions.Deployment, c clientset.Interface) (*extensions.ReplicaSet, error) {
|
||||
rsList, err := ListReplicaSets(deployment,
|
||||
rsList, err := listReplicaSets(deployment, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FindNewReplicaSet(deployment, rsList)
|
||||
}
|
||||
|
||||
// listReplicaSets lists all RSes the given deployment targets with the given client interface.
|
||||
func listReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]extensions.ReplicaSet, error) {
|
||||
return ListReplicaSets(deployment,
|
||||
func(namespace string, options api.ListOptions) ([]extensions.ReplicaSet, error) {
|
||||
rsList, err := c.Extensions().ReplicaSets(namespace).List(options)
|
||||
return rsList.Items, err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing ReplicaSets: %v", err)
|
||||
}
|
||||
return FindNewReplicaSet(deployment, rsList)
|
||||
}
|
||||
|
||||
// listReplicaSets lists all Pods the given deployment targets with the given client interface.
|
||||
func listPods(deployment *extensions.Deployment, c clientset.Interface) (*api.PodList, error) {
|
||||
return ListPods(deployment,
|
||||
func(namespace string, options api.ListOptions) (*api.PodList, error) {
|
||||
return c.Core().Pods(namespace).List(options)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: switch this to full namespacers
|
||||
|
|
@ -111,11 +141,34 @@ func ListPods(deployment *extensions.Deployment, getPodList podListFunc) (*api.P
|
|||
return getPodList(namespace, options)
|
||||
}
|
||||
|
||||
// equalIgnoreHash returns true if two given podTemplateSpec are equal, ignoring the diff in value of Labels[pod-template-hash]
|
||||
// We ignore pod-template-hash because the hash result would be different upon podTemplateSpec API changes
|
||||
// (e.g. the addition of a new field will cause the hash code to change)
|
||||
// Note that we assume input podTemplateSpecs contain non-empty labels
|
||||
func equalIgnoreHash(template1, template2 api.PodTemplateSpec) (bool, error) {
|
||||
// The podTemplateSpec must have a non-empty label so that label selectors can find them.
|
||||
// This is checked by validation (of resources contain a podTemplateSpec).
|
||||
if len(template1.Labels) == 0 || len(template2.Labels) == 0 {
|
||||
return false, fmt.Errorf("Unexpected empty labels found in given template")
|
||||
}
|
||||
hash1 := template1.Labels[extensions.DefaultDeploymentUniqueLabelKey]
|
||||
hash2 := template2.Labels[extensions.DefaultDeploymentUniqueLabelKey]
|
||||
// compare equality ignoring pod-template-hash
|
||||
template1.Labels[extensions.DefaultDeploymentUniqueLabelKey] = hash2
|
||||
result := api.Semantic.DeepEqual(template1, template2)
|
||||
template1.Labels[extensions.DefaultDeploymentUniqueLabelKey] = hash1
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindNewReplicaSet returns the new RS this given deployment targets (the one with the same pod template).
|
||||
func FindNewReplicaSet(deployment *extensions.Deployment, rsList []extensions.ReplicaSet) (*extensions.ReplicaSet, error) {
|
||||
newRSTemplate := GetNewReplicaSetTemplate(deployment)
|
||||
for i := range rsList {
|
||||
if api.Semantic.DeepEqual(rsList[i].Spec.Template, newRSTemplate) {
|
||||
equal, err := equalIgnoreHash(rsList[i].Spec.Template, newRSTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if equal {
|
||||
// This is the new ReplicaSet.
|
||||
return &rsList[i], nil
|
||||
}
|
||||
|
|
@ -140,7 +193,11 @@ func FindOldReplicaSets(deployment *extensions.Deployment, rsList []extensions.R
|
|||
return nil, nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
// Filter out replica set that has the same pod template spec as the deployment - that is the new replica set.
|
||||
if api.Semantic.DeepEqual(rs.Spec.Template, newRSTemplate) {
|
||||
equal, err := equalIgnoreHash(rs.Spec.Template, newRSTemplate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if equal {
|
||||
continue
|
||||
}
|
||||
allOldRSs[rs.ObjectMeta.Name] = rs
|
||||
|
|
@ -258,23 +315,42 @@ func GetActualReplicaCountForReplicaSets(replicaSets []*extensions.ReplicaSet) i
|
|||
return totalReplicaCount
|
||||
}
|
||||
|
||||
// Returns the number of available pods corresponding to the given replica sets.
|
||||
func GetAvailablePodsForReplicaSets(c clientset.Interface, rss []*extensions.ReplicaSet, minReadySeconds int32) (int32, error) {
|
||||
allPods, err := GetPodsForReplicaSets(c, rss)
|
||||
// GetAvailablePodsForReplicaSets returns the number of available pods (listed from clientset) corresponding to the given replica sets.
|
||||
func GetAvailablePodsForReplicaSets(c clientset.Interface, deployment *extensions.Deployment, rss []*extensions.ReplicaSet, minReadySeconds int32) (int32, error) {
|
||||
podList, err := listPods(deployment, c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return getReadyPodsCount(allPods, minReadySeconds), nil
|
||||
return CountAvailablePodsForReplicaSets(podList, rss, minReadySeconds)
|
||||
}
|
||||
|
||||
func getReadyPodsCount(pods []api.Pod, minReadySeconds int32) int32 {
|
||||
readyPodCount := int32(0)
|
||||
// CountAvailablePodsForReplicaSets returns the number of available pods corresponding to the given pod list and replica sets.
|
||||
// Note that the input pod list should be the pods targeted by the deployment of input replica sets.
|
||||
func CountAvailablePodsForReplicaSets(podList *api.PodList, rss []*extensions.ReplicaSet, minReadySeconds int32) (int32, error) {
|
||||
rsPods, err := filterPodsMatchingReplicaSets(rss, podList)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return countAvailablePods(rsPods, minReadySeconds), nil
|
||||
}
|
||||
|
||||
// GetAvailablePodsForDeployment returns the number of available pods (listed from clientset) corresponding to the given deployment.
|
||||
func GetAvailablePodsForDeployment(c clientset.Interface, deployment *extensions.Deployment, minReadySeconds int32) (int32, error) {
|
||||
podList, err := listPods(deployment, c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return countAvailablePods(podList.Items, minReadySeconds), nil
|
||||
}
|
||||
|
||||
func countAvailablePods(pods []api.Pod, minReadySeconds int32) int32 {
|
||||
availablePodCount := int32(0)
|
||||
for _, pod := range pods {
|
||||
if IsPodAvailable(&pod, minReadySeconds) {
|
||||
readyPodCount++
|
||||
availablePodCount++
|
||||
}
|
||||
}
|
||||
return readyPodCount
|
||||
return availablePodCount
|
||||
}
|
||||
|
||||
func IsPodAvailable(pod *api.Pod, minReadySeconds int32) bool {
|
||||
|
|
@ -298,29 +374,20 @@ func IsPodAvailable(pod *api.Pod, minReadySeconds int32) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func GetPodsForReplicaSets(c clientset.Interface, replicaSets []*extensions.ReplicaSet) ([]api.Pod, error) {
|
||||
allPods := map[string]api.Pod{}
|
||||
// filterPodsMatchingReplicaSets filters the given pod list and only return the ones targeted by the input replicasets
|
||||
func filterPodsMatchingReplicaSets(replicaSets []*extensions.ReplicaSet, podList *api.PodList) ([]api.Pod, error) {
|
||||
rsPods := []api.Pod{}
|
||||
for _, rs := range replicaSets {
|
||||
if rs != nil {
|
||||
selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
options := api.ListOptions{LabelSelector: selector}
|
||||
podList, err := c.Core().Pods(rs.ObjectMeta.Namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing pods: %v", err)
|
||||
}
|
||||
for _, pod := range podList.Items {
|
||||
allPods[pod.Name] = pod
|
||||
}
|
||||
matchingFunc, err := rsutil.MatchingPodsFunc(rs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if matchingFunc == nil {
|
||||
continue
|
||||
}
|
||||
rsPods = append(rsPods, podutil.Filter(podList, matchingFunc)...)
|
||||
}
|
||||
requiredPods := []api.Pod{}
|
||||
for _, pod := range allPods {
|
||||
requiredPods = append(requiredPods, pod)
|
||||
}
|
||||
return requiredPods, nil
|
||||
return rsPods, nil
|
||||
}
|
||||
|
||||
// Revision returns the revision number of the input replica set
|
||||
|
|
|
|||
8
vendor/k8s.io/kubernetes/pkg/util/framer/framer.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/util/framer/framer.go
generated
vendored
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
type lengthDelimitedFrameWriter struct {
|
||||
w io.Writer
|
||||
h [4]byte
|
||||
}
|
||||
|
||||
func NewLengthDelimitedFrameWriter(w io.Writer) io.Writer {
|
||||
|
|
@ -34,13 +35,12 @@ func NewLengthDelimitedFrameWriter(w io.Writer) io.Writer {
|
|||
// Write writes a single frame to the nested writer, prepending it with the length in
|
||||
// in bytes of data (as a 4 byte, bigendian uint32).
|
||||
func (w *lengthDelimitedFrameWriter) Write(data []byte) (int, error) {
|
||||
header := [4]byte{}
|
||||
binary.BigEndian.PutUint32(header[:], uint32(len(data)))
|
||||
n, err := w.w.Write(header[:])
|
||||
binary.BigEndian.PutUint32(w.h[:], uint32(len(data)))
|
||||
n, err := w.w.Write(w.h[:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n != len(header) {
|
||||
if n != len(w.h) {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
return w.w.Write(data)
|
||||
|
|
|
|||
1
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.proto
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.proto
generated
vendored
|
|
@ -30,6 +30,7 @@ option go_package = "intstr";
|
|||
// accept a name or number.
|
||||
// TODO: Rename to Int32OrString
|
||||
//
|
||||
// +gencopy=true
|
||||
// +protobuf=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message IntOrString {
|
||||
|
|
|
|||
1
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr.go
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr.go
generated
vendored
|
|
@ -32,6 +32,7 @@ import (
|
|||
// accept a name or number.
|
||||
// TODO: Rename to Int32OrString
|
||||
//
|
||||
// +gencopy=true
|
||||
// +protobuf=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type IntOrString struct {
|
||||
|
|
|
|||
30
vendor/k8s.io/kubernetes/pkg/util/net/http.go
generated
vendored
30
vendor/k8s.io/kubernetes/pkg/util/net/http.go
generated
vendored
|
|
@ -26,6 +26,9 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
// IsProbableEOF returns true if the given error resembles a connection termination
|
||||
|
|
@ -53,9 +56,9 @@ func IsProbableEOF(err error) bool {
|
|||
|
||||
var defaultTransport = http.DefaultTransport.(*http.Transport)
|
||||
|
||||
// SetTransportDefaults applies the defaults from http.DefaultTransport
|
||||
// SetOldTransportDefaults applies the defaults from http.DefaultTransport
|
||||
// for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
|
||||
func SetTransportDefaults(t *http.Transport) *http.Transport {
|
||||
func SetOldTransportDefaults(t *http.Transport) *http.Transport {
|
||||
if t.Proxy == nil || isDefault(t.Proxy) {
|
||||
// http.ProxyFromEnvironment doesn't respect CIDRs and that makes it impossible to exclude things like pod and service IPs from proxy settings
|
||||
// ProxierWithNoProxyCIDR allows CIDR rules in NO_PROXY
|
||||
|
|
@ -70,6 +73,19 @@ func SetTransportDefaults(t *http.Transport) *http.Transport {
|
|||
return t
|
||||
}
|
||||
|
||||
// SetTransportDefaults applies the defaults from http.DefaultTransport
|
||||
// for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
|
||||
func SetTransportDefaults(t *http.Transport) *http.Transport {
|
||||
t = SetOldTransportDefaults(t)
|
||||
// Allow HTTP2 clients but default off for now
|
||||
if s := os.Getenv("ENABLE_HTTP2"); len(s) > 0 {
|
||||
if err := http2.ConfigureTransport(t); err != nil {
|
||||
glog.Warningf("Transport failed http2 configuration: %v", err)
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
type RoundTripperWrapper interface {
|
||||
http.RoundTripper
|
||||
WrappedRoundTripper() http.RoundTripper
|
||||
|
|
@ -153,8 +169,14 @@ func GetClientIP(req *http.Request) net.IP {
|
|||
}
|
||||
|
||||
// Fallback to Remote Address in request, which will give the correct client IP when there is no proxy.
|
||||
ip := net.ParseIP(req.RemoteAddr)
|
||||
return ip
|
||||
// Remote Address in Go's HTTP server is in the form host:port so we need to split that first.
|
||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err == nil {
|
||||
return net.ParseIP(host)
|
||||
}
|
||||
|
||||
// Fallback if Remote Address was just IP.
|
||||
return net.ParseIP(req.RemoteAddr)
|
||||
}
|
||||
|
||||
var defaultProxyFuncPointer = fmt.Sprintf("%p", http.ProxyFromEnvironment)
|
||||
|
|
|
|||
11
vendor/k8s.io/kubernetes/pkg/util/pod/pod.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/util/pod/pod.go
generated
vendored
|
|
@ -87,3 +87,14 @@ func UpdatePodWithRetries(podClient unversionedcore.PodInterface, pod *api.Pod,
|
|||
// if the error is nil and podUpdated is true, the returned pod contains the applied update.
|
||||
return pod, podUpdated, err
|
||||
}
|
||||
|
||||
// Filter uses the input function f to filter the given pod list, and return the filtered pods
|
||||
func Filter(podList *api.PodList, f func(api.Pod) bool) []api.Pod {
|
||||
pods := make([]api.Pod, 0)
|
||||
for _, p := range podList.Items {
|
||||
if f(p) {
|
||||
pods = append(pods, p)
|
||||
}
|
||||
}
|
||||
return pods
|
||||
}
|
||||
|
|
|
|||
18
vendor/k8s.io/kubernetes/pkg/util/rand/rand.go
generated
vendored
18
vendor/k8s.io/kubernetes/pkg/util/rand/rand.go
generated
vendored
|
|
@ -32,7 +32,7 @@ var rng = struct {
|
|||
rand: rand.New(rand.NewSource(time.Now().UTC().UnixNano())),
|
||||
}
|
||||
|
||||
// Intn generates an integer in range 0->max.
|
||||
// Intn generates an integer in range [0,max).
|
||||
// By design this should panic if input is invalid, <= 0.
|
||||
func Intn(max int) int {
|
||||
rng.Lock()
|
||||
|
|
@ -40,6 +40,22 @@ func Intn(max int) int {
|
|||
return rng.rand.Intn(max)
|
||||
}
|
||||
|
||||
// IntnRange generates an integer in range [min,max).
|
||||
// By design this should panic if input is invalid, <= 0.
|
||||
func IntnRange(min, max int) int {
|
||||
rng.Lock()
|
||||
defer rng.Unlock()
|
||||
return rng.rand.Intn(max-min) + min
|
||||
}
|
||||
|
||||
// IntnRange generates an int64 integer in range [min,max).
|
||||
// By design this should panic if input is invalid, <= 0.
|
||||
func Int63nRange(min, max int64) int64 {
|
||||
rng.Lock()
|
||||
defer rng.Unlock()
|
||||
return rng.rand.Int63n(max-min) + min
|
||||
}
|
||||
|
||||
// Seed seeds the rng with the provided seed.
|
||||
func Seed(seed int64) {
|
||||
rng.Lock()
|
||||
|
|
|
|||
110
vendor/k8s.io/kubernetes/pkg/util/replicaset/replicaset.go
generated
vendored
Normal file
110
vendor/k8s.io/kubernetes/pkg/util/replicaset/replicaset.go
generated
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Copyright 2016 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 replicaset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
unversionedextensions "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
errorsutil "k8s.io/kubernetes/pkg/util/errors"
|
||||
labelsutil "k8s.io/kubernetes/pkg/util/labels"
|
||||
podutil "k8s.io/kubernetes/pkg/util/pod"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
// TODO: use client library instead when it starts to support update retries
|
||||
// see https://github.com/kubernetes/kubernetes/issues/21479
|
||||
type updateRSFunc func(rs *extensions.ReplicaSet) error
|
||||
|
||||
// UpdateRSWithRetries updates a RS with given applyUpdate function. Note that RS not found error is ignored.
|
||||
// The returned bool value can be used to tell if the RS is actually updated.
|
||||
func UpdateRSWithRetries(rsClient unversionedextensions.ReplicaSetInterface, rs *extensions.ReplicaSet, applyUpdate updateRSFunc) (*extensions.ReplicaSet, bool, error) {
|
||||
var err error
|
||||
var rsUpdated bool
|
||||
oldRs := rs
|
||||
if err = wait.Poll(10*time.Millisecond, 1*time.Minute, func() (bool, error) {
|
||||
rs, err = rsClient.Get(oldRs.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Apply the update, then attempt to push it to the apiserver.
|
||||
if err = applyUpdate(rs); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rs, err = rsClient.Update(rs); err == nil {
|
||||
// Update successful.
|
||||
return true, nil
|
||||
}
|
||||
// TODO: don't retry on perm-failed errors and handle them gracefully
|
||||
// Update could have failed due to conflict error. Try again.
|
||||
return false, nil
|
||||
}); err == nil {
|
||||
// When there's no error, we've updated this RS.
|
||||
rsUpdated = true
|
||||
}
|
||||
|
||||
// Handle returned error from wait poll
|
||||
if err == wait.ErrWaitTimeout {
|
||||
err = fmt.Errorf("timed out trying to update RS: %+v", oldRs)
|
||||
}
|
||||
// Ignore the RS not found error, but the RS isn't updated.
|
||||
if errors.IsNotFound(err) {
|
||||
glog.V(4).Infof("%s %s/%s is not found, skip updating it.", oldRs.Kind, oldRs.Namespace, oldRs.Name)
|
||||
err = nil
|
||||
}
|
||||
// Ignore the precondition violated error, but the RS isn't updated.
|
||||
if err == errorsutil.ErrPreconditionViolated {
|
||||
glog.V(4).Infof("%s %s/%s precondition doesn't hold, skip updating it.", oldRs.Kind, oldRs.Namespace, oldRs.Name)
|
||||
err = nil
|
||||
}
|
||||
|
||||
// If the error is non-nil the returned RS cannot be trusted; if rsUpdated is false, the contoller isn't updated;
|
||||
// if the error is nil and rsUpdated is true, the returned RS contains the applied update.
|
||||
return rs, rsUpdated, err
|
||||
}
|
||||
|
||||
// GetPodTemplateSpecHash returns the pod template hash of a ReplicaSet's pod template space
|
||||
func GetPodTemplateSpecHash(rs extensions.ReplicaSet) string {
|
||||
meta := rs.Spec.Template.ObjectMeta
|
||||
meta.Labels = labelsutil.CloneAndRemoveLabel(meta.Labels, extensions.DefaultDeploymentUniqueLabelKey)
|
||||
return fmt.Sprintf("%d", podutil.GetPodTemplateSpecHash(api.PodTemplateSpec{
|
||||
ObjectMeta: meta,
|
||||
Spec: rs.Spec.Template.Spec,
|
||||
}))
|
||||
}
|
||||
|
||||
// MatchingPodsFunc returns a filter function for pods with matching labels
|
||||
func MatchingPodsFunc(rs *extensions.ReplicaSet) (func(api.Pod) bool, error) {
|
||||
if rs == nil {
|
||||
return nil, nil
|
||||
}
|
||||
selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
return func(pod api.Pod) bool {
|
||||
podLabelsSelector := labels.Set(pod.ObjectMeta.Labels)
|
||||
return selector.Matches(podLabelsSelector)
|
||||
}, nil
|
||||
}
|
||||
5
vendor/k8s.io/kubernetes/pkg/util/runtime/runtime.go
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/util/runtime/runtime.go
generated
vendored
|
|
@ -67,6 +67,11 @@ var ErrorHandlers = []func(error){logError}
|
|||
// is preferable to logging the error - the default behavior is to log but the
|
||||
// errors may be sent to a remote server for analysis.
|
||||
func HandleError(err error) {
|
||||
// this is sometimes called with a nil error. We probably shouldn't fail and should do nothing instead
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, fn := range ErrorHandlers {
|
||||
fn(err)
|
||||
}
|
||||
|
|
|
|||
29
vendor/k8s.io/kubernetes/pkg/util/sets/deep_copy_generated.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/util/sets/deep_copy_generated.go
generated
vendored
|
|
@ -1,29 +0,0 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2016 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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
func DeepCopy_sets_Empty(in Empty, out *Empty, c *conversion.Cloner) error {
|
||||
return nil
|
||||
}
|
||||
61
vendor/k8s.io/kubernetes/pkg/util/slice/slice.go
generated
vendored
Normal file
61
vendor/k8s.io/kubernetes/pkg/util/slice/slice.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2015 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 slice provides utility methods for common operations on slices.
|
||||
package slice
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
utilrand "k8s.io/kubernetes/pkg/util/rand"
|
||||
)
|
||||
|
||||
// CopyStrings copies the contents of the specified string slice
|
||||
// into a new slice.
|
||||
func CopyStrings(s []string) []string {
|
||||
c := make([]string, len(s))
|
||||
copy(c, s)
|
||||
return c
|
||||
}
|
||||
|
||||
// SortStrings sorts the specified string slice in place. It returns the same
|
||||
// slice that was provided in order to facilitate method chaining.
|
||||
func SortStrings(s []string) []string {
|
||||
sort.Strings(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// ShuffleStrings copies strings from the specified slice into a copy in random
|
||||
// order. It returns a new slice.
|
||||
func ShuffleStrings(s []string) []string {
|
||||
shuffled := make([]string, len(s))
|
||||
perm := utilrand.Perm(len(s))
|
||||
for i, j := range perm {
|
||||
shuffled[j] = s[i]
|
||||
}
|
||||
return shuffled
|
||||
}
|
||||
|
||||
// Int64Slice attaches the methods of Interface to []int64,
|
||||
// sorting in increasing order.
|
||||
type Int64Slice []int64
|
||||
|
||||
func (p Int64Slice) Len() int { return len(p) }
|
||||
func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] }
|
||||
func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
|
||||
// Sorts []int64 in increasing order
|
||||
func SortInts64(a []int64) { sort.Sort(Int64Slice(a)) }
|
||||
2
vendor/k8s.io/kubernetes/pkg/util/strategicpatch/patch.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/util/strategicpatch/patch.go
generated
vendored
|
|
@ -432,7 +432,7 @@ loopB:
|
|||
if !ignoreChangesAndAdditions {
|
||||
// Add any remaining items found only in modified
|
||||
for ; modifiedIndex < len(modifiedSorted); modifiedIndex++ {
|
||||
patch = append(patch, modified[modifiedIndex])
|
||||
patch = append(patch, modifiedSorted[modifiedIndex])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
119
vendor/k8s.io/kubernetes/pkg/util/validation/validation.go
generated
vendored
119
vendor/k8s.io/kubernetes/pkg/util/validation/validation.go
generated
vendored
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"regexp"
|
||||
|
|
@ -25,12 +26,17 @@ import (
|
|||
|
||||
const qnameCharFmt string = "[A-Za-z0-9]"
|
||||
const qnameExtCharFmt string = "[-A-Za-z0-9_.]"
|
||||
const QualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt
|
||||
const QualifiedNameMaxLength int = 63
|
||||
const qualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt
|
||||
const qualifiedNameMaxLength int = 63
|
||||
|
||||
var qualifiedNameRegexp = regexp.MustCompile("^" + QualifiedNameFmt + "$")
|
||||
var qualifiedNameRegexp = regexp.MustCompile("^" + qualifiedNameFmt + "$")
|
||||
|
||||
func IsQualifiedName(value string) bool {
|
||||
// IsQualifiedName tests whether the value passed is what Kubernetes calls a
|
||||
// "qualified name". This is a format used in various places throughout the
|
||||
// system. If the value is not valid, a list of error strings is returned.
|
||||
// Otherwise an empty list (or nil) is returned.
|
||||
func IsQualifiedName(value string) []string {
|
||||
var errs []string
|
||||
parts := strings.Split(value, "/")
|
||||
var name string
|
||||
switch len(parts) {
|
||||
|
|
@ -39,23 +45,44 @@ func IsQualifiedName(value string) bool {
|
|||
case 2:
|
||||
var prefix string
|
||||
prefix, name = parts[0], parts[1]
|
||||
if prefix == "" || !IsDNS1123Subdomain(prefix) {
|
||||
return false
|
||||
if len(prefix) == 0 {
|
||||
errs = append(errs, "prefix part "+EmptyError())
|
||||
} else if msgs := IsDNS1123Subdomain(prefix); len(msgs) != 0 {
|
||||
errs = append(errs, prefixEach(msgs, "prefix part ")...)
|
||||
}
|
||||
default:
|
||||
return false
|
||||
return append(errs, RegexError(qualifiedNameFmt, "MyName", "my.name", "123-abc")+
|
||||
" with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName'")
|
||||
}
|
||||
|
||||
return name != "" && len(name) <= QualifiedNameMaxLength && qualifiedNameRegexp.MatchString(name)
|
||||
if len(name) == 0 {
|
||||
errs = append(errs, "name part "+EmptyError())
|
||||
} else if len(name) > qualifiedNameMaxLength {
|
||||
errs = append(errs, "name part "+MaxLenError(qualifiedNameMaxLength))
|
||||
}
|
||||
if !qualifiedNameRegexp.MatchString(name) {
|
||||
errs = append(errs, "name part "+RegexError(qualifiedNameFmt, "MyName", "my.name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const LabelValueFmt string = "(" + QualifiedNameFmt + ")?"
|
||||
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||
const LabelValueMaxLength int = 63
|
||||
|
||||
var labelValueRegexp = regexp.MustCompile("^" + LabelValueFmt + "$")
|
||||
var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$")
|
||||
|
||||
func IsValidLabelValue(value string) bool {
|
||||
return (len(value) <= LabelValueMaxLength && labelValueRegexp.MatchString(value))
|
||||
// IsValidLabelValue tests whether the value passed is a valid label value. If
|
||||
// the value is not valid, a list of error strings is returned. Otherwise an
|
||||
// empty list (or nil) is returned.
|
||||
func IsValidLabelValue(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > LabelValueMaxLength {
|
||||
errs = append(errs, MaxLenError(LabelValueMaxLength))
|
||||
}
|
||||
if !labelValueRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(labelValueFmt, "MyValue", "my_value", "12345"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const DNS1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
|
||||
|
|
@ -65,8 +92,15 @@ var dns1123LabelRegexp = regexp.MustCompile("^" + DNS1123LabelFmt + "$")
|
|||
|
||||
// IsDNS1123Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 1123).
|
||||
func IsDNS1123Label(value string) bool {
|
||||
return len(value) <= DNS1123LabelMaxLength && dns1123LabelRegexp.MatchString(value)
|
||||
func IsDNS1123Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123LabelMaxLength))
|
||||
}
|
||||
if !dns1123LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(DNS1123LabelFmt, "my-name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const DNS1123SubdomainFmt string = DNS1123LabelFmt + "(\\." + DNS1123LabelFmt + ")*"
|
||||
|
|
@ -76,8 +110,15 @@ var dns1123SubdomainRegexp = regexp.MustCompile("^" + DNS1123SubdomainFmt + "$")
|
|||
|
||||
// IsDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// subdomain in DNS (RFC 1123).
|
||||
func IsDNS1123Subdomain(value string) bool {
|
||||
return len(value) <= DNS1123SubdomainMaxLength && dns1123SubdomainRegexp.MatchString(value)
|
||||
func IsDNS1123Subdomain(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !dns1123SubdomainRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(DNS1123SubdomainFmt, "example.com"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const DNS952LabelFmt string = "[a-z]([-a-z0-9]*[a-z0-9])?"
|
||||
|
|
@ -87,8 +128,15 @@ var dns952LabelRegexp = regexp.MustCompile("^" + DNS952LabelFmt + "$")
|
|||
|
||||
// IsDNS952Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 952).
|
||||
func IsDNS952Label(value string) bool {
|
||||
return len(value) <= DNS952LabelMaxLength && dns952LabelRegexp.MatchString(value)
|
||||
func IsDNS952Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS952LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS952LabelMaxLength))
|
||||
}
|
||||
if !dns952LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(DNS952LabelFmt, "my-name", "abc-123"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const CIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
|
||||
|
|
@ -177,3 +225,38 @@ var httpHeaderNameRegexp = regexp.MustCompile("^" + HTTPHeaderNameFmt + "$")
|
|||
func IsHTTPHeaderName(value string) bool {
|
||||
return httpHeaderNameRegexp.MatchString(value)
|
||||
}
|
||||
|
||||
// MaxLenError returns a string explanation of a "string too long" validation
|
||||
// failure.
|
||||
func MaxLenError(length int) string {
|
||||
return fmt.Sprintf("must be no more than %d characters", length)
|
||||
}
|
||||
|
||||
// RegexError returns a string explanation of a regex validation failure.
|
||||
func RegexError(fmt string, examples ...string) string {
|
||||
s := "must match the regex " + fmt
|
||||
if len(examples) == 0 {
|
||||
return s
|
||||
}
|
||||
s += " (e.g. "
|
||||
for i := range examples {
|
||||
if i > 0 {
|
||||
s += " or "
|
||||
}
|
||||
s += "'" + examples[i] + "'"
|
||||
}
|
||||
return s + ")"
|
||||
}
|
||||
|
||||
// EmptyError returns a string explanation of a "must not be empty" validation
|
||||
// failure.
|
||||
func EmptyError() string {
|
||||
return "must be non-empty"
|
||||
}
|
||||
|
||||
func prefixEach(msgs []string, prefix string) []string {
|
||||
for i := range msgs {
|
||||
msgs[i] = prefix + msgs[i]
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
|
|
|||
47
vendor/k8s.io/kubernetes/pkg/util/wait/wait.go
generated
vendored
47
vendor/k8s.io/kubernetes/pkg/util/wait/wait.go
generated
vendored
|
|
@ -42,9 +42,19 @@ func Forever(f func(), period time.Duration) {
|
|||
}
|
||||
|
||||
// Until loops until stop channel is closed, running f every period.
|
||||
// Until is syntactic sugar on top of JitterUntil with zero jitter factor
|
||||
// Until is syntactic sugar on top of JitterUntil with zero jitter
|
||||
// factor, with sliding = true (which means the timer for period
|
||||
// starts after the f completes).
|
||||
func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
|
||||
JitterUntil(f, period, 0.0, stopCh)
|
||||
JitterUntil(f, period, 0.0, true, stopCh)
|
||||
}
|
||||
|
||||
// NonSlidingUntil loops until stop channel is closed, running f every
|
||||
// period. NonSlidingUntil is syntactic sugar on top of JitterUntil
|
||||
// with zero jitter factor, with sliding = false (meaning the timer for
|
||||
// period starts at the same time as the function starts).
|
||||
func NonSlidingUntil(f func(), period time.Duration, stopCh <-chan struct{}) {
|
||||
JitterUntil(f, period, 0.0, false, stopCh)
|
||||
}
|
||||
|
||||
// JitterUntil loops until stop channel is closed, running f every period.
|
||||
|
|
@ -53,7 +63,7 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
|
|||
// Catches any panics, and keeps going. f may not be invoked if
|
||||
// stop channel is already closed. Pass NeverStop to Until if you
|
||||
// don't want it stop.
|
||||
func JitterUntil(f func(), period time.Duration, jitterFactor float64, stopCh <-chan struct{}) {
|
||||
func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
|
|
@ -61,20 +71,37 @@ func JitterUntil(f func(), period time.Duration, jitterFactor float64, stopCh <-
|
|||
}
|
||||
|
||||
for {
|
||||
func() {
|
||||
defer runtime.HandleCrash()
|
||||
f()
|
||||
}()
|
||||
|
||||
jitteredPeriod := period
|
||||
if jitterFactor > 0.0 {
|
||||
jitteredPeriod = Jitter(period, jitterFactor)
|
||||
}
|
||||
|
||||
var t *time.Timer
|
||||
if !sliding {
|
||||
t = time.NewTimer(jitteredPeriod)
|
||||
}
|
||||
|
||||
func() {
|
||||
defer runtime.HandleCrash()
|
||||
f()
|
||||
}()
|
||||
|
||||
if sliding {
|
||||
t = time.NewTimer(jitteredPeriod)
|
||||
} else {
|
||||
// The timer we created could already have fired, so be
|
||||
// careful and check stopCh first.
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-time.After(jitteredPeriod):
|
||||
case <-t.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,6 +170,8 @@ func pollInternal(wait WaitFunc, condition ConditionFunc) error {
|
|||
return WaitFor(wait, condition, done)
|
||||
}
|
||||
|
||||
// PollImmediate is identical to Poll, except that it performs the first check
|
||||
// immediately, not waiting interval beforehand.
|
||||
func PollImmediate(interval, timeout time.Duration, condition ConditionFunc) error {
|
||||
return pollImmediateInternal(poller(interval, timeout), condition)
|
||||
}
|
||||
|
|
|
|||
204
vendor/k8s.io/kubernetes/pkg/util/workqueue/default_rate_limiters.go
generated
vendored
Normal file
204
vendor/k8s.io/kubernetes/pkg/util/workqueue/default_rate_limiters.go
generated
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
Copyright 2016 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 workqueue
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/juju/ratelimit"
|
||||
)
|
||||
|
||||
type RateLimiter interface {
|
||||
// When gets an item and gets to decide how long that item should wait
|
||||
When(item interface{}) time.Duration
|
||||
// Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing
|
||||
// or for success, we'll stop tracking it
|
||||
Forget(item interface{})
|
||||
// NumRequeues returns back how many failures the item has had
|
||||
NumRequeues(item interface{}) int
|
||||
}
|
||||
|
||||
// DefaultControllerRateLimiter is a no-arg constructor for a default rate limiter for a workqueue. It has
|
||||
// both overall and per-item rate limitting. The overall is a token bucket and the per-item is exponential
|
||||
func DefaultControllerRateLimiter() RateLimiter {
|
||||
return NewMaxOfRateLimiter(
|
||||
DefaultItemBasedRateLimiter(),
|
||||
// 10 qps, 100 bucket size. This is only for retry speed and its only the overall factor (not per item)
|
||||
&BucketRateLimiter{Bucket: ratelimit.NewBucketWithRate(float64(10), int64(100))},
|
||||
)
|
||||
}
|
||||
|
||||
// BucketRateLimiter adapts a standard bucket to the workqueue ratelimiter API
|
||||
type BucketRateLimiter struct {
|
||||
*ratelimit.Bucket
|
||||
}
|
||||
|
||||
var _ RateLimiter = &BucketRateLimiter{}
|
||||
|
||||
func (r *BucketRateLimiter) When(item interface{}) time.Duration {
|
||||
return r.Bucket.Take(1)
|
||||
}
|
||||
|
||||
func (r *BucketRateLimiter) NumRequeues(item interface{}) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (r *BucketRateLimiter) Forget(item interface{}) {
|
||||
}
|
||||
|
||||
// ItemExponentialFailureRateLimiter does a simple baseDelay*10^<num-failures> limit
|
||||
// dealing with max failures and expiration are up to the caller
|
||||
type ItemExponentialFailureRateLimiter struct {
|
||||
failuresLock sync.Mutex
|
||||
failures map[interface{}]int
|
||||
|
||||
baseDelay time.Duration
|
||||
maxDelay time.Duration
|
||||
}
|
||||
|
||||
var _ RateLimiter = &ItemExponentialFailureRateLimiter{}
|
||||
|
||||
func NewItemExponentialFailureRateLimiter(baseDelay time.Duration, maxDelay time.Duration) RateLimiter {
|
||||
return &ItemExponentialFailureRateLimiter{
|
||||
failures: map[interface{}]int{},
|
||||
baseDelay: baseDelay,
|
||||
maxDelay: maxDelay,
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultItemBasedRateLimiter() RateLimiter {
|
||||
return NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1000*time.Second)
|
||||
}
|
||||
|
||||
func (r *ItemExponentialFailureRateLimiter) When(item interface{}) time.Duration {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
r.failures[item] = r.failures[item] + 1
|
||||
|
||||
calculated := r.baseDelay * time.Duration(math.Pow10(r.failures[item]-1))
|
||||
if calculated > r.maxDelay {
|
||||
return r.maxDelay
|
||||
}
|
||||
|
||||
return calculated
|
||||
}
|
||||
|
||||
func (r *ItemExponentialFailureRateLimiter) NumRequeues(item interface{}) int {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
return r.failures[item]
|
||||
}
|
||||
|
||||
func (r *ItemExponentialFailureRateLimiter) Forget(item interface{}) {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
delete(r.failures, item)
|
||||
}
|
||||
|
||||
// ItemFastSlowRateLimiter does a quick retry for a certain number of attempts, then a slow retry after that
|
||||
type ItemFastSlowRateLimiter struct {
|
||||
failuresLock sync.Mutex
|
||||
failures map[interface{}]int
|
||||
|
||||
maxFastAttempts int
|
||||
fastDelay time.Duration
|
||||
slowDelay time.Duration
|
||||
}
|
||||
|
||||
var _ RateLimiter = &ItemFastSlowRateLimiter{}
|
||||
|
||||
func NewItemFastSlowRateLimiter(fastDelay, slowDelay time.Duration, maxFastAttempts int) RateLimiter {
|
||||
return &ItemFastSlowRateLimiter{
|
||||
failures: map[interface{}]int{},
|
||||
fastDelay: fastDelay,
|
||||
slowDelay: slowDelay,
|
||||
maxFastAttempts: maxFastAttempts,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ItemFastSlowRateLimiter) When(item interface{}) time.Duration {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
r.failures[item] = r.failures[item] + 1
|
||||
|
||||
if r.failures[item] <= r.maxFastAttempts {
|
||||
return r.fastDelay
|
||||
}
|
||||
|
||||
return r.slowDelay
|
||||
}
|
||||
|
||||
func (r *ItemFastSlowRateLimiter) NumRequeues(item interface{}) int {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
return r.failures[item]
|
||||
}
|
||||
|
||||
func (r *ItemFastSlowRateLimiter) Forget(item interface{}) {
|
||||
r.failuresLock.Lock()
|
||||
defer r.failuresLock.Unlock()
|
||||
|
||||
delete(r.failures, item)
|
||||
}
|
||||
|
||||
// MaxOfRateLimiter calls every RateLimiter and returns the worst case response
|
||||
// When used with a token bucket limiter, the burst could be apparently exceeded in cases where particular items
|
||||
// were separately delayed a longer time.
|
||||
type MaxOfRateLimiter struct {
|
||||
limiters []RateLimiter
|
||||
}
|
||||
|
||||
func (r *MaxOfRateLimiter) When(item interface{}) time.Duration {
|
||||
ret := time.Duration(0)
|
||||
for _, limiter := range r.limiters {
|
||||
curr := limiter.When(item)
|
||||
if curr > ret {
|
||||
ret = curr
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewMaxOfRateLimiter(limiters ...RateLimiter) RateLimiter {
|
||||
return &MaxOfRateLimiter{limiters: limiters}
|
||||
}
|
||||
|
||||
func (r *MaxOfRateLimiter) NumRequeues(item interface{}) int {
|
||||
ret := 0
|
||||
for _, limiter := range r.limiters {
|
||||
curr := limiter.NumRequeues(item)
|
||||
if curr > ret {
|
||||
ret = curr
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *MaxOfRateLimiter) Forget(item interface{}) {
|
||||
for _, limiter := range r.limiters {
|
||||
limiter.Forget(item)
|
||||
}
|
||||
}
|
||||
61
vendor/k8s.io/kubernetes/pkg/util/workqueue/rate_limitting_queue.go
generated
vendored
Normal file
61
vendor/k8s.io/kubernetes/pkg/util/workqueue/rate_limitting_queue.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2016 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 workqueue
|
||||
|
||||
// RateLimitingInterface is an Interface that can Add an item at a later time. This makes it easier to
|
||||
// requeue items after failures without ending up in a hot-loop.
|
||||
type RateLimitingInterface interface {
|
||||
DelayingInterface
|
||||
// AddRateLimited adds an item to the workqueue after the rate limiter says its ok
|
||||
AddRateLimited(item interface{})
|
||||
|
||||
// Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing
|
||||
// or for success, we'll stop the rate limiter from tracking it. This only clears the `rateLimiter`, you
|
||||
// still have to call `Done` on the queue.
|
||||
Forget(item interface{})
|
||||
// NumRequeues returns back how many times the item was requeued
|
||||
NumRequeues(item interface{}) int
|
||||
}
|
||||
|
||||
// NewRateLimitingQueue constructs a new workqueue with rateLimited queuing ability
|
||||
// Remember to call Forget! If you don't, you may end up tracking failures forever.
|
||||
func NewRateLimitingQueue(rateLimiter RateLimiter) RateLimitingInterface {
|
||||
return &rateLimitingType{
|
||||
DelayingInterface: NewDelayingQueue(),
|
||||
rateLimiter: rateLimiter,
|
||||
}
|
||||
}
|
||||
|
||||
// rateLimitingType wraps an Interface and provides rateLimited re-enquing
|
||||
type rateLimitingType struct {
|
||||
DelayingInterface
|
||||
|
||||
rateLimiter RateLimiter
|
||||
}
|
||||
|
||||
// AddRateLimited AddAfter's the item based on the time when the rate limiter says its ok
|
||||
func (q *rateLimitingType) AddRateLimited(item interface{}) {
|
||||
q.DelayingInterface.AddAfter(item, q.rateLimiter.When(item))
|
||||
}
|
||||
|
||||
func (q *rateLimitingType) NumRequeues(item interface{}) int {
|
||||
return q.rateLimiter.NumRequeues(item)
|
||||
}
|
||||
|
||||
func (q *rateLimitingType) Forget(item interface{}) {
|
||||
q.rateLimiter.Forget(item)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue