mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
33
vendor/k8s.io/client-go/tools/auth/BUILD
generated
vendored
33
vendor/k8s.io/client-go/tools/auth/BUILD
generated
vendored
@ -1,33 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["clientauth.go"],
|
||||
importpath = "k8s.io/client-go/tools/auth",
|
||||
deps = ["//vendor/k8s.io/client-go/rest:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = ["clientauth_test.go"],
|
||||
deps = ["//vendor/k8s.io/client-go/tools/auth:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
7
vendor/k8s.io/client-go/tools/auth/OWNERS
generated
vendored
Normal file
7
vendor/k8s.io/client-go/tools/auth/OWNERS
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
approvers:
|
||||
- sig-auth-authenticators-approvers
|
||||
reviewers:
|
||||
- sig-auth-authenticators-reviewers
|
||||
labels:
|
||||
- sig/auth
|
||||
|
26
vendor/k8s.io/client-go/tools/bootstrap/token/api/BUILD
generated
vendored
26
vendor/k8s.io/client-go/tools/bootstrap/token/api/BUILD
generated
vendored
@ -1,26 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/bootstrap/token/api",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
5
vendor/k8s.io/client-go/tools/bootstrap/token/api/OWNERS
generated
vendored
5
vendor/k8s.io/client-go/tools/bootstrap/token/api/OWNERS
generated
vendored
@ -1,5 +0,0 @@
|
||||
approvers:
|
||||
- jbeda
|
||||
- luxas
|
||||
reviewers:
|
||||
- mattmoyer
|
20
vendor/k8s.io/client-go/tools/bootstrap/token/api/doc.go
generated
vendored
20
vendor/k8s.io/client-go/tools/bootstrap/token/api/doc.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 api (pkg/bootstrap/token/api) contains constants and types needed for
|
||||
// bootstrap tokens as maintained by the BootstrapSigner and TokenCleaner
|
||||
// controllers (in pkg/controller/bootstrap)
|
||||
package api // import "k8s.io/client-go/tools/bootstrap/token/api"
|
100
vendor/k8s.io/client-go/tools/bootstrap/token/api/types.go
generated
vendored
100
vendor/k8s.io/client-go/tools/bootstrap/token/api/types.go
generated
vendored
@ -1,100 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 api
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// BootstrapTokenSecretPrefix is the prefix for bootstrap token names.
|
||||
// Bootstrap tokens secrets must be named in the form
|
||||
// `bootstrap-token-<token-id>`. This is the prefix to be used before the
|
||||
// token ID.
|
||||
BootstrapTokenSecretPrefix = "bootstrap-token-"
|
||||
|
||||
// SecretTypeBootstrapToken is used during the automated bootstrap process (first
|
||||
// implemented by kubeadm). It stores tokens that are used to sign well known
|
||||
// ConfigMaps. They may also eventually be used for authentication.
|
||||
SecretTypeBootstrapToken v1.SecretType = "bootstrap.kubernetes.io/token"
|
||||
|
||||
// BootstrapTokenIDKey is the id of this token. This can be transmitted in the
|
||||
// clear and encoded in the name of the secret. It must be a random 6 character
|
||||
// string that matches the regexp `^([a-z0-9]{6})$`. Required.
|
||||
BootstrapTokenIDKey = "token-id"
|
||||
|
||||
// BootstrapTokenSecretKey is the actual secret. It must be a random 16 character
|
||||
// string that matches the regexp `^([a-z0-9]{16})$`. Required.
|
||||
BootstrapTokenSecretKey = "token-secret"
|
||||
|
||||
// BootstrapTokenExpirationKey is when this token should be expired and no
|
||||
// longer used. A controller will delete this resource after this time. This
|
||||
// is an absolute UTC time using RFC3339. If this cannot be parsed, the token
|
||||
// should be considered invalid. Optional.
|
||||
BootstrapTokenExpirationKey = "expiration"
|
||||
|
||||
// BootstrapTokenDescriptionKey is a description in human-readable format that
|
||||
// describes what the bootstrap token is used for. Optional.
|
||||
BootstrapTokenDescriptionKey = "description"
|
||||
|
||||
// BootstrapTokenExtraGroupsKey is a comma-separated list of group names.
|
||||
// The bootstrap token will authenticate as these groups in addition to the
|
||||
// "system:bootstrappers" group.
|
||||
BootstrapTokenExtraGroupsKey = "auth-extra-groups"
|
||||
|
||||
// BootstrapTokenUsagePrefix is the prefix for the other usage constants that specifies different
|
||||
// functions of a bootstrap token
|
||||
BootstrapTokenUsagePrefix = "usage-bootstrap-"
|
||||
|
||||
// BootstrapTokenUsageSigningKey signals that this token should be used to
|
||||
// sign configs as part of the bootstrap process. Value must be "true". Any
|
||||
// other value is assumed to be false. Optional.
|
||||
BootstrapTokenUsageSigningKey = "usage-bootstrap-signing"
|
||||
|
||||
// BootstrapTokenUsageAuthentication signals that this token should be used
|
||||
// as a bearer token to authenticate against the Kubernetes API. The bearer
|
||||
// token takes the form "<token-id>.<token-secret>" and authenticates as the
|
||||
// user "system:bootstrap:<token-id>" in the "system:bootstrappers" group
|
||||
// as well as any groups specified using BootstrapTokenExtraGroupsKey.
|
||||
// Value must be "true". Any other value is assumed to be false. Optional.
|
||||
BootstrapTokenUsageAuthentication = "usage-bootstrap-authentication"
|
||||
|
||||
// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist
|
||||
ConfigMapClusterInfo = "cluster-info"
|
||||
|
||||
// KubeConfigKey defines at which key in the Data object of the ConfigMap the KubeConfig object is stored
|
||||
KubeConfigKey = "kubeconfig"
|
||||
|
||||
// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have
|
||||
JWSSignatureKeyPrefix = "jws-kubeconfig-"
|
||||
|
||||
// BootstrapUserPrefix is the username prefix bootstrapping bearer tokens
|
||||
// authenticate as. The full username given is "system:bootstrap:<token-id>".
|
||||
BootstrapUserPrefix = "system:bootstrap:"
|
||||
|
||||
// BootstrapGroupPattern is the valid regex pattern that all groups
|
||||
// assigned to a bootstrap token by BootstrapTokenExtraGroupsKey must match.
|
||||
// See also ValidateBootstrapGroupName().
|
||||
BootstrapGroupPattern = "system:bootstrappers:[a-z0-9:-]{0,255}[a-z0-9]"
|
||||
|
||||
// BootstrapDefaultGroup is the default group for bootstrapping bearer
|
||||
// tokens (in addition to any groups from BootstrapTokenExtraGroupsKey).
|
||||
BootstrapDefaultGroup = "system:bootstrappers"
|
||||
)
|
||||
|
||||
// KnownTokenUsages specifies the known functions a token will get.
|
||||
var KnownTokenUsages = []string{"signing", "authentication"}
|
32
vendor/k8s.io/client-go/tools/bootstrap/token/util/BUILD
generated
vendored
32
vendor/k8s.io/client-go/tools/bootstrap/token/util/BUILD
generated
vendored
@ -1,32 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["helpers.go"],
|
||||
importpath = "k8s.io/client-go/tools/bootstrap/token/util",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["helpers_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
52
vendor/k8s.io/client-go/tools/bootstrap/token/util/helpers.go
generated
vendored
52
vendor/k8s.io/client-go/tools/bootstrap/token/util/helpers.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/bootstrap/token/api"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var bootstrapGroupRegexp = regexp.MustCompile(`\A` + api.BootstrapGroupPattern + `\z`)
|
||||
|
||||
// ValidateBootstrapGroupName checks if the provided group name is a valid
|
||||
// bootstrap group name. Returns nil if valid or a validation error if invalid.
|
||||
// TODO(mattmoyer): this validation should migrate out to client-go (see https://github.com/kubernetes/client-go/issues/114)
|
||||
func ValidateBootstrapGroupName(name string) error {
|
||||
if bootstrapGroupRegexp.Match([]byte(name)) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("bootstrap group %q is invalid (must match %s)", name, api.BootstrapGroupPattern)
|
||||
}
|
||||
|
||||
// ValidateUsages validates that the passed in string are valid usage strings for bootstrap tokens.
|
||||
func ValidateUsages(usages []string) error {
|
||||
validUsages := sets.NewString(api.KnownTokenUsages...)
|
||||
invalidUsages := sets.NewString()
|
||||
for _, usage := range usages {
|
||||
if !validUsages.Has(usage) {
|
||||
invalidUsages.Insert(usage)
|
||||
}
|
||||
}
|
||||
if len(invalidUsages) > 0 {
|
||||
return fmt.Errorf("invalide bootstrap token usage string: %s, valid usage options: %s", strings.Join(invalidUsages.List(), ","), strings.Join(api.KnownTokenUsages, ","))
|
||||
}
|
||||
return nil
|
||||
}
|
76
vendor/k8s.io/client-go/tools/bootstrap/token/util/helpers_test.go
generated
vendored
76
vendor/k8s.io/client-go/tools/bootstrap/token/util/helpers_test.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 util
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateBootstrapGroupName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
valid bool
|
||||
}{
|
||||
{"valid", "system:bootstrappers:foo", true},
|
||||
{"valid nested", "system:bootstrappers:foo:bar:baz", true},
|
||||
{"valid with dashes and number", "system:bootstrappers:foo-bar-42", true},
|
||||
{"invalid uppercase", "system:bootstrappers:Foo", false},
|
||||
{"missing prefix", "foo", false},
|
||||
{"prefix with no body", "system:bootstrappers:", false},
|
||||
{"invalid spaces", "system:bootstrappers: ", false},
|
||||
{"invalid asterisk", "system:bootstrappers:*", false},
|
||||
{"trailing colon", "system:bootstrappers:foo:", false},
|
||||
{"trailing dash", "system:bootstrappers:foo-", false},
|
||||
{"script tags", "system:bootstrappers:<script> alert(\"scary?!\") </script>", false},
|
||||
{"too long", "system:bootstrappers:" + strings.Repeat("x", 300), false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
err := ValidateBootstrapGroupName(test.input)
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("test %q: ValidateBootstrapGroupName(%q) returned unexpected error: %v", test.name, test.input, err)
|
||||
}
|
||||
if err == nil && !test.valid {
|
||||
t.Errorf("test %q: ValidateBootstrapGroupName(%q) was supposed to return an error but didn't", test.name, test.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUsages(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
valid bool
|
||||
}{
|
||||
{"valid of signing", []string{"signing"}, true},
|
||||
{"valid of authentication", []string{"authentication"}, true},
|
||||
{"all valid", []string{"authentication", "signing"}, true},
|
||||
{"single invalid", []string{"authentication", "foo"}, false},
|
||||
{"all invalid", []string{"foo", "bar"}, false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := ValidateUsages(test.input)
|
||||
if err != nil && test.valid {
|
||||
t.Errorf("test %q: ValidateUsages(%v) returned unexpected error: %v", test.name, test.input, err)
|
||||
}
|
||||
if err == nil && !test.valid {
|
||||
t.Errorf("test %q: ValidateUsages(%v) was supposed to return an error but didn't", test.name, test.input)
|
||||
}
|
||||
}
|
||||
}
|
103
vendor/k8s.io/client-go/tools/cache/BUILD
generated
vendored
103
vendor/k8s.io/client-go/tools/cache/BUILD
generated
vendored
@ -1,103 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"controller_test.go",
|
||||
"delta_fifo_test.go",
|
||||
"expiration_cache_test.go",
|
||||
"fifo_test.go",
|
||||
"heap_test.go",
|
||||
"index_test.go",
|
||||
"mutation_detector_test.go",
|
||||
"processor_listener_test.go",
|
||||
"reflector_test.go",
|
||||
"shared_informer_test.go",
|
||||
"store_test.go",
|
||||
"undelta_store_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
race = "off",
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"controller.go",
|
||||
"delta_fifo.go",
|
||||
"doc.go",
|
||||
"expiration_cache.go",
|
||||
"expiration_cache_fakes.go",
|
||||
"fake_custom_store.go",
|
||||
"fifo.go",
|
||||
"heap.go",
|
||||
"index.go",
|
||||
"listers.go",
|
||||
"listwatch.go",
|
||||
"mutation_cache.go",
|
||||
"mutation_detector.go",
|
||||
"reflector.go",
|
||||
"reflector_metrics.go",
|
||||
"shared_informer.go",
|
||||
"store.go",
|
||||
"thread_safe_store.go",
|
||||
"undelta_store.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/cache",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/golang.org/x/net/context:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/cache:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/pager:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/buffer:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/retry:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/client-go/tools/cache/testing:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
30
vendor/k8s.io/client-go/tools/cache/delta_fifo.go
generated
vendored
30
vendor/k8s.io/client-go/tools/cache/delta_fifo.go
generated
vendored
@ -23,7 +23,7 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// NewDeltaFIFO returns a Store which can be used process changes to items.
|
||||
@ -320,17 +320,15 @@ func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) err
|
||||
newDeltas := append(f.items[id], Delta{actionType, obj})
|
||||
newDeltas = dedupDeltas(newDeltas)
|
||||
|
||||
_, exists := f.items[id]
|
||||
if len(newDeltas) > 0 {
|
||||
if !exists {
|
||||
if _, exists := f.items[id]; !exists {
|
||||
f.queue = append(f.queue, id)
|
||||
}
|
||||
f.items[id] = newDeltas
|
||||
f.cond.Broadcast()
|
||||
} else if exists {
|
||||
// We need to remove this from our map (extra items
|
||||
// in the queue are ignored if they are not in the
|
||||
// map).
|
||||
} else {
|
||||
// We need to remove this from our map (extra items in the queue are
|
||||
// ignored if they are not in the map).
|
||||
delete(f.items, id)
|
||||
}
|
||||
return nil
|
||||
@ -348,9 +346,6 @@ func (f *DeltaFIFO) List() []interface{} {
|
||||
func (f *DeltaFIFO) listLocked() []interface{} {
|
||||
list := make([]interface{}, 0, len(f.items))
|
||||
for _, item := range f.items {
|
||||
// Copy item's slice so operations on this slice
|
||||
// won't interfere with the object we return.
|
||||
item = copyDeltas(item)
|
||||
list = append(list, item.Newest().Object)
|
||||
}
|
||||
return list
|
||||
@ -398,10 +393,7 @@ func (f *DeltaFIFO) GetByKey(key string) (item interface{}, exists bool, err err
|
||||
func (f *DeltaFIFO) IsClosed() bool {
|
||||
f.closedLock.Lock()
|
||||
defer f.closedLock.Unlock()
|
||||
if f.closed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return f.closed
|
||||
}
|
||||
|
||||
// Pop blocks until an item is added to the queue, and then returns it. If
|
||||
@ -432,10 +424,10 @@ func (f *DeltaFIFO) Pop(process PopProcessFunc) (interface{}, error) {
|
||||
}
|
||||
id := f.queue[0]
|
||||
f.queue = f.queue[1:]
|
||||
item, ok := f.items[id]
|
||||
if f.initialPopulationCount > 0 {
|
||||
f.initialPopulationCount--
|
||||
}
|
||||
item, ok := f.items[id]
|
||||
if !ok {
|
||||
// Item may have been deleted subsequently.
|
||||
continue
|
||||
@ -506,10 +498,10 @@ func (f *DeltaFIFO) Replace(list []interface{}, resourceVersion string) error {
|
||||
deletedObj, exists, err := f.knownObjects.GetByKey(k)
|
||||
if err != nil {
|
||||
deletedObj = nil
|
||||
glog.Errorf("Unexpected error %v during lookup of key %v, placing DeleteFinalStateUnknown marker without object", err, k)
|
||||
klog.Errorf("Unexpected error %v during lookup of key %v, placing DeleteFinalStateUnknown marker without object", err, k)
|
||||
} else if !exists {
|
||||
deletedObj = nil
|
||||
glog.Infof("Key %v does not exist in known objects store, placing DeleteFinalStateUnknown marker without object", k)
|
||||
klog.Infof("Key %v does not exist in known objects store, placing DeleteFinalStateUnknown marker without object", k)
|
||||
}
|
||||
queuedDeletions++
|
||||
if err := f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}); err != nil {
|
||||
@ -553,10 +545,10 @@ func (f *DeltaFIFO) syncKey(key string) error {
|
||||
func (f *DeltaFIFO) syncKeyLocked(key string) error {
|
||||
obj, exists, err := f.knownObjects.GetByKey(key)
|
||||
if err != nil {
|
||||
glog.Errorf("Unexpected error %v during lookup of key %v, unable to queue object for sync", err, key)
|
||||
klog.Errorf("Unexpected error %v during lookup of key %v, unable to queue object for sync", err, key)
|
||||
return nil
|
||||
} else if !exists {
|
||||
glog.Infof("Key %v does not exist in known objects store, unable to queue object for sync", key)
|
||||
klog.Infof("Key %v does not exist in known objects store, unable to queue object for sync", key)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
6
vendor/k8s.io/client-go/tools/cache/expiration_cache.go
generated
vendored
6
vendor/k8s.io/client-go/tools/cache/expiration_cache.go
generated
vendored
@ -20,8 +20,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// ExpirationCache implements the store interface
|
||||
@ -95,7 +95,7 @@ func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
|
||||
return nil, false
|
||||
}
|
||||
if c.expirationPolicy.IsExpired(timestampedItem) {
|
||||
glog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
|
||||
klog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
|
||||
c.cacheStorage.Delete(key)
|
||||
return nil, false
|
||||
}
|
||||
@ -179,7 +179,7 @@ func (c *ExpirationCache) Delete(obj interface{}) error {
|
||||
func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) error {
|
||||
c.expirationLock.Lock()
|
||||
defer c.expirationLock.Unlock()
|
||||
items := map[string]interface{}{}
|
||||
items := make(map[string]interface{}, len(list))
|
||||
ts := c.clock.Now()
|
||||
for _, item := range list {
|
||||
key, err := c.keyFunc(item)
|
||||
|
2
vendor/k8s.io/client-go/tools/cache/fifo.go
generated
vendored
2
vendor/k8s.io/client-go/tools/cache/fifo.go
generated
vendored
@ -297,7 +297,7 @@ func (f *FIFO) Pop(process PopProcessFunc) (interface{}, error) {
|
||||
// after calling this function. f's queue is reset, too; upon return, it
|
||||
// will contain the items in the map, in no particular order.
|
||||
func (f *FIFO) Replace(list []interface{}, resourceVersion string) error {
|
||||
items := map[string]interface{}{}
|
||||
items := make(map[string]interface{}, len(list))
|
||||
for _, item := range list {
|
||||
key, err := f.keyFunc(item)
|
||||
if err != nil {
|
||||
|
2
vendor/k8s.io/client-go/tools/cache/heap.go
generated
vendored
2
vendor/k8s.io/client-go/tools/cache/heap.go
generated
vendored
@ -204,7 +204,7 @@ func (h *Heap) AddIfNotPresent(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// addIfNotPresentLocked assumes the lock is already held and adds the the provided
|
||||
// addIfNotPresentLocked assumes the lock is already held and adds the provided
|
||||
// item to the queue if it does not already exist.
|
||||
func (h *Heap) addIfNotPresentLocked(key string, obj interface{}) {
|
||||
if _, exists := h.data.items[key]; exists {
|
||||
|
75
vendor/k8s.io/client-go/tools/cache/index_test.go
generated
vendored
75
vendor/k8s.io/client-go/tools/cache/index_test.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -70,60 +71,31 @@ func TestMultiIndexKeys(t *testing.T) {
|
||||
index.Add(pod2)
|
||||
index.Add(pod3)
|
||||
|
||||
erniePods, err := index.ByIndex("byUser", "ernie")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(erniePods) != 2 {
|
||||
t.Errorf("Expected 2 pods but got %v", len(erniePods))
|
||||
}
|
||||
for _, erniePod := range erniePods {
|
||||
if erniePod.(*v1.Pod).Name != "one" && erniePod.(*v1.Pod).Name != "tre" {
|
||||
t.Errorf("Expected only 'one' or 'tre' but got %s", erniePod.(*v1.Pod).Name)
|
||||
}
|
||||
}
|
||||
|
||||
bertPods, err := index.ByIndex("byUser", "bert")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(bertPods) != 2 {
|
||||
t.Errorf("Expected 2 pods but got %v", len(bertPods))
|
||||
}
|
||||
for _, bertPod := range bertPods {
|
||||
if bertPod.(*v1.Pod).Name != "one" && bertPod.(*v1.Pod).Name != "two" {
|
||||
t.Errorf("Expected only 'one' or 'two' but got %s", bertPod.(*v1.Pod).Name)
|
||||
}
|
||||
}
|
||||
|
||||
oscarPods, err := index.ByIndex("byUser", "oscar")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(oscarPods) != 1 {
|
||||
t.Errorf("Expected 1 pods but got %v", len(erniePods))
|
||||
}
|
||||
for _, oscarPod := range oscarPods {
|
||||
if oscarPod.(*v1.Pod).Name != "two" {
|
||||
t.Errorf("Expected only 'two' but got %s", oscarPod.(*v1.Pod).Name)
|
||||
}
|
||||
}
|
||||
|
||||
ernieAndBertKeys, err := index.Index("byUser", pod1)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(ernieAndBertKeys) != 3 {
|
||||
t.Errorf("Expected 3 pods but got %v", len(ernieAndBertKeys))
|
||||
}
|
||||
for _, ernieAndBertKey := range ernieAndBertKeys {
|
||||
if ernieAndBertKey.(*v1.Pod).Name != "one" && ernieAndBertKey.(*v1.Pod).Name != "two" && ernieAndBertKey.(*v1.Pod).Name != "tre" {
|
||||
t.Errorf("Expected only 'one', 'two' or 'tre' but got %s", ernieAndBertKey.(*v1.Pod).Name)
|
||||
expected := map[string]sets.String{}
|
||||
expected["ernie"] = sets.NewString("one", "tre")
|
||||
expected["bert"] = sets.NewString("one", "two")
|
||||
expected["elmo"] = sets.NewString("tre")
|
||||
expected["oscar"] = sets.NewString("two")
|
||||
expected["elmo"] = sets.NewString() // let's just make sure we don't get anything back in this case
|
||||
{
|
||||
for k, v := range expected {
|
||||
found := sets.String{}
|
||||
indexResults, err := index.ByIndex("byUser", k)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
for _, item := range indexResults {
|
||||
found.Insert(item.(*v1.Pod).Name)
|
||||
}
|
||||
items := v.List()
|
||||
if !found.HasAll(items...) {
|
||||
t.Errorf("missing items, index %s, expected %v but found %v", k, items, found.List())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index.Delete(pod3)
|
||||
erniePods, err = index.ByIndex("byUser", "ernie")
|
||||
erniePods, err := index.ByIndex("byUser", "ernie")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -147,7 +119,7 @@ func TestMultiIndexKeys(t *testing.T) {
|
||||
copyOfPod2 := pod2.DeepCopy()
|
||||
copyOfPod2.Annotations["users"] = "oscar"
|
||||
index.Update(copyOfPod2)
|
||||
bertPods, err = index.ByIndex("byUser", "bert")
|
||||
bertPods, err := index.ByIndex("byUser", "bert")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -159,5 +131,4 @@ func TestMultiIndexKeys(t *testing.T) {
|
||||
t.Errorf("Expected only 'one' but got %s", bertPod.(*v1.Pod).Name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
4
vendor/k8s.io/client-go/tools/cache/listers.go
generated
vendored
4
vendor/k8s.io/client-go/tools/cache/listers.go
generated
vendored
@ -17,7 +17,7 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@ -60,7 +60,7 @@ func ListAllByNamespace(indexer Indexer, namespace string, selector labels.Selec
|
||||
items, err := indexer.Index(NamespaceIndex, &metav1.ObjectMeta{Namespace: namespace})
|
||||
if err != nil {
|
||||
// Ignore error; do slow search without index.
|
||||
glog.Warningf("can not retrieve list of objects using index : %v", err)
|
||||
klog.Warningf("can not retrieve list of objects using index : %v", err)
|
||||
for _, m := range indexer.List() {
|
||||
metadata, err := meta.Accessor(m)
|
||||
if err != nil {
|
||||
|
86
vendor/k8s.io/client-go/tools/cache/listwatch.go
generated
vendored
86
vendor/k8s.io/client-go/tools/cache/listwatch.go
generated
vendored
@ -17,15 +17,11 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/pager"
|
||||
@ -94,13 +90,6 @@ func NewFilteredListWatchFromClient(c Getter, resource string, namespace string,
|
||||
return &ListWatch{ListFunc: listFunc, WatchFunc: watchFunc}
|
||||
}
|
||||
|
||||
func timeoutFromListOptions(options metav1.ListOptions) time.Duration {
|
||||
if options.TimeoutSeconds != nil {
|
||||
return time.Duration(*options.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// List a set of apiserver resources
|
||||
func (lw *ListWatch) List(options metav1.ListOptions) (runtime.Object, error) {
|
||||
if !lw.DisableChunking {
|
||||
@ -113,76 +102,3 @@ func (lw *ListWatch) List(options metav1.ListOptions) (runtime.Object, error) {
|
||||
func (lw *ListWatch) Watch(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return lw.WatchFunc(options)
|
||||
}
|
||||
|
||||
// ListWatchUntil checks the provided conditions against the items returned by the list watcher, returning wait.ErrWaitTimeout
|
||||
// if timeout is exceeded without all conditions returning true, or an error if an error occurs.
|
||||
// TODO: check for watch expired error and retry watch from latest point? Same issue exists for Until.
|
||||
func ListWatchUntil(timeout time.Duration, lw ListerWatcher, conditions ...watch.ConditionFunc) (*watch.Event, error) {
|
||||
if len(conditions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
list, err := lw.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
initialItems, err := meta.ExtractList(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use the initial items as simulated "adds"
|
||||
var lastEvent *watch.Event
|
||||
currIndex := 0
|
||||
passedConditions := 0
|
||||
for _, condition := range conditions {
|
||||
// check the next condition against the previous event and short circuit waiting for the next watch
|
||||
if lastEvent != nil {
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ConditionSucceeded:
|
||||
for currIndex < len(initialItems) {
|
||||
lastEvent = &watch.Event{Type: watch.Added, Object: initialItems[currIndex]}
|
||||
currIndex++
|
||||
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
break ConditionSucceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
if passedConditions == len(conditions) {
|
||||
return lastEvent, nil
|
||||
}
|
||||
remainingConditions := conditions[passedConditions:]
|
||||
|
||||
metaObj, err := meta.ListAccessor(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currResourceVersion := metaObj.GetResourceVersion()
|
||||
|
||||
watchInterface, err := lw.Watch(metav1.ListOptions{ResourceVersion: currResourceVersion})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
evt, err := watch.Until(timeout, watchInterface, remainingConditions...)
|
||||
if err == watch.ErrWatchClosed {
|
||||
// present a consistent error interface to callers
|
||||
err = wait.ErrWaitTimeout
|
||||
}
|
||||
return evt, err
|
||||
}
|
||||
|
4
vendor/k8s.io/client-go/tools/cache/mutation_cache.go
generated
vendored
4
vendor/k8s.io/client-go/tools/cache/mutation_cache.go
generated
vendored
@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -156,7 +156,7 @@ func (c *mutationCache) ByIndex(name string, indexKey string) ([]interface{}, er
|
||||
}
|
||||
elements, err := fn(updated)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Unable to calculate an index entry for mutation cache entry %s: %v", key, err)
|
||||
klog.V(4).Infof("Unable to calculate an index entry for mutation cache entry %s: %v", key, err)
|
||||
continue
|
||||
}
|
||||
for _, inIndex := range elements {
|
||||
|
3
vendor/k8s.io/client-go/tools/cache/mutation_detector.go
generated
vendored
3
vendor/k8s.io/client-go/tools/cache/mutation_detector.go
generated
vendored
@ -24,6 +24,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
@ -43,6 +45,7 @@ func NewCacheMutationDetector(name string) CacheMutationDetector {
|
||||
if !mutationDetectionEnabled {
|
||||
return dummyMutationDetector{}
|
||||
}
|
||||
klog.Warningln("Mutation detector is enabled, this will result in memory leakage.")
|
||||
return &defaultCacheMutationDetector{name: name, period: 1 * time.Second}
|
||||
}
|
||||
|
||||
|
91
vendor/k8s.io/client-go/tools/cache/reflector.go
generated
vendored
91
vendor/k8s.io/client-go/tools/cache/reflector.go
generated
vendored
@ -24,9 +24,6 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
goruntime "runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -34,15 +31,16 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/naming"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// Reflector watches a specified resource and causes all changes to be reflected in the given store.
|
||||
@ -76,8 +74,6 @@ type Reflector struct {
|
||||
var (
|
||||
// We try to spread the load on apiserver by setting timeouts for
|
||||
// watch requests - it is random in [minWatchTimeout, 2*minWatchTimeout].
|
||||
// However, it can be modified to avoid periodic resync to break the
|
||||
// TCP connection.
|
||||
minWatchTimeout = 5 * time.Minute
|
||||
)
|
||||
|
||||
@ -96,7 +92,7 @@ func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interfa
|
||||
// resyncPeriod, so that you can use reflectors to periodically process everything as
|
||||
// well as incrementally processing the things that change.
|
||||
func NewReflector(lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector {
|
||||
return NewNamedReflector(getDefaultReflectorName(internalPackages...), lw, expectedType, store, resyncPeriod)
|
||||
return NewNamedReflector(naming.GetNameFromCallsite(internalPackages...), lw, expectedType, store, resyncPeriod)
|
||||
}
|
||||
|
||||
// reflectorDisambiguator is used to disambiguate started reflectors.
|
||||
@ -127,79 +123,12 @@ func makeValidPrometheusMetricLabel(in string) string {
|
||||
|
||||
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
|
||||
// call chains to NewReflector, so they'd be low entropy names for reflectors
|
||||
var internalPackages = []string{"client-go/tools/cache/", "/runtime/asm_"}
|
||||
|
||||
// getDefaultReflectorName walks back through the call stack until we find a caller from outside of the ignoredPackages
|
||||
// it returns back a shortpath/filename:line to aid in identification of this reflector when it starts logging
|
||||
func getDefaultReflectorName(ignoredPackages ...string) string {
|
||||
name := "????"
|
||||
const maxStack = 10
|
||||
for i := 1; i < maxStack; i++ {
|
||||
_, file, line, ok := goruntime.Caller(i)
|
||||
if !ok {
|
||||
file, line, ok = extractStackCreator()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
i += maxStack
|
||||
}
|
||||
if hasPackage(file, ignoredPackages) {
|
||||
continue
|
||||
}
|
||||
|
||||
file = trimPackagePrefix(file)
|
||||
name = fmt.Sprintf("%s:%d", file, line)
|
||||
break
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// hasPackage returns true if the file is in one of the ignored packages.
|
||||
func hasPackage(file string, ignoredPackages []string) bool {
|
||||
for _, ignoredPackage := range ignoredPackages {
|
||||
if strings.Contains(file, ignoredPackage) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// trimPackagePrefix reduces duplicate values off the front of a package name.
|
||||
func trimPackagePrefix(file string) string {
|
||||
if l := strings.LastIndex(file, "k8s.io/client-go/pkg/"); l >= 0 {
|
||||
return file[l+len("k8s.io/client-go/"):]
|
||||
}
|
||||
if l := strings.LastIndex(file, "/src/"); l >= 0 {
|
||||
return file[l+5:]
|
||||
}
|
||||
if l := strings.LastIndex(file, "/pkg/"); l >= 0 {
|
||||
return file[l+1:]
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
var stackCreator = regexp.MustCompile(`(?m)^created by (.*)\n\s+(.*):(\d+) \+0x[[:xdigit:]]+$`)
|
||||
|
||||
// extractStackCreator retrieves the goroutine file and line that launched this stack. Returns false
|
||||
// if the creator cannot be located.
|
||||
// TODO: Go does not expose this via runtime https://github.com/golang/go/issues/11440
|
||||
func extractStackCreator() (string, int, bool) {
|
||||
stack := debug.Stack()
|
||||
matches := stackCreator.FindStringSubmatch(string(stack))
|
||||
if matches == nil || len(matches) != 4 {
|
||||
return "", 0, false
|
||||
}
|
||||
line, err := strconv.Atoi(matches[3])
|
||||
if err != nil {
|
||||
return "", 0, false
|
||||
}
|
||||
return matches[2], line, true
|
||||
}
|
||||
var internalPackages = []string{"client-go/tools/cache/"}
|
||||
|
||||
// Run starts a watch and handles watch events. Will restart the watch if it is closed.
|
||||
// Run will exit when stopCh is closed.
|
||||
func (r *Reflector) Run(stopCh <-chan struct{}) {
|
||||
glog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name)
|
||||
klog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name)
|
||||
wait.Until(func() {
|
||||
if err := r.ListAndWatch(stopCh); err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
@ -237,7 +166,7 @@ func (r *Reflector) resyncChan() (<-chan time.Time, func() bool) {
|
||||
// and then use the resource version to watch.
|
||||
// It returns error if ListAndWatch didn't even try to initialize watch.
|
||||
func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
glog.V(3).Infof("Listing and watching %v from %s", r.expectedType, r.name)
|
||||
klog.V(3).Infof("Listing and watching %v from %s", r.expectedType, r.name)
|
||||
var resourceVersion string
|
||||
|
||||
// Explicitly set "0" as resource version - it's fine for the List()
|
||||
@ -283,7 +212,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
return
|
||||
}
|
||||
if r.ShouldResync == nil || r.ShouldResync() {
|
||||
glog.V(4).Infof("%s: forcing resync", r.name)
|
||||
klog.V(4).Infof("%s: forcing resync", r.name)
|
||||
if err := r.store.Resync(); err != nil {
|
||||
resyncerrc <- err
|
||||
return
|
||||
@ -317,7 +246,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
case io.EOF:
|
||||
// watch closed normally
|
||||
case io.ErrUnexpectedEOF:
|
||||
glog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err)
|
||||
klog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err)
|
||||
default:
|
||||
utilruntime.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err))
|
||||
}
|
||||
@ -338,7 +267,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
|
||||
if err := r.watchHandler(w, &resourceVersion, resyncerrc, stopCh); err != nil {
|
||||
if err != errorStopRequested {
|
||||
glog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err)
|
||||
klog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -425,7 +354,7 @@ loop:
|
||||
r.metrics.numberOfShortWatches.Inc()
|
||||
return fmt.Errorf("very short watch: %s: Unexpected watch close - watch lasted less than a second and no items received", r.name)
|
||||
}
|
||||
glog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount)
|
||||
klog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
18
vendor/k8s.io/client-go/tools/cache/shared_informer.go
generated
vendored
18
vendor/k8s.io/client-go/tools/cache/shared_informer.go
generated
vendored
@ -28,7 +28,7 @@ import (
|
||||
"k8s.io/client-go/util/buffer"
|
||||
"k8s.io/client-go/util/retry"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// SharedInformer has a shared data cache and is capable of distributing notifications for changes
|
||||
@ -86,7 +86,7 @@ func NewSharedIndexInformer(lw ListerWatcher, objType runtime.Object, defaultEve
|
||||
resyncCheckPeriod: defaultEventHandlerResyncPeriod,
|
||||
defaultEventHandlerResyncPeriod: defaultEventHandlerResyncPeriod,
|
||||
cacheMutationDetector: NewCacheMutationDetector(fmt.Sprintf("%T", objType)),
|
||||
clock: realClock,
|
||||
clock: realClock,
|
||||
}
|
||||
return sharedIndexInformer
|
||||
}
|
||||
@ -116,11 +116,11 @@ func WaitForCacheSync(stopCh <-chan struct{}, cacheSyncs ...InformerSynced) bool
|
||||
},
|
||||
stopCh)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("stop requested")
|
||||
klog.V(2).Infof("stop requested")
|
||||
return false
|
||||
}
|
||||
|
||||
glog.V(4).Infof("caches populated")
|
||||
klog.V(4).Infof("caches populated")
|
||||
return true
|
||||
}
|
||||
|
||||
@ -279,11 +279,11 @@ func determineResyncPeriod(desired, check time.Duration) time.Duration {
|
||||
return desired
|
||||
}
|
||||
if check == 0 {
|
||||
glog.Warningf("The specified resyncPeriod %v is invalid because this shared informer doesn't support resyncing", desired)
|
||||
klog.Warningf("The specified resyncPeriod %v is invalid because this shared informer doesn't support resyncing", desired)
|
||||
return 0
|
||||
}
|
||||
if desired < check {
|
||||
glog.Warningf("The specified resyncPeriod %v is being increased to the minimum resyncCheckPeriod %v", desired, check)
|
||||
klog.Warningf("The specified resyncPeriod %v is being increased to the minimum resyncCheckPeriod %v", desired, check)
|
||||
return check
|
||||
}
|
||||
return desired
|
||||
@ -296,19 +296,19 @@ func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEv
|
||||
defer s.startedLock.Unlock()
|
||||
|
||||
if s.stopped {
|
||||
glog.V(2).Infof("Handler %v was not added to shared informer because it has stopped already", handler)
|
||||
klog.V(2).Infof("Handler %v was not added to shared informer because it has stopped already", handler)
|
||||
return
|
||||
}
|
||||
|
||||
if resyncPeriod > 0 {
|
||||
if resyncPeriod < minimumResyncPeriod {
|
||||
glog.Warningf("resyncPeriod %d is too small. Changing it to the minimum allowed value of %d", resyncPeriod, minimumResyncPeriod)
|
||||
klog.Warningf("resyncPeriod %d is too small. Changing it to the minimum allowed value of %d", resyncPeriod, minimumResyncPeriod)
|
||||
resyncPeriod = minimumResyncPeriod
|
||||
}
|
||||
|
||||
if resyncPeriod < s.resyncCheckPeriod {
|
||||
if s.started {
|
||||
glog.Warningf("resyncPeriod %d is smaller than resyncCheckPeriod %d and the informer has already started. Changing it to %d", resyncPeriod, s.resyncCheckPeriod, s.resyncCheckPeriod)
|
||||
klog.Warningf("resyncPeriod %d is smaller than resyncCheckPeriod %d and the informer has already started. Changing it to %d", resyncPeriod, s.resyncCheckPeriod, s.resyncCheckPeriod)
|
||||
resyncPeriod = s.resyncCheckPeriod
|
||||
} else {
|
||||
// if the event handler's resyncPeriod is smaller than the current resyncCheckPeriod, update
|
||||
|
2
vendor/k8s.io/client-go/tools/cache/store.go
generated
vendored
2
vendor/k8s.io/client-go/tools/cache/store.go
generated
vendored
@ -210,7 +210,7 @@ func (c *cache) GetByKey(key string) (item interface{}, exists bool, err error)
|
||||
// 'c' takes ownership of the list, you should not reference the list again
|
||||
// after calling this function.
|
||||
func (c *cache) Replace(list []interface{}, resourceVersion string) error {
|
||||
items := map[string]interface{}{}
|
||||
items := make(map[string]interface{}, len(list))
|
||||
for _, item := range list {
|
||||
key, err := c.keyFunc(item)
|
||||
if err != nil {
|
||||
|
45
vendor/k8s.io/client-go/tools/cache/testing/BUILD
generated
vendored
45
vendor/k8s.io/client-go/tools/cache/testing/BUILD
generated
vendored
@ -1,45 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["fake_controller_source_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake_controller_source.go"],
|
||||
importpath = "k8s.io/client-go/tools/cache/testing",
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
78
vendor/k8s.io/client-go/tools/clientcmd/BUILD
generated
vendored
78
vendor/k8s.io/client-go/tools/clientcmd/BUILD
generated
vendored
@ -1,78 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"client_config_test.go",
|
||||
"loader_test.go",
|
||||
"merged_client_builder_test.go",
|
||||
"overrides_test.go",
|
||||
"validation_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/github.com/imdario/mergo:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api/latest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"auth_loaders.go",
|
||||
"client_config.go",
|
||||
"config.go",
|
||||
"doc.go",
|
||||
"flag.go",
|
||||
"helpers.go",
|
||||
"loader.go",
|
||||
"merged_client_builder.go",
|
||||
"overrides.go",
|
||||
"validation.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/clientcmd",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/howeyc/gopass:go_default_library",
|
||||
"//vendor/github.com/imdario/mergo:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/auth:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api/latest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
50
vendor/k8s.io/client-go/tools/clientcmd/api/BUILD
generated
vendored
50
vendor/k8s.io/client-go/tools/clientcmd/api/BUILD
generated
vendored
@ -1,50 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"helpers_test.go",
|
||||
"types_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//vendor/github.com/ghodss/yaml:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"helpers.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/clientcmd/api",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api/latest:all-srcs",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api/v1:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
1
vendor/k8s.io/client-go/tools/clientcmd/api/doc.go
generated
vendored
1
vendor/k8s.io/client-go/tools/clientcmd/api/doc.go
generated
vendored
@ -15,4 +15,5 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package api
|
||||
|
9
vendor/k8s.io/client-go/tools/clientcmd/api/helpers.go
generated
vendored
9
vendor/k8s.io/client-go/tools/clientcmd/api/helpers.go
generated
vendored
@ -29,6 +29,8 @@ import (
|
||||
func init() {
|
||||
sDec, _ := base64.StdEncoding.DecodeString("REDACTED+")
|
||||
redactedBytes = []byte(string(sDec))
|
||||
sDec, _ = base64.StdEncoding.DecodeString("DATA+OMITTED")
|
||||
dataOmittedBytes = []byte(string(sDec))
|
||||
}
|
||||
|
||||
// IsConfigEmpty returns true if the config is empty.
|
||||
@ -79,7 +81,10 @@ func MinifyConfig(config *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var redactedBytes []byte
|
||||
var (
|
||||
redactedBytes []byte
|
||||
dataOmittedBytes []byte
|
||||
)
|
||||
|
||||
// Flatten redacts raw data entries from the config object for a human-readable view.
|
||||
func ShortenConfig(config *Config) {
|
||||
@ -97,7 +102,7 @@ func ShortenConfig(config *Config) {
|
||||
}
|
||||
for key, cluster := range config.Clusters {
|
||||
if len(cluster.CertificateAuthorityData) > 0 {
|
||||
cluster.CertificateAuthorityData = redactedBytes
|
||||
cluster.CertificateAuthorityData = dataOmittedBytes
|
||||
}
|
||||
config.Clusters[key] = cluster
|
||||
}
|
||||
|
9
vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go
generated
vendored
9
vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go
generated
vendored
@ -23,7 +23,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func newMergedConfig(certFile, certContent, keyFile, keyContent, caFile, caContent string, t *testing.T) Config {
|
||||
@ -229,7 +229,7 @@ func Example_minifyAndShorten() {
|
||||
// clusters:
|
||||
// cow-cluster:
|
||||
// LocationOfOrigin: ""
|
||||
// certificate-authority-data: REDACTED
|
||||
// certificate-authority-data: DATA+OMITTED
|
||||
// server: http://cow.org:8080
|
||||
// contexts:
|
||||
// federal-context:
|
||||
@ -276,14 +276,15 @@ func TestShortenSuccess(t *testing.T) {
|
||||
}
|
||||
|
||||
redacted := string(redactedBytes)
|
||||
dataOmitted := string(dataOmittedBytes)
|
||||
if len(mutatingConfig.Clusters) != 2 {
|
||||
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
|
||||
}
|
||||
if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) {
|
||||
t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster])
|
||||
}
|
||||
if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != redacted {
|
||||
t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData))
|
||||
if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != dataOmitted {
|
||||
t.Errorf("expected %v, got %v", dataOmitted, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData))
|
||||
}
|
||||
|
||||
if len(mutatingConfig.AuthInfos) != 2 {
|
||||
|
33
vendor/k8s.io/client-go/tools/clientcmd/api/latest/BUILD
generated
vendored
33
vendor/k8s.io/client-go/tools/clientcmd/api/latest/BUILD
generated
vendored
@ -1,33 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["latest.go"],
|
||||
importpath = "k8s.io/client-go/tools/clientcmd/api/latest",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
11
vendor/k8s.io/client-go/tools/clientcmd/api/latest/latest.go
generated
vendored
11
vendor/k8s.io/client-go/tools/clientcmd/api/latest/latest.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/clientcmd/api/v1"
|
||||
)
|
||||
@ -47,14 +48,8 @@ var (
|
||||
|
||||
func init() {
|
||||
Scheme = runtime.NewScheme()
|
||||
if err := api.AddToScheme(Scheme); err != nil {
|
||||
// Programmer error, detect immediately
|
||||
panic(err)
|
||||
}
|
||||
if err := v1.AddToScheme(Scheme); err != nil {
|
||||
// Programmer error, detect immediately
|
||||
panic(err)
|
||||
}
|
||||
utilruntime.Must(api.AddToScheme(Scheme))
|
||||
utilruntime.Must(v1.AddToScheme(Scheme))
|
||||
yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, Scheme, Scheme)
|
||||
Codec = versioning.NewDefaultingCodecForScheme(
|
||||
Scheme,
|
||||
|
32
vendor/k8s.io/client-go/tools/clientcmd/api/types.go
generated
vendored
32
vendor/k8s.io/client-go/tools/clientcmd/api/types.go
generated
vendored
@ -119,6 +119,9 @@ type AuthInfo struct {
|
||||
// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
|
||||
// +optional
|
||||
AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"`
|
||||
// Exec specifies a custom exec-based authentication plugin for the kubernetes cluster.
|
||||
// +optional
|
||||
Exec *ExecConfig `json:"exec,omitempty"`
|
||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||
// +optional
|
||||
Extensions map[string]runtime.Object `json:"extensions,omitempty"`
|
||||
@ -147,6 +150,35 @@ type AuthProviderConfig struct {
|
||||
Config map[string]string `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// ExecConfig specifies a command to provide client credentials. The command is exec'd
|
||||
// and outputs structured stdout holding credentials.
|
||||
//
|
||||
// See the client.authentiction.k8s.io API group for specifications of the exact input
|
||||
// and output format
|
||||
type ExecConfig struct {
|
||||
// Command to execute.
|
||||
Command string `json:"command"`
|
||||
// Arguments to pass to the command when executing it.
|
||||
// +optional
|
||||
Args []string `json:"args"`
|
||||
// Env defines additional environment variables to expose to the process. These
|
||||
// are unioned with the host's environment, as well as variables client-go uses
|
||||
// to pass argument to the plugin.
|
||||
// +optional
|
||||
Env []ExecEnvVar `json:"env"`
|
||||
|
||||
// Preferred input version of the ExecInfo. The returned ExecCredentials MUST use
|
||||
// the same encoding version as the input.
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// ExecEnvVar is used for setting environment variables when executing an exec-based
|
||||
// credential plugin.
|
||||
type ExecEnvVar struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// NewConfig is a convenience function that returns a new Config object with non-nil maps
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
|
2
vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go
generated
vendored
2
vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go
generated
vendored
@ -19,7 +19,7 @@ package api
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func Example_emptyConfig() {
|
||||
|
37
vendor/k8s.io/client-go/tools/clientcmd/api/v1/BUILD
generated
vendored
37
vendor/k8s.io/client-go/tools/clientcmd/api/v1/BUILD
generated
vendored
@ -1,37 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/clientcmd/api/v1",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
25
vendor/k8s.io/client-go/tools/clientcmd/api/v1/conversion.go
generated
vendored
25
vendor/k8s.io/client-go/tools/clientcmd/api/v1/conversion.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
@ -105,7 +106,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
if err := s.Convert(&curr.Cluster, newCluster, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[curr.Name] = newCluster
|
||||
if (*out)[curr.Name] == nil {
|
||||
(*out)[curr.Name] = newCluster
|
||||
} else {
|
||||
return fmt.Errorf("error converting *[]NamedCluster into *map[string]*api.Cluster: duplicate name \"%v\" in list: %v", curr.Name, *in)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -136,7 +141,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
if err := s.Convert(&curr.AuthInfo, newAuthInfo, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[curr.Name] = newAuthInfo
|
||||
if (*out)[curr.Name] == nil {
|
||||
(*out)[curr.Name] = newAuthInfo
|
||||
} else {
|
||||
return fmt.Errorf("error converting *[]NamedAuthInfo into *map[string]*api.AuthInfo: duplicate name \"%v\" in list: %v", curr.Name, *in)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -167,7 +176,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
if err := s.Convert(&curr.Context, newContext, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[curr.Name] = newContext
|
||||
if (*out)[curr.Name] == nil {
|
||||
(*out)[curr.Name] = newContext
|
||||
} else {
|
||||
return fmt.Errorf("error converting *[]NamedContext into *map[string]*api.Context: duplicate name \"%v\" in list: %v", curr.Name, *in)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -198,7 +211,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
if err := s.Convert(&curr.Extension, &newExtension, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[curr.Name] = newExtension
|
||||
if (*out)[curr.Name] == nil {
|
||||
(*out)[curr.Name] = newExtension
|
||||
} else {
|
||||
return fmt.Errorf("error converting *[]NamedExtension into *map[string]runtime.Object: duplicate name \"%v\" in list: %v", curr.Name, *in)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
1
vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go
generated
vendored
1
vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go
generated
vendored
@ -15,4 +15,5 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package v1
|
||||
|
32
vendor/k8s.io/client-go/tools/clientcmd/api/v1/types.go
generated
vendored
32
vendor/k8s.io/client-go/tools/clientcmd/api/v1/types.go
generated
vendored
@ -113,6 +113,9 @@ type AuthInfo struct {
|
||||
// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
|
||||
// +optional
|
||||
AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"`
|
||||
// Exec specifies a custom exec-based authentication plugin for the kubernetes cluster.
|
||||
// +optional
|
||||
Exec *ExecConfig `json:"exec,omitempty"`
|
||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||
// +optional
|
||||
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||
@ -169,3 +172,32 @@ type AuthProviderConfig struct {
|
||||
Name string `json:"name"`
|
||||
Config map[string]string `json:"config"`
|
||||
}
|
||||
|
||||
// ExecConfig specifies a command to provide client credentials. The command is exec'd
|
||||
// and outputs structured stdout holding credentials.
|
||||
//
|
||||
// See the client.authentiction.k8s.io API group for specifications of the exact input
|
||||
// and output format
|
||||
type ExecConfig struct {
|
||||
// Command to execute.
|
||||
Command string `json:"command"`
|
||||
// Arguments to pass to the command when executing it.
|
||||
// +optional
|
||||
Args []string `json:"args"`
|
||||
// Env defines additional environment variables to expose to the process. These
|
||||
// are unioned with the host's environment, as well as variables client-go uses
|
||||
// to pass argument to the plugin.
|
||||
// +optional
|
||||
Env []ExecEnvVar `json:"env"`
|
||||
|
||||
// Preferred input version of the ExecInfo. The returned ExecCredentials MUST use
|
||||
// the same encoding version as the input.
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// ExecEnvVar is used for setting environment variables when executing an exec-based
|
||||
// credential plugin.
|
||||
type ExecEnvVar struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
64
vendor/k8s.io/client-go/tools/clientcmd/api/v1/zz_generated.deepcopy.go
generated
vendored
64
vendor/k8s.io/client-go/tools/clientcmd/api/v1/zz_generated.deepcopy.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -46,22 +46,26 @@ func (in *AuthInfo) DeepCopyInto(out *AuthInfo) {
|
||||
in, out := &in.ImpersonateUserExtra, &out.ImpersonateUserExtra
|
||||
*out = make(map[string][]string, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal []string
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
(*out)[key] = make([]string, len(val))
|
||||
copy((*out)[key], val)
|
||||
in, out := &val, &outVal
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.AuthProvider != nil {
|
||||
in, out := &in.AuthProvider, &out.AuthProvider
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(AuthProviderConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
*out = new(AuthProviderConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Exec != nil {
|
||||
in, out := &in.Exec, &out.Exec
|
||||
*out = new(ExecConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Extensions != nil {
|
||||
in, out := &in.Extensions, &out.Extensions
|
||||
@ -210,6 +214,48 @@ func (in *Context) DeepCopy() *Context {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecConfig) DeepCopyInto(out *ExecConfig) {
|
||||
*out = *in
|
||||
if in.Args != nil {
|
||||
in, out := &in.Args, &out.Args
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]ExecEnvVar, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecConfig.
|
||||
func (in *ExecConfig) DeepCopy() *ExecConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecEnvVar) DeepCopyInto(out *ExecEnvVar) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecEnvVar.
|
||||
func (in *ExecEnvVar) DeepCopy() *ExecEnvVar {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecEnvVar)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NamedAuthInfo) DeepCopyInto(out *NamedAuthInfo) {
|
||||
*out = *in
|
||||
|
85
vendor/k8s.io/client-go/tools/clientcmd/api/zz_generated.deepcopy.go
generated
vendored
85
vendor/k8s.io/client-go/tools/clientcmd/api/zz_generated.deepcopy.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -46,22 +46,26 @@ func (in *AuthInfo) DeepCopyInto(out *AuthInfo) {
|
||||
in, out := &in.ImpersonateUserExtra, &out.ImpersonateUserExtra
|
||||
*out = make(map[string][]string, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal []string
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
(*out)[key] = make([]string, len(val))
|
||||
copy((*out)[key], val)
|
||||
in, out := &val, &outVal
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.AuthProvider != nil {
|
||||
in, out := &in.AuthProvider, &out.AuthProvider
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(AuthProviderConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
*out = new(AuthProviderConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Exec != nil {
|
||||
in, out := &in.Exec, &out.Exec
|
||||
*out = new(ExecConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Extensions != nil {
|
||||
in, out := &in.Extensions, &out.Extensions
|
||||
@ -150,36 +154,45 @@ func (in *Config) DeepCopyInto(out *Config) {
|
||||
in, out := &in.Clusters, &out.Clusters
|
||||
*out = make(map[string]*Cluster, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal *Cluster
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
(*out)[key] = new(Cluster)
|
||||
val.DeepCopyInto((*out)[key])
|
||||
in, out := &val, &outVal
|
||||
*out = new(Cluster)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.AuthInfos != nil {
|
||||
in, out := &in.AuthInfos, &out.AuthInfos
|
||||
*out = make(map[string]*AuthInfo, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal *AuthInfo
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
(*out)[key] = new(AuthInfo)
|
||||
val.DeepCopyInto((*out)[key])
|
||||
in, out := &val, &outVal
|
||||
*out = new(AuthInfo)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.Contexts != nil {
|
||||
in, out := &in.Contexts, &out.Contexts
|
||||
*out = make(map[string]*Context, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal *Context
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
(*out)[key] = new(Context)
|
||||
val.DeepCopyInto((*out)[key])
|
||||
in, out := &val, &outVal
|
||||
*out = new(Context)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
if in.Extensions != nil {
|
||||
@ -241,6 +254,48 @@ func (in *Context) DeepCopy() *Context {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecConfig) DeepCopyInto(out *ExecConfig) {
|
||||
*out = *in
|
||||
if in.Args != nil {
|
||||
in, out := &in.Args, &out.Args
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]ExecEnvVar, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecConfig.
|
||||
func (in *ExecConfig) DeepCopy() *ExecConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecEnvVar) DeepCopyInto(out *ExecEnvVar) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecEnvVar.
|
||||
func (in *ExecEnvVar) DeepCopy() *ExecEnvVar {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecEnvVar)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Preferences) DeepCopyInto(out *Preferences) {
|
||||
*out = *in
|
||||
|
11
vendor/k8s.io/client-go/tools/clientcmd/auth_loaders.go
generated
vendored
11
vendor/k8s.io/client-go/tools/clientcmd/auth_loaders.go
generated
vendored
@ -23,7 +23,8 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/howeyc/gopass"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
clientauth "k8s.io/client-go/tools/auth"
|
||||
)
|
||||
|
||||
@ -89,8 +90,12 @@ func promptForString(field string, r io.Reader, show bool) (result string, err e
|
||||
_, err = fmt.Fscan(r, &result)
|
||||
} else {
|
||||
var data []byte
|
||||
data, err = gopass.GetPasswdMasked()
|
||||
result = string(data)
|
||||
if terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||
data, err = terminal.ReadPassword(int(os.Stdin.Fd()))
|
||||
result = string(data)
|
||||
} else {
|
||||
return "", fmt.Errorf("error reading input for %s", field)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
69
vendor/k8s.io/client-go/tools/clientcmd/client_config.go
generated
vendored
69
vendor/k8s.io/client-go/tools/clientcmd/client_config.go
generated
vendored
@ -24,10 +24,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/imdario/mergo"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
clientauth "k8s.io/client-go/tools/auth"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@ -100,6 +99,26 @@ func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string,
|
||||
return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
|
||||
}
|
||||
|
||||
// NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig
|
||||
func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) {
|
||||
config, err := Load(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DirectClientConfig{*config, "", &ConfigOverrides{}, nil, nil, promptedCredentials{}}, nil
|
||||
}
|
||||
|
||||
// RESTConfigFromKubeConfig is a convenience method to give back a restconfig from your kubeconfig bytes.
|
||||
// For programmatic access, this is what you want 80% of the time
|
||||
func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) {
|
||||
clientConfig, err := NewClientConfigFromBytes(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clientConfig.ClientConfig()
|
||||
}
|
||||
|
||||
func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
||||
return config.config, nil
|
||||
}
|
||||
@ -156,10 +175,6 @@ func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
|
||||
// only try to read the auth information if we are secure
|
||||
if restclient.IsConfigTransportTLS(*clientConfig) {
|
||||
var err error
|
||||
|
||||
// mergo is a first write wins for map value and a last writing wins for interface values
|
||||
// NOTE: This behavior changed with https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a.
|
||||
// Our mergo.Merge version is older than this change.
|
||||
var persister restclient.AuthProviderConfigPersister
|
||||
if config.configAccess != nil {
|
||||
authInfoName, _ := config.getAuthInfoName()
|
||||
@ -169,13 +184,13 @@ func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mergo.Merge(clientConfig, userAuthPartialConfig)
|
||||
mergo.MergeWithOverwrite(clientConfig, userAuthPartialConfig)
|
||||
|
||||
serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mergo.Merge(clientConfig, serverAuthPartialConfig)
|
||||
mergo.MergeWithOverwrite(clientConfig, serverAuthPartialConfig)
|
||||
}
|
||||
|
||||
return clientConfig, nil
|
||||
@ -195,7 +210,7 @@ func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo,
|
||||
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
|
||||
configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
|
||||
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
|
||||
mergo.Merge(mergedConfig, configClientConfig)
|
||||
mergo.MergeWithOverwrite(mergedConfig, configClientConfig)
|
||||
|
||||
return mergedConfig, nil
|
||||
}
|
||||
@ -214,11 +229,11 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
|
||||
if len(configAuthInfo.Token) > 0 {
|
||||
mergedConfig.BearerToken = configAuthInfo.Token
|
||||
} else if len(configAuthInfo.TokenFile) > 0 {
|
||||
tokenBytes, err := ioutil.ReadFile(configAuthInfo.TokenFile)
|
||||
if err != nil {
|
||||
ts := restclient.NewCachedFileTokenSource(configAuthInfo.TokenFile)
|
||||
if _, err := ts.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mergedConfig.BearerToken = string(tokenBytes)
|
||||
mergedConfig.WrapTransport = restclient.TokenSourceWrapTransport(ts)
|
||||
}
|
||||
if len(configAuthInfo.Impersonate) > 0 {
|
||||
mergedConfig.Impersonate = restclient.ImpersonationConfig{
|
||||
@ -241,6 +256,9 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
|
||||
mergedConfig.AuthProvider = configAuthInfo.AuthProvider
|
||||
mergedConfig.AuthConfigPersister = persistAuthConfig
|
||||
}
|
||||
if configAuthInfo.Exec != nil {
|
||||
mergedConfig.ExecProvider = configAuthInfo.Exec
|
||||
}
|
||||
|
||||
// if there still isn't enough information to authenticate the user, try prompting
|
||||
if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
|
||||
@ -257,8 +275,8 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
|
||||
promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
|
||||
previouslyMergedConfig := mergedConfig
|
||||
mergedConfig = &restclient.Config{}
|
||||
mergo.Merge(mergedConfig, promptedConfig)
|
||||
mergo.Merge(mergedConfig, previouslyMergedConfig)
|
||||
mergo.MergeWithOverwrite(mergedConfig, promptedConfig)
|
||||
mergo.MergeWithOverwrite(mergedConfig, previouslyMergedConfig)
|
||||
config.promptedCredentials.username = mergedConfig.Username
|
||||
config.promptedCredentials.password = mergedConfig.Password
|
||||
}
|
||||
@ -291,7 +309,8 @@ func canIdentifyUser(config restclient.Config) bool {
|
||||
return len(config.Username) > 0 ||
|
||||
(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
|
||||
len(config.BearerToken) > 0 ||
|
||||
config.AuthProvider != nil
|
||||
config.AuthProvider != nil ||
|
||||
config.ExecProvider != nil
|
||||
}
|
||||
|
||||
// Namespace implements ClientConfig
|
||||
@ -314,7 +333,7 @@ func (config *DirectClientConfig) Namespace() (string, bool, error) {
|
||||
}
|
||||
|
||||
if len(configContext.Namespace) == 0 {
|
||||
return v1.NamespaceDefault, false, nil
|
||||
return "default", false, nil
|
||||
}
|
||||
|
||||
return configContext.Namespace, false, nil
|
||||
@ -400,11 +419,11 @@ func (config *DirectClientConfig) getContext() (clientcmdapi.Context, error) {
|
||||
|
||||
mergedContext := clientcmdapi.NewContext()
|
||||
if configContext, exists := contexts[contextName]; exists {
|
||||
mergo.Merge(mergedContext, configContext)
|
||||
mergo.MergeWithOverwrite(mergedContext, configContext)
|
||||
} else if required {
|
||||
return clientcmdapi.Context{}, fmt.Errorf("context %q does not exist", contextName)
|
||||
}
|
||||
mergo.Merge(mergedContext, config.overrides.Context)
|
||||
mergo.MergeWithOverwrite(mergedContext, config.overrides.Context)
|
||||
|
||||
return *mergedContext, nil
|
||||
}
|
||||
@ -416,11 +435,11 @@ func (config *DirectClientConfig) getAuthInfo() (clientcmdapi.AuthInfo, error) {
|
||||
|
||||
mergedAuthInfo := clientcmdapi.NewAuthInfo()
|
||||
if configAuthInfo, exists := authInfos[authInfoName]; exists {
|
||||
mergo.Merge(mergedAuthInfo, configAuthInfo)
|
||||
mergo.MergeWithOverwrite(mergedAuthInfo, configAuthInfo)
|
||||
} else if required {
|
||||
return clientcmdapi.AuthInfo{}, fmt.Errorf("auth info %q does not exist", authInfoName)
|
||||
}
|
||||
mergo.Merge(mergedAuthInfo, config.overrides.AuthInfo)
|
||||
mergo.MergeWithOverwrite(mergedAuthInfo, config.overrides.AuthInfo)
|
||||
|
||||
return *mergedAuthInfo, nil
|
||||
}
|
||||
@ -431,13 +450,13 @@ func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
|
||||
clusterInfoName, required := config.getClusterName()
|
||||
|
||||
mergedClusterInfo := clientcmdapi.NewCluster()
|
||||
mergo.Merge(mergedClusterInfo, config.overrides.ClusterDefaults)
|
||||
mergo.MergeWithOverwrite(mergedClusterInfo, config.overrides.ClusterDefaults)
|
||||
if configClusterInfo, exists := clusterInfos[clusterInfoName]; exists {
|
||||
mergo.Merge(mergedClusterInfo, configClusterInfo)
|
||||
mergo.MergeWithOverwrite(mergedClusterInfo, configClusterInfo)
|
||||
} else if required {
|
||||
return clientcmdapi.Cluster{}, fmt.Errorf("cluster %q does not exist", clusterInfoName)
|
||||
}
|
||||
mergo.Merge(mergedClusterInfo, config.overrides.ClusterInfo)
|
||||
mergo.MergeWithOverwrite(mergedClusterInfo, config.overrides.ClusterInfo)
|
||||
// An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
|
||||
// otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set"
|
||||
caLen := len(config.overrides.ClusterInfo.CertificateAuthority)
|
||||
@ -526,12 +545,12 @@ func (config *inClusterClientConfig) Possible() bool {
|
||||
// to the default config.
|
||||
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
|
||||
if kubeconfigPath == "" && masterUrl == "" {
|
||||
glog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
|
||||
klog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
|
||||
kubeconfig, err := restclient.InClusterConfig()
|
||||
if err == nil {
|
||||
return kubeconfig, nil
|
||||
}
|
||||
glog.Warning("error creating inClusterConfig, falling back to default config: ", err)
|
||||
klog.Warning("error creating inClusterConfig, falling back to default config: ", err)
|
||||
}
|
||||
return NewNonInteractiveDeferredLoadingClientConfig(
|
||||
&ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
|
||||
|
199
vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go
generated
vendored
199
vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go
generated
vendored
@ -18,31 +18,95 @@ package clientcmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
restclient "k8s.io/client-go/rest"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
func TestOldMergoLib(t *testing.T) {
|
||||
type T struct {
|
||||
X string
|
||||
func TestMergoSemantics(t *testing.T) {
|
||||
type U struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
dst := T{X: "one"}
|
||||
src := T{X: "two"}
|
||||
mergo.Merge(&dst, &src)
|
||||
if dst.X != "two" {
|
||||
// mergo.Merge changed in an incompatible way with
|
||||
//
|
||||
// https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a
|
||||
//
|
||||
// We have to stay with the old version which still does eager
|
||||
// copying from src to dst in structs.
|
||||
t.Errorf("mergo.Merge library found with incompatible, new behavior")
|
||||
type T struct {
|
||||
S []string
|
||||
X string
|
||||
Y int64
|
||||
U U
|
||||
}
|
||||
var testDataStruct = []struct {
|
||||
dst T
|
||||
src T
|
||||
expected T
|
||||
}{
|
||||
{
|
||||
dst: T{X: "one"},
|
||||
src: T{X: "two"},
|
||||
expected: T{X: "two"},
|
||||
},
|
||||
{
|
||||
dst: T{X: "one", Y: 5, U: U{A: "four", B: 6}},
|
||||
src: T{X: "two", U: U{A: "three", B: 4}},
|
||||
expected: T{X: "two", Y: 5, U: U{A: "three", B: 4}},
|
||||
},
|
||||
{
|
||||
dst: T{S: []string{"test3", "test4", "test5"}},
|
||||
src: T{S: []string{"test1", "test2", "test3"}},
|
||||
expected: T{S: []string{"test1", "test2", "test3"}},
|
||||
},
|
||||
}
|
||||
for _, data := range testDataStruct {
|
||||
err := mergo.MergeWithOverwrite(&data.dst, &data.src)
|
||||
if err != nil {
|
||||
t.Errorf("error while merging: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(data.dst, data.expected) {
|
||||
// The mergo library has previously changed in a an incompatible way.
|
||||
// example:
|
||||
//
|
||||
// https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a
|
||||
//
|
||||
// This test verifies that the semantics of the merge are what we expect.
|
||||
// If they are not, the mergo library may have been updated and broken
|
||||
// unexpectedly.
|
||||
t.Errorf("mergo.MergeWithOverwrite did not provide expected output: %+v doesn't match %+v", data.dst, data.expected)
|
||||
}
|
||||
}
|
||||
|
||||
var testDataMap = []struct {
|
||||
dst map[string]int
|
||||
src map[string]int
|
||||
expected map[string]int
|
||||
}{
|
||||
{
|
||||
dst: map[string]int{"rsc": 6543, "r": 2138, "gri": 1908, "adg": 912, "prt": 22},
|
||||
src: map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912},
|
||||
expected: map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912, "prt": 22},
|
||||
},
|
||||
}
|
||||
for _, data := range testDataMap {
|
||||
err := mergo.MergeWithOverwrite(&data.dst, &data.src)
|
||||
if err != nil {
|
||||
t.Errorf("error while merging: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(data.dst, data.expected) {
|
||||
// The mergo library has previously changed in a an incompatible way.
|
||||
// example:
|
||||
//
|
||||
// https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a
|
||||
//
|
||||
// This test verifies that the semantics of the merge are what we expect.
|
||||
// If they are not, the mergo library may have been updated and broken
|
||||
// unexpectedly.
|
||||
t.Errorf("mergo.MergeWithOverwrite did not provide expected output: %+v doesn't match %+v", data.dst, data.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +190,54 @@ func TestMergeContext(t *testing.T) {
|
||||
matchStringArg(namespace, actual, t)
|
||||
}
|
||||
|
||||
func TestModifyContext(t *testing.T) {
|
||||
expectedCtx := map[string]bool{
|
||||
"updated": true,
|
||||
"clean": true,
|
||||
}
|
||||
|
||||
tempPath, err := ioutil.TempFile("", "testclientcmd-")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
defer os.Remove(tempPath.Name())
|
||||
|
||||
pathOptions := NewDefaultPathOptions()
|
||||
config := createValidTestConfig()
|
||||
|
||||
pathOptions.GlobalFile = tempPath.Name()
|
||||
|
||||
// define new context and assign it - our path options config
|
||||
config.Contexts["updated"] = &clientcmdapi.Context{
|
||||
Cluster: "updated",
|
||||
AuthInfo: "updated",
|
||||
}
|
||||
config.CurrentContext = "updated"
|
||||
|
||||
if err := ModifyConfig(pathOptions, *config, true); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
startingConfig, err := pathOptions.GetStartingConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// make sure the current context was updated
|
||||
matchStringArg("updated", startingConfig.CurrentContext, t)
|
||||
|
||||
// there should now be two contexts
|
||||
if len(startingConfig.Contexts) != len(expectedCtx) {
|
||||
t.Fatalf("unexpected nuber of contexts, expecting %v, but found %v", len(expectedCtx), len(startingConfig.Contexts))
|
||||
}
|
||||
|
||||
for key := range startingConfig.Contexts {
|
||||
if !expectedCtx[key] {
|
||||
t.Fatalf("expected context %q to exist", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateData(t *testing.T) {
|
||||
caData := []byte("ca-data")
|
||||
certData := []byte("cert-data")
|
||||
@ -133,7 +245,7 @@ func TestCertificateData(t *testing.T) {
|
||||
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
||||
Server: "https://localhost:8443",
|
||||
Server: "https://localhost:8443",
|
||||
CertificateAuthorityData: caData,
|
||||
}
|
||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
||||
@ -222,7 +334,19 @@ func TestBasicTokenFile(t *testing.T) {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
matchStringArg(token, clientConfig.BearerToken, t)
|
||||
var out *http.Request
|
||||
clientConfig.WrapTransport(fakeTransport(func(req *http.Request) (*http.Response, error) {
|
||||
out = req
|
||||
return &http.Response{}, nil
|
||||
})).RoundTrip(&http.Request{})
|
||||
|
||||
matchStringArg(token, strings.TrimPrefix(out.Header.Get("Authorization"), "Bearer "), t)
|
||||
}
|
||||
|
||||
type fakeTransport func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (ft fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return ft(req)
|
||||
}
|
||||
|
||||
func TestPrecedenceTokenFile(t *testing.T) {
|
||||
@ -526,3 +650,46 @@ func TestNamespaceOverride(t *testing.T) {
|
||||
|
||||
matchStringArg("foo", ns, t)
|
||||
}
|
||||
|
||||
func TestAuthConfigMerge(t *testing.T) {
|
||||
content := `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://localhost:8080
|
||||
name: foo-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: foo-cluster
|
||||
user: foo-user
|
||||
namespace: bar
|
||||
name: foo-context
|
||||
current-context: foo-context
|
||||
kind: Config
|
||||
users:
|
||||
- name: foo-user
|
||||
user:
|
||||
exec:
|
||||
apiVersion: client.authentication.k8s.io/v1alpha1
|
||||
args:
|
||||
- arg-1
|
||||
- arg-2
|
||||
command: foo-command
|
||||
`
|
||||
tmpfile, err := ioutil.TempFile("", "kubeconfig")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer os.Remove(tmpfile.Name())
|
||||
if err := ioutil.WriteFile(tmpfile.Name(), []byte(content), 0666); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
config, err := BuildConfigFromFlags("", tmpfile.Name())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(config.ExecProvider.Args, []string{"arg-1", "arg-2"}) {
|
||||
t.Errorf("Got args %v when they should be %v\n", config.ExecProvider.Args, []string{"arg-1", "arg-2"})
|
||||
}
|
||||
|
||||
}
|
||||
|
38
vendor/k8s.io/client-go/tools/clientcmd/config.go
generated
vendored
38
vendor/k8s.io/client-go/tools/clientcmd/config.go
generated
vendored
@ -24,7 +24,7 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
restclient "k8s.io/client-go/rest"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@ -68,7 +68,9 @@ func (o *PathOptions) GetEnvVarFiles() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return filepath.SplitList(envVarValue)
|
||||
fileList := filepath.SplitList(envVarValue)
|
||||
// prevent the same path load multiple times
|
||||
return deduplicate(fileList)
|
||||
}
|
||||
|
||||
func (o *PathOptions) GetLoadingPrecedence() []string {
|
||||
@ -218,6 +220,9 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
|
||||
}
|
||||
}
|
||||
|
||||
// seenConfigs stores a map of config source filenames to computed config objects
|
||||
seenConfigs := map[string]*clientcmdapi.Config{}
|
||||
|
||||
for key, context := range newConfig.Contexts {
|
||||
startingContext, exists := startingConfig.Contexts[key]
|
||||
if !reflect.DeepEqual(context, startingContext) || !exists {
|
||||
@ -226,15 +231,28 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
|
||||
destinationFile = configAccess.GetDefaultFilename()
|
||||
}
|
||||
|
||||
configToWrite, err := getConfigFromFile(destinationFile)
|
||||
if err != nil {
|
||||
return err
|
||||
// we only obtain a fresh config object from its source file
|
||||
// if we have not seen it already - this prevents us from
|
||||
// reading and writing to the same number of files repeatedly
|
||||
// when multiple / all contexts share the same destination file.
|
||||
configToWrite, seen := seenConfigs[destinationFile]
|
||||
if !seen {
|
||||
var err error
|
||||
configToWrite, err = getConfigFromFile(destinationFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
seenConfigs[destinationFile] = configToWrite
|
||||
}
|
||||
configToWrite.Contexts[key] = context
|
||||
|
||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||
return err
|
||||
}
|
||||
configToWrite.Contexts[key] = context
|
||||
}
|
||||
}
|
||||
|
||||
// actually persist config object changes
|
||||
for destinationFile, configToWrite := range seenConfigs {
|
||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +483,7 @@ func getConfigFromFile(filename string) (*clientcmdapi.Config, error) {
|
||||
func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config {
|
||||
config, err := getConfigFromFile(filename)
|
||||
if err != nil {
|
||||
glog.FatalDepth(1, err)
|
||||
klog.FatalDepth(1, err)
|
||||
}
|
||||
|
||||
return config
|
||||
|
37
vendor/k8s.io/client-go/tools/clientcmd/loader.go
generated
vendored
37
vendor/k8s.io/client-go/tools/clientcmd/loader.go
generated
vendored
@ -27,8 +27,8 @@ import (
|
||||
goruntime "runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/imdario/mergo"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -139,7 +139,9 @@ func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules {
|
||||
|
||||
envVarFiles := os.Getenv(RecommendedConfigPathEnvVar)
|
||||
if len(envVarFiles) != 0 {
|
||||
chain = append(chain, filepath.SplitList(envVarFiles)...)
|
||||
fileList := filepath.SplitList(envVarFiles)
|
||||
// prevent the same path load multiple times
|
||||
chain = append(chain, deduplicate(fileList)...)
|
||||
|
||||
} else {
|
||||
chain = append(chain, RecommendedHomeFile)
|
||||
@ -209,7 +211,7 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
||||
mapConfig := clientcmdapi.NewConfig()
|
||||
|
||||
for _, kubeconfig := range kubeconfigs {
|
||||
mergo.Merge(mapConfig, kubeconfig)
|
||||
mergo.MergeWithOverwrite(mapConfig, kubeconfig)
|
||||
}
|
||||
|
||||
// merge all of the struct values in the reverse order so that priority is given correctly
|
||||
@ -217,14 +219,14 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
||||
nonMapConfig := clientcmdapi.NewConfig()
|
||||
for i := len(kubeconfigs) - 1; i >= 0; i-- {
|
||||
kubeconfig := kubeconfigs[i]
|
||||
mergo.Merge(nonMapConfig, kubeconfig)
|
||||
mergo.MergeWithOverwrite(nonMapConfig, kubeconfig)
|
||||
}
|
||||
|
||||
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
|
||||
// get the values we expect.
|
||||
config := clientcmdapi.NewConfig()
|
||||
mergo.Merge(config, mapConfig)
|
||||
mergo.Merge(config, nonMapConfig)
|
||||
mergo.MergeWithOverwrite(config, mapConfig)
|
||||
mergo.MergeWithOverwrite(config, nonMapConfig)
|
||||
|
||||
if rules.ResolvePaths() {
|
||||
if err := ResolveLocalPaths(config); err != nil {
|
||||
@ -354,7 +356,7 @@ func LoadFromFile(filename string) (*clientcmdapi.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.V(6).Infoln("Config loaded from file", filename)
|
||||
klog.V(6).Infoln("Config loaded from file", filename)
|
||||
|
||||
// set LocationOfOrigin on every Cluster, User, and Context
|
||||
for key, obj := range config.AuthInfos {
|
||||
@ -557,7 +559,12 @@ func GetClusterFileReferences(cluster *clientcmdapi.Cluster) []*string {
|
||||
}
|
||||
|
||||
func GetAuthInfoFileReferences(authInfo *clientcmdapi.AuthInfo) []*string {
|
||||
return []*string{&authInfo.ClientCertificate, &authInfo.ClientKey, &authInfo.TokenFile}
|
||||
s := []*string{&authInfo.ClientCertificate, &authInfo.ClientKey, &authInfo.TokenFile}
|
||||
// Only resolve exec command if it isn't PATH based.
|
||||
if authInfo.Exec != nil && strings.ContainsRune(authInfo.Exec.Command, filepath.Separator) {
|
||||
s = append(s, &authInfo.Exec.Command)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ResolvePaths updates the given refs to be absolute paths, relative to the given base directory
|
||||
@ -610,3 +617,17 @@ func MakeRelative(path, base string) (string, error) {
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// deduplicate removes any duplicated values and returns a new slice, keeping the order unchanged
|
||||
func deduplicate(s []string) []string {
|
||||
encountered := map[string]bool{}
|
||||
ret := make([]string, 0)
|
||||
for i := range s {
|
||||
if encountered[s[i]] {
|
||||
continue
|
||||
}
|
||||
encountered[s[i]] = true
|
||||
ret = append(ret, s[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
216
vendor/k8s.io/client-go/tools/clientcmd/loader_test.go
generated
vendored
216
vendor/k8s.io/client-go/tools/clientcmd/loader_test.go
generated
vendored
@ -26,7 +26,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@ -201,11 +201,182 @@ func TestLoadingEmptyMaps(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateClusterName(t *testing.T) {
|
||||
configFile, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
err := ioutil.WriteFile(configFile.Name(), []byte(`
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
api-version: v1
|
||||
server: https://kubernetes.default.svc:443
|
||||
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
name: kubeconfig-cluster
|
||||
- cluster:
|
||||
api-version: v2
|
||||
server: https://test.example.server:443
|
||||
certificate-authority: /var/run/secrets/test.example.io/serviceaccount/ca.crt
|
||||
name: kubeconfig-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubeconfig-cluster
|
||||
namespace: default
|
||||
user: kubeconfig-user
|
||||
name: kubeconfig-context
|
||||
current-context: kubeconfig-context
|
||||
users:
|
||||
- name: kubeconfig-user
|
||||
user:
|
||||
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
`), os.FileMode(0755))
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = LoadFromFile(configFile.Name())
|
||||
if err == nil || !strings.Contains(err.Error(),
|
||||
"error converting *[]NamedCluster into *map[string]*api.Cluster: duplicate name \"kubeconfig-cluster\" in list") {
|
||||
t.Error("Expected error in loading duplicate cluster name, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateContextName(t *testing.T) {
|
||||
configFile, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
err := ioutil.WriteFile(configFile.Name(), []byte(`
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
api-version: v1
|
||||
server: https://kubernetes.default.svc:443
|
||||
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
name: kubeconfig-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubeconfig-cluster
|
||||
namespace: default
|
||||
user: kubeconfig-user
|
||||
name: kubeconfig-context
|
||||
- context:
|
||||
cluster: test-example-cluster
|
||||
namespace: test-example
|
||||
user: test-example-user
|
||||
name: kubeconfig-context
|
||||
current-context: kubeconfig-context
|
||||
users:
|
||||
- name: kubeconfig-user
|
||||
user:
|
||||
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
`), os.FileMode(0755))
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = LoadFromFile(configFile.Name())
|
||||
if err == nil || !strings.Contains(err.Error(),
|
||||
"error converting *[]NamedContext into *map[string]*api.Context: duplicate name \"kubeconfig-context\" in list") {
|
||||
t.Error("Expected error in loading duplicate context name, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateUserName(t *testing.T) {
|
||||
configFile, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
err := ioutil.WriteFile(configFile.Name(), []byte(`
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
api-version: v1
|
||||
server: https://kubernetes.default.svc:443
|
||||
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
name: kubeconfig-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubeconfig-cluster
|
||||
namespace: default
|
||||
user: kubeconfig-user
|
||||
name: kubeconfig-context
|
||||
current-context: kubeconfig-context
|
||||
users:
|
||||
- name: kubeconfig-user
|
||||
user:
|
||||
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
- name: kubeconfig-user
|
||||
user:
|
||||
tokenFile: /var/run/secrets/test.example.com/serviceaccount/token
|
||||
`), os.FileMode(0755))
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = LoadFromFile(configFile.Name())
|
||||
if err == nil || !strings.Contains(err.Error(),
|
||||
"error converting *[]NamedAuthInfo into *map[string]*api.AuthInfo: duplicate name \"kubeconfig-user\" in list") {
|
||||
t.Error("Expected error in loading duplicate user name, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateExtensionName(t *testing.T) {
|
||||
configFile, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
err := ioutil.WriteFile(configFile.Name(), []byte(`
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
api-version: v1
|
||||
server: https://kubernetes.default.svc:443
|
||||
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
name: kubeconfig-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubeconfig-cluster
|
||||
namespace: default
|
||||
user: kubeconfig-user
|
||||
name: kubeconfig-context
|
||||
current-context: kubeconfig-context
|
||||
users:
|
||||
- name: kubeconfig-user
|
||||
user:
|
||||
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
extensions:
|
||||
- extension:
|
||||
bytes: test
|
||||
name: test-extension
|
||||
- extension:
|
||||
bytes: some-example
|
||||
name: test-extension
|
||||
`), os.FileMode(0755))
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = LoadFromFile(configFile.Name())
|
||||
if err == nil || !strings.Contains(err.Error(),
|
||||
"error converting *[]NamedExtension into *map[string]runtime.Object: duplicate name \"test-extension\" in list") {
|
||||
t.Error("Expected error in loading duplicate extension name, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveRelativePaths(t *testing.T) {
|
||||
pathResolutionConfig1 := clientcmdapi.Config{
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"relative-user-1": {ClientCertificate: "relative/client/cert", ClientKey: "../relative/client/key"},
|
||||
"absolute-user-1": {ClientCertificate: "/absolute/client/cert", ClientKey: "/absolute/client/key"},
|
||||
"relative-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "../relative/client/cmd"}},
|
||||
"absolute-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "/absolute/client/cmd"}},
|
||||
"PATH-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "cmd"}},
|
||||
},
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"relative-server-1": {CertificateAuthority: "../relative/ca"},
|
||||
@ -291,9 +462,21 @@ func TestResolveRelativePaths(t *testing.T) {
|
||||
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientCertificate, authInfo.ClientCertificate, t)
|
||||
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientKey, authInfo.ClientKey, t)
|
||||
}
|
||||
if key == "relative-cmd-1" {
|
||||
foundAuthInfoCount++
|
||||
matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos[key].Exec.Command), authInfo.Exec.Command, t)
|
||||
}
|
||||
if key == "absolute-cmd-1" {
|
||||
foundAuthInfoCount++
|
||||
matchStringArg(pathResolutionConfig1.AuthInfos[key].Exec.Command, authInfo.Exec.Command, t)
|
||||
}
|
||||
if key == "PATH-cmd-1" {
|
||||
foundAuthInfoCount++
|
||||
matchStringArg(pathResolutionConfig1.AuthInfos[key].Exec.Command, authInfo.Exec.Command, t)
|
||||
}
|
||||
}
|
||||
if foundAuthInfoCount != 4 {
|
||||
t.Errorf("Expected 4 users, found %v: %v", foundAuthInfoCount, mergedConfig.AuthInfos)
|
||||
if foundAuthInfoCount != 7 {
|
||||
t.Errorf("Expected 7 users, found %v: %v", foundAuthInfoCount, mergedConfig.AuthInfos)
|
||||
}
|
||||
|
||||
}
|
||||
@ -577,3 +760,30 @@ func Example_mergingEverythingNoConflicts() {
|
||||
// user:
|
||||
// token: red-token
|
||||
}
|
||||
|
||||
func TestDeduplicate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
src []string
|
||||
expect []string
|
||||
}{
|
||||
{
|
||||
src: []string{"a", "b", "c", "d", "e", "f"},
|
||||
expect: []string{"a", "b", "c", "d", "e", "f"},
|
||||
},
|
||||
{
|
||||
src: []string{"a", "b", "c", "b", "e", "f"},
|
||||
expect: []string{"a", "b", "c", "e", "f"},
|
||||
},
|
||||
{
|
||||
src: []string{"a", "a", "b", "b", "c", "b"},
|
||||
expect: []string{"a", "b", "c"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
get := deduplicate(testCase.src)
|
||||
if !reflect.DeepEqual(get, testCase.expect) {
|
||||
t.Errorf("expect: %v, get: %v", testCase.expect, get)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder.go
generated
vendored
9
vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder.go
generated
vendored
@ -20,9 +20,8 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
@ -120,7 +119,7 @@ func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, e
|
||||
|
||||
// check for in-cluster configuration and use it
|
||||
if config.icc.Possible() {
|
||||
glog.V(4).Infof("Using in-cluster configuration")
|
||||
klog.V(4).Infof("Using in-cluster configuration")
|
||||
return config.icc.ClientConfig()
|
||||
}
|
||||
|
||||
@ -145,7 +144,7 @@ func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
|
||||
|
||||
if len(ns) > 0 {
|
||||
// if we got a non-default namespace from the kubeconfig, use it
|
||||
if ns != v1.NamespaceDefault {
|
||||
if ns != "default" {
|
||||
return ns, false, nil
|
||||
}
|
||||
|
||||
@ -157,7 +156,7 @@ func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Using in-cluster namespace")
|
||||
klog.V(4).Infof("Using in-cluster namespace")
|
||||
|
||||
// allow the namespace from the service account token directory to be used.
|
||||
return config.icc.Namespace()
|
||||
|
19
vendor/k8s.io/client-go/tools/clientcmd/validation.go
generated
vendored
19
vendor/k8s.io/client-go/tools/clientcmd/validation.go
generated
vendored
@ -237,6 +237,25 @@ func validateAuthInfo(authInfoName string, authInfo clientcmdapi.AuthInfo) []err
|
||||
}
|
||||
}
|
||||
|
||||
if authInfo.Exec != nil {
|
||||
if authInfo.AuthProvider != nil {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("authProvider cannot be provided in combination with an exec plugin for %s", authInfoName))
|
||||
}
|
||||
if len(authInfo.Exec.Command) == 0 {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("command must be specified for %v to use exec authentication plugin", authInfoName))
|
||||
}
|
||||
if len(authInfo.Exec.APIVersion) == 0 {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("apiVersion must be specified for %v to use exec authentication plugin", authInfoName))
|
||||
}
|
||||
for _, v := range authInfo.Exec.Env {
|
||||
if len(v.Name) == 0 {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("env variable name must be specified for %v to use exec authentication plugin", authInfoName))
|
||||
} else if len(v.Value) == 0 {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("env variable %s value must be specified for %v to use exec authentication plugin", v.Name, authInfoName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// authPath also provides information for the client to identify the server, so allow multiple auth methods in that case
|
||||
if (len(methods) > 1) && (!usingAuthPath) {
|
||||
validationErrors = append(validationErrors, fmt.Errorf("more than one authentication method found for %v; found %v, only one is allowed", authInfoName, methods))
|
||||
|
100
vendor/k8s.io/client-go/tools/clientcmd/validation_test.go
generated
vendored
100
vendor/k8s.io/client-go/tools/clientcmd/validation_test.go
generated
vendored
@ -365,6 +365,106 @@ func TestValidateMultipleMethodsAuthInfo(t *testing.T) {
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
func TestValidateAuthInfoExec(t *testing.T) {
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.AuthInfos["user"] = &clientcmdapi.AuthInfo{
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
Command: "/bin/example",
|
||||
APIVersion: "clientauthentication.k8s.io/v1alpha1",
|
||||
Args: []string{"hello", "world"},
|
||||
Env: []clientcmdapi.ExecEnvVar{
|
||||
{Name: "foo", Value: "bar"},
|
||||
},
|
||||
},
|
||||
}
|
||||
test := configValidationTest{
|
||||
config: config,
|
||||
}
|
||||
|
||||
test.testAuthInfo("user", t)
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
func TestValidateAuthInfoExecNoVersion(t *testing.T) {
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.AuthInfos["user"] = &clientcmdapi.AuthInfo{
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
Command: "/bin/example",
|
||||
},
|
||||
}
|
||||
test := configValidationTest{
|
||||
config: config,
|
||||
expectedErrorSubstring: []string{
|
||||
"apiVersion must be specified for user to use exec authentication plugin",
|
||||
},
|
||||
}
|
||||
|
||||
test.testAuthInfo("user", t)
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
func TestValidateAuthInfoExecNoCommand(t *testing.T) {
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.AuthInfos["user"] = &clientcmdapi.AuthInfo{
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
APIVersion: "clientauthentication.k8s.io/v1alpha1",
|
||||
},
|
||||
}
|
||||
test := configValidationTest{
|
||||
config: config,
|
||||
expectedErrorSubstring: []string{
|
||||
"command must be specified for user to use exec authentication plugin",
|
||||
},
|
||||
}
|
||||
|
||||
test.testAuthInfo("user", t)
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
func TestValidateAuthInfoExecWithAuthProvider(t *testing.T) {
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.AuthInfos["user"] = &clientcmdapi.AuthInfo{
|
||||
AuthProvider: &clientcmdapi.AuthProviderConfig{
|
||||
Name: "oidc",
|
||||
},
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
Command: "/bin/example",
|
||||
APIVersion: "clientauthentication.k8s.io/v1alpha1",
|
||||
},
|
||||
}
|
||||
test := configValidationTest{
|
||||
config: config,
|
||||
expectedErrorSubstring: []string{
|
||||
"authProvider cannot be provided in combination with an exec plugin for user",
|
||||
},
|
||||
}
|
||||
|
||||
test.testAuthInfo("user", t)
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
func TestValidateAuthInfoExecInvalidEnv(t *testing.T) {
|
||||
config := clientcmdapi.NewConfig()
|
||||
config.AuthInfos["user"] = &clientcmdapi.AuthInfo{
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
Command: "/bin/example",
|
||||
APIVersion: "clientauthentication.k8s.io/v1alpha1",
|
||||
Env: []clientcmdapi.ExecEnvVar{
|
||||
{Name: "foo"}, // No value
|
||||
},
|
||||
},
|
||||
}
|
||||
test := configValidationTest{
|
||||
config: config,
|
||||
expectedErrorSubstring: []string{
|
||||
"env variable foo value must be specified for user to use exec authentication plugin",
|
||||
},
|
||||
}
|
||||
|
||||
test.testAuthInfo("user", t)
|
||||
test.testConfig(t)
|
||||
}
|
||||
|
||||
type configValidationTest struct {
|
||||
config *clientcmdapi.Config
|
||||
expectedErrorSubstring []string
|
||||
|
53
vendor/k8s.io/client-go/tools/leaderelection/BUILD
generated
vendored
53
vendor/k8s.io/client-go/tools/leaderelection/BUILD
generated
vendored
@ -1,53 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["leaderelection.go"],
|
||||
importpath = "k8s.io/client-go/tools/leaderelection",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["leaderelection_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/client-go/tools/leaderelection/resourcelock:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
69
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
generated
vendored
Normal file
69
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
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 leaderelection
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HealthzAdaptor associates the /healthz endpoint with the LeaderElection object.
|
||||
// It helps deal with the /healthz endpoint being set up prior to the LeaderElection.
|
||||
// This contains the code needed to act as an adaptor between the leader
|
||||
// election code the health check code. It allows us to provide health
|
||||
// status about the leader election. Most specifically about if the leader
|
||||
// has failed to renew without exiting the process. In that case we should
|
||||
// report not healthy and rely on the kubelet to take down the process.
|
||||
type HealthzAdaptor struct {
|
||||
pointerLock sync.Mutex
|
||||
le *LeaderElector
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// Name returns the name of the health check we are implementing.
|
||||
func (l *HealthzAdaptor) Name() string {
|
||||
return "leaderElection"
|
||||
}
|
||||
|
||||
// Check is called by the healthz endpoint handler.
|
||||
// It fails (returns an error) if we own the lease but had not been able to renew it.
|
||||
func (l *HealthzAdaptor) Check(req *http.Request) error {
|
||||
l.pointerLock.Lock()
|
||||
defer l.pointerLock.Unlock()
|
||||
if l.le == nil {
|
||||
return nil
|
||||
}
|
||||
return l.le.Check(l.timeout)
|
||||
}
|
||||
|
||||
// SetLeaderElection ties a leader election object to a HealthzAdaptor
|
||||
func (l *HealthzAdaptor) SetLeaderElection(le *LeaderElector) {
|
||||
l.pointerLock.Lock()
|
||||
defer l.pointerLock.Unlock()
|
||||
l.le = le
|
||||
}
|
||||
|
||||
// NewLeaderHealthzAdaptor creates a basic healthz adaptor to monitor a leader election.
|
||||
// timeout determines the time beyond the lease expiry to be allowed for timeout.
|
||||
// checks within the timeout period after the lease expires will still return healthy.
|
||||
func NewLeaderHealthzAdaptor(timeout time.Duration) *HealthzAdaptor {
|
||||
result := &HealthzAdaptor{
|
||||
timeout: timeout,
|
||||
}
|
||||
return result
|
||||
}
|
175
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor_test.go
generated
vendored
Normal file
175
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor_test.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
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 leaderelection
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type fakeLock struct {
|
||||
identity string
|
||||
}
|
||||
|
||||
// Get is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) Get() (ler *rl.LeaderElectionRecord, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Create is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) Create(ler rl.LeaderElectionRecord) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) Update(ler rl.LeaderElectionRecord) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecordEvent is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) RecordEvent(string) {}
|
||||
|
||||
// Identity is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) Identity() string {
|
||||
return fl.identity
|
||||
}
|
||||
|
||||
// Describe is a dummy to allow us to have a fakeLock for testing.
|
||||
func (fl *fakeLock) Describe() string {
|
||||
return "Dummy implementation of lock for testing"
|
||||
}
|
||||
|
||||
// TestLeaderElectionHealthChecker tests that the healthcheck for leader election handles its edge cases.
|
||||
func TestLeaderElectionHealthChecker(t *testing.T) {
|
||||
current := time.Now()
|
||||
req := &http.Request{}
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
expected error
|
||||
adaptorTimeout time.Duration
|
||||
elector *LeaderElector
|
||||
}{
|
||||
{
|
||||
description: "call check before leader elector initialized",
|
||||
expected: nil,
|
||||
adaptorTimeout: time.Second * 20,
|
||||
elector: nil,
|
||||
},
|
||||
{
|
||||
description: "call check when the the lease is far expired",
|
||||
expected: fmt.Errorf("failed election to renew leadership on lease %s", "foo"),
|
||||
adaptorTimeout: time.Second * 20,
|
||||
elector: &LeaderElector{
|
||||
config: LeaderElectionConfig{
|
||||
Lock: &fakeLock{identity: "healthTest"},
|
||||
LeaseDuration: time.Minute,
|
||||
Name: "foo",
|
||||
},
|
||||
observedRecord: rl.LeaderElectionRecord{
|
||||
HolderIdentity: "healthTest",
|
||||
},
|
||||
observedTime: current,
|
||||
clock: clock.NewFakeClock(current.Add(time.Hour)),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "call check when the the lease is far expired but held by another server",
|
||||
expected: nil,
|
||||
adaptorTimeout: time.Second * 20,
|
||||
elector: &LeaderElector{
|
||||
config: LeaderElectionConfig{
|
||||
Lock: &fakeLock{identity: "healthTest"},
|
||||
LeaseDuration: time.Minute,
|
||||
Name: "foo",
|
||||
},
|
||||
observedRecord: rl.LeaderElectionRecord{
|
||||
HolderIdentity: "otherServer",
|
||||
},
|
||||
observedTime: current,
|
||||
clock: clock.NewFakeClock(current.Add(time.Hour)),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "call check when the the lease is not expired",
|
||||
expected: nil,
|
||||
adaptorTimeout: time.Second * 20,
|
||||
elector: &LeaderElector{
|
||||
config: LeaderElectionConfig{
|
||||
Lock: &fakeLock{identity: "healthTest"},
|
||||
LeaseDuration: time.Minute,
|
||||
Name: "foo",
|
||||
},
|
||||
observedRecord: rl.LeaderElectionRecord{
|
||||
HolderIdentity: "healthTest",
|
||||
},
|
||||
observedTime: current,
|
||||
clock: clock.NewFakeClock(current),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "call check when the the lease is expired but inside the timeout",
|
||||
expected: nil,
|
||||
adaptorTimeout: time.Second * 20,
|
||||
elector: &LeaderElector{
|
||||
config: LeaderElectionConfig{
|
||||
Lock: &fakeLock{identity: "healthTest"},
|
||||
LeaseDuration: time.Minute,
|
||||
Name: "foo",
|
||||
},
|
||||
observedRecord: rl.LeaderElectionRecord{
|
||||
HolderIdentity: "healthTest",
|
||||
},
|
||||
observedTime: current,
|
||||
clock: clock.NewFakeClock(current.Add(time.Minute).Add(time.Second)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
adaptor := NewLeaderHealthzAdaptor(test.adaptorTimeout)
|
||||
if adaptor.le != nil {
|
||||
t.Errorf("[%s] leaderChecker started with a LeaderElector %v", test.description, adaptor.le)
|
||||
}
|
||||
if test.elector != nil {
|
||||
test.elector.config.WatchDog = adaptor
|
||||
adaptor.SetLeaderElection(test.elector)
|
||||
if adaptor.le == nil {
|
||||
t.Errorf("[%s] adaptor failed to set the LeaderElector", test.description)
|
||||
}
|
||||
}
|
||||
err := adaptor.Check(req)
|
||||
if test.expected == nil {
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
t.Errorf("[%s] called check, expected no error but received \"%v\"", test.description, err)
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Errorf("[%s] called check and failed to received the expected error \"%v\"", test.description, test.expected)
|
||||
}
|
||||
if err.Error() != test.expected.Error() {
|
||||
t.Errorf("[%s] called check, expected %v, received %v", test.description, test.expected, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
156
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
156
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
@ -49,17 +49,19 @@ limitations under the License.
|
||||
package leaderelection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -74,11 +76,22 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) {
|
||||
if lec.RenewDeadline <= time.Duration(JitterFactor*float64(lec.RetryPeriod)) {
|
||||
return nil, fmt.Errorf("renewDeadline must be greater than retryPeriod*JitterFactor")
|
||||
}
|
||||
if lec.LeaseDuration < 1 {
|
||||
return nil, fmt.Errorf("leaseDuration must be greater than zero")
|
||||
}
|
||||
if lec.RenewDeadline < 1 {
|
||||
return nil, fmt.Errorf("renewDeadline must be greater than zero")
|
||||
}
|
||||
if lec.RetryPeriod < 1 {
|
||||
return nil, fmt.Errorf("retryPeriod must be greater than zero")
|
||||
}
|
||||
|
||||
if lec.Lock == nil {
|
||||
return nil, fmt.Errorf("Lock must not be nil.")
|
||||
}
|
||||
return &LeaderElector{
|
||||
config: lec,
|
||||
clock: clock.RealClock{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -100,6 +113,13 @@ type LeaderElectionConfig struct {
|
||||
// Callbacks are callbacks that are triggered during certain lifecycle
|
||||
// events of the LeaderElector
|
||||
Callbacks LeaderCallbacks
|
||||
|
||||
// WatchDog is the associated health checker
|
||||
// WatchDog may be null if its not needed/configured.
|
||||
WatchDog *HealthzAdaptor
|
||||
|
||||
// Name is the name of the resource lock for debugging
|
||||
Name string
|
||||
}
|
||||
|
||||
// LeaderCallbacks are callbacks that are triggered during certain
|
||||
@ -109,7 +129,7 @@ type LeaderElectionConfig struct {
|
||||
// * OnChallenge()
|
||||
type LeaderCallbacks struct {
|
||||
// OnStartedLeading is called when a LeaderElector client starts leading
|
||||
OnStartedLeading func(stop <-chan struct{})
|
||||
OnStartedLeading func(context.Context)
|
||||
// OnStoppedLeading is called when a LeaderElector client stops leading
|
||||
OnStoppedLeading func()
|
||||
// OnNewLeader is called when the client observes a leader that is
|
||||
@ -119,10 +139,6 @@ type LeaderCallbacks struct {
|
||||
}
|
||||
|
||||
// LeaderElector is a leader election client.
|
||||
//
|
||||
// possible future methods:
|
||||
// * (le *LeaderElector) IsLeader()
|
||||
// * (le *LeaderElector) GetLeader()
|
||||
type LeaderElector struct {
|
||||
config LeaderElectionConfig
|
||||
// internal bookkeeping
|
||||
@ -132,29 +148,40 @@ type LeaderElector struct {
|
||||
// value observedRecord.HolderIdentity if the transition has
|
||||
// not yet been reported.
|
||||
reportedLeader string
|
||||
|
||||
// clock is wrapper around time to allow for less flaky testing
|
||||
clock clock.Clock
|
||||
|
||||
// name is the name of the resource lock for debugging
|
||||
name string
|
||||
}
|
||||
|
||||
// Run starts the leader election loop
|
||||
func (le *LeaderElector) Run() {
|
||||
func (le *LeaderElector) Run(ctx context.Context) {
|
||||
defer func() {
|
||||
runtime.HandleCrash()
|
||||
le.config.Callbacks.OnStoppedLeading()
|
||||
}()
|
||||
le.acquire()
|
||||
stop := make(chan struct{})
|
||||
go le.config.Callbacks.OnStartedLeading(stop)
|
||||
le.renew()
|
||||
close(stop)
|
||||
if !le.acquire(ctx) {
|
||||
return // ctx signalled done
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
go le.config.Callbacks.OnStartedLeading(ctx)
|
||||
le.renew(ctx)
|
||||
}
|
||||
|
||||
// RunOrDie starts a client with the provided config or panics if the config
|
||||
// fails to validate.
|
||||
func RunOrDie(lec LeaderElectionConfig) {
|
||||
func RunOrDie(ctx context.Context, lec LeaderElectionConfig) {
|
||||
le, err := NewLeaderElector(lec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
le.Run()
|
||||
if lec.WatchDog != nil {
|
||||
lec.WatchDog.SetLeaderElection(le)
|
||||
}
|
||||
le.Run(ctx)
|
||||
}
|
||||
|
||||
// GetLeader returns the identity of the last observed leader or returns the empty string if
|
||||
@ -168,41 +195,60 @@ func (le *LeaderElector) IsLeader() bool {
|
||||
return le.observedRecord.HolderIdentity == le.config.Lock.Identity()
|
||||
}
|
||||
|
||||
// acquire loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew succeeds.
|
||||
func (le *LeaderElector) acquire() {
|
||||
stop := make(chan struct{})
|
||||
// acquire loops calling tryAcquireOrRenew and returns true immediately when tryAcquireOrRenew succeeds.
|
||||
// Returns false if ctx signals done.
|
||||
func (le *LeaderElector) acquire(ctx context.Context) bool {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
succeeded := false
|
||||
desc := le.config.Lock.Describe()
|
||||
glog.Infof("attempting to acquire leader lease %v...", desc)
|
||||
klog.Infof("attempting to acquire leader lease %v...", desc)
|
||||
wait.JitterUntil(func() {
|
||||
succeeded := le.tryAcquireOrRenew()
|
||||
succeeded = le.tryAcquireOrRenew()
|
||||
le.maybeReportTransition()
|
||||
if !succeeded {
|
||||
glog.V(4).Infof("failed to acquire lease %v", desc)
|
||||
klog.V(4).Infof("failed to acquire lease %v", desc)
|
||||
return
|
||||
}
|
||||
le.config.Lock.RecordEvent("became leader")
|
||||
glog.Infof("successfully acquired lease %v", desc)
|
||||
close(stop)
|
||||
}, le.config.RetryPeriod, JitterFactor, true, stop)
|
||||
klog.Infof("successfully acquired lease %v", desc)
|
||||
cancel()
|
||||
}, le.config.RetryPeriod, JitterFactor, true, ctx.Done())
|
||||
return succeeded
|
||||
}
|
||||
|
||||
// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails.
|
||||
func (le *LeaderElector) renew() {
|
||||
stop := make(chan struct{})
|
||||
// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails or ctx signals done.
|
||||
func (le *LeaderElector) renew(ctx context.Context) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
wait.Until(func() {
|
||||
err := wait.Poll(le.config.RetryPeriod, le.config.RenewDeadline, func() (bool, error) {
|
||||
return le.tryAcquireOrRenew(), nil
|
||||
})
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, le.config.RenewDeadline)
|
||||
defer timeoutCancel()
|
||||
err := wait.PollImmediateUntil(le.config.RetryPeriod, func() (bool, error) {
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
defer close(done)
|
||||
done <- le.tryAcquireOrRenew()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeoutCtx.Done():
|
||||
return false, fmt.Errorf("failed to tryAcquireOrRenew %s", timeoutCtx.Err())
|
||||
case result := <-done:
|
||||
return result, nil
|
||||
}
|
||||
}, timeoutCtx.Done())
|
||||
|
||||
le.maybeReportTransition()
|
||||
desc := le.config.Lock.Describe()
|
||||
if err == nil {
|
||||
glog.V(4).Infof("successfully renewed lease %v", desc)
|
||||
klog.V(5).Infof("successfully renewed lease %v", desc)
|
||||
return
|
||||
}
|
||||
le.config.Lock.RecordEvent("stopped leading")
|
||||
glog.Infof("failed to renew lease %v: %v", desc, err)
|
||||
close(stop)
|
||||
}, 0, stop)
|
||||
klog.Infof("failed to renew lease %v: %v", desc, err)
|
||||
cancel()
|
||||
}, le.config.RetryPeriod, ctx.Done())
|
||||
}
|
||||
|
||||
// tryAcquireOrRenew tries to acquire a leader lease if it is not already acquired,
|
||||
@ -221,32 +267,32 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
|
||||
oldLeaderElectionRecord, err := le.config.Lock.Get()
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
glog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err)
|
||||
klog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err)
|
||||
return false
|
||||
}
|
||||
if err = le.config.Lock.Create(leaderElectionRecord); err != nil {
|
||||
glog.Errorf("error initially creating leader election record: %v", err)
|
||||
klog.Errorf("error initially creating leader election record: %v", err)
|
||||
return false
|
||||
}
|
||||
le.observedRecord = leaderElectionRecord
|
||||
le.observedTime = time.Now()
|
||||
le.observedTime = le.clock.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. Record obtained, check the Identity & Time
|
||||
if !reflect.DeepEqual(le.observedRecord, *oldLeaderElectionRecord) {
|
||||
le.observedRecord = *oldLeaderElectionRecord
|
||||
le.observedTime = time.Now()
|
||||
le.observedTime = le.clock.Now()
|
||||
}
|
||||
if le.observedTime.Add(le.config.LeaseDuration).After(now.Time) &&
|
||||
oldLeaderElectionRecord.HolderIdentity != le.config.Lock.Identity() {
|
||||
glog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity)
|
||||
!le.IsLeader() {
|
||||
klog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity)
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. We're going to try to update. The leaderElectionRecord is set to it's default
|
||||
// here. Let's correct it before updating.
|
||||
if oldLeaderElectionRecord.HolderIdentity == le.config.Lock.Identity() {
|
||||
if le.IsLeader() {
|
||||
leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime
|
||||
leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions
|
||||
} else {
|
||||
@ -255,20 +301,36 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
|
||||
|
||||
// update the lock itself
|
||||
if err = le.config.Lock.Update(leaderElectionRecord); err != nil {
|
||||
glog.Errorf("Failed to update lock: %v", err)
|
||||
klog.Errorf("Failed to update lock: %v", err)
|
||||
return false
|
||||
}
|
||||
le.observedRecord = leaderElectionRecord
|
||||
le.observedTime = time.Now()
|
||||
le.observedTime = le.clock.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *LeaderElector) maybeReportTransition() {
|
||||
if l.observedRecord.HolderIdentity == l.reportedLeader {
|
||||
func (le *LeaderElector) maybeReportTransition() {
|
||||
if le.observedRecord.HolderIdentity == le.reportedLeader {
|
||||
return
|
||||
}
|
||||
l.reportedLeader = l.observedRecord.HolderIdentity
|
||||
if l.config.Callbacks.OnNewLeader != nil {
|
||||
go l.config.Callbacks.OnNewLeader(l.reportedLeader)
|
||||
le.reportedLeader = le.observedRecord.HolderIdentity
|
||||
if le.config.Callbacks.OnNewLeader != nil {
|
||||
go le.config.Callbacks.OnNewLeader(le.reportedLeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Check will determine if the current lease is expired by more than timeout.
|
||||
func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error {
|
||||
if !le.IsLeader() {
|
||||
// Currently not concerned with the case that we are hot standby
|
||||
return nil
|
||||
}
|
||||
// If we are more than timeout seconds after the lease duration that is past the timeout
|
||||
// on the lease renew. Time to start reporting ourselves as unhealthy. We should have
|
||||
// died but conditions like deadlock can prevent this. (See #70819)
|
||||
if le.clock.Since(le.observedTime) > le.config.LeaseDuration+maxTolerableExpiredLease {
|
||||
return fmt.Errorf("failed election to renew leadership on lease %s", le.config.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
2
vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go
generated
vendored
2
vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go
generated
vendored
@ -26,6 +26,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
fakecorev1 "k8s.io/client-go/kubernetes/typed/core/v1/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
@ -257,6 +258,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
config: lec,
|
||||
observedRecord: test.observedRecord,
|
||||
observedTime: test.observedTime,
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
if test.expectSuccess != le.tryAcquireOrRenew() {
|
||||
|
35
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/BUILD
generated
vendored
35
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/BUILD
generated
vendored
@ -1,35 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"configmaplock.go",
|
||||
"endpointslock.go",
|
||||
"interface.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/leaderelection/resourcelock",
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
2
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
generated
vendored
2
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
generated
vendored
@ -80,7 +80,7 @@ func (cml *ConfigMapLock) Create(ler LeaderElectionRecord) error {
|
||||
// Update will update an existing annotation on a given resource.
|
||||
func (cml *ConfigMapLock) Update(ler LeaderElectionRecord) error {
|
||||
if cml.cm == nil {
|
||||
return errors.New("endpoint not initialized, call get or create first")
|
||||
return errors.New("configmap not initialized, call get or create first")
|
||||
}
|
||||
recordBytes, err := json.Marshal(ler)
|
||||
if err != nil {
|
||||
|
25
vendor/k8s.io/client-go/tools/metrics/BUILD
generated
vendored
25
vendor/k8s.io/client-go/tools/metrics/BUILD
generated
vendored
@ -1,25 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["metrics.go"],
|
||||
importpath = "k8s.io/client-go/tools/metrics",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
49
vendor/k8s.io/client-go/tools/pager/BUILD
generated
vendored
49
vendor/k8s.io/client-go/tools/pager/BUILD
generated
vendored
@ -1,49 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["pager.go"],
|
||||
importpath = "k8s.io/client-go/tools/pager",
|
||||
deps = [
|
||||
"//vendor/golang.org/x/net/context:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["pager_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/golang.org/x/net/context:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
3
vendor/k8s.io/client-go/tools/pager/pager.go
generated
vendored
3
vendor/k8s.io/client-go/tools/pager/pager.go
generated
vendored
@ -17,10 +17,9 @@ limitations under the License.
|
||||
package pager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
|
2
vendor/k8s.io/client-go/tools/pager/pager_test.go
generated
vendored
2
vendor/k8s.io/client-go/tools/pager/pager_test.go
generated
vendored
@ -17,11 +17,11 @@ limitations under the License.
|
||||
package pager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
41
vendor/k8s.io/client-go/tools/portforward/BUILD
generated
vendored
41
vendor/k8s.io/client-go/tools/portforward/BUILD
generated
vendored
@ -1,41 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["portforward_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/util/httpstream:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"portforward.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/portforward",
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/httpstream:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
107
vendor/k8s.io/client-go/tools/portforward/portforward.go
generated
vendored
107
vendor/k8s.io/client-go/tools/portforward/portforward.go
generated
vendored
@ -39,8 +39,9 @@ const PortForwardProtocolV1Name = "portforward.k8s.io"
|
||||
// PortForwarder knows how to listen for local connections and forward them to
|
||||
// a remote pod via an upgraded HTTP request.
|
||||
type PortForwarder struct {
|
||||
ports []ForwardedPort
|
||||
stopChan <-chan struct{}
|
||||
addresses []listenAddress
|
||||
ports []ForwardedPort
|
||||
stopChan <-chan struct{}
|
||||
|
||||
dialer httpstream.Dialer
|
||||
streamConn httpstream.Connection
|
||||
@ -110,8 +111,52 @@ func parsePorts(ports []string) ([]ForwardedPort, error) {
|
||||
return forwards, nil
|
||||
}
|
||||
|
||||
// New creates a new PortForwarder.
|
||||
type listenAddress struct {
|
||||
address string
|
||||
protocol string
|
||||
failureMode string
|
||||
}
|
||||
|
||||
func parseAddresses(addressesToParse []string) ([]listenAddress, error) {
|
||||
var addresses []listenAddress
|
||||
parsed := make(map[string]listenAddress)
|
||||
for _, address := range addressesToParse {
|
||||
if address == "localhost" {
|
||||
ip := listenAddress{address: "127.0.0.1", protocol: "tcp4", failureMode: "all"}
|
||||
parsed[ip.address] = ip
|
||||
ip = listenAddress{address: "::1", protocol: "tcp6", failureMode: "all"}
|
||||
parsed[ip.address] = ip
|
||||
} else if net.ParseIP(address).To4() != nil {
|
||||
parsed[address] = listenAddress{address: address, protocol: "tcp4", failureMode: "any"}
|
||||
} else if net.ParseIP(address) != nil {
|
||||
parsed[address] = listenAddress{address: address, protocol: "tcp6", failureMode: "any"}
|
||||
} else {
|
||||
return nil, fmt.Errorf("%s is not a valid IP", address)
|
||||
}
|
||||
}
|
||||
addresses = make([]listenAddress, len(parsed))
|
||||
id := 0
|
||||
for _, v := range parsed {
|
||||
addresses[id] = v
|
||||
id++
|
||||
}
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
// New creates a new PortForwarder with localhost listen addresses.
|
||||
func New(dialer httpstream.Dialer, ports []string, stopChan <-chan struct{}, readyChan chan struct{}, out, errOut io.Writer) (*PortForwarder, error) {
|
||||
return NewOnAddresses(dialer, []string{"localhost"}, ports, stopChan, readyChan, out, errOut)
|
||||
}
|
||||
|
||||
// NewOnAddresses creates a new PortForwarder with custom listen addresses.
|
||||
func NewOnAddresses(dialer httpstream.Dialer, addresses []string, ports []string, stopChan <-chan struct{}, readyChan chan struct{}, out, errOut io.Writer) (*PortForwarder, error) {
|
||||
if len(addresses) == 0 {
|
||||
return nil, errors.New("You must specify at least 1 address")
|
||||
}
|
||||
parsedAddresses, err := parseAddresses(addresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ports) == 0 {
|
||||
return nil, errors.New("You must specify at least 1 port")
|
||||
}
|
||||
@ -120,12 +165,13 @@ func New(dialer httpstream.Dialer, ports []string, stopChan <-chan struct{}, rea
|
||||
return nil, err
|
||||
}
|
||||
return &PortForwarder{
|
||||
dialer: dialer,
|
||||
ports: parsedPorts,
|
||||
stopChan: stopChan,
|
||||
Ready: readyChan,
|
||||
out: out,
|
||||
errOut: errOut,
|
||||
dialer: dialer,
|
||||
addresses: parsedAddresses,
|
||||
ports: parsedPorts,
|
||||
stopChan: stopChan,
|
||||
Ready: readyChan,
|
||||
out: out,
|
||||
errOut: errOut,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -181,13 +227,26 @@ func (pf *PortForwarder) forward() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// listenOnPort delegates tcp4 and tcp6 listener creation and waits for connections on both of these addresses.
|
||||
// If both listener creation fail, an error is raised.
|
||||
// listenOnPort delegates listener creation and waits for connections on requested bind addresses.
|
||||
// An error is raised based on address groups (default and localhost) and their failure modes
|
||||
func (pf *PortForwarder) listenOnPort(port *ForwardedPort) error {
|
||||
errTcp4 := pf.listenOnPortAndAddress(port, "tcp4", "127.0.0.1")
|
||||
errTcp6 := pf.listenOnPortAndAddress(port, "tcp6", "::1")
|
||||
if errTcp4 != nil && errTcp6 != nil {
|
||||
return fmt.Errorf("All listeners failed to create with the following errors: %s, %s", errTcp4, errTcp6)
|
||||
var errors []error
|
||||
failCounters := make(map[string]int, 2)
|
||||
successCounters := make(map[string]int, 2)
|
||||
for _, addr := range pf.addresses {
|
||||
err := pf.listenOnPortAndAddress(port, addr.protocol, addr.address)
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
failCounters[addr.failureMode]++
|
||||
} else {
|
||||
successCounters[addr.failureMode]++
|
||||
}
|
||||
}
|
||||
if successCounters["all"] == 0 && failCounters["all"] > 0 {
|
||||
return fmt.Errorf("%s: %v", "Listeners failed to create with the following errors", errors)
|
||||
}
|
||||
if failCounters["any"] > 0 {
|
||||
return fmt.Errorf("%s: %v", "Listeners failed to create with the following errors", errors)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -216,6 +275,7 @@ func (pf *PortForwarder) getListener(protocol string, hostname string, port *For
|
||||
localPortUInt, err := strconv.ParseUint(localPort, 10, 16)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(pf.out, "Failed to forward from %s:%d -> %d\n", hostname, localPortUInt, port.Remote)
|
||||
return nil, fmt.Errorf("Error parsing local port: %s from %s (%s)", err, listenerAddress, host)
|
||||
}
|
||||
port.Local = uint16(localPortUInt)
|
||||
@ -340,3 +400,20 @@ func (pf *PortForwarder) Close() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPorts will return the ports that were forwarded; this can be used to
|
||||
// retrieve the locally-bound port in cases where the input was port 0. This
|
||||
// function will signal an error if the Ready channel is nil or if the
|
||||
// listeners are not ready yet; this function will succeed after the Ready
|
||||
// channel has been closed.
|
||||
func (pf *PortForwarder) GetPorts() ([]ForwardedPort, error) {
|
||||
if pf.Ready == nil {
|
||||
return nil, fmt.Errorf("no Ready channel provided")
|
||||
}
|
||||
select {
|
||||
case <-pf.Ready:
|
||||
return pf.ports, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("listeners not ready")
|
||||
}
|
||||
}
|
||||
|
114
vendor/k8s.io/client-go/tools/portforward/portforward_test.go
generated
vendored
114
vendor/k8s.io/client-go/tools/portforward/portforward_test.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -40,23 +41,52 @@ func (d *fakeDialer) Dial(protocols ...string) (httpstream.Connection, string, e
|
||||
|
||||
func TestParsePortsAndNew(t *testing.T) {
|
||||
tests := []struct {
|
||||
input []string
|
||||
expected []ForwardedPort
|
||||
expectParseError bool
|
||||
expectNewError bool
|
||||
input []string
|
||||
addresses []string
|
||||
expectedPorts []ForwardedPort
|
||||
expectedAddresses []listenAddress
|
||||
expectPortParseError bool
|
||||
expectAddressParseError bool
|
||||
expectNewError bool
|
||||
}{
|
||||
{input: []string{}, expectNewError: true},
|
||||
{input: []string{"a"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{":a"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"-1"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"65536"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"0"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"0:0"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"a:5000"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"5000:a"}, expectParseError: true, expectNewError: true},
|
||||
{input: []string{"a"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{":a"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"-1"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"65536"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"0"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"0:0"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"a:5000"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"5000:a"}, expectPortParseError: true, expectAddressParseError: false, expectNewError: true},
|
||||
{input: []string{"5000:5000"}, addresses: []string{"127.0.0.257"}, expectPortParseError: false, expectAddressParseError: true, expectNewError: true},
|
||||
{input: []string{"5000:5000"}, addresses: []string{"::g"}, expectPortParseError: false, expectAddressParseError: true, expectNewError: true},
|
||||
{input: []string{"5000:5000"}, addresses: []string{"domain.invalid"}, expectPortParseError: false, expectAddressParseError: true, expectNewError: true},
|
||||
{
|
||||
input: []string{"5000", "5000:5000", "8888:5000", "5000:8888", ":5000", "0:5000"},
|
||||
expected: []ForwardedPort{
|
||||
input: []string{"5000:5000"},
|
||||
addresses: []string{"localhost"},
|
||||
expectedPorts: []ForwardedPort{
|
||||
{5000, 5000},
|
||||
},
|
||||
expectedAddresses: []listenAddress{
|
||||
{protocol: "tcp4", address: "127.0.0.1", failureMode: "all"},
|
||||
{protocol: "tcp6", address: "::1", failureMode: "all"},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: []string{"5000:5000"},
|
||||
addresses: []string{"localhost", "127.0.0.1"},
|
||||
expectedPorts: []ForwardedPort{
|
||||
{5000, 5000},
|
||||
},
|
||||
expectedAddresses: []listenAddress{
|
||||
{protocol: "tcp4", address: "127.0.0.1", failureMode: "any"},
|
||||
{protocol: "tcp6", address: "::1", failureMode: "all"},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: []string{"5000", "5000:5000", "8888:5000", "5000:8888", ":5000", "0:5000"},
|
||||
addresses: []string{"127.0.0.1", "::1"},
|
||||
expectedPorts: []ForwardedPort{
|
||||
{5000, 5000},
|
||||
{5000, 5000},
|
||||
{8888, 5000},
|
||||
@ -64,34 +94,63 @@ func TestParsePortsAndNew(t *testing.T) {
|
||||
{0, 5000},
|
||||
{0, 5000},
|
||||
},
|
||||
expectedAddresses: []listenAddress{
|
||||
{protocol: "tcp4", address: "127.0.0.1", failureMode: "any"},
|
||||
{protocol: "tcp6", address: "::1", failureMode: "any"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
parsed, err := parsePorts(test.input)
|
||||
parsedPorts, err := parsePorts(test.input)
|
||||
haveError := err != nil
|
||||
if e, a := test.expectParseError, haveError; e != a {
|
||||
if e, a := test.expectPortParseError, haveError; e != a {
|
||||
t.Fatalf("%d: parsePorts: error expected=%t, got %t: %s", i, e, a, err)
|
||||
}
|
||||
|
||||
// default to localhost
|
||||
if len(test.addresses) == 0 && len(test.expectedAddresses) == 0 {
|
||||
test.addresses = []string{"localhost"}
|
||||
test.expectedAddresses = []listenAddress{{protocol: "tcp4", address: "127.0.0.1"}, {protocol: "tcp6", address: "::1"}}
|
||||
}
|
||||
// assert address parser
|
||||
parsedAddresses, err := parseAddresses(test.addresses)
|
||||
haveError = err != nil
|
||||
if e, a := test.expectAddressParseError, haveError; e != a {
|
||||
t.Fatalf("%d: parseAddresses: error expected=%t, got %t: %s", i, e, a, err)
|
||||
}
|
||||
|
||||
dialer := &fakeDialer{}
|
||||
expectedStopChan := make(chan struct{})
|
||||
readyChan := make(chan struct{})
|
||||
pf, err := New(dialer, test.input, expectedStopChan, readyChan, os.Stdout, os.Stderr)
|
||||
|
||||
var pf *PortForwarder
|
||||
if len(test.addresses) > 0 {
|
||||
pf, err = NewOnAddresses(dialer, test.addresses, test.input, expectedStopChan, readyChan, os.Stdout, os.Stderr)
|
||||
} else {
|
||||
pf, err = New(dialer, test.input, expectedStopChan, readyChan, os.Stdout, os.Stderr)
|
||||
}
|
||||
haveError = err != nil
|
||||
if e, a := test.expectNewError, haveError; e != a {
|
||||
t.Fatalf("%d: New: error expected=%t, got %t: %s", i, e, a, err)
|
||||
}
|
||||
|
||||
if test.expectParseError || test.expectNewError {
|
||||
if test.expectPortParseError || test.expectAddressParseError || test.expectNewError {
|
||||
continue
|
||||
}
|
||||
|
||||
for pi, expectedPort := range test.expected {
|
||||
if e, a := expectedPort.Local, parsed[pi].Local; e != a {
|
||||
sort.Slice(test.expectedAddresses, func(i, j int) bool { return test.expectedAddresses[i].address < test.expectedAddresses[j].address })
|
||||
sort.Slice(parsedAddresses, func(i, j int) bool { return parsedAddresses[i].address < parsedAddresses[j].address })
|
||||
|
||||
if !reflect.DeepEqual(test.expectedAddresses, parsedAddresses) {
|
||||
t.Fatalf("%d: expectedAddresses: %v, got: %v", i, test.expectedAddresses, parsedAddresses)
|
||||
}
|
||||
|
||||
for pi, expectedPort := range test.expectedPorts {
|
||||
if e, a := expectedPort.Local, parsedPorts[pi].Local; e != a {
|
||||
t.Fatalf("%d: local expected: %d, got: %d", i, e, a)
|
||||
}
|
||||
if e, a := expectedPort.Remote, parsed[pi].Remote; e != a {
|
||||
if e, a := expectedPort.Remote, parsedPorts[pi].Remote; e != a {
|
||||
t.Fatalf("%d: remote expected: %d, got: %d", i, e, a)
|
||||
}
|
||||
}
|
||||
@ -99,8 +158,17 @@ func TestParsePortsAndNew(t *testing.T) {
|
||||
if dialer.dialed {
|
||||
t.Fatalf("%d: expected not dialed", i)
|
||||
}
|
||||
if e, a := test.expected, pf.ports; !reflect.DeepEqual(e, a) {
|
||||
t.Fatalf("%d: ports: expected %#v, got %#v", i, e, a)
|
||||
if _, portErr := pf.GetPorts(); portErr == nil {
|
||||
t.Fatalf("%d: GetPorts: error expected but got nil", i)
|
||||
}
|
||||
|
||||
// mock-signal the Ready channel
|
||||
close(readyChan)
|
||||
|
||||
if ports, portErr := pf.GetPorts(); portErr != nil {
|
||||
t.Fatalf("%d: GetPorts: unable to retrieve ports: %s", i, portErr)
|
||||
} else if !reflect.DeepEqual(test.expectedPorts, ports) {
|
||||
t.Fatalf("%d: ports: expected %#v, got %#v", i, test.expectedPorts, ports)
|
||||
}
|
||||
if e, a := expectedStopChan, pf.stopChan; e != a {
|
||||
t.Fatalf("%d: stopChan: expected %#v, got %#v", i, e, a)
|
||||
|
68
vendor/k8s.io/client-go/tools/record/BUILD
generated
vendored
68
vendor/k8s.io/client-go/tools/record/BUILD
generated
vendored
@ -1,68 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"event_test.go",
|
||||
"events_cache_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/reference:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"event.go",
|
||||
"events_cache.go",
|
||||
"fake.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/record",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/golang/groupcache/lru:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/reference:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
44
vendor/k8s.io/client-go/tools/record/event.go
generated
vendored
44
vendor/k8s.io/client-go/tools/record/event.go
generated
vendored
@ -33,7 +33,7 @@ import (
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const maxTriesPerEvent = 12
|
||||
@ -72,6 +72,9 @@ type EventRecorder interface {
|
||||
|
||||
// PastEventf is just like Eventf, but with an option to specify the event's 'timestamp' field.
|
||||
PastEventf(object runtime.Object, timestamp metav1.Time, eventtype, reason, messageFmt string, args ...interface{})
|
||||
|
||||
// AnnotatedEventf is just like eventf, but with annotations attached
|
||||
AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{})
|
||||
}
|
||||
|
||||
// EventBroadcaster knows how to receive events and send them to any EventSink, watcher, or log.
|
||||
@ -141,7 +144,7 @@ func recordToSink(sink EventSink, event *v1.Event, eventCorrelator *EventCorrela
|
||||
}
|
||||
tries++
|
||||
if tries >= maxTriesPerEvent {
|
||||
glog.Errorf("Unable to write event '%#v' (retry limit exceeded!)", event)
|
||||
klog.Errorf("Unable to write event '%#v' (retry limit exceeded!)", event)
|
||||
break
|
||||
}
|
||||
// Randomize the first sleep so that various clients won't all be
|
||||
@ -191,13 +194,13 @@ func recordEvent(sink EventSink, event *v1.Event, patch []byte, updateExistingEv
|
||||
switch err.(type) {
|
||||
case *restclient.RequestConstructionError:
|
||||
// We will construct the request the same next time, so don't keep trying.
|
||||
glog.Errorf("Unable to construct event '%#v': '%v' (will not retry!)", event, err)
|
||||
klog.Errorf("Unable to construct event '%#v': '%v' (will not retry!)", event, err)
|
||||
return true
|
||||
case *errors.StatusError:
|
||||
if errors.IsAlreadyExists(err) {
|
||||
glog.V(5).Infof("Server rejected event '%#v': '%v' (will not retry!)", event, err)
|
||||
klog.V(5).Infof("Server rejected event '%#v': '%v' (will not retry!)", event, err)
|
||||
} else {
|
||||
glog.Errorf("Server rejected event '%#v': '%v' (will not retry!)", event, err)
|
||||
klog.Errorf("Server rejected event '%#v': '%v' (will not retry!)", event, err)
|
||||
}
|
||||
return true
|
||||
case *errors.UnexpectedObjectError:
|
||||
@ -206,7 +209,7 @@ func recordEvent(sink EventSink, event *v1.Event, patch []byte, updateExistingEv
|
||||
default:
|
||||
// This case includes actual http transport errors. Go ahead and retry.
|
||||
}
|
||||
glog.Errorf("Unable to write event: '%v' (may retry after sleeping)", err)
|
||||
klog.Errorf("Unable to write event: '%v' (may retry after sleeping)", err)
|
||||
return false
|
||||
}
|
||||
|
||||
@ -225,11 +228,7 @@ func (eventBroadcaster *eventBroadcasterImpl) StartEventWatcher(eventHandler fun
|
||||
watcher := eventBroadcaster.Watch()
|
||||
go func() {
|
||||
defer utilruntime.HandleCrash()
|
||||
for {
|
||||
watchEvent, open := <-watcher.ResultChan()
|
||||
if !open {
|
||||
return
|
||||
}
|
||||
for watchEvent := range watcher.ResultChan() {
|
||||
event, ok := watchEvent.Object.(*v1.Event)
|
||||
if !ok {
|
||||
// This is all local, so there's no reason this should
|
||||
@ -254,19 +253,19 @@ type recorderImpl struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) generateEvent(object runtime.Object, timestamp metav1.Time, eventtype, reason, message string) {
|
||||
func (recorder *recorderImpl) generateEvent(object runtime.Object, annotations map[string]string, timestamp metav1.Time, eventtype, reason, message string) {
|
||||
ref, err := ref.GetReference(recorder.scheme, object)
|
||||
if err != nil {
|
||||
glog.Errorf("Could not construct reference to: '%#v' due to: '%v'. Will not report event: '%v' '%v' '%v'", object, err, eventtype, reason, message)
|
||||
klog.Errorf("Could not construct reference to: '%#v' due to: '%v'. Will not report event: '%v' '%v' '%v'", object, err, eventtype, reason, message)
|
||||
return
|
||||
}
|
||||
|
||||
if !validateEventType(eventtype) {
|
||||
glog.Errorf("Unsupported event type: '%v'", eventtype)
|
||||
klog.Errorf("Unsupported event type: '%v'", eventtype)
|
||||
return
|
||||
}
|
||||
|
||||
event := recorder.makeEvent(ref, eventtype, reason, message)
|
||||
event := recorder.makeEvent(ref, annotations, eventtype, reason, message)
|
||||
event.Source = recorder.source
|
||||
|
||||
go func() {
|
||||
@ -285,7 +284,7 @@ func validateEventType(eventtype string) bool {
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) Event(object runtime.Object, eventtype, reason, message string) {
|
||||
recorder.generateEvent(object, metav1.Now(), eventtype, reason, message)
|
||||
recorder.generateEvent(object, nil, metav1.Now(), eventtype, reason, message)
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
@ -293,10 +292,14 @@ func (recorder *recorderImpl) Eventf(object runtime.Object, eventtype, reason, m
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) PastEventf(object runtime.Object, timestamp metav1.Time, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
recorder.generateEvent(object, timestamp, eventtype, reason, fmt.Sprintf(messageFmt, args...))
|
||||
recorder.generateEvent(object, nil, timestamp, eventtype, reason, fmt.Sprintf(messageFmt, args...))
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) makeEvent(ref *v1.ObjectReference, eventtype, reason, message string) *v1.Event {
|
||||
func (recorder *recorderImpl) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
recorder.generateEvent(object, annotations, metav1.Now(), eventtype, reason, fmt.Sprintf(messageFmt, args...))
|
||||
}
|
||||
|
||||
func (recorder *recorderImpl) makeEvent(ref *v1.ObjectReference, annotations map[string]string, eventtype, reason, message string) *v1.Event {
|
||||
t := metav1.Time{Time: recorder.clock.Now()}
|
||||
namespace := ref.Namespace
|
||||
if namespace == "" {
|
||||
@ -304,8 +307,9 @@ func (recorder *recorderImpl) makeEvent(ref *v1.ObjectReference, eventtype, reas
|
||||
}
|
||||
return &v1.Event{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
|
||||
Namespace: namespace,
|
||||
Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
|
||||
Namespace: namespace,
|
||||
Annotations: annotations,
|
||||
},
|
||||
InvolvedObject: *ref,
|
||||
Reason: reason,
|
||||
|
5
vendor/k8s.io/client-go/tools/record/events_cache.go
generated
vendored
5
vendor/k8s.io/client-go/tools/record/events_cache.go
generated
vendored
@ -84,11 +84,6 @@ func getSpamKey(event *v1.Event) string {
|
||||
// EventFilterFunc is a function that returns true if the event should be skipped
|
||||
type EventFilterFunc func(event *v1.Event) bool
|
||||
|
||||
// DefaultEventFilterFunc returns false for all incoming events
|
||||
func DefaultEventFilterFunc(event *v1.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// EventSourceObjectSpamFilter is responsible for throttling
|
||||
// the amount of events a source and object can produce.
|
||||
type EventSourceObjectSpamFilter struct {
|
||||
|
8
vendor/k8s.io/client-go/tools/record/events_cache_test.go
generated
vendored
8
vendor/k8s.io/client-go/tools/record/events_cache_test.go
generated
vendored
@ -127,14 +127,6 @@ func validateEvent(messagePrefix string, actualEvent *v1.Event, expectedEvent *v
|
||||
return actualEvent, nil
|
||||
}
|
||||
|
||||
// TestDefaultEventFilterFunc ensures that no events are filtered
|
||||
func TestDefaultEventFilterFunc(t *testing.T) {
|
||||
event := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other"))
|
||||
if DefaultEventFilterFunc(&event) {
|
||||
t.Fatalf("DefaultEventFilterFunc should always return false")
|
||||
}
|
||||
}
|
||||
|
||||
// TestEventAggregatorByReasonFunc ensures that two events are aggregated if they vary only by event.message
|
||||
func TestEventAggregatorByReasonFunc(t *testing.T) {
|
||||
event1 := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other"))
|
||||
|
4
vendor/k8s.io/client-go/tools/record/fake.go
generated
vendored
4
vendor/k8s.io/client-go/tools/record/fake.go
generated
vendored
@ -45,6 +45,10 @@ func (f *FakeRecorder) Eventf(object runtime.Object, eventtype, reason, messageF
|
||||
func (f *FakeRecorder) PastEventf(object runtime.Object, timestamp metav1.Time, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (f *FakeRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
f.Eventf(object, eventtype, reason, messageFmt, args)
|
||||
}
|
||||
|
||||
// NewFakeRecorder creates new fake event recorder with event channel with
|
||||
// buffer of given size.
|
||||
func NewFakeRecorder(bufferSize int) *FakeRecorder {
|
||||
|
31
vendor/k8s.io/client-go/tools/reference/BUILD
generated
vendored
31
vendor/k8s.io/client-go/tools/reference/BUILD
generated
vendored
@ -1,31 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["ref.go"],
|
||||
importpath = "k8s.io/client-go/tools/reference",
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
8
vendor/k8s.io/client-go/tools/reference/ref.go
generated
vendored
8
vendor/k8s.io/client-go/tools/reference/ref.go
generated
vendored
@ -86,10 +86,14 @@ func GetReference(scheme *runtime.Scheme, obj runtime.Object) (*v1.ObjectReferen
|
||||
}
|
||||
// example paths: /<prefix>/<version>/*
|
||||
parts := strings.Split(selfLinkUrl.Path, "/")
|
||||
if len(parts) < 3 {
|
||||
if len(parts) < 4 {
|
||||
return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version)
|
||||
}
|
||||
version = parts[2]
|
||||
if parts[1] == "api" {
|
||||
version = parts[2]
|
||||
} else {
|
||||
version = parts[2] + "/" + parts[3]
|
||||
}
|
||||
}
|
||||
|
||||
// only has list metadata
|
||||
|
72
vendor/k8s.io/client-go/tools/reference/ref_test.go
generated
vendored
Normal file
72
vendor/k8s.io/client-go/tools/reference/ref_test.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 reference
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type TestRuntimeObj struct {
|
||||
metav1.TypeMeta
|
||||
metav1.ObjectMeta
|
||||
}
|
||||
|
||||
func (o *TestRuntimeObj) DeepCopyObject() runtime.Object {
|
||||
panic("die")
|
||||
}
|
||||
|
||||
func TestGetReferenceRefVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *TestRuntimeObj
|
||||
expectedRefVersion string
|
||||
}{
|
||||
{
|
||||
name: "api from selflink",
|
||||
input: &TestRuntimeObj{
|
||||
ObjectMeta: metav1.ObjectMeta{SelfLink: "/api/v1/namespaces"},
|
||||
},
|
||||
expectedRefVersion: "v1",
|
||||
},
|
||||
{
|
||||
name: "foo.group/v3 from selflink",
|
||||
input: &TestRuntimeObj{
|
||||
ObjectMeta: metav1.ObjectMeta{SelfLink: "/apis/foo.group/v3/namespaces"},
|
||||
},
|
||||
expectedRefVersion: "foo.group/v3",
|
||||
},
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypes(schema.GroupVersion{Group: "this", Version: "is ignored"}, &TestRuntimeObj{})
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ref, err := GetReference(scheme, test.input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if test.expectedRefVersion != ref.APIVersion {
|
||||
t.Errorf("expected %q, got %q", test.expectedRefVersion, ref.APIVersion)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
60
vendor/k8s.io/client-go/tools/remotecommand/BUILD
generated
vendored
60
vendor/k8s.io/client-go/tools/remotecommand/BUILD
generated
vendored
@ -1,60 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"v2_test.go",
|
||||
"v4_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/httpstream:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"errorstream.go",
|
||||
"remotecommand.go",
|
||||
"resize.go",
|
||||
"v1.go",
|
||||
"v2.go",
|
||||
"v3.go",
|
||||
"v4.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/tools/remotecommand",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/httpstream:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/remotecommand:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/transport/spdy:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
41
vendor/k8s.io/client-go/tools/remotecommand/reader.go
generated
vendored
Normal file
41
vendor/k8s.io/client-go/tools/remotecommand/reader.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 remotecommand
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// readerWrapper delegates to an io.Reader so that only the io.Reader interface is implemented,
|
||||
// to keep io.Copy from doing things we don't want when copying from the reader to the data stream.
|
||||
//
|
||||
// If the Stdin io.Reader provided to remotecommand implements a WriteTo function (like bytes.Buffer does[1]),
|
||||
// io.Copy calls that method[2] to attempt to write the entire buffer to the stream in one call.
|
||||
// That results in an oversized call to spdystream.Stream#Write [3],
|
||||
// which results in a single oversized data frame[4] that is too large.
|
||||
//
|
||||
// [1] https://golang.org/pkg/bytes/#Buffer.WriteTo
|
||||
// [2] https://golang.org/pkg/io/#Copy
|
||||
// [3] https://github.com/kubernetes/kubernetes/blob/90295640ef87db9daa0144c5617afe889e7992b2/vendor/github.com/docker/spdystream/stream.go#L66-L73
|
||||
// [4] https://github.com/kubernetes/kubernetes/blob/90295640ef87db9daa0144c5617afe889e7992b2/vendor/github.com/docker/spdystream/spdy/write.go#L302-L304
|
||||
type readerWrapper struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
func (r readerWrapper) Read(p []byte) (int, error) {
|
||||
return r.reader.Read(p)
|
||||
}
|
8
vendor/k8s.io/client-go/tools/remotecommand/remotecommand.go
generated
vendored
8
vendor/k8s.io/client-go/tools/remotecommand/remotecommand.go
generated
vendored
@ -22,7 +22,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/apimachinery/pkg/util/remotecommand"
|
||||
@ -30,8 +30,8 @@ import (
|
||||
spdy "k8s.io/client-go/transport/spdy"
|
||||
)
|
||||
|
||||
// StreamOptions holds information pertaining to the current streaming session: supported stream
|
||||
// protocols, input/output streams, if the client is requesting a TTY, and a terminal size queue to
|
||||
// StreamOptions holds information pertaining to the current streaming session:
|
||||
// input/output streams, if the client is requesting a TTY, and a terminal size queue to
|
||||
// support terminal resizing.
|
||||
type StreamOptions struct {
|
||||
Stdin io.Reader
|
||||
@ -132,7 +132,7 @@ func (e *streamExecutor) Stream(options StreamOptions) error {
|
||||
case remotecommand.StreamProtocolV2Name:
|
||||
streamer = newStreamProtocolV2(options)
|
||||
case "":
|
||||
glog.V(4).Infof("The server did not negotiate a streaming protocol version. Falling back to %s", remotecommand.StreamProtocolV1Name)
|
||||
klog.V(4).Infof("The server did not negotiate a streaming protocol version. Falling back to %s", remotecommand.StreamProtocolV1Name)
|
||||
fallthrough
|
||||
case remotecommand.StreamProtocolV1Name:
|
||||
streamer = newStreamProtocolV1(options)
|
||||
|
10
vendor/k8s.io/client-go/tools/remotecommand/v1.go
generated
vendored
10
vendor/k8s.io/client-go/tools/remotecommand/v1.go
generated
vendored
@ -22,9 +22,9 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// streamProtocolV1 implements the first version of the streaming exec & attach
|
||||
@ -53,10 +53,10 @@ func (p *streamProtocolV1) stream(conn streamCreator) error {
|
||||
errorChan := make(chan error)
|
||||
|
||||
cp := func(s string, dst io.Writer, src io.Reader) {
|
||||
glog.V(6).Infof("Copying %s", s)
|
||||
defer glog.V(6).Infof("Done copying %s", s)
|
||||
klog.V(6).Infof("Copying %s", s)
|
||||
defer klog.V(6).Infof("Done copying %s", s)
|
||||
if _, err := io.Copy(dst, src); err != nil && err != io.EOF {
|
||||
glog.Errorf("Error copying %s: %v", s, err)
|
||||
klog.Errorf("Error copying %s: %v", s, err)
|
||||
}
|
||||
if s == v1.StreamTypeStdout || s == v1.StreamTypeStderr {
|
||||
doneChan <- struct{}{}
|
||||
@ -127,7 +127,7 @@ func (p *streamProtocolV1) stream(conn streamCreator) error {
|
||||
// because stdin is not closed until the process exits. If we try to call
|
||||
// stdin.Close(), it returns no error but doesn't unblock the copy. It will
|
||||
// exit when the process exits, instead.
|
||||
go cp(v1.StreamTypeStdin, p.remoteStdin, p.Stdin)
|
||||
go cp(v1.StreamTypeStdin, p.remoteStdin, readerWrapper{p.Stdin})
|
||||
}
|
||||
|
||||
waitCount := 0
|
||||
|
2
vendor/k8s.io/client-go/tools/remotecommand/v2.go
generated
vendored
2
vendor/k8s.io/client-go/tools/remotecommand/v2.go
generated
vendored
@ -101,7 +101,7 @@ func (p *streamProtocolV2) copyStdin() {
|
||||
// the executed command will remain running.
|
||||
defer once.Do(func() { p.remoteStdin.Close() })
|
||||
|
||||
if _, err := io.Copy(p.remoteStdin, p.Stdin); err != nil {
|
||||
if _, err := io.Copy(p.remoteStdin, readerWrapper{p.Stdin}); err != nil {
|
||||
runtime.HandleError(err)
|
||||
}
|
||||
}()
|
||||
|
114
vendor/k8s.io/client-go/tools/watch/informerwatcher.go
generated
vendored
Normal file
114
vendor/k8s.io/client-go/tools/watch/informerwatcher.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 watch
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func newTicketer() *ticketer {
|
||||
return &ticketer{
|
||||
cond: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
}
|
||||
|
||||
type ticketer struct {
|
||||
counter uint64
|
||||
|
||||
cond *sync.Cond
|
||||
current uint64
|
||||
}
|
||||
|
||||
func (t *ticketer) GetTicket() uint64 {
|
||||
// -1 to start from 0
|
||||
return atomic.AddUint64(&t.counter, 1) - 1
|
||||
}
|
||||
|
||||
func (t *ticketer) WaitForTicket(ticket uint64, f func()) {
|
||||
t.cond.L.Lock()
|
||||
defer t.cond.L.Unlock()
|
||||
for ticket != t.current {
|
||||
t.cond.Wait()
|
||||
}
|
||||
|
||||
f()
|
||||
|
||||
t.current++
|
||||
t.cond.Broadcast()
|
||||
}
|
||||
|
||||
// NewIndexerInformerWatcher will create an IndexerInformer and wrap it into watch.Interface
|
||||
// so you can use it anywhere where you'd have used a regular Watcher returned from Watch method.
|
||||
func NewIndexerInformerWatcher(lw cache.ListerWatcher, objType runtime.Object) (cache.Indexer, cache.Controller, watch.Interface) {
|
||||
ch := make(chan watch.Event)
|
||||
w := watch.NewProxyWatcher(ch)
|
||||
t := newTicketer()
|
||||
|
||||
indexer, informer := cache.NewIndexerInformer(lw, objType, 0, cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
go t.WaitForTicket(t.GetTicket(), func() {
|
||||
select {
|
||||
case ch <- watch.Event{
|
||||
Type: watch.Added,
|
||||
Object: obj.(runtime.Object),
|
||||
}:
|
||||
case <-w.StopChan():
|
||||
}
|
||||
})
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
go t.WaitForTicket(t.GetTicket(), func() {
|
||||
select {
|
||||
case ch <- watch.Event{
|
||||
Type: watch.Modified,
|
||||
Object: new.(runtime.Object),
|
||||
}:
|
||||
case <-w.StopChan():
|
||||
}
|
||||
})
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
go t.WaitForTicket(t.GetTicket(), func() {
|
||||
staleObj, stale := obj.(cache.DeletedFinalStateUnknown)
|
||||
if stale {
|
||||
// We have no means of passing the additional information down using watch API based on watch.Event
|
||||
// but the caller can filter such objects by checking if metadata.deletionTimestamp is set
|
||||
obj = staleObj
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- watch.Event{
|
||||
Type: watch.Deleted,
|
||||
Object: obj.(runtime.Object),
|
||||
}:
|
||||
case <-w.StopChan():
|
||||
}
|
||||
})
|
||||
},
|
||||
}, cache.Indexers{})
|
||||
|
||||
go func() {
|
||||
informer.Run(w.StopChan())
|
||||
}()
|
||||
|
||||
return indexer, informer, w
|
||||
}
|
236
vendor/k8s.io/client-go/tools/watch/informerwatcher_test.go
generated
vendored
Normal file
236
vendor/k8s.io/client-go/tools/watch/informerwatcher_test.go
generated
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 watch
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
||||
testcore "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type byEventTypeAndName []watch.Event
|
||||
|
||||
func (a byEventTypeAndName) Len() int { return len(a) }
|
||||
func (a byEventTypeAndName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byEventTypeAndName) Less(i, j int) bool {
|
||||
if a[i].Type < a[j].Type {
|
||||
return true
|
||||
}
|
||||
|
||||
if a[i].Type > a[j].Type {
|
||||
return false
|
||||
}
|
||||
|
||||
return a[i].Object.(*corev1.Secret).Name < a[j].Object.(*corev1.Secret).Name
|
||||
}
|
||||
|
||||
func TestTicketer(t *testing.T) {
|
||||
tg := newTicketer()
|
||||
|
||||
const numTickets = 100 // current golang limit for race detector is 8192 simultaneously alive goroutines
|
||||
var tickets []uint64
|
||||
for i := 0; i < numTickets; i++ {
|
||||
ticket := tg.GetTicket()
|
||||
tickets = append(tickets, ticket)
|
||||
|
||||
exp, got := uint64(i), ticket
|
||||
if got != exp {
|
||||
t.Fatalf("expected ticket %d, got %d", exp, got)
|
||||
}
|
||||
}
|
||||
|
||||
// shuffle tickets
|
||||
rand.Shuffle(len(tickets), func(i, j int) {
|
||||
tickets[i], tickets[j] = tickets[j], tickets[i]
|
||||
})
|
||||
|
||||
res := make(chan uint64, len(tickets))
|
||||
for _, ticket := range tickets {
|
||||
go func(ticket uint64) {
|
||||
time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
|
||||
tg.WaitForTicket(ticket, func() {
|
||||
res <- ticket
|
||||
})
|
||||
}(ticket)
|
||||
}
|
||||
|
||||
for i := 0; i < numTickets; i++ {
|
||||
exp, got := uint64(i), <-res
|
||||
if got != exp {
|
||||
t.Fatalf("expected ticket %d, got %d", exp, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewInformerWatcher(t *testing.T) {
|
||||
// Make sure there are no 2 same types of events on a secret with the same name or that might be flaky.
|
||||
tt := []struct {
|
||||
name string
|
||||
objects []runtime.Object
|
||||
events []watch.Event
|
||||
}{
|
||||
{
|
||||
name: "basic test",
|
||||
objects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-1",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"foo-1": "initial",
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-2",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"foo-2": "initial",
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-3",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"foo-3": "initial",
|
||||
},
|
||||
},
|
||||
},
|
||||
events: []watch.Event{
|
||||
{
|
||||
Type: watch.Added,
|
||||
Object: &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-4",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"foo-4": "initial",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: watch.Modified,
|
||||
Object: &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-2",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"foo-2": "new",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: watch.Deleted,
|
||||
Object: &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var expected []watch.Event
|
||||
for _, o := range tc.objects {
|
||||
expected = append(expected, watch.Event{
|
||||
Type: watch.Added,
|
||||
Object: o.DeepCopyObject(),
|
||||
})
|
||||
}
|
||||
for _, e := range tc.events {
|
||||
expected = append(expected, *e.DeepCopy())
|
||||
}
|
||||
|
||||
fake := fakeclientset.NewSimpleClientset(tc.objects...)
|
||||
fakeWatch := watch.NewFakeWithChanSize(len(tc.events), false)
|
||||
fake.PrependWatchReactor("secrets", testcore.DefaultWatchReactor(fakeWatch, nil))
|
||||
|
||||
for _, e := range tc.events {
|
||||
fakeWatch.Action(e.Type, e.Object)
|
||||
}
|
||||
|
||||
lw := &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
return fake.Core().Secrets("").List(options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return fake.Core().Secrets("").Watch(options)
|
||||
},
|
||||
}
|
||||
_, _, w := NewIndexerInformerWatcher(lw, &corev1.Secret{})
|
||||
|
||||
var result []watch.Event
|
||||
loop:
|
||||
for {
|
||||
var event watch.Event
|
||||
var ok bool
|
||||
select {
|
||||
case event, ok = <-w.ResultChan():
|
||||
if !ok {
|
||||
t.Errorf("Failed to read event: channel is already closed!")
|
||||
return
|
||||
}
|
||||
|
||||
result = append(result, *event.DeepCopy())
|
||||
case <-time.After(time.Second * 1):
|
||||
// All the events are buffered -> this means we are done
|
||||
// Also the one sec will make sure that we would detect RetryWatcher's incorrect behaviour after last event
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
// Informers don't guarantee event order so we need to sort these arrays to compare them
|
||||
sort.Sort(byEventTypeAndName(expected))
|
||||
sort.Sort(byEventTypeAndName(result))
|
||||
|
||||
if !reflect.DeepEqual(expected, result) {
|
||||
t.Error(spew.Errorf("\nexpected: %#v,\ngot: %#v,\ndiff: %s", expected, result, diff.ObjectReflectDiff(expected, result)))
|
||||
return
|
||||
}
|
||||
|
||||
// Fill in some data to test watch closing while there are some events to be read
|
||||
for _, e := range tc.events {
|
||||
fakeWatch.Action(e.Type, e.Object)
|
||||
}
|
||||
|
||||
// Stop before reading all the data to make sure the informer can deal with closed channel
|
||||
w.Stop()
|
||||
|
||||
// Wait a bit to see if the informer won't panic
|
||||
// TODO: Try to figure out a more reliable mechanism than time.Sleep (https://github.com/kubernetes/kubernetes/pull/50102/files#r184716591)
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
225
vendor/k8s.io/client-go/tools/watch/until.go
generated
vendored
Normal file
225
vendor/k8s.io/client-go/tools/watch/until.go
generated
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 watch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// PreconditionFunc returns true if the condition has been reached, false if it has not been reached yet,
|
||||
// or an error if the condition failed or detected an error state.
|
||||
type PreconditionFunc func(store cache.Store) (bool, error)
|
||||
|
||||
// ConditionFunc returns true if the condition has been reached, false if it has not been reached yet,
|
||||
// or an error if the condition cannot be checked and should terminate. In general, it is better to define
|
||||
// level driven conditions over edge driven conditions (pod has ready=true, vs pod modified and ready changed
|
||||
// from false to true).
|
||||
type ConditionFunc func(event watch.Event) (bool, error)
|
||||
|
||||
// ErrWatchClosed is returned when the watch channel is closed before timeout in UntilWithoutRetry.
|
||||
var ErrWatchClosed = errors.New("watch closed before UntilWithoutRetry timeout")
|
||||
|
||||
// UntilWithoutRetry reads items from the watch until each provided condition succeeds, and then returns the last watch
|
||||
// encountered. The first condition that returns an error terminates the watch (and the event is also returned).
|
||||
// If no event has been received, the returned event will be nil.
|
||||
// Conditions are satisfied sequentially so as to provide a useful primitive for higher level composition.
|
||||
// Waits until context deadline or until context is canceled.
|
||||
//
|
||||
// Warning: Unless you have a very specific use case (probably a special Watcher) don't use this function!!!
|
||||
// Warning: This will fail e.g. on API timeouts and/or 'too old resource version' error.
|
||||
// Warning: You are most probably looking for a function *Until* or *UntilWithSync* below,
|
||||
// Warning: solving such issues.
|
||||
// TODO: Consider making this function private to prevent misuse when the other occurrences in our codebase are gone.
|
||||
func UntilWithoutRetry(ctx context.Context, watcher watch.Interface, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
ch := watcher.ResultChan()
|
||||
defer watcher.Stop()
|
||||
var lastEvent *watch.Event
|
||||
for _, condition := range conditions {
|
||||
// check the next condition against the previous event and short circuit waiting for the next watch
|
||||
if lastEvent != nil {
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ConditionSucceeded:
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-ch:
|
||||
if !ok {
|
||||
return lastEvent, ErrWatchClosed
|
||||
}
|
||||
lastEvent = &event
|
||||
|
||||
done, err := condition(event)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
break ConditionSucceeded
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return lastEvent, wait.ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastEvent, nil
|
||||
}
|
||||
|
||||
// UntilWithSync creates an informer from lw, optionally checks precondition when the store is synced,
|
||||
// and watches the output until each provided condition succeeds, in a way that is identical
|
||||
// to function UntilWithoutRetry. (See above.)
|
||||
// UntilWithSync can deal with all errors like API timeout, lost connections and 'Resource version too old'.
|
||||
// It is the only function that can recover from 'Resource version too old', Until and UntilWithoutRetry will
|
||||
// just fail in that case. On the other hand it can't provide you with guarantees as strong as using simple
|
||||
// Watch method with Until. It can skip some intermediate events in case of watch function failing but it will
|
||||
// re-list to recover and you always get an event, if there has been a change, after recovery.
|
||||
// Also with the current implementation based on DeltaFIFO, order of the events you receive is guaranteed only for
|
||||
// particular object, not between more of them even it's the same resource.
|
||||
// The most frequent usage would be a command that needs to watch the "state of the world" and should't fail, like:
|
||||
// waiting for object reaching a state, "small" controllers, ...
|
||||
func UntilWithSync(ctx context.Context, lw cache.ListerWatcher, objType runtime.Object, precondition PreconditionFunc, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
indexer, informer, watcher := NewIndexerInformerWatcher(lw, objType)
|
||||
// Proxy watcher can be stopped multiple times so it's fine to use defer here to cover alternative branches and
|
||||
// let UntilWithoutRetry to stop it
|
||||
defer watcher.Stop()
|
||||
|
||||
if precondition != nil {
|
||||
if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) {
|
||||
return nil, fmt.Errorf("UntilWithSync: unable to sync caches: %v", ctx.Err())
|
||||
}
|
||||
|
||||
done, err := precondition(indexer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if done {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return UntilWithoutRetry(ctx, watcher, conditions...)
|
||||
}
|
||||
|
||||
// ContextWithOptionalTimeout wraps context.WithTimeout and handles infinite timeouts expressed as 0 duration.
|
||||
func ContextWithOptionalTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
if timeout < 0 {
|
||||
// This should be handled in validation
|
||||
klog.Errorf("Timeout for context shall not be negative!")
|
||||
timeout = 0
|
||||
}
|
||||
|
||||
if timeout == 0 {
|
||||
return context.WithCancel(parent)
|
||||
}
|
||||
|
||||
return context.WithTimeout(parent, timeout)
|
||||
}
|
||||
|
||||
// ListWatchUntil checks the provided conditions against the items returned by the list watcher, returning wait.ErrWaitTimeout
|
||||
// if timeout is exceeded without all conditions returning true, or an error if an error occurs.
|
||||
// TODO: check for watch expired error and retry watch from latest point? Same issue exists for Until.
|
||||
// TODO: remove when no longer used
|
||||
//
|
||||
// Deprecated: Use UntilWithSync instead.
|
||||
func ListWatchUntil(timeout time.Duration, lw cache.ListerWatcher, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
if len(conditions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
list, err := lw.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
initialItems, err := meta.ExtractList(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use the initial items as simulated "adds"
|
||||
var lastEvent *watch.Event
|
||||
currIndex := 0
|
||||
passedConditions := 0
|
||||
for _, condition := range conditions {
|
||||
// check the next condition against the previous event and short circuit waiting for the next watch
|
||||
if lastEvent != nil {
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ConditionSucceeded:
|
||||
for currIndex < len(initialItems) {
|
||||
lastEvent = &watch.Event{Type: watch.Added, Object: initialItems[currIndex]}
|
||||
currIndex++
|
||||
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
break ConditionSucceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
if passedConditions == len(conditions) {
|
||||
return lastEvent, nil
|
||||
}
|
||||
remainingConditions := conditions[passedConditions:]
|
||||
|
||||
metaObj, err := meta.ListAccessor(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currResourceVersion := metaObj.GetResourceVersion()
|
||||
|
||||
watchInterface, err := lw.Watch(metav1.ListOptions{ResourceVersion: currResourceVersion})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := ContextWithOptionalTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
evt, err := UntilWithoutRetry(ctx, watchInterface, remainingConditions...)
|
||||
if err == ErrWatchClosed {
|
||||
// present a consistent error interface to callers
|
||||
err = wait.ErrWaitTimeout
|
||||
}
|
||||
return evt, err
|
||||
}
|
303
vendor/k8s.io/client-go/tools/watch/until_test.go
generated
vendored
Normal file
303
vendor/k8s.io/client-go/tools/watch/until_test.go
generated
vendored
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 watch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
fakeclient "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type fakePod struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (obj *fakePod) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
func (obj *fakePod) DeepCopyObject() runtime.Object { panic("DeepCopyObject not supported by fakePod") }
|
||||
|
||||
func TestUntil(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *fakePod
|
||||
fw.Add(obj)
|
||||
fw.Modify(obj)
|
||||
}()
|
||||
conditions := []ConditionFunc{
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Modified, nil },
|
||||
}
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Minute)
|
||||
lastEvent, err := UntilWithoutRetry(ctx, fw, conditions...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %#v", err)
|
||||
}
|
||||
if lastEvent == nil {
|
||||
t.Fatal("expected an event")
|
||||
}
|
||||
if lastEvent.Type != watch.Modified {
|
||||
t.Fatalf("expected MODIFIED event type, got %v", lastEvent.Type)
|
||||
}
|
||||
if got, isPod := lastEvent.Object.(*fakePod); !isPod {
|
||||
t.Fatalf("expected a pod event, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntilMultipleConditions(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *fakePod
|
||||
fw.Add(obj)
|
||||
}()
|
||||
conditions := []ConditionFunc{
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
}
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Minute)
|
||||
lastEvent, err := UntilWithoutRetry(ctx, fw, conditions...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %#v", err)
|
||||
}
|
||||
if lastEvent == nil {
|
||||
t.Fatal("expected an event")
|
||||
}
|
||||
if lastEvent.Type != watch.Added {
|
||||
t.Fatalf("expected MODIFIED event type, got %v", lastEvent.Type)
|
||||
}
|
||||
if got, isPod := lastEvent.Object.(*fakePod); !isPod {
|
||||
t.Fatalf("expected a pod event, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntilMultipleConditionsFail(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *fakePod
|
||||
fw.Add(obj)
|
||||
}()
|
||||
conditions := []ConditionFunc{
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Deleted, nil },
|
||||
}
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
lastEvent, err := UntilWithoutRetry(ctx, fw, conditions...)
|
||||
if err != wait.ErrWaitTimeout {
|
||||
t.Fatalf("expected ErrWaitTimeout error, got %#v", err)
|
||||
}
|
||||
if lastEvent == nil {
|
||||
t.Fatal("expected an event")
|
||||
}
|
||||
if lastEvent.Type != watch.Added {
|
||||
t.Fatalf("expected ADDED event type, got %v", lastEvent.Type)
|
||||
}
|
||||
if got, isPod := lastEvent.Object.(*fakePod); !isPod {
|
||||
t.Fatalf("expected a pod event, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntilTimeout(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *fakePod
|
||||
fw.Add(obj)
|
||||
fw.Modify(obj)
|
||||
}()
|
||||
conditions := []ConditionFunc{
|
||||
func(event watch.Event) (bool, error) {
|
||||
return event.Type == watch.Added, nil
|
||||
},
|
||||
func(event watch.Event) (bool, error) {
|
||||
return event.Type == watch.Modified, nil
|
||||
},
|
||||
}
|
||||
|
||||
lastEvent, err := UntilWithoutRetry(context.Background(), fw, conditions...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %#v", err)
|
||||
}
|
||||
if lastEvent == nil {
|
||||
t.Fatal("expected an event")
|
||||
}
|
||||
if lastEvent.Type != watch.Modified {
|
||||
t.Fatalf("expected MODIFIED event type, got %v", lastEvent.Type)
|
||||
}
|
||||
if got, isPod := lastEvent.Object.(*fakePod); !isPod {
|
||||
t.Fatalf("expected a pod event, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntilErrorCondition(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *fakePod
|
||||
fw.Add(obj)
|
||||
}()
|
||||
expected := "something bad"
|
||||
conditions := []ConditionFunc{
|
||||
func(event watch.Event) (bool, error) { return event.Type == watch.Added, nil },
|
||||
func(event watch.Event) (bool, error) { return false, errors.New(expected) },
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
_, err := UntilWithoutRetry(ctx, fw, conditions...)
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), expected) {
|
||||
t.Fatalf("expected %q in error string, got %q", expected, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntilWithSync(t *testing.T) {
|
||||
// FIXME: test preconditions
|
||||
tt := []struct {
|
||||
name string
|
||||
lw *cache.ListWatch
|
||||
preconditionFunc PreconditionFunc
|
||||
conditionFunc ConditionFunc
|
||||
expectedErr error
|
||||
expectedEvent *watch.Event
|
||||
}{
|
||||
{
|
||||
name: "doesn't wait for sync with no precondition",
|
||||
lw: &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
select {}
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
select {}
|
||||
},
|
||||
},
|
||||
preconditionFunc: nil,
|
||||
conditionFunc: func(e watch.Event) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
expectedErr: errors.New("timed out waiting for the condition"),
|
||||
expectedEvent: nil,
|
||||
},
|
||||
{
|
||||
name: "waits indefinitely with precondition if it can't sync",
|
||||
lw: &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
select {}
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
select {}
|
||||
},
|
||||
},
|
||||
preconditionFunc: func(store cache.Store) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
conditionFunc: func(e watch.Event) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
expectedErr: errors.New("UntilWithSync: unable to sync caches: context deadline exceeded"),
|
||||
expectedEvent: nil,
|
||||
},
|
||||
{
|
||||
name: "precondition can stop the loop",
|
||||
lw: func() *cache.ListWatch {
|
||||
fakeclient := fakeclient.NewSimpleClientset(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "first"}})
|
||||
|
||||
return &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
return fakeclient.CoreV1().Secrets("").List(options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return fakeclient.CoreV1().Secrets("").Watch(options)
|
||||
},
|
||||
}
|
||||
}(),
|
||||
preconditionFunc: func(store cache.Store) (bool, error) {
|
||||
_, exists, err := store.Get(&metav1.ObjectMeta{Namespace: "", Name: "first"})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if exists {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
},
|
||||
conditionFunc: func(e watch.Event) (bool, error) {
|
||||
return true, errors.New("should never reach this")
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectedEvent: nil,
|
||||
},
|
||||
{
|
||||
name: "precondition lets it proceed to regular condition",
|
||||
lw: func() *cache.ListWatch {
|
||||
fakeclient := fakeclient.NewSimpleClientset(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "first"}})
|
||||
|
||||
return &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
return fakeclient.CoreV1().Secrets("").List(options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return fakeclient.CoreV1().Secrets("").Watch(options)
|
||||
},
|
||||
}
|
||||
}(),
|
||||
preconditionFunc: func(store cache.Store) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
conditionFunc: func(e watch.Event) (bool, error) {
|
||||
if e.Type == watch.Added {
|
||||
return true, nil
|
||||
}
|
||||
panic("no other events are expected")
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectedEvent: &watch.Event{Type: watch.Added, Object: &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "first"}}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Informer waits for caches to sync by polling in 100ms intervals,
|
||||
// timeout needs to be reasonably higher
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
event, err := UntilWithSync(ctx, tc.lw, &corev1.Secret{}, tc.preconditionFunc, tc.conditionFunc)
|
||||
|
||||
if !reflect.DeepEqual(err, tc.expectedErr) {
|
||||
t.Errorf("expected error %#v, got %#v", tc.expectedErr, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(event, tc.expectedEvent) {
|
||||
t.Errorf("expected event %#v, got %#v", tc.expectedEvent, event)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user