mirror of https://github.com/docker/docs.git
initial pass at internal api
Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
parent
7a336225e1
commit
27be8cf28e
217
commands.go
217
commands.go
|
@ -29,6 +29,7 @@ import (
|
|||
_ "github.com/docker/machine/drivers/vmwarefusion"
|
||||
_ "github.com/docker/machine/drivers/vmwarevcloudair"
|
||||
_ "github.com/docker/machine/drivers/vmwarevsphere"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/state"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
@ -88,7 +89,22 @@ func confirmInput(msg string) bool {
|
|||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func newMcn(store libmachine.Store) (*libmachine.Machine, error) {
|
||||
return libmachine.New(store)
|
||||
}
|
||||
|
||||
func getMachineDir(rootPath string) string {
|
||||
return filepath.Join(rootPath, "machines")
|
||||
}
|
||||
|
||||
func getDefaultStore(rootPath, caCertPath, privateKeyPath string) (libmachine.Store, error) {
|
||||
return libmachine.NewFilestore(
|
||||
rootPath,
|
||||
caCertPath,
|
||||
privateKeyPath,
|
||||
), nil
|
||||
}
|
||||
|
||||
func setupCertificates(caCertPath, caKeyPath, clientCertPath, clientKeyPath string) error {
|
||||
|
@ -310,10 +326,23 @@ var Commands = []cli.Command{
|
|||
|
||||
func cmdActive(c *cli.Context) {
|
||||
name := c.Args().First()
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
host, err := store.GetActive()
|
||||
host, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("error getting active host: %v", err)
|
||||
}
|
||||
|
@ -321,12 +350,12 @@ func cmdActive(c *cli.Context) {
|
|||
fmt.Println(host.Name)
|
||||
}
|
||||
} else if name != "" {
|
||||
host, err := store.Load(name)
|
||||
host, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
log.Fatalf("error loading host: %v", err)
|
||||
}
|
||||
|
||||
if err := store.SetActive(host); err != nil {
|
||||
if err := mcn.SetActive(host); err != nil {
|
||||
log.Fatalf("error setting active host: %v", err)
|
||||
}
|
||||
} else {
|
||||
|
@ -348,15 +377,27 @@ func cmdCreate(c *cli.Context) {
|
|||
log.Fatalf("Error generating certificates: %s", err)
|
||||
}
|
||||
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := store.Create(name, driver, c)
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := mcn.Create(name, driver, c)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating machine: %s", err)
|
||||
log.Warn("You will want to check the provider to make sure the machine and associated resources were properly removed.")
|
||||
log.Fatal("Error creating machine")
|
||||
}
|
||||
if err := store.SetActive(host); err != nil {
|
||||
if err := mcn.SetActive(host); err != nil {
|
||||
log.Fatalf("error setting active host: %v", err)
|
||||
}
|
||||
|
||||
|
@ -462,9 +503,22 @@ func cmdIp(c *cli.Context) {
|
|||
|
||||
func cmdLs(c *cli.Context) {
|
||||
quiet := c.Bool("quiet")
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
|
||||
hostList, err := store.List()
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
hostList, err := mcn.List()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -491,7 +545,7 @@ func cmdLs(c *cli.Context) {
|
|||
swarmInfo[host.Name] = host.SwarmDiscovery
|
||||
}
|
||||
|
||||
go getHostState(host, *store, hostListItems)
|
||||
go getHostState(*host, defaultStore, hostListItems)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\n", host.Name)
|
||||
}
|
||||
|
@ -548,9 +602,22 @@ func cmdRm(c *cli.Context) {
|
|||
|
||||
isError := false
|
||||
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, host := range c.Args() {
|
||||
if err := store.Remove(host, force); err != nil {
|
||||
if err := mcn.Remove(host, force); err != nil {
|
||||
log.Errorf("Error removing machine %s: %s", host, err)
|
||||
isError = true
|
||||
}
|
||||
|
@ -642,10 +709,23 @@ func cmdSsh(c *cli.Context) {
|
|||
sshCmd *exec.Cmd
|
||||
)
|
||||
name := c.Args().First()
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
host, err := store.GetActive()
|
||||
host, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to get active host: %v", err)
|
||||
}
|
||||
|
@ -653,7 +733,7 @@ func cmdSsh(c *cli.Context) {
|
|||
name = host.Name
|
||||
}
|
||||
|
||||
host, err := store.Load(name)
|
||||
host, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -677,17 +757,17 @@ func cmdSsh(c *cli.Context) {
|
|||
|
||||
// machineCommand maps the command name to the corresponding machine command.
|
||||
// We run commands concurrently and communicate back an error if there was one.
|
||||
func machineCommand(actionName string, machine *Host, errorChan chan<- error) {
|
||||
func machineCommand(actionName string, host *libmachine.Host, errorChan chan<- error) {
|
||||
commands := map[string](func() error){
|
||||
"configureAuth": machine.ConfigureAuth,
|
||||
"start": machine.Start,
|
||||
"stop": machine.Stop,
|
||||
"restart": machine.Restart,
|
||||
"kill": machine.Kill,
|
||||
"upgrade": machine.Upgrade,
|
||||
"configureAuth": host.ConfigureAuth,
|
||||
"start": host.Start,
|
||||
"stop": host.Stop,
|
||||
"restart": host.Restart,
|
||||
"kill": host.Kill,
|
||||
"upgrade": host.Upgrade,
|
||||
}
|
||||
|
||||
log.Debugf("command=%s machine=%s", actionName, machine.Name)
|
||||
log.Debugf("command=%s machine=%s", actionName, host.Name)
|
||||
|
||||
if err := commands[actionName](); err != nil {
|
||||
errorChan <- err
|
||||
|
@ -698,10 +778,10 @@ func machineCommand(actionName string, machine *Host, errorChan chan<- error) {
|
|||
}
|
||||
|
||||
// runActionForeachMachine will run the command across multiple machines
|
||||
func runActionForeachMachine(actionName string, machines []*Host) {
|
||||
func runActionForeachMachine(actionName string, machines []*libmachine.Host) {
|
||||
var (
|
||||
numConcurrentActions = 0
|
||||
serialMachines = []*Host{}
|
||||
serialMachines = []*libmachine.Host{}
|
||||
errorChan = make(chan error)
|
||||
)
|
||||
|
||||
|
@ -751,12 +831,25 @@ func runActionWithContext(actionName string, c *cli.Context) error {
|
|||
|
||||
// No args specified, so use active.
|
||||
if len(machines) == 0 {
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
activeHost, err := store.GetActive()
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
activeHost, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to get active host: %v", err)
|
||||
}
|
||||
machines = []*Host{activeHost}
|
||||
machines = []*libmachine.Host{activeHost}
|
||||
}
|
||||
|
||||
runActionForeachMachine(actionName, machines)
|
||||
|
@ -813,8 +906,8 @@ func cmdNotFound(c *cli.Context, command string) {
|
|||
)
|
||||
}
|
||||
|
||||
func getHosts(c *cli.Context) ([]*Host, error) {
|
||||
machines := []*Host{}
|
||||
func getHosts(c *cli.Context) ([]*libmachine.Host, error) {
|
||||
machines := []*libmachine.Host{}
|
||||
for _, n := range c.Args() {
|
||||
machine, err := loadMachine(n, c)
|
||||
if err != nil {
|
||||
|
@ -827,23 +920,48 @@ func getHosts(c *cli.Context) ([]*Host, error) {
|
|||
return machines, nil
|
||||
}
|
||||
|
||||
func loadMachine(name string, c *cli.Context) (*Host, error) {
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
func loadMachine(name string, c *cli.Context) (*libmachine.Host, error) {
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
machine, err := store.Load(name)
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return machine, nil
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func getHost(c *cli.Context) *Host {
|
||||
func getHost(c *cli.Context) *libmachine.Host {
|
||||
name := c.Args().First()
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
host, err := store.GetActive()
|
||||
host, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to get active host: %v", err)
|
||||
}
|
||||
|
@ -854,14 +972,14 @@ func getHost(c *cli.Context) *Host {
|
|||
return host
|
||||
}
|
||||
|
||||
host, err := store.Load(name)
|
||||
host, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to load host: %v", err)
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
func getHostState(host Host, store Store, hostListItems chan<- hostListItem) {
|
||||
func getHostState(host libmachine.Host, store libmachine.Store, hostListItems chan<- hostListItem) {
|
||||
currentState, err := host.Driver.GetState()
|
||||
if err != nil {
|
||||
log.Errorf("error getting state for host %s: %s", host.Name, err)
|
||||
|
@ -895,11 +1013,24 @@ func getHostState(host Host, store Store, hostListItems chan<- hostListItem) {
|
|||
|
||||
func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
||||
name := c.Args().First()
|
||||
store := NewStore(utils.GetMachineDir(), c.GlobalString("tls-ca-cert"), c.GlobalString("tls-ca-key"))
|
||||
var machine *Host
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
c.GlobalString("tls-ca-cert"),
|
||||
c.GlobalString("tls-ca-key"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var machine *libmachine.Host
|
||||
|
||||
if name == "" {
|
||||
m, err := store.GetActive()
|
||||
m, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("error getting active host: %v", err)
|
||||
}
|
||||
|
@ -908,7 +1039,7 @@ func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
|||
}
|
||||
machine = m
|
||||
} else {
|
||||
m, err := store.Load(name)
|
||||
m, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error loading machine config: %s", err)
|
||||
}
|
||||
|
|
184
commands_test.go
184
commands_test.go
|
@ -13,10 +13,85 @@ import (
|
|||
|
||||
"github.com/codegangsta/cli"
|
||||
drivers "github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/provider"
|
||||
"github.com/docker/machine/state"
|
||||
)
|
||||
|
||||
const (
|
||||
hostTestName = "test-host"
|
||||
hostTestDriverName = "none"
|
||||
hostTestCaCert = "test-cert"
|
||||
hostTestPrivateKey = "test-key"
|
||||
)
|
||||
|
||||
var (
|
||||
hostTestStorePath string
|
||||
)
|
||||
|
||||
func getTestStore() (libmachine.Store, error) {
|
||||
tmpDir, err := ioutil.TempDir("", "machine-test-")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hostTestStorePath = tmpDir
|
||||
|
||||
os.Setenv("MACHINE_STORAGE_PATH", tmpDir)
|
||||
|
||||
return libmachine.NewFilestore(tmpDir, hostTestCaCert, hostTestPrivateKey), nil
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
os.RemoveAll(hostTestStorePath)
|
||||
}
|
||||
|
||||
func getTestDriverFlags() *DriverOptionsMock {
|
||||
name := hostTestName
|
||||
flags := &DriverOptionsMock{
|
||||
Data: map[string]interface{}{
|
||||
"name": name,
|
||||
"url": "unix:///var/run/docker.sock",
|
||||
"swarm": false,
|
||||
"swarm-host": "",
|
||||
"swarm-master": false,
|
||||
"swarm-discovery": "",
|
||||
},
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func getDefaultTestHost() (*libmachine.Host, error) {
|
||||
host, err := libmachine.NewHost(hostTestName, hostTestDriverName, hostTestStorePath, hostTestCaCert, hostTestPrivateKey, false, "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flags := getTestDriverFlags()
|
||||
if err := host.Driver.SetConfigFromFlags(flags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
type DriverOptionsMock struct {
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
func (d DriverOptionsMock) String(key string) string {
|
||||
return d.Data[key].(string)
|
||||
}
|
||||
|
||||
func (d DriverOptionsMock) Int(key string) int {
|
||||
return d.Data[key].(int)
|
||||
}
|
||||
|
||||
func (d DriverOptionsMock) Bool(key string) bool {
|
||||
return d.Data[key].(bool)
|
||||
}
|
||||
|
||||
type FakeDriver struct {
|
||||
MockState state.State
|
||||
}
|
||||
|
@ -123,61 +198,9 @@ func (d *FakeDriver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
|
|||
return &exec.Cmd{}, nil
|
||||
}
|
||||
|
||||
func TestGetHosts(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
store := NewStore(TestMachineDir, "", "")
|
||||
var err error
|
||||
|
||||
_, err = store.Create("test-a", "none", flags)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = store.Create("test-b", "none", flags)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
storeHosts, err := store.List()
|
||||
|
||||
if len(storeHosts) != 2 {
|
||||
t.Fatalf("List returned %d items", len(storeHosts))
|
||||
}
|
||||
|
||||
set := flag.NewFlagSet("start", 0)
|
||||
set.Parse([]string{"test-a", "test-b"})
|
||||
|
||||
globalSet := flag.NewFlagSet("-d", 0)
|
||||
globalSet.String("-d", "none", "driver")
|
||||
globalSet.String("storage-path", store.Path, "storage path")
|
||||
globalSet.String("tls-ca-cert", "", "")
|
||||
globalSet.String("tls-ca-key", "", "")
|
||||
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
|
||||
hosts, err := getHosts(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(hosts) != 2 {
|
||||
t.Fatal("Expected %d hosts, got %d hosts", 2, len(hosts))
|
||||
}
|
||||
|
||||
os.Setenv("MACHINE_STORAGE_PATH", "")
|
||||
}
|
||||
|
||||
func TestGetHostState(t *testing.T) {
|
||||
storePath, err := ioutil.TempDir("", ".docker")
|
||||
if err != nil {
|
||||
t.Fatal("Error creating tmp dir:", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
hostListItems := make(chan hostListItem)
|
||||
|
||||
store, err := getTestStore()
|
||||
|
@ -185,14 +208,14 @@ func TestGetHostState(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts := []Host{
|
||||
hosts := []libmachine.Host{
|
||||
{
|
||||
Name: "foo",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: store.GetPath(),
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
|
@ -200,7 +223,7 @@ func TestGetHostState(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: store.GetPath(),
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
|
@ -208,7 +231,7 @@ func TestGetHostState(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: store.GetPath(),
|
||||
},
|
||||
}
|
||||
expected := map[string]state.State{
|
||||
|
@ -218,7 +241,7 @@ func TestGetHostState(t *testing.T) {
|
|||
}
|
||||
items := []hostListItem{}
|
||||
for _, host := range hosts {
|
||||
go getHostState(host, *store, hostListItems)
|
||||
go getHostState(host, store, hostListItems)
|
||||
}
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
items = append(items, <-hostListItems)
|
||||
|
@ -238,14 +261,14 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
|
||||
// Assume a bunch of machines in randomly started or
|
||||
// stopped states.
|
||||
machines := []*Host{
|
||||
machines := []*libmachine.Host{
|
||||
{
|
||||
Name: "foo",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
|
@ -253,7 +276,7 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
|
@ -265,7 +288,7 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
{
|
||||
Name: "spam",
|
||||
|
@ -273,7 +296,7 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
{
|
||||
Name: "eggs",
|
||||
|
@ -281,7 +304,7 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
{
|
||||
Name: "ham",
|
||||
|
@ -289,7 +312,7 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
Driver: &FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
storePath: storePath,
|
||||
StorePath: storePath,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -332,34 +355,29 @@ func TestRunActionForeachMachine(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCmdConfig(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
stdout := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
|
||||
os.Stdout = w
|
||||
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
||||
|
||||
defer func() {
|
||||
os.Setenv("MACHINE_STORAGE_PATH", "")
|
||||
os.Stdout = stdout
|
||||
}()
|
||||
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
store := NewStore(TestMachineDir, "", "")
|
||||
var err error
|
||||
|
||||
_, err = store.Create("test-a", "none", flags)
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := store.Load("test-a")
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatalf("error loading host: %v", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.SetActive(host); err != nil {
|
||||
|
@ -375,7 +393,11 @@ func TestCmdConfig(t *testing.T) {
|
|||
}()
|
||||
|
||||
set := flag.NewFlagSet("config", 0)
|
||||
c := cli.NewContext(nil, set, set)
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.String("storage-path", store.GetPath(), "")
|
||||
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
|
||||
cmdConfig(c)
|
||||
|
||||
w.Close()
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package libmachine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrHostDoesNotExist = errors.New("Host does not exist")
|
||||
ErrInvalidHostname = errors.New("Invalid hostname specified")
|
||||
ErrUnknownProviderType = errors.New("Unknown hypervisor type")
|
||||
)
|
|
@ -0,0 +1,148 @@
|
|||
package libmachine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
type Filestore struct {
|
||||
path string
|
||||
caCertPath string
|
||||
privateKeyPath string
|
||||
}
|
||||
|
||||
func NewFilestore(rootPath string, caCert string, privateKey string) *Filestore {
|
||||
return &Filestore{path: rootPath, caCertPath: caCert, privateKeyPath: privateKey}
|
||||
}
|
||||
|
||||
func (s Filestore) loadHost(name string) (*Host, error) {
|
||||
hostPath := filepath.Join(utils.GetMachineDir(), name)
|
||||
if _, err := os.Stat(hostPath); os.IsNotExist(err) {
|
||||
return nil, ErrHostDoesNotExist
|
||||
}
|
||||
|
||||
host := &Host{Name: name, StorePath: hostPath}
|
||||
if err := host.LoadConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (s Filestore) GetPath() string {
|
||||
return s.path
|
||||
}
|
||||
|
||||
func (s Filestore) GetCACertificatePath() (string, error) {
|
||||
return s.caCertPath, nil
|
||||
}
|
||||
|
||||
func (s Filestore) GetPrivateKeyPath() (string, error) {
|
||||
return s.privateKeyPath, nil
|
||||
}
|
||||
|
||||
func (s Filestore) Save(host *Host) error {
|
||||
data, err := json.Marshal(host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hostPath := filepath.Join(utils.GetMachineDir(), host.Name)
|
||||
|
||||
if err := os.MkdirAll(hostPath, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(hostPath, "config.json"), data, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Filestore) Remove(name string, force bool) error {
|
||||
hostPath := filepath.Join(utils.GetMachineDir(), name)
|
||||
return os.RemoveAll(hostPath)
|
||||
}
|
||||
|
||||
func (s Filestore) List() ([]*Host, error) {
|
||||
dir, err := ioutil.ReadDir(utils.GetMachineDir())
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hosts := []*Host{}
|
||||
|
||||
for _, file := range dir {
|
||||
// don't load hidden dirs; used for configs
|
||||
if file.IsDir() && strings.Index(file.Name(), ".") != 0 {
|
||||
host, err := s.Get(file.Name())
|
||||
if err != nil {
|
||||
log.Errorf("error loading host %q: %s", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (s Filestore) Exists(name string) (bool, error) {
|
||||
_, err := os.Stat(filepath.Join(utils.GetMachineDir(), name))
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (s Filestore) Get(name string) (*Host, error) {
|
||||
return s.loadHost(name)
|
||||
}
|
||||
|
||||
func (s Filestore) GetActive() (*Host, error) {
|
||||
hostName, err := ioutil.ReadFile(s.activePath())
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.Get(string(hostName))
|
||||
}
|
||||
|
||||
func (s Filestore) IsActive(host *Host) (bool, error) {
|
||||
active, err := s.GetActive()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if active == nil {
|
||||
return false, nil
|
||||
}
|
||||
return active.Name == host.Name, nil
|
||||
}
|
||||
|
||||
func (s Filestore) SetActive(host *Host) error {
|
||||
if err := os.MkdirAll(filepath.Dir(s.activePath()), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(s.activePath(), []byte(host.Name), 0600)
|
||||
}
|
||||
|
||||
func (s Filestore) RemoveActive() error {
|
||||
return os.Remove(s.activePath())
|
||||
}
|
||||
|
||||
// activePath returns the path to the file that stores the name of the
|
||||
// active host
|
||||
func (s Filestore) activePath() string {
|
||||
return filepath.Join(utils.GetMachineDir(), ".active")
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package libmachine
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
@ -6,14 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
_ "github.com/docker/machine/drivers/none"
|
||||
)
|
||||
|
||||
const (
|
||||
TestStoreDir = ".store-test"
|
||||
)
|
||||
|
||||
var (
|
||||
TestMachineDir = filepath.Join(TestStoreDir, "machine", "machines")
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
type DriverOptionsMock struct {
|
||||
|
@ -32,62 +25,49 @@ func (d DriverOptionsMock) Bool(key string) bool {
|
|||
return d.Data[key].(bool)
|
||||
}
|
||||
|
||||
func clearHosts() error {
|
||||
return os.RemoveAll(TestStoreDir)
|
||||
}
|
||||
func TestStoreSave(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
func getDefaultTestDriverFlags() *DriverOptionsMock {
|
||||
return &DriverOptionsMock{
|
||||
Data: map[string]interface{}{
|
||||
"name": "test",
|
||||
"url": "unix:///var/run/docker.sock",
|
||||
"swarm": false,
|
||||
"swarm-host": "",
|
||||
"swarm-master": false,
|
||||
"swarm-discovery": "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreCreate(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
store := NewStore(TestStoreDir, "", "")
|
||||
|
||||
host, err := store.Create("test", "none", flags)
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if host.Name != "test" {
|
||||
t.Fatal("Host name is incorrect")
|
||||
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(TestStoreDir, "test")
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path := filepath.Join(utils.GetMachineDir(), host.Name)
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
t.Fatalf("Host path doesn't exist: %s", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreRemove(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
store := NewStore(TestStoreDir, "", "")
|
||||
_, err := store.Create("test", "none", flags)
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(TestStoreDir, "test")
|
||||
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(utils.GetMachineDir(), host.Name)
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
t.Fatalf("Host path doesn't exist: %s", path)
|
||||
}
|
||||
err = store.Remove("test", false)
|
||||
err = store.Remove(host.Name, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -97,88 +77,117 @@ func TestStoreRemove(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStoreList(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
store := NewStore(TestStoreDir, "", "")
|
||||
_, err := store.Create("test", "none", flags)
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts, err := store.List()
|
||||
if len(hosts) != 1 {
|
||||
t.Fatalf("List returned %d items", len(hosts))
|
||||
}
|
||||
if hosts[0].Name != "test" {
|
||||
if hosts[0].Name != host.Name {
|
||||
t.Fatalf("hosts[0] name is incorrect, got: %s", hosts[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreExists(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
defer cleanup()
|
||||
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
store := NewStore(TestStoreDir, "", "")
|
||||
exists, err := store.Exists("test")
|
||||
exists, err := store.Exists(host.Name)
|
||||
if exists {
|
||||
t.Fatal("Exists returned true when it should have been false")
|
||||
}
|
||||
_, err = store.Create("test", "none", flags)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exists, err = store.Exists("test")
|
||||
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exists, err = store.Exists(host.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatal("Exists returned false when it should have been true")
|
||||
}
|
||||
if err := store.Remove(host.Name, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exists, err = store.Exists(host.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if exists {
|
||||
t.Fatal("Exists returned true when it should have been false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreLoad(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
expectedURL := "unix:///foo/baz"
|
||||
flags := getDefaultTestDriverFlags()
|
||||
flags := getTestDriverFlags()
|
||||
flags.Data["url"] = expectedURL
|
||||
|
||||
store := NewStore(TestStoreDir, "", "")
|
||||
_, err := store.Create("test", "none", flags)
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
store = NewStore(TestStoreDir, "", "")
|
||||
host, err := store.Load("test")
|
||||
if host.Name != "test" {
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := host.Driver.SetConfigFromFlags(flags); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err = store.Get(host.Name)
|
||||
if host.Name != host.Name {
|
||||
t.Fatal("Host name is incorrect")
|
||||
}
|
||||
actualURL, err := host.GetURL()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if actualURL != expectedURL {
|
||||
t.Fatalf("GetURL is not %q, got %q", expectedURL, expectedURL)
|
||||
t.Fatalf("GetURL is not %q, got %q", expectedURL, actualURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreGetSetActive(t *testing.T) {
|
||||
if err := clearHosts(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
flags := getDefaultTestDriverFlags()
|
||||
|
||||
//store := NewStore(TestStoreDir, "", "")
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -194,12 +203,18 @@ func TestStoreGetSetActive(t *testing.T) {
|
|||
t.Fatalf("GetActive: Active host should not exist")
|
||||
}
|
||||
|
||||
// Set normal host
|
||||
originalHost, err := store.Create("test", "none", flags)
|
||||
host, err = getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Set normal host
|
||||
if err := store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
originalHost := host
|
||||
|
||||
if err := store.SetActive(originalHost); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -208,7 +223,7 @@ func TestStoreGetSetActive(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if host.Name != "test" {
|
||||
if host.Name != host.Name {
|
||||
t.Fatalf("Active host is not 'test', got %s", host.Name)
|
||||
}
|
||||
isActive, err := store.IsActive(host)
|
|
@ -1,9 +1,8 @@
|
|||
package main
|
||||
package libmachine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -26,10 +25,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
validHostNameChars = `[a-zA-Z0-9\-\.]`
|
||||
validHostNamePattern = regexp.MustCompile(`^` + validHostNameChars + `+$`)
|
||||
ErrInvalidHostname = errors.New("Invalid hostname specified. Hostnames must be comprised only of alphanumeric characters, \".\", or \"-\".")
|
||||
ErrUnknownHypervisorType = errors.New("Unknown hypervisor type")
|
||||
validHostNameChars = `[a-zA-Z0-9\-\.]`
|
||||
validHostNamePattern = regexp.MustCompile(`^` + validHostNameChars + `+$`)
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -42,14 +39,14 @@ type Host struct {
|
|||
DriverName string
|
||||
Driver drivers.Driver
|
||||
CaCertPath string
|
||||
PrivateKeyPath string
|
||||
ServerCertPath string
|
||||
ServerKeyPath string
|
||||
PrivateKeyPath string
|
||||
ClientCertPath string
|
||||
SwarmMaster bool
|
||||
SwarmHost string
|
||||
SwarmDiscovery string
|
||||
storePath string
|
||||
StorePath string
|
||||
}
|
||||
|
||||
type DockerConfig struct {
|
||||
|
@ -74,8 +71,8 @@ func waitForDocker(addr string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewHost(name, driverName, storePath, caCert, privateKey string, swarmMaster bool, swarmHost string, swarmDiscovery string) (*Host, error) {
|
||||
driver, err := drivers.NewDriver(driverName, name, storePath, caCert, privateKey)
|
||||
func NewHost(name, driverName, StorePath, caCert, privateKey string, swarmMaster bool, swarmHost string, swarmDiscovery string) (*Host, error) {
|
||||
driver, err := drivers.NewDriver(driverName, name, StorePath, caCert, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -88,16 +85,16 @@ func NewHost(name, driverName, storePath, caCert, privateKey string, swarmMaster
|
|||
SwarmMaster: swarmMaster,
|
||||
SwarmHost: swarmHost,
|
||||
SwarmDiscovery: swarmDiscovery,
|
||||
storePath: storePath,
|
||||
StorePath: StorePath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func LoadHost(name string, storePath string) (*Host, error) {
|
||||
if _, err := os.Stat(storePath); os.IsNotExist(err) {
|
||||
func LoadHost(name string, StorePath string) (*Host, error) {
|
||||
if _, err := os.Stat(StorePath); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("Host %q does not exist", name)
|
||||
}
|
||||
|
||||
host := &Host{Name: name, storePath: storePath}
|
||||
host := &Host{Name: name, StorePath: StorePath}
|
||||
if err := host.LoadConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -121,7 +118,7 @@ func (h *Host) GetDockerConfigDir() (string, error) {
|
|||
case provider.None:
|
||||
return "", nil
|
||||
default:
|
||||
return "", ErrUnknownHypervisorType
|
||||
return "", ErrUnknownProviderType
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +218,7 @@ func (h *Host) StartDocker() error {
|
|||
case provider.Remote:
|
||||
cmd, err = h.GetSSHCommand("sudo service docker start")
|
||||
default:
|
||||
return ErrUnknownHypervisorType
|
||||
return ErrUnknownProviderType
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -249,7 +246,7 @@ func (h *Host) StopDocker() error {
|
|||
case provider.Remote:
|
||||
cmd, err = h.GetSSHCommand("sudo service docker stop")
|
||||
default:
|
||||
return ErrUnknownHypervisorType
|
||||
return ErrUnknownProviderType
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -308,8 +305,8 @@ func (h *Host) ConfigureAuth() error {
|
|||
return fmt.Errorf("unable to get machine IP")
|
||||
}
|
||||
|
||||
serverCertPath := filepath.Join(h.storePath, "server.pem")
|
||||
serverKeyPath := filepath.Join(h.storePath, "server-key.pem")
|
||||
serverCertPath := filepath.Join(h.StorePath, "server.pem")
|
||||
serverKeyPath := filepath.Join(h.StorePath, "server-key.pem")
|
||||
|
||||
org := h.Name
|
||||
bits := 2048
|
||||
|
@ -579,7 +576,7 @@ func (h *Host) SetHostname() error {
|
|||
h.Name,
|
||||
))
|
||||
default:
|
||||
return ErrUnknownHypervisorType
|
||||
return ErrUnknownProviderType
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -688,14 +685,14 @@ func (h *Host) Remove(force bool) error {
|
|||
}
|
||||
|
||||
func (h *Host) removeStorePath() error {
|
||||
file, err := os.Stat(h.storePath)
|
||||
file, err := os.Stat(h.StorePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !file.IsDir() {
|
||||
return fmt.Errorf("%q is not a directory", h.storePath)
|
||||
return fmt.Errorf("%q is not a directory", h.StorePath)
|
||||
}
|
||||
return os.RemoveAll(h.storePath)
|
||||
return os.RemoveAll(h.StorePath)
|
||||
}
|
||||
|
||||
func (h *Host) GetURL() (string, error) {
|
||||
|
@ -703,7 +700,7 @@ func (h *Host) GetURL() (string, error) {
|
|||
}
|
||||
|
||||
func (h *Host) LoadConfig() error {
|
||||
data, err := ioutil.ReadFile(filepath.Join(h.storePath, "config.json"))
|
||||
data, err := ioutil.ReadFile(filepath.Join(h.StorePath, "config.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -714,7 +711,7 @@ func (h *Host) LoadConfig() error {
|
|||
return err
|
||||
}
|
||||
|
||||
driver, err := drivers.NewDriver(config.DriverName, h.Name, h.storePath, h.CaCertPath, h.PrivateKeyPath)
|
||||
driver, err := drivers.NewDriver(config.DriverName, h.Name, h.StorePath, h.CaCertPath, h.PrivateKeyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -733,7 +730,8 @@ func (h *Host) SaveConfig() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(h.storePath, "config.json"), data, 0600); err != nil {
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(h.StorePath, "config.json"), data, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package libmachine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -14,20 +14,30 @@ import (
|
|||
const (
|
||||
hostTestName = "test-host"
|
||||
hostTestDriverName = "none"
|
||||
hostTestStorePath = "/test/path"
|
||||
hostTestCaCert = "test-cert"
|
||||
hostTestPrivateKey = "test-key"
|
||||
)
|
||||
|
||||
func getTestStore() (*Store, error) {
|
||||
var (
|
||||
hostTestStorePath string
|
||||
)
|
||||
|
||||
func getTestStore() (Store, error) {
|
||||
tmpDir, err := ioutil.TempDir("", "machine-test-")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hostTestStorePath = tmpDir
|
||||
|
||||
os.Setenv("MACHINE_STORAGE_PATH", tmpDir)
|
||||
|
||||
return NewStore(tmpDir, hostTestCaCert, hostTestPrivateKey), nil
|
||||
return NewFilestore(tmpDir, hostTestCaCert, hostTestPrivateKey), nil
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
os.RemoveAll(hostTestStorePath)
|
||||
}
|
||||
|
||||
func getTestDriverFlags() *DriverOptionsMock {
|
||||
|
@ -162,14 +172,17 @@ func TestMachinePort(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
flags := getTestDriverFlags()
|
||||
|
||||
_, err = store.Create(hostTestName, hostTestDriverName, flags)
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := store.Load(hostTestName)
|
||||
if err = store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err = store.Get(hostTestName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -205,14 +218,17 @@ func TestMachineCustomPort(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
flags := getTestDriverFlags()
|
||||
|
||||
_, err = store.Create(hostTestName, hostTestDriverName, flags)
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err := store.Load(hostTestName)
|
||||
if err = store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err = store.Get(hostTestName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -248,12 +264,15 @@ func TestHostConfig(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
flags := getTestDriverFlags()
|
||||
host, err := store.Create(hostTestName, hostTestDriverName, flags)
|
||||
host, err := getDefaultTestHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = store.Save(host); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := host.SaveConfig(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package libmachine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
store Store
|
||||
}
|
||||
|
||||
func New(store Store) (*Machine, error) {
|
||||
return &Machine{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Machine) Create(name string, driverName string, flags drivers.DriverOptions) (*Host, error) {
|
||||
exists, err := m.store.Exists(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exists {
|
||||
return nil, fmt.Errorf("Machine %s already exists", name)
|
||||
}
|
||||
|
||||
hostPath := filepath.Join(utils.GetMachineDir(), name)
|
||||
|
||||
caCert, err := m.store.GetCACertificatePath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privateKey, err := m.store.GetPrivateKeyPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host, err := NewHost(name, driverName, hostPath, caCert, privateKey, flags.Bool("swarm-master"), flags.String("swarm-host"), flags.String("swarm-discovery"))
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
if flags != nil {
|
||||
if err := host.Driver.SetConfigFromFlags(flags); err != nil {
|
||||
return host, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := host.Driver.PreCreateCheck(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(hostPath, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := host.SaveConfig(); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if err := host.Create(name); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if err := host.ConfigureAuth(); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if flags.Bool("swarm") {
|
||||
log.Info("Configuring Swarm...")
|
||||
|
||||
discovery := flags.String("swarm-discovery")
|
||||
master := flags.Bool("swarm-master")
|
||||
swarmHost := flags.String("swarm-host")
|
||||
addr := flags.String("swarm-addr")
|
||||
if err := host.ConfigureSwarm(discovery, master, swarmHost, addr); err != nil {
|
||||
log.Errorf("Error configuring Swarm: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.store.SetActive(host); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (m *Machine) Exists(name string) (bool, error) {
|
||||
return m.store.Exists(name)
|
||||
}
|
||||
|
||||
func (m *Machine) GetActive() (*Host, error) {
|
||||
return m.store.GetActive()
|
||||
}
|
||||
|
||||
func (m *Machine) IsActive(host *Host) (bool, error) {
|
||||
return m.store.IsActive(host)
|
||||
}
|
||||
|
||||
func (m *Machine) List() ([]*Host, error) {
|
||||
return m.store.List()
|
||||
}
|
||||
|
||||
func (m *Machine) Get(name string) (*Host, error) {
|
||||
return m.store.Get(name)
|
||||
}
|
||||
|
||||
func (m *Machine) Remove(name string, force bool) error {
|
||||
active, err := m.store.GetActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if active != nil && active.Name == name {
|
||||
if err := m.RemoveActive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
host, err := m.store.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := host.Remove(force); err != nil {
|
||||
if !force {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return m.store.Remove(name, force)
|
||||
}
|
||||
|
||||
func (m *Machine) RemoveActive() error {
|
||||
return m.store.RemoveActive()
|
||||
}
|
||||
|
||||
func (m *Machine) SetActive(host *Host) error {
|
||||
return m.store.SetActive(host)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package libmachine
|
|
@ -0,0 +1,28 @@
|
|||
package libmachine
|
||||
|
||||
type Store interface {
|
||||
// Exists returns whether a machine exists or not
|
||||
Exists(name string) (bool, error)
|
||||
// GetActive returns the active host
|
||||
GetActive() (*Host, error)
|
||||
// GetPath returns the path to the store
|
||||
GetPath() string
|
||||
// GetCACertPath returns the CA certificate
|
||||
GetCACertificatePath() (string, error)
|
||||
// GetPrivateKeyPath returns the private key
|
||||
GetPrivateKeyPath() (string, error)
|
||||
// IsActive returns whether the host is active or not
|
||||
IsActive(host *Host) (bool, error)
|
||||
// List returns a list of hosts
|
||||
List() ([]*Host, error)
|
||||
// Load loads a host by name
|
||||
Get(name string) (*Host, error)
|
||||
// Remove removes a machine from the store
|
||||
Remove(name string, force bool) error
|
||||
// RemoveActive removes the active machine from the store
|
||||
RemoveActive() error
|
||||
// Save persists a machine in the store
|
||||
Save(host *Host) error
|
||||
// SetActive sets the specified host as the active host
|
||||
SetActive(host *Host) error
|
||||
}
|
6
main.go
6
main.go
|
@ -22,6 +22,10 @@ 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 {
|
||||
os.Setenv("MACHINE_STORAGE_PATH", c.GlobalString("storage-path"))
|
||||
return nil
|
||||
}
|
||||
app.Commands = Commands
|
||||
app.CommandNotFound = cmdNotFound
|
||||
app.Usage = "Create and manage machines running Docker."
|
||||
|
@ -35,7 +39,7 @@ func main() {
|
|||
cli.StringFlag{
|
||||
EnvVar: "MACHINE_STORAGE_PATH",
|
||||
Name: "storage-path",
|
||||
Value: utils.GetMachineRoot(),
|
||||
Value: utils.GetBaseDir(),
|
||||
Usage: "Configures storage path",
|
||||
},
|
||||
cli.StringFlag{
|
||||
|
|
178
store.go
178
store.go
|
@ -1,178 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
// Store persists hosts on the filesystem
|
||||
type Store struct {
|
||||
Path string
|
||||
CaCertPath string
|
||||
PrivateKeyPath string
|
||||
}
|
||||
|
||||
func NewStore(rootPath string, caCert string, privateKey string) *Store {
|
||||
if rootPath == "" {
|
||||
rootPath = utils.GetMachineDir()
|
||||
}
|
||||
|
||||
return &Store{Path: rootPath, CaCertPath: caCert, PrivateKeyPath: privateKey}
|
||||
}
|
||||
|
||||
func (s *Store) Create(name string, driverName string, flags drivers.DriverOptions) (*Host, error) {
|
||||
exists, err := s.Exists(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exists {
|
||||
return nil, fmt.Errorf("Machine %s already exists", name)
|
||||
}
|
||||
|
||||
hostPath := filepath.Join(s.Path, name)
|
||||
|
||||
host, err := NewHost(name, driverName, hostPath, s.CaCertPath, s.PrivateKeyPath, flags.Bool("swarm-master"), flags.String("swarm-host"), flags.String("swarm-discovery"))
|
||||
if err != nil {
|
||||
return host, err
|
||||
}
|
||||
if flags != nil {
|
||||
if err := host.Driver.SetConfigFromFlags(flags); err != nil {
|
||||
return host, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := host.Driver.PreCreateCheck(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(hostPath, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := host.SaveConfig(); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if err := host.Create(name); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if err := host.ConfigureAuth(); err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
if flags.Bool("swarm") {
|
||||
log.Info("Configuring Swarm...")
|
||||
|
||||
discovery := flags.String("swarm-discovery")
|
||||
master := flags.Bool("swarm-master")
|
||||
swarmHost := flags.String("swarm-host")
|
||||
addr := flags.String("swarm-addr")
|
||||
if err := host.ConfigureSwarm(discovery, master, swarmHost, addr); err != nil {
|
||||
log.Errorf("Error configuring Swarm: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (s *Store) Remove(name string, force bool) error {
|
||||
active, err := s.GetActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if active != nil && active.Name == name {
|
||||
if err := s.RemoveActive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
host, err := s.Load(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return host.Remove(force)
|
||||
}
|
||||
|
||||
func (s *Store) List() ([]Host, error) {
|
||||
dir, err := ioutil.ReadDir(s.Path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hosts := []Host{}
|
||||
|
||||
for _, file := range dir {
|
||||
// don't load hidden dirs; used for configs
|
||||
if file.IsDir() && strings.Index(file.Name(), ".") != 0 {
|
||||
host, err := s.Load(file.Name())
|
||||
if err != nil {
|
||||
log.Errorf("error loading host %q: %s", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
hosts = append(hosts, *host)
|
||||
}
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (s *Store) Exists(name string) (bool, error) {
|
||||
_, err := os.Stat(filepath.Join(s.Path, name))
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (s *Store) Load(name string) (*Host, error) {
|
||||
hostPath := filepath.Join(s.Path, name)
|
||||
return LoadHost(name, hostPath)
|
||||
}
|
||||
|
||||
func (s *Store) GetActive() (*Host, error) {
|
||||
hostName, err := ioutil.ReadFile(s.activePath())
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.Load(string(hostName))
|
||||
}
|
||||
|
||||
func (s *Store) IsActive(host *Host) (bool, error) {
|
||||
active, err := s.GetActive()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if active == nil {
|
||||
return false, nil
|
||||
}
|
||||
return active.Name == host.Name, nil
|
||||
}
|
||||
|
||||
func (s *Store) SetActive(host *Host) error {
|
||||
if err := os.MkdirAll(filepath.Dir(s.activePath()), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(s.activePath(), []byte(host.Name), 0600)
|
||||
}
|
||||
|
||||
func (s *Store) RemoveActive() error {
|
||||
return os.Remove(s.activePath())
|
||||
}
|
||||
|
||||
// activePath returns the path to the file that stores the name of the
|
||||
// active host
|
||||
func (s *Store) activePath() string {
|
||||
return filepath.Join(s.Path, ".active")
|
||||
}
|
|
@ -22,7 +22,7 @@ func GetHomeDir() string {
|
|||
func GetBaseDir() string {
|
||||
baseDir := os.Getenv("MACHINE_STORAGE_PATH")
|
||||
if baseDir == "" {
|
||||
baseDir = filepath.Join(GetHomeDir(), ".docker")
|
||||
baseDir = filepath.Join(GetHomeDir(), ".docker", "machine")
|
||||
}
|
||||
return baseDir
|
||||
}
|
||||
|
@ -31,20 +31,16 @@ func GetDockerDir() string {
|
|||
return filepath.Join(GetHomeDir(), ".docker")
|
||||
}
|
||||
|
||||
func GetMachineRoot() string {
|
||||
return filepath.Join(GetBaseDir(), "machine")
|
||||
}
|
||||
|
||||
func GetMachineDir() string {
|
||||
return filepath.Join(GetMachineRoot(), "machines")
|
||||
return filepath.Join(GetBaseDir(), "machines")
|
||||
}
|
||||
|
||||
func GetMachineCertDir() string {
|
||||
return filepath.Join(GetMachineRoot(), "certs")
|
||||
return filepath.Join(GetBaseDir(), "certs")
|
||||
}
|
||||
|
||||
func GetMachineCacheDir() string {
|
||||
return filepath.Join(GetMachineRoot(), "cache")
|
||||
return filepath.Join(GetBaseDir(), "cache")
|
||||
}
|
||||
|
||||
func GetUsername() string {
|
||||
|
|
Loading…
Reference in New Issue