diff --git a/commands/create.go b/commands/create.go index ab53bb5e62..ccb5d4e085 100644 --- a/commands/create.go +++ b/commands/create.go @@ -14,7 +14,6 @@ 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/auth" "github.com/docker/machine/libmachine/drivers" @@ -152,12 +151,7 @@ func cmdCreateInner(c CommandLine, api libmachine.API) error { } driverName := c.String("driver") - driver, err := api.NewPluginDriver(driverName, rawDriver) - if err != nil { - return fmt.Errorf("Error loading driver %q: %s", driverName, err) - } - - h, err := api.NewHost(driver) + h, err := api.NewHost(driverName, rawDriver) if err != nil { return fmt.Errorf("Error getting new host: %s", err) } @@ -211,7 +205,7 @@ func cmdCreateInner(c CommandLine, api libmachine.API) error { // driverOpts is the actual data we send over the wire to set the // driver parameters (an interface fulfilling drivers.DriverOptions, // concrete type rpcdriver.RpcFlags). - mcnFlags := driver.GetCreateFlags() + mcnFlags := h.Driver.GetCreateFlags() driverOpts := getDriverOpts(c, mcnFlags) if err := h.Driver.SetConfigFromFlags(driverOpts); err != nil { @@ -287,13 +281,9 @@ func cmdCreateOuter(c CommandLine, api libmachine.API) error { return fmt.Errorf("Error attempting to marshal bare driver data: %s", err) } - driver, err := api.NewPluginDriver(driverName, rawDriver) + h, err := api.NewHost(driverName, rawDriver) if err != nil { - return fmt.Errorf("Error loading driver %q: %s", driverName, err) - } - - if _, ok := driver.(*errdriver.Driver); ok { - return errdriver.NotLoadable{Name: driverName} + return err } // TODO: So much flag manipulation and voodoo here, it seems to be @@ -301,7 +291,7 @@ func cmdCreateOuter(c CommandLine, api libmachine.API) error { // // mcnFlags is the data we get back over the wire (type mcnflag.Flag) // to indicate which parameters are available. - mcnFlags := driver.GetCreateFlags() + mcnFlags := h.Driver.GetCreateFlags() // This bit will actually make "create" display the correct flags based // on the requested driver. @@ -317,10 +307,6 @@ func cmdCreateOuter(c CommandLine, api libmachine.API) error { } } - if serialDriver, ok := driver.(*drivers.SerialDriver); ok { - driver = serialDriver.Driver - } - return c.Application().Run(os.Args) } diff --git a/libmachine/examples/vbox_create.go b/libmachine/examples/vbox_create.go index 96b67f38b8..70d32348f2 100644 --- a/libmachine/examples/vbox_create.go +++ b/libmachine/examples/vbox_create.go @@ -27,12 +27,7 @@ func main() { log.Fatal(err) } - pluginDriver, err := client.NewPluginDriver("virtualbox", data) - if err != nil { - log.Fatal(err) - } - - h, err := client.NewHost(pluginDriver) + h, err := client.NewHost("virtualbox", data) if err != nil { log.Fatal(err) } diff --git a/libmachine/libmachine.go b/libmachine/libmachine.go index e5daee91af..3c00dc7270 100644 --- a/libmachine/libmachine.go +++ b/libmachine/libmachine.go @@ -4,11 +4,16 @@ 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" @@ -22,62 +27,92 @@ import ( ) type API interface { - persist.Store - persist.PluginDriverFactory - NewHost(drivers.Driver) (*host.Host, error) + io.Closer + NewHost(driverName string, rawDriver []byte) (*host.Host, error) Create(h *host.Host) error + persist.Store } type Client struct { - *persist.PluginStore 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, - PluginStore: persist.NewPluginStore(storePath, certsDir, certsDir), + IsDebug: false, + SSHClientType: ssh.External, + Filestore: persist.NewFilestore(storePath, certsDir, certsDir), + clientDriverFactory: rpcdriver.NewRPCClientDriverFactory(), } } -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", - }, +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: hostOptions, + 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 { @@ -159,3 +194,7 @@ func sendCrashReport(err error, api *Client, host *host.Host) { crashreport.Send(err, "api.performCreate", host.DriverName, "Create") } } + +func (api *Client) Close() error { + return api.clientDriverFactory.Close() +} diff --git a/libmachine/libmachinetest/fake_api.go b/libmachine/libmachinetest/fake_api.go index f8f32a3a9b..7a6a47fa6c 100644 --- a/libmachine/libmachinetest/fake_api.go +++ b/libmachine/libmachinetest/fake_api.go @@ -20,7 +20,7 @@ func (api *FakeAPI) Close() error { return nil } -func (api *FakeAPI) NewHost(driver drivers.Driver) (*host.Host, error) { +func (api *FakeAPI) NewHost(driverName string, rawDriver []byte) (*host.Host, error) { return nil, nil } diff --git a/libmachine/persist/plugin_store.go b/libmachine/persist/plugin_store.go deleted file mode 100644 index ef0cc19880..0000000000 --- a/libmachine/persist/plugin_store.go +++ /dev/null @@ -1,75 +0,0 @@ -package persist - -import ( - "io" - - "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(driverName string, rawDriver []byte) (drivers.Driver, error) - io.Closer -} - -type RPCPluginDriverFactory struct { - rpcClientDriverFactory rpcdriver.RPCClientDriverFactory -} - -func NewPluginDriverFactory() *RPCPluginDriverFactory { - return &RPCPluginDriverFactory{ - rpcClientDriverFactory: rpcdriver.NewRPCClientDriverFactory(), - } -} - -type PluginStore struct { - *Filestore - PluginDriverFactory -} - -func (factory *RPCPluginDriverFactory) NewPluginDriver(driverName string, rawDriver []byte) (drivers.Driver, error) { - d, err := factory.rpcClientDriverFactory.NewRPCClientDriver(driverName, rawDriver) - 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 (factory *RPCPluginDriverFactory) Close() error { - return factory.rpcClientDriverFactory.Close() -} - -func NewPluginStore(path, caCertPath, caPrivateKeyPath string) *PluginStore { - return &PluginStore{ - Filestore: NewFilestore(path, caCertPath, caPrivateKeyPath), - PluginDriverFactory: NewPluginDriverFactory(), - } -} - -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 -}