mirror of https://github.com/docker/cli.git
222 lines
5.7 KiB
Go
222 lines
5.7 KiB
Go
|
package context
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/docker/cli/cli/command"
|
||
|
"github.com/docker/cli/cli/context"
|
||
|
"github.com/docker/cli/cli/context/docker"
|
||
|
"github.com/docker/cli/cli/context/kubernetes"
|
||
|
"github.com/docker/cli/cli/context/store"
|
||
|
"github.com/docker/docker/client"
|
||
|
"github.com/docker/docker/pkg/homedir"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
keyFromCurrent = "from-current"
|
||
|
keyHost = "host"
|
||
|
keyCA = "ca"
|
||
|
keyCert = "cert"
|
||
|
keyKey = "key"
|
||
|
keySkipTLSVerify = "skip-tls-verify"
|
||
|
keyKubeconfig = "config-file"
|
||
|
keyKubecontext = "context-override"
|
||
|
keyKubenamespace = "namespace-override"
|
||
|
)
|
||
|
|
||
|
type configKeyDescription struct {
|
||
|
name string
|
||
|
description string
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
allowedDockerConfigKeys = map[string]struct{}{
|
||
|
keyFromCurrent: {},
|
||
|
keyHost: {},
|
||
|
keyCA: {},
|
||
|
keyCert: {},
|
||
|
keyKey: {},
|
||
|
keySkipTLSVerify: {},
|
||
|
}
|
||
|
allowedKubernetesConfigKeys = map[string]struct{}{
|
||
|
keyFromCurrent: {},
|
||
|
keyKubeconfig: {},
|
||
|
keyKubecontext: {},
|
||
|
keyKubenamespace: {},
|
||
|
}
|
||
|
dockerConfigKeysDescriptions = []configKeyDescription{
|
||
|
{
|
||
|
name: keyFromCurrent,
|
||
|
description: "Copy current Docker endpoint configuration",
|
||
|
},
|
||
|
{
|
||
|
name: keyHost,
|
||
|
description: "Docker endpoint on which to connect",
|
||
|
},
|
||
|
{
|
||
|
name: keyCA,
|
||
|
description: "Trust certs signed only by this CA",
|
||
|
},
|
||
|
{
|
||
|
name: keyCert,
|
||
|
description: "Path to TLS certificate file",
|
||
|
},
|
||
|
{
|
||
|
name: keyKey,
|
||
|
description: "Path to TLS key file",
|
||
|
},
|
||
|
{
|
||
|
name: keySkipTLSVerify,
|
||
|
description: "Skip TLS certificate validation",
|
||
|
},
|
||
|
}
|
||
|
kubernetesConfigKeysDescriptions = []configKeyDescription{
|
||
|
{
|
||
|
name: keyFromCurrent,
|
||
|
description: "Copy current Kubernetes endpoint configuration",
|
||
|
},
|
||
|
{
|
||
|
name: keyKubeconfig,
|
||
|
description: "Path to a Kubernetes config file",
|
||
|
},
|
||
|
{
|
||
|
name: keyKubecontext,
|
||
|
description: "Overrides the context set in the kubernetes config file",
|
||
|
},
|
||
|
{
|
||
|
name: keyKubenamespace,
|
||
|
description: "Overrides the namespace set in the kubernetes config file",
|
||
|
},
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func parseBool(config map[string]string, name string) (bool, error) {
|
||
|
strVal, ok := config[name]
|
||
|
if !ok {
|
||
|
return false, nil
|
||
|
}
|
||
|
res, err := strconv.ParseBool(strVal)
|
||
|
return res, errors.Wrap(err, name)
|
||
|
}
|
||
|
|
||
|
func validateConfig(config map[string]string, allowedKeys map[string]struct{}) error {
|
||
|
var errs []string
|
||
|
for k := range config {
|
||
|
if _, ok := allowedKeys[k]; !ok {
|
||
|
errs = append(errs, fmt.Sprintf("%s: unrecognized config key", k))
|
||
|
}
|
||
|
}
|
||
|
if len(errs) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
return errors.New(strings.Join(errs, "\n"))
|
||
|
}
|
||
|
|
||
|
func getDockerEndpoint(dockerCli command.Cli, config map[string]string) (docker.Endpoint, error) {
|
||
|
if err := validateConfig(config, allowedDockerConfigKeys); err != nil {
|
||
|
return docker.Endpoint{}, err
|
||
|
}
|
||
|
fromCurrent, err := parseBool(config, keyFromCurrent)
|
||
|
if err != nil {
|
||
|
return docker.Endpoint{}, err
|
||
|
}
|
||
|
if fromCurrent {
|
||
|
return dockerCli.DockerEndpoint(), nil
|
||
|
}
|
||
|
tlsData, err := context.TLSDataFromFiles(config[keyCA], config[keyCert], config[keyKey])
|
||
|
if err != nil {
|
||
|
return docker.Endpoint{}, err
|
||
|
}
|
||
|
skipTLSVerify, err := parseBool(config, keySkipTLSVerify)
|
||
|
if err != nil {
|
||
|
return docker.Endpoint{}, err
|
||
|
}
|
||
|
ep := docker.Endpoint{
|
||
|
EndpointMeta: docker.EndpointMeta{
|
||
|
Host: config[keyHost],
|
||
|
SkipTLSVerify: skipTLSVerify,
|
||
|
},
|
||
|
TLSData: tlsData,
|
||
|
}
|
||
|
// try to resolve a docker client, validating the configuration
|
||
|
opts, err := ep.ClientOpts()
|
||
|
if err != nil {
|
||
|
return docker.Endpoint{}, errors.Wrap(err, "invalid docker endpoint options")
|
||
|
}
|
||
|
if _, err := client.NewClientWithOpts(opts...); err != nil {
|
||
|
return docker.Endpoint{}, errors.Wrap(err, "unable to apply docker endpoint options")
|
||
|
}
|
||
|
return ep, nil
|
||
|
}
|
||
|
|
||
|
func getDockerEndpointMetadataAndTLS(dockerCli command.Cli, config map[string]string) (docker.EndpointMeta, *store.EndpointTLSData, error) {
|
||
|
ep, err := getDockerEndpoint(dockerCli, config)
|
||
|
if err != nil {
|
||
|
return docker.EndpointMeta{}, nil, err
|
||
|
}
|
||
|
return ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil
|
||
|
}
|
||
|
|
||
|
func getKubernetesEndpoint(dockerCli command.Cli, config map[string]string) (*kubernetes.Endpoint, error) {
|
||
|
if err := validateConfig(config, allowedKubernetesConfigKeys); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if len(config) == 0 {
|
||
|
return nil, nil
|
||
|
}
|
||
|
fromCurrent, err := parseBool(config, keyFromCurrent)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if fromCurrent {
|
||
|
if dockerCli.CurrentContext() != "" {
|
||
|
ctxMeta, err := dockerCli.ContextStore().GetContextMetadata(dockerCli.CurrentContext())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
endpointMeta := kubernetes.EndpointFromContext(ctxMeta)
|
||
|
if endpointMeta != nil {
|
||
|
res, err := endpointMeta.WithTLSData(dockerCli.ContextStore(), dockerCli.CurrentContext())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &res, nil
|
||
|
}
|
||
|
}
|
||
|
// fallback to env-based kubeconfig
|
||
|
kubeconfig := os.Getenv("KUBECONFIG")
|
||
|
if kubeconfig == "" {
|
||
|
kubeconfig = filepath.Join(homedir.Get(), ".kube/config")
|
||
|
}
|
||
|
ep, err := kubernetes.FromKubeConfig(kubeconfig, "", "")
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &ep, nil
|
||
|
}
|
||
|
if config[keyKubeconfig] != "" {
|
||
|
ep, err := kubernetes.FromKubeConfig(config[keyKubeconfig], config[keyKubecontext], config[keyKubenamespace])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &ep, nil
|
||
|
}
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func getKubernetesEndpointMetadataAndTLS(dockerCli command.Cli, config map[string]string) (*kubernetes.EndpointMeta, *store.EndpointTLSData, error) {
|
||
|
ep, err := getKubernetesEndpoint(dockerCli, config)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
if ep == nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
return &ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil
|
||
|
}
|