LEFT | RIGHT |
1 // Copyright 2013 Canonical Ltd. | 1 // Copyright 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package manual | 4 package manual |
5 | 5 |
6 import ( | 6 import ( |
7 "bytes" | 7 "bytes" |
8 "errors" | 8 "errors" |
9 "fmt" | 9 "fmt" |
10 "net" | 10 "net" |
11 "path" | 11 "path" |
12 "strings" | 12 "strings" |
13 "sync" | 13 "sync" |
14 | 14 |
15 "github.com/juju/loggo" | 15 "github.com/juju/loggo" |
16 | 16 |
17 "launchpad.net/juju-core/agent" | 17 "launchpad.net/juju-core/agent" |
18 "launchpad.net/juju-core/constraints" | 18 "launchpad.net/juju-core/constraints" |
19 "launchpad.net/juju-core/environs" | 19 "launchpad.net/juju-core/environs" |
20 "launchpad.net/juju-core/environs/config" | 20 "launchpad.net/juju-core/environs/config" |
21 "launchpad.net/juju-core/environs/httpstorage" | 21 "launchpad.net/juju-core/environs/httpstorage" |
22 "launchpad.net/juju-core/environs/manual" | 22 "launchpad.net/juju-core/environs/manual" |
23 "launchpad.net/juju-core/environs/simplestreams" | 23 "launchpad.net/juju-core/environs/simplestreams" |
24 "launchpad.net/juju-core/environs/sshstorage" | 24 "launchpad.net/juju-core/environs/sshstorage" |
25 "launchpad.net/juju-core/environs/storage" | 25 "launchpad.net/juju-core/environs/storage" |
26 envtools "launchpad.net/juju-core/environs/tools" | 26 envtools "launchpad.net/juju-core/environs/tools" |
27 "launchpad.net/juju-core/instance" | 27 "launchpad.net/juju-core/instance" |
| 28 "launchpad.net/juju-core/juju/arch" |
28 "launchpad.net/juju-core/provider/common" | 29 "launchpad.net/juju-core/provider/common" |
29 "launchpad.net/juju-core/state" | 30 "launchpad.net/juju-core/state" |
30 "launchpad.net/juju-core/state/api" | 31 "launchpad.net/juju-core/state/api" |
| 32 "launchpad.net/juju-core/utils" |
31 "launchpad.net/juju-core/utils/ssh" | 33 "launchpad.net/juju-core/utils/ssh" |
32 "launchpad.net/juju-core/worker/localstorage" | 34 "launchpad.net/juju-core/worker/localstorage" |
33 "launchpad.net/juju-core/worker/terminationworker" | 35 "launchpad.net/juju-core/worker/terminationworker" |
34 ) | 36 ) |
35 | 37 |
36 const ( | 38 const ( |
37 // TODO(axw) make this configurable? | |
38 dataDir = agent.DefaultDataDir | |
39 | |
40 // storageSubdir is the subdirectory of | 39 // storageSubdir is the subdirectory of |
41 // dataDir in which storage will be located. | 40 // dataDir in which storage will be located. |
42 storageSubdir = "storage" | 41 storageSubdir = "storage" |
43 | 42 |
44 // storageTmpSubdir is the subdirectory of | 43 // storageTmpSubdir is the subdirectory of |
45 // dataDir in which temporary storage will | 44 // dataDir in which temporary storage will |
46 // be located. | 45 // be located. |
47 storageTmpSubdir = "storage-tmp" | 46 storageTmpSubdir = "storage-tmp" |
48 ) | 47 ) |
49 | 48 |
50 var logger = loggo.GetLogger("juju.provider.manual") | 49 var logger = loggo.GetLogger("juju.provider.manual") |
51 | 50 |
52 type manualEnviron struct { | 51 type manualEnviron struct { |
53 » common.DoesSupportUnitPlacement | 52 » common.SupportsUnitPlacementPolicy |
54 | 53 |
55 cfg *environConfig | 54 cfg *environConfig |
56 cfgmutex sync.Mutex | 55 cfgmutex sync.Mutex |
57 storage storage.Storage | 56 storage storage.Storage |
58 ubuntuUserInited bool | 57 ubuntuUserInited bool |
59 ubuntuUserInitMutex sync.Mutex | 58 ubuntuUserInitMutex sync.Mutex |
60 } | 59 } |
61 | 60 |
62 var _ envtools.SupportsCustomSources = (*manualEnviron)(nil) | 61 var _ envtools.SupportsCustomSources = (*manualEnviron)(nil) |
63 | 62 |
(...skipping 22 matching lines...) Expand all Loading... |
86 func (e *manualEnviron) Config() *config.Config { | 85 func (e *manualEnviron) Config() *config.Config { |
87 return e.envConfig().Config | 86 return e.envConfig().Config |
88 } | 87 } |
89 | 88 |
90 func (e *manualEnviron) Name() string { | 89 func (e *manualEnviron) Name() string { |
91 return e.envConfig().Name() | 90 return e.envConfig().Name() |
92 } | 91 } |
93 | 92 |
94 // SupportedArchitectures is specified on the EnvironCapability interface. | 93 // SupportedArchitectures is specified on the EnvironCapability interface. |
95 func (e *manualEnviron) SupportedArchitectures() ([]string, error) { | 94 func (e *manualEnviron) SupportedArchitectures() ([]string, error) { |
96 » envConfig := e.envConfig() | 95 » return arch.AllSupportedArches, nil |
97 » host := envConfig.bootstrapHost() | 96 } |
98 » hc, _, err := manual.DetectSeriesAndHardwareCharacteristics(host) | 97 |
99 » if err != nil { | 98 // SupportNetworks is specified on the EnvironCapability interface. |
100 » » return nil, err | 99 func (e *manualEnviron) SupportNetworks() bool { |
101 » } | 100 » return false |
102 » return []string{*hc.Arch}, nil | |
103 } | 101 } |
104 | 102 |
105 func (e *manualEnviron) Bootstrap(ctx environs.BootstrapContext, cons constraint
s.Value) error { | 103 func (e *manualEnviron) Bootstrap(ctx environs.BootstrapContext, cons constraint
s.Value) error { |
106 // Set "use-sshstorage" to false, so agents know not to use sshstorage. | 104 // Set "use-sshstorage" to false, so agents know not to use sshstorage. |
107 cfg, err := e.Config().Apply(map[string]interface{}{"use-sshstorage": fa
lse}) | 105 cfg, err := e.Config().Apply(map[string]interface{}{"use-sshstorage": fa
lse}) |
108 if err != nil { | 106 if err != nil { |
109 return err | 107 return err |
110 } | 108 } |
111 if err := e.SetConfig(cfg); err != nil { | 109 if err := e.SetConfig(cfg); err != nil { |
112 return err | 110 return err |
113 } | 111 } |
114 envConfig := e.envConfig() | 112 envConfig := e.envConfig() |
115 host := envConfig.bootstrapHost() | 113 host := envConfig.bootstrapHost() |
116 hc, series, err := manual.DetectSeriesAndHardwareCharacteristics(host) | 114 hc, series, err := manual.DetectSeriesAndHardwareCharacteristics(host) |
117 if err != nil { | 115 if err != nil { |
118 return err | 116 return err |
119 } | 117 } |
120 » selectedTools, err := common.EnsureBootstrapTools(e, series, hc.Arch) | 118 » selectedTools, err := common.EnsureBootstrapTools(ctx, e, series, hc.Arc
h) |
121 if err != nil { | 119 if err != nil { |
122 return err | 120 return err |
123 } | 121 } |
124 return manual.Bootstrap(manual.BootstrapArgs{ | 122 return manual.Bootstrap(manual.BootstrapArgs{ |
125 Context: ctx, | 123 Context: ctx, |
126 Host: host, | 124 Host: host, |
127 » » DataDir: dataDir, | 125 » » DataDir: agent.DefaultDataDir, |
128 Environ: e, | 126 Environ: e, |
129 PossibleTools: selectedTools, | 127 PossibleTools: selectedTools, |
130 Series: series, | 128 Series: series, |
131 HardwareCharacteristics: &hc, | 129 HardwareCharacteristics: &hc, |
132 }) | 130 }) |
133 } | 131 } |
134 | 132 |
135 func (e *manualEnviron) StateInfo() (*state.Info, *api.Info, error) { | 133 func (e *manualEnviron) StateInfo() (*state.Info, *api.Info, error) { |
136 return common.StateInfo(e) | 134 return common.StateInfo(e) |
137 } | 135 } |
138 | 136 |
139 func (e *manualEnviron) SetConfig(cfg *config.Config) error { | 137 func (e *manualEnviron) SetConfig(cfg *config.Config) error { |
140 e.cfgmutex.Lock() | 138 e.cfgmutex.Lock() |
141 defer e.cfgmutex.Unlock() | 139 defer e.cfgmutex.Unlock() |
142 envConfig, err := manualProvider{}.validate(cfg, e.cfg.Config) | 140 envConfig, err := manualProvider{}.validate(cfg, e.cfg.Config) |
143 if err != nil { | 141 if err != nil { |
144 return err | 142 return err |
145 } | 143 } |
146 // Set storage. If "use-sshstorage" is true then use the SSH storage. | 144 // Set storage. If "use-sshstorage" is true then use the SSH storage. |
147 // Otherwise, use HTTP storage. | 145 // Otherwise, use HTTP storage. |
148 // | 146 // |
149 // We don't change storage once it's been set. Storage parameters | 147 // We don't change storage once it's been set. Storage parameters |
150 // are fixed at bootstrap time, and it is not possible to change | 148 // are fixed at bootstrap time, and it is not possible to change |
151 // them. | 149 // them. |
152 if e.storage == nil { | 150 if e.storage == nil { |
153 var stor storage.Storage | 151 var stor storage.Storage |
154 if envConfig.useSSHStorage() { | 152 if envConfig.useSSHStorage() { |
155 storageDir := e.StorageDir() | 153 storageDir := e.StorageDir() |
156 » » » storageTmpdir := path.Join(dataDir, storageTmpSubdir) | 154 » » » storageTmpdir := path.Join(agent.DefaultDataDir, storage
TmpSubdir) |
157 stor, err = newSSHStorage("ubuntu@"+e.cfg.bootstrapHost(
), storageDir, storageTmpdir) | 155 stor, err = newSSHStorage("ubuntu@"+e.cfg.bootstrapHost(
), storageDir, storageTmpdir) |
158 if err != nil { | 156 if err != nil { |
159 return fmt.Errorf("initialising SSH storage fail
ed: %v", err) | 157 return fmt.Errorf("initialising SSH storage fail
ed: %v", err) |
160 } | 158 } |
161 } else { | 159 } else { |
162 caCertPEM, ok := envConfig.CACert() | 160 caCertPEM, ok := envConfig.CACert() |
163 if !ok { | 161 if !ok { |
164 // should not be possible to validate base confi
g | 162 // should not be possible to validate base confi
g |
165 return fmt.Errorf("ca-cert not set") | 163 return fmt.Errorf("ca-cert not set") |
166 } | 164 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 storage.NewStorageSimpleStreamsDataSource("cloud storage", e.Sto
rage(), storage.BaseToolsPath), | 214 storage.NewStorageSimpleStreamsDataSource("cloud storage", e.Sto
rage(), storage.BaseToolsPath), |
217 }, nil | 215 }, nil |
218 } | 216 } |
219 | 217 |
220 func (e *manualEnviron) Storage() storage.Storage { | 218 func (e *manualEnviron) Storage() storage.Storage { |
221 e.cfgmutex.Lock() | 219 e.cfgmutex.Lock() |
222 defer e.cfgmutex.Unlock() | 220 defer e.cfgmutex.Unlock() |
223 return e.storage | 221 return e.storage |
224 } | 222 } |
225 | 223 |
226 var runSSHCommand = func(host string, command []string) (stderr string, err erro
r) { | 224 var runSSHCommand = func(host string, command []string, stdin string) (stderr st
ring, err error) { |
227 cmd := ssh.Command(host, command, nil) | 225 cmd := ssh.Command(host, command, nil) |
228 var stderrBuf bytes.Buffer | 226 var stderrBuf bytes.Buffer |
| 227 cmd.Stdin = strings.NewReader(stdin) |
229 cmd.Stderr = &stderrBuf | 228 cmd.Stderr = &stderrBuf |
230 err = cmd.Run() | 229 err = cmd.Run() |
231 return stderrBuf.String(), err | 230 return stderrBuf.String(), err |
232 } | 231 } |
233 | 232 |
234 func (e *manualEnviron) Destroy() error { | 233 func (e *manualEnviron) Destroy() error { |
| 234 script := ` |
| 235 set -x |
| 236 pkill -%d jujud && exit |
| 237 stop juju-db |
| 238 rm -f /etc/init/juju* |
| 239 rm -f /etc/rsyslog.d/*juju* |
| 240 rm -fr %s %s |
| 241 exit 0 |
| 242 ` |
| 243 script = fmt.Sprintf( |
| 244 script, |
| 245 terminationworker.TerminationSignal, |
| 246 utils.ShQuote(agent.DefaultDataDir), |
| 247 utils.ShQuote(agent.DefaultLogDir), |
| 248 ) |
235 stderr, err := runSSHCommand( | 249 stderr, err := runSSHCommand( |
236 "ubuntu@"+e.envConfig().bootstrapHost(), | 250 "ubuntu@"+e.envConfig().bootstrapHost(), |
237 » » []string{"sudo", "pkill", fmt.Sprintf("-%d", terminationworker.T
erminationSignal), "jujud"}, | 251 » » []string{"sudo", "/bin/bash"}, script, |
238 ) | 252 ) |
239 if err != nil { | 253 if err != nil { |
240 if stderr := strings.TrimSpace(stderr); len(stderr) > 0 { | 254 if stderr := strings.TrimSpace(stderr); len(stderr) > 0 { |
241 err = fmt.Errorf("%v (%v)", err, stderr) | 255 err = fmt.Errorf("%v (%v)", err, stderr) |
242 } | 256 } |
243 } | 257 } |
244 return err | 258 return err |
245 } | 259 } |
246 | 260 |
247 func (*manualEnviron) PrecheckInstance(series string, cons constraints.Value) er
ror { | 261 func (*manualEnviron) PrecheckInstance(series string, cons constraints.Value) er
ror { |
(...skipping 14 matching lines...) Expand all Loading... |
262 | 276 |
263 func (*manualEnviron) Provider() environs.EnvironProvider { | 277 func (*manualEnviron) Provider() environs.EnvironProvider { |
264 return manualProvider{} | 278 return manualProvider{} |
265 } | 279 } |
266 | 280 |
267 func (e *manualEnviron) StorageAddr() string { | 281 func (e *manualEnviron) StorageAddr() string { |
268 return e.envConfig().storageListenAddr() | 282 return e.envConfig().storageListenAddr() |
269 } | 283 } |
270 | 284 |
271 func (e *manualEnviron) StorageDir() string { | 285 func (e *manualEnviron) StorageDir() string { |
272 » return path.Join(dataDir, storageSubdir) | 286 » return path.Join(agent.DefaultDataDir, storageSubdir) |
273 } | 287 } |
274 | 288 |
275 func (e *manualEnviron) SharedStorageAddr() string { | 289 func (e *manualEnviron) SharedStorageAddr() string { |
276 return "" | 290 return "" |
277 } | 291 } |
278 | 292 |
279 func (e *manualEnviron) SharedStorageDir() string { | 293 func (e *manualEnviron) SharedStorageDir() string { |
280 return "" | 294 return "" |
281 } | 295 } |
282 | 296 |
(...skipping 20 matching lines...) Expand all Loading... |
303 } | 317 } |
304 } | 318 } |
305 return hostnames | 319 return hostnames |
306 } | 320 } |
307 | 321 |
308 func (e *manualEnviron) StorageAuthKey() string { | 322 func (e *manualEnviron) StorageAuthKey() string { |
309 return e.envConfig().storageAuthKey() | 323 return e.envConfig().storageAuthKey() |
310 } | 324 } |
311 | 325 |
312 var _ localstorage.LocalTLSStorageConfig = (*manualEnviron)(nil) | 326 var _ localstorage.LocalTLSStorageConfig = (*manualEnviron)(nil) |
LEFT | RIGHT |