forked from toolshed/abra
.gitea
cli
cmd
pkg
app
autocomplete
client
compose
config
container
context
dns
formatter
git
integration
limit
lint
recipe
secret
server
service
ssh
test
upstream
commandconn
commandconn.go
connection.go
pdeathsig_linux.go
pdeathsig_nolinux.go
container
convert
service
stack
web
scripts
tests
.drone.yml
.e2e.env.sample
.envrc.sample
.gitignore
.goreleaser.yml
AUTHORS.md
LICENSE
Makefile
README.md
go.mod
go.sum
renovate.json
105 lines
3.0 KiB
Go
105 lines
3.0 KiB
Go
package commandconn
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
|
|
sshPkg "coopcloud.tech/abra/pkg/ssh"
|
|
"github.com/docker/cli/cli/connhelper"
|
|
"github.com/docker/cli/cli/connhelper/ssh"
|
|
"github.com/docker/cli/cli/context/docker"
|
|
dCliContextStore "github.com/docker/cli/cli/context/store"
|
|
dClient "github.com/docker/docker/client"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// GetConnectionHelper returns Docker-specific connection helper for the given URL.
|
|
// GetConnectionHelper returns nil without error when no helper is registered for the scheme.
|
|
//
|
|
// ssh://<user>@<host> URL requires Docker 18.09 or later on the remote host.
|
|
func GetConnectionHelper(daemonURL string) (*connhelper.ConnectionHelper, error) {
|
|
return getConnectionHelper(daemonURL, []string{"-o ConnectTimeout=5"})
|
|
}
|
|
|
|
func getConnectionHelper(daemonURL string, sshFlags []string) (*connhelper.ConnectionHelper, error) {
|
|
url, err := url.Parse(daemonURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch scheme := url.Scheme; scheme {
|
|
case "ssh":
|
|
ctxConnDetails, err := ssh.ParseURL(daemonURL)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "ssh host connection is not valid")
|
|
}
|
|
|
|
if err := sshPkg.EnsureHostKey(ctxConnDetails.Host); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hostConfig, err := sshPkg.GetHostConfig(
|
|
ctxConnDetails.Host,
|
|
ctxConnDetails.User,
|
|
ctxConnDetails.Port,
|
|
false,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if hostConfig.IdentityFile != "" {
|
|
msg := "discovered %s as identity file for %s, using for ssh connection"
|
|
logrus.Debugf(msg, hostConfig.IdentityFile, ctxConnDetails.Host)
|
|
sshFlags = append(sshFlags, fmt.Sprintf("-o IdentityFile=%s", hostConfig.IdentityFile))
|
|
}
|
|
|
|
return &connhelper.ConnectionHelper{
|
|
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return New(ctx, "ssh", append(sshFlags, ctxConnDetails.Args("docker", "system", "dial-stdio")...)...)
|
|
},
|
|
Host: "http://docker.example.com",
|
|
}, nil
|
|
}
|
|
// Future version may support plugins via ~/.docker/config.json. e.g. "dind"
|
|
// See docker/cli#889 for the previous discussion.
|
|
return nil, err
|
|
}
|
|
|
|
func NewConnectionHelper(daemonURL string) (*connhelper.ConnectionHelper, error) {
|
|
helper, err := GetConnectionHelper(daemonURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return helper, nil
|
|
}
|
|
|
|
func getDockerEndpoint(host string) (docker.Endpoint, error) {
|
|
skipTLSVerify := false
|
|
ep := docker.Endpoint{
|
|
EndpointMeta: docker.EndpointMeta{
|
|
Host: host,
|
|
SkipTLSVerify: skipTLSVerify,
|
|
},
|
|
}
|
|
// try to resolve a docker client, validating the configuration
|
|
opts, err := ep.ClientOpts()
|
|
if err != nil {
|
|
return docker.Endpoint{}, err
|
|
}
|
|
if _, err := dClient.NewClientWithOpts(opts...); err != nil {
|
|
return docker.Endpoint{}, err
|
|
}
|
|
return ep, nil
|
|
}
|
|
|
|
func GetDockerEndpointMetadataAndTLS(host string) (docker.EndpointMeta, *dCliContextStore.EndpointTLSData, error) {
|
|
ep, err := getDockerEndpoint(host)
|
|
if err != nil {
|
|
return docker.EndpointMeta{}, nil, err
|
|
}
|
|
return ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil
|
|
}
|