mirror of https://github.com/docker/docs.git
201 lines
6.0 KiB
Go
201 lines
6.0 KiB
Go
package libmachine
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"io"
|
|
|
|
"github.com/docker/machine/drivers/errdriver"
|
|
"github.com/docker/machine/libmachine/auth"
|
|
"github.com/docker/machine/libmachine/cert"
|
|
"github.com/docker/machine/libmachine/check"
|
|
"github.com/docker/machine/libmachine/crashreport"
|
|
"github.com/docker/machine/libmachine/drivers"
|
|
"github.com/docker/machine/libmachine/drivers/plugin/localbinary"
|
|
"github.com/docker/machine/libmachine/drivers/rpc"
|
|
"github.com/docker/machine/libmachine/engine"
|
|
"github.com/docker/machine/libmachine/host"
|
|
"github.com/docker/machine/libmachine/log"
|
|
"github.com/docker/machine/libmachine/mcnutils"
|
|
"github.com/docker/machine/libmachine/persist"
|
|
"github.com/docker/machine/libmachine/provision"
|
|
"github.com/docker/machine/libmachine/ssh"
|
|
"github.com/docker/machine/libmachine/state"
|
|
"github.com/docker/machine/libmachine/swarm"
|
|
"github.com/docker/machine/libmachine/version"
|
|
)
|
|
|
|
type API interface {
|
|
io.Closer
|
|
NewHost(driverName string, rawDriver []byte) (*host.Host, error)
|
|
Create(h *host.Host) error
|
|
persist.Store
|
|
}
|
|
|
|
type Client struct {
|
|
IsDebug bool
|
|
SSHClientType ssh.ClientType
|
|
GithubAPIToken string
|
|
*persist.Filestore
|
|
clientDriverFactory rpcdriver.RPCClientDriverFactory
|
|
}
|
|
|
|
func NewClient(storePath string) *Client {
|
|
certsDir := filepath.Join(storePath, ".docker", "machine", "certs")
|
|
return &Client{
|
|
IsDebug: false,
|
|
SSHClientType: ssh.External,
|
|
Filestore: persist.NewFilestore(storePath, certsDir, certsDir),
|
|
clientDriverFactory: rpcdriver.NewRPCClientDriverFactory(),
|
|
}
|
|
}
|
|
|
|
func (api *Client) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
|
|
driver, err := api.clientDriverFactory.NewRPCClientDriver(driverName, rawDriver)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certDir := filepath.Join(api.Path, "certs")
|
|
|
|
return &host.Host{
|
|
ConfigVersion: version.ConfigVersion,
|
|
Name: driver.GetMachineName(),
|
|
Driver: driver,
|
|
DriverName: driver.DriverName(),
|
|
HostOptions: &host.Options{
|
|
AuthOptions: &auth.Options{
|
|
CertDir: certDir,
|
|
CaCertPath: filepath.Join(certDir, "ca.pem"),
|
|
CaPrivateKeyPath: filepath.Join(certDir, "ca-key.pem"),
|
|
ClientCertPath: filepath.Join(certDir, "cert.pem"),
|
|
ClientKeyPath: filepath.Join(certDir, "key.pem"),
|
|
ServerCertPath: filepath.Join(api.GetMachinesDir(), "server.pem"),
|
|
ServerKeyPath: filepath.Join(api.GetMachinesDir(), "server-key.pem"),
|
|
},
|
|
EngineOptions: &engine.Options{
|
|
InstallURL: "https://get.docker.com",
|
|
StorageDriver: "aufs",
|
|
TLSVerify: true,
|
|
},
|
|
SwarmOptions: &swarm.Options{
|
|
Host: "tcp://0.0.0.0:3376",
|
|
Image: "swarm:latest",
|
|
Strategy: "spread",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (api *Client) Load(name string) (*host.Host, error) {
|
|
h, err := api.Filestore.Load(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d, err := api.clientDriverFactory.NewRPCClientDriver(h.DriverName, h.RawDriver)
|
|
if err != nil {
|
|
// Not being able to find a driver binary is a "known error"
|
|
if _, ok := err.(localbinary.ErrPluginBinaryNotFound); ok {
|
|
h.Driver = errdriver.NewDriver(h.DriverName)
|
|
return h, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
if h.DriverName == "virtualbox" {
|
|
h.Driver = drivers.NewSerialDriver(d)
|
|
} else {
|
|
h.Driver = d
|
|
}
|
|
|
|
return h, nil
|
|
}
|
|
|
|
// Create is the wrapper method which covers all of the boilerplate around
|
|
// actually creating, provisioning, and persisting an instance in the store.
|
|
func (api *Client) Create(h *host.Host) error {
|
|
if err := cert.BootstrapCertificates(h.HostOptions.AuthOptions); err != nil {
|
|
return fmt.Errorf("Error generating certificates: %s", err)
|
|
}
|
|
|
|
log.Info("Running pre-create checks...")
|
|
|
|
if err := h.Driver.PreCreateCheck(); err != nil {
|
|
return fmt.Errorf("Error with pre-create check: %s", err)
|
|
}
|
|
|
|
if err := api.Save(h); err != nil {
|
|
return fmt.Errorf("Error saving host to store before attempting creation: %s", err)
|
|
}
|
|
|
|
log.Info("Creating machine...")
|
|
|
|
if err := api.performCreate(h); err != nil {
|
|
sendCrashReport(err, api, h)
|
|
return err
|
|
}
|
|
|
|
log.Debug("Reticulating splines...")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (api *Client) performCreate(h *host.Host) error {
|
|
if err := h.Driver.Create(); err != nil {
|
|
return fmt.Errorf("Error in driver during machine creation: %s", err)
|
|
}
|
|
|
|
if err := api.Save(h); err != nil {
|
|
return fmt.Errorf("Error saving host to store after attempting creation: %s", err)
|
|
}
|
|
|
|
// TODO: Not really a fan of just checking "none" here.
|
|
if h.Driver.DriverName() != "none" {
|
|
log.Info("Waiting for machine to be running, this may take a few minutes...")
|
|
if err := mcnutils.WaitFor(drivers.MachineInState(h.Driver, state.Running)); err != nil {
|
|
return fmt.Errorf("Error waiting for machine to be running: %s", err)
|
|
}
|
|
|
|
log.Info("Machine is running, waiting for SSH to be available...")
|
|
if err := drivers.WaitForSSH(h.Driver); err != nil {
|
|
return fmt.Errorf("Error waiting for SSH: %s", err)
|
|
}
|
|
|
|
log.Info("Detecting operating system of created instance...")
|
|
provisioner, err := provision.DetectProvisioner(h.Driver)
|
|
if err != nil {
|
|
return fmt.Errorf("Error detecting OS: %s", err)
|
|
}
|
|
|
|
log.Infof("Provisioning with %s...", provisioner.String())
|
|
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!")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func sendCrashReport(err error, api *Client, host *host.Host) {
|
|
if host.DriverName == "virtualbox" {
|
|
vboxlogPath := filepath.Join(api.GetMachinesDir(), host.Name, host.Name, "Logs", "VBox.log")
|
|
crashreport.SendWithFile(err, "api.performCreate", host.DriverName, "Create", vboxlogPath)
|
|
} else {
|
|
crashreport.Send(err, "api.performCreate", host.DriverName, "Create")
|
|
}
|
|
}
|
|
|
|
func (api *Client) Close() error {
|
|
return api.clientDriverFactory.Close()
|
|
}
|