package commands import ( "fmt" "net/url" "os" "strings" "github.com/docker/machine/cli" "github.com/docker/machine/libmachine/auth" "github.com/docker/machine/libmachine/cert" "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/state" ) func cmdConfig(c *cli.Context) { // Ensure that log messages always go to stderr when this command is // being run (it is intended to be run in a subshell) log.SetOutWriter(os.Stderr) if len(c.Args()) != 1 { fatal(ErrExpectedOneMachine) } h := getFirstArgHost(c) dockerHost, authOptions, err := runConnectionBoilerplate(h, c) if err != nil { fatalf("Error running connection boilerplate: %s", err) } log.Debug(dockerHost) fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s", authOptions.CaCertPath, authOptions.ClientCertPath, authOptions.ClientKeyPath, dockerHost) } func runConnectionBoilerplate(h *host.Host, c *cli.Context) (string, *auth.AuthOptions, error) { hostState, err := h.Driver.GetState() if err != nil { // TODO: This is a common operation and should have a commonly // defined error. return "", &auth.AuthOptions{}, fmt.Errorf("Error trying to get host state: %s", err) } if hostState != state.Running { return "", &auth.AuthOptions{}, fmt.Errorf("%s is not running. Please start it in order to use the connection settings.", h.Name) } dockerHost, err := h.Driver.GetURL() if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error getting driver URL: %s", err) } if c.Bool("swarm") { var err error dockerHost, err = parseSwarm(dockerHost, h) if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing swarm: %s", err) } } u, err := url.Parse(dockerHost) if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing URL: %s", err) } authOptions := h.HostOptions.AuthOptions if err := checkCert(u.Host, authOptions, c); err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err) } return dockerHost, authOptions, nil } func checkCert(hostUrl string, authOptions *auth.AuthOptions, c *cli.Context) error { valid, err := cert.ValidateCertificate( hostUrl, authOptions.CaCertPath, authOptions.ServerCertPath, authOptions.ServerKeyPath, ) if err != nil { return fmt.Errorf("Error attempting to validate the certificates: %s", err) } if !valid { log.Errorf("Invalid certs detected; regenerating for %s", hostUrl) if err := runActionWithContext("configureAuth", c); err != nil { return fmt.Errorf("Error attempting to regenerate the certs: %s", err) } } return nil } // TODO: This could use a unit test. func parseSwarm(hostUrl string, h *host.Host) (string, error) { swarmOptions := h.HostOptions.SwarmOptions if !swarmOptions.Master { return "", fmt.Errorf("Error: %s is not a swarm master. The --swarm flag is intended for use with swarm masters.", h.Name) } u, err := url.Parse(swarmOptions.Host) if err != nil { return "", fmt.Errorf("There was an error parsing the url: %s", err) } parts := strings.Split(u.Host, ":") swarmPort := parts[1] // get IP of machine to replace in case swarm host is 0.0.0.0 mUrl, err := url.Parse(hostUrl) if err != nil { return "", fmt.Errorf("There was an error parsing the url: %s", err) } mParts := strings.Split(mUrl.Host, ":") machineIp := mParts[0] hostUrl = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort) return hostUrl, nil }