mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: update kubernetes to 1.30
updating kubernetes to 1.30 release Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
62ddcf715b
commit
e727bd351e
10
vendor/k8s.io/client-go/tools/cache/controller.go
generated
vendored
10
vendor/k8s.io/client-go/tools/cache/controller.go
generated
vendored
@ -336,6 +336,16 @@ func DeletionHandlingMetaNamespaceKeyFunc(obj interface{}) (string, error) {
|
||||
return MetaNamespaceKeyFunc(obj)
|
||||
}
|
||||
|
||||
// DeletionHandlingObjectToName checks for
|
||||
// DeletedFinalStateUnknown objects before calling
|
||||
// ObjectToName.
|
||||
func DeletionHandlingObjectToName(obj interface{}) (ObjectName, error) {
|
||||
if d, ok := obj.(DeletedFinalStateUnknown); ok {
|
||||
return ParseObjectName(d.Key)
|
||||
}
|
||||
return ObjectToName(obj)
|
||||
}
|
||||
|
||||
// NewInformer returns a Store and a controller for populating the store
|
||||
// while also providing event notifications. You should only used the returned
|
||||
// Store for Get/List operations; Add/Modify/Deletes will cause the event
|
||||
|
3
vendor/k8s.io/client-go/tools/cache/index.go
generated
vendored
3
vendor/k8s.io/client-go/tools/cache/index.go
generated
vendored
@ -50,8 +50,7 @@ type Indexer interface {
|
||||
// GetIndexers return the indexers
|
||||
GetIndexers() Indexers
|
||||
|
||||
// AddIndexers adds more indexers to this store. If you call this after you already have data
|
||||
// in the store, the results are undefined.
|
||||
// AddIndexers adds more indexers to this store. This supports adding indexes after the store already has items.
|
||||
AddIndexers(newIndexers Indexers) error
|
||||
}
|
||||
|
||||
|
18
vendor/k8s.io/client-go/tools/cache/reflector.go
generated
vendored
18
vendor/k8s.io/client-go/tools/cache/reflector.go
generated
vendored
@ -43,6 +43,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/clock"
|
||||
"k8s.io/utils/pointer"
|
||||
"k8s.io/utils/ptr"
|
||||
"k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
@ -107,7 +108,9 @@ type Reflector struct {
|
||||
// might result in an increased memory consumption of the APIServer.
|
||||
//
|
||||
// See https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/3157-watch-list#design-details
|
||||
UseWatchList bool
|
||||
//
|
||||
// TODO(#115478): Consider making reflector.UseWatchList a private field. Since we implemented "api streaming" on the etcd storage layer it should work.
|
||||
UseWatchList *bool
|
||||
}
|
||||
|
||||
// ResourceVersionUpdater is an interface that allows store implementation to
|
||||
@ -237,8 +240,12 @@ func NewReflectorWithOptions(lw ListerWatcher, expectedType interface{}, store S
|
||||
r.expectedGVK = getExpectedGVKFromObject(expectedType)
|
||||
}
|
||||
|
||||
if s := os.Getenv("ENABLE_CLIENT_GO_WATCH_LIST_ALPHA"); len(s) > 0 {
|
||||
r.UseWatchList = true
|
||||
// don't overwrite UseWatchList if already set
|
||||
// because the higher layers (e.g. storage/cacher) disabled it on purpose
|
||||
if r.UseWatchList == nil {
|
||||
if s := os.Getenv("ENABLE_CLIENT_GO_WATCH_LIST_ALPHA"); len(s) > 0 {
|
||||
r.UseWatchList = ptr.To(true)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
@ -325,9 +332,10 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
klog.V(3).Infof("Listing and watching %v from %s", r.typeDescription, r.name)
|
||||
var err error
|
||||
var w watch.Interface
|
||||
fallbackToList := !r.UseWatchList
|
||||
useWatchList := ptr.Deref(r.UseWatchList, false)
|
||||
fallbackToList := !useWatchList
|
||||
|
||||
if r.UseWatchList {
|
||||
if useWatchList {
|
||||
w, err = r.watchList(stopCh)
|
||||
if w == nil && err == nil {
|
||||
// stopCh was closed
|
||||
|
10
vendor/k8s.io/client-go/tools/cache/shared_informer.go
generated
vendored
10
vendor/k8s.io/client-go/tools/cache/shared_informer.go
generated
vendored
@ -31,6 +31,8 @@ import (
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
clientgofeaturegate "k8s.io/client-go/features"
|
||||
)
|
||||
|
||||
// SharedInformer provides eventually consistent linkage of its
|
||||
@ -409,6 +411,10 @@ func (v *dummyController) HasSynced() bool {
|
||||
}
|
||||
|
||||
func (v *dummyController) LastSyncResourceVersion() string {
|
||||
if clientgofeaturegate.FeatureGates().Enabled(clientgofeaturegate.InformerResourceVersion) {
|
||||
return v.informer.LastSyncResourceVersion()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -540,8 +546,8 @@ func (s *sharedIndexInformer) AddIndexers(indexers Indexers) error {
|
||||
s.startedLock.Lock()
|
||||
defer s.startedLock.Unlock()
|
||||
|
||||
if s.started {
|
||||
return fmt.Errorf("informer has already started")
|
||||
if s.stopped {
|
||||
return fmt.Errorf("indexer was not added because it has stopped already")
|
||||
}
|
||||
|
||||
return s.indexer.AddIndexers(indexers)
|
||||
|
108
vendor/k8s.io/client-go/tools/cache/thread_safe_store.go
generated
vendored
108
vendor/k8s.io/client-go/tools/cache/thread_safe_store.go
generated
vendored
@ -52,8 +52,7 @@ type ThreadSafeStore interface {
|
||||
ByIndex(indexName, indexedValue string) ([]interface{}, error)
|
||||
GetIndexers() Indexers
|
||||
|
||||
// AddIndexers adds more indexers to this store. If you call this after you already have data
|
||||
// in the store, the results are undefined.
|
||||
// AddIndexers adds more indexers to this store. This supports adding indexes after the store already has items.
|
||||
AddIndexers(newIndexers Indexers) error
|
||||
// Resync is a no-op and is deprecated
|
||||
Resync() error
|
||||
@ -135,50 +134,66 @@ func (i *storeIndex) addIndexers(newIndexers Indexers) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateSingleIndex modifies the objects location in the named index:
|
||||
// - for create you must provide only the newObj
|
||||
// - for update you must provide both the oldObj and the newObj
|
||||
// - for delete you must provide only the oldObj
|
||||
// updateSingleIndex must be called from a function that already has a lock on the cache
|
||||
func (i *storeIndex) updateSingleIndex(name string, oldObj interface{}, newObj interface{}, key string) {
|
||||
var oldIndexValues, indexValues []string
|
||||
indexFunc, ok := i.indexers[name]
|
||||
if !ok {
|
||||
// Should never happen. Caller is responsible for ensuring this exists, and should call with lock
|
||||
// held to avoid any races.
|
||||
panic(fmt.Errorf("indexer %q does not exist", name))
|
||||
}
|
||||
if oldObj != nil {
|
||||
var err error
|
||||
oldIndexValues, err = indexFunc(oldObj)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
|
||||
}
|
||||
} else {
|
||||
oldIndexValues = oldIndexValues[:0]
|
||||
}
|
||||
|
||||
if newObj != nil {
|
||||
var err error
|
||||
indexValues, err = indexFunc(newObj)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
|
||||
}
|
||||
} else {
|
||||
indexValues = indexValues[:0]
|
||||
}
|
||||
|
||||
index := i.indices[name]
|
||||
if index == nil {
|
||||
index = Index{}
|
||||
i.indices[name] = index
|
||||
}
|
||||
|
||||
if len(indexValues) == 1 && len(oldIndexValues) == 1 && indexValues[0] == oldIndexValues[0] {
|
||||
// We optimize for the most common case where indexFunc returns a single value which has not been changed
|
||||
return
|
||||
}
|
||||
|
||||
for _, value := range oldIndexValues {
|
||||
i.deleteKeyFromIndex(key, value, index)
|
||||
}
|
||||
for _, value := range indexValues {
|
||||
i.addKeyToIndex(key, value, index)
|
||||
}
|
||||
}
|
||||
|
||||
// updateIndices modifies the objects location in the managed indexes:
|
||||
// - for create you must provide only the newObj
|
||||
// - for update you must provide both the oldObj and the newObj
|
||||
// - for delete you must provide only the oldObj
|
||||
// updateIndices must be called from a function that already has a lock on the cache
|
||||
func (i *storeIndex) updateIndices(oldObj interface{}, newObj interface{}, key string) {
|
||||
var oldIndexValues, indexValues []string
|
||||
var err error
|
||||
for name, indexFunc := range i.indexers {
|
||||
if oldObj != nil {
|
||||
oldIndexValues, err = indexFunc(oldObj)
|
||||
} else {
|
||||
oldIndexValues = oldIndexValues[:0]
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
|
||||
}
|
||||
|
||||
if newObj != nil {
|
||||
indexValues, err = indexFunc(newObj)
|
||||
} else {
|
||||
indexValues = indexValues[:0]
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
|
||||
}
|
||||
|
||||
index := i.indices[name]
|
||||
if index == nil {
|
||||
index = Index{}
|
||||
i.indices[name] = index
|
||||
}
|
||||
|
||||
if len(indexValues) == 1 && len(oldIndexValues) == 1 && indexValues[0] == oldIndexValues[0] {
|
||||
// We optimize for the most common case where indexFunc returns a single value which has not been changed
|
||||
continue
|
||||
}
|
||||
|
||||
for _, value := range oldIndexValues {
|
||||
i.deleteKeyFromIndex(key, value, index)
|
||||
}
|
||||
for _, value := range indexValues {
|
||||
i.addKeyToIndex(key, value, index)
|
||||
}
|
||||
for name := range i.indexers {
|
||||
i.updateSingleIndex(name, oldObj, newObj, key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,11 +354,18 @@ func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if len(c.items) > 0 {
|
||||
return fmt.Errorf("cannot add indexers to running index")
|
||||
if err := c.index.addIndexers(newIndexers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.index.addIndexers(newIndexers)
|
||||
// If there are already items, index them
|
||||
for key, item := range c.items {
|
||||
for name := range newIndexers {
|
||||
c.index.updateSingleIndex(name, nil, item, key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *threadSafeMap) Resync() error {
|
||||
|
2
vendor/k8s.io/client-go/tools/clientcmd/api/doc.go
generated
vendored
2
vendor/k8s.io/client-go/tools/clientcmd/api/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package api
|
||||
package api // import "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
2
vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go
generated
vendored
2
vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go
generated
vendored
@ -18,4 +18,4 @@ limitations under the License.
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:defaulter-gen=Kind
|
||||
|
||||
package v1
|
||||
package v1 // import "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||
|
49
vendor/k8s.io/client-go/tools/clientcmd/client_config.go
generated
vendored
49
vendor/k8s.io/client-go/tools/clientcmd/client_config.go
generated
vendored
@ -72,6 +72,13 @@ type ClientConfig interface {
|
||||
ConfigAccess() ConfigAccess
|
||||
}
|
||||
|
||||
// OverridingClientConfig is used to enable overrriding the raw KubeConfig
|
||||
type OverridingClientConfig interface {
|
||||
ClientConfig
|
||||
// MergedRawConfig return the RawConfig merged with all overrides.
|
||||
MergedRawConfig() (clientcmdapi.Config, error)
|
||||
}
|
||||
|
||||
type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
|
||||
|
||||
type promptedCredentials struct {
|
||||
@ -91,22 +98,22 @@ type DirectClientConfig struct {
|
||||
}
|
||||
|
||||
// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name
|
||||
func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig {
|
||||
func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) OverridingClientConfig {
|
||||
return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
|
||||
}
|
||||
|
||||
// NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information
|
||||
func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig {
|
||||
func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) OverridingClientConfig {
|
||||
return &DirectClientConfig{config, contextName, overrides, nil, configAccess, promptedCredentials{}}
|
||||
}
|
||||
|
||||
// NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags
|
||||
func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig {
|
||||
func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) OverridingClientConfig {
|
||||
return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
|
||||
}
|
||||
|
||||
// NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig
|
||||
func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) {
|
||||
func NewClientConfigFromBytes(configBytes []byte) (OverridingClientConfig, error) {
|
||||
config, err := Load(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -129,6 +136,40 @@ func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
||||
return config.config, nil
|
||||
}
|
||||
|
||||
// MergedRawConfig returns the raw kube config merged with the overrides
|
||||
func (config *DirectClientConfig) MergedRawConfig() (clientcmdapi.Config, error) {
|
||||
if err := config.ConfirmUsable(); err != nil {
|
||||
return clientcmdapi.Config{}, err
|
||||
}
|
||||
merged := config.config.DeepCopy()
|
||||
|
||||
// set the AuthInfo merged with overrides in the merged config
|
||||
mergedAuthInfo, err := config.getAuthInfo()
|
||||
if err != nil {
|
||||
return clientcmdapi.Config{}, err
|
||||
}
|
||||
mergedAuthInfoName, _ := config.getAuthInfoName()
|
||||
merged.AuthInfos[mergedAuthInfoName] = &mergedAuthInfo
|
||||
|
||||
// set the Context merged with overrides in the merged config
|
||||
mergedContext, err := config.getContext()
|
||||
if err != nil {
|
||||
return clientcmdapi.Config{}, err
|
||||
}
|
||||
mergedContextName, _ := config.getContextName()
|
||||
merged.Contexts[mergedContextName] = &mergedContext
|
||||
merged.CurrentContext = mergedContextName
|
||||
|
||||
// set the Cluster merged with overrides in the merged config
|
||||
configClusterInfo, err := config.getCluster()
|
||||
if err != nil {
|
||||
return clientcmdapi.Config{}, err
|
||||
}
|
||||
configClusterName, _ := config.getClusterName()
|
||||
merged.Clusters[configClusterName] = &configClusterInfo
|
||||
return *merged, nil
|
||||
}
|
||||
|
||||
// ClientConfig implements ClientConfig
|
||||
func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
|
||||
// check that getAuthInfo, getContext, and getCluster do not return an error.
|
||||
|
10
vendor/k8s.io/client-go/tools/events/event_broadcaster.go
generated
vendored
10
vendor/k8s.io/client-go/tools/events/event_broadcaster.go
generated
vendored
@ -404,7 +404,15 @@ type eventBroadcasterAdapterImpl struct {
|
||||
|
||||
// NewEventBroadcasterAdapter creates a wrapper around new and legacy broadcasters to simplify
|
||||
// migration of individual components to the new Event API.
|
||||
//
|
||||
//logcheck:context // NewEventBroadcasterAdapterWithContext should be used instead because record.NewBroadcaster is called and works better when a context is supplied (contextual logging, cancellation).
|
||||
func NewEventBroadcasterAdapter(client clientset.Interface) EventBroadcasterAdapter {
|
||||
return NewEventBroadcasterAdapterWithContext(context.Background(), client)
|
||||
}
|
||||
|
||||
// NewEventBroadcasterAdapterWithContext creates a wrapper around new and legacy broadcasters to simplify
|
||||
// migration of individual components to the new Event API.
|
||||
func NewEventBroadcasterAdapterWithContext(ctx context.Context, client clientset.Interface) EventBroadcasterAdapter {
|
||||
eventClient := &eventBroadcasterAdapterImpl{}
|
||||
if _, err := client.Discovery().ServerResourcesForGroupVersion(eventsv1.SchemeGroupVersion.String()); err == nil {
|
||||
eventClient.eventsv1Client = client.EventsV1()
|
||||
@ -414,7 +422,7 @@ func NewEventBroadcasterAdapter(client clientset.Interface) EventBroadcasterAdap
|
||||
// we create it unconditionally because its overhead is minor and will simplify using usage
|
||||
// patterns of this library in all components.
|
||||
eventClient.coreClient = client.CoreV1()
|
||||
eventClient.coreBroadcaster = record.NewBroadcaster()
|
||||
eventClient.coreBroadcaster = record.NewBroadcaster(record.WithContext(ctx))
|
||||
return eventClient
|
||||
}
|
||||
|
||||
|
30
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
30
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
@ -325,7 +325,22 @@ func (le *LeaderElector) tryAcquireOrRenew(ctx context.Context) bool {
|
||||
AcquireTime: now,
|
||||
}
|
||||
|
||||
// 1. obtain or create the ElectionRecord
|
||||
// 1. fast path for the leader to update optimistically assuming that the record observed
|
||||
// last time is the current version.
|
||||
if le.IsLeader() && le.isLeaseValid(now.Time) {
|
||||
oldObservedRecord := le.getObservedRecord()
|
||||
leaderElectionRecord.AcquireTime = oldObservedRecord.AcquireTime
|
||||
leaderElectionRecord.LeaderTransitions = oldObservedRecord.LeaderTransitions
|
||||
|
||||
err := le.config.Lock.Update(ctx, leaderElectionRecord)
|
||||
if err == nil {
|
||||
le.setObservedRecord(&leaderElectionRecord)
|
||||
return true
|
||||
}
|
||||
klog.Errorf("Failed to update lock optimitically: %v, falling back to slow path", err)
|
||||
}
|
||||
|
||||
// 2. obtain or create the ElectionRecord
|
||||
oldLeaderElectionRecord, oldLeaderElectionRawRecord, err := le.config.Lock.Get(ctx)
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
@ -342,24 +357,23 @@ func (le *LeaderElector) tryAcquireOrRenew(ctx context.Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. Record obtained, check the Identity & Time
|
||||
// 3. Record obtained, check the Identity & Time
|
||||
if !bytes.Equal(le.observedRawRecord, oldLeaderElectionRawRecord) {
|
||||
le.setObservedRecord(oldLeaderElectionRecord)
|
||||
|
||||
le.observedRawRecord = oldLeaderElectionRawRecord
|
||||
}
|
||||
if len(oldLeaderElectionRecord.HolderIdentity) > 0 &&
|
||||
le.observedTime.Add(time.Second*time.Duration(oldLeaderElectionRecord.LeaseDurationSeconds)).After(now.Time) &&
|
||||
!le.IsLeader() {
|
||||
if len(oldLeaderElectionRecord.HolderIdentity) > 0 && le.isLeaseValid(now.Time) && !le.IsLeader() {
|
||||
klog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity)
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. We're going to try to update. The leaderElectionRecord is set to it's default
|
||||
// 4. We're going to try to update. The leaderElectionRecord is set to it's default
|
||||
// here. Let's correct it before updating.
|
||||
if le.IsLeader() {
|
||||
leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime
|
||||
leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions
|
||||
le.metrics.slowpathExercised(le.config.Name)
|
||||
} else {
|
||||
leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1
|
||||
}
|
||||
@ -400,6 +414,10 @@ func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (le *LeaderElector) isLeaseValid(now time.Time) bool {
|
||||
return le.observedTime.Add(time.Second * time.Duration(le.getObservedRecord().LeaseDurationSeconds)).After(now)
|
||||
}
|
||||
|
||||
// setObservedRecord will set a new observedRecord and update observedTime to the current time.
|
||||
// Protect critical sections with lock.
|
||||
func (le *LeaderElector) setObservedRecord(observedRecord *rl.LeaderElectionRecord) {
|
||||
|
30
vendor/k8s.io/client-go/tools/leaderelection/metrics.go
generated
vendored
30
vendor/k8s.io/client-go/tools/leaderelection/metrics.go
generated
vendored
@ -26,24 +26,26 @@ import (
|
||||
type leaderMetricsAdapter interface {
|
||||
leaderOn(name string)
|
||||
leaderOff(name string)
|
||||
slowpathExercised(name string)
|
||||
}
|
||||
|
||||
// GaugeMetric represents a single numerical value that can arbitrarily go up
|
||||
// and down.
|
||||
type SwitchMetric interface {
|
||||
// LeaderMetric instruments metrics used in leader election.
|
||||
type LeaderMetric interface {
|
||||
On(name string)
|
||||
Off(name string)
|
||||
SlowpathExercised(name string)
|
||||
}
|
||||
|
||||
type noopMetric struct{}
|
||||
|
||||
func (noopMetric) On(name string) {}
|
||||
func (noopMetric) Off(name string) {}
|
||||
func (noopMetric) On(name string) {}
|
||||
func (noopMetric) Off(name string) {}
|
||||
func (noopMetric) SlowpathExercised(name string) {}
|
||||
|
||||
// defaultLeaderMetrics expects the caller to lock before setting any metrics.
|
||||
type defaultLeaderMetrics struct {
|
||||
// leader's value indicates if the current process is the owner of name lease
|
||||
leader SwitchMetric
|
||||
leader LeaderMetric
|
||||
}
|
||||
|
||||
func (m *defaultLeaderMetrics) leaderOn(name string) {
|
||||
@ -60,19 +62,27 @@ func (m *defaultLeaderMetrics) leaderOff(name string) {
|
||||
m.leader.Off(name)
|
||||
}
|
||||
|
||||
func (m *defaultLeaderMetrics) slowpathExercised(name string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
m.leader.SlowpathExercised(name)
|
||||
}
|
||||
|
||||
type noMetrics struct{}
|
||||
|
||||
func (noMetrics) leaderOn(name string) {}
|
||||
func (noMetrics) leaderOff(name string) {}
|
||||
func (noMetrics) leaderOn(name string) {}
|
||||
func (noMetrics) leaderOff(name string) {}
|
||||
func (noMetrics) slowpathExercised(name string) {}
|
||||
|
||||
// MetricsProvider generates various metrics used by the leader election.
|
||||
type MetricsProvider interface {
|
||||
NewLeaderMetric() SwitchMetric
|
||||
NewLeaderMetric() LeaderMetric
|
||||
}
|
||||
|
||||
type noopMetricsProvider struct{}
|
||||
|
||||
func (_ noopMetricsProvider) NewLeaderMetric() SwitchMetric {
|
||||
func (noopMetricsProvider) NewLeaderMetric() LeaderMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
|
10
vendor/k8s.io/client-go/tools/portforward/OWNERS
generated
vendored
Normal file
10
vendor/k8s.io/client-go/tools/portforward/OWNERS
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- aojea
|
||||
- liggitt
|
||||
- seans3
|
||||
reviewers:
|
||||
- aojea
|
||||
- liggitt
|
||||
- seans3
|
57
vendor/k8s.io/client-go/tools/portforward/fallback_dialer.go
generated
vendored
Normal file
57
vendor/k8s.io/client-go/tools/portforward/fallback_dialer.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2024 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 portforward
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var _ httpstream.Dialer = &fallbackDialer{}
|
||||
|
||||
// fallbackDialer encapsulates a primary and secondary dialer, including
|
||||
// the boolean function to determine if the primary dialer failed. Implements
|
||||
// the httpstream.Dialer interface.
|
||||
type fallbackDialer struct {
|
||||
primary httpstream.Dialer
|
||||
secondary httpstream.Dialer
|
||||
shouldFallback func(error) bool
|
||||
}
|
||||
|
||||
// NewFallbackDialer creates the fallbackDialer with the primary and secondary dialers,
|
||||
// as well as the boolean function to determine if the primary dialer failed.
|
||||
func NewFallbackDialer(primary, secondary httpstream.Dialer, shouldFallback func(error) bool) httpstream.Dialer {
|
||||
return &fallbackDialer{
|
||||
primary: primary,
|
||||
secondary: secondary,
|
||||
shouldFallback: shouldFallback,
|
||||
}
|
||||
}
|
||||
|
||||
// Dial is the single function necessary to implement the "httpstream.Dialer" interface.
|
||||
// It takes the protocol version strings to request, returning an the upgraded
|
||||
// httstream.Connection and the negotiated protocol version accepted. If the initial
|
||||
// primary dialer fails, this function attempts the secondary dialer. Returns an error
|
||||
// if one occurs.
|
||||
func (f *fallbackDialer) Dial(protocols ...string) (httpstream.Connection, string, error) {
|
||||
conn, version, err := f.primary.Dial(protocols...)
|
||||
if err != nil && f.shouldFallback(err) {
|
||||
klog.V(4).Infof("fallback to secondary dialer from primary dialer err: %v", err)
|
||||
return f.secondary.Dial(protocols...)
|
||||
}
|
||||
return conn, version, err
|
||||
}
|
6
vendor/k8s.io/client-go/tools/portforward/portforward.go
generated
vendored
6
vendor/k8s.io/client-go/tools/portforward/portforward.go
generated
vendored
@ -191,11 +191,15 @@ func (pf *PortForwarder) ForwardPorts() error {
|
||||
defer pf.Close()
|
||||
|
||||
var err error
|
||||
pf.streamConn, _, err = pf.dialer.Dial(PortForwardProtocolV1Name)
|
||||
var protocol string
|
||||
pf.streamConn, protocol, err = pf.dialer.Dial(PortForwardProtocolV1Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error upgrading connection: %s", err)
|
||||
}
|
||||
defer pf.streamConn.Close()
|
||||
if protocol != PortForwardProtocolV1Name {
|
||||
return fmt.Errorf("unable to negotiate protocol: client supports %q, server returned %q", PortForwardProtocolV1Name, protocol)
|
||||
}
|
||||
|
||||
return pf.forward()
|
||||
}
|
||||
|
158
vendor/k8s.io/client-go/tools/portforward/tunneling_connection.go
generated
vendored
Normal file
158
vendor/k8s.io/client-go/tools/portforward/tunneling_connection.go
generated
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
Copyright 2023 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 portforward
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
gwebsocket "github.com/gorilla/websocket"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var _ net.Conn = &TunnelingConnection{}
|
||||
|
||||
// TunnelingConnection implements the "httpstream.Connection" interface, wrapping
|
||||
// a websocket connection that tunnels SPDY.
|
||||
type TunnelingConnection struct {
|
||||
name string
|
||||
conn *gwebsocket.Conn
|
||||
inProgressMessage io.Reader
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// NewTunnelingConnection wraps the passed gorilla/websockets connection
|
||||
// with the TunnelingConnection struct (implementing net.Conn).
|
||||
func NewTunnelingConnection(name string, conn *gwebsocket.Conn) *TunnelingConnection {
|
||||
return &TunnelingConnection{
|
||||
name: name,
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements "io.Reader" interface, reading from the stored connection
|
||||
// into the passed buffer "p". Returns the number of bytes read and an error.
|
||||
// Can keep track of the "inProgress" messsage from the tunneled connection.
|
||||
func (c *TunnelingConnection) Read(p []byte) (int, error) {
|
||||
klog.V(7).Infof("%s: tunneling connection read...", c.name)
|
||||
defer klog.V(7).Infof("%s: tunneling connection read...complete", c.name)
|
||||
for {
|
||||
if c.inProgressMessage == nil {
|
||||
klog.V(8).Infof("%s: tunneling connection read before NextReader()...", c.name)
|
||||
messageType, nextReader, err := c.conn.NextReader()
|
||||
if err != nil {
|
||||
closeError := &gwebsocket.CloseError{}
|
||||
if errors.As(err, &closeError) && closeError.Code == gwebsocket.CloseNormalClosure {
|
||||
return 0, io.EOF
|
||||
}
|
||||
klog.V(4).Infof("%s:tunneling connection NextReader() error: %v", c.name, err)
|
||||
return 0, err
|
||||
}
|
||||
if messageType != gwebsocket.BinaryMessage {
|
||||
return 0, fmt.Errorf("invalid message type received")
|
||||
}
|
||||
c.inProgressMessage = nextReader
|
||||
}
|
||||
klog.V(8).Infof("%s: tunneling connection read in progress message...", c.name)
|
||||
i, err := c.inProgressMessage.Read(p)
|
||||
if i == 0 && err == io.EOF {
|
||||
c.inProgressMessage = nil
|
||||
} else {
|
||||
klog.V(8).Infof("%s: read %d bytes, error=%v, bytes=% X", c.name, i, err, p[:i])
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write implements "io.Writer" interface, copying the data in the passed
|
||||
// byte array "p" into the stored tunneled connection. Returns the number
|
||||
// of bytes written and an error.
|
||||
func (c *TunnelingConnection) Write(p []byte) (n int, err error) {
|
||||
klog.V(7).Infof("%s: write: %d bytes, bytes=% X", c.name, len(p), p)
|
||||
defer klog.V(7).Infof("%s: tunneling connection write...complete", c.name)
|
||||
w, err := c.conn.NextWriter(gwebsocket.BinaryMessage)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
// close, which flushes the message
|
||||
closeErr := w.Close()
|
||||
if closeErr != nil && err == nil {
|
||||
// if closing/flushing errored and we weren't already returning an error, return the close error
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
|
||||
n, err = w.Write(p)
|
||||
return
|
||||
}
|
||||
|
||||
// Close implements "io.Closer" interface, signaling the other tunneled connection
|
||||
// endpoint, and closing the tunneled connection only once.
|
||||
func (c *TunnelingConnection) Close() error {
|
||||
var err error
|
||||
c.closeOnce.Do(func() {
|
||||
klog.V(7).Infof("%s: tunneling connection Close()...", c.name)
|
||||
// Signal other endpoint that websocket connection is closing; ignore error.
|
||||
normalCloseMsg := gwebsocket.FormatCloseMessage(gwebsocket.CloseNormalClosure, "")
|
||||
writeControlErr := c.conn.WriteControl(gwebsocket.CloseMessage, normalCloseMsg, time.Now().Add(time.Second))
|
||||
closeErr := c.conn.Close()
|
||||
if closeErr != nil {
|
||||
err = closeErr
|
||||
} else if writeControlErr != nil {
|
||||
err = writeControlErr
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// LocalAddr implements part of the "net.Conn" interface, returning the local
|
||||
// endpoint network address of the tunneled connection.
|
||||
func (c *TunnelingConnection) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
// LocalAddr implements part of the "net.Conn" interface, returning the remote
|
||||
// endpoint network address of the tunneled connection.
|
||||
func (c *TunnelingConnection) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// SetDeadline sets the *absolute* time in the future for both
|
||||
// read and write deadlines. Returns an error if one occurs.
|
||||
func (c *TunnelingConnection) SetDeadline(t time.Time) error {
|
||||
rerr := c.SetReadDeadline(t)
|
||||
werr := c.SetWriteDeadline(t)
|
||||
return errors.Join(rerr, werr)
|
||||
}
|
||||
|
||||
// SetDeadline sets the *absolute* time in the future for the
|
||||
// read deadlines. Returns an error if one occurs.
|
||||
func (c *TunnelingConnection) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetDeadline sets the *absolute* time in the future for the
|
||||
// write deadlines. Returns an error if one occurs.
|
||||
func (c *TunnelingConnection) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
93
vendor/k8s.io/client-go/tools/portforward/tunneling_dialer.go
generated
vendored
Normal file
93
vendor/k8s.io/client-go/tools/portforward/tunneling_dialer.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2023 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 portforward
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
|
||||
constants "k8s.io/apimachinery/pkg/util/portforward"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/transport/websocket"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const PingPeriod = 10 * time.Second
|
||||
|
||||
// tunnelingDialer implements "httpstream.Dial" interface
|
||||
type tunnelingDialer struct {
|
||||
url *url.URL
|
||||
transport http.RoundTripper
|
||||
holder websocket.ConnectionHolder
|
||||
}
|
||||
|
||||
// NewTunnelingDialer creates and returns the tunnelingDialer structure which implemements the "httpstream.Dialer"
|
||||
// interface. The dialer can upgrade a websocket request, creating a websocket connection. This function
|
||||
// returns an error if one occurs.
|
||||
func NewSPDYOverWebsocketDialer(url *url.URL, config *restclient.Config) (httpstream.Dialer, error) {
|
||||
transport, holder, err := websocket.RoundTripperFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tunnelingDialer{
|
||||
url: url,
|
||||
transport: transport,
|
||||
holder: holder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Dial upgrades to a tunneling streaming connection, returning a SPDY connection
|
||||
// containing a WebSockets connection (which implements "net.Conn"). Also
|
||||
// returns the protocol negotiated, or an error.
|
||||
func (d *tunnelingDialer) Dial(protocols ...string) (httpstream.Connection, string, error) {
|
||||
// There is no passed context, so skip the context when creating request for now.
|
||||
// Websockets requires "GET" method: RFC 6455 Sec. 4.1 (page 17).
|
||||
req, err := http.NewRequest("GET", d.url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
// Add the spdy tunneling prefix to the requested protocols. The tunneling
|
||||
// handler will know how to negotiate these protocols.
|
||||
tunnelingProtocols := []string{}
|
||||
for _, protocol := range protocols {
|
||||
tunnelingProtocol := constants.WebsocketsSPDYTunnelingPrefix + protocol
|
||||
tunnelingProtocols = append(tunnelingProtocols, tunnelingProtocol)
|
||||
}
|
||||
klog.V(4).Infoln("Before WebSocket Upgrade Connection...")
|
||||
conn, err := websocket.Negotiate(d.transport, d.holder, req, tunnelingProtocols...)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if conn == nil {
|
||||
return nil, "", fmt.Errorf("negotiated websocket connection is nil")
|
||||
}
|
||||
protocol := conn.Subprotocol()
|
||||
protocol = strings.TrimPrefix(protocol, constants.WebsocketsSPDYTunnelingPrefix)
|
||||
klog.V(4).Infof("negotiated protocol: %s", protocol)
|
||||
|
||||
// Wrap the websocket connection which implements "net.Conn".
|
||||
tConn := NewTunnelingConnection("client", conn)
|
||||
// Create SPDY connection injecting the previously created tunneling connection.
|
||||
spdyConn, err := spdy.NewClientConnectionWithPings(tConn, PingPeriod)
|
||||
|
||||
return spdyConn, protocol, err
|
||||
}
|
19
vendor/k8s.io/client-go/tools/record/event.go
generated
vendored
19
vendor/k8s.io/client-go/tools/record/event.go
generated
vendored
@ -198,16 +198,29 @@ func NewBroadcaster(opts ...BroadcasterOption) EventBroadcaster {
|
||||
ctx := c.Context
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
} else {
|
||||
}
|
||||
// The are two scenarios where it makes no sense to wait for context cancelation:
|
||||
// - The context was nil.
|
||||
// - The context was context.Background() to begin with.
|
||||
//
|
||||
// Both cases get checked here.
|
||||
haveCtxCancelation := ctx.Done() == nil
|
||||
|
||||
eventBroadcaster.cancelationCtx, eventBroadcaster.cancel = context.WithCancel(ctx)
|
||||
|
||||
if haveCtxCancelation {
|
||||
// Calling Shutdown is not required when a context was provided:
|
||||
// when the context is canceled, this goroutine will shut down
|
||||
// the broadcaster.
|
||||
//
|
||||
// If Shutdown is called first, then this goroutine will
|
||||
// also stop.
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
<-eventBroadcaster.cancelationCtx.Done()
|
||||
eventBroadcaster.Broadcaster.Shutdown()
|
||||
}()
|
||||
}
|
||||
eventBroadcaster.cancelationCtx, eventBroadcaster.cancel = context.WithCancel(ctx)
|
||||
|
||||
return eventBroadcaster
|
||||
}
|
||||
|
||||
|
10
vendor/k8s.io/client-go/tools/remotecommand/OWNERS
generated
vendored
Normal file
10
vendor/k8s.io/client-go/tools/remotecommand/OWNERS
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- aojea
|
||||
- liggitt
|
||||
- seans3
|
||||
reviewers:
|
||||
- aojea
|
||||
- liggitt
|
||||
- seans3
|
10
vendor/k8s.io/client-go/tools/remotecommand/fallback.go
generated
vendored
10
vendor/k8s.io/client-go/tools/remotecommand/fallback.go
generated
vendored
@ -20,9 +20,9 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
var _ Executor = &fallbackExecutor{}
|
||||
var _ Executor = &FallbackExecutor{}
|
||||
|
||||
type fallbackExecutor struct {
|
||||
type FallbackExecutor struct {
|
||||
primary Executor
|
||||
secondary Executor
|
||||
shouldFallback func(error) bool
|
||||
@ -33,7 +33,7 @@ type fallbackExecutor struct {
|
||||
// websocket "StreamWithContext" call fails.
|
||||
// func NewFallbackExecutor(config *restclient.Config, method string, url *url.URL) (Executor, error) {
|
||||
func NewFallbackExecutor(primary, secondary Executor, shouldFallback func(error) bool) (Executor, error) {
|
||||
return &fallbackExecutor{
|
||||
return &FallbackExecutor{
|
||||
primary: primary,
|
||||
secondary: secondary,
|
||||
shouldFallback: shouldFallback,
|
||||
@ -41,14 +41,14 @@ func NewFallbackExecutor(primary, secondary Executor, shouldFallback func(error)
|
||||
}
|
||||
|
||||
// Stream is deprecated. Please use "StreamWithContext".
|
||||
func (f *fallbackExecutor) Stream(options StreamOptions) error {
|
||||
func (f *FallbackExecutor) Stream(options StreamOptions) error {
|
||||
return f.StreamWithContext(context.Background(), options)
|
||||
}
|
||||
|
||||
// StreamWithContext initially attempts to call "StreamWithContext" using the
|
||||
// primary executor, falling back to calling the secondary executor if the
|
||||
// initial primary call to upgrade to a websocket connection fails.
|
||||
func (f *fallbackExecutor) StreamWithContext(ctx context.Context, options StreamOptions) error {
|
||||
func (f *FallbackExecutor) StreamWithContext(ctx context.Context, options StreamOptions) error {
|
||||
err := f.primary.StreamWithContext(ctx, options)
|
||||
if f.shouldFallback(err) {
|
||||
return f.secondary.StreamWithContext(ctx, options)
|
||||
|
39
vendor/k8s.io/client-go/tools/remotecommand/websocket.go
generated
vendored
39
vendor/k8s.io/client-go/tools/remotecommand/websocket.go
generated
vendored
@ -36,13 +36,9 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// writeDeadline defines the time that a write to the websocket connection
|
||||
// must complete by, otherwise an i/o timeout occurs. The writeDeadline
|
||||
// has nothing to do with a response from the other websocket connection
|
||||
// endpoint; only that the message was successfully processed by the
|
||||
// local websocket connection. The typical write deadline within the websocket
|
||||
// library is one second.
|
||||
const writeDeadline = 2 * time.Second
|
||||
// writeDeadline defines the time that a client-side write to the websocket
|
||||
// connection must complete before an i/o timeout occurs.
|
||||
const writeDeadline = 60 * time.Second
|
||||
|
||||
var (
|
||||
_ Executor = &wsStreamExecutor{}
|
||||
@ -65,8 +61,8 @@ const (
|
||||
// "pong" message before a timeout error occurs for websocket reading.
|
||||
// This duration must always be greater than the "pingPeriod". By defining
|
||||
// this deadline in terms of the ping period, we are essentially saying
|
||||
// we can drop "X-1" (e.g. 3-1=2) pings before firing the timeout.
|
||||
pingReadDeadline = (pingPeriod * 3) + (1 * time.Second)
|
||||
// we can drop "X" (e.g. 12) pings before firing the timeout.
|
||||
pingReadDeadline = (pingPeriod * 12) + (1 * time.Second)
|
||||
)
|
||||
|
||||
// wsStreamExecutor handles transporting standard shell streams over an httpstream connection.
|
||||
@ -187,6 +183,9 @@ type wsStreamCreator struct {
|
||||
// map of stream id to stream; multiple streams read/write the connection
|
||||
streams map[byte]*stream
|
||||
streamsMu sync.Mutex
|
||||
// setStreamErr holds the error to return to anyone calling setStreams.
|
||||
// this is populated in closeAllStreamReaders
|
||||
setStreamErr error
|
||||
}
|
||||
|
||||
func newWSStreamCreator(conn *gwebsocket.Conn) *wsStreamCreator {
|
||||
@ -202,10 +201,14 @@ func (c *wsStreamCreator) getStream(id byte) *stream {
|
||||
return c.streams[id]
|
||||
}
|
||||
|
||||
func (c *wsStreamCreator) setStream(id byte, s *stream) {
|
||||
func (c *wsStreamCreator) setStream(id byte, s *stream) error {
|
||||
c.streamsMu.Lock()
|
||||
defer c.streamsMu.Unlock()
|
||||
if c.setStreamErr != nil {
|
||||
return c.setStreamErr
|
||||
}
|
||||
c.streams[id] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateStream uses id from passed headers to create a stream over "c.conn" connection.
|
||||
@ -228,7 +231,11 @@ func (c *wsStreamCreator) CreateStream(headers http.Header) (httpstream.Stream,
|
||||
connWriteLock: &c.connWriteLock,
|
||||
id: id,
|
||||
}
|
||||
c.setStream(id, s)
|
||||
if err := c.setStream(id, s); err != nil {
|
||||
_ = s.writePipe.Close()
|
||||
_ = s.readPipe.Close()
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@ -312,7 +319,7 @@ func (c *wsStreamCreator) readDemuxLoop(bufferSize int, period time.Duration, de
|
||||
}
|
||||
|
||||
// closeAllStreamReaders closes readers in all streams.
|
||||
// This unblocks all stream.Read() calls.
|
||||
// This unblocks all stream.Read() calls, and keeps any future streams from being created.
|
||||
func (c *wsStreamCreator) closeAllStreamReaders(err error) {
|
||||
c.streamsMu.Lock()
|
||||
defer c.streamsMu.Unlock()
|
||||
@ -320,6 +327,12 @@ func (c *wsStreamCreator) closeAllStreamReaders(err error) {
|
||||
// Closing writePipe unblocks all readPipe.Read() callers and prevents any future writes.
|
||||
_ = s.writePipe.CloseWithError(err)
|
||||
}
|
||||
// ensure callers to setStreams receive an error after this point
|
||||
if err != nil {
|
||||
c.setStreamErr = err
|
||||
} else {
|
||||
c.setStreamErr = fmt.Errorf("closed all streams")
|
||||
}
|
||||
}
|
||||
|
||||
type stream struct {
|
||||
@ -480,7 +493,7 @@ func (h *heartbeat) start() {
|
||||
// "WriteControl" does not need to be protected by a mutex. According to
|
||||
// gorilla/websockets library docs: "The Close and WriteControl methods can
|
||||
// be called concurrently with all other methods."
|
||||
if err := h.conn.WriteControl(gwebsocket.PingMessage, h.message, time.Now().Add(writeDeadline)); err == nil {
|
||||
if err := h.conn.WriteControl(gwebsocket.PingMessage, h.message, time.Now().Add(pingReadDeadline)); err == nil {
|
||||
klog.V(8).Infof("Websocket Ping succeeeded")
|
||||
} else {
|
||||
klog.Errorf("Websocket Ping failed: %v", err)
|
||||
|
Reference in New Issue
Block a user