Make libmachine usable by outside world

- Clear out some cruft tightly coupling libmachine to filestore

- Comment out drivers other than virtualbox for now

- Change way too many things

- Mostly, break out the code to be more modular.

- Destroy all traces of "provider" in its current form.  It will be
brought back as something more sensible, instead of something which
overlaps in function with both Host and Store.

- Fix mis-managed config passthru

- Remove a few instances of state stored in env vars

- This should be explicitly communicated in Go-land, not through the
shell.

- Rename "store" module to "persist"

- This is done mostly to avoid confusion about the fact that a concrete
instance of a "Store" interface is oftentimes referred to as "store" in
the code.

- Rip out repetitive antipattern for getting store

- This replaces the previous repetive idiom for getting the cert info, and
consequently the store, with a much less repetitive idiom.

- Also, some redundant methods in commands.go for accessing hosts have
either been simplified or removed entirely.

- First steps towards fixing up tests

- Test progress continues

- Replace unit tests with integration tests

- MAKE ALL UNIT TESTS PASS YAY

- Add helper test files

- Don't write to disk in libmachine/host

- Heh.. coverage check strikes again

- Fix remove code

- Move cert code around

- Continued progress: simplify Driver

- Fixups and make creation work with new model

- Move drivers module inside of libmachine

- Move ssh module inside of libmachine

- Move state module to libmachine

- Move utils module to libmachine

- Move version module to libmachine

- Move log module to libmachine

- Modify some constructor methods around

- Change Travis build dep structure

- Boring gofmt fix

- Add version module

- Move NewHost to store

- Update some boring cert path infos to make API easier to use

- Fix up some issues around the new model

- Clean up some cert path stuff

- Don't use shady functions to get store path :D

- Continue artifact work

- Fix silly machines dir bug

- Continue fixing silly path issues

- Change up output of vbm a bit

- Continue work to make example go

- Change output a little more

- Last changes needed to make create finish properly

- Fix config.go to use libmachine

- Cut down code duplication and make both methods work with libmachine

- Add pluggable logging implementation

- Return error when machine already in desired state

- Update example to show log method

- Fix file:// bug

- Fix Swarm defaults

- Remove unused TLS settings from Engine and Swarm options

- Remove spurious error

- Correct bug detecting if migration was performed

- Fix compilation errors from tests

- Fix most of remaining test issues

- Fix final silly bug in tests

- Remove extraneous debug code

- Add -race to test command

- Appease the gofmt

- Appease the generate coverage

- Making executive decision to remove Travis coverage check

In the early days I thought this would be a good idea because it would
encourage people to write tests in case they added a new module.  Well,
in fact it has just turned into a giant nuisance and made refactoring
work like this even more difficult.

- Move Get to Load
- Move HostListItem code to CLI

Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
Nathan LeClaire 2015-08-18 11:26:42 +09:00
parent f2bb2e0e4e
commit b5927f10c4
197 changed files with 3517 additions and 3882 deletions

View File

