Skip to content

Commit fb2e843

Browse files
- Re-introduce config migration; fix panics occurring from older configs
- Introduce boilerplate for config.json migrations Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
1 parent 79b9450 commit fb2e843

File tree

11 files changed

+264
-171
lines changed

11 files changed

+264
-171
lines changed

drivers/openstack/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ func (c *GenericClient) Authenticate(d *Driver) error {
437437
return err
438438
}
439439

440-
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.VERSION))
440+
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.Version))
441441

442442
if d.Insecure {
443443
// Configure custom TLS settings.

drivers/rackspace/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (c *Client) Authenticate(d *openstack.Driver) error {
4242
return err
4343
}
4444

45-
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.VERSION))
45+
provider.UserAgent.Prepend(fmt.Sprintf("docker-machine/v%s", version.Version))
4646

4747
err = rackspace.Authenticate(provider, opts)
4848
if err != nil {

libmachine/filestore.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ type Filestore struct {
1919
}
2020

2121
func NewFilestore(rootPath string, caCert string, privateKey string) *Filestore {
22-
return &Filestore{path: rootPath, caCertPath: caCert, privateKeyPath: privateKey}
22+
return &Filestore{
23+
path: rootPath,
24+
caCertPath: caCert,
25+
privateKeyPath: privateKey,
26+
}
2327
}
2428

2529
func (s Filestore) loadHost(name string) (*Host, error) {
@@ -30,13 +34,15 @@ func (s Filestore) loadHost(name string) (*Host, error) {
3034
}
3135
}
3236

33-
host := &Host{Name: name, StorePath: hostPath}
37+
host := &Host{
38+
Name: name,
39+
StorePath: hostPath,
40+
}
3441
if err := host.LoadConfig(); err != nil {
3542
return nil, err
3643
}
3744

38-
h := FillNestedHost(host)
39-
return h, nil
45+
return host, nil
4046
}
4147

