Simplify Api

Signed-off-by: David Gageot <david@gageot.net>
This commit is contained in:
David Gageot 2015-12-30 16:42:45 +01:00
parent 67f8b19c9b
commit 00eee7db1d
5 changed files with 77 additions and 132 deletions

View File

@ -14,7 +14,6 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/docker/machine/commands/mcndirs" "github.com/docker/machine/commands/mcndirs"
"github.com/docker/machine/drivers/errdriver"
"github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth" "github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
@ -152,12 +151,7 @@ func cmdCreateInner(c CommandLine, api libmachine.API) error {
} }
driverName := c.String("driver") driverName := c.String("driver")
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)
}
h, err := api.NewHost(driver)
if err != nil { if err != nil {
return fmt.Errorf("Error getting new host: %s", err) 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 // driverOpts is the actual data we send over the wire to set the
// driver parameters (an interface fulfilling drivers.DriverOptions, // driver parameters (an interface fulfilling drivers.DriverOptions,
// concrete type rpcdriver.RpcFlags). // concrete type rpcdriver.RpcFlags).
mcnFlags := driver.GetCreateFlags() mcnFlags := h.Driver.GetCreateFlags()
driverOpts := getDriverOpts(c, mcnFlags) driverOpts := getDriverOpts(c, mcnFlags)
if err := h.Driver.SetConfigFromFlags(driverOpts); err != nil { 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) 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 { if err != nil {
return fmt.Errorf("Error loading driver %q: %s", driverName, err) return err
}
if _, ok := driver.(*errdriver.Driver); ok {
return errdriver.NotLoadable{Name: driverName}
} }
// TODO: So much flag manipulation and voodoo here, it seems to be // 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) // mcnFlags is the data we get back over the wire (type mcnflag.Flag)
// to indicate which parameters are available. // to indicate which parameters are available.
mcnFlags := driver.GetCreateFlags() mcnFlags := h.Driver.GetCreateFlags()
// This bit will actually make "create" display the correct flags based // This bit will actually make "create" display the correct flags based
// on the requested driver. // 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) return c.Application().Run(os.Args)
} }

View File

@ -27,12 +27,7 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
pluginDriver, err := client.NewPluginDriver("virtualbox", data) h, err := client.NewHost("virtualbox", data)
if err != nil {
log.Fatal(err)
}
h, err := client.NewHost(pluginDriver)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -4,11 +4,16 @@ import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"io"
"github.com/docker/machine/drivers/errdriver"
"github.com/docker/machine/libmachine/auth" "github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/cert" "github.com/docker/machine/libmachine/cert"
"github.com/docker/machine/libmachine/check" "github.com/docker/machine/libmachine/check"
"github.com/docker/machine/libmachine/crashreport" "github.com/docker/machine/libmachine/crashreport"
"github.com/docker/machine/libmachine/drivers" "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/engine"
"github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/log"
@ -22,62 +27,92 @@ import (
) )
type API interface { type API interface {
persist.Store io.Closer
persist.PluginDriverFactory NewHost(driverName string, rawDriver []byte) (*host.Host, error)
NewHost(drivers.Driver) (*host.Host, error)
Create(h *host.Host) error Create(h *host.Host) error
persist.Store
} }
type Client struct { type Client struct {
*persist.PluginStore
IsDebug bool IsDebug bool
SSHClientType ssh.ClientType SSHClientType ssh.ClientType
GithubAPIToken string GithubAPIToken string
*persist.Filestore
clientDriverFactory rpcdriver.RPCClientDriverFactory
} }
func NewClient(storePath string) *Client { func NewClient(storePath string) *Client {
certsDir := filepath.Join(storePath, ".docker", "machine", "certs") certsDir := filepath.Join(storePath, ".docker", "machine", "certs")
return &Client{ return &Client{
IsDebug: false, IsDebug: false,
SSHClientType: ssh.External, SSHClientType: ssh.External,
PluginStore: persist.NewPluginStore(storePath, certsDir, certsDir), Filestore: persist.NewFilestore(storePath, certsDir, certsDir),
clientDriverFactory: rpcdriver.NewRPCClientDriverFactory(),
} }
} }
func (api *Client) NewHost(driver drivers.Driver) (*host.Host, error) { func (api *Client) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
certDir := filepath.Join(api.Path, "certs") driver, err := api.clientDriverFactory.NewRPCClientDriver(driverName, rawDriver)
if err != nil {
hostOptions := &host.Options{ return nil, err
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",
},
} }
certDir := filepath.Join(api.Path, "certs")
return &host.Host{ return &host.Host{
ConfigVersion: version.ConfigVersion, ConfigVersion: version.ConfigVersion,
Name: driver.GetMachineName(), Name: driver.GetMachineName(),
Driver: driver, Driver: driver,
DriverName: driver.DriverName(), 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 }, 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 // Create is the wrapper method which covers all of the boilerplate around
// actually creating, provisioning, and persisting an instance in the store. // actually creating, provisioning, and persisting an instance in the store.
func (api *Client) Create(h *host.Host) error { 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") crashreport.Send(err, "api.performCreate", host.DriverName, "Create")
} }
} }
func (api *Client) Close() error {
return api.clientDriverFactory.Close()
}

View File

@ -20,7 +20,7 @@ func (api *FakeAPI) Close() error {
return nil 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 return nil, nil
} }

View File

@ -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
}