mirror of https://github.com/docker/docs.git
Merge pull request #2434 from dgageot/check-after-create
Check machine after create
This commit is contained in:
commit
f7ea3d9f19
|
|
@ -2,39 +2,13 @@ package commands
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/cert"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine/check"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultConnChecker ConnChecker
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultConnChecker = &MachineConnChecker{}
|
||||
}
|
||||
|
||||
// ErrCertInvalid for when the cert is computed to be invalid.
|
||||
type ErrCertInvalid struct {
|
||||
wrappedErr error
|
||||
hostURL string
|
||||
}
|
||||
|
||||
func (e ErrCertInvalid) Error() string {
|
||||
return fmt.Sprintf(`There was an error validating certificates for host %q: %s
|
||||
You can attempt to regenerate them using 'docker-machine regenerate-certs [name]'.
|
||||
Be advised that this will trigger a Docker daemon restart which will stop running containers.
|
||||
`, e.hostURL, e.wrappedErr)
|
||||
}
|
||||
|
||||
func cmdConfig(c CommandLine, api libmachine.API) error {
|
||||
// Ensure that log messages always go to stderr when this command is
|
||||
// being run (it is intended to be run in a subshell)
|
||||
|
|
@ -49,7 +23,7 @@ func cmdConfig(c CommandLine, api libmachine.API) error {
|
|||
return err
|
||||
}
|
||||
|
||||
dockerHost, authOptions, err := defaultConnChecker.Check(host, c.Bool("swarm"))
|
||||
dockerHost, authOptions, err := check.DefaultConnChecker.Check(host, c.Bool("swarm"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error running connection boilerplate: %s", err)
|
||||
}
|
||||
|
|
@ -61,88 +35,3 @@ func cmdConfig(c CommandLine, api libmachine.API) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ConnChecker interface {
|
||||
Check(*host.Host, bool) (string, *auth.Options, error)
|
||||
}
|
||||
|
||||
type MachineConnChecker struct{}
|
||||
|
||||
func (mcc *MachineConnChecker) Check(h *host.Host, swarm bool) (string, *auth.Options, error) {
|
||||
hostState, err := h.Driver.GetState()
|
||||
if err != nil {
|
||||
// TODO: This is a common operation and should have a commonly
|
||||
// defined error.
|
||||
return "", &auth.Options{}, fmt.Errorf("Error trying to get host state: %s", err)
|
||||
}
|
||||
if hostState != state.Running {
|
||||
return "", &auth.Options{}, 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.Options{}, fmt.Errorf("Error getting driver URL: %s", err)
|
||||
}
|
||||
|
||||
if swarm {
|
||||
var err error
|
||||
dockerHost, err = parseSwarm(dockerHost, h)
|
||||
if err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error parsing swarm: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := url.Parse(dockerHost)
|
||||
if err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error parsing URL: %s", err)
|
||||
}
|
||||
|
||||
authOptions := h.HostOptions.AuthOptions
|
||||
|
||||
if err := checkCert(u.Host, authOptions); err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err)
|
||||
}
|
||||
|
||||
return dockerHost, authOptions, nil
|
||||
}
|
||||
|
||||
func checkCert(hostURL string, authOptions *auth.Options) error {
|
||||
valid, err := cert.ValidateCertificate(hostURL, authOptions)
|
||||
if !valid || err != nil {
|
||||
return ErrCertInvalid{
|
||||
wrappedErr: err,
|
||||
hostURL: hostURL,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/docker/machine/commands/mcndirs"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/check"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ func shellCfgSet(c CommandLine, api libmachine.API) (*ShellConfig, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
dockerHost, _, err := defaultConnChecker.Check(host, c.Bool("swarm"))
|
||||
dockerHost, _, err := check.DefaultConnChecker.Check(host, c.Bool("swarm"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error checking TLS connection: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/machine/drivers/fakedriver"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/check"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine/libmachinetest"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
|
|
@ -90,7 +91,7 @@ func TestShellCfgSet(t *testing.T) {
|
|||
description string
|
||||
commandLine CommandLine
|
||||
api libmachine.API
|
||||
connChecker ConnChecker
|
||||
connChecker check.ConnChecker
|
||||
noProxyVar string
|
||||
noProxyValue string
|
||||
expectedShellCfg *ShellConfig
|
||||
|
|
@ -345,7 +346,7 @@ func TestShellCfgSet(t *testing.T) {
|
|||
|
||||
t.Log(test.description)
|
||||
|
||||
defaultConnChecker = test.connChecker
|
||||
check.DefaultConnChecker = test.connChecker
|
||||
shellCfg, err := shellCfgSet(test.commandLine, test.api)
|
||||
assert.Equal(t, test.expectedShellCfg, shellCfg)
|
||||
assert.Equal(t, test.expectedErr, err)
|
||||
|
|
@ -366,7 +367,7 @@ func TestShellCfgUnset(t *testing.T) {
|
|||
description string
|
||||
commandLine CommandLine
|
||||
api libmachine.API
|
||||
connChecker ConnChecker
|
||||
connChecker check.ConnChecker
|
||||
noProxyVar string
|
||||
noProxyValue string
|
||||
expectedShellCfg *ShellConfig
|
||||
|
|
@ -496,7 +497,7 @@ func TestShellCfgUnset(t *testing.T) {
|
|||
|
||||
t.Log(test.description)
|
||||
|
||||
defaultConnChecker = test.connChecker
|
||||
check.DefaultConnChecker = test.connChecker
|
||||
shellCfg, err := shellCfgUnset(test.commandLine, test.api)
|
||||
assert.Equal(t, test.expectedShellCfg, shellCfg)
|
||||
assert.Equal(t, test.expectedErr, err)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
package check
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/cert"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultConnChecker ConnChecker
|
||||
)
|
||||
|
||||
func init() {
|
||||
DefaultConnChecker = &MachineConnChecker{}
|
||||
}
|
||||
|
||||
// ErrCertInvalid for when the cert is computed to be invalid.
|
||||
type ErrCertInvalid struct {
|
||||
wrappedErr error
|
||||
hostURL string
|
||||
}
|
||||
|
||||
func (e ErrCertInvalid) Error() string {
|
||||
return fmt.Sprintf(`There was an error validating certificates for host %q: %s
|
||||
You can attempt to regenerate them using 'docker-machine regenerate-certs [name]'.
|
||||
Be advised that this will trigger a Docker daemon restart which will stop running containers.
|
||||
`, e.hostURL, e.wrappedErr)
|
||||
}
|
||||
|
||||
type ConnChecker interface {
|
||||
Check(*host.Host, bool) (dockerHost string, authOptions *auth.Options, err error)
|
||||
}
|
||||
|
||||
type MachineConnChecker struct{}
|
||||
|
||||
func (mcc *MachineConnChecker) Check(h *host.Host, swarm bool) (string, *auth.Options, error) {
|
||||
hostState, err := h.Driver.GetState()
|
||||
if err != nil {
|
||||
// TODO: This is a common operation and should have a commonly
|
||||
// defined error.
|
||||
return "", &auth.Options{}, fmt.Errorf("Error trying to get host state: %s", err)
|
||||
}
|
||||
if hostState != state.Running {
|
||||
return "", &auth.Options{}, 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.Options{}, fmt.Errorf("Error getting driver URL: %s", err)
|
||||
}
|
||||
|
||||
if swarm {
|
||||
var err error
|
||||
dockerHost, err = parseSwarm(dockerHost, h)
|
||||
if err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error parsing swarm: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := url.Parse(dockerHost)
|
||||
if err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error parsing URL: %s", err)
|
||||
}
|
||||
|
||||
authOptions := h.HostOptions.AuthOptions
|
||||
|
||||
if err := checkCert(u.Host, authOptions); err != nil {
|
||||
return "", &auth.Options{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err)
|
||||
}
|
||||
|
||||
return dockerHost, authOptions, nil
|
||||
}
|
||||
|
||||
func checkCert(hostURL string, authOptions *auth.Options) error {
|
||||
valid, err := cert.ValidateCertificate(hostURL, authOptions)
|
||||
if !valid || err != nil {
|
||||
return ErrCertInvalid{
|
||||
wrappedErr: err,
|
||||
hostURL: hostURL,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package commands
|
||||
package check
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/cert"
|
||||
"github.com/docker/machine/libmachine/check"
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"github.com/docker/machine/libmachine/engine"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
|
|
@ -125,6 +126,14 @@ func (api *Client) Create(h *host.Host) error {
|
|||
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil {
|
||||
return fmt.Errorf("Error running provisioning: %s", err)
|
||||
}
|
||||
|
||||
// We should check the connection to docker here
|
||||
log.Info("Checking connection to Docker...")
|
||||
if _, _, err = check.DefaultConnChecker.Check(h, false); err != nil {
|
||||
return fmt.Errorf("Error checking the host: %s", err)
|
||||
}
|
||||
|
||||
log.Info("Docker is up and running!")
|
||||
}
|
||||
|
||||
log.Debug("Reticulating splines...")
|
||||
|
|
|
|||
Loading…
Reference in New Issue