Merge lp:~axwalk/juju-core/lp1306902-ha-upgrade-take2 into lp:~go-bot/juju-core/trunk
- lp1306902-ha-upgrade-take2
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andrew Wilkins |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2654 |
Proposed branch: | lp:~axwalk/juju-core/lp1306902-ha-upgrade-take2 |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
506 lines (+181/-94) 9 files modified
agent/format-1.18.go (+7/-4) agent/mongo/mongo.go (+3/-6) cmd/jujud/bootstrap.go (+4/-4) cmd/jujud/machine.go (+126/-58) cmd/jujud/machine_test.go (+18/-8) worker/peergrouper/desired_test.go (+0/-6) worker/peergrouper/initiate.go (+8/-8) worker/peergrouper/initiate_test.go (+1/-0) worker/peergrouper/suite_test.go (+14/-0) |
To merge this branch: | bzr merge lp:~axwalk/juju-core/lp1306902-ha-upgrade-take2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+216245@code.launchpad.net |
Commit message
HA: upgrade upstart and initiate replset
The machine agent will now upgrade the
Mongo upstart script and initiate the
replicaset when upgrading from a version
prior to 1.19.0.
Tested upgrading 1.18.1 to 1.19.1 with and
without HA enabled; tested straight bootstrap
to 1.19.1 with and without HA enabled.
(Supersedes https:/
Description of the change
HA: upgrade upstart and initiate replset
The machine agent will now upgrade the
Mongo upstart script and initiate the
replicaset when upgrading from a version
prior to 1.19.0.
Tested upgrading 1.18.1 to 1.19.1 with and
without HA enabled; tested straight bootstrap
to 1.19.1 with and without HA enabled.
(Supersedes https:/
Andrew Wilkins (axwalk) wrote : | # |
Roger Peppe (rogpeppe) wrote : | # |
LGTM with two minor suggestions.
https:/
File cmd/jujud/
https:/
cmd/jujud/
ensureMongoServ
can we put this after StateWorker, so functions read generally from
higher level to lower level?
https:/
cmd/jujud/
perhaps refresh agentConfig here?
(I actually think that ChangeConfig should probably always return the
new version of the agent configuration)
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
https:/
File cmd/jujud/
https:/
cmd/jujud/
ensureMongoServ
On 2014/04/17 18:20:23, rog wrote:
> can we put this after StateWorker, so functions read generally from
higher level
> to lower level?
Done.
https:/
cmd/jujud/
On 2014/04/17 18:20:23, rog wrote:
> perhaps refresh agentConfig here?
> (I actually think that ChangeConfig should probably always return the
new
> version of the agent configuration)
Done.
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Preview Diff
1 | === modified file 'agent/format-1.18.go' | |||
2 | --- agent/format-1.18.go 2014-04-11 17:51:58 +0000 | |||
3 | +++ agent/format-1.18.go 2014-04-18 04:41:05 +0000 | |||
4 | @@ -46,6 +46,7 @@ | |||
5 | 46 | StateServerKey string `yaml:",omitempty"` | 46 | StateServerKey string `yaml:",omitempty"` |
6 | 47 | APIPort int `yaml:",omitempty"` | 47 | APIPort int `yaml:",omitempty"` |
7 | 48 | StatePort int `yaml:",omitempty"` | 48 | StatePort int `yaml:",omitempty"` |
8 | 49 | SharedSecret string `yaml:",omitempty"` | ||
9 | 49 | } | 50 | } |
10 | 50 | 51 | ||
11 | 51 | func init() { | 52 | func init() { |
12 | @@ -99,10 +100,11 @@ | |||
13 | 99 | } | 100 | } |
14 | 100 | if len(format.StateServerKey) != 0 { | 101 | if len(format.StateServerKey) != 0 { |
15 | 101 | config.servingInfo = ¶ms.StateServingInfo{ | 102 | config.servingInfo = ¶ms.StateServingInfo{ |
20 | 102 | Cert: format.StateServerCert, | 103 | Cert: format.StateServerCert, |
21 | 103 | PrivateKey: format.StateServerKey, | 104 | PrivateKey: format.StateServerKey, |
22 | 104 | APIPort: format.APIPort, | 105 | APIPort: format.APIPort, |
23 | 105 | StatePort: format.StatePort, | 106 | StatePort: format.StatePort, |
24 | 107 | SharedSecret: format.SharedSecret, | ||
25 | 106 | } | 108 | } |
26 | 107 | // There's a private key, then we need the state port, | 109 | // There's a private key, then we need the state port, |
27 | 108 | // which wasn't always in the 1.18 format. If it's not present | 110 | // which wasn't always in the 1.18 format. If it's not present |
28 | @@ -144,6 +146,7 @@ | |||
29 | 144 | format.StateServerKey = config.servingInfo.PrivateKey | 146 | format.StateServerKey = config.servingInfo.PrivateKey |
30 | 145 | format.APIPort = config.servingInfo.APIPort | 147 | format.APIPort = config.servingInfo.APIPort |
31 | 146 | format.StatePort = config.servingInfo.StatePort | 148 | format.StatePort = config.servingInfo.StatePort |
32 | 149 | format.SharedSecret = config.servingInfo.SharedSecret | ||
33 | 147 | } | 150 | } |
34 | 148 | if config.stateDetails != nil { | 151 | if config.stateDetails != nil { |
35 | 149 | format.StateAddresses = config.stateDetails.addresses | 152 | format.StateAddresses = config.stateDetails.addresses |
36 | 150 | 153 | ||
37 | === modified file 'agent/mongo/mongo.go' | |||
38 | --- agent/mongo/mongo.go 2014-04-17 12:33:55 +0000 | |||
39 | +++ agent/mongo/mongo.go 2014-04-18 04:41:05 +0000 | |||
40 | @@ -192,14 +192,11 @@ | |||
41 | 192 | } | 192 | } |
42 | 193 | logMongoVersion(mongoPath) | 193 | logMongoVersion(mongoPath) |
43 | 194 | 194 | ||
48 | 195 | // TODO(natefinch) 2014-04-12 https://launchpad.net/bugs/1306902 | 195 | if err := upstartServiceStop(&upstartConf.Service); err != nil { |
49 | 196 | // remove this once we support upgrading to HA | 196 | return fmt.Errorf("failed to stop mongo: %v", err) |
46 | 197 | if upstartConf.Installed() { | ||
47 | 198 | return nil | ||
50 | 199 | } | 197 | } |
51 | 200 | |||
52 | 201 | if err := makeJournalDirs(dbDir); err != nil { | 198 | if err := makeJournalDirs(dbDir); err != nil { |
54 | 202 | return fmt.Errorf("Error creating journal directories: %v", err) | 199 | return fmt.Errorf("error creating journal directories: %v", err) |
55 | 203 | } | 200 | } |
56 | 204 | return upstartConfInstall(upstartConf) | 201 | return upstartConfInstall(upstartConf) |
57 | 205 | } | 202 | } |
58 | 206 | 203 | ||
59 | === modified file 'cmd/jujud/bootstrap.go' | |||
60 | --- cmd/jujud/bootstrap.go 2014-04-17 16:26:01 +0000 | |||
61 | +++ cmd/jujud/bootstrap.go 2014-04-18 04:41:05 +0000 | |||
62 | @@ -18,7 +18,6 @@ | |||
63 | 18 | "launchpad.net/juju-core/environs" | 18 | "launchpad.net/juju-core/environs" |
64 | 19 | "launchpad.net/juju-core/environs/config" | 19 | "launchpad.net/juju-core/environs/config" |
65 | 20 | "launchpad.net/juju-core/instance" | 20 | "launchpad.net/juju-core/instance" |
66 | 21 | "launchpad.net/juju-core/provider" | ||
67 | 22 | "launchpad.net/juju-core/state" | 21 | "launchpad.net/juju-core/state" |
68 | 23 | "launchpad.net/juju-core/state/api/params" | 22 | "launchpad.net/juju-core/state/api/params" |
69 | 24 | "launchpad.net/juju-core/worker/peergrouper" | 23 | "launchpad.net/juju-core/worker/peergrouper" |
70 | @@ -171,14 +170,15 @@ | |||
71 | 171 | dialInfo.Addrs = []string{ | 170 | dialInfo.Addrs = []string{ |
72 | 172 | net.JoinHostPort("127.0.0.1", fmt.Sprint(servingInfo.StatePort)), | 171 | net.JoinHostPort("127.0.0.1", fmt.Sprint(servingInfo.StatePort)), |
73 | 173 | } | 172 | } |
74 | 173 | |||
75 | 174 | logger.Debugf("calling ensureMongoServer") | 174 | logger.Debugf("calling ensureMongoServer") |
78 | 175 | providerType := agentConfig.Value(agent.ProviderType) | 175 | withHA := shouldEnableHA(agentConfig) |
77 | 176 | withHA := providerType != provider.Local | ||
79 | 177 | err = ensureMongoServer( | 176 | err = ensureMongoServer( |
80 | 178 | agentConfig.DataDir(), | 177 | agentConfig.DataDir(), |
81 | 179 | agentConfig.Value(agent.Namespace), | 178 | agentConfig.Value(agent.Namespace), |
82 | 180 | servingInfo, | 179 | servingInfo, |
84 | 181 | withHA) | 180 | withHA, |
85 | 181 | ) | ||
86 | 182 | if err != nil { | 182 | if err != nil { |
87 | 183 | return err | 183 | return err |
88 | 184 | } | 184 | } |
89 | 185 | 185 | ||
90 | === modified file 'cmd/jujud/machine.go' | |||
91 | --- cmd/jujud/machine.go 2014-04-17 17:30:48 +0000 | |||
92 | +++ cmd/jujud/machine.go 2014-04-18 04:41:05 +0000 | |||
93 | @@ -5,6 +5,7 @@ | |||
94 | 5 | 5 | ||
95 | 6 | import ( | 6 | import ( |
96 | 7 | "fmt" | 7 | "fmt" |
97 | 8 | "net" | ||
98 | 8 | "os" | 9 | "os" |
99 | 9 | "path/filepath" | 10 | "path/filepath" |
100 | 10 | "runtime" | 11 | "runtime" |
101 | @@ -397,76 +398,19 @@ | |||
102 | 397 | return nil | 398 | return nil |
103 | 398 | } | 399 | } |
104 | 399 | 400 | ||
105 | 400 | func (a *MachineAgent) ensureMongoAdminUser(agentConfig agent.Config) (added bool, err error) { | ||
106 | 401 | stateInfo, ok1 := agentConfig.StateInfo() | ||
107 | 402 | servingInfo, ok2 := agentConfig.StateServingInfo() | ||
108 | 403 | if !ok1 || !ok2 { | ||
109 | 404 | return false, fmt.Errorf("no state serving info configuration") | ||
110 | 405 | } | ||
111 | 406 | dialInfo, err := state.DialInfo(stateInfo, state.DefaultDialOpts()) | ||
112 | 407 | if err != nil { | ||
113 | 408 | return false, err | ||
114 | 409 | } | ||
115 | 410 | if len(dialInfo.Addrs) > 1 { | ||
116 | 411 | logger.Infof("more than one state server; admin user must exist") | ||
117 | 412 | return false, nil | ||
118 | 413 | } | ||
119 | 414 | return ensureMongoAdminUser(mongo.EnsureAdminUserParams{ | ||
120 | 415 | DialInfo: dialInfo, | ||
121 | 416 | Namespace: agentConfig.Value(agent.Namespace), | ||
122 | 417 | DataDir: agentConfig.DataDir(), | ||
123 | 418 | Port: servingInfo.StatePort, | ||
124 | 419 | User: stateInfo.Tag, | ||
125 | 420 | Password: stateInfo.Password, | ||
126 | 421 | }) | ||
127 | 422 | } | ||
128 | 423 | |||
129 | 424 | // StateJobs returns a worker running all the workers that require | 401 | // StateJobs returns a worker running all the workers that require |
130 | 425 | // a *state.State connection. | 402 | // a *state.State connection. |
131 | 426 | func (a *MachineAgent) StateWorker() (worker.Worker, error) { | 403 | func (a *MachineAgent) StateWorker() (worker.Worker, error) { |
132 | 427 | agentConfig := a.CurrentConfig() | 404 | agentConfig := a.CurrentConfig() |
148 | 428 | 405 | if err := a.ensureMongoServer(agentConfig); err != nil { | |
134 | 429 | servingInfo, ok := agentConfig.StateServingInfo() | ||
135 | 430 | if !ok { | ||
136 | 431 | return nil, fmt.Errorf("state worker was started with no state serving info") | ||
137 | 432 | } | ||
138 | 433 | providerType := agentConfig.Value(agent.ProviderType) | ||
139 | 434 | namespace := agentConfig.Value(agent.Namespace) | ||
140 | 435 | withHA := providerType != provider.Local | ||
141 | 436 | err := ensureMongoServer( | ||
142 | 437 | agentConfig.DataDir(), | ||
143 | 438 | namespace, | ||
144 | 439 | servingInfo, | ||
145 | 440 | withHA, | ||
146 | 441 | ) | ||
147 | 442 | if err != nil { | ||
149 | 443 | return nil, err | 406 | return nil, err |
150 | 444 | } | 407 | } |
151 | 445 | |||
152 | 446 | st, m, err := openState(agentConfig) | 408 | st, m, err := openState(agentConfig) |
153 | 447 | if errors.IsUnauthorized(err) { | ||
154 | 448 | // TODO(axw) remove this when we no longer need | ||
155 | 449 | // to upgrade from pre-HA-capable environments. | ||
156 | 450 | logger.Debugf("failed to open state, reattempt after ensuring admin user exists: %v", err) | ||
157 | 451 | added, ensureErr := a.ensureMongoAdminUser(agentConfig) | ||
158 | 452 | if ensureErr != nil { | ||
159 | 453 | err = ensureErr | ||
160 | 454 | } | ||
161 | 455 | if !added { | ||
162 | 456 | // No user added, so it's probably a genuine unauthorized error. | ||
163 | 457 | return nil, err | ||
164 | 458 | } | ||
165 | 459 | st, m, err = openState(agentConfig) | ||
166 | 460 | } | ||
167 | 461 | if err != nil { | 409 | if err != nil { |
168 | 462 | return nil, err | 410 | return nil, err |
169 | 463 | } | 411 | } |
170 | 464 | reportOpenedState(st) | 412 | reportOpenedState(st) |
171 | 465 | 413 | ||
172 | 466 | // TODO(rog) call maybeInitiateMongoServer to upgrade mongo | ||
173 | 467 | // from old environments. We'll need to acquire a non-localhost | ||
174 | 468 | // address for the current instance before we do. | ||
175 | 469 | |||
176 | 470 | singularStateConn := singularStateConn{st.MongoSession(), m} | 414 | singularStateConn := singularStateConn{st.MongoSession(), m} |
177 | 471 | runner := newRunner(connectionIsFatal(st), moreImportant) | 415 | runner := newRunner(connectionIsFatal(st), moreImportant) |
178 | 472 | singularRunner, err := newSingularRunner(runner, singularStateConn) | 416 | singularRunner, err := newSingularRunner(runner, singularStateConn) |
179 | @@ -476,6 +420,7 @@ | |||
180 | 476 | 420 | ||
181 | 477 | // Take advantage of special knowledge here in that we will only ever want | 421 | // Take advantage of special knowledge here in that we will only ever want |
182 | 478 | // the storage provider on one machine, and that is the "bootstrap" node. | 422 | // the storage provider on one machine, and that is the "bootstrap" node. |
183 | 423 | providerType := agentConfig.Value(agent.ProviderType) | ||
184 | 479 | if (providerType == provider.Local || provider.IsManual(providerType)) && m.Id() == bootstrapMachineId { | 424 | if (providerType == provider.Local || provider.IsManual(providerType)) && m.Id() == bootstrapMachineId { |
185 | 480 | a.startWorkerAfterUpgrade(runner, "local-storage", func() (worker.Worker, error) { | 425 | a.startWorkerAfterUpgrade(runner, "local-storage", func() (worker.Worker, error) { |
186 | 481 | // TODO(axw) 2013-09-24 bug #1229507 | 426 | // TODO(axw) 2013-09-24 bug #1229507 |
187 | @@ -540,6 +485,129 @@ | |||
188 | 540 | return newCloseWorker(runner, st), nil | 485 | return newCloseWorker(runner, st), nil |
189 | 541 | } | 486 | } |
190 | 542 | 487 | ||
191 | 488 | // ensureMongoServer ensures that mongo is installed and running, | ||
192 | 489 | // and ready for opening a state connection. | ||
193 | 490 | func (a *MachineAgent) ensureMongoServer(agentConfig agent.Config) error { | ||
194 | 491 | servingInfo, ok := agentConfig.StateServingInfo() | ||
195 | 492 | if !ok { | ||
196 | 493 | return fmt.Errorf("state worker was started with no state serving info") | ||
197 | 494 | } | ||
198 | 495 | namespace := agentConfig.Value(agent.Namespace) | ||
199 | 496 | withHA := shouldEnableHA(agentConfig) | ||
200 | 497 | |||
201 | 498 | // When upgrading from a pre-HA-capable environment, | ||
202 | 499 | // we must add machine-0 to the admin database and | ||
203 | 500 | // initiate its replicaset. | ||
204 | 501 | // | ||
205 | 502 | // TODO(axw) remove this when we no longer need | ||
206 | 503 | // to upgrade from pre-HA-capable environments. | ||
207 | 504 | var shouldInitiateMongoServer bool | ||
208 | 505 | var addrs []instance.Address | ||
209 | 506 | if isPreHAVersion(agentConfig.UpgradedToVersion()) { | ||
210 | 507 | _, err := a.ensureMongoAdminUser(agentConfig) | ||
211 | 508 | if err != nil { | ||
212 | 509 | return err | ||
213 | 510 | } | ||
214 | 511 | if servingInfo.SharedSecret == "" { | ||
215 | 512 | servingInfo.SharedSecret, err = mongo.GenerateSharedSecret() | ||
216 | 513 | if err != nil { | ||
217 | 514 | return err | ||
218 | 515 | } | ||
219 | 516 | if err = a.ChangeConfig(func(config agent.ConfigSetter) { | ||
220 | 517 | config.SetStateServingInfo(servingInfo) | ||
221 | 518 | }); err != nil { | ||
222 | 519 | return err | ||
223 | 520 | } | ||
224 | 521 | agentConfig = a.CurrentConfig() | ||
225 | 522 | } | ||
226 | 523 | st, m, err := openState(agentConfig) | ||
227 | 524 | if err != nil { | ||
228 | 525 | return err | ||
229 | 526 | } | ||
230 | 527 | if err := st.SetStateServingInfo(servingInfo); err != nil { | ||
231 | 528 | st.Close() | ||
232 | 529 | return fmt.Errorf("cannot set state serving info: %v", err) | ||
233 | 530 | } | ||
234 | 531 | st.Close() | ||
235 | 532 | addrs = m.Addresses() | ||
236 | 533 | shouldInitiateMongoServer = withHA | ||
237 | 534 | } | ||
238 | 535 | |||
239 | 536 | // ensureMongoServer installs/upgrades the upstart config as necessary. | ||
240 | 537 | if err := ensureMongoServer( | ||
241 | 538 | agentConfig.DataDir(), | ||
242 | 539 | namespace, | ||
243 | 540 | servingInfo, | ||
244 | 541 | withHA, | ||
245 | 542 | ); err != nil { | ||
246 | 543 | return err | ||
247 | 544 | } | ||
248 | 545 | if !shouldInitiateMongoServer { | ||
249 | 546 | return nil | ||
250 | 547 | } | ||
251 | 548 | |||
252 | 549 | // Initiate the replicaset for upgraded environments. | ||
253 | 550 | // | ||
254 | 551 | // TODO(axw) remove this when we no longer need | ||
255 | 552 | // to upgrade from pre-HA-capable environments. | ||
256 | 553 | stateInfo, ok := agentConfig.StateInfo() | ||
257 | 554 | if !ok { | ||
258 | 555 | return fmt.Errorf("state worker was started with no state serving info") | ||
259 | 556 | } | ||
260 | 557 | dialInfo, err := state.DialInfo(stateInfo, state.DefaultDialOpts()) | ||
261 | 558 | if err != nil { | ||
262 | 559 | return err | ||
263 | 560 | } | ||
264 | 561 | peerAddr := mongo.SelectPeerAddress(addrs) | ||
265 | 562 | if peerAddr == "" { | ||
266 | 563 | return fmt.Errorf("no appropriate peer address found in %q", addrs) | ||
267 | 564 | } | ||
268 | 565 | return maybeInitiateMongoServer(peergrouper.InitiateMongoParams{ | ||
269 | 566 | DialInfo: dialInfo, | ||
270 | 567 | MemberHostPort: net.JoinHostPort(peerAddr, fmt.Sprint(servingInfo.StatePort)), | ||
271 | 568 | User: stateInfo.Tag, | ||
272 | 569 | Password: stateInfo.Password, | ||
273 | 570 | }) | ||
274 | 571 | } | ||
275 | 572 | |||
276 | 573 | func (a *MachineAgent) ensureMongoAdminUser(agentConfig agent.Config) (added bool, err error) { | ||
277 | 574 | stateInfo, ok1 := agentConfig.StateInfo() | ||
278 | 575 | servingInfo, ok2 := agentConfig.StateServingInfo() | ||
279 | 576 | if !ok1 || !ok2 { | ||
280 | 577 | return false, fmt.Errorf("no state serving info configuration") | ||
281 | 578 | } | ||
282 | 579 | dialInfo, err := state.DialInfo(stateInfo, state.DefaultDialOpts()) | ||
283 | 580 | if err != nil { | ||
284 | 581 | return false, err | ||
285 | 582 | } | ||
286 | 583 | if len(dialInfo.Addrs) > 1 { | ||
287 | 584 | logger.Infof("more than one state server; admin user must exist") | ||
288 | 585 | return false, nil | ||
289 | 586 | } | ||
290 | 587 | return ensureMongoAdminUser(mongo.EnsureAdminUserParams{ | ||
291 | 588 | DialInfo: dialInfo, | ||
292 | 589 | Namespace: agentConfig.Value(agent.Namespace), | ||
293 | 590 | DataDir: agentConfig.DataDir(), | ||
294 | 591 | Port: servingInfo.StatePort, | ||
295 | 592 | User: stateInfo.Tag, | ||
296 | 593 | Password: stateInfo.Password, | ||
297 | 594 | }) | ||
298 | 595 | } | ||
299 | 596 | |||
300 | 597 | func isPreHAVersion(v version.Number) bool { | ||
301 | 598 | return v.Compare(version.MustParse("1.19.0")) < 0 | ||
302 | 599 | } | ||
303 | 600 | |||
304 | 601 | // shouldEnableHA reports whether HA should be enabled. | ||
305 | 602 | // | ||
306 | 603 | // Eventually this should always be true, and ideally | ||
307 | 604 | // it should be true before 1.20 is released or we'll | ||
308 | 605 | // have more upgrade scenarios on our hands. | ||
309 | 606 | func shouldEnableHA(agentConfig agent.Config) bool { | ||
310 | 607 | providerType := agentConfig.Value(agent.ProviderType) | ||
311 | 608 | return providerType != provider.Local | ||
312 | 609 | } | ||
313 | 610 | |||
314 | 543 | func openState(agentConfig agent.Config) (_ *state.State, _ *state.Machine, err error) { | 611 | func openState(agentConfig agent.Config) (_ *state.State, _ *state.Machine, err error) { |
315 | 544 | info, ok := agentConfig.StateInfo() | 612 | info, ok := agentConfig.StateInfo() |
316 | 545 | if !ok { | 613 | if !ok { |
317 | 546 | 614 | ||
318 | === modified file 'cmd/jujud/machine_test.go' | |||
319 | --- cmd/jujud/machine_test.go 2014-04-17 17:30:48 +0000 | |||
320 | +++ cmd/jujud/machine_test.go 2014-04-18 04:41:05 +0000 | |||
321 | @@ -59,6 +59,7 @@ | |||
322 | 59 | agentSuite | 59 | agentSuite |
323 | 60 | singularRecord *singularRunnerRecord | 60 | singularRecord *singularRunnerRecord |
324 | 61 | lxctesting.TestSuite | 61 | lxctesting.TestSuite |
325 | 62 | fakeEnsureMongo fakeEnsure | ||
326 | 62 | } | 63 | } |
327 | 63 | 64 | ||
328 | 64 | func (s *commonMachineSuite) SetUpSuite(c *gc.C) { | 65 | func (s *commonMachineSuite) SetUpSuite(c *gc.C) { |
329 | @@ -96,6 +97,10 @@ | |||
330 | 96 | testing.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { | 97 | testing.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { |
331 | 97 | return newDummyWorker(), nil | 98 | return newDummyWorker(), nil |
332 | 98 | }) | 99 | }) |
333 | 100 | |||
334 | 101 | s.fakeEnsureMongo = fakeEnsure{} | ||
335 | 102 | s.PatchValue(&ensureMongoServer, s.fakeEnsureMongo.fakeEnsureMongo) | ||
336 | 103 | s.PatchValue(&maybeInitiateMongoServer, s.fakeEnsureMongo.fakeInitiateMongo) | ||
337 | 99 | } | 104 | } |
338 | 100 | 105 | ||
339 | 101 | func fakeCmd(path string) { | 106 | func fakeCmd(path string) { |
340 | @@ -123,6 +128,10 @@ | |||
341 | 123 | inst, md := jujutesting.AssertStartInstance(c, s.Conn.Environ, m.Id()) | 128 | inst, md := jujutesting.AssertStartInstance(c, s.Conn.Environ, m.Id()) |
342 | 124 | c.Assert(m.SetProvisioned(inst.Id(), state.BootstrapNonce, md), gc.IsNil) | 129 | c.Assert(m.SetProvisioned(inst.Id(), state.BootstrapNonce, md), gc.IsNil) |
343 | 125 | 130 | ||
344 | 131 | // Add an address for the tests in case the maybeInitiateMongoServer | ||
345 | 132 | // codepath is exercised. | ||
346 | 133 | s.setFakeMachineAddresses(c, m) | ||
347 | 134 | |||
348 | 126 | // Set up the new machine. | 135 | // Set up the new machine. |
349 | 127 | err = m.SetAgentVersion(vers) | 136 | err = m.SetAgentVersion(vers) |
350 | 128 | c.Assert(err, gc.IsNil) | 137 | c.Assert(err, gc.IsNil) |
351 | @@ -327,7 +336,7 @@ | |||
352 | 327 | return ctx, func() { newDeployContext = orig } | 336 | return ctx, func() { newDeployContext = orig } |
353 | 328 | } | 337 | } |
354 | 329 | 338 | ||
356 | 330 | func (s *MachineSuite) setFakeMachineAddresses(c *gc.C, machine *state.Machine) { | 339 | func (s *commonMachineSuite) setFakeMachineAddresses(c *gc.C, machine *state.Machine) { |
357 | 331 | addrs := []instance.Address{ | 340 | addrs := []instance.Address{ |
358 | 332 | instance.NewAddress("0.1.2.3", instance.NetworkUnknown), | 341 | instance.NewAddress("0.1.2.3", instance.NetworkUnknown), |
359 | 333 | } | 342 | } |
360 | @@ -347,7 +356,6 @@ | |||
361 | 347 | usefulVersion.Series = "quantal" // to match the charm created below | 356 | usefulVersion.Series = "quantal" // to match the charm created below |
362 | 348 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) | 357 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) |
363 | 349 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) | 358 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) |
364 | 350 | s.setFakeMachineAddresses(c, m) | ||
365 | 351 | op := make(chan dummy.Operation, 200) | 359 | op := make(chan dummy.Operation, 200) |
366 | 352 | dummy.Listen(op) | 360 | dummy.Listen(op) |
367 | 353 | 361 | ||
368 | @@ -405,7 +413,6 @@ | |||
369 | 405 | usefulVersion.Series = "quantal" // to match the charm created below | 413 | usefulVersion.Series = "quantal" // to match the charm created below |
370 | 406 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) | 414 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) |
371 | 407 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) | 415 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) |
372 | 408 | s.setFakeMachineAddresses(c, m) | ||
373 | 409 | a := s.newAgent(c, m) | 416 | a := s.newAgent(c, m) |
374 | 410 | defer a.Stop() | 417 | defer a.Stop() |
375 | 411 | go func() { | 418 | go func() { |
376 | @@ -469,7 +476,6 @@ | |||
377 | 469 | usefulVersion.Series = "quantal" | 476 | usefulVersion.Series = "quantal" |
378 | 470 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) | 477 | envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), usefulVersion) |
379 | 471 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) | 478 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) |
380 | 472 | s.setFakeMachineAddresses(c, m) | ||
381 | 473 | calledChan := make(chan struct{}, 1) | 479 | calledChan := make(chan struct{}, 1) |
382 | 474 | s.PatchValue(&useMultipleCPUs, func() { calledChan <- struct{}{} }) | 480 | s.PatchValue(&useMultipleCPUs, func() { calledChan <- struct{}{} }) |
383 | 475 | // Now, start the agent, and observe that a JobManageEnviron agent | 481 | // Now, start the agent, and observe that a JobManageEnviron agent |
384 | @@ -489,7 +495,6 @@ | |||
385 | 489 | c.Check(a.Stop(), gc.IsNil) | 495 | c.Check(a.Stop(), gc.IsNil) |
386 | 490 | // However, an agent that just JobHostUnits doesn't call UseMultipleCPUs | 496 | // However, an agent that just JobHostUnits doesn't call UseMultipleCPUs |
387 | 491 | m2, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) | 497 | m2, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) |
388 | 492 | s.setFakeMachineAddresses(c, m2) | ||
389 | 493 | a2 := s.newAgent(c, m2) | 498 | a2 := s.newAgent(c, m2) |
390 | 494 | defer a2.Stop() | 499 | defer a2.Stop() |
391 | 495 | go func() { | 500 | go func() { |
392 | @@ -923,9 +928,12 @@ | |||
393 | 923 | c.Fatalf("timeout while waiting for agent config to change") | 928 | c.Fatalf("timeout while waiting for agent config to change") |
394 | 924 | } | 929 | } |
395 | 925 | 930 | ||
399 | 926 | func (s *MachineSuite) TestMachineAgentEnsureAdminUser(c *gc.C) { | 931 | func (s *MachineSuite) TestMachineAgentUpgradeMongo(c *gc.C) { |
400 | 927 | m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) | 932 | m, agentConfig, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) |
401 | 928 | err := s.State.MongoSession().DB("admin").RemoveUser(m.Tag()) | 933 | agentConfig.SetUpgradedToVersion(version.MustParse("1.18.0")) |
402 | 934 | err := agentConfig.Write() | ||
403 | 935 | c.Assert(err, gc.IsNil) | ||
404 | 936 | err = s.State.MongoSession().DB("admin").RemoveUser(m.Tag()) | ||
405 | 929 | c.Assert(err, gc.IsNil) | 937 | c.Assert(err, gc.IsNil) |
406 | 930 | 938 | ||
407 | 931 | s.PatchValue(&ensureMongoAdminUser, func(p mongo.EnsureAdminUserParams) (bool, error) { | 939 | s.PatchValue(&ensureMongoAdminUser, func(p mongo.EnsureAdminUserParams) (bool, error) { |
408 | @@ -954,6 +962,8 @@ | |||
409 | 954 | c.Fatalf("state not opened") | 962 | c.Fatalf("state not opened") |
410 | 955 | } | 963 | } |
411 | 956 | s.waitStopped(c, state.JobManageEnviron, a, done) | 964 | s.waitStopped(c, state.JobManageEnviron, a, done) |
412 | 965 | c.Assert(s.fakeEnsureMongo.ensureCount, gc.Equals, 1) | ||
413 | 966 | c.Assert(s.fakeEnsureMongo.initiateCount, gc.Equals, 1) | ||
414 | 957 | } | 967 | } |
415 | 958 | 968 | ||
416 | 959 | // MachineWithCharmsSuite provides infrastructure for tests which need to | 969 | // MachineWithCharmsSuite provides infrastructure for tests which need to |
417 | 960 | 970 | ||
418 | === modified file 'worker/peergrouper/desired_test.go' | |||
419 | --- worker/peergrouper/desired_test.go 2014-04-17 16:27:08 +0000 | |||
420 | +++ worker/peergrouper/desired_test.go 2014-04-18 04:41:05 +0000 | |||
421 | @@ -8,21 +8,15 @@ | |||
422 | 8 | "sort" | 8 | "sort" |
423 | 9 | "strconv" | 9 | "strconv" |
424 | 10 | "strings" | 10 | "strings" |
425 | 11 | stdtesting "testing" | ||
426 | 12 | 11 | ||
427 | 13 | jc "github.com/juju/testing/checkers" | 12 | jc "github.com/juju/testing/checkers" |
428 | 14 | gc "launchpad.net/gocheck" | 13 | gc "launchpad.net/gocheck" |
429 | 15 | 14 | ||
430 | 16 | "launchpad.net/juju-core/instance" | 15 | "launchpad.net/juju-core/instance" |
431 | 17 | "launchpad.net/juju-core/replicaset" | 16 | "launchpad.net/juju-core/replicaset" |
432 | 18 | coretesting "launchpad.net/juju-core/testing" | ||
433 | 19 | "launchpad.net/juju-core/testing/testbase" | 17 | "launchpad.net/juju-core/testing/testbase" |
434 | 20 | ) | 18 | ) |
435 | 21 | 19 | ||
436 | 22 | func TestPackage(t *stdtesting.T) { | ||
437 | 23 | coretesting.MgoTestPackage(t) | ||
438 | 24 | } | ||
439 | 25 | |||
440 | 26 | type desiredPeerGroupSuite struct { | 20 | type desiredPeerGroupSuite struct { |
441 | 27 | testbase.LoggingSuite | 21 | testbase.LoggingSuite |
442 | 28 | } | 22 | } |
443 | 29 | 23 | ||
444 | === modified file 'worker/peergrouper/initiate.go' | |||
445 | --- worker/peergrouper/initiate.go 2014-04-15 16:37:08 +0000 | |||
446 | +++ worker/peergrouper/initiate.go 2014-04-18 04:41:05 +0000 | |||
447 | @@ -39,20 +39,20 @@ | |||
448 | 39 | return nil | 39 | return nil |
449 | 40 | } | 40 | } |
450 | 41 | p.DialInfo.Direct = true | 41 | p.DialInfo.Direct = true |
451 | 42 | |||
452 | 43 | // TODO(rog) remove this code when we no longer need to upgrade | ||
453 | 44 | // from pre-HA-capable environments. | ||
454 | 45 | if p.User != "" { | ||
455 | 46 | p.DialInfo.Username = p.User | ||
456 | 47 | p.DialInfo.Password = p.Password | ||
457 | 48 | } | ||
458 | 49 | |||
459 | 42 | session, err := mgo.DialWithInfo(p.DialInfo) | 50 | session, err := mgo.DialWithInfo(p.DialInfo) |
460 | 43 | if err != nil { | 51 | if err != nil { |
461 | 44 | return fmt.Errorf("can't dial mongo to initiate replicaset: %v", err) | 52 | return fmt.Errorf("can't dial mongo to initiate replicaset: %v", err) |
462 | 45 | } | 53 | } |
463 | 46 | defer session.Close() | 54 | defer session.Close() |
464 | 47 | 55 | ||
465 | 48 | // TODO(rog) remove this code when we no longer need to upgrade | ||
466 | 49 | // from pre-HA-capable environments. | ||
467 | 50 | if p.User != "" { | ||
468 | 51 | err := session.DB("admin").Login(p.User, p.Password) | ||
469 | 52 | if err != nil { | ||
470 | 53 | logger.Errorf("cannot login to admin db as %q, password %q, falling back: %v", p.User, p.Password, err) | ||
471 | 54 | } | ||
472 | 55 | } | ||
473 | 56 | cfg, err := replicaset.CurrentConfig(session) | 56 | cfg, err := replicaset.CurrentConfig(session) |
474 | 57 | if err == nil && len(cfg.Members) > 0 { | 57 | if err == nil && len(cfg.Members) > 0 { |
475 | 58 | logger.Infof("replica set configuration already found: %#v", cfg) | 58 | logger.Infof("replica set configuration already found: %#v", cfg) |
476 | 59 | 59 | ||
477 | === modified file 'worker/peergrouper/initiate_test.go' | |||
478 | --- worker/peergrouper/initiate_test.go 2014-04-14 19:23:22 +0000 | |||
479 | +++ worker/peergrouper/initiate_test.go 2014-04-18 04:41:05 +0000 | |||
480 | @@ -25,6 +25,7 @@ | |||
481 | 25 | inst := &coretesting.MgoInstance{Params: []string{"--replSet", "juju"}} | 25 | inst := &coretesting.MgoInstance{Params: []string{"--replSet", "juju"}} |
482 | 26 | err = inst.Start(true) | 26 | err = inst.Start(true) |
483 | 27 | c.Assert(err, gc.IsNil) | 27 | c.Assert(err, gc.IsNil) |
484 | 28 | defer inst.Destroy() | ||
485 | 28 | 29 | ||
486 | 29 | info := inst.DialInfo() | 30 | info := inst.DialInfo() |
487 | 30 | args := peergrouper.InitiateMongoParams{ | 31 | args := peergrouper.InitiateMongoParams{ |
488 | 31 | 32 | ||
489 | === added file 'worker/peergrouper/suite_test.go' | |||
490 | --- worker/peergrouper/suite_test.go 1970-01-01 00:00:00 +0000 | |||
491 | +++ worker/peergrouper/suite_test.go 2014-04-18 04:41:05 +0000 | |||
492 | @@ -0,0 +1,14 @@ | |||
493 | 1 | // Copyright 2014 Canonical Ltd. | ||
494 | 2 | // Licensed under the AGPLv3, see LICENCE file for details. | ||
495 | 3 | |||
496 | 4 | package peergrouper_test | ||
497 | 5 | |||
498 | 6 | import ( | ||
499 | 7 | stdtesting "testing" | ||
500 | 8 | |||
501 | 9 | "launchpad.net/juju-core/testing" | ||
502 | 10 | ) | ||
503 | 11 | |||
504 | 12 | func TestPackage(t *stdtesting.T) { | ||
505 | 13 | testing.MgoTestPackage(t) | ||
506 | 14 | } |
Reviewers: mp+216245_ code.launchpad. net,
Message:
Please take a look.
Description:
HA: upgrade upstart and initiate replset
The machine agent will now upgrade the
Mongo upstart script and initiate the
replicaset when upgrading from a version
prior to 1.19.0.
Tested upgrading 1.18.1 to 1.19.1 with and
without HA enabled; tested straight bootstrap
to 1.19.1 with and without HA enabled.
(Supersedes https:/ /codereview. appspot. com/88350043/)
https:/ /code.launchpad .net/~axwalk/ juju-core/ lp1306902- ha-upgrade- take2/+ merge/216245
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/88790043/
Affected files (+153, -66 lines): 1.18.go mongo.go bootstrap. go machine. go machine_ test.go peergrouper/ desired_ test.go peergrouper/ initiate. go peergrouper/ initiate_ test.go peergrouper/ suite_test. go
A [revision details]
M agent/format-
M agent/mongo/
M cmd/jujud/
M cmd/jujud/
M cmd/jujud/
M worker/
M worker/
M worker/
A worker/