~dave-cheney/juju-core/167-simplestreams-add-trusty

« back to all changes in this revision

Viewing changes to provider/manual/environ.go

[r=axwalk] provider/manual: set storage in SetConfig

We currently rely on EnableBootstrapStorage to
specify the storage mechanism to use for bootstrap
and sync-tools. This is insufficient in practice,
causing panics such as those in lp:1262764.

Instead, we inject a boolean attribute into the
environment config that is stored in state; this
attribute is false in the .jenv file, and true
in state. We use its value to decide whether to
use sshstorage (external) or httpstorage (internal).

A followup will eliminate BootstrapStorager.

Fixes lp:1262764

https://codereview.appspot.com/61480043/

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
var logger = loggo.GetLogger("juju.provider.manual")
52
52
 
53
53
type manualEnviron struct {
54
 
        cfg                   *environConfig
55
 
        cfgmutex              sync.Mutex
56
 
        bootstrapStorage      storage.Storage
57
 
        bootstrapStorageMutex sync.Mutex
58
 
        ubuntuUserInited      bool
59
 
        ubuntuUserInitMutex   sync.Mutex
 
54
        cfg                 *environConfig
 
55
        cfgmutex            sync.Mutex
 
56
        storage             storage.Storage
 
57
        ubuntuUserInited    bool
 
58
        ubuntuUserInitMutex sync.Mutex
60
59
}
61
60
 
62
61
var _ environs.BootstrapStorager = (*manualEnviron)(nil)
115
114
        if err := e.ensureBootstrapUbuntuUser(ctx); err != nil {
116
115
                return err
117
116
        }
 
117
        // Set "use-sshstorage" to false, so agents know not to use sshstorage.
 
118
        cfg, err := e.Config().Apply(map[string]interface{}{"use-sshstorage": false})
 
119
        if err != nil {
 
120
                return err
 
121
        }
 
122
        if err := e.SetConfig(cfg); err != nil {
 
123
                return err
 
124
        }
118
125
        envConfig := e.envConfig()
119
126
        host := envConfig.bootstrapHost()
120
127
        hc, series, err := manual.DetectSeriesAndHardwareCharacteristics(host)
147
154
        if err != nil {
148
155
                return err
149
156
        }
 
157
        // Set storage. If "use-sshstorage" is true then use the SSH storage.
 
158
        // Otherwise, use HTTP storage.
 
159
        //
 
160
        // We don't change storage once it's been set. Storage parameters
 
161
        // are fixed at bootstrap time, and it is not possible to change
 
162
        // them.
 
163
        if e.storage == nil {
 
164
                var stor storage.Storage
 
165
                if envConfig.useSSHStorage() {
 
166
                        storageDir := e.StorageDir()
 
167
                        storageTmpdir := path.Join(dataDir, storageTmpSubdir)
 
168
                        stor, err = newSSHStorage("ubuntu@"+e.cfg.bootstrapHost(), storageDir, storageTmpdir)
 
169
                        if err != nil {
 
170
                                return fmt.Errorf("initialising SSH storage failed: %v", err)
 
171
                        }
 
172
                } else {
 
173
                        caCertPEM, ok := envConfig.CACert()
 
174
                        if !ok {
 
175
                                // should not be possible to validate base config
 
176
                                return fmt.Errorf("ca-cert not set")
 
177
                        }
 
178
                        authkey := envConfig.storageAuthKey()
 
179
                        stor, err = httpstorage.ClientTLS(envConfig.storageAddr(), caCertPEM, authkey)
 
180
                        if err != nil {
 
181
                                return fmt.Errorf("initialising HTTPS storage failed: %v", err)
 
182
                        }
 
183
                }
 
184
                e.storage = stor
 
185
        }
150
186
        e.cfg = envConfig
151
187
        return nil
152
188
}
184
220
 
185
221
// Implements environs.BootstrapStorager.
186
222
func (e *manualEnviron) EnableBootstrapStorage(ctx environs.BootstrapContext) error {
187
 
        e.bootstrapStorageMutex.Lock()
188
 
        defer e.bootstrapStorageMutex.Unlock()
189
 
        if e.bootstrapStorage != nil {
190
 
                return nil
191
 
        }
192
 
        if err := e.ensureBootstrapUbuntuUser(ctx); err != nil {
193
 
                return err
194
 
        }
195
 
        cfg := e.envConfig()
196
 
        storageDir := e.StorageDir()
197
 
        storageTmpdir := path.Join(dataDir, storageTmpSubdir)
198
 
        bootstrapStorage, err := newSSHStorage("ubuntu@"+cfg.bootstrapHost(), storageDir, storageTmpdir)
199
 
        if err != nil {
200
 
                return err
201
 
        }
202
 
        e.bootstrapStorage = bootstrapStorage
203
 
        return nil
 
223
        return e.ensureBootstrapUbuntuUser(ctx)
204
224
}
205
225
 
206
226
// GetToolsSources returns a list of sources which are
213
233
}
214
234
 
215
235
func (e *manualEnviron) Storage() storage.Storage {
216
 
        e.bootstrapStorageMutex.Lock()
217
 
        defer e.bootstrapStorageMutex.Unlock()
218
 
        if e.bootstrapStorage != nil {
219
 
                return e.bootstrapStorage
220
 
        }
221
 
        caCertPEM, authkey := e.StorageCACert(), e.StorageAuthKey()
222
 
        if caCertPEM != nil && authkey != "" {
223
 
                storage, err := httpstorage.ClientTLS(e.envConfig().storageAddr(), caCertPEM, authkey)
224
 
                if err != nil {
225
 
                        // Should be impossible, since ca-cert will always be validated.
226
 
                        logger.Errorf("initialising HTTPS storage failed: %v", err)
227
 
                } else {
228
 
                        return storage
229
 
                }
230
 
        } else {
231
 
                logger.Errorf("missing CA cert or auth-key")
232
 
        }
233
 
        return nil
 
236
        e.cfgmutex.Lock()
 
237
        defer e.cfgmutex.Unlock()
 
238
        return e.storage
234
239
}
235
240
 
236
241
var runSSHCommand = func(host string, command []string) (stderr string, err error) {