Add docker-machine provision command

Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
Nathan LeClaire 2015-10-29 10:42:10 -07:00
parent 248596da8a
commit 01c7556e3a
7 changed files with 224 additions and 1 deletions

View File

@ -240,6 +240,11 @@ var Commands = []cli.Command{
},
},
},
{
Name: "provision",
Usage: "Re-provision existing machines",
Action: runCommand(cmdProvision),
},
{
Name: "regenerate-certs",
Usage: "Regenerate TLS Certificates for a machine",
@ -355,6 +360,7 @@ func machineCommand(actionName string, host *host.Host, errorChan chan<- error)
"kill": host.Kill,
"upgrade": host.Upgrade,
"ip": printIP(host),
"provision": host.Provision,
}
log.Debugf("command=%s machine=%s", actionName, host.Name)

7
commands/provision.go Normal file
View File

@ -0,0 +1,7 @@
package commands
import "github.com/docker/machine/libmachine"
func cmdProvision(c CommandLine, api libmachine.API) error {
return runAction("provision", c, api)
}

View File

@ -0,0 +1,68 @@
package commands
import (
"testing"
"github.com/docker/machine/commands/commandstest"
"github.com/docker/machine/drivers/fakedriver"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/libmachinetest"
"github.com/docker/machine/libmachine/provision"
"github.com/docker/machine/libmachine/provision/provisiontest"
"github.com/docker/machine/libmachine/swarm"
"github.com/stretchr/testify/assert"
)
func TestCmdProvision(t *testing.T) {
testCases := []struct {
commandLine CommandLine
api libmachine.API
expectedErr error
}{
{
commandLine: &commandstest.FakeCommandLine{
CliArgs: []string{"foo", "bar"},
},
api: &libmachinetest.FakeAPI{
Hosts: []*host.Host{
{
Name: "foo",
Driver: &fakedriver.Driver{},
HostOptions: &host.Options{
EngineOptions: &engine.Options{},
AuthOptions: &auth.Options{},
SwarmOptions: &swarm.Options{},
},
},
{
Name: "bar",
Driver: &fakedriver.Driver{},
HostOptions: &host.Options{
EngineOptions: &engine.Options{},
AuthOptions: &auth.Options{},
SwarmOptions: &swarm.Options{},
},
},
},
},
expectedErr: nil,
},
}
provision.SetDetector(&provisiontest.FakeDetector{
Provisioner: provisiontest.NewFakeProvisioner(nil),
})
// fakeprovisioner always returns "true" for compatible host, so we
// just need to register it.
provision.Register("fakeprovisioner", &provision.RegisteredProvisioner{
New: provisiontest.NewFakeProvisioner,
})
for _, tc := range testCases {
assert.Equal(t, tc.expectedErr, cmdProvision(tc.commandLine, tc.api))
}
}

View File

@ -0,0 +1,37 @@
<!--[metadata]>
+++
title = "provision"
description = "Re-run provisioning on a created machine."
keywords = ["machine, provision, subcommand"]
[menu.main]
parent="smn_machine_subcmds"
+++
<![end-metadata]-->
# provision
Re-run provisioning on a created machine.
Sometimes it may be helpful to re-run Machine's provisioning process on a
created machine. Reasons for doing so may include a failure during the original
provisioning process, or a drift from the desired system state (including the
originally specified Swarm or Engine configuration).
Usage is `docker-machine provision [name]`. Multiple names may be specified.
$ docker-machine provision foo bar
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
The Machine provisioning process will:
1. Set the hostname on the instance to the name Machine addresses it by (e.g.
`default`).
2. Install Docker if it is not present already.
3. Generate a set of certificates (usually with the default, self-signed CA) and
configure the daemon to accept connections over TLS.
4. Copy the generated certificates to the server and local config directory.
5. Configure the Docker Engine according to the options specified at create
time.
6. Configure and activate Swarm if applicable.

View File

@ -192,3 +192,12 @@ func (h *Host) ConfigureAuth() error {
// Call provision to re-provision the certs properly.
return provisioner.Provision(swarm.Options{}, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions)
}
func (h *Host) Provision() error {
provisioner, err := provision.DetectProvisioner(h.Driver)
if err != nil {
return err
}
return provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions)
}

View File

@ -12,13 +12,26 @@ import (
"github.com/docker/machine/libmachine/swarm"
)
var provisioners = make(map[string]*RegisteredProvisioner)
var (
provisioners = make(map[string]*RegisteredProvisioner)
detector Detector = &StandardDetector{}
)
type SSHCommander interface {
// Short-hand for accessing an SSH command from the driver.
SSHCommand(args string) (string, error)
}
type Detector interface {
DetectProvisioner(d drivers.Driver) (Provisioner, error)
}
type StandardDetector struct{}
func SetDetector(newDetector Detector) {
detector = newDetector
}
// Provisioner defines distribution specific actions
type Provisioner interface {
fmt.Stringer
@ -77,6 +90,10 @@ func Register(name string, p *RegisteredProvisioner) {
}
func DetectProvisioner(d drivers.Driver) (Provisioner, error) {
return detector.DetectProvisioner(d)
}
func (detector StandardDetector) DetectProvisioner(d drivers.Driver) (Provisioner, error) {
log.Info("Detecting the provisioner...")
osReleaseOut, err := drivers.RunSSHCommandFromDriver(d, "cat /etc/os-release")

View File

@ -0,0 +1,79 @@
package provisiontest
import (
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/provision"
"github.com/docker/machine/libmachine/provision/pkgaction"
"github.com/docker/machine/libmachine/provision/serviceaction"
"github.com/docker/machine/libmachine/swarm"
)
type FakeDetector struct {
provision.Provisioner
}
func (fd *FakeDetector) DetectProvisioner(d drivers.Driver) (provision.Provisioner, error) {
return fd.Provisioner, nil
}
type FakeProvisioner struct{}
func NewFakeProvisioner(d drivers.Driver) provision.Provisioner {
return &FakeProvisioner{}
}
func (fp *FakeProvisioner) SSHCommand(args string) (string, error) {
return "", nil
}
func (fp *FakeProvisioner) String() string {
return "fakeprovisioner"
}
func (fp *FakeProvisioner) GenerateDockerOptions(dockerPort int) (*provision.DockerOptions, error) {
return nil, nil
}
func (fp *FakeProvisioner) GetDockerOptionsDir() string {
return ""
}
func (fp *FakeProvisioner) GetAuthOptions() auth.Options {
return auth.Options{}
}
func (fp *FakeProvisioner) Package(name string, action pkgaction.PackageAction) error {
return nil
}
func (fp *FakeProvisioner) Hostname() (string, error) {
return "", nil
}
func (fp *FakeProvisioner) SetHostname(hostname string) error {
return nil
}
func (fp *FakeProvisioner) CompatibleWithHost() bool {
return true
}
func (fp *FakeProvisioner) Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error {
return nil
}
func (fp *FakeProvisioner) Service(name string, action serviceaction.ServiceAction) error {
return nil
}
func (fp *FakeProvisioner) GetDriver() drivers.Driver {
return nil
}
func (fp *FakeProvisioner) SetOsReleaseInfo(info *provision.OsRelease) {}
func (fp *FakeProvisioner) GetOsReleaseInfo() (*provision.OsRelease, error) {
return nil, nil
}