mirror of https://github.com/docker/docs.git
Revise CommandLine interface to contain libmachine client and store
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
parent
3affe5ec25
commit
19ce7b79bd
|
@ -10,8 +10,6 @@ import (
|
|||
"github.com/docker/machine/commands"
|
||||
"github.com/docker/machine/commands/mcndirs"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/mcnutils"
|
||||
"github.com/docker/machine/libmachine/ssh"
|
||||
"github.com/docker/machine/version"
|
||||
)
|
||||
|
||||
|
@ -74,16 +72,6 @@ func main() {
|
|||
app.Name = path.Base(os.Args[0])
|
||||
app.Author = "Docker Machine Contributors"
|
||||
app.Email = "https://github.com/docker/machine"
|
||||
app.Before = func(c *cli.Context) error {
|
||||
// TODO: Need better handling of config, everything is too
|
||||
// complected together right now.
|
||||
if c.GlobalBool("native-ssh") {
|
||||
ssh.SetDefaultClient(ssh.Native)
|
||||
}
|
||||
mcnutils.GithubAPIToken = c.GlobalString("github-api-token")
|
||||
mcndirs.BaseDir = c.GlobalString("storage-path")
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = commands.Commands
|
||||
app.CommandNotFound = cmdNotFound
|
||||
|
|
|
@ -4,46 +4,33 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/persist"
|
||||
)
|
||||
|
||||
var (
|
||||
errTooManyArguments = errors.New("Error: Too many arguments given")
|
||||
errNoActiveHost = errors.New("No active host found")
|
||||
)
|
||||
|
||||
func cmdActive(c CommandLine) error {
|
||||
func cmdActive(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) > 0 {
|
||||
return errTooManyArguments
|
||||
}
|
||||
|
||||
store := getStore(c)
|
||||
|
||||
host, err := getActiveHost(store)
|
||||
hosts, err := persist.LoadAllHosts(api)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting active host: %s", err)
|
||||
}
|
||||
|
||||
if host != nil {
|
||||
fmt.Println(host.Name)
|
||||
}
|
||||
items := getHostListItems(hosts)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getActiveHost(store persist.Store) (*host.Host, error) {
|
||||
hosts, err := listHosts(store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hostListItems := getHostListItems(hosts)
|
||||
|
||||
for _, item := range hostListItems {
|
||||
for _, item := range items {
|
||||
if item.Active {
|
||||
return loadHost(store, item.Name)
|
||||
fmt.Println(item.Name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("Active host not found")
|
||||
return errNoActiveHost
|
||||
}
|
||||
|
|
|
@ -9,14 +9,13 @@ import (
|
|||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/machine/commands/mcndirs"
|
||||
"github.com/docker/machine/drivers/errdriver"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/cert"
|
||||
"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/host"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/mcnutils"
|
||||
"github.com/docker/machine/libmachine/persist"
|
||||
"github.com/docker/machine/libmachine/ssh"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -64,26 +63,49 @@ func (c *contextCommandLine) Application() *cli.App {
|
|||
return c.App
|
||||
}
|
||||
|
||||
func newPluginDriver(driverName string, rawContent []byte) (drivers.Driver, error) {
|
||||
d, err := rpcdriver.NewRPCClientDriver(rawContent, driverName)
|
||||
func runAction(actionName string, c CommandLine, api libmachine.API) error {
|
||||
hosts, err := persist.LoadHosts(api, c.Args())
|
||||
if err != nil {
|
||||
// Not being able to find a driver binary is a "known error"
|
||||
if _, ok := err.(localbinary.ErrPluginBinaryNotFound); ok {
|
||||
return errdriver.NewDriver(driverName), nil
|
||||
return err
|
||||
}
|
||||
|
||||
if len(hosts) == 0 {
|
||||
return ErrNoMachineSpecified
|
||||
}
|
||||
|
||||
if errs := runActionForeachMachine(actionName, hosts); len(errs) > 0 {
|
||||
return consolidateErrs(errs)
|
||||
}
|
||||
|
||||
for _, h := range hosts {
|
||||
if err := api.Save(h); err != nil {
|
||||
return fmt.Errorf("Error saving host to store: %s", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if driverName == "virtualbox" {
|
||||
return drivers.NewSerialDriver(d), nil
|
||||
}
|
||||
|
||||
return d, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func fatalOnError(command func(commandLine CommandLine) error) func(context *cli.Context) {
|
||||
func fatalOnError(command func(commandLine CommandLine, api libmachine.API) error) func(context *cli.Context) {
|
||||
return func(context *cli.Context) {
|
||||
if err := command(&contextCommandLine{context}); err != nil {
|
||||
api := libmachine.NewClient(mcndirs.GetBaseDir())
|
||||
|
||||
if context.GlobalBool("native-ssh") {
|
||||
api.SSHClientType = ssh.Native
|
||||
}
|
||||
api.GithubAPIToken = context.GlobalString("github-api-token")
|
||||
api.Filestore.Path = context.GlobalString("storage-path")
|
||||
|
||||
// TODO (nathanleclaire): These should ultimately be accessed
|
||||
// through the libmachine client by the rest of the code and
|
||||
// not through their respective modules. For now, however,
|
||||
// they are also being set the way that they originally were
|
||||
// set to preserve backwards compatibility.
|
||||
mcndirs.BaseDir = api.Filestore.Path
|
||||
mcnutils.GithubAPIToken = api.GithubAPIToken
|
||||
ssh.SetDefaultClient(api.SSHClientType)
|
||||
|
||||
if err := command(&contextCommandLine{context}, api); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -102,88 +124,6 @@ func confirmInput(msg string) (bool, error) {
|
|||
return confirmed, nil
|
||||
}
|
||||
|
||||
func getStore(c CommandLine) persist.Store {
|
||||
certInfo := getCertPathInfoFromContext(c)
|
||||
return &persist.Filestore{
|
||||
Path: c.GlobalString("storage-path"),
|
||||
CaCertPath: certInfo.CaCertPath,
|
||||
CaPrivateKeyPath: certInfo.CaPrivateKeyPath,
|
||||
}
|
||||
}
|
||||
|
||||
func listHosts(store persist.Store) ([]*host.Host, error) {
|
||||
cliHosts := []*host.Host{}
|
||||
|
||||
hosts, err := store.List()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error attempting to list hosts from store: %s", err)
|
||||
}
|
||||
|
||||
for _, h := range hosts {
|
||||
d, err := newPluginDriver(h.DriverName, h.RawDriver)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error attempting to invoke binary for plugin '%s': %s", h.DriverName, err)
|
||||
}
|
||||
|
||||
h.Driver = d
|
||||
|
||||
cliHosts = append(cliHosts, h)
|
||||
}
|
||||
|
||||
return cliHosts, nil
|
||||
}
|
||||
|
||||
func loadHost(store persist.Store, hostName string) (*host.Host, error) {
|
||||
h, err := store.Load(hostName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Loading host from store failed: %s", err)
|
||||
}
|
||||
|
||||
d, err := newPluginDriver(h.DriverName, h.RawDriver)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error attempting to invoke binary for plugin: %s", err)
|
||||
}
|
||||
|
||||
h.Driver = d
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func saveHost(store persist.Store, h *host.Host) error {
|
||||
if err := store.Save(h); err != nil {
|
||||
return fmt.Errorf("Error attempting to save host to store: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFirstArgHost(c CommandLine) (*host.Host, error) {
|
||||
store := getStore(c)
|
||||
hostName := c.Args().First()
|
||||
|
||||
h, err := loadHost(store, hostName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error trying to get host %q: %s", hostName, err)
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func getHostsFromContext(c CommandLine) ([]*host.Host, error) {
|
||||
store := getStore(c)
|
||||
hosts := []*host.Host{}
|
||||
|
||||
for _, hostName := range c.Args() {
|
||||
h, err := loadHost(store, hostName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not load host %q: %s", hostName, err)
|
||||
}
|
||||
hosts = append(hosts, h)
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
var Commands = []cli.Command{
|
||||
{
|
||||
Name: "active",
|
||||
|
@ -427,52 +367,27 @@ func consolidateErrs(errs []error) error {
|
|||
return errors.New(strings.TrimSpace(finalErr))
|
||||
}
|
||||
|
||||
func runActionWithContext(actionName string, c CommandLine) error {
|
||||
store := getStore(c)
|
||||
|
||||
hosts, err := getHostsFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(hosts) == 0 {
|
||||
return ErrNoMachineSpecified
|
||||
}
|
||||
|
||||
if errs := runActionForeachMachine(actionName, hosts); len(errs) > 0 {
|
||||
return consolidateErrs(errs)
|
||||
}
|
||||
|
||||
for _, h := range hosts {
|
||||
if err := saveHost(store, h); err != nil {
|
||||
return fmt.Errorf("Error saving host to store: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the cert paths.
|
||||
// codegangsta/cli will not set the cert paths if the storage-path is set to
|
||||
// something different so we cannot use the paths in the global options. le
|
||||
// sigh.
|
||||
func getCertPathInfoFromContext(c CommandLine) cert.PathInfo {
|
||||
// Returns the cert paths. codegangsta/cli will not set the cert paths if the
|
||||
// storage-path is set to something different so we cannot use the paths in the
|
||||
// global options. le sigh.
|
||||
func getCertPathInfoFromCommandLine(c CommandLine) cert.PathInfo {
|
||||
caCertPath := c.GlobalString("tls-ca-cert")
|
||||
caKeyPath := c.GlobalString("tls-ca-key")
|
||||
clientCertPath := c.GlobalString("tls-client-cert")
|
||||
clientKeyPath := c.GlobalString("tls-client-key")
|
||||
|
||||
if caCertPath == "" {
|
||||
caCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca.pem")
|
||||
}
|
||||
|
||||
caKeyPath := c.GlobalString("tls-ca-key")
|
||||
if caKeyPath == "" {
|
||||
caKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca-key.pem")
|
||||
}
|
||||
|
||||
clientCertPath := c.GlobalString("tls-client-cert")
|
||||
if clientCertPath == "" {
|
||||
clientCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "cert.pem")
|
||||
}
|
||||
|
||||
clientKeyPath := c.GlobalString("tls-client-key")
|
||||
if clientKeyPath == "" {
|
||||
clientKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "key.pem")
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"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"
|
||||
|
@ -26,7 +27,7 @@ Be advised that this will trigger a Docker daemon restart which will stop runnin
|
|||
`, e.hostURL, e.wrappedErr)
|
||||
}
|
||||
|
||||
func cmdConfig(c CommandLine) error {
|
||||
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)
|
||||
log.SetOutWriter(os.Stderr)
|
||||
|
@ -35,7 +36,7 @@ func cmdConfig(c CommandLine) error {
|
|||
return ErrExpectedOneMachine
|
||||
}
|
||||
|
||||
host, err := getFirstArgHost(c)
|
||||
host, err := api.Load(c.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/mcnerror"
|
||||
"github.com/docker/machine/libmachine/mcnflag"
|
||||
"github.com/docker/machine/libmachine/persist"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
)
|
||||
|
||||
|
@ -123,28 +122,19 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func cmdCreateInner(c CommandLine) error {
|
||||
func cmdCreateInner(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) > 1 {
|
||||
return fmt.Errorf("Invalid command line. Found extra arguments %v", c.Args()[1:])
|
||||
}
|
||||
|
||||
name := c.Args().First()
|
||||
driverName := c.String("driver")
|
||||
certInfo := getCertPathInfoFromContext(c)
|
||||
|
||||
storePath := c.GlobalString("storage-path")
|
||||
|
||||
store := &persist.Filestore{
|
||||
Path: storePath,
|
||||
CaCertPath: certInfo.CaCertPath,
|
||||
CaPrivateKeyPath: certInfo.CaPrivateKeyPath,
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
c.ShowHelp()
|
||||
return errNoMachineName
|
||||
}
|
||||
|
||||
driverName := c.String("driver")
|
||||
|
||||
validName := host.ValidateHostName(name)
|
||||
if !validName {
|
||||
return fmt.Errorf("Error creating machine: %s", mcnerror.ErrInvalidHostname)
|
||||
|
@ -163,16 +153,18 @@ func cmdCreateInner(c CommandLine) error {
|
|||
return fmt.Errorf("Error attempting to marshal bare driver data: %s", err)
|
||||
}
|
||||
|
||||
driver, err := newPluginDriver(driverName, bareDriverData)
|
||||
driver, err := api.NewPluginDriver(driverName, bareDriverData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading driver %q: %s", driverName, err)
|
||||
}
|
||||
|
||||
h, err := store.NewHost(driver)
|
||||
h, err := api.NewHost(driver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting new host: %s", err)
|
||||
}
|
||||
|
||||
certInfo := getCertPathInfoFromCommandLine(c)
|
||||
|
||||
h.HostOptions = &host.Options{
|
||||
AuthOptions: &auth.Options{
|
||||
CertDir: mcndirs.GetMachineCertDir(),
|
||||
|
@ -207,7 +199,7 @@ func cmdCreateInner(c CommandLine) error {
|
|||
},
|
||||
}
|
||||
|
||||
exists, err := store.Exists(h.Name)
|
||||
exists, err := api.Exists(h.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error checking if host exists: %s", err)
|
||||
}
|
||||
|
@ -227,11 +219,11 @@ func cmdCreateInner(c CommandLine) error {
|
|||
return fmt.Errorf("Error setting machine configuration from flags provided: %s", err)
|
||||
}
|
||||
|
||||
if err := libmachine.Create(store, h); err != nil {
|
||||
if err := api.Create(h); err != nil {
|
||||
return fmt.Errorf("Error creating machine: %s", err)
|
||||
}
|
||||
|
||||
if err := saveHost(store, h); err != nil {
|
||||
if err := api.Save(h); err != nil {
|
||||
return fmt.Errorf("Error attempting to save store: %s", err)
|
||||
}
|
||||
|
||||
|
@ -276,7 +268,7 @@ func flagHackLookup(flagName string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func cmdCreateOuter(c CommandLine) error {
|
||||
func cmdCreateOuter(c CommandLine, api libmachine.API) error {
|
||||
const (
|
||||
flagLookupMachineName = "flag-lookup"
|
||||
)
|
||||
|
@ -296,7 +288,7 @@ func cmdCreateOuter(c CommandLine) error {
|
|||
return fmt.Errorf("Error attempting to marshal bare driver data: %s", err)
|
||||
}
|
||||
|
||||
driver, err := newPluginDriver(driverName, bareDriverData)
|
||||
driver, err := api.NewPluginDriver(driverName, bareDriverData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading driver %q: %s", driverName, err)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"text/template"
|
||||
|
||||
"github.com/docker/machine/commands/mcndirs"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
|
@ -35,23 +36,23 @@ type ShellConfig struct {
|
|||
NoProxyValue string
|
||||
}
|
||||
|
||||
func cmdEnv(c CommandLine) error {
|
||||
func cmdEnv(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)
|
||||
log.SetOutWriter(os.Stderr)
|
||||
|
||||
if c.Bool("unset") {
|
||||
return unset(c)
|
||||
return unset(c, api)
|
||||
}
|
||||
return set(c)
|
||||
return set(c, api)
|
||||
}
|
||||
|
||||
func set(c CommandLine) error {
|
||||
func set(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return errImproperEnvArgs
|
||||
}
|
||||
|
||||
host, err := getFirstArgHost(c)
|
||||
host, err := api.Load(c.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ func set(c CommandLine) error {
|
|||
return executeTemplateStdout(shellCfg)
|
||||
}
|
||||
|
||||
func unset(c CommandLine) error {
|
||||
func unset(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) != 0 {
|
||||
return errImproperUnsetEnvArgs
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
)
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
|
@ -18,13 +20,13 @@ var funcMap = template.FuncMap{
|
|||
},
|
||||
}
|
||||
|
||||
func cmdInspect(c CommandLine) error {
|
||||
func cmdInspect(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) == 0 {
|
||||
c.ShowHelp()
|
||||
return ErrExpectedOneMachine
|
||||
}
|
||||
|
||||
host, err := getFirstArgHost(c)
|
||||
host, err := api.Load(c.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package commands
|
||||
|
||||
func cmdIP(c CommandLine) error {
|
||||
return runActionWithContext("ip", c)
|
||||
import "github.com/docker/machine/libmachine"
|
||||
|
||||
func cmdIP(c CommandLine, api libmachine.API) error {
|
||||
return runAction("ip", c, api)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package commands
|
||||
|
||||
func cmdKill(c CommandLine) error {
|
||||
return runActionWithContext("kill", c)
|
||||
import "github.com/docker/machine/libmachine"
|
||||
|
||||
func cmdKill(c CommandLine, api libmachine.API) error {
|
||||
return runAction("kill", c, api)
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import (
|
|||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/persist"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/skarademir/naturalsort"
|
||||
|
@ -39,15 +41,14 @@ type HostListItem struct {
|
|||
SwarmOptions *swarm.Options
|
||||
}
|
||||
|
||||
func cmdLs(c CommandLine) error {
|
||||
func cmdLs(c CommandLine, api libmachine.API) error {
|
||||
quiet := c.Bool("quiet")
|
||||
filters, err := parseFilters(c.StringSlice("filter"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store := getStore(c)
|
||||
hostList, err := listHosts(store)
|
||||
hostList, err := persist.LoadAllHosts(api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -261,15 +262,9 @@ func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
|
|||
close(stateCh)
|
||||
close(urlCh)
|
||||
|
||||
active, err := isActive(currentState, url)
|
||||
if err != nil {
|
||||
log.Errorf("error determining if host is active for host %s: %s",
|
||||
h.Name, err)
|
||||
}
|
||||
|
||||
stateQueryChan <- HostListItem{
|
||||
Name: h.Name,
|
||||
Active: active,
|
||||
Active: isActive(currentState, url),
|
||||
DriverName: h.Driver.DriverName(),
|
||||
State: currentState,
|
||||
URL: url,
|
||||
|
@ -332,14 +327,14 @@ func sortHostListItemsByName(items []HostListItem) {
|
|||
|
||||
// IsActive provides a single function for determining if a host is active
|
||||
// based on both the url and if the host is stopped.
|
||||
func isActive(currentState state.State, url string) (bool, error) {
|
||||
if currentState != state.Running {
|
||||
return false, nil
|
||||
}
|
||||
func isActive(currentState state.State, url string) bool {
|
||||
dockerHost := os.Getenv("DOCKER_HOST")
|
||||
|
||||
// TODO: hard-coding the swarm port is a travesty...
|
||||
dockerHost := os.Getenv("DOCKER_HOST")
|
||||
deSwarmedHost := strings.Replace(dockerHost, ":3376", ":2376", 1)
|
||||
if dockerHost == url || deSwarmedHost == url {
|
||||
return currentState == state.Running
|
||||
}
|
||||
|
||||
return dockerHost == url || deSwarmedHost == url, nil
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -467,9 +467,8 @@ func TestIsActive(t *testing.T) {
|
|||
os.Setenv("DOCKER_HOST", c.dockerHost)
|
||||
}
|
||||
|
||||
actual, err := isActive(c.state, "tcp://1.2.3.4:2376")
|
||||
actual := isActive(c.state, "tcp://1.2.3.4:2376")
|
||||
|
||||
assert.Equal(t, c.expected, actual, "IsActive(%s, \"%s\") should return %v, but didn't", c.state, c.dockerHost, c.expected)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
func cmdRegenerateCerts(c CommandLine) error {
|
||||
func cmdRegenerateCerts(c CommandLine, api libmachine.API) error {
|
||||
if !c.Bool("force") {
|
||||
ok, err := confirmInput("Regenerate TLS machine certs? Warning: this is irreversible.")
|
||||
if err != nil {
|
||||
|
@ -18,5 +19,5 @@ func cmdRegenerateCerts(c CommandLine) error {
|
|||
|
||||
log.Infof("Regenerating TLS certificates")
|
||||
|
||||
return runActionWithContext("configureAuth", c)
|
||||
return runAction("configureAuth", c, api)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
func cmdRestart(c CommandLine) error {
|
||||
if err := runActionWithContext("restart", c); err != nil {
|
||||
func cmdRestart(c CommandLine, api libmachine.API) error {
|
||||
if err := runAction("restart", c, api); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -4,20 +4,20 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
func cmdRm(c CommandLine) error {
|
||||
func cmdRm(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) == 0 {
|
||||
c.ShowHelp()
|
||||
return errors.New("You must specify a machine name")
|
||||
}
|
||||
|
||||
force := c.Bool("force")
|
||||
store := getStore(c)
|
||||
|
||||
for _, hostName := range c.Args() {
|
||||
h, err := loadHost(store, hostName)
|
||||
h, err := api.Load(hostName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error removing host %q: %s", hostName, err)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ func cmdRm(c CommandLine) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := store.Remove(hostName); err != nil {
|
||||
if err := api.Remove(hostName); err != nil {
|
||||
log.Errorf("Error removing machine %q from store: %s", hostName, err)
|
||||
} else {
|
||||
log.Infof("Successfully removed %s", hostName)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
"github.com/docker/machine/libmachine/persist"
|
||||
)
|
||||
|
@ -44,7 +45,7 @@ type storeHostInfoLoader struct {
|
|||
}
|
||||
|
||||
func (s *storeHostInfoLoader) load(name string) (HostInfo, error) {
|
||||
host, err := loadHost(s.store, name)
|
||||
host, err := s.store.Load(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error loading host: %s", err)
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ func (s *storeHostInfoLoader) load(name string) (HostInfo, error) {
|
|||
return host.Driver, nil
|
||||
}
|
||||
|
||||
func cmdScp(c CommandLine) error {
|
||||
func cmdScp(c CommandLine, api libmachine.API) error {
|
||||
args := c.Args()
|
||||
if len(args) != 2 {
|
||||
c.ShowHelp()
|
||||
|
@ -62,8 +63,7 @@ func cmdScp(c CommandLine) error {
|
|||
src := args[0]
|
||||
dest := args[1]
|
||||
|
||||
store := getStore(c)
|
||||
hostInfoLoader := &storeHostInfoLoader{store}
|
||||
hostInfoLoader := &storeHostInfoLoader{api}
|
||||
|
||||
cmd, err := getScpCmd(src, dest, c.Bool("recursive"), hostInfoLoader)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,10 +3,11 @@ package commands
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
)
|
||||
|
||||
func cmdSSH(c CommandLine) error {
|
||||
func cmdSSH(c CommandLine, api libmachine.API) error {
|
||||
// Check for help flag -- Needed due to SkipFlagParsing
|
||||
for _, arg := range c.Args() {
|
||||
if arg == "-help" || arg == "--help" || arg == "-h" {
|
||||
|
@ -20,8 +21,7 @@ func cmdSSH(c CommandLine) error {
|
|||
return ErrExpectedOneMachine
|
||||
}
|
||||
|
||||
store := getStore(c)
|
||||
host, err := loadHost(store, name)
|
||||
host, err := api.Load(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
func cmdStart(c CommandLine) error {
|
||||
if err := runActionWithContext("start", c); err != nil {
|
||||
func cmdStart(c CommandLine, api libmachine.API) error {
|
||||
if err := runAction("start", c, api); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/log"
|
||||
)
|
||||
|
||||
func cmdStatus(c CommandLine) error {
|
||||
func cmdStatus(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return ErrExpectedOneMachine
|
||||
}
|
||||
|
||||
host, err := getFirstArgHost(c)
|
||||
host, err := api.Load(c.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package commands
|
||||
|
||||
func cmdStop(c CommandLine) error {
|
||||
return runActionWithContext("stop", c)
|
||||
import "github.com/docker/machine/libmachine"
|
||||
|
||||
func cmdStop(c CommandLine, api libmachine.API) error {
|
||||
return runAction("stop", c, api)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package commands
|
||||
|
||||
func cmdUpgrade(c CommandLine) error {
|
||||
return runActionWithContext("upgrade", c)
|
||||
import "github.com/docker/machine/libmachine"
|
||||
|
||||
func cmdUpgrade(c CommandLine, api libmachine.API) error {
|
||||
return runAction("upgrade", c, api)
|
||||
}
|
||||
|
|
|
@ -2,14 +2,16 @@ package commands
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
)
|
||||
|
||||
func cmdURL(c CommandLine) error {
|
||||
func cmdURL(c CommandLine, api libmachine.API) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return ErrExpectedOneMachine
|
||||
}
|
||||
|
||||
host, err := getFirstArgHost(c)
|
||||
host, err := api.Load(c.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package commands
|
||||
|
||||
func cmdVersion(c CommandLine) error {
|
||||
import "github.com/docker/machine/libmachine"
|
||||
|
||||
func cmdVersion(c CommandLine, api libmachine.API) error {
|
||||
c.ShowVersion()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"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/log"
|
||||
"github.com/docker/machine/libmachine/version"
|
||||
)
|
||||
|
||||
|
@ -29,7 +29,7 @@ Please use this plugin through the main 'docker-machine' binary.
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
libmachine.SetDebug(true)
|
||||
log.IsDebug = true
|
||||
|
||||
rpcd := rpcdriver.NewRPCServerDriver(d)
|
||||
rpc.Register(rpcd)
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
// Sample Virtualbox create independent of Machine CLI.
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
|
@ -11,16 +12,11 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
libmachine.SetDebug(true)
|
||||
|
||||
log.IsDebug = true
|
||||
log.SetOutWriter(os.Stdout)
|
||||
log.SetErrWriter(os.Stderr)
|
||||
|
||||
// returns the familiar store at $HOME/.docker/machine
|
||||
store := libmachine.GetDefaultStore()
|
||||
|
||||
// over-ride this for now (don't want to muck with my default store)
|
||||
store.Path = "/tmp/automatic"
|
||||
client := libmachine.NewClient("/tmp/automatic")
|
||||
|
||||
hostName := "myfunhost"
|
||||
|
||||
|
@ -29,14 +25,24 @@ func main() {
|
|||
driver.CPU = 2
|
||||
driver.Memory = 2048
|
||||
|
||||
h, err := store.NewHost(driver)
|
||||
data, err := json.Marshal(driver)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pluginDriver, err := client.NewPluginDriver("virtualbox", data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
h, err := client.NewHost(pluginDriver)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
h.HostOptions.EngineOptions.StorageDriver = "overlay"
|
||||
|
||||
if err := libmachine.Create(store, h); err != nil {
|
||||
if err := client.Create(h); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,29 +4,81 @@ import (
|
|||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/cert"
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"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"
|
||||
)
|
||||
|
||||
func GetDefaultStore() *persist.Filestore {
|
||||
homeDir := mcnutils.GetHomeDir()
|
||||
certsDir := filepath.Join(homeDir, ".docker", "machine", "certs")
|
||||
return &persist.Filestore{
|
||||
Path: homeDir,
|
||||
CaCertPath: certsDir,
|
||||
CaPrivateKeyPath: certsDir,
|
||||
type API interface {
|
||||
persist.Store
|
||||
NewPluginDriver(string, []byte) (drivers.Driver, error)
|
||||
NewHost(drivers.Driver) (*host.Host, error)
|
||||
Create(h *host.Host) error
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*persist.PluginStore
|
||||
IsDebug bool
|
||||
SSHClientType ssh.ClientType
|
||||
GithubAPIToken string
|
||||
}
|
||||
|
||||
func NewClient(storePath string) *Client {
|
||||
certsDir := filepath.Join(storePath, ".docker", "machine", "certs")
|
||||
return &Client{
|
||||
IsDebug: false,
|
||||
SSHClientType: ssh.External,
|
||||
PluginStore: persist.NewPluginStore(storePath, certsDir, certsDir),
|
||||
}
|
||||
}
|
||||
|
||||
func (api *Client) NewHost(driver drivers.Driver) (*host.Host, error) {
|
||||
certDir := filepath.Join(api.Path, "certs")
|
||||
|
||||
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",
|
||||
},
|
||||
}
|
||||
|
||||
return &host.Host{
|
||||
ConfigVersion: version.ConfigVersion,
|
||||
Name: driver.GetMachineName(),
|
||||
Driver: driver,
|
||||
DriverName: driver.DriverName(),
|
||||
HostOptions: hostOptions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create is the wrapper method which covers all of the boilerplate around
|
||||
// actually creating, provisioning, and persisting an instance in the store.
|
||||
func Create(store persist.Store, h *host.Host) error {
|
||||
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)
|
||||
}
|
||||
|
@ -37,7 +89,7 @@ func Create(store persist.Store, h *host.Host) error {
|
|||
return fmt.Errorf("Error with pre-create check: %s", err)
|
||||
}
|
||||
|
||||
if err := store.Save(h); err != nil {
|
||||
if err := api.Save(h); err != nil {
|
||||
return fmt.Errorf("Error saving host to store before attempting creation: %s", err)
|
||||
}
|
||||
|
||||
|
@ -47,7 +99,7 @@ func Create(store persist.Store, h *host.Host) error {
|
|||
return fmt.Errorf("Error in driver during machine creation: %s", err)
|
||||
}
|
||||
|
||||
if err := store.Save(h); err != nil {
|
||||
if err := api.Save(h); err != nil {
|
||||
return fmt.Errorf("Error saving host to store after attempting creation: %s", err)
|
||||
}
|
||||
|
||||
|
@ -79,7 +131,3 @@ func Create(store persist.Store, h *host.Host) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetDebug(val bool) {
|
||||
log.IsDebug = val
|
||||
}
|
||||
|
|
|
@ -8,15 +8,8 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"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/mcnerror"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/docker/machine/libmachine/version"
|
||||
)
|
||||
|
||||
type Filestore struct {
|
||||
|
@ -25,7 +18,15 @@ type Filestore struct {
|
|||
CaPrivateKeyPath string
|
||||
}
|
||||
|
||||
func (s Filestore) getMachinesDir() string {
|
||||
func NewFilestore(path, caCertPath, caPrivateKeyPath string) *Filestore {
|
||||
return &Filestore{
|
||||
Path: path,
|
||||
CaCertPath: caCertPath,
|
||||
CaPrivateKeyPath: caPrivateKeyPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (s Filestore) GetMachinesDir() string {
|
||||
return filepath.Join(s.Path, "machines")
|
||||
}
|
||||
|
||||
|
@ -34,31 +35,12 @@ func (s Filestore) saveToFile(data []byte, file string) error {
|
|||
}
|
||||
|
||||
func (s Filestore) Save(host *host.Host) error {
|
||||
if serialDriver, ok := host.Driver.(*drivers.SerialDriver); ok {
|
||||
// Unwrap Driver
|
||||
host.Driver = serialDriver.Driver
|
||||
|
||||
// Re-wrap Driver when done
|
||||
defer func() {
|
||||
host.Driver = serialDriver
|
||||
}()
|
||||
}
|
||||
|
||||
// TODO: Does this belong here?
|
||||
if rpcClientDriver, ok := host.Driver.(*rpcdriver.RPCClientDriver); ok {
|
||||
data, err := rpcClientDriver.GetConfigRaw()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting raw config for driver: %s", err)
|
||||
}
|
||||
host.RawDriver = data
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(host, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hostPath := filepath.Join(s.getMachinesDir(), host.Name)
|
||||
hostPath := filepath.Join(s.GetMachinesDir(), host.Name)
|
||||
|
||||
// Ensure that the directory we want to save to exists.
|
||||
if err := os.MkdirAll(hostPath, 0700); err != nil {
|
||||
|
@ -69,34 +51,29 @@ func (s Filestore) Save(host *host.Host) error {
|
|||
}
|
||||
|
||||
func (s Filestore) Remove(name string) error {
|
||||
hostPath := filepath.Join(s.getMachinesDir(), name)
|
||||
hostPath := filepath.Join(s.GetMachinesDir(), name)
|
||||
return os.RemoveAll(hostPath)
|
||||
}
|
||||
|
||||
func (s Filestore) List() ([]*host.Host, error) {
|
||||
dir, err := ioutil.ReadDir(s.getMachinesDir())
|
||||
func (s Filestore) List() ([]string, error) {
|
||||
dir, err := ioutil.ReadDir(s.GetMachinesDir())
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hosts := []*host.Host{}
|
||||
hostNames := []string{}
|
||||
|
||||
for _, file := range dir {
|
||||
if file.IsDir() && !strings.HasPrefix(file.Name(), ".") {
|
||||
host, err := s.Load(file.Name())
|
||||
if err != nil {
|
||||
log.Errorf("error loading host %q: %s", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
hosts = append(hosts, host)
|
||||
hostNames = append(hostNames, file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
return hostNames, nil
|
||||
}
|
||||
|
||||
func (s Filestore) Exists(name string) (bool, error) {
|
||||
_, err := os.Stat(filepath.Join(s.getMachinesDir(), name))
|
||||
_, err := os.Stat(filepath.Join(s.GetMachinesDir(), name))
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
|
@ -108,7 +85,7 @@ func (s Filestore) Exists(name string) (bool, error) {
|
|||
}
|
||||
|
||||
func (s Filestore) loadConfig(h *host.Host) error {
|
||||
data, err := ioutil.ReadFile(filepath.Join(s.getMachinesDir(), h.Name, "config.json"))
|
||||
data, err := ioutil.ReadFile(filepath.Join(s.GetMachinesDir(), h.Name, "config.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,7 +105,7 @@ func (s Filestore) loadConfig(h *host.Host) error {
|
|||
|
||||
// If we end up performing a migration, we should save afterwards so we don't have to do it again on subsequent invocations.
|
||||
if migrationPerformed {
|
||||
if err := s.saveToFile(data, filepath.Join(s.getMachinesDir(), h.Name, "config.json.bak")); err != nil {
|
||||
if err := s.saveToFile(data, filepath.Join(s.GetMachinesDir(), h.Name, "config.json.bak")); err != nil {
|
||||
return fmt.Errorf("Error attempting to save backup after migration: %s", err)
|
||||
}
|
||||
|
||||
|
@ -138,11 +115,10 @@ func (s Filestore) loadConfig(h *host.Host) error {
|
|||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (s Filestore) Load(name string) (*host.Host, error) {
|
||||
hostPath := filepath.Join(s.getMachinesDir(), name)
|
||||
hostPath := filepath.Join(s.GetMachinesDir(), name)
|
||||
|
||||
if _, err := os.Stat(hostPath); os.IsNotExist(err) {
|
||||
return nil, mcnerror.ErrHostDoesNotExist{
|
||||
|
@ -160,37 +136,3 @@ func (s Filestore) Load(name string) (*host.Host, error) {
|
|||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (s Filestore) NewHost(driver drivers.Driver) (*host.Host, error) {
|
||||
certDir := filepath.Join(s.Path, "certs")
|
||||
|
||||
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(s.getMachinesDir(), "server.pem"),
|
||||
ServerKeyPath: filepath.Join(s.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",
|
||||
},
|
||||
}
|
||||
|
||||
return &host.Host{
|
||||
ConfigVersion: version.ConfigVersion,
|
||||
Name: driver.GetMachineName(),
|
||||
Driver: driver,
|
||||
DriverName: driver.DriverName(),
|
||||
HostOptions: hostOptions,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func TestStoreSave(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path := filepath.Join(store.getMachinesDir(), h.Name)
|
||||
path := filepath.Join(store.GetMachinesDir(), h.Name)
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
t.Fatalf("Host path doesn't exist: %s", path)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func TestStoreRemove(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path := filepath.Join(store.getMachinesDir(), h.Name)
|
||||
path := filepath.Join(store.GetMachinesDir(), h.Name)
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
t.Fatalf("Host path doesn't exist: %s", path)
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ func TestStoreList(t *testing.T) {
|
|||
t.Fatalf("List returned %d items, expected 1", len(hosts))
|
||||
}
|
||||
|
||||
if hosts[0].Name != h.Name {
|
||||
t.Fatalf("hosts[0] name is incorrect, got: %s", hosts[0].Name)
|
||||
if hosts[0] != h.Name {
|
||||
t.Fatalf("hosts[0] name is incorrect, got: %s", hosts[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package persist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/machine/drivers/errdriver"
|
||||
"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/host"
|
||||
)
|
||||
|
||||
type PluginDriverFactory interface {
|
||||
NewPluginDriver(string, []byte) (drivers.Driver, error)
|
||||
}
|
||||
|
||||
type RPCPluginDriverFactory struct{}
|
||||
|
||||
type PluginStore struct {
|
||||
*Filestore
|
||||
PluginDriverFactory
|
||||
}
|
||||
|
||||
func (factory RPCPluginDriverFactory) NewPluginDriver(driverName string, rawContent []byte) (drivers.Driver, error) {
|
||||
d, err := rpcdriver.NewRPCClientDriver(rawContent, driverName)
|
||||
if err != nil {
|
||||
// Not being able to find a driver binary is a "known error"
|
||||
if _, ok := err.(localbinary.ErrPluginBinaryNotFound); ok {
|
||||
return errdriver.NewDriver(driverName), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if driverName == "virtualbox" {
|
||||
return drivers.NewSerialDriver(d), nil
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func NewPluginStore(path, caCertPath, caPrivateKeyPath string) *PluginStore {
|
||||
return &PluginStore{
|
||||
Filestore: NewFilestore(path, caCertPath, caPrivateKeyPath),
|
||||
PluginDriverFactory: RPCPluginDriverFactory{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ps PluginStore) Save(host *host.Host) error {
|
||||
if serialDriver, ok := host.Driver.(*drivers.SerialDriver); ok {
|
||||
// Unwrap Driver
|
||||
host.Driver = serialDriver.Driver
|
||||
|
||||
// Re-wrap Driver when done
|
||||
defer func() {
|
||||
host.Driver = serialDriver
|
||||
}()
|
||||
}
|
||||
|
||||
// TODO: Does this belong here?
|
||||
if rpcClientDriver, ok := host.Driver.(*rpcdriver.RPCClientDriver); ok {
|
||||
data, err := rpcClientDriver.GetConfigRaw()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting raw config for driver: %s", err)
|
||||
}
|
||||
host.RawDriver = data
|
||||
}
|
||||
|
||||
return ps.Filestore.Save(host)
|
||||
}
|
||||
|
||||
func (ps PluginStore) Load(name string) (*host.Host, error) {
|
||||
h, err := ps.Filestore.Load(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := ps.NewPluginDriver(h.DriverName, h.RawDriver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.Driver = d
|
||||
|
||||
return h, nil
|
||||
}
|
|
@ -1,21 +1,15 @@
|
|||
package persist
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
)
|
||||
import "github.com/docker/machine/libmachine/host"
|
||||
|
||||
type Store interface {
|
||||
// Exists returns whether a machine exists or not
|
||||
Exists(name string) (bool, error)
|
||||
|
||||
// NewHost will initialize a new host machine
|
||||
NewHost(driver drivers.Driver) (*host.Host, error)
|
||||
|
||||
// List returns a list of all hosts in the store
|
||||
List() ([]*host.Host, error)
|
||||
List() ([]string, error)
|
||||
|
||||
// Get loads a host by name
|
||||
// Load loads a host by name
|
||||
Load(name string) (*host.Host, error)
|
||||
|
||||
// Remove removes a machine from the store
|
||||
|
@ -24,3 +18,28 @@ type Store interface {
|
|||
// Save persists a machine in the store
|
||||
Save(host *host.Host) error
|
||||
}
|
||||
|
||||
func LoadHosts(s Store, hostNames []string) ([]*host.Host, error) {
|
||||
loadedHosts := []*host.Host{}
|
||||
|
||||
for _, hostName := range hostNames {
|
||||
h, err := s.Load(hostName)
|
||||
if err != nil {
|
||||
// TODO: (nathanleclaire) Should these be bundled up
|
||||
// into one error instead of exiting?
|
||||
return nil, err
|
||||
}
|
||||
loadedHosts = append(loadedHosts, h)
|
||||
}
|
||||
|
||||
return loadedHosts, nil
|
||||
}
|
||||
|
||||
func LoadAllHosts(s Store) ([]*host.Host, error) {
|
||||
hostNames, err := s.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return LoadHosts(s, hostNames)
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ load ${BASE_TEST_DIR}/helpers.bash
|
|||
@test "none: rm non existent machine fails 'machine rm ∞'" {
|
||||
run machine rm ∞
|
||||
[ "$status" -eq 1 ]
|
||||
[[ ${lines[0]} == "Error removing host \"∞\": Loading host from store failed: Host does not exist: \"∞\"" ]]
|
||||
[[ ${lines[0]} == "Error removing host \"∞\": Host does not exist: \"∞\"" ]]
|
||||
}
|
||||
|
||||
@test "none: rm is successful 'machine rm 0'" {
|
||||
|
|
Loading…
Reference in New Issue