github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/context/options.go (about)

     1  package context
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/docker/cli/cli/command"
     9  	"github.com/docker/cli/cli/context"
    10  	"github.com/docker/cli/cli/context/docker"
    11  	"github.com/docker/cli/cli/context/store"
    12  	"github.com/docker/docker/client"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  const (
    17  	keyFrom          = "from"
    18  	keyHost          = "host"
    19  	keyCA            = "ca"
    20  	keyCert          = "cert"
    21  	keyKey           = "key"
    22  	keySkipTLSVerify = "skip-tls-verify"
    23  )
    24  
    25  type configKeyDescription struct {
    26  	name        string
    27  	description string
    28  }
    29  
    30  var (
    31  	allowedDockerConfigKeys = map[string]struct{}{
    32  		keyFrom:          {},
    33  		keyHost:          {},
    34  		keyCA:            {},
    35  		keyCert:          {},
    36  		keyKey:           {},
    37  		keySkipTLSVerify: {},
    38  	}
    39  	dockerConfigKeysDescriptions = []configKeyDescription{
    40  		{
    41  			name:        keyFrom,
    42  			description: "Copy named context's Docker endpoint configuration",
    43  		},
    44  		{
    45  			name:        keyHost,
    46  			description: "Docker endpoint on which to connect",
    47  		},
    48  		{
    49  			name:        keyCA,
    50  			description: "Trust certs signed only by this CA",
    51  		},
    52  		{
    53  			name:        keyCert,
    54  			description: "Path to TLS certificate file",
    55  		},
    56  		{
    57  			name:        keyKey,
    58  			description: "Path to TLS key file",
    59  		},
    60  		{
    61  			name:        keySkipTLSVerify,
    62  			description: "Skip TLS certificate validation",
    63  		},
    64  	}
    65  )
    66  
    67  func parseBool(config map[string]string, name string) (bool, error) {
    68  	strVal, ok := config[name]
    69  	if !ok {
    70  		return false, nil
    71  	}
    72  	res, err := strconv.ParseBool(strVal)
    73  	return res, errors.Wrap(err, name)
    74  }
    75  
    76  func validateConfig(config map[string]string, allowedKeys map[string]struct{}) error {
    77  	var errs []string
    78  	for k := range config {
    79  		if _, ok := allowedKeys[k]; !ok {
    80  			errs = append(errs, fmt.Sprintf("%s: unrecognized config key", k))
    81  		}
    82  	}
    83  	if len(errs) == 0 {
    84  		return nil
    85  	}
    86  	return errors.New(strings.Join(errs, "\n"))
    87  }
    88  
    89  func getDockerEndpoint(dockerCli command.Cli, config map[string]string) (docker.Endpoint, error) {
    90  	if err := validateConfig(config, allowedDockerConfigKeys); err != nil {
    91  		return docker.Endpoint{}, err
    92  	}
    93  	if contextName, ok := config[keyFrom]; ok {
    94  		metadata, err := dockerCli.ContextStore().GetMetadata(contextName)
    95  		if err != nil {
    96  			return docker.Endpoint{}, err
    97  		}
    98  		if ep, ok := metadata.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta); ok {
    99  			return docker.Endpoint{EndpointMeta: ep}, nil
   100  		}
   101  		return docker.Endpoint{}, errors.Errorf("unable to get endpoint from context %q", contextName)
   102  	}
   103  	tlsData, err := context.TLSDataFromFiles(config[keyCA], config[keyCert], config[keyKey])
   104  	if err != nil {
   105  		return docker.Endpoint{}, err
   106  	}
   107  	skipTLSVerify, err := parseBool(config, keySkipTLSVerify)
   108  	if err != nil {
   109  		return docker.Endpoint{}, err
   110  	}
   111  	ep := docker.Endpoint{
   112  		EndpointMeta: docker.EndpointMeta{
   113  			Host:          config[keyHost],
   114  			SkipTLSVerify: skipTLSVerify,
   115  		},
   116  		TLSData: tlsData,
   117  	}
   118  	// try to resolve a docker client, validating the configuration
   119  	opts, err := ep.ClientOpts()
   120  	if err != nil {
   121  		return docker.Endpoint{}, errors.Wrap(err, "invalid docker endpoint options")
   122  	}
   123  	if _, err := client.NewClientWithOpts(opts...); err != nil {
   124  		return docker.Endpoint{}, errors.Wrap(err, "unable to apply docker endpoint options")
   125  	}
   126  	return ep, nil
   127  }
   128  
   129  func getDockerEndpointMetadataAndTLS(dockerCli command.Cli, config map[string]string) (docker.EndpointMeta, *store.EndpointTLSData, error) {
   130  	ep, err := getDockerEndpoint(dockerCli, config)
   131  	if err != nil {
   132  		return docker.EndpointMeta{}, nil, err
   133  	}
   134  	return ep.EndpointMeta, ep.TLSData.ToStoreTLSData(), nil
   135  }