1 /* 2 Copyright 2024 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package portforward 18 19 import ( 20 "k8s.io/apimachinery/pkg/util/httpstream" 21 "k8s.io/klog/v2" 22 ) 23 24 var _ httpstream.Dialer = &fallbackDialer{} 25 26 // fallbackDialer encapsulates a primary and secondary dialer, including 27 // the boolean function to determine if the primary dialer failed. Implements 28 // the httpstream.Dialer interface. 29 type fallbackDialer struct { 30 primary httpstream.Dialer 31 secondary httpstream.Dialer 32 shouldFallback func(error) bool 33 } 34 35 // NewFallbackDialer creates the fallbackDialer with the primary and secondary dialers, 36 // as well as the boolean function to determine if the primary dialer failed. 37 func NewFallbackDialer(primary, secondary httpstream.Dialer, shouldFallback func(error) bool) httpstream.Dialer { 38 return &fallbackDialer{ 39 primary: primary, 40 secondary: secondary, 41 shouldFallback: shouldFallback, 42 } 43 } 44 45 // Dial is the single function necessary to implement the "httpstream.Dialer" interface. 46 // It takes the protocol version strings to request, returning an the upgraded 47 // httstream.Connection and the negotiated protocol version accepted. If the initial 48 // primary dialer fails, this function attempts the secondary dialer. Returns an error 49 // if one occurs. 50 func (f *fallbackDialer) Dial(protocols ...string) (httpstream.Connection, string, error) { 51 conn, version, err := f.primary.Dial(protocols...) 52 if err != nil && f.shouldFallback(err) { 53 klog.V(4).Infof("fallback to secondary dialer from primary dialer err: %v", err) 54 return f.secondary.Dial(protocols...) 55 } 56 return conn, version, err 57 } 58