github.com/thajeztah/cli@v0.0.0-20240223162942-dc6bfac81a8b/cli/connhelper/connhelper.go (about) 1 // Package connhelper provides helpers for connecting to a remote daemon host with custom logic. 2 package connhelper 3 4 import ( 5 "context" 6 "net" 7 "net/url" 8 "strings" 9 10 "github.com/docker/cli/cli/connhelper/commandconn" 11 "github.com/docker/cli/cli/connhelper/ssh" 12 "github.com/pkg/errors" 13 ) 14 15 // ConnectionHelper allows to connect to a remote host with custom stream provider binary. 16 type ConnectionHelper struct { 17 Dialer func(ctx context.Context, network, addr string) (net.Conn, error) 18 Host string // dummy URL used for HTTP requests. e.g. "http://docker" 19 } 20 21 // GetConnectionHelper returns Docker-specific connection helper for the given URL. 22 // GetConnectionHelper returns nil without error when no helper is registered for the scheme. 23 // 24 // ssh://<user>@<host> URL requires Docker 18.09 or later on the remote host. 25 func GetConnectionHelper(daemonURL string) (*ConnectionHelper, error) { 26 return getConnectionHelper(daemonURL, nil) 27 } 28 29 // GetConnectionHelperWithSSHOpts returns Docker-specific connection helper for 30 // the given URL, and accepts additional options for ssh connections. It returns 31 // nil without error when no helper is registered for the scheme. 32 // 33 // Requires Docker 18.09 or later on the remote host. 34 func GetConnectionHelperWithSSHOpts(daemonURL string, sshFlags []string) (*ConnectionHelper, error) { 35 return getConnectionHelper(daemonURL, sshFlags) 36 } 37 38 func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper, error) { 39 u, err := url.Parse(daemonURL) 40 if err != nil { 41 return nil, err 42 } 43 if u.Scheme == "ssh" { 44 sp, err := ssh.ParseURL(daemonURL) 45 if err != nil { 46 return nil, errors.Wrap(err, "ssh host connection is not valid") 47 } 48 return &ConnectionHelper{ 49 Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { 50 args := []string{"docker"} 51 if sp.Path != "" { 52 args = append(args, "--host", "unix://"+sp.Path) 53 } 54 sshFlags = addSSHTimeout(sshFlags) 55 args = append(args, "system", "dial-stdio") 56 return commandconn.New(ctx, "ssh", append(sshFlags, sp.Args(args...)...)...) 57 }, 58 Host: "http://docker.example.com", 59 }, nil 60 } 61 // Future version may support plugins via ~/.docker/config.json. e.g. "dind" 62 // See docker/cli#889 for the previous discussion. 63 return nil, err 64 } 65 66 // GetCommandConnectionHelper returns Docker-specific connection helper constructed from an arbitrary command. 67 func GetCommandConnectionHelper(cmd string, flags ...string) (*ConnectionHelper, error) { 68 return &ConnectionHelper{ 69 Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { 70 return commandconn.New(ctx, cmd, flags...) 71 }, 72 Host: "http://docker.example.com", 73 }, nil 74 } 75 76 func addSSHTimeout(sshFlags []string) []string { 77 if !strings.Contains(strings.Join(sshFlags, ""), "ConnectTimeout") { 78 sshFlags = append(sshFlags, "-o ConnectTimeout=30") 79 } 80 return sshFlags 81 }