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 }