4248
func (s Filestore) GetPath() string {
@@ -85,7 +91,7 @@ func (s Filestore) List() ([]*Host, error) {
8591

8692
for _, file := range dir {
8793
// don't load hidden dirs; used for configs
88-
if file.IsDir() && strings.Index(file.Name(), ".") != 0 {
94+
if file.IsDir() && !strings.HasPrefix(file.Name(), ".") {
8995
host, err := s.Get(file.Name())
9096
if err != nil {
9197
log.Errorf("error loading host %q: %s", file.Name(), err)

libmachine/host.go

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/docker/machine/ssh"
2020
"github.com/docker/machine/state"
2121
"github.com/docker/machine/utils"
22+
"github.com/docker/machine/version"
2223
)
2324

2425
var (
@@ -28,22 +29,12 @@ var (
2829
)
2930

3031
type Host struct {
31-
Name string `json:"-"`
32-
DriverName string
33-
Driver drivers.Driver
34-
StorePath string
35-
HostOptions *HostOptions
36-
37-
// deprecated options; these are left to assist in config migrations
38-
SwarmHost string
39-
SwarmMaster bool
40-
SwarmDiscovery string
41-
CaCertPath string
42-
PrivateKeyPath string
43-
ServerCertPath string
44-
ServerKeyPath string
45-
ClientCertPath string
46-
ClientKeyPath string
32+
ConfigVersion int
33+
Driver drivers.Driver
34+
DriverName string
35+
HostOptions *HostOptions
36+
Name string `json:"-"`
37+
StorePath string
4738
}
4839

4940
type HostOptions struct {
@@ -56,14 +47,9 @@ type HostOptions struct {
5647
}
5748

5849
type HostMetadata struct {
59-
DriverName string
60-
HostOptions HostOptions
61-
StorePath string
62-
CaCertPath string
63-
PrivateKeyPath string
64-
ServerCertPath string
65-
ServerKeyPath string
66-
ClientCertPath string
50+
ConfigVersion int
51+
DriverName string
52+
HostOptions HostOptions
6753
}
6854

6955
type HostListItem struct {
@@ -75,6 +61,14 @@ type HostListItem struct {
7561
SwarmOptions swarm.SwarmOptions
7662
}
7763

64+
type ErrSavingConfig struct {
65+
wrappedErr error
66+
}
67+
68+
func (e ErrSavingConfig) Error() string {
69+
return fmt.Sprintf("Error saving config: %s", e.wrappedErr)
70+
}
71+
7872
func NewHost(name, driverName string, hostOptions *HostOptions) (*Host, error) {
7973
authOptions := hostOptions.AuthOptions
8074
storePath := filepath.Join(utils.GetMachineDir(), name)
@@ -83,11 +77,12 @@ func NewHost(name, driverName string, hostOptions *HostOptions) (*Host, error) {
8377
return nil, err
8478
}
8579
return &Host{
86-
Name: name,
87-
DriverName: driverName,
88-
Driver: driver,
89-
StorePath: storePath,
90-
HostOptions: hostOptions,
80+
Name: name,
81+
ConfigVersion: version.ConfigVersion,
82+
DriverName: driverName,
83+
Driver: driver,
84+
StorePath: storePath,
85+
HostOptions: hostOptions,
9186
}, nil
9287
}
9388

@@ -100,6 +95,7 @@ func LoadHost(name string, StorePath string) (*Host, error) {
10095
if err := host.LoadConfig(); err != nil {
10196
return nil, err
10297
}
98+
10399
return host, nil
104100
}
105101

@@ -287,26 +283,28 @@ func (h *Host) LoadConfig() error {
287283
return err
288284
}
289285

290-
// First pass: find the driver name and load the driver
291-
var hostMetadata HostMetadata
292-
if err := json.Unmarshal(data, &hostMetadata); err != nil {
293-
return err
294-
}
295-
296-
meta := FillNestedHostMetadata(&hostMetadata)
286+
// Remember the machine name and store path so we don't have to pass it
287+
// through each struct in the migration.
288+
name := h.Name
289+
storePath := h.StorePath
297290

298-
authOptions := meta.HostOptions.AuthOptions
291+
// If we end up performing a migration, we should save afterwards so we don't have to do it again on subsequent invocations.
292+
migrationPerformed := h.ConfigVersion != version.ConfigVersion
299293

300-
driver, err := drivers.NewDriver(hostMetadata.DriverName, h.Name, h.StorePath, authOptions.CaCertPath, authOptions.PrivateKeyPath)
294+
migratedHost, err := MigrateHost(h, data)
301295
if err != nil {
302-
return err
296+
return fmt.Errorf("Error getting migrated host: %s", err)
303297
}
304298

305-
h.Driver = driver
299+
*h = *migratedHost
306300

307-
// Second pass: unmarshal driver config into correct driver
308-
if err := json.Unmarshal(data, &h); err != nil {
309-
return err
301+
h.Name = name
302+
h.StorePath = storePath
303+
304+
if migrationPerformed {
305+
if err := h.SaveConfig(); err != nil {
306+
return fmt.Errorf("Error saving config after migration was performed: %s", err)
307+
}
310308
}
311309

312310
return nil

libmachine/host_v0.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package libmachine
2+
3+
import "github.com/docker/machine/drivers"
4+
5+
type HostV0 struct {
6+
Name string `json:"-"`
7+
Driver drivers.Driver
8+
DriverName string
9+
ConfigVersion int
10+
HostOptions *HostOptions
11+
12+
StorePath string
13+
CaCertPath string
14+
PrivateKeyPath string
15+
ServerCertPath string
16+
ServerKeyPath string
17+
ClientCertPath string
18+
SwarmHost string
19+
SwarmMaster bool
20+
SwarmDiscovery string
21+
ClientKeyPath string
22+
}
23+
24+
type HostMetadataV0 struct {
25+
HostOptions HostOptions
26+
DriverName string
27+
28+
StorePath string
29+
CaCertPath string
30+
PrivateKeyPath string
31+
ServerCertPath string
32+
ServerKeyPath string
33+
ClientCertPath string
34+
}

libmachine/migrate.go

Lines changed: 44 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,65 @@
11
package libmachine
22

33
import (
4-
"path/filepath"
4+
"encoding/json"
5+
"fmt"
56

6-
"github.com/docker/machine/libmachine/auth"
7-
"github.com/docker/machine/libmachine/engine"
8-
"github.com/docker/machine/libmachine/swarm"
9-
"github.com/docker/machine/utils"
7+
"github.com/docker/machine/drivers"
8+
"github.com/docker/machine/version"
109
)
1110

12-
// In the 0.0.1 => 0.0.2 transition, the JSON representation of
13-
// machines changed from a "flat" to a more "nested" structure
14-
// for various options and configuration settings. To preserve
15-
// compatibility with existing machines, these migration functions
16-
// have been introduced. They preserve backwards compat at the expense
17-
// of some duplicated information.
11+
func getMigratedHostMetadata(data []byte) (*HostMetadata, error) {
12+
// HostMetadata is for a "first pass" so we can then load the driver
13+
var (
14+
hostMetadata *HostMetadataV0
15+
)
1816

19-
// validates host config and modifies if needed
20-
// this is used for configuration updates
21-
func FillNestedHost(host *Host) *Host {
22-
certInfo := getCertInfoFromHost(host)
23-
24-
if host.HostOptions == nil {
25-
host.HostOptions = &HostOptions{}
26-
}
27-
if host.HostOptions.EngineOptions == nil {
28-
host.HostOptions.EngineOptions = &engine.EngineOptions{}
29-
}
30-
31-
if host.HostOptions.SwarmOptions == nil {
32-
host.HostOptions.SwarmOptions = &swarm.SwarmOptions{
33-
Address: "",
34-
Discovery: host.SwarmDiscovery,
35-
Host: host.SwarmHost,
36-
Master: host.SwarmMaster,
37-
}
38-
}
39-
40-
host.HostOptions.AuthOptions = &auth.AuthOptions{
41-
StorePath: host.StorePath,
42-
CaCertPath: certInfo.CaCertPath,
43-
CaCertRemotePath: "",
44-
ServerCertPath: certInfo.ServerCertPath,
45-
ServerKeyPath: certInfo.ServerKeyPath,
46-
ClientKeyPath: certInfo.ClientKeyPath,
47-
ServerCertRemotePath: "",
48-
ServerKeyRemotePath: "",
49-
PrivateKeyPath: certInfo.CaKeyPath,
50-
ClientCertPath: certInfo.ClientCertPath,
51-
}
52-
53-
return host
54-
}
55-
56-
// fills nested host metadata and modifies if needed
57-
// this is used for configuration updates
58-
func FillNestedHostMetadata(m *HostMetadata) *HostMetadata {
59-
if m.HostOptions.EngineOptions == nil {
60-
m.HostOptions.EngineOptions = &engine.EngineOptions{}
17+
if err := json.Unmarshal(data, &hostMetadata); err != nil {
18+
return &HostMetadata{}, err
6119
}
6220

63-
if m.HostOptions.AuthOptions == nil {
64-
m.HostOptions.AuthOptions = &auth.AuthOptions{
65-
StorePath: m.StorePath,
66-
CaCertPath: m.CaCertPath,
67-
CaCertRemotePath: "",
68-
ServerCertPath: m.ServerCertPath,
69-
ServerKeyPath: m.ServerKeyPath,
70-
ClientKeyPath: "",
71-
ServerCertRemotePath: "",
72-
ServerKeyRemotePath: "",
73-
PrivateKeyPath: m.PrivateKeyPath,
74-
ClientCertPath: m.ClientCertPath,
75-
}
76-
}
21+
migratedHostMetadata := MigrateHostMetadataV0ToHostMetadataV1(hostMetadata)
7722

78-
return m
23+
return migratedHostMetadata, nil
7924
}
8025

81-
func getCertInfoFromHost(h *Host) CertPathInfo {
82-
// setup cert paths
83-
caCertPath := h.CaCertPath
84-
caKeyPath := h.PrivateKeyPath
85-
clientCertPath := h.ClientCertPath
86-
clientKeyPath := h.ClientKeyPath
87-
serverCertPath := h.ServerCertPath
88-
serverKeyPath := h.ServerKeyPath
89-
90-
if caCertPath == "" {
91-
caCertPath = filepath.Join(utils.GetMachineCertDir(), "ca.pem")
92-
}
93-
94-
if caKeyPath == "" {
95-
caKeyPath = filepath.Join(utils.GetMachineCertDir(), "ca-key.pem")
96-
}
97-
98-
if clientCertPath == "" {
99-
clientCertPath = filepath.Join(utils.GetMachineCertDir(), "cert.pem")
26+
func MigrateHost(h *Host, data []byte) (*Host, error) {
27+
migratedHostMetadata, err := getMigratedHostMetadata(data)
28+
if err != nil {
29+
return &Host{}, err
10030
}
10131

102-
if clientKeyPath == "" {
103-
clientKeyPath = filepath.Join(utils.GetMachineCertDir(), "key.pem")
32+
authOptions := migratedHostMetadata.HostOptions.AuthOptions
33+
34+
driver, err := drivers.NewDriver(
35+
migratedHostMetadata.DriverName,
36+
h.Name,
37+
h.StorePath,
38+
authOptions.CaCertPath,
39+
authOptions.PrivateKeyPath,
40+
)
41+
if err != nil {
42+
return &Host{}, err
10443
}
10544

106-
if serverCertPath == "" {
107-
serverCertPath = filepath.Join(utils.GetMachineCertDir(), "server.pem")
45+
for h.ConfigVersion = migratedHostMetadata.ConfigVersion; h.ConfigVersion < version.ConfigVersion; h.ConfigVersion++ {
46+
switch h.ConfigVersion {
47+
case 0:
48+
hostV0 := &HostV0{
49+
Driver: driver,
50+
}
51+
if err := json.Unmarshal(data, &hostV0); err != nil {
52+
return &Host{}, fmt.Errorf("Error unmarshalling host config version 0: %s", err)
53+
}
54+
h = MigrateHostV0ToHostV1(hostV0)
55+
default:
56+
}
10857
}
10958

110-
if serverKeyPath == "" {
111-
serverKeyPath = filepath.Join(utils.GetMachineCertDir(), "server-key.pem")
59+
h.Driver = driver
60+
if err := json.Unmarshal(data, &h); err != nil {
61+
return &Host{}, fmt.Errorf("Error unmarshalling most recent host version: %s", err)
11262
}
11363

114-
return CertPathInfo{
115-
CaCertPath: caCertPath,
116-
CaKeyPath: caKeyPath,
117-
ClientCertPath: clientCertPath,
118-
ClientKeyPath: clientKeyPath,
119-
ServerCertPath: serverCertPath,
120-
ServerKeyPath: serverKeyPath,
121-
}
64+
return h, nil
12265
}

0 commit comments

Comments
 (0)