mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package remotecommand
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
 | 
						|
	"k8s.io/klog/v2"
 | 
						|
 | 
						|
	"k8s.io/apimachinery/pkg/util/httpstream"
 | 
						|
	"k8s.io/apimachinery/pkg/util/remotecommand"
 | 
						|
	restclient "k8s.io/client-go/rest"
 | 
						|
	spdy "k8s.io/client-go/transport/spdy"
 | 
						|
)
 | 
						|
 | 
						|
// StreamOptions holds information pertaining to the current streaming session:
 | 
						|
// input/output streams, if the client is requesting a TTY, and a terminal size queue to
 | 
						|
// support terminal resizing.
 | 
						|
type StreamOptions struct {
 | 
						|
	Stdin             io.Reader
 | 
						|
	Stdout            io.Writer
 | 
						|
	Stderr            io.Writer
 | 
						|
	Tty               bool
 | 
						|
	TerminalSizeQueue TerminalSizeQueue
 | 
						|
}
 | 
						|
 | 
						|
// Executor is an interface for transporting shell-style streams.
 | 
						|
type Executor interface {
 | 
						|
	// Stream initiates the transport of the standard shell streams. It will transport any
 | 
						|
	// non-nil stream to a remote system, and return an error if a problem occurs. If tty
 | 
						|
	// is set, the stderr stream is not used (raw TTY manages stdout and stderr over the
 | 
						|
	// stdout stream).
 | 
						|
	Stream(options StreamOptions) error
 | 
						|
}
 | 
						|
 | 
						|
type streamCreator interface {
 | 
						|
	CreateStream(headers http.Header) (httpstream.Stream, error)
 | 
						|
}
 | 
						|
 | 
						|
type streamProtocolHandler interface {
 | 
						|
	stream(conn streamCreator) error
 | 
						|
}
 | 
						|
 | 
						|
// streamExecutor handles transporting standard shell streams over an httpstream connection.
 | 
						|
type streamExecutor struct {
 | 
						|
	upgrader  spdy.Upgrader
 | 
						|
	transport http.RoundTripper
 | 
						|
 | 
						|
	method    string
 | 
						|
	url       *url.URL
 | 
						|
	protocols []string
 | 
						|
}
 | 
						|
 | 
						|
// NewSPDYExecutor connects to the provided server and upgrades the connection to
 | 
						|
// multiplexed bidirectional streams.
 | 
						|
func NewSPDYExecutor(config *restclient.Config, method string, url *url.URL) (Executor, error) {
 | 
						|
	wrapper, upgradeRoundTripper, err := spdy.RoundTripperFor(config)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return NewSPDYExecutorForTransports(wrapper, upgradeRoundTripper, method, url)
 | 
						|
}
 | 
						|
 | 
						|
// NewSPDYExecutorForTransports connects to the provided server using the given transport,
 | 
						|
// upgrades the response using the given upgrader to multiplexed bidirectional streams.
 | 
						|
func NewSPDYExecutorForTransports(transport http.RoundTripper, upgrader spdy.Upgrader, method string, url *url.URL) (Executor, error) {
 | 
						|
	return NewSPDYExecutorForProtocols(
 | 
						|
		transport, upgrader, method, url,
 | 
						|
		remotecommand.StreamProtocolV4Name,
 | 
						|
		remotecommand.StreamProtocolV3Name,
 | 
						|
		remotecommand.StreamProtocolV2Name,
 | 
						|
		remotecommand.StreamProtocolV1Name,
 | 
						|
	)
 | 
						|
}
 | 
						|
 | 
						|
// NewSPDYExecutorForProtocols connects to the provided server and upgrades the connection to
 | 
						|
// multiplexed bidirectional streams using only the provided protocols. Exposed for testing, most
 | 
						|
// callers should use NewSPDYExecutor or NewSPDYExecutorForTransports.
 | 
						|
func NewSPDYExecutorForProtocols(transport http.RoundTripper, upgrader spdy.Upgrader, method string, url *url.URL, protocols ...string) (Executor, error) {
 | 
						|
	return &streamExecutor{
 | 
						|
		upgrader:  upgrader,
 | 
						|
		transport: transport,
 | 
						|
		method:    method,
 | 
						|
		url:       url,
 | 
						|
		protocols: protocols,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// Stream opens a protocol streamer to the server and streams until a client closes
 | 
						|
// the connection or the server disconnects.
 | 
						|
func (e *streamExecutor) Stream(options StreamOptions) error {
 | 
						|
	req, err := http.NewRequest(e.method, e.url.String(), nil)
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("error creating request: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	conn, protocol, err := spdy.Negotiate(
 | 
						|
		e.upgrader,
 | 
						|
		&http.Client{Transport: e.transport},
 | 
						|
		req,
 | 
						|
		e.protocols...,
 | 
						|
	)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer conn.Close()
 | 
						|
 | 
						|
	var streamer streamProtocolHandler
 | 
						|
 | 
						|
	switch protocol {
 | 
						|
	case remotecommand.StreamProtocolV4Name:
 | 
						|
		streamer = newStreamProtocolV4(options)
 | 
						|
	case remotecommand.StreamProtocolV3Name:
 | 
						|
		streamer = newStreamProtocolV3(options)
 | 
						|
	case remotecommand.StreamProtocolV2Name:
 | 
						|
		streamer = newStreamProtocolV2(options)
 | 
						|
	case "":
 | 
						|
		klog.V(4).Infof("The server did not negotiate a streaming protocol version. Falling back to %s", remotecommand.StreamProtocolV1Name)
 | 
						|
		fallthrough
 | 
						|
	case remotecommand.StreamProtocolV1Name:
 | 
						|
		streamer = newStreamProtocolV1(options)
 | 
						|
	}
 | 
						|
 | 
						|
	return streamer.stream(conn)
 | 
						|
}
 |