go.mod: update kubernetes to v1.22.0
This brings in some cri api changes for cgroups, Windows pod sandbox security context changes and some new fields for the Windows version of a privileged container. This also unfortunately bumps the prometheus client, grpc middleware, bolt and klog :( Signed-off-by: Daniel Canter <dcanter@microsoft.com>
This commit is contained in:
36
vendor/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go
generated
vendored
Normal file
36
vendor/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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 install installs the experimental API group, making it available as
|
||||
// an option to all of the API encoding/decoding machinery.
|
||||
package install
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
)
|
||||
|
||||
// Install registers the API group and adds types to a scheme
|
||||
func Install(scheme *runtime.Scheme) {
|
||||
utilruntime.Must(clientauthentication.AddToScheme(scheme))
|
||||
utilruntime.Must(v1.AddToScheme(scheme))
|
||||
utilruntime.Must(v1beta1.AddToScheme(scheme))
|
||||
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||
}
|
||||
2
vendor/k8s.io/client-go/pkg/apis/clientauthentication/types.go
generated
vendored
2
vendor/k8s.io/client-go/pkg/apis/clientauthentication/types.go
generated
vendored
@@ -47,7 +47,7 @@ type ExecCredentialSpec struct {
|
||||
Response *Response
|
||||
|
||||
// Interactive is true when the transport detects the command is being called from an
|
||||
// interactive prompt.
|
||||
// interactive prompt, i.e., when stdin has been passed to this exec plugin.
|
||||
// +optional
|
||||
Interactive bool
|
||||
|
||||
|
||||
28
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/conversion.go
generated
vendored
Normal file
28
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/conversion.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2021 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 v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
)
|
||||
|
||||
func Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error {
|
||||
// This conversion intentionally omits the Response field, which were only
|
||||
// supported in v1alpha1.
|
||||
return autoConvert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in, out, s)
|
||||
}
|
||||
24
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go
generated
vendored
Normal file
24
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2021 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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:conversion-gen=k8s.io/client-go/pkg/apis/clientauthentication
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// +groupName=client.authentication.k8s.io
|
||||
|
||||
package v1 // import "k8s.io/client-go/pkg/apis/clientauthentication/v1"
|
||||
55
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/register.go
generated
vendored
Normal file
55
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/register.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2021 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 v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "client.authentication.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes)
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&ExecCredential{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
122
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/types.go
generated
vendored
Normal file
122
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/types.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2021 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 v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ExecCredential is used by exec-based plugins to communicate credentials to
|
||||
// HTTP transports.
|
||||
type ExecCredential struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Spec holds information passed to the plugin by the transport.
|
||||
Spec ExecCredentialSpec `json:"spec,omitempty"`
|
||||
|
||||
// Status is filled in by the plugin and holds the credentials that the transport
|
||||
// should use to contact the API.
|
||||
// +optional
|
||||
Status *ExecCredentialStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ExecCredentialSpec holds request and runtime specific information provided by
|
||||
// the transport.
|
||||
type ExecCredentialSpec struct {
|
||||
// Cluster contains information to allow an exec plugin to communicate with the
|
||||
// kubernetes cluster being authenticated to. Note that Cluster is non-nil only
|
||||
// when provideClusterInfo is set to true in the exec provider config (i.e.,
|
||||
// ExecConfig.ProvideClusterInfo).
|
||||
// +optional
|
||||
Cluster *Cluster `json:"cluster,omitempty"`
|
||||
|
||||
// Interactive declares whether stdin has been passed to this exec plugin.
|
||||
Interactive bool `json:"interactive"`
|
||||
}
|
||||
|
||||
// ExecCredentialStatus holds credentials for the transport to use.
|
||||
//
|
||||
// Token and ClientKeyData are sensitive fields. This data should only be
|
||||
// transmitted in-memory between client and exec plugin process. Exec plugin
|
||||
// itself should at least be protected via file permissions.
|
||||
type ExecCredentialStatus struct {
|
||||
// ExpirationTimestamp indicates a time when the provided credentials expire.
|
||||
// +optional
|
||||
ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"`
|
||||
// Token is a bearer token used by the client for request authentication.
|
||||
Token string `json:"token,omitempty" datapolicy:"token"`
|
||||
// PEM-encoded client TLS certificates (including intermediates, if any).
|
||||
ClientCertificateData string `json:"clientCertificateData,omitempty"`
|
||||
// PEM-encoded private key for the above certificate.
|
||||
ClientKeyData string `json:"clientKeyData,omitempty" datapolicy:"security-key"`
|
||||
}
|
||||
|
||||
// Cluster contains information to allow an exec plugin to communicate
|
||||
// with the kubernetes cluster being authenticated to.
|
||||
//
|
||||
// To ensure that this struct contains everything someone would need to communicate
|
||||
// with a kubernetes cluster (just like they would via a kubeconfig), the fields
|
||||
// should shadow "k8s.io/client-go/tools/clientcmd/api/v1".Cluster, with the exception
|
||||
// of CertificateAuthority, since CA data will always be passed to the plugin as bytes.
|
||||
type Cluster struct {
|
||||
// Server is the address of the kubernetes cluster (https://hostname:port).
|
||||
Server string `json:"server"`
|
||||
// TLSServerName is passed to the server for SNI and is used in the client to
|
||||
// check server certificates against. If ServerName is empty, the hostname
|
||||
// used to contact the server is used.
|
||||
// +optional
|
||||
TLSServerName string `json:"tls-server-name,omitempty"`
|
||||
// InsecureSkipTLSVerify skips the validity check for the server's certificate.
|
||||
// This will make your HTTPS connections insecure.
|
||||
// +optional
|
||||
InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"`
|
||||
// CAData contains PEM-encoded certificate authority certificates.
|
||||
// If empty, system roots should be used.
|
||||
// +listType=atomic
|
||||
// +optional
|
||||
CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"`
|
||||
// ProxyURL is the URL to the proxy to be used for all requests to this
|
||||
// cluster.
|
||||
// +optional
|
||||
ProxyURL string `json:"proxy-url,omitempty"`
|
||||
// Config holds additional config data that is specific to the exec
|
||||
// plugin with regards to the cluster being authenticated to.
|
||||
//
|
||||
// This data is sourced from the clientcmd Cluster object's
|
||||
// extensions[client.authentication.k8s.io/exec] field:
|
||||
//
|
||||
// clusters:
|
||||
// - name: my-cluster
|
||||
// cluster:
|
||||
// ...
|
||||
// extensions:
|
||||
// - name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config
|
||||
// extension:
|
||||
// audience: 06e3fbd18de8 # arbitrary config
|
||||
//
|
||||
// In some environments, the user config may be exactly the same across many clusters
|
||||
// (i.e. call this exec plugin) minus some details that are specific to each cluster
|
||||
// such as the audience. This field allows the per cluster config to be directly
|
||||
// specified with the cluster info. Using this field to store secret data is not
|
||||
// recommended as one of the prime benefits of exec plugins is that no secrets need
|
||||
// to be stored directly in the kubeconfig.
|
||||
// +optional
|
||||
Config runtime.RawExtension `json:"config,omitempty"`
|
||||
}
|
||||
200
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.conversion.go
generated
vendored
Normal file
200
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.conversion.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by conversion-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
unsafe "unsafe"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
clientauthentication "k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*Cluster)(nil), (*clientauthentication.Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_Cluster_To_clientauthentication_Cluster(a.(*Cluster), b.(*clientauthentication.Cluster), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*clientauthentication.Cluster)(nil), (*Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_clientauthentication_Cluster_To_v1_Cluster(a.(*clientauthentication.Cluster), b.(*Cluster), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*ExecCredential)(nil), (*clientauthentication.ExecCredential)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_ExecCredential_To_clientauthentication_ExecCredential(a.(*ExecCredential), b.(*clientauthentication.ExecCredential), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*clientauthentication.ExecCredential)(nil), (*ExecCredential)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_clientauthentication_ExecCredential_To_v1_ExecCredential(a.(*clientauthentication.ExecCredential), b.(*ExecCredential), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*ExecCredentialSpec)(nil), (*clientauthentication.ExecCredentialSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(a.(*ExecCredentialSpec), b.(*clientauthentication.ExecCredentialSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*ExecCredentialStatus)(nil), (*clientauthentication.ExecCredentialStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(a.(*ExecCredentialStatus), b.(*clientauthentication.ExecCredentialStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*clientauthentication.ExecCredentialStatus)(nil), (*ExecCredentialStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(a.(*clientauthentication.ExecCredentialStatus), b.(*ExecCredentialStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*clientauthentication.ExecCredentialSpec)(nil), (*ExecCredentialSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(a.(*clientauthentication.ExecCredentialSpec), b.(*ExecCredentialSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1_Cluster_To_clientauthentication_Cluster(in *Cluster, out *clientauthentication.Cluster, s conversion.Scope) error {
|
||||
out.Server = in.Server
|
||||
out.TLSServerName = in.TLSServerName
|
||||
out.InsecureSkipTLSVerify = in.InsecureSkipTLSVerify
|
||||
out.CertificateAuthorityData = *(*[]byte)(unsafe.Pointer(&in.CertificateAuthorityData))
|
||||
out.ProxyURL = in.ProxyURL
|
||||
if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Config, &out.Config, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_Cluster_To_clientauthentication_Cluster is an autogenerated conversion function.
|
||||
func Convert_v1_Cluster_To_clientauthentication_Cluster(in *Cluster, out *clientauthentication.Cluster, s conversion.Scope) error {
|
||||
return autoConvert_v1_Cluster_To_clientauthentication_Cluster(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_clientauthentication_Cluster_To_v1_Cluster(in *clientauthentication.Cluster, out *Cluster, s conversion.Scope) error {
|
||||
out.Server = in.Server
|
||||
out.TLSServerName = in.TLSServerName
|
||||
out.InsecureSkipTLSVerify = in.InsecureSkipTLSVerify
|
||||
out.CertificateAuthorityData = *(*[]byte)(unsafe.Pointer(&in.CertificateAuthorityData))
|
||||
out.ProxyURL = in.ProxyURL
|
||||
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Config, &out.Config, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_clientauthentication_Cluster_To_v1_Cluster is an autogenerated conversion function.
|
||||
func Convert_clientauthentication_Cluster_To_v1_Cluster(in *clientauthentication.Cluster, out *Cluster, s conversion.Scope) error {
|
||||
return autoConvert_clientauthentication_Cluster_To_v1_Cluster(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ExecCredential_To_clientauthentication_ExecCredential(in *ExecCredential, out *clientauthentication.ExecCredential, s conversion.Scope) error {
|
||||
if err := Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Status = (*clientauthentication.ExecCredentialStatus)(unsafe.Pointer(in.Status))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ExecCredential_To_clientauthentication_ExecCredential is an autogenerated conversion function.
|
||||
func Convert_v1_ExecCredential_To_clientauthentication_ExecCredential(in *ExecCredential, out *clientauthentication.ExecCredential, s conversion.Scope) error {
|
||||
return autoConvert_v1_ExecCredential_To_clientauthentication_ExecCredential(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_clientauthentication_ExecCredential_To_v1_ExecCredential(in *clientauthentication.ExecCredential, out *ExecCredential, s conversion.Scope) error {
|
||||
if err := Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Status = (*ExecCredentialStatus)(unsafe.Pointer(in.Status))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_clientauthentication_ExecCredential_To_v1_ExecCredential is an autogenerated conversion function.
|
||||
func Convert_clientauthentication_ExecCredential_To_v1_ExecCredential(in *clientauthentication.ExecCredential, out *ExecCredential, s conversion.Scope) error {
|
||||
return autoConvert_clientauthentication_ExecCredential_To_v1_ExecCredential(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in *ExecCredentialSpec, out *clientauthentication.ExecCredentialSpec, s conversion.Scope) error {
|
||||
if in.Cluster != nil {
|
||||
in, out := &in.Cluster, &out.Cluster
|
||||
*out = new(clientauthentication.Cluster)
|
||||
if err := Convert_v1_Cluster_To_clientauthentication_Cluster(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Cluster = nil
|
||||
}
|
||||
out.Interactive = in.Interactive
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec is an autogenerated conversion function.
|
||||
func Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in *ExecCredentialSpec, out *clientauthentication.ExecCredentialSpec, s conversion.Scope) error {
|
||||
return autoConvert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error {
|
||||
// WARNING: in.Response requires manual conversion: does not exist in peer-type
|
||||
out.Interactive = in.Interactive
|
||||
if in.Cluster != nil {
|
||||
in, out := &in.Cluster, &out.Cluster
|
||||
*out = new(Cluster)
|
||||
if err := Convert_clientauthentication_Cluster_To_v1_Cluster(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Cluster = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in *ExecCredentialStatus, out *clientauthentication.ExecCredentialStatus, s conversion.Scope) error {
|
||||
out.ExpirationTimestamp = (*metav1.Time)(unsafe.Pointer(in.ExpirationTimestamp))
|
||||
out.Token = in.Token
|
||||
out.ClientCertificateData = in.ClientCertificateData
|
||||
out.ClientKeyData = in.ClientKeyData
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus is an autogenerated conversion function.
|
||||
func Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in *ExecCredentialStatus, out *clientauthentication.ExecCredentialStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in *clientauthentication.ExecCredentialStatus, out *ExecCredentialStatus, s conversion.Scope) error {
|
||||
out.ExpirationTimestamp = (*metav1.Time)(unsafe.Pointer(in.ExpirationTimestamp))
|
||||
out.Token = in.Token
|
||||
out.ClientCertificateData = in.ClientCertificateData
|
||||
out.ClientKeyData = in.ClientKeyData
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus is an autogenerated conversion function.
|
||||
func Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in *clientauthentication.ExecCredentialStatus, out *ExecCredentialStatus, s conversion.Scope) error {
|
||||
return autoConvert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in, out, s)
|
||||
}
|
||||
119
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.deepcopy.go
generated
vendored
Normal file
119
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Cluster) DeepCopyInto(out *Cluster) {
|
||||
*out = *in
|
||||
if in.CertificateAuthorityData != nil {
|
||||
in, out := &in.CertificateAuthorityData, &out.CertificateAuthorityData
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.Config.DeepCopyInto(&out.Config)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster.
|
||||
func (in *Cluster) DeepCopy() *Cluster {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Cluster)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecCredential) DeepCopyInto(out *ExecCredential) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
if in.Status != nil {
|
||||
in, out := &in.Status, &out.Status
|
||||
*out = new(ExecCredentialStatus)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredential.
|
||||
func (in *ExecCredential) DeepCopy() *ExecCredential {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecCredential)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ExecCredential) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecCredentialSpec) DeepCopyInto(out *ExecCredentialSpec) {
|
||||
*out = *in
|
||||
if in.Cluster != nil {
|
||||
in, out := &in.Cluster, &out.Cluster
|
||||
*out = new(Cluster)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredentialSpec.
|
||||
func (in *ExecCredentialSpec) DeepCopy() *ExecCredentialSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecCredentialSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecCredentialStatus) DeepCopyInto(out *ExecCredentialStatus) {
|
||||
*out = *in
|
||||
if in.ExpirationTimestamp != nil {
|
||||
in, out := &in.ExpirationTimestamp, &out.ExpirationTimestamp
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredentialStatus.
|
||||
func (in *ExecCredentialStatus) DeepCopy() *ExecCredentialStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecCredentialStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
32
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.defaults.go
generated
vendored
Normal file
32
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.defaults.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
2
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/conversion.go
generated
vendored
2
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/conversion.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
func Convert_clientauthentication_ExecCredentialSpec_To_v1beta1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error {
|
||||
// This conversion intentionally omits the Response and Interactive fields, which were only
|
||||
// This conversion intentionally omits the Response field, which were only
|
||||
// supported in v1alpha1.
|
||||
return autoConvert_clientauthentication_ExecCredentialSpec_To_v1beta1_ExecCredentialSpec(in, out, s)
|
||||
}
|
||||
|
||||
3
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/types.go
generated
vendored
3
vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/types.go
generated
vendored
@@ -46,6 +46,9 @@ type ExecCredentialSpec struct {
|
||||
// ExecConfig.ProvideClusterInfo).
|
||||
// +optional
|
||||
Cluster *Cluster `json:"cluster,omitempty"`
|
||||
|
||||
// Interactive declares whether stdin has been passed to this exec plugin.
|
||||
Interactive bool `json:"interactive"`
|
||||
}
|
||||
|
||||
// ExecCredentialStatus holds credentials for the transport to use.
|
||||
|
||||
@@ -149,6 +149,7 @@ func autoConvert_v1beta1_ExecCredentialSpec_To_clientauthentication_ExecCredenti
|
||||
} else {
|
||||
out.Cluster = nil
|
||||
}
|
||||
out.Interactive = in.Interactive
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -159,7 +160,7 @@ func Convert_v1beta1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSp
|
||||
|
||||
func autoConvert_clientauthentication_ExecCredentialSpec_To_v1beta1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error {
|
||||
// WARNING: in.Response requires manual conversion: does not exist in peer-type
|
||||
// WARNING: in.Interactive requires manual conversion: does not exist in peer-type
|
||||
out.Interactive = in.Interactive
|
||||
if in.Cluster != nil {
|
||||
in, out := &in.Cluster, &out.Cluster
|
||||
*out = new(Cluster)
|
||||
|
||||
2
vendor/k8s.io/client-go/pkg/version/base.go
generated
vendored
2
vendor/k8s.io/client-go/pkg/version/base.go
generated
vendored
@@ -55,7 +55,7 @@ var (
|
||||
// NOTE: The $Format strings are replaced during 'git archive' thanks to the
|
||||
// companion .gitattributes file containing 'export-subst' in this same
|
||||
// directory. See also https://git-scm.com/docs/gitattributes
|
||||
gitVersion string = "v0.0.0-master+$Format:%h$"
|
||||
gitVersion string = "v0.0.0-master+$Format:%H$"
|
||||
gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
|
||||
gitTreeState string = "" // state of git tree, either "clean" or "dirty"
|
||||
|
||||
|
||||
38
vendor/k8s.io/client-go/pkg/version/def.bzl
generated
vendored
38
vendor/k8s.io/client-go/pkg/version/def.bzl
generated
vendored
@@ -1,38 +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.
|
||||
|
||||
# Implements hack/lib/version.sh's kube::version::ldflags() for Bazel.
|
||||
def version_x_defs():
|
||||
# This should match the list of packages in kube::version::ldflag
|
||||
stamp_pkgs = [
|
||||
"k8s.io/component-base/version",
|
||||
# In hack/lib/version.sh, this has a vendor/ prefix. That isn't needed here?
|
||||
"k8s.io/client-go/pkg/version",
|
||||
]
|
||||
# This should match the list of vars in kube::version::ldflags
|
||||
# It should also match the list of vars set in hack/print-workspace-status.sh.
|
||||
stamp_vars = [
|
||||
"buildDate",
|
||||
"gitCommit",
|
||||
"gitMajor",
|
||||
"gitMinor",
|
||||
"gitTreeState",
|
||||
"gitVersion",
|
||||
]
|
||||
# Generate the cross-product.
|
||||
x_defs = {}
|
||||
for pkg in stamp_pkgs:
|
||||
for var in stamp_vars:
|
||||
x_defs["%s.%s" % (pkg, var)] = "{%s}" % var
|
||||
return x_defs
|
||||
130
vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go
generated
vendored
130
vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go
generated
vendored
@@ -18,7 +18,6 @@ package exec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
@@ -34,16 +33,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"golang.org/x/term"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/install"
|
||||
clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
|
||||
clientauthenticationv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
|
||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/metrics"
|
||||
"k8s.io/client-go/transport"
|
||||
@@ -52,7 +52,6 @@ import (
|
||||
)
|
||||
|
||||
const execInfoEnv = "KUBERNETES_EXEC_INFO"
|
||||
const onRotateListWarningLength = 1000
|
||||
const installHintVerboseHelp = `
|
||||
|
||||
It looks like you are trying to use a client-go credential plugin that is not installed.
|
||||
@@ -64,10 +63,7 @@ var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||
utilruntime.Must(v1beta1.AddToScheme(scheme))
|
||||
utilruntime.Must(clientauthentication.AddToScheme(scheme))
|
||||
install.Install(scheme)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -76,8 +72,9 @@ var (
|
||||
globalCache = newCache()
|
||||
// The list of API versions we accept.
|
||||
apiVersions = map[string]schema.GroupVersion{
|
||||
v1alpha1.SchemeGroupVersion.String(): v1alpha1.SchemeGroupVersion,
|
||||
v1beta1.SchemeGroupVersion.String(): v1beta1.SchemeGroupVersion,
|
||||
clientauthenticationv1alpha1.SchemeGroupVersion.String(): clientauthenticationv1alpha1.SchemeGroupVersion,
|
||||
clientauthenticationv1beta1.SchemeGroupVersion.String(): clientauthenticationv1beta1.SchemeGroupVersion,
|
||||
clientauthenticationv1.SchemeGroupVersion.String(): clientauthenticationv1.SchemeGroupVersion,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -163,10 +160,10 @@ func (s *sometimes) Do(f func()) {
|
||||
|
||||
// GetAuthenticator returns an exec-based plugin for providing client credentials.
|
||||
func GetAuthenticator(config *api.ExecConfig, cluster *clientauthentication.Cluster) (*Authenticator, error) {
|
||||
return newAuthenticator(globalCache, config, cluster)
|
||||
return newAuthenticator(globalCache, term.IsTerminal, config, cluster)
|
||||
}
|
||||
|
||||
func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentication.Cluster) (*Authenticator, error) {
|
||||
func newAuthenticator(c *cache, isTerminalFunc func(int) bool, config *api.ExecConfig, cluster *clientauthentication.Cluster) (*Authenticator, error) {
|
||||
key := cacheKey(config, cluster)
|
||||
if a, ok := c.get(key); ok {
|
||||
return a, nil
|
||||
@@ -177,6 +174,12 @@ func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentic
|
||||
return nil, fmt.Errorf("exec plugin: invalid apiVersion %q", config.APIVersion)
|
||||
}
|
||||
|
||||
connTracker := connrotation.NewConnectionTracker()
|
||||
defaultDialer := connrotation.NewDialerWithTracker(
|
||||
(&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext,
|
||||
connTracker,
|
||||
)
|
||||
|
||||
a := &Authenticator{
|
||||
cmd: config.Command,
|
||||
args: config.Args,
|
||||
@@ -191,11 +194,14 @@ func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentic
|
||||
clock: clock.RealClock{},
|
||||
},
|
||||
|
||||
stdin: os.Stdin,
|
||||
stderr: os.Stderr,
|
||||
interactive: terminal.IsTerminal(int(os.Stdout.Fd())),
|
||||
now: time.Now,
|
||||
environ: os.Environ,
|
||||
stdin: os.Stdin,
|
||||
stderr: os.Stderr,
|
||||
interactiveFunc: func() (bool, error) { return isInteractive(isTerminalFunc, config) },
|
||||
now: time.Now,
|
||||
environ: os.Environ,
|
||||
|
||||
defaultDialer: defaultDialer,
|
||||
connTracker: connTracker,
|
||||
}
|
||||
|
||||
for _, env := range config.Env {
|
||||
@@ -205,6 +211,33 @@ func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentic
|
||||
return c.put(key, a), nil
|
||||
}
|
||||
|
||||
func isInteractive(isTerminalFunc func(int) bool, config *api.ExecConfig) (bool, error) {
|
||||
var shouldBeInteractive bool
|
||||
switch config.InteractiveMode {
|
||||
case api.NeverExecInteractiveMode:
|
||||
shouldBeInteractive = false
|
||||
case api.IfAvailableExecInteractiveMode:
|
||||
shouldBeInteractive = !config.StdinUnavailable && isTerminalFunc(int(os.Stdin.Fd()))
|
||||
case api.AlwaysExecInteractiveMode:
|
||||
if !isTerminalFunc(int(os.Stdin.Fd())) {
|
||||
return false, errors.New("standard input is not a terminal")
|
||||
}
|
||||
if config.StdinUnavailable {
|
||||
suffix := ""
|
||||
if len(config.StdinUnavailableMessage) > 0 {
|
||||
// only print extra ": <message>" if the user actually specified a message
|
||||
suffix = fmt.Sprintf(": %s", config.StdinUnavailableMessage)
|
||||
}
|
||||
return false, fmt.Errorf("standard input is unavailable%s", suffix)
|
||||
}
|
||||
shouldBeInteractive = true
|
||||
default:
|
||||
return false, fmt.Errorf("unknown interactiveMode: %q", config.InteractiveMode)
|
||||
}
|
||||
|
||||
return shouldBeInteractive, nil
|
||||
}
|
||||
|
||||
// Authenticator is a client credential provider that rotates credentials by executing a plugin.
|
||||
// The plugin input and output are defined by the API group client.authentication.k8s.io.
|
||||
type Authenticator struct {
|
||||
@@ -223,11 +256,16 @@ type Authenticator struct {
|
||||
installHint string
|
||||
|
||||
// Stubbable for testing
|
||||
stdin io.Reader
|
||||
stderr io.Writer
|
||||
interactive bool
|
||||
now func() time.Time
|
||||
environ func() []string
|
||||
stdin io.Reader
|
||||
stderr io.Writer
|
||||
interactiveFunc func() (bool, error)
|
||||
now func() time.Time
|
||||
environ func() []string
|
||||
|
||||
// defaultDialer is used for clients which don't specify a custom dialer
|
||||
defaultDialer *connrotation.Dialer
|
||||
// connTracker tracks all connections opened that we need to close when rotating a client certificate
|
||||
connTracker *connrotation.ConnectionTracker
|
||||
|
||||
// Cached results.
|
||||
//
|
||||
@@ -236,8 +274,6 @@ type Authenticator struct {
|
||||
mu sync.Mutex
|
||||
cachedCreds *credentials
|
||||
exp time.Time
|
||||
|
||||
onRotateList []func()
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
@@ -252,8 +288,9 @@ func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
|
||||
// setting up the transport, as that triggers the exec action if the server is
|
||||
// also configured to allow client certificates for authentication. For requests
|
||||
// like "kubectl get --token (token) pods" we should assume the intention is to
|
||||
// use the provided token for authentication.
|
||||
if c.HasTokenAuth() {
|
||||
// use the provided token for authentication. The same can be said for when the
|
||||
// user specifies basic auth.
|
||||
if c.HasTokenAuth() || c.HasBasicAuth() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -266,20 +303,12 @@ func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
|
||||
}
|
||||
c.TLS.GetCert = a.cert
|
||||
|
||||
var dial func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
var d *connrotation.Dialer
|
||||
if c.Dial != nil {
|
||||
dial = c.Dial
|
||||
// if c has a custom dialer, we have to wrap it
|
||||
d = connrotation.NewDialerWithTracker(c.Dial, a.connTracker)
|
||||
} else {
|
||||
dial = (&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext
|
||||
}
|
||||
d := connrotation.NewDialer(dial)
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.onRotateList = append(a.onRotateList, d.CloseAll)
|
||||
onRotateListLength := len(a.onRotateList)
|
||||
if onRotateListLength > onRotateListWarningLength {
|
||||
klog.Warningf("constructing many client instances from the same exec auth config can cause performance problems during cert rotation and can exhaust available network connections; %d clients constructed calling %q", onRotateListLength, a.cmd)
|
||||
d = a.defaultDialer
|
||||
}
|
||||
|
||||
c.Dial = d.DialContext
|
||||
@@ -372,10 +401,15 @@ func (a *Authenticator) maybeRefreshCreds(creds *credentials, r *clientauthentic
|
||||
// refreshCredsLocked executes the plugin and reads the credentials from
|
||||
// stdout. It must be called while holding the Authenticator's mutex.
|
||||
func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) error {
|
||||
interactive, err := a.interactiveFunc()
|
||||
if err != nil {
|
||||
return fmt.Errorf("exec plugin cannot support interactive mode: %w", err)
|
||||
}
|
||||
|
||||
cred := &clientauthentication.ExecCredential{
|
||||
Spec: clientauthentication.ExecCredentialSpec{
|
||||
Response: r,
|
||||
Interactive: a.interactive,
|
||||
Interactive: interactive,
|
||||
},
|
||||
}
|
||||
if a.provideClusterInfo {
|
||||
@@ -394,11 +428,13 @@ func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) err
|
||||
cmd.Env = env
|
||||
cmd.Stderr = a.stderr
|
||||
cmd.Stdout = stdout
|
||||
if a.interactive {
|
||||
if interactive {
|
||||
cmd.Stdin = a.stdin
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
err = cmd.Run()
|
||||
incrementCallsMetric(err)
|
||||
if err != nil {
|
||||
return a.wrapCmdRunErrorLocked(err)
|
||||
}
|
||||
|
||||
@@ -456,11 +492,9 @@ func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) err
|
||||
if oldCreds != nil && !reflect.DeepEqual(oldCreds.cert, a.cachedCreds.cert) {
|
||||
// Can be nil if the exec auth plugin only returned token auth.
|
||||
if oldCreds.cert != nil && oldCreds.cert.Leaf != nil {
|
||||
metrics.ClientCertRotationAge.Observe(time.Now().Sub(oldCreds.cert.Leaf.NotBefore))
|
||||
}
|
||||
for _, onRotate := range a.onRotateList {
|
||||
onRotate()
|
||||
metrics.ClientCertRotationAge.Observe(time.Since(oldCreds.cert.Leaf.NotBefore))
|
||||
}
|
||||
a.connTracker.CloseAll()
|
||||
}
|
||||
|
||||
expiry := time.Time{}
|
||||
|
||||
51
vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/metrics.go
generated
vendored
51
vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/metrics.go
generated
vendored
@@ -17,12 +17,40 @@ limitations under the License.
|
||||
package exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/client-go/tools/metrics"
|
||||
)
|
||||
|
||||
// The following constants shadow the special values used in the prometheus metrics implementation.
|
||||
const (
|
||||
// noError indicates that the plugin process was successfully started and exited with an exit
|
||||
// code of 0.
|
||||
noError = "no_error"
|
||||
// pluginExecutionError indicates that the plugin process was successfully started and then
|
||||
// it returned a non-zero exit code.
|
||||
pluginExecutionError = "plugin_execution_error"
|
||||
// pluginNotFoundError indicates that we could not find the exec plugin.
|
||||
pluginNotFoundError = "plugin_not_found_error"
|
||||
// clientInternalError indicates that we attempted to start the plugin process, but failed
|
||||
// for some reason.
|
||||
clientInternalError = "client_internal_error"
|
||||
|
||||
// successExitCode represents an exec plugin invocation that was successful.
|
||||
successExitCode = 0
|
||||
// failureExitCode represents an exec plugin invocation that was not successful. This code is
|
||||
// used in some failure modes (e.g., plugin not found, client internal error) so that someone
|
||||
// can more easily monitor all unsuccessful invocations.
|
||||
failureExitCode = 1
|
||||
)
|
||||
|
||||
type certificateExpirationTracker struct {
|
||||
mu sync.RWMutex
|
||||
m map[*Authenticator]time.Time
|
||||
@@ -58,3 +86,26 @@ func (c *certificateExpirationTracker) set(a *Authenticator, t time.Time) {
|
||||
c.metricSet(&earliest)
|
||||
}
|
||||
}
|
||||
|
||||
// incrementCallsMetric increments a global metrics counter for the number of calls to an exec
|
||||
// plugin, partitioned by exit code. The provided err should be the return value from
|
||||
// exec.Cmd.Run().
|
||||
func incrementCallsMetric(err error) {
|
||||
execExitError := &exec.ExitError{}
|
||||
execError := &exec.Error{}
|
||||
pathError := &fs.PathError{}
|
||||
switch {
|
||||
case err == nil: // Binary execution succeeded.
|
||||
metrics.ExecPluginCalls.Increment(successExitCode, noError)
|
||||
|
||||
case errors.As(err, &execExitError): // Binary execution failed (see "os/exec".Cmd.Run()).
|
||||
metrics.ExecPluginCalls.Increment(execExitError.ExitCode(), pluginExecutionError)
|
||||
|
||||
case errors.As(err, &execError), errors.As(err, &pathError): // Binary does not exist (see exec.Error, fs.PathError).
|
||||
metrics.ExecPluginCalls.Increment(failureExitCode, pluginNotFoundError)
|
||||
|
||||
default: // We don't know about this error type.
|
||||
klog.V(2).InfoS("unexpected exec plugin return error type", "type", reflect.TypeOf(err).String(), "err", err)
|
||||
metrics.ExecPluginCalls.Increment(failureExitCode, clientInternalError)
|
||||
}
|
||||
}
|
||||
|
||||
3
vendor/k8s.io/client-go/rest/OWNERS
generated
vendored
3
vendor/k8s.io/client-go/rest/OWNERS
generated
vendored
@@ -8,9 +8,6 @@ reviewers:
|
||||
- deads2k
|
||||
- brendandburns
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- sttts
|
||||
- luxas
|
||||
- dims
|
||||
|
||||
2
vendor/k8s.io/client-go/rest/client.go
generated
vendored
2
vendor/k8s.io/client-go/rest/client.go
generated
vendored
@@ -127,7 +127,7 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientConte
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetRateLimiter returns rate limier for a given client, or nil if it's called on a nil client
|
||||
// GetRateLimiter returns rate limiter for a given client, or nil if it's called on a nil client
|
||||
func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
if c == nil {
|
||||
return nil
|
||||
|
||||
10
vendor/k8s.io/client-go/rest/plugin.go
generated
vendored
10
vendor/k8s.io/client-go/rest/plugin.go
generated
vendored
@@ -47,6 +47,13 @@ type AuthProviderConfigPersister interface {
|
||||
Persist(map[string]string) error
|
||||
}
|
||||
|
||||
type noopPersister struct{}
|
||||
|
||||
func (n *noopPersister) Persist(_ map[string]string) error {
|
||||
// no operation persister
|
||||
return nil
|
||||
}
|
||||
|
||||
// All registered auth provider plugins.
|
||||
var pluginsLock sync.Mutex
|
||||
var plugins = make(map[string]Factory)
|
||||
@@ -69,5 +76,8 @@ func GetAuthProvider(clusterAddress string, apc *clientcmdapi.AuthProviderConfig
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no Auth Provider found for name %q", apc.Name)
|
||||
}
|
||||
if persister == nil {
|
||||
persister = &noopPersister{}
|
||||
}
|
||||
return p(clusterAddress, apc.Config, persister)
|
||||
}
|
||||
|
||||
359
vendor/k8s.io/client-go/rest/request.go
generated
vendored
359
vendor/k8s.io/client-go/rest/request.go
generated
vendored
@@ -93,7 +93,6 @@ type Request struct {
|
||||
rateLimiter flowcontrol.RateLimiter
|
||||
backoff BackoffManager
|
||||
timeout time.Duration
|
||||
maxRetries int
|
||||
|
||||
// generic components accessible via method setters
|
||||
verb string
|
||||
@@ -110,8 +109,9 @@ type Request struct {
|
||||
subresource string
|
||||
|
||||
// output
|
||||
err error
|
||||
body io.Reader
|
||||
err error
|
||||
body io.Reader
|
||||
retry WithRetry
|
||||
}
|
||||
|
||||
// NewRequest creates a new request helper object for accessing runtime.Objects on a server.
|
||||
@@ -142,7 +142,7 @@ func NewRequest(c *RESTClient) *Request {
|
||||
backoff: backoff,
|
||||
timeout: timeout,
|
||||
pathPrefix: pathPrefix,
|
||||
maxRetries: 10,
|
||||
retry: &withRetry{maxRetries: 10},
|
||||
warningHandler: c.warningHandler,
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ func (r *Request) SubResource(subresources ...string) *Request {
|
||||
}
|
||||
subresource := path.Join(subresources...)
|
||||
if len(r.subresource) != 0 {
|
||||
r.err = fmt.Errorf("subresource already set to %q, cannot change to %q", r.resource, subresource)
|
||||
r.err = fmt.Errorf("subresource already set to %q, cannot change to %q", r.subresource, subresource)
|
||||
return r
|
||||
}
|
||||
for _, s := range subresources {
|
||||
@@ -408,10 +408,7 @@ func (r *Request) Timeout(d time.Duration) *Request {
|
||||
// function is specifically called with a different value.
|
||||
// A zero maxRetries prevent it from doing retires and return an error immediately.
|
||||
func (r *Request) MaxRetries(maxRetries int) *Request {
|
||||
if maxRetries < 0 {
|
||||
maxRetries = 0
|
||||
}
|
||||
r.maxRetries = maxRetries
|
||||
r.retry.SetMaxRetries(maxRetries)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -577,7 +574,7 @@ func (r Request) finalURLTemplate() url.URL {
|
||||
return *url
|
||||
}
|
||||
|
||||
func (r *Request) tryThrottle(ctx context.Context) error {
|
||||
func (r *Request) tryThrottleWithInfo(ctx context.Context, retryInfo string) error {
|
||||
if r.rateLimiter == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -587,19 +584,32 @@ func (r *Request) tryThrottle(ctx context.Context) error {
|
||||
err := r.rateLimiter.Wait(ctx)
|
||||
|
||||
latency := time.Since(now)
|
||||
|
||||
var message string
|
||||
switch {
|
||||
case len(retryInfo) > 0:
|
||||
message = fmt.Sprintf("Waited for %v, %s - request: %s:%s", latency, retryInfo, r.verb, r.URL().String())
|
||||
default:
|
||||
message = fmt.Sprintf("Waited for %v due to client-side throttling, not priority and fairness, request: %s:%s", latency, r.verb, r.URL().String())
|
||||
}
|
||||
|
||||
if latency > longThrottleLatency {
|
||||
klog.V(3).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
|
||||
klog.V(3).Info(message)
|
||||
}
|
||||
if latency > extraLongThrottleLatency {
|
||||
// If the rate limiter latency is very high, the log message should be printed at a higher log level,
|
||||
// but we use a throttled logger to prevent spamming.
|
||||
globalThrottledLogger.Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
|
||||
globalThrottledLogger.Infof("%s", message)
|
||||
}
|
||||
metrics.RateLimiterLatency.Observe(r.verb, r.finalURLTemplate(), latency)
|
||||
metrics.RateLimiterLatency.Observe(ctx, r.verb, r.finalURLTemplate(), latency)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Request) tryThrottle(ctx context.Context) error {
|
||||
return r.tryThrottleWithInfo(ctx, "")
|
||||
}
|
||||
|
||||
type throttleSettings struct {
|
||||
logLevel klog.Level
|
||||
minLogInterval time.Duration
|
||||
@@ -665,43 +675,88 @@ func (r *Request) Watch(ctx context.Context) (watch.Interface, error) {
|
||||
return nil, r.err
|
||||
}
|
||||
|
||||
url := r.URL().String()
|
||||
req, err := http.NewRequest(r.verb, url, r.body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header = r.headers
|
||||
client := r.c.Client
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
if r.c.base != nil {
|
||||
if err != nil {
|
||||
r.backoff.UpdateBackoff(r.c.base, err, 0)
|
||||
} else {
|
||||
r.backoff.UpdateBackoff(r.c.base, err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
isErrRetryableFunc := func(request *http.Request, err error) bool {
|
||||
// The watch stream mechanism handles many common partial data errors, so closed
|
||||
// connections can be retried in many cases.
|
||||
if net.IsProbableEOF(err) || net.IsTimeout(err) {
|
||||
return watch.NewEmptyWatch(), nil
|
||||
return true
|
||||
}
|
||||
return nil, err
|
||||
return false
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
defer resp.Body.Close()
|
||||
if result := r.transformResponse(resp, req); result.err != nil {
|
||||
return nil, result.err
|
||||
var retryAfter *RetryAfter
|
||||
url := r.URL().String()
|
||||
for {
|
||||
req, err := r.newHTTPRequest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf("for request %s, got status: %v", url, resp.StatusCode)
|
||||
}
|
||||
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
if retryAfter != nil {
|
||||
// We are retrying the request that we already send to apiserver
|
||||
// at least once before.
|
||||
// This request should also be throttled with the client-internal rate limiter.
|
||||
if err := r.tryThrottleWithInfo(ctx, retryAfter.Reason); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retryAfter = nil
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(ctx, r, resp, err)
|
||||
if r.c.base != nil {
|
||||
if err != nil {
|
||||
r.backoff.UpdateBackoff(r.c.base, err, 0)
|
||||
} else {
|
||||
r.backoff.UpdateBackoff(r.c.base, err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
if err == nil && resp.StatusCode == http.StatusOK {
|
||||
return r.newStreamWatcher(resp)
|
||||
}
|
||||
|
||||
done, transformErr := func() (bool, error) {
|
||||
defer readAndCloseResponseBody(resp)
|
||||
|
||||
var retry bool
|
||||
retryAfter, retry = r.retry.NextRetry(req, resp, err, isErrRetryableFunc)
|
||||
if retry {
|
||||
err := r.retry.BeforeNextRetry(ctx, r.backoff, retryAfter, url, r.body)
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
klog.V(4).Infof("Could not retry request - %v", err)
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
// the server must have sent us an error in 'err'
|
||||
return true, nil
|
||||
}
|
||||
if result := r.transformResponse(resp, req); result.err != nil {
|
||||
return true, result.err
|
||||
}
|
||||
return true, fmt.Errorf("for request %s, got status: %v", url, resp.StatusCode)
|
||||
}()
|
||||
if done {
|
||||
if isErrRetryableFunc(req, err) {
|
||||
return watch.NewEmptyWatch(), nil
|
||||
}
|
||||
if err == nil {
|
||||
// if the server sent us an HTTP Response object,
|
||||
// we need to return the error object from that.
|
||||
err = transformErr
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) newStreamWatcher(resp *http.Response) (watch.Interface, error) {
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
mediaType, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
@@ -727,7 +782,7 @@ func (r *Request) Watch(ctx context.Context) (watch.Interface, error) {
|
||||
|
||||
// updateURLMetrics is a convenience function for pushing metrics.
|
||||
// It also handles corner cases for incomplete/invalid request data.
|
||||
func updateURLMetrics(req *Request, resp *http.Response, err error) {
|
||||
func updateURLMetrics(ctx context.Context, req *Request, resp *http.Response, err error) {
|
||||
url := "none"
|
||||
if req.c.base != nil {
|
||||
url = req.c.base.Host
|
||||
@@ -736,10 +791,10 @@ func updateURLMetrics(req *Request, resp *http.Response, err error) {
|
||||
// Errors can be arbitrary strings. Unbound label cardinality is not suitable for a metric
|
||||
// system so we just report them as `<error>`.
|
||||
if err != nil {
|
||||
metrics.RequestResult.Increment("<error>", req.verb, url)
|
||||
metrics.RequestResult.Increment(ctx, "<error>", req.verb, url)
|
||||
} else {
|
||||
//Metrics for failure codes
|
||||
metrics.RequestResult.Increment(strconv.Itoa(resp.StatusCode), req.verb, url)
|
||||
metrics.RequestResult.Increment(ctx, strconv.Itoa(resp.StatusCode), req.verb, url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,49 +811,75 @@ func (r *Request) Stream(ctx context.Context) (io.ReadCloser, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url := r.URL().String()
|
||||
req, err := http.NewRequest(r.verb, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.body != nil {
|
||||
req.Body = ioutil.NopCloser(r.body)
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header = r.headers
|
||||
client := r.c.Client
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
if r.c.base != nil {
|
||||
|
||||
var retryAfter *RetryAfter
|
||||
url := r.URL().String()
|
||||
for {
|
||||
req, err := r.newHTTPRequest(ctx)
|
||||
if err != nil {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, 0)
|
||||
} else {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case (resp.StatusCode >= 200) && (resp.StatusCode < 300):
|
||||
handleWarnings(resp.Header, r.warningHandler)
|
||||
return resp.Body, nil
|
||||
|
||||
default:
|
||||
// ensure we close the body before returning the error
|
||||
defer resp.Body.Close()
|
||||
|
||||
result := r.transformResponse(resp, req)
|
||||
err := result.Error()
|
||||
if err == nil {
|
||||
err = fmt.Errorf("%d while accessing %v: %s", result.statusCode, url, string(result.body))
|
||||
if r.body != nil {
|
||||
req.Body = ioutil.NopCloser(r.body)
|
||||
}
|
||||
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
if retryAfter != nil {
|
||||
// We are retrying the request that we already send to apiserver
|
||||
// at least once before.
|
||||
// This request should also be throttled with the client-internal rate limiter.
|
||||
if err := r.tryThrottleWithInfo(ctx, retryAfter.Reason); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retryAfter = nil
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(ctx, r, resp, err)
|
||||
if r.c.base != nil {
|
||||
if err != nil {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, 0)
|
||||
} else {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// we only retry on an HTTP response with 'Retry-After' header
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case (resp.StatusCode >= 200) && (resp.StatusCode < 300):
|
||||
handleWarnings(resp.Header, r.warningHandler)
|
||||
return resp.Body, nil
|
||||
|
||||
default:
|
||||
done, transformErr := func() (bool, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
var retry bool
|
||||
retryAfter, retry = r.retry.NextRetry(req, resp, err, neverRetryError)
|
||||
if retry {
|
||||
err := r.retry.BeforeNextRetry(ctx, r.backoff, retryAfter, url, r.body)
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
klog.V(4).Infof("Could not retry request - %v", err)
|
||||
}
|
||||
result := r.transformResponse(resp, req)
|
||||
if err := result.Error(); err != nil {
|
||||
return true, err
|
||||
}
|
||||
return true, fmt.Errorf("%d while accessing %v: %s", result.statusCode, url, string(result.body))
|
||||
}()
|
||||
if done {
|
||||
return nil, transformErr
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,6 +910,17 @@ func (r *Request) requestPreflightCheck() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Request) newHTTPRequest(ctx context.Context) (*http.Request, error) {
|
||||
url := r.URL().String()
|
||||
req, err := http.NewRequest(r.verb, url, r.body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header = r.headers
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// request connects to the server and invokes the provided function when a server response is
|
||||
// received. It handles retry behavior and up front validation of requests. It will invoke
|
||||
// fn at most once. It will return an error if a problem occurred prior to connecting to the
|
||||
@@ -837,7 +929,7 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp
|
||||
//Metrics for total request latency
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
metrics.RequestLatency.Observe(r.verb, r.finalURLTemplate(), time.Since(start))
|
||||
metrics.RequestLatency.Observe(ctx, r.verb, r.finalURLTemplate(), time.Since(start))
|
||||
}()
|
||||
|
||||
if r.err != nil {
|
||||
@@ -868,87 +960,69 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp
|
||||
}
|
||||
|
||||
// Right now we make about ten retry attempts if we get a Retry-After response.
|
||||
retries := 0
|
||||
var retryAfter *RetryAfter
|
||||
for {
|
||||
|
||||
url := r.URL().String()
|
||||
req, err := http.NewRequest(r.verb, url, r.body)
|
||||
req, err := r.newHTTPRequest(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header = r.headers
|
||||
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
if retries > 0 {
|
||||
if retryAfter != nil {
|
||||
// We are retrying the request that we already send to apiserver
|
||||
// at least once before.
|
||||
// This request should also be throttled with the client-internal rate limiter.
|
||||
if err := r.tryThrottle(ctx); err != nil {
|
||||
if err := r.tryThrottleWithInfo(ctx, retryAfter.Reason); err != nil {
|
||||
return err
|
||||
}
|
||||
retryAfter = nil
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
updateURLMetrics(ctx, r, resp, err)
|
||||
if err != nil {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, 0)
|
||||
} else {
|
||||
r.backoff.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
}
|
||||
if err != nil {
|
||||
// "Connection reset by peer" or "apiserver is shutting down" are usually a transient errors.
|
||||
// Thus in case of "GET" operations, we simply retry it.
|
||||
// We are not automatically retrying "write" operations, as
|
||||
// they are not idempotent.
|
||||
if r.verb != "GET" {
|
||||
return err
|
||||
}
|
||||
// For connection errors and apiserver shutdown errors retry.
|
||||
if net.IsConnectionReset(err) || net.IsProbableEOF(err) {
|
||||
// For the purpose of retry, we set the artificial "retry-after" response.
|
||||
// TODO: Should we clean the original response if it exists?
|
||||
resp = &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{"Retry-After": []string{"1"}},
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
done := func() bool {
|
||||
// Ensure the response body is fully read and closed
|
||||
// before we reconnect, so that we reuse the same TCP
|
||||
// connection.
|
||||
defer func() {
|
||||
const maxBodySlurpSize = 2 << 10
|
||||
if resp.ContentLength <= maxBodySlurpSize {
|
||||
io.Copy(ioutil.Discard, &io.LimitedReader{R: resp.Body, N: maxBodySlurpSize})
|
||||
}
|
||||
resp.Body.Close()
|
||||
}()
|
||||
defer readAndCloseResponseBody(resp)
|
||||
|
||||
retries++
|
||||
if seconds, wait := checkWait(resp); wait && retries <= r.maxRetries {
|
||||
if seeker, ok := r.body.(io.Seeker); ok && r.body != nil {
|
||||
_, err := seeker.Seek(0, 0)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Could not retry request, can't Seek() back to beginning of body for %T", r.body)
|
||||
fn(req, resp)
|
||||
return true
|
||||
}
|
||||
// if the the server returns an error in err, the response will be nil.
|
||||
f := func(req *http.Request, resp *http.Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url)
|
||||
r.backoff.Sleep(time.Duration(seconds) * time.Second)
|
||||
return false
|
||||
fn(req, resp)
|
||||
}
|
||||
fn(req, resp)
|
||||
|
||||
var retry bool
|
||||
retryAfter, retry = r.retry.NextRetry(req, resp, err, func(req *http.Request, err error) bool {
|
||||
// "Connection reset by peer" or "apiserver is shutting down" are usually a transient errors.
|
||||
// Thus in case of "GET" operations, we simply retry it.
|
||||
// We are not automatically retrying "write" operations, as they are not idempotent.
|
||||
if r.verb != "GET" {
|
||||
return false
|
||||
}
|
||||
// For connection errors and apiserver shutdown errors retry.
|
||||
if net.IsConnectionReset(err) || net.IsProbableEOF(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if retry {
|
||||
err := r.retry.BeforeNextRetry(ctx, r.backoff, retryAfter, req.URL.String(), r.body)
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
klog.V(4).Infof("Could not retry request - %v", err)
|
||||
}
|
||||
|
||||
f(req, resp)
|
||||
return true
|
||||
}()
|
||||
if done {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1003,13 +1077,13 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
// 3. Apiserver closes connection.
|
||||
// 4. client-go should catch this and return an error.
|
||||
klog.V(2).Infof("Stream error %#v when reading response body, may be caused by closed connection.", err)
|
||||
streamErr := fmt.Errorf("stream error when reading response body, may be caused by closed connection. Please retry. Original error: %v", err)
|
||||
streamErr := fmt.Errorf("stream error when reading response body, may be caused by closed connection. Please retry. Original error: %w", err)
|
||||
return Result{
|
||||
err: streamErr,
|
||||
}
|
||||
default:
|
||||
klog.Errorf("Unexpected error when reading response body: %v", err)
|
||||
unexpectedErr := fmt.Errorf("unexpected error when reading response body. Please retry. Original error: %v", err)
|
||||
unexpectedErr := fmt.Errorf("unexpected error when reading response body. Please retry. Original error: %w", err)
|
||||
return Result{
|
||||
err: unexpectedErr,
|
||||
}
|
||||
@@ -1180,19 +1254,6 @@ func isTextResponse(resp *http.Response) bool {
|
||||
return strings.HasPrefix(media, "text/")
|
||||
}
|
||||
|
||||
// checkWait returns true along with a number of seconds if the server instructed us to wait
|
||||
// before retrying.
|
||||
func checkWait(resp *http.Response) (int, bool) {
|
||||
switch r := resp.StatusCode; {
|
||||
// any 500 error code and 429 can trigger a wait
|
||||
case r == http.StatusTooManyRequests, r >= 500:
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
i, ok := retryAfterSeconds(resp)
|
||||
return i, ok
|
||||
}
|
||||
|
||||
// retryAfterSeconds returns the value of the Retry-After header and true, or 0 and false if
|
||||
// the header was missing or not a valid number.
|
||||
func retryAfterSeconds(resp *http.Response) (int, bool) {
|
||||
|
||||
232
vendor/k8s.io/client-go/rest/with_retry.go
generated
vendored
Normal file
232
vendor/k8s.io/client-go/rest/with_retry.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
Copyright 2021 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// IsRetryableErrorFunc allows the client to provide its own function
|
||||
// that determines whether the specified err from the server is retryable.
|
||||
//
|
||||
// request: the original request sent to the server
|
||||
// err: the server sent this error to us
|
||||
//
|
||||
// The function returns true if the error is retryable and the request
|
||||
// can be retried, otherwise it returns false.
|
||||
// We have four mode of communications - 'Stream', 'Watch', 'Do' and 'DoRaw', this
|
||||
// function allows us to customize the retryability aspect of each.
|
||||
type IsRetryableErrorFunc func(request *http.Request, err error) bool
|
||||
|
||||
func (r IsRetryableErrorFunc) IsErrorRetryable(request *http.Request, err error) bool {
|
||||
return r(request, err)
|
||||
}
|
||||
|
||||
var neverRetryError = IsRetryableErrorFunc(func(_ *http.Request, _ error) bool {
|
||||
return false
|
||||
})
|
||||
|
||||
// WithRetry allows the client to retry a request up to a certain number of times
|
||||
// Note that WithRetry is not safe for concurrent use by multiple
|
||||
// goroutines without additional locking or coordination.
|
||||
type WithRetry interface {
|
||||
// SetMaxRetries makes the request use the specified integer as a ceiling
|
||||
// for retries upon receiving a 429 status code and the "Retry-After" header
|
||||
// in the response.
|
||||
// A zero maxRetries should prevent from doing any retry and return immediately.
|
||||
SetMaxRetries(maxRetries int)
|
||||
|
||||
// NextRetry advances the retry counter appropriately and returns true if the
|
||||
// request should be retried, otherwise it returns false if:
|
||||
// - we have already reached the maximum retry threshold.
|
||||
// - the error does not fall into the retryable category.
|
||||
// - the server has not sent us a 429, or 5xx status code and the
|
||||
// 'Retry-After' response header is not set with a value.
|
||||
//
|
||||
// if retry is set to true, retryAfter will contain the information
|
||||
// regarding the next retry.
|
||||
//
|
||||
// request: the original request sent to the server
|
||||
// resp: the response sent from the server, it is set if err is nil
|
||||
// err: the server sent this error to us, if err is set then resp is nil.
|
||||
// f: a IsRetryableErrorFunc function provided by the client that determines
|
||||
// if the err sent by the server is retryable.
|
||||
NextRetry(req *http.Request, resp *http.Response, err error, f IsRetryableErrorFunc) (*RetryAfter, bool)
|
||||
|
||||
// BeforeNextRetry is responsible for carrying out operations that need
|
||||
// to be completed before the next retry is initiated:
|
||||
// - if the request context is already canceled there is no need to
|
||||
// retry, the function will return ctx.Err().
|
||||
// - we need to seek to the beginning of the request body before we
|
||||
// initiate the next retry, the function should return an error if
|
||||
// it fails to do so.
|
||||
// - we should wait the number of seconds the server has asked us to
|
||||
// in the 'Retry-After' response header.
|
||||
//
|
||||
// If BeforeNextRetry returns an error the client should abort the retry,
|
||||
// otherwise it is safe to initiate the next retry.
|
||||
BeforeNextRetry(ctx context.Context, backoff BackoffManager, retryAfter *RetryAfter, url string, body io.Reader) error
|
||||
}
|
||||
|
||||
// RetryAfter holds information associated with the next retry.
|
||||
type RetryAfter struct {
|
||||
// Wait is the duration the server has asked us to wait before
|
||||
// the next retry is initiated.
|
||||
// This is the value of the 'Retry-After' response header in seconds.
|
||||
Wait time.Duration
|
||||
|
||||
// Attempt is the Nth attempt after which we have received a retryable
|
||||
// error or a 'Retry-After' response header from the server.
|
||||
Attempt int
|
||||
|
||||
// Reason describes why we are retrying the request
|
||||
Reason string
|
||||
}
|
||||
|
||||
type withRetry struct {
|
||||
maxRetries int
|
||||
attempts int
|
||||
}
|
||||
|
||||
func (r *withRetry) SetMaxRetries(maxRetries int) {
|
||||
if maxRetries < 0 {
|
||||
maxRetries = 0
|
||||
}
|
||||
r.maxRetries = maxRetries
|
||||
}
|
||||
|
||||
func (r *withRetry) NextRetry(req *http.Request, resp *http.Response, err error, f IsRetryableErrorFunc) (*RetryAfter, bool) {
|
||||
if req == nil || (resp == nil && err == nil) {
|
||||
// bad input, we do nothing.
|
||||
return nil, false
|
||||
}
|
||||
|
||||
r.attempts++
|
||||
retryAfter := &RetryAfter{Attempt: r.attempts}
|
||||
if r.attempts > r.maxRetries {
|
||||
return retryAfter, false
|
||||
}
|
||||
|
||||
// if the server returned an error, it takes precedence over the http response.
|
||||
var errIsRetryable bool
|
||||
if f != nil && err != nil && f.IsErrorRetryable(req, err) {
|
||||
errIsRetryable = true
|
||||
// we have a retryable error, for which we will create an
|
||||
// artificial "Retry-After" response.
|
||||
resp = retryAfterResponse()
|
||||
}
|
||||
if err != nil && !errIsRetryable {
|
||||
return retryAfter, false
|
||||
}
|
||||
|
||||
// if we are here, we have either a or b:
|
||||
// a: we have a retryable error, for which we already
|
||||
// have an artificial "Retry-After" response.
|
||||
// b: we have a response from the server for which we
|
||||
// need to check if it is retryable
|
||||
seconds, wait := checkWait(resp)
|
||||
if !wait {
|
||||
return retryAfter, false
|
||||
}
|
||||
|
||||
retryAfter.Wait = time.Duration(seconds) * time.Second
|
||||
retryAfter.Reason = getRetryReason(r.attempts, seconds, resp, err)
|
||||
return retryAfter, true
|
||||
}
|
||||
|
||||
func (r *withRetry) BeforeNextRetry(ctx context.Context, backoff BackoffManager, retryAfter *RetryAfter, url string, body io.Reader) error {
|
||||
// Ensure the response body is fully read and closed before
|
||||
// we reconnect, so that we reuse the same TCP connection.
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
if seeker, ok := body.(io.Seeker); ok && body != nil {
|
||||
if _, err := seeker.Seek(0, 0); err != nil {
|
||||
return fmt.Errorf("can't Seek() back to beginning of body for %T", r)
|
||||
}
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", retryAfter.Wait, retryAfter.Attempt, url)
|
||||
if backoff != nil {
|
||||
backoff.Sleep(retryAfter.Wait)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkWait returns true along with a number of seconds if
|
||||
// the server instructed us to wait before retrying.
|
||||
func checkWait(resp *http.Response) (int, bool) {
|
||||
switch r := resp.StatusCode; {
|
||||
// any 500 error code and 429 can trigger a wait
|
||||
case r == http.StatusTooManyRequests, r >= 500:
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
i, ok := retryAfterSeconds(resp)
|
||||
return i, ok
|
||||
}
|
||||
|
||||
func getRetryReason(retries, seconds int, resp *http.Response, err error) string {
|
||||
// priority and fairness sets the UID of the FlowSchema
|
||||
// associated with a request in the following response Header.
|
||||
const responseHeaderMatchedFlowSchemaUID = "X-Kubernetes-PF-FlowSchema-UID"
|
||||
|
||||
message := fmt.Sprintf("retries: %d, retry-after: %ds", retries, seconds)
|
||||
|
||||
switch {
|
||||
case resp.StatusCode == http.StatusTooManyRequests:
|
||||
// it is server-side throttling from priority and fairness
|
||||
flowSchemaUID := resp.Header.Get(responseHeaderMatchedFlowSchemaUID)
|
||||
return fmt.Sprintf("%s - retry-reason: due to server-side throttling, FlowSchema UID: %q", message, flowSchemaUID)
|
||||
case err != nil:
|
||||
// it's a retryable error
|
||||
return fmt.Sprintf("%s - retry-reason: due to retryable error, error: %v", message, err)
|
||||
default:
|
||||
return fmt.Sprintf("%s - retry-reason: %d", message, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func readAndCloseResponseBody(resp *http.Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure the response body is fully read and closed
|
||||
// before we reconnect, so that we reuse the same TCP
|
||||
// connection.
|
||||
const maxBodySlurpSize = 2 << 10
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.ContentLength <= maxBodySlurpSize {
|
||||
io.Copy(ioutil.Discard, &io.LimitedReader{R: resp.Body, N: maxBodySlurpSize})
|
||||
}
|
||||
}
|
||||
|
||||
func retryAfterResponse() *http.Response {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{"Retry-After": []string{"1"}},
|
||||
}
|
||||
}
|
||||
49
vendor/k8s.io/client-go/tools/clientcmd/api/types.go
generated
vendored
49
vendor/k8s.io/client-go/tools/clientcmd/api/types.go
generated
vendored
@@ -245,6 +245,33 @@ type ExecConfig struct {
|
||||
// to be stored directly in the kubeconfig.
|
||||
// +k8s:conversion-gen=false
|
||||
Config runtime.Object
|
||||
|
||||
// InteractiveMode determines this plugin's relationship with standard input. Valid
|
||||
// values are "Never" (this exec plugin never uses standard input), "IfAvailable" (this
|
||||
// exec plugin wants to use standard input if it is available), or "Always" (this exec
|
||||
// plugin requires standard input to function). See ExecInteractiveMode values for more
|
||||
// details.
|
||||
//
|
||||
// If APIVersion is client.authentication.k8s.io/v1alpha1 or
|
||||
// client.authentication.k8s.io/v1beta1, then this field is optional and defaults
|
||||
// to "IfAvailable" when unset. Otherwise, this field is required.
|
||||
// +optional
|
||||
InteractiveMode ExecInteractiveMode
|
||||
|
||||
// StdinUnavailable indicates whether the exec authenticator can pass standard
|
||||
// input through to this exec plugin. For example, a higher level entity might be using
|
||||
// standard input for something else and therefore it would not be safe for the exec
|
||||
// plugin to use standard input. This is kept here in order to keep all of the exec configuration
|
||||
// together, but it is never serialized.
|
||||
// +k8s:conversion-gen=false
|
||||
StdinUnavailable bool
|
||||
|
||||
// StdinUnavailableMessage is an optional message to be displayed when the exec authenticator
|
||||
// cannot successfully run this exec plugin because it needs to use standard input and
|
||||
// StdinUnavailable is true. For example, a process that is already using standard input to
|
||||
// read user instructions might set this to "used by my-program to read user instructions".
|
||||
// +k8s:conversion-gen=false
|
||||
StdinUnavailableMessage string
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = new(ExecConfig)
|
||||
@@ -271,7 +298,7 @@ func (c ExecConfig) String() string {
|
||||
if c.Config != nil {
|
||||
config = "runtime.Object(--- REDACTED ---)"
|
||||
}
|
||||
return fmt.Sprintf("api.ExecConfig{Command: %q, Args: %#v, Env: %s, APIVersion: %q, ProvideClusterInfo: %t, Config: %s}", c.Command, args, env, c.APIVersion, c.ProvideClusterInfo, config)
|
||||
return fmt.Sprintf("api.ExecConfig{Command: %q, Args: %#v, Env: %s, APIVersion: %q, ProvideClusterInfo: %t, Config: %s, StdinUnavailable: %t}", c.Command, args, env, c.APIVersion, c.ProvideClusterInfo, config, c.StdinUnavailable)
|
||||
}
|
||||
|
||||
// ExecEnvVar is used for setting environment variables when executing an exec-based
|
||||
@@ -281,6 +308,26 @@ type ExecEnvVar struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ExecInteractiveMode is a string that describes an exec plugin's relationship with standard input.
|
||||
type ExecInteractiveMode string
|
||||
|
||||
const (
|
||||
// NeverExecInteractiveMode declares that this exec plugin never needs to use standard
|
||||
// input, and therefore the exec plugin will be run regardless of whether standard input is
|
||||
// available for user input.
|
||||
NeverExecInteractiveMode ExecInteractiveMode = "Never"
|
||||
// IfAvailableExecInteractiveMode declares that this exec plugin would like to use standard input
|
||||
// if it is available, but can still operate if standard input is not available. Therefore, the
|
||||
// exec plugin will be run regardless of whether stdin is available for user input. If standard
|
||||
// input is available for user input, then it will be provided to this exec plugin.
|
||||
IfAvailableExecInteractiveMode ExecInteractiveMode = "IfAvailable"
|
||||
// AlwaysExecInteractiveMode declares that this exec plugin requires standard input in order to
|
||||
// run, and therefore the exec plugin will only be run if standard input is available for user
|
||||
// input. If standard input is not available for user input, then the exec plugin will not be run
|
||||
// and an error will be returned by the exec plugin runner.
|
||||
AlwaysExecInteractiveMode ExecInteractiveMode = "Always"
|
||||
)
|
||||
|
||||
// NewConfig is a convenience function that returns a new Config object with non-nil maps
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
|
||||
26
vendor/k8s.io/client-go/tools/metrics/metrics.go
generated
vendored
26
vendor/k8s.io/client-go/tools/metrics/metrics.go
generated
vendored
@@ -19,6 +19,7 @@ limitations under the License.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -38,12 +39,18 @@ type ExpiryMetric interface {
|
||||
|
||||
// LatencyMetric observes client latency partitioned by verb and url.
|
||||
type LatencyMetric interface {
|
||||
Observe(verb string, u url.URL, latency time.Duration)
|
||||
Observe(ctx context.Context, verb string, u url.URL, latency time.Duration)
|
||||
}
|
||||
|
||||
// ResultMetric counts response codes partitioned by method and host.
|
||||
type ResultMetric interface {
|
||||
Increment(code string, method string, host string)
|
||||
Increment(ctx context.Context, code string, method string, host string)
|
||||
}
|
||||
|
||||
// CallsMetric counts calls that take place for a specific exec plugin.
|
||||
type CallsMetric interface {
|
||||
// Increment increments a counter per exitCode and callStatus.
|
||||
Increment(exitCode int, callStatus string)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -57,6 +64,9 @@ var (
|
||||
RateLimiterLatency LatencyMetric = noopLatency{}
|
||||
// RequestResult is the result metric that rest clients will update.
|
||||
RequestResult ResultMetric = noopResult{}
|
||||
// ExecPluginCalls is the number of calls made to an exec plugin, partitioned by
|
||||
// exit code and call status.
|
||||
ExecPluginCalls CallsMetric = noopCalls{}
|
||||
)
|
||||
|
||||
// RegisterOpts contains all the metrics to register. Metrics may be nil.
|
||||
@@ -66,6 +76,7 @@ type RegisterOpts struct {
|
||||
RequestLatency LatencyMetric
|
||||
RateLimiterLatency LatencyMetric
|
||||
RequestResult ResultMetric
|
||||
ExecPluginCalls CallsMetric
|
||||
}
|
||||
|
||||
// Register registers metrics for the rest client to use. This can
|
||||
@@ -87,6 +98,9 @@ func Register(opts RegisterOpts) {
|
||||
if opts.RequestResult != nil {
|
||||
RequestResult = opts.RequestResult
|
||||
}
|
||||
if opts.ExecPluginCalls != nil {
|
||||
ExecPluginCalls = opts.ExecPluginCalls
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -100,8 +114,12 @@ func (noopExpiry) Set(*time.Time) {}
|
||||
|
||||
type noopLatency struct{}
|
||||
|
||||
func (noopLatency) Observe(string, url.URL, time.Duration) {}
|
||||
func (noopLatency) Observe(context.Context, string, url.URL, time.Duration) {}
|
||||
|
||||
type noopResult struct{}
|
||||
|
||||
func (noopResult) Increment(string, string, string) {}
|
||||
func (noopResult) Increment(context.Context, string, string, string) {}
|
||||
|
||||
type noopCalls struct{}
|
||||
|
||||
func (noopCalls) Increment(int, string) {}
|
||||
|
||||
5
vendor/k8s.io/client-go/tools/remotecommand/v2.go
generated
vendored
5
vendor/k8s.io/client-go/tools/remotecommand/v2.go
generated
vendored
@@ -142,6 +142,10 @@ func (p *streamProtocolV2) copyStdout(wg *sync.WaitGroup) {
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
defer wg.Done()
|
||||
// make sure, packet in queue can be consumed.
|
||||
// block in queue may lead to deadlock in conn.server
|
||||
// issue: https://github.com/kubernetes/kubernetes/issues/96339
|
||||
defer io.Copy(ioutil.Discard, p.remoteStdout)
|
||||
|
||||
if _, err := io.Copy(p.Stdout, p.remoteStdout); err != nil {
|
||||
runtime.HandleError(err)
|
||||
@@ -158,6 +162,7 @@ func (p *streamProtocolV2) copyStderr(wg *sync.WaitGroup) {
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
defer wg.Done()
|
||||
defer io.Copy(ioutil.Discard, p.remoteStderr)
|
||||
|
||||
if _, err := io.Copy(p.Stderr, p.remoteStderr); err != nil {
|
||||
runtime.HandleError(err)
|
||||
|
||||
61
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
61
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
@@ -23,9 +23,9 @@ import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// HTTPWrappersForConfig wraps a round tripper with any relevant layered
|
||||
@@ -68,13 +68,13 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip
|
||||
func DebugWrappers(rt http.RoundTripper) http.RoundTripper {
|
||||
switch {
|
||||
case bool(klog.V(9).Enabled()):
|
||||
rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders)
|
||||
rt = NewDebuggingRoundTripper(rt, DebugCurlCommand, DebugURLTiming, DebugResponseHeaders)
|
||||
case bool(klog.V(8).Enabled()):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders)
|
||||
rt = NewDebuggingRoundTripper(rt, DebugJustURL, DebugRequestHeaders, DebugResponseStatus, DebugResponseHeaders)
|
||||
case bool(klog.V(7).Enabled()):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus)
|
||||
rt = NewDebuggingRoundTripper(rt, DebugJustURL, DebugRequestHeaders, DebugResponseStatus)
|
||||
case bool(klog.V(6).Enabled()):
|
||||
rt = newDebuggingRoundTripper(rt, debugURLTiming)
|
||||
rt = NewDebuggingRoundTripper(rt, DebugURLTiming)
|
||||
}
|
||||
|
||||
return rt
|
||||
@@ -346,32 +346,42 @@ func (r *requestInfo) toCurl() string {
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("curl -k -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL)
|
||||
return fmt.Sprintf("curl -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL)
|
||||
}
|
||||
|
||||
// debuggingRoundTripper will display information about the requests passing
|
||||
// through it based on what is configured
|
||||
type debuggingRoundTripper struct {
|
||||
delegatedRoundTripper http.RoundTripper
|
||||
|
||||
levels map[debugLevel]bool
|
||||
levels map[DebugLevel]bool
|
||||
}
|
||||
|
||||
type debugLevel int
|
||||
// DebugLevel is used to enable debugging of certain
|
||||
// HTTP requests and responses fields via the debuggingRoundTripper.
|
||||
type DebugLevel int
|
||||
|
||||
const (
|
||||
debugJustURL debugLevel = iota
|
||||
debugURLTiming
|
||||
debugCurlCommand
|
||||
debugRequestHeaders
|
||||
debugResponseStatus
|
||||
debugResponseHeaders
|
||||
// DebugJustURL will add to the debug output HTTP requests method and url.
|
||||
DebugJustURL DebugLevel = iota
|
||||
// DebugURLTiming will add to the debug output the duration of HTTP requests.
|
||||
DebugURLTiming
|
||||
// DebugCurlCommand will add to the debug output the curl command equivalent to the
|
||||
// HTTP request.
|
||||
DebugCurlCommand
|
||||
// DebugRequestHeaders will add to the debug output the HTTP requests headers.
|
||||
DebugRequestHeaders
|
||||
// DebugResponseStatus will add to the debug output the HTTP response status.
|
||||
DebugResponseStatus
|
||||
// DebugResponseHeaders will add to the debug output the HTTP response headers.
|
||||
DebugResponseHeaders
|
||||
)
|
||||
|
||||
func newDebuggingRoundTripper(rt http.RoundTripper, levels ...debugLevel) *debuggingRoundTripper {
|
||||
// NewDebuggingRoundTripper allows to display in the logs output debug information
|
||||
// on the API requests performed by the client.
|
||||
func NewDebuggingRoundTripper(rt http.RoundTripper, levels ...DebugLevel) http.RoundTripper {
|
||||
drt := &debuggingRoundTripper{
|
||||
delegatedRoundTripper: rt,
|
||||
levels: make(map[debugLevel]bool, len(levels)),
|
||||
levels: make(map[DebugLevel]bool, len(levels)),
|
||||
}
|
||||
for _, v := range levels {
|
||||
drt.levels[v] = true
|
||||
@@ -418,15 +428,14 @@ func maskValue(key string, value string) string {
|
||||
func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
reqInfo := newRequestInfo(req)
|
||||
|
||||
if rt.levels[debugJustURL] {
|
||||
if rt.levels[DebugJustURL] {
|
||||
klog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL)
|
||||
}
|
||||
if rt.levels[debugCurlCommand] {
|
||||
if rt.levels[DebugCurlCommand] {
|
||||
klog.Infof("%s", reqInfo.toCurl())
|
||||
|
||||
}
|
||||
if rt.levels[debugRequestHeaders] {
|
||||
klog.Infof("Request Headers:")
|
||||
if rt.levels[DebugRequestHeaders] {
|
||||
klog.Info("Request Headers:")
|
||||
for key, values := range reqInfo.RequestHeaders {
|
||||
for _, value := range values {
|
||||
value = maskValue(key, value)
|
||||
@@ -441,14 +450,14 @@ func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, e
|
||||
|
||||
reqInfo.complete(response, err)
|
||||
|
||||
if rt.levels[debugURLTiming] {
|
||||
if rt.levels[DebugURLTiming] {
|
||||
klog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseStatus] {
|
||||
if rt.levels[DebugResponseStatus] {
|
||||
klog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseHeaders] {
|
||||
klog.Infof("Response Headers:")
|
||||
if rt.levels[DebugResponseHeaders] {
|
||||
klog.Info("Response Headers:")
|
||||
for key, values := range reqInfo.ResponseHeaders {
|
||||
for _, value := range values {
|
||||
klog.Infof(" %s: %s", key, value)
|
||||
|
||||
9
vendor/k8s.io/client-go/transport/spdy/spdy.go
generated
vendored
9
vendor/k8s.io/client-go/transport/spdy/spdy.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
|
||||
@@ -42,7 +43,13 @@ func RoundTripperFor(config *restclient.Config) (http.RoundTripper, Upgrader, er
|
||||
if config.Proxy != nil {
|
||||
proxy = config.Proxy
|
||||
}
|
||||
upgradeRoundTripper := spdy.NewRoundTripperWithProxy(tlsConfig, true, false, proxy)
|
||||
upgradeRoundTripper := spdy.NewRoundTripperWithConfig(spdy.RoundTripperConfig{
|
||||
TLS: tlsConfig,
|
||||
FollowRedirects: true,
|
||||
RequireSameHostRedirects: false,
|
||||
Proxier: proxy,
|
||||
PingPeriod: time.Second * 5,
|
||||
})
|
||||
wrapper, err := restclient.HTTPWrappersForConfig(config, upgradeRoundTripper)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
56
vendor/k8s.io/client-go/transport/token_source.go
generated
vendored
56
vendor/k8s.io/client-go/transport/token_source.go
generated
vendored
@@ -43,9 +43,29 @@ func TokenSourceWrapTransport(ts oauth2.TokenSource) func(http.RoundTripper) htt
|
||||
}
|
||||
}
|
||||
|
||||
// NewCachedFileTokenSource returns a oauth2.TokenSource reads a token from a
|
||||
// file at a specified path and periodically reloads it.
|
||||
func NewCachedFileTokenSource(path string) oauth2.TokenSource {
|
||||
type ResettableTokenSource interface {
|
||||
oauth2.TokenSource
|
||||
ResetTokenOlderThan(time.Time)
|
||||
}
|
||||
|
||||
// ResettableTokenSourceWrapTransport returns a WrapTransport that injects bearer tokens
|
||||
// authentication from an ResettableTokenSource.
|
||||
func ResettableTokenSourceWrapTransport(ts ResettableTokenSource) func(http.RoundTripper) http.RoundTripper {
|
||||
return func(rt http.RoundTripper) http.RoundTripper {
|
||||
return &tokenSourceTransport{
|
||||
base: rt,
|
||||
ort: &oauth2.Transport{
|
||||
Source: ts,
|
||||
Base: rt,
|
||||
},
|
||||
src: ts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCachedFileTokenSource returns a resettable token source which reads a
|
||||
// token from a file at a specified path and periodically reloads it.
|
||||
func NewCachedFileTokenSource(path string) *cachingTokenSource {
|
||||
return &cachingTokenSource{
|
||||
now: time.Now,
|
||||
leeway: 10 * time.Second,
|
||||
@@ -60,9 +80,9 @@ func NewCachedFileTokenSource(path string) oauth2.TokenSource {
|
||||
}
|
||||
}
|
||||
|
||||
// NewCachedTokenSource returns a oauth2.TokenSource reads a token from a
|
||||
// designed TokenSource. The ts would provide the source of token.
|
||||
func NewCachedTokenSource(ts oauth2.TokenSource) oauth2.TokenSource {
|
||||
// NewCachedTokenSource returns resettable token source with caching. It reads
|
||||
// a token from a designed TokenSource if not in cache or expired.
|
||||
func NewCachedTokenSource(ts oauth2.TokenSource) *cachingTokenSource {
|
||||
return &cachingTokenSource{
|
||||
now: time.Now,
|
||||
base: ts,
|
||||
@@ -72,6 +92,7 @@ func NewCachedTokenSource(ts oauth2.TokenSource) oauth2.TokenSource {
|
||||
type tokenSourceTransport struct {
|
||||
base http.RoundTripper
|
||||
ort http.RoundTripper
|
||||
src ResettableTokenSource
|
||||
}
|
||||
|
||||
func (tst *tokenSourceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
@@ -79,7 +100,15 @@ func (tst *tokenSourceTransport) RoundTrip(req *http.Request) (*http.Response, e
|
||||
if req.Header.Get("Authorization") != "" {
|
||||
return tst.base.RoundTrip(req)
|
||||
}
|
||||
return tst.ort.RoundTrip(req)
|
||||
// record time before RoundTrip to make sure newly acquired Unauthorized
|
||||
// token would not be reset. Another request from user is required to reset
|
||||
// and proceed.
|
||||
start := time.Now()
|
||||
resp, err := tst.ort.RoundTrip(req)
|
||||
if err == nil && resp != nil && resp.StatusCode == 401 && tst.src != nil {
|
||||
tst.src.ResetTokenOlderThan(start)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (tst *tokenSourceTransport) CancelRequest(req *http.Request) {
|
||||
@@ -119,13 +148,12 @@ type cachingTokenSource struct {
|
||||
|
||||
sync.RWMutex
|
||||
tok *oauth2.Token
|
||||
t time.Time
|
||||
|
||||
// for testing
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
var _ = oauth2.TokenSource(&cachingTokenSource{})
|
||||
|
||||
func (ts *cachingTokenSource) Token() (*oauth2.Token, error) {
|
||||
now := ts.now()
|
||||
// fast path
|
||||
@@ -153,6 +181,16 @@ func (ts *cachingTokenSource) Token() (*oauth2.Token, error) {
|
||||
return ts.tok, nil
|
||||
}
|
||||
|
||||
ts.t = ts.now()
|
||||
ts.tok = tok
|
||||
return tok, nil
|
||||
}
|
||||
|
||||
func (ts *cachingTokenSource) ResetTokenOlderThan(t time.Time) {
|
||||
ts.Lock()
|
||||
defer ts.Unlock()
|
||||
if ts.t.Before(t) {
|
||||
ts.tok = nil
|
||||
ts.t = time.Time{}
|
||||
}
|
||||
}
|
||||
|
||||
40
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
40
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -79,7 +80,11 @@ func TLSConfigFor(c *Config) (*tls.Config, error) {
|
||||
}
|
||||
|
||||
if c.HasCA() {
|
||||
tlsConfig.RootCAs = rootCertPool(c.TLS.CAData)
|
||||
rootCAs, err := rootCertPool(c.TLS.CAData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load root certificates: %w", err)
|
||||
}
|
||||
tlsConfig.RootCAs = rootCAs
|
||||
}
|
||||
|
||||
var staticCert *tls.Certificate
|
||||
@@ -176,18 +181,41 @@ func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
|
||||
|
||||
// rootCertPool returns nil if caData is empty. When passed along, this will mean "use system CAs".
|
||||
// When caData is not empty, it will be the ONLY information used in the CertPool.
|
||||
func rootCertPool(caData []byte) *x509.CertPool {
|
||||
func rootCertPool(caData []byte) (*x509.CertPool, error) {
|
||||
// What we really want is a copy of x509.systemRootsPool, but that isn't exposed. It's difficult to build (see the go
|
||||
// code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values
|
||||
// It doesn't allow trusting either/or, but hopefully that won't be an issue
|
||||
if len(caData) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if we have caData, use it
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AppendCertsFromPEM(caData)
|
||||
return certPool
|
||||
if ok := certPool.AppendCertsFromPEM(caData); !ok {
|
||||
return nil, createErrorParsingCAData(caData)
|
||||
}
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
// createErrorParsingCAData ALWAYS returns an error. We call it because know we failed to AppendCertsFromPEM
|
||||
// but we don't know the specific error because that API is just true/false
|
||||
func createErrorParsingCAData(pemCerts []byte) error {
|
||||
for len(pemCerts) > 0 {
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
return fmt.Errorf("unable to parse bytes as PEM block")
|
||||
}
|
||||
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
|
||||
return fmt.Errorf("failed to parse certificate: %w", err)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no valid certificate authority data seen")
|
||||
}
|
||||
|
||||
// WrapperFunc wraps an http.RoundTripper when a new transport
|
||||
@@ -269,7 +297,7 @@ type certificateCacheEntry struct {
|
||||
|
||||
// isStale returns true when this cache entry is too old to be usable
|
||||
func (c *certificateCacheEntry) isStale() bool {
|
||||
return time.Now().Sub(c.birth) > time.Second
|
||||
return time.Since(c.birth) > time.Second
|
||||
}
|
||||
|
||||
func newCertificateCacheEntry(certFile, keyFile string) certificateCacheEntry {
|
||||
|
||||
1
vendor/k8s.io/client-go/util/cert/cert.go
generated
vendored
1
vendor/k8s.io/client-go/util/cert/cert.go
generated
vendored
@@ -62,6 +62,7 @@ func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, erro
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: cfg.Organization,
|
||||
},
|
||||
DNSNames: []string{cfg.CommonName},
|
||||
NotBefore: now.UTC(),
|
||||
NotAfter: now.Add(duration365d * 10).UTC(),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
|
||||
88
vendor/k8s.io/client-go/util/connrotation/connrotation.go
generated
vendored
88
vendor/k8s.io/client-go/util/connrotation/connrotation.go
generated
vendored
@@ -33,18 +33,40 @@ type DialFunc func(ctx context.Context, network, address string) (net.Conn, erro
|
||||
// Dialer opens connections through Dial and tracks them.
|
||||
type Dialer struct {
|
||||
dial DialFunc
|
||||
*ConnectionTracker
|
||||
}
|
||||
|
||||
// NewDialer creates a new Dialer instance.
|
||||
// Equivalent to NewDialerWithTracker(dial, nil).
|
||||
func NewDialer(dial DialFunc) *Dialer {
|
||||
return NewDialerWithTracker(dial, nil)
|
||||
}
|
||||
|
||||
// NewDialerWithTracker creates a new Dialer instance.
|
||||
//
|
||||
// If dial is not nil, it will be used to create new underlying connections.
|
||||
// Otherwise net.DialContext is used.
|
||||
// If tracker is not nil, it will be used to track new underlying connections.
|
||||
// Otherwise NewConnectionTracker() is used.
|
||||
func NewDialerWithTracker(dial DialFunc, tracker *ConnectionTracker) *Dialer {
|
||||
if tracker == nil {
|
||||
tracker = NewConnectionTracker()
|
||||
}
|
||||
return &Dialer{
|
||||
dial: dial,
|
||||
ConnectionTracker: tracker,
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectionTracker keeps track of opened connections
|
||||
type ConnectionTracker struct {
|
||||
mu sync.Mutex
|
||||
conns map[*closableConn]struct{}
|
||||
}
|
||||
|
||||
// NewDialer creates a new Dialer instance.
|
||||
//
|
||||
// If dial is not nil, it will be used to create new underlying connections.
|
||||
// Otherwise net.DialContext is used.
|
||||
func NewDialer(dial DialFunc) *Dialer {
|
||||
return &Dialer{
|
||||
dial: dial,
|
||||
// NewConnectionTracker returns a connection tracker for use with NewDialerWithTracker
|
||||
func NewConnectionTracker() *ConnectionTracker {
|
||||
return &ConnectionTracker{
|
||||
conns: make(map[*closableConn]struct{}),
|
||||
}
|
||||
}
|
||||
@@ -52,17 +74,40 @@ func NewDialer(dial DialFunc) *Dialer {
|
||||
// CloseAll forcibly closes all tracked connections.
|
||||
//
|
||||
// Note: new connections may get created before CloseAll returns.
|
||||
func (d *Dialer) CloseAll() {
|
||||
d.mu.Lock()
|
||||
conns := d.conns
|
||||
d.conns = make(map[*closableConn]struct{})
|
||||
d.mu.Unlock()
|
||||
func (c *ConnectionTracker) CloseAll() {
|
||||
c.mu.Lock()
|
||||
conns := c.conns
|
||||
c.conns = make(map[*closableConn]struct{})
|
||||
c.mu.Unlock()
|
||||
|
||||
for conn := range conns {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Track adds the connection to the list of tracked connections,
|
||||
// and returns a wrapped copy of the connection that stops tracking the connection
|
||||
// when it is closed.
|
||||
func (c *ConnectionTracker) Track(conn net.Conn) net.Conn {
|
||||
closable := &closableConn{Conn: conn}
|
||||
|
||||
// When the connection is closed, remove it from the map. This will
|
||||
// be no-op if the connection isn't in the map, e.g. if CloseAll()
|
||||
// is called.
|
||||
closable.onClose = func() {
|
||||
c.mu.Lock()
|
||||
delete(c.conns, closable)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Start tracking the connection
|
||||
c.mu.Lock()
|
||||
c.conns[closable] = struct{}{}
|
||||
c.mu.Unlock()
|
||||
|
||||
return closable
|
||||
}
|
||||
|
||||
// Dial creates a new tracked connection.
|
||||
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
|
||||
return d.DialContext(context.Background(), network, address)
|
||||
@@ -74,24 +119,7 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
closable := &closableConn{Conn: conn}
|
||||
|
||||
// When the connection is closed, remove it from the map. This will
|
||||
// be no-op if the connection isn't in the map, e.g. if CloseAll()
|
||||
// is called.
|
||||
closable.onClose = func() {
|
||||
d.mu.Lock()
|
||||
delete(d.conns, closable)
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
// Start tracking the connection
|
||||
d.mu.Lock()
|
||||
d.conns[closable] = struct{}{}
|
||||
d.mu.Unlock()
|
||||
|
||||
return closable, nil
|
||||
return d.ConnectionTracker.Track(conn), nil
|
||||
}
|
||||
|
||||
type closableConn struct {
|
||||
|
||||
8
vendor/k8s.io/client-go/util/workqueue/queue.go
generated
vendored
8
vendor/k8s.io/client-go/util/workqueue/queue.go
generated
vendored
@@ -55,7 +55,13 @@ func newQueue(c clock.Clock, metrics queueMetrics, updatePeriod time.Duration) *
|
||||
metrics: metrics,
|
||||
unfinishedWorkUpdatePeriod: updatePeriod,
|
||||
}
|
||||
go t.updateUnfinishedWorkLoop()
|
||||
|
||||
// Don't start the goroutine for a type of noMetrics so we don't consume
|
||||
// resources unnecessarily
|
||||
if _, ok := metrics.(noMetrics); !ok {
|
||||
go t.updateUnfinishedWorkLoop()
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user