@ -4,7 +4,7 @@ import (
"fmt"
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
func cmdActive(c *cli.Context) {
@ -12,22 +12,8 @@ func cmdActive(c *cli.Context) {
log.Fatal("Error: Too many arguments given.")
}
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
host, err := provider.GetActive()
store := getStore(c)
host, err := getActiveHost(store)
if err != nil {
log.Fatalf("Error getting active host: %s", err)
}

View File

@ -1 +0,0 @@
package commands

View File

@ -6,13 +6,10 @@ import (
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/codegangsta/cli"
"github.com/skarademir/naturalsort"
"github.com/docker/machine/drivers"
"github.com/docker/machine/commands/mcndirs"
_ "github.com/docker/machine/drivers/amazonec2"
_ "github.com/docker/machine/drivers/azure"
_ "github.com/docker/machine/drivers/digitalocean"
@ -28,12 +25,11 @@ 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/libmachine/auth"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/log"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/cert"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/persist"
)
var (
@ -42,34 +38,6 @@ var (
ErrExpectedOneMachine = errors.New("Error: Expected one machine name as an argument.")
)
type machineConfig struct {
machineName string
machineDir string
machineUrl string
clientKeyPath string
serverCertPath string
clientCertPath string
caCertPath string
caKeyPath string
serverKeyPath string
AuthOptions auth.AuthOptions
SwarmOptions swarm.SwarmOptions
}
func sortHostListItemsByName(items []libmachine.HostListItem) {
m := make(map[string]libmachine.HostListItem, len(items))
s := make([]string, len(items))
for i, v := range items {
name := strings.ToLower(v.Name)
m[name] = v
s[i] = name
}
sort.Sort(naturalsort.NaturalSort(s))
for i, v := range s {
items[i] = m[v]
}
}
func confirmInput(msg string) bool {
fmt.Printf("%s (y/n): ", msg)
var resp string
@ -88,69 +56,46 @@ func confirmInput(msg string) bool {
return false
}
func newProvider(store libmachine.Store) (*libmachine.Provider, 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 getStore(c *cli.Context) persist.Store {
certInfo := getCertPathInfoFromContext(c)
return &persist.Filestore{
Path: c.GlobalString("storage-path"),
CaCertPath: certInfo.CaCertPath,
CaPrivateKeyPath: certInfo.CaPrivateKeyPath,
}
}
func setupCertificates(caCertPath, caKeyPath, clientCertPath, clientKeyPath string) error {
org := utils.GetUsername()
bits := 2048
func getFirstArgHost(c *cli.Context) *host.Host {
store := getStore(c)
hostName := c.Args().First()
h, err := store.Load(hostName)
if err != nil {
// I guess I feel OK with bailing here since if we can't get
// the host reliably we're definitely not going to be able to
// do anything else interesting, but also this premature exit
// feels wrong to me. Let's revisit it later.
log.Fatalf("Error trying to get host %q: %s", hostName, err)
}
return h
}
if _, err := os.Stat(utils.GetMachineCertDir()); err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(utils.GetMachineCertDir(), 0700); err != nil {
log.Fatalf("Error creating machine config dir: %s", err)
}
} else {
log.Fatal(err)
func getHostsFromContext(c *cli.Context) ([]*host.Host, error) {
store := getStore(c)
hosts := []*host.Host{}
for _, hostName := range c.Args() {
h, err := store.Load(hostName)
if err != nil {
return nil, fmt.Errorf("Could not load host %q: %s", hostName, err)
}
hosts = append(hosts, h)
}
if _, err := os.Stat(caCertPath); os.IsNotExist(err) {
log.Infof("Creating CA: %s", caCertPath)
// check if the key path exists; if so, error
if _, err := os.Stat(caKeyPath); err == nil {
log.Fatalf("The CA key already exists. Please remove it or specify a different key/cert.")
}
if err := utils.GenerateCACertificate(caCertPath, caKeyPath, org, bits); err != nil {
log.Infof("Error generating CA certificate: %s", err)
}
}
if _, err := os.Stat(clientCertPath); os.IsNotExist(err) {
log.Infof("Creating client certificate: %s", clientCertPath)
if _, err := os.Stat(utils.GetMachineCertDir()); err != nil {
if os.IsNotExist(err) {
if err := os.Mkdir(utils.GetMachineCertDir(), 0700); err != nil {
log.Fatalf("Error creating machine client cert dir: %s", err)
}
} else {
log.Fatal(err)
}
}
// check if the key path exists; if so, error
if _, err := os.Stat(clientKeyPath); err == nil {
log.Fatalf("The client key already exists. Please remove it or specify a different key/cert.")
}
if err := utils.GenerateCert([]string{""}, clientCertPath, clientKeyPath, caCertPath, caKeyPath, org, bits); err != nil {
log.Fatalf("Error generating client certificate: %s", err)
}
}
return nil
return hosts, nil
}
var sharedCreateFlags = []cli.Flag{
@ -407,9 +352,21 @@ var Commands = []cli.Command{
},
}
func printIP(h *host.Host) func() error {
return func() error {
ip, err := h.Driver.GetIP()
if err != nil {
return fmt.Errorf("Error getting IP address: %s", err)
}
fmt.Println(ip)
return nil
}
}
// 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, host *libmachine.Host, errorChan chan<- error) {
func machineCommand(actionName string, host *host.Host, errorChan chan<- error) {
// TODO: These actions should have their own type.
commands := map[string](func() error){
"configureAuth": host.ConfigureAuth,
"start": host.Start,
@ -417,7 +374,7 @@ func machineCommand(actionName string, host *libmachine.Host, errorChan chan<- e
"restart": host.Restart,
"kill": host.Kill,
"upgrade": host.Upgrade,
"ip": host.PrintIP,
"ip": printIP(host),
}
log.Debugf("command=%s machine=%s", actionName, host.Name)
@ -431,10 +388,10 @@ func machineCommand(actionName string, host *libmachine.Host, errorChan chan<- e
}
// runActionForeachMachine will run the command across multiple machines
func runActionForeachMachine(actionName string, machines []*libmachine.Host) {
func runActionForeachMachine(actionName string, machines []*host.Host) {
var (
numConcurrentActions = 0
serialMachines = []*libmachine.Host{}
serialMachines = []*host.Host{}
errorChan = make(chan error)
)
@ -459,7 +416,7 @@ func runActionForeachMachine(actionName string, machines []*libmachine.Host) {
serialChan := make(chan error)
go machineCommand(actionName, machine, serialChan)
if err := <-serialChan; err != nil {
log.Error(err)
log.Errorln(err)
}
close(serialChan)
}
@ -469,7 +426,7 @@ func runActionForeachMachine(actionName string, machines []*libmachine.Host) {
// rate limit us.
for i := 0; i < numConcurrentActions; i++ {
if err := <-errorChan; err != nil {
log.Error(err)
log.Errorln(err)
}
}
@ -477,185 +434,59 @@ func runActionForeachMachine(actionName string, machines []*libmachine.Host) {
}
func runActionWithContext(actionName string, c *cli.Context) error {
machines, err := getHosts(c)
store := getStore(c)
hosts, err := getHostsFromContext(c)
if err != nil {
return err
}
if len(machines) == 0 {
if len(hosts) == 0 {
log.Fatal(ErrNoMachineSpecified)
}
runActionForeachMachine(actionName, machines)
runActionForeachMachine(actionName, hosts)
for _, h := range hosts {
if err := store.Save(h); err != nil {
return fmt.Errorf("Error saving host to store: %s", err)
}
}
return nil
}
func getHosts(c *cli.Context) ([]*libmachine.Host, error) {
machines := []*libmachine.Host{}
for _, n := range c.Args() {
machine, err := loadMachine(n, c)
if err != nil {
return nil, err
}
machines = append(machines, machine)
}
return machines, nil
}
func loadMachine(name string, c *cli.Context) (*libmachine.Host, error) {
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
host, err := provider.Get(name)
if err != nil {
return nil, err
}
return host, nil
}
func getHost(c *cli.Context) *libmachine.Host {
name := c.Args().First()
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
c.GlobalString("tls-ca-cert"),
c.GlobalString("tls-ca-key"),
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
host, err := provider.Get(name)
if err != nil {
log.Fatalf("unable to load host: %v", err)
}
return host
}
func getDefaultProvider(c *cli.Context) *libmachine.Provider {
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
return provider
}
func getMachineConfig(c *cli.Context) (*machineConfig, error) {
name := c.Args().First()
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
m, err := provider.Get(name)
if err != nil {
return nil, err
}
machineDir := filepath.Join(utils.GetMachineDir(), m.Name)
caCert := filepath.Join(machineDir, "ca.pem")
caKey := filepath.Join(utils.GetMachineCertDir(), "ca-key.pem")
clientCert := filepath.Join(machineDir, "cert.pem")
clientKey := filepath.Join(machineDir, "key.pem")
serverCert := filepath.Join(machineDir, "server.pem")
serverKey := filepath.Join(machineDir, "server-key.pem")
machineUrl, err := m.GetURL()
if err != nil {
if err == drivers.ErrHostIsNotRunning {
machineUrl = ""
} else {
return nil, fmt.Errorf("Unexpected error getting machine url: %s", err)
}
}
return &machineConfig{
machineName: name,
machineDir: machineDir,
machineUrl: machineUrl,
clientKeyPath: clientKey,
clientCertPath: clientCert,
serverCertPath: serverCert,
caKeyPath: caKey,
caCertPath: caCert,
serverKeyPath: serverKey,
AuthOptions: *m.HostOptions.AuthOptions,
SwarmOptions: *m.HostOptions.SwarmOptions,
}, nil
}
// getCertPaths 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 getCertPathInfo(c *cli.Context) libmachine.CertPathInfo {
// setup cert paths
// 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 *cli.Context) cert.CertPathInfo {
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(utils.GetMachineCertDir(), "ca.pem")
caCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca.pem")
}
if caKeyPath == "" {
caKeyPath = filepath.Join(utils.GetMachineCertDir(), "ca-key.pem")
caKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca-key.pem")
}
if clientCertPath == "" {
clientCertPath = filepath.Join(utils.GetMachineCertDir(), "cert.pem")
clientCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "cert.pem")
}
if clientKeyPath == "" {
clientKeyPath = filepath.Join(utils.GetMachineCertDir(), "key.pem")
clientKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "key.pem")
}
return libmachine.CertPathInfo{
CaCertPath: caCertPath,
CaKeyPath: caKeyPath,
ClientCertPath: clientCertPath,
ClientKeyPath: clientKeyPath,
return cert.CertPathInfo{
CaCertPath: caCertPath,
CaPrivateKeyPath: caKeyPath,
ClientCertPath: clientCertPath,
ClientKeyPath: clientKeyPath,
}
}

View File

@ -1,112 +1,27 @@
package commands
import (
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
"github.com/docker/machine/drivers/fakedriver"
_ "github.com/docker/machine/drivers/none"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/hosttest"
"github.com/docker/machine/libmachine/persisttest"
"github.com/docker/machine/libmachine/state"
"github.com/stretchr/testify/assert"
)
const (
hostTestName = "test-host"
hostTestDriverName = "none"
hostTestCaCert = "test-cert"
hostTestPrivateKey = "test-key"
)
var (
hostTestStorePath string
TestStoreDir string
)
func init() {
tmpDir, err := ioutil.TempDir("", "machine-test-")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
TestStoreDir = tmpDir
}
func clearHosts() error {
return os.RemoveAll(TestStoreDir)
}
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
}
type DriverOptionsMock struct {
Data map[string]interface{}
}
func (d DriverOptionsMock) String(key string) string {
return d.Data[key].(string)
}
func (d DriverOptionsMock) StringSlice(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)
}
func TestRunActionForeachMachine(t *testing.T) {
storePath, err := ioutil.TempDir("", ".docker")
if err != nil {
t.Fatal("Error creating tmp dir:", err)
}
// Assume a bunch of machines in randomly started or
// stopped states.
machines := []*libmachine.Host{
machines := []*host.Host{
{
Name: "foo",
DriverName: "fakedriver",
Driver: &fakedriver.FakeDriver{
MockState: state.Running,
},
StorePath: storePath,
},
{
Name: "bar",
@ -114,7 +29,6 @@ func TestRunActionForeachMachine(t *testing.T) {
Driver: &fakedriver.FakeDriver{
MockState: state.Stopped,
},
StorePath: storePath,
},
{
Name: "baz",
@ -126,7 +40,6 @@ func TestRunActionForeachMachine(t *testing.T) {
Driver: &fakedriver.FakeDriver{
MockState: state.Stopped,
},
StorePath: storePath,
},
{
Name: "spam",
@ -134,7 +47,6 @@ func TestRunActionForeachMachine(t *testing.T) {
Driver: &fakedriver.FakeDriver{
MockState: state.Running,
},
StorePath: storePath,
},
{
Name: "eggs",
@ -142,7 +54,6 @@ func TestRunActionForeachMachine(t *testing.T) {
Driver: &fakedriver.FakeDriver{
MockState: state.Stopped,
},
StorePath: storePath,
},
{
Name: "ham",
@ -150,7 +61,6 @@ func TestRunActionForeachMachine(t *testing.T) {
Driver: &fakedriver.FakeDriver{
MockState: state.Running,
},
StorePath: storePath,
},
}
@ -191,3 +101,29 @@ func TestRunActionForeachMachine(t *testing.T) {
}
}
}
func TestPrintIPEmptyGivenLocalEngine(t *testing.T) {
defer persisttest.Cleanup()
host, _ := hosttest.GetDefaultTestHost()
out, w := captureStdout()
assert.Nil(t, printIP(host)())
w.Close()
assert.Equal(t, "", strings.TrimSpace(<-out))
}
func TestPrintIPPrintsGivenRemoteEngine(t *testing.T) {
defer cleanup()
host, _ := hosttest.GetDefaultTestHost()
host.Driver = &fakedriver.FakeDriver{}
out, w := captureStdout()
assert.Nil(t, printIP(host)())
w.Close()
assert.Equal(t, "1.2.3.4", strings.TrimSpace(<-out))
}

View File

@ -6,74 +6,116 @@ import (
"strings"
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/cert"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/state"
)
func cmdConfig(c *cli.Context) {
if len(c.Args()) != 1 {
log.Fatal(ErrExpectedOneMachine)
}
cfg, err := getMachineConfig(c)
h := getFirstArgHost(c)
dockerHost, authOptions, err := runConnectionBoilerplate(h, c)
if err != nil {
log.Fatal(err)
}
dockerHost, err := getHost(c).Driver.GetURL()
if err != nil {
log.Fatal(err)
}
if c.Bool("swarm") {
if !cfg.SwarmOptions.Master {
log.Fatalf("%s is not a swarm master", cfg.machineName)
}
u, err := url.Parse(cfg.SwarmOptions.Host)
if err != nil {
log.Fatal(err)
}
parts := strings.Split(u.Host, ":")
swarmPort := parts[1]
// get IP of machine to replace in case swarm host is 0.0.0.0
mUrl, err := url.Parse(dockerHost)
if err != nil {
log.Fatal(err)
}
mParts := strings.Split(mUrl.Host, ":")
machineIp := mParts[0]
dockerHost = fmt.Sprintf("tcp://%s:%s\n", machineIp, swarmPort)
log.Fatalf("Error running connection boilerplate: %s", err)
}
log.Debug(dockerHost)
u, err := url.Parse(cfg.machineUrl)
if err != nil {
log.Fatal(err)
}
if u.Scheme != "unix" {
// validate cert and regenerate if needed
valid, err := utils.ValidateCertificate(
u.Host,
cfg.caCertPath,
cfg.serverCertPath,
cfg.serverKeyPath,
)
if err != nil {
log.Fatal(err)
}
if !valid {
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
if err := runActionWithContext("configureAuth", c); err != nil {
log.Fatal(err)
}
}
}
fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s\n",
cfg.caCertPath, cfg.clientCertPath, cfg.clientKeyPath, dockerHost)
fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s",
authOptions.CaCertPath, authOptions.ClientCertPath, authOptions.ClientKeyPath, dockerHost)
}
func runConnectionBoilerplate(h *host.Host, c *cli.Context) (string, *auth.AuthOptions, error) {
hostState, err := h.Driver.GetState()
if err != nil {
// TODO: This is a common operation and should have a commonly
// defined error.
return "", &auth.AuthOptions{}, fmt.Errorf("Error trying to get host state: %s", err)
}
if hostState != state.Running {
return "", &auth.AuthOptions{}, fmt.Errorf("%s is not running. Please start it in order to use the connection settings.", h.Name)
}
dockerHost, err := h.Driver.GetURL()
if err != nil {
return "", &auth.AuthOptions{}, fmt.Errorf("Error getting driver URL: %s", err)
}
if c.Bool("swarm") {
var err error
dockerHost, err = parseSwarm(dockerHost, h)
if err != nil {
return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing swarm: %s", err)
}
}
u, err := url.Parse(dockerHost)
if err != nil {
return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing URL: %s", err)
}
authOptions := h.HostOptions.AuthOptions
if err := checkCert(u.Host, authOptions, c); err != nil {
return "", &auth.AuthOptions{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err)
}
return dockerHost, authOptions, nil
}
func checkCert(hostUrl string, authOptions *auth.AuthOptions, c *cli.Context) error {
valid, err := cert.ValidateCertificate(
hostUrl,
authOptions.CaCertPath,
authOptions.ServerCertPath,
authOptions.ServerKeyPath,
)
if err != nil {
return fmt.Errorf("Error attempting to validate the certficate: %s", err)
}
if !valid {
log.Errorf("Invalid certs detected; regenerating for %s", hostUrl)
if err := runActionWithContext("configureAuth", c); err != nil {
return fmt.Errorf("Error attempting to regenerate the certs: %s", err)
}
}
return nil
}
// TODO: This could use a unit test.
func parseSwarm(hostUrl string, h *host.Host) (string, error) {
swarmOptions := h.HostOptions.SwarmOptions
if !swarmOptions.Master {
return "", fmt.Errorf("Error: %s is not a swarm master. The --swarm flag is intended for use with swarm masters.", h.Name)
}
u, err := url.Parse(swarmOptions.Host)
if err != nil {
return "", fmt.Errorf("There was an error parsing the url: %s", err)
}
parts := strings.Split(u.Host, ":")
swarmPort := parts[1]
// get IP of machine to replace in case swarm host is 0.0.0.0
mUrl, err := url.Parse(hostUrl)
if err != nil {
return "", fmt.Errorf("There was an error parsing the url: %s", err)
}
mParts := strings.Split(mUrl.Host, ":")
machineIp := mParts[0]
hostUrl = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
return hostUrl, nil
}

View File

@ -1,104 +0,0 @@
package commands
import (
"bytes"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/swarm"
)
func TestCmdConfig(t *testing.T) {
defer cleanup()
stdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
defer func() {
os.Stdout = stdout
}()
store, err := getTestStore()
if err != nil {
t.Fatal(err)
}
provider, err := libmachine.New(store)
if err != nil {
t.Fatal(err)
}
flags := getTestDriverFlags()
hostOptions := &libmachine.HostOptions{
EngineOptions: &engine.EngineOptions{},
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Discovery: "",
Address: "",
Host: "",
},
AuthOptions: &auth.AuthOptions{},
}
host, err := provider.Create("test-a", "none", hostOptions, flags)
if err != nil {
t.Fatal(err)
}
outStr := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
outStr <- testOutput.String()
}()
set := flag.NewFlagSet("config", 0)
set.Parse([]string{"test-a"})
globalSet := flag.NewFlagSet("test", 0)
globalSet.String("storage-path", store.GetPath(), "")
c := cli.NewContext(nil, set, globalSet)
cmdConfig(c)
w.Close()
out := <-outStr
if !strings.Contains(out, "--tlsverify") {
t.Fatalf("Expect --tlsverify")
}
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
tlscacert := fmt.Sprintf("--tlscacert=\"%s/ca.pem\"", testMachineDir)
if !strings.Contains(out, tlscacert) {
t.Fatalf("Expected to find %s in %s", tlscacert, out)
}
tlscert := fmt.Sprintf("--tlscert=\"%s/cert.pem\"", testMachineDir)
if !strings.Contains(out, tlscert) {
t.Fatalf("Expected to find %s in %s", tlscert, out)
}
tlskey := fmt.Sprintf("--tlskey=\"%s/key.pem\"", testMachineDir)
if !strings.Contains(out, tlskey) {
t.Fatalf("Expected to find %s in %s", tlskey, out)
}
if !strings.Contains(out, "-H=unix:///var/run/docker.sock") {
t.Fatalf("Expect docker host URL")
}
}

View File

@ -1,31 +1,51 @@
package commands
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/docker/machine/log"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/commands/mcndirs"
"github.com/docker/machine/drivers/driverfactory"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth"
"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/mcnerror"
"github.com/docker/machine/libmachine/persist"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/utils"
)
var (
ErrDriverNotRecognized = errors.New("Driver not recognized.")
)
func cmdCreate(c *cli.Context) {
var (
err error
driver drivers.Driver
)
driver := c.String("driver")
driverName := c.String("driver")
name := c.Args().First()
certInfo := getCertPathInfoFromContext(c)
storePath := c.GlobalString("storage-path")
store := &persist.Filestore{
Path: storePath,
CaCertPath: certInfo.CaCertPath,
CaPrivateKeyPath: certInfo.CaPrivateKeyPath,
}
// TODO: Not really a fan of "none" as the default driver...
if driver != "none" {
c.App.Commands, err = trimDriverFlags(driver, c.App.Commands)
if driverName != "none" {
var err error
c.App.Commands, err = trimDriverFlags(driverName, c.App.Commands)
if err != nil {
log.Fatal(err)
}
@ -36,42 +56,25 @@ func cmdCreate(c *cli.Context) {
log.Fatal("You must specify a machine name")
}
validName := host.ValidateHostName(name)
if !validName {
log.Fatal("Error creating machine: ", mcnerror.ErrInvalidHostname)
}
if err := validateSwarmDiscovery(c.String("swarm-discovery")); err != nil {
log.Fatalf("Error parsing swarm discovery: %s", err)
}
certInfo := getCertPathInfo(c)
if err := setupCertificates(
certInfo.CaCertPath,
certInfo.CaKeyPath,
certInfo.ClientCertPath,
certInfo.ClientKeyPath); err != nil {
log.Fatalf("Error generating certificates: %s", err)
}
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
hostOptions := &libmachine.HostOptions{
hostOptions := &host.HostOptions{
AuthOptions: &auth.AuthOptions{
CaCertPath: certInfo.CaCertPath,
PrivateKeyPath: certInfo.CaKeyPath,
ClientCertPath: certInfo.ClientCertPath,
ClientKeyPath: certInfo.ClientKeyPath,
ServerCertPath: filepath.Join(utils.GetMachineDir(), name, "server.pem"),
ServerKeyPath: filepath.Join(utils.GetMachineDir(), name, "server-key.pem"),
CertDir: mcndirs.GetMachineCertDir(),
CaCertPath: certInfo.CaCertPath,
CaPrivateKeyPath: certInfo.CaPrivateKeyPath,
ClientCertPath: certInfo.ClientCertPath,
ClientKeyPath: certInfo.ClientKeyPath,
ServerCertPath: filepath.Join(mcndirs.GetMachineDir(), name, "server.pem"),
ServerKeyPath: filepath.Join(mcndirs.GetMachineDir(), name, "server-key.pem"),
StorePath: filepath.Join(mcndirs.GetMachineDir(), name),
},
EngineOptions: &engine.EngineOptions{
ArbitraryFlags: c.StringSlice("engine-opt"),
@ -95,13 +98,39 @@ func cmdCreate(c *cli.Context) {
},
}
_, err = provider.Create(name, driver, hostOptions, c)
driver, err := driverfactory.NewDriver(driverName, name, storePath)
if err != nil {
log.Errorf("Error creating machine: %s", err)
log.Fatal("You will want to check the provider to make sure the machine and associated resources were properly removed.")
log.Fatalf("Error trying to get driver: %s", err)
}
info := fmt.Sprintf("%s env %s", c.App.Name, name)
h, err := store.NewHost(driver)
if err != nil {
log.Fatalf("Error getting new host: %s", err)
}
h.HostOptions = hostOptions
exists, err := store.Exists(h.Name)
if err != nil {
log.Fatalf("Error checking if host exists: %s", err)
}
if exists {
log.Fatal(mcnerror.ErrHostAlreadyExists{
Name: h.Name,
})
}
// TODO: This should be moved out of the driver and done in the
// commands module.
if err := h.Driver.SetConfigFromFlags(c); err != nil {
log.Fatalf("Error setting machine configuration from flags provided: %s", err)
}
if err := libmachine.Create(store, h); err != nil {
log.Fatalf("Error creating machine: %s", err)
}
info := fmt.Sprintf("%s env %s", os.Args[0], name)
log.Infof("To see how to connect Docker to this machine, run: %s", info)
}

View File

@ -3,15 +3,11 @@ package commands
import (
"errors"
"fmt"
"net/url"
"os"
"strings"
"text/template"
"github.com/docker/machine/log"
"github.com/codegangsta/cli"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/log"
)
const (
@ -37,6 +33,14 @@ func cmdEnv(c *cli.Context) {
if len(c.Args()) != 1 && !c.Bool("unset") {
log.Fatal(improperEnvArgsError)
}
h := getFirstArgHost(c)
dockerHost, authOptions, err := runConnectionBoilerplate(h, c)
if err != nil {
log.Fatalf("Error running connection boilerplate: %s", err)
}
userShell := c.String("shell")
if userShell == "" {
shell, err := detectShell()
@ -93,70 +97,12 @@ func cmdEnv(c *cli.Context) {
return
}
cfg, err := getMachineConfig(c)
if err != nil {
log.Fatal(err)
}
if cfg.machineUrl == "" {
log.Fatalf("%s is not running. Please start this with %s start %s", cfg.machineName, c.App.Name, cfg.machineName)
}
dockerHost := cfg.machineUrl
if c.Bool("swarm") {
if !cfg.SwarmOptions.Master {
log.Fatalf("%s is not a swarm master", cfg.machineName)
}
u, err := url.Parse(cfg.SwarmOptions.Host)
if err != nil {
log.Fatal(err)
}
parts := strings.Split(u.Host, ":")
swarmPort := parts[1]
// get IP of machine to replace in case swarm host is 0.0.0.0
mUrl, err := url.Parse(cfg.machineUrl)
if err != nil {
log.Fatal(err)
}
mParts := strings.Split(mUrl.Host, ":")
machineIp := mParts[0]
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
}
u, err := url.Parse(cfg.machineUrl)
if err != nil {
log.Fatal(err)
}
if u.Scheme != "unix" {
// validate cert and regenerate if needed
valid, err := utils.ValidateCertificate(
u.Host,
cfg.caCertPath,
cfg.serverCertPath,
cfg.serverKeyPath,
)
if err != nil {
log.Fatal(err)
}
if !valid {
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
if err := runActionWithContext("configureAuth", c); err != nil {
log.Fatal(err)
}
}
}
shellCfg = ShellConfig{
DockerCertPath: cfg.machineDir,
DockerCertPath: authOptions.CertDir,
DockerHost: dockerHost,
DockerTLSVerify: "1",
UsageHint: usageHint,
MachineName: cfg.machineName,
MachineName: h.Name,
}
switch userShell {

View File

@ -1,316 +0,0 @@
package commands
import (
"bytes"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/swarm"
)
func TestCmdEnvBash(t *testing.T) {
stdout := os.Stdout
shell := os.Getenv("SHELL")
r, w, _ := os.Pipe()
os.Stdout = w
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
os.Setenv("SHELL", "/bin/bash")
defer func() {
os.Setenv("MACHINE_STORAGE_PATH", "")
os.Setenv("SHELL", shell)
os.Stdout = stdout
}()
if err := clearHosts(); err != nil {
t.Fatal(err)
}
flags := getTestDriverFlags()
store, sErr := getTestStore()
if sErr != nil {
t.Fatal(sErr)
}
provider, err := libmachine.New(store)
if err != nil {
t.Fatal(err)
}
hostOptions := &libmachine.HostOptions{
EngineOptions: &engine.EngineOptions{},
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Discovery: "",
Address: "",
Host: "",
},
AuthOptions: &auth.AuthOptions{},
}
host, err := provider.Create("test-a", "none", hostOptions, flags)
if err != nil {
t.Fatal(err)
}
host, err = provider.Get("test-a")
if err != nil {
t.Fatalf("error loading host: %v", err)
}
outStr := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
outStr <- testOutput.String()
}()
set := flag.NewFlagSet("config", 0)
set.Parse([]string{"test-a"})
c := cli.NewContext(nil, set, set)
c.App = &cli.App{
Name: "docker-machine-test",
}
cmdEnv(c)
w.Close()
out := <-outStr
// parse the output into a map of envvar:value for easier testing below
envvars := make(map[string]string)
for _, e := range strings.Split(strings.TrimSpace(out), "\n") {
if !strings.HasPrefix(e, "export ") {
continue
}
kv := strings.SplitN(e, "=", 2)
key, value := kv[0], kv[1]
envvars[strings.Replace(key, "export ", "", 1)] = value
}
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
expected := map[string]string{
"DOCKER_TLS_VERIFY": "\"1\"",
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
"DOCKER_HOST": "\"unix:///var/run/docker.sock\"",
"DOCKER_MACHINE_NAME": `"test-a"`,
}
for k, v := range envvars {
if v != expected[k] {
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
}
}
}
func TestCmdEnvFish(t *testing.T) {
stdout := os.Stdout
shell := os.Getenv("SHELL")
r, w, _ := os.Pipe()
os.Stdout = w
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
os.Setenv("SHELL", "/bin/fish")
defer func() {
os.Setenv("MACHINE_STORAGE_PATH", "")
os.Setenv("SHELL", shell)
os.Stdout = stdout
}()
if err := clearHosts(); err != nil {
t.Fatal(err)
}
flags := getTestDriverFlags()
store, err := getTestStore()
if err != nil {
t.Fatal(err)
}
provider, err := libmachine.New(store)
if err != nil {
t.Fatal(err)
}
hostOptions := &libmachine.HostOptions{
EngineOptions: &engine.EngineOptions{},
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Discovery: "",
Address: "",
Host: "",
},
AuthOptions: &auth.AuthOptions{},
}
host, err := provider.Create("test-a", "none", hostOptions, flags)
if err != nil {
t.Fatal(err)
}
host, err = provider.Get("test-a")
if err != nil {
t.Fatalf("error loading host: %v", err)
}
outStr := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
outStr <- testOutput.String()
}()
set := flag.NewFlagSet("config", 0)
set.Parse([]string{"test-a"})
c := cli.NewContext(nil, set, set)
c.App = &cli.App{
Name: "docker-machine-test",
}
cmdEnv(c)
w.Close()
out := <-outStr
// parse the output into a map of envvar:value for easier testing below
envvars := make(map[string]string)
for _, e := range strings.Split(strings.TrimSuffix(out, ";\n"), ";\n") {
if !strings.HasPrefix(e, "set -x ") {
continue
}
kv := strings.SplitN(strings.Replace(e, "set -x ", "", 1), " ", 2)
key, value := kv[0], kv[1]
envvars[key] = value
}
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
expected := map[string]string{
"DOCKER_TLS_VERIFY": "\"1\"",
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
"DOCKER_HOST": "\"unix:///var/run/docker.sock\"",
"DOCKER_MACHINE_NAME": `"test-a"`,
}
for k, v := range envvars {
if v != expected[k] {
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
}
}
}
func TestCmdEnvPowerShell(t *testing.T) {
stdout := os.Stdout
shell := os.Getenv("SHELL")
r, w, _ := os.Pipe()
os.Stdout = w
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
os.Setenv("SHELL", "")
defer func() {
os.Setenv("MACHINE_STORAGE_PATH", "")
os.Setenv("SHELL", shell)
os.Stdout = stdout
}()
if err := clearHosts(); err != nil {
t.Fatal(err)
}
flags := getTestDriverFlags()
store, sErr := getTestStore()
if sErr != nil {
t.Fatal(sErr)
}
provider, err := libmachine.New(store)
if err != nil {
t.Fatal(err)
}
hostOptions := &libmachine.HostOptions{
EngineOptions: &engine.EngineOptions{},
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Discovery: "",
Address: "",
Host: "",
},
AuthOptions: &auth.AuthOptions{},
}
host, err := provider.Create("test-a", "none", hostOptions, flags)
if err != nil {
t.Fatal(err)
}
host, err = provider.Get("test-a")
if err != nil {
t.Fatalf("error loading host: %v", err)
}
outStr := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
outStr <- testOutput.String()
}()
set := flag.NewFlagSet("config", 0)
set.Parse([]string{"test-a"})
set.String("shell", "powershell", "")
c := cli.NewContext(nil, set, set)
c.App = &cli.App{
Name: "docker-machine-test",
}
cmdEnv(c)
w.Close()
out := <-outStr
// parse the output into a map of envvar:value for easier testing below
envvars := make(map[string]string)
for _, e := range strings.Split(strings.TrimSpace(out), "\n") {
if !strings.HasPrefix(e, "$Env") {
continue
}
kv := strings.SplitN(e, " = ", 2)
key, value := kv[0], kv[1]
envvars[strings.Replace(key, "$Env:", "", 1)] = value
}
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
expected := map[string]string{
"DOCKER_TLS_VERIFY": "\"1\"",
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
"DOCKER_HOST": "\"unix:///var/run/docker.sock\"",
"DOCKER_MACHINE_NAME": `"test-a"`,
}
for k, v := range envvars {
if v != expected[k] {
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
}
}
}

View File

@ -6,7 +6,7 @@ import (
"os"
"text/template"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)
@ -31,7 +31,7 @@ func cmdInspect(c *cli.Context) {
log.Fatalf("Template parsing error: %v\n", err)
}
jsonHost, err := json.Marshal(getHost(c))
jsonHost, err := json.Marshal(getFirstArgHost(c))
if err != nil {
log.Fatal(err)
}
@ -45,7 +45,7 @@ func cmdInspect(c *cli.Context) {
}
os.Stdout.Write([]byte{'\n'})
} else {
prettyJSON, err := json.MarshalIndent(getHost(c), "", " ")
prettyJSON, err := json.MarshalIndent(getFirstArgHost(c), "", " ")
if err != nil {
log.Fatal(err)
}

View File

@ -1,117 +0,0 @@
package commands
import (
"bytes"
"encoding/json"
"flag"
"io"
"os"
"strings"
"testing"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/swarm"
"github.com/stretchr/testify/assert"
)
func TestCmdInspectFormat(t *testing.T) {
actual, host := runInspectCommand(t, []string{"test-a"})
expected, _ := json.MarshalIndent(host, "", " ")
assert.Equal(t, string(expected), actual)
actual, _ = runInspectCommand(t, []string{"--format", "{{.DriverName}}", "test-a"})
assert.Equal(t, "none", actual)
actual, _ = runInspectCommand(t, []string{"--format", "{{json .DriverName}}", "test-a"})
assert.Equal(t, "\"none\"", actual)
actual, _ = runInspectCommand(t, []string{"--format", "{{prettyjson .Driver}}", "test-a"})
type ExpectedDriver struct {
CaCertPath string
IPAddress string
MachineName string
PrivateKeyPath string
SSHPort int
SSHUser string
SwarmDiscovery string
SwarmHost string
SwarmMaster bool
URL string
}
expected, err := json.MarshalIndent(&ExpectedDriver{MachineName: "test-a", URL: "unix:///var/run/docker.sock"}, "", " ")
assert.NoError(t, err)
assert.Equal(t, string(expected), actual)
}
func runInspectCommand(t *testing.T, args []string) (string, *libmachine.Host) {
stdout := os.Stdout
stderr := os.Stderr
shell := os.Getenv("SHELL")
r, w, _ := os.Pipe()
os.Stdout = w
os.Stderr = w
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
os.Setenv("SHELL", "/bin/bash")
defer func() {
os.Setenv("MACHINE_STORAGE_PATH", "")
os.Setenv("SHELL", shell)
os.Stdout = stdout
os.Stderr = stderr
}()
if err := clearHosts(); err != nil {
t.Fatal(err)
}
store, sErr := getTestStore()
if sErr != nil {
t.Fatal(sErr)
}
provider, err := libmachine.New(store)
if err != nil {
t.Fatal(err)
}
hostOptions := &libmachine.HostOptions{
EngineOptions: &engine.EngineOptions{},
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Discovery: "",
Address: "",
Host: "",
},
AuthOptions: &auth.AuthOptions{},
}
flags := getTestDriverFlags()
_, err = provider.Create("test-a", "none", hostOptions, flags)
if err != nil {
t.Fatal(err)
}
outStr := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
outStr <- testOutput.String()
}()
set := flag.NewFlagSet("inspect", 0)
set.String("format", "", "")
set.Parse(args)
c := cli.NewContext(nil, set, set)
cmdInspect(c)
w.Close()
out := <-outStr
return strings.TrimSpace(out), getHost(c)
}

View File

@ -2,7 +2,7 @@ package commands
import (
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
func cmdIp(c *cli.Context) {

View File

@ -1 +0,0 @@
package commands

View File

@ -1,7 +1,7 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)

View File

@ -1 +0,0 @@
package commands

View File

@ -5,12 +5,23 @@ import (
"fmt"
"os"
"regexp"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/log"
"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"
)
var (
stateTimeoutDuration = 10 * time.Second
)
// FilterOptions -
@ -21,6 +32,15 @@ type FilterOptions struct {
Name []string
}
type HostListItem struct {
Name string
Active bool
DriverName string
State state.State
URL string
SwarmOptions *swarm.SwarmOptions
}
func cmdLs(c *cli.Context) {
quiet := c.Bool("quiet")
filters, err := parseFilters(c.StringSlice("filter"))
@ -28,8 +48,8 @@ func cmdLs(c *cli.Context) {
log.Fatal(err)
}
provider := getDefaultProvider(c)
hostList, err := provider.List()
store := getStore(c)
hostList, err := store.List()
if err != nil {
log.Fatal(err)
}
@ -61,7 +81,7 @@ func cmdLs(c *cli.Context) {
}
}
items := libmachine.GetHostListItems(hostList)
items := getHostListItems(hostList)
sortHostListItemsByName(items)
@ -111,7 +131,7 @@ func parseFilters(filters []string) (FilterOptions, error) {
return options, nil
}
func filterHosts(hosts []*libmachine.Host, filters FilterOptions) []*libmachine.Host {
func filterHosts(hosts []*host.Host, filters FilterOptions) []*host.Host {
if len(filters.SwarmName) == 0 &&
len(filters.DriverName) == 0 &&
len(filters.State) == 0 &&
@ -119,7 +139,7 @@ func filterHosts(hosts []*libmachine.Host, filters FilterOptions) []*libmachine.
return hosts
}
filteredHosts := []*libmachine.Host{}
filteredHosts := []*host.Host{}
swarmMasters := getSwarmMasters(hosts)
for _, h := range hosts {
@ -130,7 +150,7 @@ func filterHosts(hosts []*libmachine.Host, filters FilterOptions) []*libmachine.
return filteredHosts
}
func getSwarmMasters(hosts []*libmachine.Host) map[string]string {
func getSwarmMasters(hosts []*host.Host) map[string]string {
swarmMasters := make(map[string]string)
for _, h := range hosts {
swarmOptions := h.HostOptions.SwarmOptions
@ -141,7 +161,7 @@ func getSwarmMasters(hosts []*libmachine.Host) map[string]string {
return swarmMasters
}
func filterHost(host *libmachine.Host, filters FilterOptions, swarmMasters map[string]string) bool {
func filterHost(host *host.Host, filters FilterOptions, swarmMasters map[string]string) bool {
swarmMatches := matchesSwarmName(host, filters.SwarmName, swarmMasters)
driverMatches := matchesDriverName(host, filters.DriverName)
stateMatches := matchesState(host, filters.State)
@ -150,7 +170,7 @@ func filterHost(host *libmachine.Host, filters FilterOptions, swarmMasters map[s
return swarmMatches && driverMatches && stateMatches && nameMatches
}
func matchesSwarmName(host *libmachine.Host, swarmNames []string, swarmMasters map[string]string) bool {
func matchesSwarmName(host *host.Host, swarmNames []string, swarmMasters map[string]string) bool {
if len(swarmNames) == 0 {
return true
}
@ -164,7 +184,7 @@ func matchesSwarmName(host *libmachine.Host, swarmNames []string, swarmMasters m
return false
}
func matchesDriverName(host *libmachine.Host, driverNames []string) bool {
func matchesDriverName(host *host.Host, driverNames []string) bool {
if len(driverNames) == 0 {
return true
}
@ -176,7 +196,7 @@ func matchesDriverName(host *libmachine.Host, driverNames []string) bool {
return false
}
func matchesState(host *libmachine.Host, states []string) bool {
func matchesState(host *host.Host, states []string) bool {
if len(states) == 0 {
return true
}
@ -192,7 +212,7 @@ func matchesState(host *libmachine.Host, states []string) bool {
return false
}
func matchesName(host *libmachine.Host, names []string) bool {
func matchesName(host *host.Host, names []string) bool {
if len(names) == 0 {
return true
}
@ -207,3 +227,139 @@ func matchesName(host *libmachine.Host, names []string) bool {
}
return false
}
func getActiveHost(store persist.Store) (*host.Host, error) {
hosts, err := store.List()
if err != nil {
return nil, err
}
hostListItems := getHostListItems(hosts)
for _, item := range hostListItems {
if item.Active {
h, err := store.Load(item.Name)
if err != nil {
return nil, err
}
return h, nil
}
}
return nil, errors.New("Active host not found")
}
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
currentState, err := h.Driver.GetState()
if err != nil {
log.Errorf("error getting state for host %s: %s", h.Name, err)
}
url, err := h.GetURL()
if err != nil {
if err == drivers.ErrHostIsNotRunning {
url = ""
} else {
log.Errorf("error getting URL for host %s: %s", h.Name, err)
}
}
active, err := isActive(h)
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,
DriverName: h.Driver.DriverName(),
State: currentState,
URL: url,
SwarmOptions: h.HostOptions.SwarmOptions,
}
}
func getHostState(h *host.Host, hostListItemsChan chan<- HostListItem) {
// This channel is used to communicate the properties we are querying
// about the host in the case of a successful read.
stateQueryChan := make(chan HostListItem)
go attemptGetHostState(h, stateQueryChan)
select {
// If we get back useful information, great. Forward it straight to
// the original parent channel.
case hli := <-stateQueryChan:
hostListItemsChan <- hli
// Otherwise, give up after a predetermined duration.
case <-time.After(stateTimeoutDuration):
hostListItemsChan <- HostListItem{
Name: h.Name,
DriverName: h.Driver.DriverName(),
State: state.Timeout,
}
}
}
func getHostListItems(hostList []*host.Host) []HostListItem {
hostListItems := []HostListItem{}
hostListItemsChan := make(chan HostListItem)
for _, h := range hostList {
go getHostState(h, hostListItemsChan)
}
for range hostList {
hostListItems = append(hostListItems, <-hostListItemsChan)
}
close(hostListItemsChan)
return hostListItems
}
// 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(h *host.Host) (bool, error) {
currentState, err := h.Driver.GetState()
if err != nil {
log.Errorf("error getting state for host %s: %s", h.Name, err)
return false, err
}
url, err := h.GetURL()
if err != nil {
if err == drivers.ErrHostIsNotRunning {
url = ""
} else {
log.Errorf("error getting URL for host %s: %s", h.Name, err)
return false, err
}
}
dockerHost := os.Getenv("DOCKER_HOST")
notStopped := currentState != state.Stopped
correctURL := url == dockerHost
isActive := notStopped && correctURL
return isActive, nil
}
func sortHostListItemsByName(items []HostListItem) {
m := make(map[string]HostListItem, len(items))
s := make([]string, len(items))
for i, v := range items {
name := strings.ToLower(v.Name)
m[name] = v
s[i] = name
}
sort.Sort(naturalsort.NaturalSort(s))
for i, v := range s {
items[i] = m[v]
}
}

View File

@ -1,15 +1,32 @@
package commands
import (
"bytes"
"io"
"os"
"testing"
"github.com/docker/machine/drivers/fakedriver"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/state"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/state"
"github.com/stretchr/testify/assert"
)
var (
hostTestStorePath string
stdout *os.File
)
func init() {
stdout = os.Stdout
}
func cleanup() {
os.Stdout = stdout
os.RemoveAll(hostTestStorePath)
}
func TestParseFiltersErrorsGivenInvalidFilter(t *testing.T) {
_, err := parseFilters([]string{"foo=bar"})
assert.EqualError(t, err, "Unsupported filter key 'foo'")
@ -52,11 +69,11 @@ func TestParseFiltersValueWithEqual(t *testing.T) {
func TestFilterHostsReturnsSameGivenNoFilters(t *testing.T) {
opts := FilterOptions{}
hosts := []*libmachine.Host{
hosts := []*host.Host{
{
Name: "testhost",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
},
}
actual := filterHosts(hosts, opts)
@ -67,7 +84,7 @@ func TestFilterHostsReturnsEmptyGivenEmptyHosts(t *testing.T) {
opts := FilterOptions{
SwarmName: []string{"foo"},
}
hosts := []*libmachine.Host{}
hosts := []*host.Host{}
assert.Empty(t, filterHosts(hosts, opts))
}
@ -75,11 +92,11 @@ func TestFilterHostsReturnsEmptyGivenNonMatchingFilters(t *testing.T) {
opts := FilterOptions{
SwarmName: []string{"foo"},
}
hosts := []*libmachine.Host{
hosts := []*host.Host{
{
Name: "testhost",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
},
}
assert.Empty(t, filterHosts(hosts, opts))
@ -90,28 +107,28 @@ func TestFilterHostsBySwarmName(t *testing.T) {
SwarmName: []string{"master"},
}
master :=
&libmachine.Host{
&host.Host{
Name: "master",
HostOptions: &libmachine.HostOptions{
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{Master: true, Discovery: "foo"},
},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "node1",
HostOptions: &libmachine.HostOptions{
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{Master: false, Discovery: "foo"},
},
}
othermaster :=
&libmachine.Host{
&host.Host{
Name: "othermaster",
HostOptions: &libmachine.HostOptions{
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{Master: true, Discovery: "bar"},
},
}
hosts := []*libmachine.Host{master, node1, othermaster}
expected := []*libmachine.Host{master, node1}
hosts := []*host.Host{master, node1, othermaster}
expected := []*host.Host{master, node1}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
@ -121,25 +138,25 @@ func TestFilterHostsByDriverName(t *testing.T) {
DriverName: []string{"fakedriver"},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "node1",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
node2 :=
&libmachine.Host{
&host.Host{
Name: "node2",
DriverName: "virtualbox",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
node3 :=
&libmachine.Host{
&host.Host{
Name: "node3",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
hosts := []*libmachine.Host{node1, node2, node3}
expected := []*libmachine.Host{node1, node3}
hosts := []*host.Host{node1, node2, node3}
expected := []*host.Host{node1, node3}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
@ -149,28 +166,28 @@ func TestFilterHostsByState(t *testing.T) {
State: []string{"Paused", "Saved", "Stopped"},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "node1",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused},
}
node2 :=
&libmachine.Host{
&host.Host{
Name: "node2",
DriverName: "virtualbox",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Stopped},
}
node3 :=
&libmachine.Host{
&host.Host{
Name: "node3",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Running},
}
hosts := []*libmachine.Host{node1, node2, node3}
expected := []*libmachine.Host{node1, node2}
hosts := []*host.Host{node1, node2, node3}
expected := []*host.Host{node1, node2}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
@ -180,35 +197,35 @@ func TestFilterHostsByName(t *testing.T) {
Name: []string{"fire", "ice", "earth", "a.?r"},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "fire",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "fire"},
}
node2 :=
&libmachine.Host{
&host.Host{
Name: "ice",
DriverName: "adriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "ice"},
}
node3 :=
&libmachine.Host{
&host.Host{
Name: "air",
DriverName: "nodriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "air"},
}
node4 :=
&libmachine.Host{
&host.Host{
Name: "water",
DriverName: "falsedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "water"},
}
hosts := []*libmachine.Host{node1, node2, node3, node4}
expected := []*libmachine.Host{node1, node2, node3}
hosts := []*host.Host{node1, node2, node3, node4}
expected := []*host.Host{node1, node2, node3}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
@ -219,25 +236,25 @@ func TestFilterHostsMultiFlags(t *testing.T) {
DriverName: []string{"fakedriver", "virtualbox"},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "node1",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
node2 :=
&libmachine.Host{
&host.Host{
Name: "node2",
DriverName: "virtualbox",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
node3 :=
&libmachine.Host{
&host.Host{
Name: "node3",
DriverName: "softlayer",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
}
hosts := []*libmachine.Host{node1, node2, node3}
expected := []*libmachine.Host{node1, node2}
hosts := []*host.Host{node1, node2, node3}
expected := []*host.Host{node1, node2}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
@ -248,28 +265,114 @@ func TestFilterHostsDifferentFlagsProduceAND(t *testing.T) {
State: []string{"Running"},
}
node1 :=
&libmachine.Host{
&host.Host{
Name: "node1",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Paused},
}
node2 :=
&libmachine.Host{
&host.Host{
Name: "node2",
DriverName: "virtualbox",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Stopped},
}
node3 :=
&libmachine.Host{
&host.Host{
Name: "node3",
DriverName: "fakedriver",
HostOptions: &libmachine.HostOptions{},
HostOptions: &host.HostOptions{},
Driver: &fakedriver.FakeDriver{MockState: state.Running},
}
hosts := []*libmachine.Host{node1, node2, node3}
expected := []*libmachine.Host{}
hosts := []*host.Host{node1, node2, node3}
expected := []*host.Host{}
assert.EqualValues(t, filterHosts(hosts, opts), expected)
}
func captureStdout() (chan string, *os.File) {
r, w, _ := os.Pipe()
os.Stdout = w
out := make(chan string)
go func() {
var testOutput bytes.Buffer
io.Copy(&testOutput, r)
out <- testOutput.String()
}()
return out, w
}
func TestGetHostListItems(t *testing.T) {
defer cleanup()
hostListItemsChan := make(chan HostListItem)
hosts := []*host.Host{
{
Name: "foo",
DriverName: "fakedriver",
Driver: &fakedriver.FakeDriver{
MockState: state.Running,
},
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Address: "",
Discovery: "",
},
},
},
{
Name: "bar",
DriverName: "fakedriver",
Driver: &fakedriver.FakeDriver{
MockState: state.Stopped,
},
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Address: "",
Discovery: "",
},
},
},
{
Name: "baz",
DriverName: "fakedriver",
Driver: &fakedriver.FakeDriver{
MockState: state.Running,
},
HostOptions: &host.HostOptions{
SwarmOptions: &swarm.SwarmOptions{
Master: false,
Address: "",
Discovery: "",
},
},
},
}
expected := map[string]state.State{
"foo": state.Running,
"bar": state.Stopped,
"baz": state.Running,
}
items := []HostListItem{}
for _, host := range hosts {
go getHostState(host, hostListItemsChan)
}
for i := 0; i < len(hosts); i++ {
items = append(items, <-hostListItemsChan)
}
for _, item := range items {
if expected[item.Name] != item.State {
t.Fatal("Expected state did not match for item", item)
}
}
}

32
commands/mcndirs/utils.go Normal file
View File

@ -0,0 +1,32 @@
package mcndirs
import (
"os"
"path/filepath"
"github.com/docker/machine/libmachine/mcnutils"
)
func GetBaseDir() string {
baseDir := os.Getenv("MACHINE_STORAGE_PATH")
if baseDir == "" {
baseDir = filepath.Join(mcnutils.GetHomeDir(), ".docker", "machine")
}
return baseDir
}
func GetDockerDir() string {
return filepath.Join(mcnutils.GetHomeDir(), ".docker")
}
func GetMachineDir() string {
return filepath.Join(GetBaseDir(), "machines")
}
func GetMachineCertDir() string {
return filepath.Join(GetBaseDir(), "certs")
}
func GetMachineCacheDir() string {
return filepath.Join(GetBaseDir(), "cache")
}

View File

@ -1,18 +1,17 @@
package utils
package mcndirs
import (
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/docker/machine/libmachine/mcnutils"
)
func TestGetBaseDir(t *testing.T) {
// reset any override env var
homeDir := GetHomeDir()
homeDir := mcnutils.GetHomeDir()
baseDir := GetBaseDir()
if strings.Index(baseDir, homeDir) != 0 {
@ -32,7 +31,7 @@ func TestGetCustomBaseDir(t *testing.T) {
}
func TestGetDockerDir(t *testing.T) {
homeDir := GetHomeDir()
homeDir := mcnutils.GetHomeDir()
baseDir := GetBaseDir()
if strings.Index(baseDir, homeDir) != 0 {
@ -77,63 +76,3 @@ func TestGetMachineCertDir(t *testing.T) {
}
os.Setenv("MACHINE_STORAGE_PATH", "")
}
func TestCopyFile(t *testing.T) {
testStr := "test-machine"
srcFile, err := ioutil.TempFile("", "machine-test-")
if err != nil {
t.Fatal(err)
}
srcFi, err := srcFile.Stat()
if err != nil {
t.Fatal(err)
}
srcFile.Write([]byte(testStr))
srcFile.Close()
srcFilePath := filepath.Join(os.TempDir(), srcFi.Name())
destFile, err := ioutil.TempFile("", "machine-copy-test-")
if err != nil {
t.Fatal(err)
}
destFi, err := destFile.Stat()
if err != nil {
t.Fatal(err)
}
destFile.Close()
destFilePath := filepath.Join(os.TempDir(), destFi.Name())
if err := CopyFile(srcFilePath, destFilePath); err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadFile(destFilePath)
if err != nil {
t.Fatal(err)
}
if string(data) != testStr {
t.Fatalf("expected data \"%s\"; received \"%s\"", testStr, string(data))
}
}
func TestGetUsername(t *testing.T) {
currentUser := "unknown"
switch runtime.GOOS {
case "darwin", "linux":
currentUser = os.Getenv("USER")
case "windows":
currentUser = os.Getenv("USERNAME")
}
username := GetUsername()
if username != currentUser {
t.Fatalf("expected username %s; received %s", currentUser, username)
}
}

View File

@ -2,7 +2,7 @@ package commands
import (
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
func cmdRegenerateCerts(c *cli.Context) {

View File

@ -1 +0,0 @@
package commands

View File

@ -1,7 +1,7 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)

View File

@ -1 +0,0 @@
package commands

View File

@ -2,7 +2,7 @@ package commands
import (
"github.com/codegangsta/cli"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
func cmdRm(c *cli.Context) {
@ -15,27 +15,14 @@ func cmdRm(c *cli.Context) {
isError := false
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
store := getStore(c)
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
for _, host := range c.Args() {
if err := provider.Remove(host, force); err != nil {
log.Errorf("Error removing machine %s: %s", host, err)
for _, hostName := range c.Args() {
if err := store.Remove(hostName, force); err != nil {
log.Errorf("Error removing machine %s: %s", hostName, err)
isError = true
} else {
log.Infof("Successfully removed %s", host)
log.Infof("Successfully removed %s", hostName)
}
}
if isError {

View File

@ -1 +0,0 @@
package commands

View File

@ -8,8 +8,9 @@ import (
"strings"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/persist"
)
var (
@ -26,7 +27,7 @@ var (
}
)
func getInfoForScpArg(hostAndPath string, provider libmachine.Provider) (*libmachine.Host, string, []string, error) {
func getInfoForScpArg(hostAndPath string, store persist.Store) (*host.Host, string, []string, error) {
// TODO: What to do about colon in filepath?
splitInfo := strings.Split(hostAndPath, ":")
@ -38,7 +39,7 @@ func getInfoForScpArg(hostAndPath string, provider libmachine.Provider) (*libmac
// Remote path. e.g. "machinename:/usr/bin/cmatrix"
if len(splitInfo) == 2 {
path := splitInfo[1]
host, err := provider.Get(splitInfo[0])
host, err := store.Load(splitInfo[0])
if err != nil {
return nil, "", nil, fmt.Errorf("Error loading host: %s", err)
}
@ -52,7 +53,7 @@ func getInfoForScpArg(hostAndPath string, provider libmachine.Provider) (*libmac
return nil, "", nil, ErrMalformedInput
}
func generateLocationArg(host *libmachine.Host, path string) (string, error) {
func generateLocationArg(host *host.Host, path string) (string, error) {
locationPrefix := ""
if host != nil {
ip, err := host.Driver.GetIP()
@ -64,18 +65,18 @@ func generateLocationArg(host *libmachine.Host, path string) (string, error) {
return locationPrefix + path, nil
}
func getScpCmd(src, dest string, sshArgs []string, provider libmachine.Provider) (*exec.Cmd, error) {
func getScpCmd(src, dest string, sshArgs []string, store persist.Store) (*exec.Cmd, error) {
cmdPath, err := exec.LookPath("scp")
if err != nil {
return nil, errors.New("Error: You must have a copy of the scp binary locally to use the scp feature.")
}
srcHost, srcPath, srcOpts, err := getInfoForScpArg(src, provider)
srcHost, srcPath, srcOpts, err := getInfoForScpArg(src, store)
if err != nil {
return nil, err
}
destHost, destPath, destOpts, err := getInfoForScpArg(dest, provider)
destHost, destPath, destOpts, err := getInfoForScpArg(dest, store)
if err != nil {
return nil, err
}
@ -129,8 +130,8 @@ func cmdScp(c *cli.Context) {
src := args[0]
dest := args[1]
provider := getDefaultProvider(c)
cmd, err := getScpCmd(src, dest, sshArgs, *provider)
store := getStore(c)
cmd, err := getScpCmd(src, dest, sshArgs, store)
if err != nil {
log.Fatal(err)

View File

@ -7,9 +7,9 @@ import (
"reflect"
"testing"
"github.com/docker/machine/drivers"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/state"
)
type ScpFakeDriver struct {
@ -18,14 +18,6 @@ type ScpFakeDriver struct {
type ScpFakeStore struct{}
func (d ScpFakeDriver) AuthorizePort(ports []*drivers.Port) error {
return nil
}
func (d ScpFakeDriver) DeauthorizePort(ports []*drivers.Port) error {
return nil
}
func (d ScpFakeDriver) DriverName() string {
return "fake"
}
@ -114,33 +106,25 @@ func (d ScpFakeDriver) GetSSHKeyPath() string {
return "/fake/keypath/id_rsa"
}
func (d ScpFakeDriver) ResolveStorePath(file string) string {
return "/tmp/store/machines/fake"
}
func (s ScpFakeStore) Exists(name string) (bool, error) {
return true, nil
}
func (s ScpFakeStore) GetActive() (*libmachine.Host, error) {
func (s ScpFakeStore) GetActive() (*host.Host, error) {
return nil, nil
}
func (s ScpFakeStore) GetPath() string {
return ""
}
func (s ScpFakeStore) GetCACertificatePath() (string, error) {
return "", nil
}
func (s ScpFakeStore) GetPrivateKeyPath() (string, error) {
return "", nil
}
func (s ScpFakeStore) List() ([]*libmachine.Host, error) {
func (s ScpFakeStore) List() ([]*host.Host, error) {
return nil, nil
}
func (s ScpFakeStore) Get(name string) (*libmachine.Host, error) {
func (s ScpFakeStore) Load(name string) (*host.Host, error) {
if name == "myfunhost" {
return &libmachine.Host{
return &host.Host{
Name: "myfunhost",
Driver: ScpFakeDriver{},
}, nil
@ -152,15 +136,19 @@ func (s ScpFakeStore) Remove(name string, force bool) error {
return nil
}
func (s ScpFakeStore) Save(host *libmachine.Host) error {
func (s ScpFakeStore) Save(host *host.Host) error {
return nil
}
func (s ScpFakeStore) NewHost(driver drivers.Driver) (*host.Host, error) {
return nil, nil
}
func TestGetInfoForScpArg(t *testing.T) {
provider, _ := libmachine.New(ScpFakeStore{})
store := ScpFakeStore{}
expectedPath := "/tmp/foo"
host, path, opts, err := getInfoForScpArg("/tmp/foo", *provider)
host, path, opts, err := getInfoForScpArg("/tmp/foo", store)
if err != nil {
t.Fatalf("Unexpected error in local getInfoForScpArg call: %s", err)
}
@ -174,7 +162,7 @@ func TestGetInfoForScpArg(t *testing.T) {
t.Fatal("opts should be nil")
}
host, path, opts, err = getInfoForScpArg("myfunhost:/home/docker/foo", *provider)
host, path, opts, err = getInfoForScpArg("myfunhost:/home/docker/foo", store)
if err != nil {
t.Fatalf("Unexpected error in machine-based getInfoForScpArg call: %s", err)
}
@ -194,14 +182,14 @@ func TestGetInfoForScpArg(t *testing.T) {
t.Fatalf("Expected path to be /home/docker/foo, got %s", path)
}
host, path, opts, err = getInfoForScpArg("foo:bar:widget", *provider)
host, path, opts, err = getInfoForScpArg("foo:bar:widget", store)
if err != ErrMalformedInput {
t.Fatalf("Didn't get back an error when we were expecting it for malformed args")
}
}
func TestGenerateLocationArg(t *testing.T) {
host := libmachine.Host{
host := host.Host{
Driver: ScpFakeDriver{},
}
@ -224,8 +212,6 @@ func TestGenerateLocationArg(t *testing.T) {
}
func TestGetScpCmd(t *testing.T) {
provider, _ := libmachine.New(ScpFakeStore{})
// TODO: This is a little "integration-ey". Perhaps
// make an ScpDispatcher (name?) interface so that the reliant
// methods can be mocked.
@ -238,8 +224,9 @@ func TestGetScpCmd(t *testing.T) {
"root@12.34.56.78:/home/docker/foo",
)
expectedCmd := exec.Command("/usr/bin/scp", expectedArgs...)
store := ScpFakeStore{}
cmd, err := getScpCmd("/tmp/foo", "myfunhost:/home/docker/foo", append(baseSSHArgs, "-3"), *provider)
cmd, err := getScpCmd("/tmp/foo", "myfunhost:/home/docker/foo", append(baseSSHArgs, "-3"), store)
if err != nil {
t.Fatalf("Unexpected err getting scp command: %s", err)
}

View File

@ -4,8 +4,8 @@ import (
"fmt"
"strings"
"github.com/docker/machine/log"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/state"
"github.com/codegangsta/cli"
)
@ -18,22 +18,8 @@ func cmdSsh(c *cli.Context) {
log.Fatal("Error: Please specify a machine name.")
}
certInfo := getCertPathInfo(c)
defaultStore, err := getDefaultStore(
c.GlobalString("storage-path"),
certInfo.CaCertPath,
certInfo.CaKeyPath,
)
if err != nil {
log.Fatal(err)
}
provider, err := newProvider(defaultStore)
if err != nil {
log.Fatal(err)
}
host, err := provider.Get(name)
store := getStore(c)
host, err := store.Load(name)
if err != nil {
log.Fatal(err)
}

View File

@ -1 +0,0 @@
package commands

View File

@ -1,7 +1,7 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)

View File

@ -1 +0,0 @@
package commands

View File

@ -1,13 +1,13 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)
func cmdStatus(c *cli.Context) {
host := getHost(c)
host := getFirstArgHost(c)
currentState, err := host.Driver.GetState()
if err != nil {
log.Errorf("error getting state for host %s: %s", host.Name, err)

View File

@ -1 +0,0 @@
package commands

View File

@ -1,7 +1,7 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)

View File

@ -1 +0,0 @@
package commands

View File

@ -1,7 +1,7 @@
package commands
import (
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)

View File

@ -1 +0,0 @@
package commands

View File

@ -3,13 +3,13 @@ package commands
import (
"fmt"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
"github.com/codegangsta/cli"
)
func cmdUrl(c *cli.Context) {
url, err := getHost(c).GetURL()
url, err := getFirstArgHost(c).GetURL()
if err != nil {
log.Fatal(err)
}

View File

@ -1 +0,0 @@
package commands

View File

@ -12,21 +12,26 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/drivers/amazonec2/amz"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
const (
driverName = "amazonec2"
ipRange = "0.0.0.0/0"
machineSecurityGroupName = "docker-machine"
defaultAmiId = "ami-615cb725"
defaultRegion = "us-east-1"
defaultInstanceType = "t2.micro"
defaultRootSize = 16
ipRange = "0.0.0.0/0"
machineSecurityGroupName = "docker-machine"
defaultZone = "a"
defaultSecurityGroup = machineSecurityGroupName
defaultSSHUser = "ubuntu"
defaultSpotPrice = "0.50"
)
var (
@ -65,7 +70,6 @@ type Driver struct {
func init() {
drivers.Register(driverName, &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -75,19 +79,16 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "amazonec2-access-key",
Usage: "AWS Access Key",
Value: "",
EnvVar: "AWS_ACCESS_KEY_ID",
},
cli.StringFlag{
Name: "amazonec2-secret-key",
Usage: "AWS Secret Key",
Value: "",
EnvVar: "AWS_SECRET_ACCESS_KEY",
},
cli.StringFlag{
Name: "amazonec2-session-token",
Usage: "AWS Session Token",
Value: "",
EnvVar: "AWS_SESSION_TOKEN",
},
cli.StringFlag{
@ -104,25 +105,23 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "amazonec2-vpc-id",
Usage: "AWS VPC id",
Value: "",
EnvVar: "AWS_VPC_ID",
},
cli.StringFlag{
Name: "amazonec2-zone",
Usage: "AWS zone for instance (i.e. a,b,c,d,e)",
Value: "a",
Value: defaultZone,
EnvVar: "AWS_ZONE",
},
cli.StringFlag{
Name: "amazonec2-subnet-id",
Usage: "AWS VPC subnet id",
Value: "",
EnvVar: "AWS_SUBNET_ID",
},
cli.StringFlag{
Name: "amazonec2-security-group",
Usage: "AWS VPC security group",
Value: "docker-machine",
Value: defaultSecurityGroup,
EnvVar: "AWS_SECURITY_GROUP",
},
cli.StringFlag{
@ -145,7 +144,7 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "amazonec2-ssh-user",
Usage: "set the name of the ssh user",
Value: "ubuntu",
Value: defaultSSHUser,
EnvVar: "AWS_SSH_USER",
},
cli.BoolFlag{
@ -155,7 +154,7 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "amazonec2-spot-price",
Usage: "AWS spot instance bid price (in dollar)",
Value: "0.50",
Value: defaultSpotPrice,
},
cli.BoolFlag{
Name: "amazonec2-private-address-only",
@ -172,13 +171,23 @@ func GetCreateFlags() []cli.Flag {
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
func NewDriver(hostName, storePath string) drivers.Driver {
id := generateId()
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{
Id: id,
BaseDriver: inner,
}, nil
Id: id,
AMI: defaultAmiId,
Region: defaultRegion,
InstanceType: defaultInstanceType,
RootSize: defaultRootSize,
Zone: defaultZone,
SecurityGroupName: defaultSecurityGroup,
SpotPrice: defaultSpotPrice,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultSSHUser,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
@ -372,7 +381,7 @@ func (d *Driver) Create() error {
d.InstanceId = instance.InstanceId
log.Debug("waiting for ip address to become available")
if err := utils.WaitFor(d.instanceIpAvailable); err != nil {
if err := mcnutils.WaitFor(d.instanceIpAvailable); err != nil {
return err
}
@ -536,7 +545,7 @@ func (d *Driver) instanceIsRunning() bool {
}
func (d *Driver) waitForInstance() error {
if err := utils.WaitFor(d.instanceIsRunning); err != nil {
if err := mcnutils.WaitFor(d.instanceIsRunning); err != nil {
return err
}
@ -622,7 +631,7 @@ func (d *Driver) configureSecurityGroup(groupName string) error {
securityGroup = group
// wait until created (dat eventual consistency)
log.Debugf("waiting for group (%s) to become available", group.GroupId)
if err := utils.WaitFor(d.securityGroupAvailableFunc(group.GroupId)); err != nil {
if err := mcnutils.WaitFor(d.securityGroupAvailableFunc(group.GroupId)); err != nil {
return err
}
}

View File

@ -98,10 +98,7 @@ func getTestDriver() (*Driver, error) {
}
defer cleanup()
d, err := NewDriver(machineTestName, storePath, machineTestCaCert, machineTestPrivateKey)
if err != nil {
return nil, err
}
d := NewDriver(machineTestName, storePath)
d.SetConfigFromFlags(getDefaultTestDriverFlags())
drv := d.(*Driver)
return drv, nil

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -9,8 +9,8 @@ import (
"net/url"
"strconv"
"github.com/docker/machine/log"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
awsauth "github.com/smartystreets/go-aws-auth"
)
@ -151,7 +151,7 @@ func NewEC2(auth Auth, region string) *EC2 {
func (e *EC2) awsApiCall(v url.Values) (*http.Response, error) {
v.Set("Version", "2014-06-15")
log.Debug("Making AWS API call with values:")
utils.DumpVal(v)
mcnutils.DumpVal(v)
client := &http.Client{}
finalEndpoint := fmt.Sprintf("%s?%s", e.Endpoint, v.Encode())
req, err := http.NewRequest("GET", finalEndpoint, nil)

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -1 +0,0 @@
package amz

View File

@ -11,11 +11,11 @@ import (
"github.com/MSOpenTech/azure-sdk-for-go/clients/vmClient"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
@ -31,9 +31,17 @@ type Driver struct {
DockerSwarmMasterPort int
}
const (
defaultDockerPort = 2376
defaultSwarmMasterPort = 3376
defaultLocation = "West US"
defaultSize = "Small"
defaultSSHPort = 22
defaultSSHUsername = "ubuntu"
)
func init() {
drivers.Register("azure", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -45,12 +53,12 @@ func GetCreateFlags() []cli.Flag {
cli.IntFlag{
Name: "azure-docker-port",
Usage: "Azure Docker port",
Value: 2376,
Value: defaultDockerPort,
},
cli.IntFlag{
Name: "azure-docker-swarm-master-port",
Usage: "Azure Docker Swarm master port",
Value: 3376,
Value: defaultSwarmMasterPort,
},
cli.StringFlag{
EnvVar: "AZURE_IMAGE",
@ -61,7 +69,7 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "AZURE_LOCATION",
Name: "azure-location",
Usage: "Azure location",
Value: "West US",
Value: defaultLocation,
},
cli.StringFlag{
Name: "azure-password",
@ -76,12 +84,12 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "AZURE_SIZE",
Name: "azure-size",
Usage: "Azure size",
Value: "Small",
Value: defaultSize,
},
cli.IntFlag{
Name: "azure-ssh-port",
Usage: "Azure SSH port",
Value: 22,
Value: defaultSSHPort,
},
cli.StringFlag{
@ -97,15 +105,25 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "azure-username",
Usage: "Azure username",
Value: "ubuntu",
Value: defaultSSHUsername,
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
d := &Driver{BaseDriver: inner}
return d, nil
func NewDriver(hostName, storePath string) drivers.Driver {
d := &Driver{
DockerPort: defaultDockerPort,
DockerSwarmMasterPort: defaultSwarmMasterPort,
Location: defaultLocation,
Size: defaultSize,
BaseDriver: &drivers.BaseDriver{
SSHPort: defaultSSHPort,
SSHUser: defaultSSHUsername,
MachineName: hostName,
StorePath: storePath,
},
}
return d
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -368,7 +386,7 @@ func (d *Driver) Kill() error {
}
func generateVMName() string {
randomID := utils.TruncateID(utils.GenerateRandomID())
randomID := mcnutils.TruncateID(mcnutils.GenerateRandomID())
return fmt.Sprintf("docker-host-%s", randomID)
}

View File

@ -1 +0,0 @@
package azure

View File

@ -8,10 +8,10 @@ import (
"code.google.com/p/goauth2/oauth"
"github.com/codegangsta/cli"
"github.com/digitalocean/godo"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
@ -28,9 +28,14 @@ type Driver struct {
PrivateNetworking bool
}
const (
defaultImage = "ubuntu-14-04-x64"
defaultRegion = "nyc3"
defaultSize = "512mb"
)
func init() {
drivers.Register("digitalocean", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -54,19 +59,19 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "DIGITALOCEAN_IMAGE",
Name: "digitalocean-image",
Usage: "Digital Ocean Image",
Value: "ubuntu-14-04-x64",
Value: defaultImage,
},
cli.StringFlag{
EnvVar: "DIGITALOCEAN_REGION",
Name: "digitalocean-region",
Usage: "Digital Ocean region",
Value: "nyc3",
Value: defaultRegion,
},
cli.StringFlag{
EnvVar: "DIGITALOCEAN_SIZE",
Name: "digitalocean-size",
Usage: "Digital Ocean size",
Value: "512mb",
Value: defaultSize,
},
cli.BoolFlag{
EnvVar: "DIGITALOCEAN_IPV6",
@ -86,9 +91,16 @@ func GetCreateFlags() []cli.Flag {
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) *Driver {
return &Driver{
Image: defaultImage,
Size: defaultSize,
Region: defaultRegion,
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {

View File

@ -1 +0,0 @@
package digitalocean

View File

@ -0,0 +1,65 @@
package driverfactory
import (
"fmt"
"github.com/docker/machine/drivers/amazonec2"
"github.com/docker/machine/drivers/azure"
"github.com/docker/machine/drivers/digitalocean"
"github.com/docker/machine/drivers/exoscale"
"github.com/docker/machine/drivers/generic"
"github.com/docker/machine/drivers/google"
"github.com/docker/machine/drivers/hyperv"
"github.com/docker/machine/drivers/none"
"github.com/docker/machine/drivers/openstack"
"github.com/docker/machine/drivers/rackspace"
"github.com/docker/machine/drivers/softlayer"
"github.com/docker/machine/drivers/virtualbox"
"github.com/docker/machine/drivers/vmwarefusion"
"github.com/docker/machine/drivers/vmwarevcloudair"
"github.com/docker/machine/drivers/vmwarevsphere"
"github.com/docker/machine/libmachine/drivers"
)
func NewDriver(driverName, hostName, storePath string) (drivers.Driver, error) {
var (
driver drivers.Driver
)
switch driverName {
case "virtualbox":
driver = virtualbox.NewDriver(hostName, storePath)
case "digitalocean":
driver = digitalocean.NewDriver(hostName, storePath)
case "amazonec2":
driver = amazonec2.NewDriver(hostName, storePath)
case "azure":
driver = azure.NewDriver(hostName, storePath)
case "exoscale":
driver = exoscale.NewDriver(hostName, storePath)
case "generic":
driver = generic.NewDriver(hostName, storePath)
case "google":
driver = google.NewDriver(hostName, storePath)
case "hyperv":
driver = hyperv.NewDriver(hostName, storePath)
case "openstack":
driver = openstack.NewDriver(hostName, storePath)
case "rackspace":
driver = rackspace.NewDriver(hostName, storePath)
case "softlayer":
driver = softlayer.NewDriver(hostName, storePath)
case "vmwarefusion":
driver = vmwarefusion.NewDriver(hostName, storePath)
case "vmwarevcloudair":
driver = vmwarevcloudair.NewDriver(hostName, storePath)
case "vmwarevsphere":
driver = vmwarevsphere.NewDriver(hostName, storePath)
case "none":
driver = none.NewDriver(hostName, storePath)
default:
return nil, fmt.Errorf("Driver %q not recognized", driverName)
}
return driver, nil
}

View File

@ -9,10 +9,10 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/state"
"github.com/pyr/egoscale/src/egoscale"
)
@ -31,9 +31,15 @@ type Driver struct {
Id string
}
const (
defaultInstanceProfile = "small"
defaultDiskSize = 50
defaultImage = "ubuntu-14.04"
defaultAvailabilityZone = "ch-gva-2"
)
func init() {
drivers.Register("exoscale", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -60,19 +66,19 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
EnvVar: "EXOSCALE_INSTANCE_PROFILE",
Name: "exoscale-instance-profile",
Value: "small",
Value: defaultInstanceProfile,
Usage: "exoscale instance profile (small, medium, large, ...)",
},
cli.IntFlag{
EnvVar: "EXOSCALE_DISK_SIZE",
Name: "exoscale-disk-size",
Value: 50,
Value: defaultDiskSize,
Usage: "exoscale disk size (10, 50, 100, 200, 400)",
},
cli.StringFlag{
EnvVar: "EXSOCALE_IMAGE",
Name: "exoscale-image",
Value: "ubuntu-14.04",
Value: defaultImage,
Usage: "exoscale image template",
},
cli.StringSliceFlag{
@ -84,15 +90,23 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
EnvVar: "EXOSCALE_AVAILABILITY_ZONE",
Name: "exoscale-availability-zone",
Value: "ch-gva-2",
Value: defaultAvailabilityZone,
Usage: "exoscale availibility zone",
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
InstanceProfile: defaultInstanceProfile,
DiskSize: defaultDiskSize,
Image: defaultImage,
AvailabilityZone: defaultAvailabilityZone,
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -426,7 +440,7 @@ func (d *Driver) jobIsDone(client *egoscale.Client, jobid string) (bool, error)
func (d *Driver) waitForJob(client *egoscale.Client, jobid string) error {
log.Infof("Waiting for job to complete...")
return utils.WaitForSpecificOrError(func() (bool, error) {
return mcnutils.WaitForSpecificOrError(func() (bool, error) {
return d.jobIsDone(client, jobid)
}, 60, 2*time.Second)
}

View File

@ -1 +0,0 @@
package exoscale

View File

@ -1,8 +1,8 @@
package fakedriver
import (
"github.com/docker/machine/drivers"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/state"
)
type FakeDriver struct {

View File

@ -1 +0,0 @@
package fakedriver

View File

@ -8,10 +8,10 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
@ -20,12 +20,17 @@ type Driver struct {
}
const (
defaultSSHUser = "root"
defaultSSHPort = 22
defaultTimeout = 1 * time.Second
)
var (
defaultSSHKey = filepath.Join(mcnutils.GetHomeDir(), ".ssh", "id_rsa")
)
func init() {
drivers.Register("generic", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -37,29 +42,35 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "generic-ip-address",
Usage: "IP Address of machine",
Value: "",
},
cli.StringFlag{
Name: "generic-ssh-user",
Usage: "SSH user",
Value: "root",
Value: defaultSSHUser,
},
cli.StringFlag{
Name: "generic-ssh-key",
Usage: "SSH private key path",
Value: filepath.Join(utils.GetHomeDir(), ".ssh", "id_rsa"),
Value: defaultSSHKey,
},
cli.IntFlag{
Name: "generic-ssh-port",
Usage: "SSH port",
Value: 22,
Value: defaultSSHPort,
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
SSHKey: defaultSSHKey,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultSSHUser,
SSHPort: defaultSSHPort,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) DriverName() string {
@ -98,7 +109,7 @@ func (d *Driver) PreCreateCheck() error {
func (d *Driver) Create() error {
log.Infof("Importing SSH key...")
if err := utils.CopyFile(d.SSHKey, d.GetSSHKeyPath()); err != nil {
if err := mcnutils.CopyFile(d.SSHKey, d.GetSSHKeyPath()); err != nil {
return fmt.Errorf("unable to copy ssh key: %s", err)
}

View File

@ -1 +0,0 @@
package generic

View File

@ -12,7 +12,7 @@ import (
"time"
"code.google.com/p/goauth2/oauth"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
raw "google.golang.org/api/compute/v1"
)

View File

@ -1 +0,0 @@
package google

View File

@ -8,8 +8,8 @@ import (
"strings"
"time"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/ssh"
raw "google.golang.org/api/compute/v1"
)

View File

@ -1 +0,0 @@
package google

View File

@ -5,10 +5,10 @@ import (
"strings"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
// Driver is a struct compatible with the docker.hosts.drivers.Driver interface.
@ -26,9 +26,17 @@ type Driver struct {
Tags []string
}
const (
defaultZone = "us-central1-a"
defaultUser = "docker-user"
defaultMachineType = "f1-micro"
defaultScopes = "https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write"
defaultDiskType = "pd-standard"
defaultDiskSize = 10
)
func init() {
drivers.Register("google", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -40,19 +48,19 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "google-zone",
Usage: "GCE Zone",
Value: "us-central1-a",
Value: defaultZone,
EnvVar: "GOOGLE_ZONE",
},
cli.StringFlag{
Name: "google-machine-type",
Usage: "GCE Machine Type",
Value: "f1-micro",
Value: defaultMachineType,
EnvVar: "GOOGLE_MACHINE_TYPE",
},
cli.StringFlag{
Name: "google-username",
Usage: "GCE User Name",
Value: "docker-user",
Value: defaultUser,
EnvVar: "GOOGLE_USERNAME",
},
cli.StringFlag{
@ -68,19 +76,19 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "google-scopes",
Usage: "GCE Scopes (comma-separated if multiple scopes)",
Value: "https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write",
Value: defaultScopes,
EnvVar: "GOOGLE_SCOPES",
},
cli.IntFlag{
Name: "google-disk-size",
Usage: "GCE Instance Disk Size (in GB)",
Value: 10,
Value: defaultDiskSize,
EnvVar: "GOOGLE_DISK_SIZE",
},
cli.StringFlag{
Name: "google-disk-type",
Usage: "GCE Instance Disk type",
Value: "pd-standard",
Value: defaultDiskType,
EnvVar: "GOOGLE_DISK_TYPE",
},
cli.StringFlag{
@ -102,9 +110,19 @@ func GetCreateFlags() []cli.Flag {
}
// NewDriver creates a Driver with the specified storePath.
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(machineName string, storePath string) *Driver {
return &Driver{
Zone: defaultZone,
DiskType: defaultDiskType,
DiskSize: defaultDiskSize,
MachineType: defaultMachineType,
Scopes: defaultScopes,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultUser,
MachineName: machineName,
StorePath: storePath,
},
}
}
// GetSSHHostname returns hostname for use with ssh

View File

@ -1 +0,0 @@
package google

View File

@ -1,2 +1,472 @@
// this is empty to allow builds on non-windows platforms
package hyperv
import (
"archive/tar"
"bytes"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
*drivers.BaseDriver
boot2DockerURL string
boot2DockerLoc string
vSwitch string
diskImage string
DiskSize int
MemSize int
}
const (
defaultDiskSize = 20000
defaultMemory = 1024
)
func init() {
drivers.Register("hyper-v", &drivers.RegisteredDriver{
GetCreateFlags: GetCreateFlags,
})
}
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
DiskSize: defaultDiskSize,
MemSize: defaultMemory,
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
}
}
// GetCreateFlags registers the flags this driver adds to
// "docker hosts create"
func GetCreateFlags() []cli.Flag {
return []cli.Flag{
cli.StringFlag{
Name: "hyper-v-boot2docker-url",
Usage: "Hyper-V URL of the boot2docker image. Defaults to the latest available version.",
},
cli.StringFlag{
Name: "hyper-v-boot2docker-location",
Usage: "Hyper-V local boot2docker iso. Overrides URL.",
},
cli.StringFlag{
Name: "hyper-v-virtual-switch",
Usage: "Hyper-V virtual switch name. Defaults to first found.",
},
cli.IntFlag{
Name: "hyper-v-disk-size",
Usage: "Hyper-V disk size for host in MB.",
Value: defaultDiskSize,
},
cli.IntFlag{
Name: "hyper-v-memory",
Usage: "Hyper-V memory size for host in MB.",
Value: defaultMemory,
},
}
}
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.boot2DockerURL = flags.String("hyper-v-boot2docker-url")
d.boot2DockerLoc = flags.String("hyper-v-boot2docker-location")
d.vSwitch = flags.String("hyper-v-virtual-switch")
d.DiskSize = flags.Int("hyper-v-disk-size")
d.MemSize = flags.Int("hyper-v-memory")
d.SwarmMaster = flags.Bool("swarm-master")
d.SwarmHost = flags.String("swarm-host")
d.SwarmDiscovery = flags.String("swarm-discovery")
d.SSHUser = "docker"
d.SSHPort = 22
return nil
}
func (d *Driver) GetSSHHostname() (string, error) {
return d.GetIP()
}
func (d *Driver) GetSSHUsername() string {
if d.SSHUser == "" {
d.SSHUser = "docker"
}
return d.SSHUser
}
func (d *Driver) DriverName() string {
return "hyper-v"
}
func (d *Driver) PreCreateCheck() error {
return nil
}
func (d *Driver) GetURL() (string, error) {
ip, err := d.GetIP()
if err != nil {
return "", err
}
if ip == "" {
return "", nil
}
return fmt.Sprintf("tcp://%s:2376", ip), nil
}
func (d *Driver) GetState() (state.State, error) {
command := []string{
"(",
"Get-VM",
"-Name", d.MachineName,
").state"}
stdout, err := execute(command)
if err != nil {
return state.None, fmt.Errorf("Failed to find the VM status")
}
resp := parseStdout(stdout)
if len(resp) < 1 {
return state.None, nil
}
switch resp[0] {
case "Running":
return state.Running, nil
case "Off":
return state.Stopped, nil
}
return state.None, nil
}
func (d *Driver) Create() error {
err := hypervAvailable()
if err != nil {
return err
}
d.setMachineNameIfNotSet()
b2dutils := mcnutils.NewB2dUtils("", "", d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.boot2DockerURL, d.MachineName); err != nil {
return err
}
log.Infof("Creating SSH key...")
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
return err
}
log.Infof("Creating VM...")
virtualSwitch, err := d.chooseVirtualSwitch()
if err != nil {
return err
}
err = d.generateDiskImage()
if err != nil {
return err
}
command := []string{
"New-VM",
"-Name", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.ResolveStorePath(".")),
"-MemoryStartupBytes", fmt.Sprintf("%dMB", d.MemSize)}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Set-VMDvdDrive",
"-VMName", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.ResolveStorePath("boot2docker.iso"))}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Add-VMHardDiskDrive",
"-VMName", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.diskImage)}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Connect-VMNetworkAdapter",
"-VMName", d.MachineName,
"-SwitchName", fmt.Sprintf("'%s'", virtualSwitch)}
_, err = execute(command)
if err != nil {
return err
}
log.Infof("Starting VM...")
if err := d.Start(); err != nil {
return err
}
return nil
}
func (d *Driver) chooseVirtualSwitch() (string, error) {
if d.vSwitch != "" {
return d.vSwitch, nil
}
command := []string{
"@(Get-VMSwitch).Name"}
stdout, err := execute(command)
if err != nil {
return "", err
}
switches := parseStdout(stdout)
if len(switches) > 0 {
log.Infof("Using switch %s", switches[0])
return switches[0], nil
}
return "", fmt.Errorf("no vswitch found")
}
func (d *Driver) wait() error {
log.Infof("Waiting for host to start...")
for {
ip, _ := d.GetIP()
if ip != "" {
break
}
time.Sleep(1 * time.Second)
}
return nil
}
func (d *Driver) Start() error {
command := []string{
"Start-VM",
"-Name", d.MachineName}
_, err := execute(command)
if err != nil {
return err
}
if err := d.wait(); err != nil {
return err
}
d.IPAddress, err = d.GetIP()
return err
}
func (d *Driver) Stop() error {
command := []string{
"Stop-VM",
"-Name", d.MachineName}
_, err := execute(command)
if err != nil {
return err
}
for {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
time.Sleep(1 * time.Second)
} else {
break
}
}
d.IPAddress = ""
return nil
}
func (d *Driver) Remove() error {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
if err := d.Kill(); err != nil {
return err
}
}
command := []string{
"Remove-VM",
"-Name", d.MachineName,
"-Force"}
_, err = execute(command)
return err
}
func (d *Driver) Restart() error {
err := d.Stop()
if err != nil {
return err
}
return d.Start()
}
func (d *Driver) Kill() error {
command := []string{
"Stop-VM",
"-Name", d.MachineName,
"-TurnOff"}
_, err := execute(command)
if err != nil {
return err
}
for {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
time.Sleep(1 * time.Second)
} else {
break
}
}
d.IPAddress = ""
return nil
}
func (d *Driver) setMachineNameIfNotSet() {
if d.MachineName == "" {
d.MachineName = fmt.Sprintf("docker-machine-unknown")
}
}
func (d *Driver) GetIP() (string, error) {
command := []string{
"((",
"Get-VM",
"-Name", d.MachineName,
").networkadapters[0]).ipaddresses[0]"}
stdout, err := execute(command)
if err != nil {
return "", err
}
resp := parseStdout(stdout)
if len(resp) < 1 {
return "", fmt.Errorf("IP not found")
}
return resp[0], nil
}
func (d *Driver) publicSSHKeyPath() string {
return d.GetSSHKeyPath() + ".pub"
}
func (d *Driver) generateDiskImage() error {
// Create a small fixed vhd, put the tar in,
// convert to dynamic, then resize
d.diskImage = d.ResolveStorePath("disk.vhd")
fixed := d.ResolveStorePath("fixed.vhd")
log.Infof("Creating VHD")
command := []string{
"New-VHD",
"-Path", fmt.Sprintf("'%s'", fixed),
"-SizeBytes", "10MB",
"-Fixed"}
_, err := execute(command)
if err != nil {
return err
}
tarBuf, err := d.generateTar()
if err != nil {
return err
}
file, err := os.OpenFile(fixed, os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
file.Seek(0, os.SEEK_SET)
_, err = file.Write(tarBuf.Bytes())
if err != nil {
return err
}
file.Close()
command = []string{
"Convert-VHD",
"-Path", fmt.Sprintf("'%s'", fixed),
"-DestinationPath", fmt.Sprintf("'%s'", d.diskImage),
"-VHDType", "Dynamic"}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Resize-VHD",
"-Path", fmt.Sprintf("'%s'", d.diskImage),
"-SizeBytes", fmt.Sprintf("%dMB", d.DiskSize)}
_, err = execute(command)
if err != nil {
return err
}
return err
}
// Make a boot2docker VM disk image.
// See https://github.com/boot2docker/boot2docker/blob/master/rootfs/rootfs/etc/rc.d/automount
func (d *Driver) generateTar() (*bytes.Buffer, error) {
magicString := "boot2docker, please format-me"
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
// magicString first so the automount script knows to format the disk
file := &tar.Header{Name: magicString, Size: int64(len(magicString))}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(magicString)); err != nil {
return nil, err
}
// .ssh/key.pub => authorized_keys
file = &tar.Header{Name: ".ssh", Typeflag: tar.TypeDir, Mode: 0700}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
pubKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
if err != nil {
return nil, err
}
file = &tar.Header{Name: ".ssh/authorized_keys", Size: int64(len(pubKey)), Mode: 0644}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(pubKey)); err != nil {
return nil, err
}
file = &tar.Header{Name: ".ssh/authorized_keys2", Size: int64(len(pubKey)), Mode: 0644}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(pubKey)); err != nil {
return nil, err
}
if err := tw.Close(); err != nil {
return nil, err
}
return buf, nil
}

View File

@ -1 +0,0 @@
package hyperv

View File

@ -1,509 +0,0 @@
package hyperv
import (
"archive/tar"
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
)
type Driver struct {
*drivers.BaseDriver
boot2DockerURL string
boot2DockerLoc string
vSwitch string
diskImage string
diskSize int
memSize int
}
func init() {
drivers.Register("hyper-v", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
// GetCreateFlags registers the flags this driver adds to
// "docker hosts create"
func GetCreateFlags() []cli.Flag {
return []cli.Flag{
cli.StringFlag{
Name: "hyper-v-boot2docker-url",
Usage: "Hyper-V URL of the boot2docker image. Defaults to the latest available version.",
},
cli.StringFlag{
Name: "hyper-v-boot2docker-location",
Usage: "Hyper-V local boot2docker iso. Overrides URL.",
},
cli.StringFlag{
Name: "hyper-v-virtual-switch",
Usage: "Hyper-V virtual switch name. Defaults to first found.",
},
cli.IntFlag{
Name: "hyper-v-disk-size",
Usage: "Hyper-V disk size for host in MB.",
Value: 20000,
},
cli.IntFlag{
Name: "hyper-v-memory",
Usage: "Hyper-V memory size for host in MB.",
Value: 1024,
},
}
}
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.boot2DockerURL = flags.String("hyper-v-boot2docker-url")
d.boot2DockerLoc = flags.String("hyper-v-boot2docker-location")
d.vSwitch = flags.String("hyper-v-virtual-switch")
d.diskSize = flags.Int("hyper-v-disk-size")
d.memSize = flags.Int("hyper-v-memory")
d.SwarmMaster = flags.Bool("swarm-master")
d.SwarmHost = flags.String("swarm-host")
d.SwarmDiscovery = flags.String("swarm-discovery")
d.SSHUser = "docker"
d.SSHPort = 22
return nil
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
}
func (d *Driver) GetSSHHostname() (string, error) {
return d.GetIP()
}
func (d *Driver) GetSSHUsername() string {
if d.SSHUser == "" {
d.SSHUser = "docker"
}
return d.SSHUser
}
func (d *Driver) DriverName() string {
return "hyper-v"
}
func (d *Driver) PreCreateCheck() error {
return nil
}
func (d *Driver) GetURL() (string, error) {
ip, err := d.GetIP()
if err != nil {
return "", err
}
if ip == "" {
return "", nil
}
return fmt.Sprintf("tcp://%s:2376", ip), nil
}
func (d *Driver) GetState() (state.State, error) {
command := []string{
"(",
"Get-VM",
"-Name", d.MachineName,
").state"}
stdout, err := execute(command)
if err != nil {
return state.None, fmt.Errorf("Failed to find the VM status")
}
resp := parseStdout(stdout)
if len(resp) < 1 {
return state.None, nil
}
switch resp[0] {
case "Running":
return state.Running, nil
case "Off":
return state.Stopped, nil
}
return state.None, nil
}
func (d *Driver) Create() error {
err := hypervAvailable()
if err != nil {
return err
}
d.setMachineNameIfNotSet()
var isoURL string
b2dutils := utils.NewB2dUtils("", "")
if d.boot2DockerLoc == "" {
if d.boot2DockerURL != "" {
isoURL = d.boot2DockerURL
log.Infof("Downloading boot2docker.iso from %s...", isoURL)
if err := b2dutils.DownloadISO(d.ResolveStorePath("."), "boot2docker.iso", isoURL); err != nil {
return err
}
} else {
// todo: check latest release URL, download if it's new
// until then always use "latest"
isoURL, err = b2dutils.GetLatestBoot2DockerReleaseURL()
if err != nil {
log.Warnf("Unable to check for the latest release: %s", err)
}
// todo: use real constant for .docker
rootPath := filepath.Join(utils.GetDockerDir())
imgPath := filepath.Join(rootPath, "images")
commonIsoPath := filepath.Join(imgPath, "boot2docker.iso")
if _, err := os.Stat(commonIsoPath); os.IsNotExist(err) {
log.Infof("Downloading boot2docker.iso to %s...", commonIsoPath)
// just in case boot2docker.iso has been manually deleted
if _, err := os.Stat(imgPath); os.IsNotExist(err) {
if err := os.Mkdir(imgPath, 0700); err != nil {
return err
}
}
if err := b2dutils.DownloadISO(imgPath, "boot2docker.iso", isoURL); err != nil {
return err
}
}
isoDest := d.ResolveStorePath("boot2docker.iso")
if err := utils.CopyFile(commonIsoPath, isoDest); err != nil {
return err
}
}
} else {
if err := utils.CopyFile(d.boot2DockerLoc, d.ResolveStorePath("boot2docker.iso")); err != nil {
return err
}
}
log.Infof("Creating SSH key...")
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
return err
}
log.Infof("Creating VM...")
virtualSwitch, err := d.chooseVirtualSwitch()
if err != nil {
return err
}
err = d.generateDiskImage()
if err != nil {
return err
}
command := []string{
"New-VM",
"-Name", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.ResolveStorePath(".")),
"-MemoryStartupBytes", fmt.Sprintf("%dMB", d.memSize)}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Set-VMDvdDrive",
"-VMName", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.ResolveStorePath("boot2docker.iso"))}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Add-VMHardDiskDrive",
"-VMName", d.MachineName,
"-Path", fmt.Sprintf("'%s'", d.diskImage)}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Connect-VMNetworkAdapter",
"-VMName", d.MachineName,
"-SwitchName", fmt.Sprintf("'%s'", virtualSwitch)}
_, err = execute(command)
if err != nil {
return err
}
log.Infof("Starting VM...")
if err := d.Start(); err != nil {
return err
}
return nil
}
func (d *Driver) chooseVirtualSwitch() (string, error) {
if d.vSwitch != "" {
return d.vSwitch, nil
}
command := []string{
"@(Get-VMSwitch).Name"}
stdout, err := execute(command)
if err != nil {
return "", err
}
switches := parseStdout(stdout)
if len(switches) > 0 {
log.Infof("Using switch %s", switches[0])
return switches[0], nil
}
return "", fmt.Errorf("no vswitch found")
}
func (d *Driver) wait() error {
log.Infof("Waiting for host to start...")
for {
ip, _ := d.GetIP()
if ip != "" {
break
}
time.Sleep(1 * time.Second)
}
return nil
}
func (d *Driver) Start() error {
command := []string{
"Start-VM",
"-Name", d.MachineName}
_, err := execute(command)
if err != nil {
return err
}
if err := d.wait(); err != nil {
return err
}
d.IPAddress, err = d.GetIP()
return err
}
func (d *Driver) Stop() error {
command := []string{
"Stop-VM",
"-Name", d.MachineName}
_, err := execute(command)
if err != nil {
return err
}
for {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
time.Sleep(1 * time.Second)
} else {
break
}
}
d.IPAddress = ""
return nil
}
func (d *Driver) Remove() error {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
if err := d.Kill(); err != nil {
return err
}
}
command := []string{
"Remove-VM",
"-Name", d.MachineName,
"-Force"}
_, err = execute(command)
return err
}
func (d *Driver) Restart() error {
err := d.Stop()
if err != nil {
return err
}
return d.Start()
}
func (d *Driver) Kill() error {
command := []string{
"Stop-VM",
"-Name", d.MachineName,
"-TurnOff"}
_, err := execute(command)
if err != nil {
return err
}
for {
s, err := d.GetState()
if err != nil {
return err
}
if s == state.Running {
time.Sleep(1 * time.Second)
} else {
break
}
}
d.IPAddress = ""
return nil
}
func (d *Driver) setMachineNameIfNotSet() {
if d.MachineName == "" {
d.MachineName = fmt.Sprintf("docker-machine-unknown")
}
}
func (d *Driver) GetIP() (string, error) {
command := []string{
"((",
"Get-VM",
"-Name", d.MachineName,
").networkadapters[0]).ipaddresses[0]"}
stdout, err := execute(command)
if err != nil {
return "", err
}
resp := parseStdout(stdout)
if len(resp) < 1 {
return "", fmt.Errorf("IP not found")
}
return resp[0], nil
}
func (d *Driver) publicSSHKeyPath() string {
return d.GetSSHKeyPath() + ".pub"
}
func (d *Driver) generateDiskImage() error {
// Create a small fixed vhd, put the tar in,
// convert to dynamic, then resize
d.diskImage = d.ResolveStorePath("disk.vhd")
fixed := d.ResolveStorePath("fixed.vhd")
log.Infof("Creating VHD")
command := []string{
"New-VHD",
"-Path", fmt.Sprintf("'%s'", fixed),
"-SizeBytes", "10MB",
"-Fixed"}
_, err := execute(command)
if err != nil {
return err
}
tarBuf, err := d.generateTar()
if err != nil {
return err
}
file, err := os.OpenFile(fixed, os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
file.Seek(0, os.SEEK_SET)
_, err = file.Write(tarBuf.Bytes())
if err != nil {
return err
}
file.Close()
command = []string{
"Convert-VHD",
"-Path", fmt.Sprintf("'%s'", fixed),
"-DestinationPath", fmt.Sprintf("'%s'", d.diskImage),
"-VHDType", "Dynamic"}
_, err = execute(command)
if err != nil {
return err
}
command = []string{
"Resize-VHD",
"-Path", fmt.Sprintf("'%s'", d.diskImage),
"-SizeBytes", fmt.Sprintf("%dMB", d.diskSize)}
_, err = execute(command)
if err != nil {
return err
}
return err
}
// Make a boot2docker VM disk image.
// See https://github.com/boot2docker/boot2docker/blob/master/rootfs/rootfs/etc/rc.d/automount
func (d *Driver) generateTar() (*bytes.Buffer, error) {
magicString := "boot2docker, please format-me"
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
// magicString first so the automount script knows to format the disk
file := &tar.Header{Name: magicString, Size: int64(len(magicString))}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(magicString)); err != nil {
return nil, err
}
// .ssh/key.pub => authorized_keys
file = &tar.Header{Name: ".ssh", Typeflag: tar.TypeDir, Mode: 0700}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
pubKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
if err != nil {
return nil, err
}
file = &tar.Header{Name: ".ssh/authorized_keys", Size: int64(len(pubKey)), Mode: 0644}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(pubKey)); err != nil {
return nil, err
}
file = &tar.Header{Name: ".ssh/authorized_keys2", Size: int64(len(pubKey)), Mode: 0644}
if err := tw.WriteHeader(file); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(pubKey)); err != nil {
return nil, err
}
if err := tw.Close(); err != nil {
return nil, err
}
return buf, nil
}

View File

@ -9,7 +9,7 @@ import (
"path/filepath"
"strings"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
var powershell string

View File

@ -5,8 +5,8 @@ import (
neturl "net/url"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/state"
)
// Driver is the driver used when no driver is selected. It is used to
@ -19,7 +19,6 @@ type Driver struct {
func init() {
drivers.Register("none", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -34,9 +33,13 @@ func GetCreateFlags() []cli.Flag {
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{inner, ""}, nil
func NewDriver(hostName, storePath string) *Driver {
return &Driver{
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) Create() error {

View File

@ -1 +0,0 @@
package none

View File

@ -6,9 +6,9 @@ import (
"net/http"
"time"
"github.com/docker/machine/log"
"github.com/docker/machine/utils"
"github.com/docker/machine/version"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/version"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
@ -136,7 +136,7 @@ func (c *GenericClient) DeleteInstance(d *Driver) error {
}
func (c *GenericClient) WaitForInstanceStatus(d *Driver, status string) error {
return utils.WaitForSpecificOrError(func() (bool, error) {
return mcnutils.WaitForSpecificOrError(func() (bool, error) {
current, err := servers.Get(c.Compute, d.MachineId).Extract()
if err != nil {
return true, err
@ -437,7 +437,7 @@ func (c *GenericClient) Authenticate(d *Driver) error {
return err
}
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.Version))
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%d", version.ApiVersion))
if d.Insecure {
// Configure custom TLS settings.

View File

@ -1 +0,0 @@
package openstack

View File

@ -7,11 +7,11 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
@ -42,9 +42,14 @@ type Driver struct {
client Client
}
const (
defaultSSHUser = "root"
defaultSSHPort = 22
defaultActiveTimeout = 200
)
func init() {
drivers.Register("openstack", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -158,35 +163,36 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "openstack-ssh-user",
Usage: "OpenStack SSH user",
Value: "root",
Value: defaultSSHUser,
},
cli.IntFlag{
Name: "openstack-ssh-port",
Usage: "OpenStack SSH port",
Value: 22,
Value: defaultSSHPort,
},
cli.IntFlag{
Name: "openstack-active-timeout",
Usage: "OpenStack active timeout",
Value: 200,
Value: defaultActiveTimeout,
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
log.WithFields(log.Fields{
"machineName": machineName,
"storePath": storePath,
"caCert": caCert,
"privateKey": privateKey,
}).Debug("Instantiating OpenStack driver...")
return NewDerivedDriver(machineName, storePath, &GenericClient{}, caCert, privateKey)
func NewDriver(hostName, storePath string) drivers.Driver {
return NewDerivedDriver(hostName, storePath)
}
func NewDerivedDriver(machineName string, storePath string, client Client, caCert string, privateKey string) (*Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner, client: client}, nil
func NewDerivedDriver(hostName, storePath string) *Driver {
return &Driver{
client: &GenericClient{},
ActiveTimeout: defaultActiveTimeout,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultSSHUser,
SSHPort: defaultSSHPort,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -310,7 +316,7 @@ func (d *Driver) PreCreateCheck() error {
}
func (d *Driver) Create() error {
d.KeyPairName = fmt.Sprintf("%s-%s", d.MachineName, utils.GenerateRandomID())
d.KeyPairName = fmt.Sprintf("%s-%s", d.MachineName, mcnutils.GenerateRandomID())
if err := d.resolveIds(); err != nil {
return err

View File

@ -1 +0,0 @@
package openstack

View File

@ -4,8 +4,8 @@ import (
"fmt"
"github.com/docker/machine/drivers/openstack"
"github.com/docker/machine/log"
"github.com/docker/machine/version"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/version"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/rackspace"
)
@ -17,7 +17,6 @@ func unsupportedOpErr(operation string) error {
// Client is a Rackspace specialization of the generic OpenStack driver.
type Client struct {
openstack.GenericClient
driver *Driver
}
@ -42,7 +41,7 @@ func (c *Client) Authenticate(d *openstack.Driver) error {
return err
}
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.Version))
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%d", version.ApiVersion))
err = rackspace.Authenticate(provider, opts)
if err != nil {

View File

@ -1 +0,0 @@
package rackspace

View File

@ -4,9 +4,9 @@ import (
"fmt"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/drivers/openstack"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
)
// Driver is a machine driver for Rackspace. It's a specialization of the generic OpenStack one.
@ -16,9 +16,16 @@ type Driver struct {
APIKey string
}
const (
defaultEndpointType = "publicURL"
defaultFlavorId = "general1-1"
defaultSSHUser = "root"
defaultSSHPort = 22
defaultDockerInstall = "true"
)
func init() {
drivers.Register("rackspace", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -49,7 +56,7 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "OS_ENDPOINT_TYPE",
Name: "rackspace-endpoint-type",
Usage: "Rackspace endpoint type (adminURL, internalURL or the default publicURL)",
Value: "publicURL",
Value: defaultEndpointType,
},
cli.StringFlag{
Name: "rackspace-image-id",
@ -58,45 +65,38 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "rackspace-flavor-id",
Usage: "Rackspace flavor ID. Default: General Purpose 1GB",
Value: "general1-1",
Value: defaultFlavorId,
EnvVar: "OS_FLAVOR_ID",
},
cli.StringFlag{
Name: "rackspace-ssh-user",
Usage: "SSH user for the newly booted machine. Set to root by default",
Value: "root",
Value: defaultSSHUser,
},
cli.IntFlag{
Name: "rackspace-ssh-port",
Usage: "SSH port for the newly booted machine. Set to 22 by default",
Value: 22,
Value: defaultSSHPort,
},
cli.StringFlag{
Name: "rackspace-docker-install",
Usage: "Set if docker have to be installed on the machine",
Value: "true",
Value: defaultDockerInstall,
},
}
}
// NewDriver instantiates a Rackspace driver.
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
func NewDriver(machineName, storePath string) drivers.Driver {
log.WithFields(log.Fields{
"machineName": machineName,
"storePath": storePath,
"caCert": caCert,
"privateKey": privateKey,
}).Debug("Instantiating Rackspace driver.")
client := &Client{}
inner, err := openstack.NewDerivedDriver(machineName, storePath, client, caCert, privateKey)
if err != nil {
return nil, err
}
inner := openstack.NewDerivedDriver(machineName, storePath)
driver := &Driver{Driver: inner}
client.driver = driver
return driver, nil
return &Driver{
Driver: inner,
}
}
// DriverName is the user-visible name of this driver.

View File

@ -1 +0,0 @@
package rackspace

View File

@ -8,10 +8,10 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
const (
@ -41,16 +41,42 @@ type deviceConfig struct {
PrivateVLAN int
}
const (
defaultMemory = 1024
defaultDiskSize = 0
defaultRegion = "dal01"
defaultCpus = 1
defaultImage = "UBUNTU_LATEST"
defaultPublicVLANIP = 0
defaultPrivateVLANIP = 0
)
func init() {
drivers.Register("softlayer", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
Client: &Client{
Endpoint: ApiEndpoint,
},
deviceConfig: &deviceConfig{
HourlyBilling: true,
DiskSize: defaultDiskSize,
Image: defaultImage,
Memory: defaultMemory,
Cpu: defaultCpus,
Region: defaultRegion,
PrivateVLAN: defaultPrivateVLANIP,
PublicVLAN: defaultPublicVLANIP,
},
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -67,49 +93,45 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "SOFTLAYER_MEMORY",
Name: "softlayer-memory",
Usage: "Memory in MB for machine",
Value: 1024,
Value: defaultMemory,
},
cli.IntFlag{
EnvVar: "SOFTLAYER_DISK_SIZE",
Name: "softlayer-disk-size",
Usage: "Disk size for machine, a value of 0 uses the default size on softlayer",
Value: 0,
Value: defaultDiskSize,
},
cli.StringFlag{
EnvVar: "SOFTLAYER_USER",
Name: "softlayer-user",
Usage: "softlayer user account name",
Value: "",
},
cli.StringFlag{
EnvVar: "SOFTLAYER_API_KEY",
Name: "softlayer-api-key",
Usage: "softlayer user API key",
Value: "",
},
cli.StringFlag{
EnvVar: "SOFTLAYER_REGION",
Name: "softlayer-region",
Usage: "softlayer region for machine",
Value: "dal01",
Value: defaultRegion,
},
cli.IntFlag{
EnvVar: "SOFTLAYER_CPU",
Name: "softlayer-cpu",
Usage: "number of CPU's for the machine",
Value: 1,
Value: defaultCpus,
},
cli.StringFlag{
EnvVar: "SOFTLAYER_HOSTNAME",
Name: "softlayer-hostname",
Usage: "hostname for the machine - defaults to machine name",
Value: "",
},
cli.StringFlag{
EnvVar: "SOFTLAYER_DOMAIN",
Name: "softlayer-domain",
Usage: "domain name for machine",
Value: "",
},
cli.StringFlag{
EnvVar: "SOFTLAYER_API_ENDPOINT",
@ -136,19 +158,17 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "SOFTLAYER_IMAGE",
Name: "softlayer-image",
Usage: "OS image for machine",
Value: "UBUNTU_LATEST",
Value: defaultImage,
},
cli.IntFlag{
EnvVar: "SOFTLAYER_PUBLIC_VLAN_ID",
Name: "softlayer-public-vlan-id",
Usage: "",
Value: 0,
},
cli.IntFlag{
EnvVar: "SOFTLAYER_PRIVATE_VLAN_ID",
Name: "softlayer-private-vlan-id",
Usage: "",
Value: 0,
},
}
}

View File

@ -80,10 +80,7 @@ func getTestDriver() (*Driver, error) {
}
defer cleanup()
d, err := NewDriver(machineTestName, storePath, machineTestCaCert, machineTestPrivateKey)
if err != nil {
return nil, err
}
d := NewDriver(machineTestName, storePath)
d.SetConfigFromFlags(getDefaultTestDriverFlags())
drv := d.(*Driver)
return drv, nil

View File

@ -1 +0,0 @@
package softlayer

View File

@ -11,7 +11,7 @@ import (
"runtime"
"strings"
"github.com/docker/machine/log"
"github.com/docker/machine/libmachine/log"
)
var (
@ -68,15 +68,17 @@ func vbmOut(args ...string) (string, error) {
func vbmOutErr(args ...string) (string, string, error) {
cmd := exec.Command(vboxManageCmd, args...)
log.Debugf("executing: %v %v", vboxManageCmd, strings.Join(args, " "))
log.Debugf("COMMAND: %v %v", vboxManageCmd, strings.Join(args, " "))
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
stderrStr := stderr.String()
log.Debugf("STDOUT: %v", stdout.String())
log.Debugf("STDERR: %v", stderrStr)
if len(args) > 0 {
log.Debugf("STDOUT:\n{\n%v}", stdout.String())
log.Debugf("STDERR:\n{\n%v}", stderrStr)
}
if err != nil {
if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound {
err = ErrVBMNotFound

View File

@ -1 +0,0 @@
package virtualbox

View File

@ -19,18 +19,24 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
const (
isoFilename = "boot2docker.iso"
defaultHostOnlyCIDR = "192.168.99.1/24"
defaultNictype = "82540EM"
defaultNicpromisc = "deny"
isoFilename = "boot2docker.iso"
defaultCPU = 1
defaultMemory = 1024
defaultBoot2DockerURL = ""
defaultBoot2DockerImportVM = ""
defaultHostOnlyCIDR = "192.168.99.1/24"
defaultHostOnlyNictype = "82540EM"
defaultHostOnlyPromiscMode = "deny"
defaultNoShare = false
defaultDiskSize = 20000
)
var (
@ -52,11 +58,25 @@ type Driver struct {
func init() {
drivers.Register("virtualbox", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
func NewDriver(hostName, storePath string) *Driver {
return &Driver{
BaseDriver: &drivers.BaseDriver{
MachineName: hostName,
StorePath: storePath,
},
Memory: defaultMemory,
CPU: defaultCPU,
DiskSize: defaultDiskSize,
HostOnlyCIDR: defaultHostOnlyCIDR,
HostOnlyNicType: defaultHostOnlyNictype,
HostOnlyPromiscMode: defaultHostOnlyPromiscMode,
}
}
// RegisterCreateFlags registers the flags this driver adds to
// "docker hosts create"
func GetCreateFlags() []cli.Flag {
@ -65,30 +85,30 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "VIRTUALBOX_MEMORY_SIZE",
Name: "virtualbox-memory",
Usage: "Size of memory for host in MB",
Value: 1024,
Value: defaultMemory,
},
cli.IntFlag{
EnvVar: "VIRTUALBOX_CPU_COUNT",
Name: "virtualbox-cpu-count",
Usage: "number of CPUs for the machine (-1 to use the number of CPUs available)",
Value: 1,
Value: defaultCPU,
},
cli.IntFlag{
EnvVar: "VIRTUALBOX_DISK_SIZE",
Name: "virtualbox-disk-size",
Usage: "Size of disk for host in MB",
Value: 20000,
Value: defaultDiskSize,
},
cli.StringFlag{
EnvVar: "VIRTUALBOX_BOOT2DOCKER_URL",
Name: "virtualbox-boot2docker-url",
Usage: "The URL of the boot2docker image. Defaults to the latest available version",
Value: "",
Value: defaultBoot2DockerURL,
},
cli.StringFlag{
Name: "virtualbox-import-boot2docker-vm",
Usage: "The name of a Boot2Docker VM to import",
Value: "",
Value: defaultBoot2DockerImportVM,
},
cli.StringFlag{
Name: "virtualbox-hostonly-cidr",
@ -99,13 +119,13 @@ func GetCreateFlags() []cli.Flag {
cli.StringFlag{
Name: "virtualbox-hostonly-nictype",
Usage: "Specify the Host Only Network Adapter Type",
Value: defaultNictype,
Value: defaultHostOnlyNictype,
EnvVar: "VIRTUALBOX_HOSTONLY_NIC_TYPE",
},
cli.StringFlag{
Name: "virtualbox-hostonly-nicpromisc",
Usage: "Specify the Host Only Network Adapter Promiscuous Mode",
Value: defaultNicpromisc,
Value: defaultHostOnlyPromiscMode,
EnvVar: "VIRTUALBOX_HOSTONLY_NIC_PROMISC",
},
cli.BoolFlag{
@ -115,11 +135,6 @@ func GetCreateFlags() []cli.Flag {
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
}
func (d *Driver) GetSSHHostname() (string, error) {
return "localhost", nil
}
@ -179,7 +194,7 @@ func (d *Driver) Create() error {
return err
}
b2dutils := utils.NewB2dUtils("", "")
b2dutils := mcnutils.NewB2dUtils("", "", d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
return err
}
@ -216,8 +231,8 @@ func (d *Driver) Create() error {
d.Memory = vmInfo.Memory
log.Debugf("Importing SSH key...")
keyPath := filepath.Join(utils.GetHomeDir(), ".ssh", "id_boot2docker")
if err := utils.CopyFile(keyPath, d.GetSSHKeyPath()); err != nil {
keyPath := filepath.Join(mcnutils.GetHomeDir(), ".ssh", "id_boot2docker")
if err := mcnutils.CopyFile(keyPath, d.GetSSHKeyPath()); err != nil {
return err
}
} else {
@ -416,7 +431,7 @@ func (d *Driver) Start() error {
}
// Bail if we don't get an IP from DHCP after a given number of seconds.
if err := utils.WaitForSpecific(d.hostOnlyIpAvailable, 5, 4*time.Second); err != nil {
if err := mcnutils.WaitForSpecific(d.hostOnlyIpAvailable, 5, 4*time.Second); err != nil {
return err
}
@ -510,12 +525,6 @@ func (d *Driver) GetState() (state.State, error) {
return state.None, nil
}
func (d *Driver) setMachineNameIfNotSet() {
if d.MachineName == "" {
d.MachineName = fmt.Sprintf("docker-machine-unknown")
}
}
func (d *Driver) GetIP() (string, error) {
// DHCP is used to get the IP, so virtualbox hosts don't have IPs unless
// they are running

View File

@ -18,11 +18,11 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
cryptossh "golang.org/x/crypto/ssh"
)
@ -48,9 +48,16 @@ type Driver struct {
ConfigDriveURL string
}
const (
defaultSSHUser = B2DUser
defaultSSHPass = B2DPass
defaultDiskSize = 20000
defaultCpus = 1
defaultMemory = 1024
)
func init() {
drivers.Register("vmwarefusion", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -73,38 +80,47 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "FUSION_CPU_COUNT",
Name: "vmwarefusion-cpu-count",
Usage: "number of CPUs for the machine (-1 to use the number of CPUs available)",
Value: 1,
Value: defaultCpus,
},
cli.IntFlag{
EnvVar: "FUSION_MEMORY_SIZE",
Name: "vmwarefusion-memory-size",
Usage: "Fusion size of memory for host VM (in MB)",
Value: 1024,
Value: defaultMemory,
},
cli.IntFlag{
EnvVar: "FUSION_DISK_SIZE",
Name: "vmwarefusion-disk-size",
Usage: "Fusion size of disk for host VM (in MB)",
Value: 20000,
Value: defaultDiskSize,
},
cli.StringFlag{
EnvVar: "FUSION_SSH_USER",
Name: "vmwarefusion-ssh-user",
Usage: "SSH user",
Value: B2DUser,
Value: defaultSSHUser,
},
cli.StringFlag{
EnvVar: "FUSION_SSH_PASSWORD",
Name: "vmwarefusion-ssh-password",
Usage: "SSH password",
Value: B2DPass,
Value: defaultSSHPass,
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
CPUS: defaultCpus,
Memory: defaultMemory,
DiskSize: defaultDiskSize,
SSHPassword: defaultSSHPass,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultSSHUser,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -129,7 +145,6 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.DiskSize = flags.Int("vmwarefusion-disk-size")
d.Boot2DockerURL = flags.String("vmwarefusion-boot2docker-url")
d.ConfigDriveURL = flags.String("vmwarefusion-configdrive-url")
d.ConfigDriveISO = d.ResolveStorePath(isoConfigDrive)
d.ISO = d.ResolveStorePath(isoFilename)
d.SwarmMaster = flags.Bool("swarm-master")
d.SwarmHost = flags.String("swarm-host")
@ -191,8 +206,7 @@ func (d *Driver) PreCreateCheck() error {
}
func (d *Driver) Create() error {
b2dutils := utils.NewB2dUtils("", "")
b2dutils := mcnutils.NewB2dUtils("", "", d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
return err
}

View File

@ -1 +0,0 @@
package vmwarefusion

View File

@ -8,11 +8,12 @@ import (
"bytes"
"errors"
"fmt"
"github.com/docker/machine/log"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/docker/machine/libmachine/log"
)
var (

View File

@ -1 +0,0 @@
package vmwarefusion

View File

@ -1,2 +0,0 @@
// Package vmwarefusion is empty to allow builds on non-darwin platforms
package vmwarefusion

View File

@ -1 +0,0 @@
package vmwarefusion

View File

@ -12,11 +12,11 @@ import (
"github.com/vmware/govcloudair"
"github.com/codegangsta/cli"
"github.com/docker/machine/drivers"
"github.com/docker/machine/log"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
@ -37,9 +37,17 @@ type Driver struct {
VAppID string
}
const (
defaultCatalog = "Public Catalog"
defaultCatalogItem = "Ubuntu Server 12.04 LTS (amd64 20150127)"
defaultCpus = 1
defaultMemory = 2048
defaultSSHPort = 22
defaultDockerPort = 2376
)
func init() {
drivers.Register("vmwarevcloudair", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
@ -87,13 +95,13 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "VCLOUDAIR_CATALOG",
Name: "vmwarevcloudair-catalog",
Usage: "vCloud Air Catalog (default is Public Catalog)",
Value: "Public Catalog",
Value: defaultCatalog,
},
cli.StringFlag{
EnvVar: "VCLOUDAIR_CATALOGITEM",
Name: "vmwarevcloudair-catalogitem",
Usage: "vCloud Air Catalog Item (default is Ubuntu Precise)",
Value: "Ubuntu Server 12.04 LTS (amd64 20150127)",
Value: defaultCatalogItem,
},
// BoolTFlag is true by default.
@ -107,32 +115,42 @@ func GetCreateFlags() []cli.Flag {
EnvVar: "VCLOUDAIR_CPU_COUNT",
Name: "vmwarevcloudair-cpu-count",
Usage: "vCloud Air VM Cpu Count (default 1)",
Value: 1,
Value: defaultCpus,
},
cli.IntFlag{
EnvVar: "VCLOUDAIR_MEMORY_SIZE",
Name: "vmwarevcloudair-memory-size",
Usage: "vCloud Air VM Memory Size in MB (default 2048)",
Value: 2048,
Value: defaultMemory,
},
cli.IntFlag{
EnvVar: "VCLOUDAIR_SSH_PORT",
Name: "vmwarevcloudair-ssh-port",
Usage: "vCloud Air SSH port",
Value: 22,
Value: defaultSSHPort,
},
cli.IntFlag{
EnvVar: "VCLOUDAIR_DOCKER_PORT",
Name: "vmwarevcloudair-docker-port",
Usage: "vCloud Air Docker port",
Value: 2376,
Value: defaultDockerPort,
},
}
}
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
inner := drivers.NewBaseDriver(machineName, storePath, caCert, privateKey)
return &Driver{BaseDriver: inner}, nil
func NewDriver(hostName, storePath string) drivers.Driver {
return &Driver{
Catalog: defaultCatalog,
CatalogItem: defaultCatalogItem,
CPUCount: defaultCpus,
MemorySize: defaultMemory,
DockerPort: defaultDockerPort,
BaseDriver: &drivers.BaseDriver{
SSHPort: defaultSSHPort,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
@ -645,7 +663,7 @@ func (d *Driver) Kill() error {
// Helpers
func generateVMName() string {
randomID := utils.TruncateID(utils.GenerateRandomID())
randomID := mcnutils.TruncateID(mcnutils.GenerateRandomID())
return fmt.Sprintf("docker-host-%s", randomID)
}

Some files were not shown because too many files have changed in this diff Show More