github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/jujud/agent/machine_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package agent 5 6 import ( 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "reflect" 12 "runtime" 13 "strings" 14 "sync/atomic" 15 "testing" 16 "time" 17 18 "github.com/juju/cmd" 19 "github.com/juju/errors" 20 "github.com/juju/names" 21 gitjujutesting "github.com/juju/testing" 22 jc "github.com/juju/testing/checkers" 23 "github.com/juju/utils/clock" 24 "github.com/juju/utils/proxy" 25 "github.com/juju/utils/set" 26 "github.com/juju/utils/symlink" 27 gc "gopkg.in/check.v1" 28 "gopkg.in/juju/charm.v6-unstable" 29 "gopkg.in/juju/charmrepo.v1" 30 "gopkg.in/natefinch/lumberjack.v2" 31 32 "github.com/juju/juju/agent" 33 "github.com/juju/juju/api" 34 apiaddresser "github.com/juju/juju/api/addresser" 35 apideployer "github.com/juju/juju/api/deployer" 36 apienvironment "github.com/juju/juju/api/environment" 37 apifirewaller "github.com/juju/juju/api/firewaller" 38 "github.com/juju/juju/api/imagemetadata" 39 apiinstancepoller "github.com/juju/juju/api/instancepoller" 40 apimetricsmanager "github.com/juju/juju/api/metricsmanager" 41 apinetworker "github.com/juju/juju/api/networker" 42 apirsyslog "github.com/juju/juju/api/rsyslog" 43 charmtesting "github.com/juju/juju/apiserver/charmrevisionupdater/testing" 44 "github.com/juju/juju/apiserver/params" 45 "github.com/juju/juju/cert" 46 agenttesting "github.com/juju/juju/cmd/jujud/agent/testing" 47 cmdutil "github.com/juju/juju/cmd/jujud/util" 48 lxctesting "github.com/juju/juju/container/lxc/testing" 49 "github.com/juju/juju/environs/config" 50 envtesting "github.com/juju/juju/environs/testing" 51 "github.com/juju/juju/feature" 52 "github.com/juju/juju/instance" 53 "github.com/juju/juju/juju" 54 jujutesting "github.com/juju/juju/juju/testing" 55 "github.com/juju/juju/mongo" 56 "github.com/juju/juju/network" 57 "github.com/juju/juju/provider/dummy" 58 "github.com/juju/juju/service/upstart" 59 "github.com/juju/juju/state" 60 "github.com/juju/juju/state/watcher" 61 "github.com/juju/juju/storage" 62 coretesting "github.com/juju/juju/testing" 63 "github.com/juju/juju/testing/factory" 64 "github.com/juju/juju/tools" 65 "github.com/juju/juju/utils/ssh" 66 sshtesting "github.com/juju/juju/utils/ssh/testing" 67 "github.com/juju/juju/version" 68 "github.com/juju/juju/worker" 69 "github.com/juju/juju/worker/addresser" 70 "github.com/juju/juju/worker/apicaller" 71 "github.com/juju/juju/worker/authenticationworker" 72 "github.com/juju/juju/worker/certupdater" 73 "github.com/juju/juju/worker/deployer" 74 "github.com/juju/juju/worker/diskmanager" 75 "github.com/juju/juju/worker/instancepoller" 76 "github.com/juju/juju/worker/logsender" 77 "github.com/juju/juju/worker/machiner" 78 "github.com/juju/juju/worker/networker" 79 "github.com/juju/juju/worker/peergrouper" 80 "github.com/juju/juju/worker/proxyupdater" 81 "github.com/juju/juju/worker/resumer" 82 "github.com/juju/juju/worker/rsyslog" 83 "github.com/juju/juju/worker/singular" 84 "github.com/juju/juju/worker/storageprovisioner" 85 "github.com/juju/juju/worker/upgrader" 86 ) 87 88 var ( 89 _ = gc.Suite(&MachineSuite{}) 90 _ = gc.Suite(&MachineWithCharmsSuite{}) 91 _ = gc.Suite(&mongoSuite{}) 92 ) 93 94 func TestPackage(t *testing.T) { 95 // TODO(waigani) 2014-03-19 bug 1294458 96 // Refactor to use base suites 97 98 // Change the path to "juju-run", so that the 99 // tests don't try to write to /usr/local/bin. 100 JujuRun = mktemp("juju-run", "") 101 defer os.Remove(JujuRun) 102 103 coretesting.MgoTestPackage(t) 104 } 105 106 type commonMachineSuite struct { 107 singularRecord *singularRunnerRecord 108 lxctesting.TestSuite 109 fakeEnsureMongo *agenttesting.FakeEnsureMongo 110 AgentSuite 111 } 112 113 func (s *commonMachineSuite) SetUpSuite(c *gc.C) { 114 s.AgentSuite.SetUpSuite(c) 115 s.TestSuite.SetUpSuite(c) 116 } 117 118 func (s *commonMachineSuite) TearDownSuite(c *gc.C) { 119 s.TestSuite.TearDownSuite(c) 120 s.AgentSuite.TearDownSuite(c) 121 } 122 123 func (s *commonMachineSuite) SetUpTest(c *gc.C) { 124 s.AgentSuite.PatchValue(&version.Current.Number, coretesting.FakeVersionNumber) 125 s.AgentSuite.SetUpTest(c) 126 s.TestSuite.SetUpTest(c) 127 s.AgentSuite.PatchValue(&charmrepo.CacheDir, c.MkDir()) 128 s.AgentSuite.PatchValue(&stateWorkerDialOpts, mongo.DefaultDialOpts()) 129 130 os.Remove(JujuRun) // ignore error; may not exist 131 // Patch ssh user to avoid touching ~ubuntu/.ssh/authorized_keys. 132 s.AgentSuite.PatchValue(&authenticationworker.SSHUser, "") 133 134 testpath := c.MkDir() 135 s.AgentSuite.PatchEnvPathPrepend(testpath) 136 // mock out the start method so we can fake install services without sudo 137 fakeCmd(filepath.Join(testpath, "start")) 138 fakeCmd(filepath.Join(testpath, "stop")) 139 140 s.AgentSuite.PatchValue(&upstart.InitDir, c.MkDir()) 141 142 s.singularRecord = newSingularRunnerRecord() 143 s.AgentSuite.PatchValue(&newSingularRunner, s.singularRecord.newSingularRunner) 144 s.AgentSuite.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { 145 return newDummyWorker(), nil 146 }) 147 148 s.fakeEnsureMongo = agenttesting.InstallFakeEnsureMongo(s) 149 s.AgentSuite.PatchValue(&maybeInitiateMongoServer, s.fakeEnsureMongo.InitiateMongo) 150 } 151 152 func fakeCmd(path string) { 153 err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 0"), 0755) 154 if err != nil { 155 panic(err) 156 } 157 } 158 159 func (s *commonMachineSuite) TearDownTest(c *gc.C) { 160 s.TestSuite.TearDownTest(c) 161 s.AgentSuite.TearDownTest(c) 162 } 163 164 // primeAgent adds a new Machine to run the given jobs, and sets up the 165 // machine agent's directory. It returns the new machine, the 166 // agent's configuration and the tools currently running. 167 func (s *commonMachineSuite) primeAgent( 168 c *gc.C, vers version.Binary, 169 jobs ...state.MachineJob) (m *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools) { 170 171 m, err := s.State.AddMachine("quantal", jobs...) 172 c.Assert(err, jc.ErrorIsNil) 173 174 pinger, err := m.SetAgentPresence() 175 c.Assert(err, jc.ErrorIsNil) 176 s.AddCleanup(func(c *gc.C) { 177 err := pinger.Stop() 178 c.Check(err, jc.ErrorIsNil) 179 }) 180 181 return s.configureMachine(c, m.Id(), vers) 182 } 183 184 func (s *commonMachineSuite) configureMachine(c *gc.C, machineId string, vers version.Binary) ( 185 machine *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools, 186 ) { 187 m, err := s.State.Machine(machineId) 188 c.Assert(err, jc.ErrorIsNil) 189 190 // Add a machine and ensure it is provisioned. 191 inst, md := jujutesting.AssertStartInstance(c, s.Environ, machineId) 192 c.Assert(m.SetProvisioned(inst.Id(), agent.BootstrapNonce, md), jc.ErrorIsNil) 193 194 // Add an address for the tests in case the maybeInitiateMongoServer 195 // codepath is exercised. 196 s.setFakeMachineAddresses(c, m) 197 198 // Set up the new machine. 199 err = m.SetAgentVersion(vers) 200 c.Assert(err, jc.ErrorIsNil) 201 err = m.SetPassword(initialMachinePassword) 202 c.Assert(err, jc.ErrorIsNil) 203 tag := m.Tag() 204 if m.IsManager() { 205 err = m.SetMongoPassword(initialMachinePassword) 206 c.Assert(err, jc.ErrorIsNil) 207 agentConfig, tools = s.AgentSuite.PrimeStateAgent(c, tag, initialMachinePassword, vers) 208 info, ok := agentConfig.StateServingInfo() 209 c.Assert(ok, jc.IsTrue) 210 ssi := cmdutil.ParamsStateServingInfoToStateStateServingInfo(info) 211 err = s.State.SetStateServingInfo(ssi) 212 c.Assert(err, jc.ErrorIsNil) 213 } else { 214 agentConfig, tools = s.PrimeAgent(c, tag, initialMachinePassword, vers) 215 } 216 err = agentConfig.Write() 217 c.Assert(err, jc.ErrorIsNil) 218 return m, agentConfig, tools 219 } 220 221 // newAgent returns a new MachineAgent instance 222 func (s *commonMachineSuite) newAgent(c *gc.C, m *state.Machine) *MachineAgent { 223 agentConf := agentConf{dataDir: s.DataDir()} 224 agentConf.ReadConfig(names.NewMachineTag(m.Id()).String()) 225 logsCh, err := logsender.InstallBufferedLogWriter(1024) 226 c.Assert(err, jc.ErrorIsNil) 227 machineAgentFactory := MachineAgentFactoryFn( 228 &agentConf, logsCh, &mockLoopDeviceManager{}, 229 ) 230 return machineAgentFactory(m.Id()) 231 } 232 233 func (s *MachineSuite) TestParseSuccess(c *gc.C) { 234 create := func() (cmd.Command, AgentConf) { 235 agentConf := agentConf{dataDir: s.DataDir()} 236 a := NewMachineAgentCmd( 237 nil, 238 MachineAgentFactoryFn( 239 &agentConf, nil, &mockLoopDeviceManager{}, 240 ), 241 &agentConf, 242 &agentConf, 243 ) 244 a.(*machineAgentCmd).logToStdErr = true 245 246 return a, &agentConf 247 } 248 a := CheckAgentCommand(c, create, []string{"--machine-id", "42"}) 249 c.Assert(a.(*machineAgentCmd).machineId, gc.Equals, "42") 250 } 251 252 type MachineSuite struct { 253 commonMachineSuite 254 metricAPI *mockMetricAPI 255 } 256 257 var perEnvSingularWorkers = []string{ 258 "cleaner", 259 "minunitsworker", 260 "addresserworker", 261 "environ-provisioner", 262 "charm-revision-updater", 263 "instancepoller", 264 "firewaller", 265 } 266 267 const initialMachinePassword = "machine-password-1234567890" 268 269 func (s *MachineSuite) SetUpTest(c *gc.C) { 270 s.commonMachineSuite.SetUpTest(c) 271 s.metricAPI = newMockMetricAPI() 272 s.PatchValue(&getMetricAPI, func(_ api.Connection) apimetricsmanager.MetricsManagerClient { 273 return s.metricAPI 274 }) 275 s.AddCleanup(func(*gc.C) { s.metricAPI.Stop() }) 276 // Most of these tests normally finish sub-second on a fast machine. 277 // If any given test hits a minute, we have almost certainly become 278 // wedged, so dump the logs. 279 coretesting.DumpTestLogsAfter(time.Minute, c, s) 280 } 281 282 func (s *MachineSuite) TestParseNonsense(c *gc.C) { 283 for _, args := range [][]string{ 284 {}, 285 {"--machine-id", "-4004"}, 286 } { 287 var agentConf agentConf 288 err := ParseAgentCommand(&machineAgentCmd{agentInitializer: &agentConf}, args) 289 c.Assert(err, gc.ErrorMatches, "--machine-id option must be set, and expects a non-negative integer") 290 } 291 } 292 293 func (s *MachineSuite) TestParseUnknown(c *gc.C) { 294 var agentConf agentConf 295 a := &machineAgentCmd{agentInitializer: &agentConf} 296 err := ParseAgentCommand(a, []string{"--machine-id", "42", "blistering barnacles"}) 297 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["blistering barnacles"\]`) 298 } 299 300 func (s *MachineSuite) TestRunInvalidMachineId(c *gc.C) { 301 c.Skip("agents don't yet distinguish between temporary and permanent errors") 302 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 303 err := s.newAgent(c, m).Run(nil) 304 c.Assert(err, gc.ErrorMatches, "some error") 305 } 306 307 func (s *MachineSuite) TestUseLumberjack(c *gc.C) { 308 ctx, err := cmd.DefaultContext() 309 c.Assert(err, gc.IsNil) 310 311 agentConf := FakeAgentConfig{} 312 313 a := NewMachineAgentCmd( 314 ctx, 315 MachineAgentFactoryFn( 316 agentConf, nil, &mockLoopDeviceManager{}, 317 ), 318 agentConf, 319 agentConf, 320 ) 321 // little hack to set the data that Init expects to already be set 322 a.(*machineAgentCmd).machineId = "42" 323 324 err = a.Init(nil) 325 c.Assert(err, gc.IsNil) 326 327 l, ok := ctx.Stderr.(*lumberjack.Logger) 328 c.Assert(ok, jc.IsTrue) 329 c.Check(l.MaxAge, gc.Equals, 0) 330 c.Check(l.MaxBackups, gc.Equals, 2) 331 c.Check(l.Filename, gc.Equals, filepath.FromSlash("/var/log/juju/machine-42.log")) 332 c.Check(l.MaxSize, gc.Equals, 300) 333 } 334 335 func (s *MachineSuite) TestDontUseLumberjack(c *gc.C) { 336 ctx, err := cmd.DefaultContext() 337 c.Assert(err, gc.IsNil) 338 339 agentConf := FakeAgentConfig{} 340 341 a := NewMachineAgentCmd( 342 ctx, 343 MachineAgentFactoryFn( 344 agentConf, nil, 345 &mockLoopDeviceManager{}, 346 ), 347 agentConf, 348 agentConf, 349 ) 350 // little hack to set the data that Init expects to already be set 351 a.(*machineAgentCmd).machineId = "42" 352 353 // set the value that normally gets set by the flag parsing 354 a.(*machineAgentCmd).logToStdErr = true 355 356 err = a.Init(nil) 357 c.Assert(err, gc.IsNil) 358 359 _, ok := ctx.Stderr.(*lumberjack.Logger) 360 c.Assert(ok, jc.IsFalse) 361 } 362 363 func (s *MachineSuite) TestRunStop(c *gc.C) { 364 m, ac, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 365 a := s.newAgent(c, m) 366 done := make(chan error) 367 go func() { 368 done <- a.Run(nil) 369 }() 370 err := a.Stop() 371 c.Assert(err, jc.ErrorIsNil) 372 c.Assert(<-done, jc.ErrorIsNil) 373 c.Assert(charmrepo.CacheDir, gc.Equals, filepath.Join(ac.DataDir(), "charmcache")) 374 } 375 376 func (s *MachineSuite) TestWithDeadMachine(c *gc.C) { 377 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 378 err := m.EnsureDead() 379 c.Assert(err, jc.ErrorIsNil) 380 a := s.newAgent(c, m) 381 err = runWithTimeout(a) 382 c.Assert(err, jc.ErrorIsNil) 383 } 384 385 func (s *MachineSuite) TestWithRemovedMachine(c *gc.C) { 386 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 387 err := m.EnsureDead() 388 c.Assert(err, jc.ErrorIsNil) 389 err = m.Remove() 390 c.Assert(err, jc.ErrorIsNil) 391 a := s.newAgent(c, m) 392 err = runWithTimeout(a) 393 c.Assert(err, jc.ErrorIsNil) 394 } 395 396 func (s *MachineSuite) TestDyingMachine(c *gc.C) { 397 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 398 a := s.newAgent(c, m) 399 done := make(chan error) 400 go func() { 401 done <- a.Run(nil) 402 }() 403 defer func() { 404 c.Check(a.Stop(), jc.ErrorIsNil) 405 }() 406 // Wait for configuration to be finished 407 <-a.WorkersStarted() 408 err := m.Destroy() 409 c.Assert(err, jc.ErrorIsNil) 410 select { 411 case err := <-done: 412 c.Assert(err, jc.ErrorIsNil) 413 case <-time.After(watcher.Period * 5 / 4): 414 // TODO(rog) Fix this so it doesn't wait for so long. 415 // https://bugs.launchpad.net/juju-core/+bug/1163983 416 c.Fatalf("timed out waiting for agent to terminate") 417 } 418 err = m.Refresh() 419 c.Assert(err, jc.ErrorIsNil) 420 c.Assert(m.Life(), gc.Equals, state.Dead) 421 } 422 423 func (s *MachineSuite) TestHostUnits(c *gc.C) { 424 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 425 a := s.newAgent(c, m) 426 ctx, reset := patchDeployContext(c, s.BackingState) 427 defer reset() 428 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 429 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 430 431 // check that unassigned units don't trigger any deployments. 432 svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 433 u0, err := svc.AddUnit() 434 c.Assert(err, jc.ErrorIsNil) 435 u1, err := svc.AddUnit() 436 c.Assert(err, jc.ErrorIsNil) 437 438 ctx.waitDeployed(c) 439 440 // assign u0, check it's deployed. 441 err = u0.AssignToMachine(m) 442 c.Assert(err, jc.ErrorIsNil) 443 ctx.waitDeployed(c, u0.Name()) 444 445 // "start the agent" for u0 to prevent short-circuited remove-on-destroy; 446 // check that it's kept deployed despite being Dying. 447 err = u0.SetAgentStatus(state.StatusIdle, "", nil) 448 c.Assert(err, jc.ErrorIsNil) 449 err = u0.Destroy() 450 c.Assert(err, jc.ErrorIsNil) 451 ctx.waitDeployed(c, u0.Name()) 452 453 // add u1 to the machine, check it's deployed. 454 err = u1.AssignToMachine(m) 455 c.Assert(err, jc.ErrorIsNil) 456 ctx.waitDeployed(c, u0.Name(), u1.Name()) 457 458 // make u0 dead; check the deployer recalls the unit and removes it from 459 // state. 460 err = u0.EnsureDead() 461 c.Assert(err, jc.ErrorIsNil) 462 ctx.waitDeployed(c, u1.Name()) 463 464 // The deployer actually removes the unit just after 465 // removing its deployment, so we need to poll here 466 // until it actually happens. 467 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 468 err := u0.Refresh() 469 if err == nil && attempt.HasNext() { 470 continue 471 } 472 c.Assert(err, jc.Satisfies, errors.IsNotFound) 473 } 474 475 // short-circuit-remove u1 after it's been deployed; check it's recalled 476 // and removed from state. 477 err = u1.Destroy() 478 c.Assert(err, jc.ErrorIsNil) 479 err = u1.Refresh() 480 c.Assert(err, jc.Satisfies, errors.IsNotFound) 481 ctx.waitDeployed(c) 482 } 483 484 func patchDeployContext(c *gc.C, st *state.State) (*fakeContext, func()) { 485 ctx := &fakeContext{ 486 inited: make(chan struct{}), 487 deployed: make(set.Strings), 488 } 489 orig := newDeployContext 490 newDeployContext = func(dst *apideployer.State, agentConfig agent.Config) deployer.Context { 491 ctx.st = st 492 ctx.agentConfig = agentConfig 493 close(ctx.inited) 494 return ctx 495 } 496 return ctx, func() { newDeployContext = orig } 497 } 498 499 func (s *commonMachineSuite) setFakeMachineAddresses(c *gc.C, machine *state.Machine) { 500 addrs := network.NewAddresses("0.1.2.3") 501 err := machine.SetProviderAddresses(addrs...) 502 c.Assert(err, jc.ErrorIsNil) 503 // Set the addresses in the environ instance as well so that if the instance poller 504 // runs it won't overwrite them. 505 instId, err := machine.InstanceId() 506 c.Assert(err, jc.ErrorIsNil) 507 insts, err := s.Environ.Instances([]instance.Id{instId}) 508 c.Assert(err, jc.ErrorIsNil) 509 dummy.SetInstanceAddresses(insts[0], addrs) 510 } 511 512 func (s *MachineSuite) TestManageEnviron(c *gc.C) { 513 usefulVersion := version.Current 514 usefulVersion.Series = "quantal" // to match the charm created below 515 envtesting.AssertUploadFakeToolsVersions( 516 c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), usefulVersion) 517 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 518 op := make(chan dummy.Operation, 200) 519 dummy.Listen(op) 520 521 a := s.newAgent(c, m) 522 // Make sure the agent is stopped even if the test fails. 523 defer a.Stop() 524 done := make(chan error) 525 go func() { 526 done <- a.Run(nil) 527 }() 528 529 // See state server runners start 530 r0 := s.singularRecord.nextRunner(c) 531 r0.waitForWorker(c, "txnpruner") 532 533 r1 := s.singularRecord.nextRunner(c) 534 r1.waitForWorkers(c, perEnvSingularWorkers) 535 536 // Check that the provisioner and firewaller are alive by doing 537 // a rudimentary check that it responds to state changes. 538 539 // Add one unit to a service; it should get allocated a machine 540 // and then its ports should be opened. 541 charm := s.AddTestingCharm(c, "dummy") 542 svc := s.AddTestingService(c, "test-service", charm) 543 err := svc.SetExposed() 544 c.Assert(err, jc.ErrorIsNil) 545 units, err := juju.AddUnits(s.State, svc, 1, "") 546 c.Assert(err, jc.ErrorIsNil) 547 c.Check(opRecvTimeout(c, s.State, op, dummy.OpStartInstance{}), gc.NotNil) 548 549 // Wait for the instance id to show up in the state. 550 s.waitProvisioned(c, units[0]) 551 err = units[0].OpenPort("tcp", 999) 552 c.Assert(err, jc.ErrorIsNil) 553 554 c.Check(opRecvTimeout(c, s.State, op, dummy.OpOpenPorts{}), gc.NotNil) 555 556 // Check that the metrics workers have started by adding metrics 557 select { 558 case <-time.After(coretesting.LongWait): 559 c.Fatalf("timed out waiting for metric cleanup API to be called") 560 case <-s.metricAPI.CleanupCalled(): 561 } 562 select { 563 case <-time.After(coretesting.LongWait): 564 c.Fatalf("timed out waiting for metric sender API to be called") 565 case <-s.metricAPI.SendCalled(): 566 } 567 568 err = a.Stop() 569 c.Assert(err, jc.ErrorIsNil) 570 571 select { 572 case err := <-done: 573 c.Assert(err, jc.ErrorIsNil) 574 case <-time.After(5 * time.Second): 575 c.Fatalf("timed out waiting for agent to terminate") 576 } 577 } 578 579 func (s *MachineSuite) TestManageEnvironRunsResumer(c *gc.C) { 580 started := make(chan struct{}) 581 s.AgentSuite.PatchValue(&newResumer, func(st resumer.TransactionResumer) *resumer.Resumer { 582 close(started) 583 return resumer.NewResumer(st) 584 }) 585 586 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 587 a := s.newAgent(c, m) 588 defer a.Stop() 589 go func() { 590 c.Check(a.Run(nil), jc.ErrorIsNil) 591 }() 592 593 // Wait for the worker that starts before the resumer to start. 594 _ = s.singularRecord.nextRunner(c) 595 r := s.singularRecord.nextRunner(c) 596 r.waitForWorker(c, "charm-revision-updater") 597 598 // Now make sure the resumer starts. 599 select { 600 case <-started: 601 case <-time.After(coretesting.LongWait): 602 c.Fatalf("resumer worker not started as expected") 603 } 604 } 605 606 func (s *MachineSuite) TestManageEnvironStartsInstancePoller(c *gc.C) { 607 started := make(chan struct{}) 608 s.AgentSuite.PatchValue(&newInstancePoller, func(st *apiinstancepoller.API) worker.Worker { 609 close(started) 610 return instancepoller.NewWorker(st) 611 }) 612 613 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 614 a := s.newAgent(c, m) 615 defer a.Stop() 616 go func() { 617 c.Check(a.Run(nil), jc.ErrorIsNil) 618 }() 619 620 // Wait for the worker that starts before the instancepoller to 621 // start. 622 _ = s.singularRecord.nextRunner(c) 623 r := s.singularRecord.nextRunner(c) 624 r.waitForWorker(c, "charm-revision-updater") 625 626 // Now make sure the resumer starts. 627 select { 628 case <-started: 629 case <-time.After(coretesting.LongWait): 630 c.Fatalf("instancepoller worker not started as expected") 631 } 632 } 633 634 const startWorkerWait = 250 * time.Millisecond 635 636 func (s *MachineSuite) TestManageEnvironDoesNotRunFirewallerWhenModeIsNone(c *gc.C) { 637 s.PatchValue(&getFirewallMode, func(api.Connection) (string, error) { 638 return config.FwNone, nil 639 }) 640 started := make(chan struct{}) 641 s.AgentSuite.PatchValue(&newFirewaller, func(st *apifirewaller.State) (worker.Worker, error) { 642 close(started) 643 return newDummyWorker(), nil 644 }) 645 646 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 647 a := s.newAgent(c, m) 648 defer a.Stop() 649 go func() { 650 c.Check(a.Run(nil), jc.ErrorIsNil) 651 }() 652 653 // Wait for the worker that starts before the firewaller to start. 654 _ = s.singularRecord.nextRunner(c) 655 r := s.singularRecord.nextRunner(c) 656 r.waitForWorker(c, "charm-revision-updater") 657 658 // Now make sure the firewaller doesn't start. 659 select { 660 case <-started: 661 c.Fatalf("firewaller worker unexpectedly started") 662 case <-time.After(startWorkerWait): 663 } 664 } 665 666 func (s *MachineSuite) TestManageEnvironRunsInstancePoller(c *gc.C) { 667 s.AgentSuite.PatchValue(&instancepoller.ShortPoll, 500*time.Millisecond) 668 usefulVersion := version.Current 669 usefulVersion.Series = "quantal" // to match the charm created below 670 envtesting.AssertUploadFakeToolsVersions( 671 c, s.DefaultToolsStorage, 672 s.Environ.Config().AgentStream(), 673 s.Environ.Config().AgentStream(), 674 usefulVersion, 675 ) 676 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 677 a := s.newAgent(c, m) 678 defer a.Stop() 679 go func() { 680 c.Check(a.Run(nil), jc.ErrorIsNil) 681 }() 682 683 // Add one unit to a service; 684 charm := s.AddTestingCharm(c, "dummy") 685 svc := s.AddTestingService(c, "test-service", charm) 686 units, err := juju.AddUnits(s.State, svc, 1, "") 687 c.Assert(err, jc.ErrorIsNil) 688 689 m, instId := s.waitProvisioned(c, units[0]) 690 insts, err := s.Environ.Instances([]instance.Id{instId}) 691 c.Assert(err, jc.ErrorIsNil) 692 addrs := network.NewAddresses("1.2.3.4") 693 dummy.SetInstanceAddresses(insts[0], addrs) 694 dummy.SetInstanceStatus(insts[0], "running") 695 696 for a := coretesting.LongAttempt.Start(); a.Next(); { 697 if !a.HasNext() { 698 c.Logf("final machine addresses: %#v", m.Addresses()) 699 c.Fatalf("timed out waiting for machine to get address") 700 } 701 err := m.Refresh() 702 c.Assert(err, jc.ErrorIsNil) 703 instStatus, err := m.InstanceStatus() 704 c.Assert(err, jc.ErrorIsNil) 705 if reflect.DeepEqual(m.Addresses(), addrs) && instStatus == "running" { 706 break 707 } 708 } 709 } 710 711 func (s *MachineSuite) TestManageEnvironRunsPeergrouper(c *gc.C) { 712 started := make(chan struct{}, 1) 713 s.AgentSuite.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { 714 c.Check(st, gc.NotNil) 715 select { 716 case started <- struct{}{}: 717 default: 718 } 719 return newDummyWorker(), nil 720 }) 721 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 722 a := s.newAgent(c, m) 723 defer a.Stop() 724 go func() { 725 c.Check(a.Run(nil), jc.ErrorIsNil) 726 }() 727 select { 728 case <-started: 729 case <-time.After(coretesting.LongWait): 730 c.Fatalf("timed out waiting for peergrouper worker to be started") 731 } 732 } 733 734 func (s *MachineSuite) testAddresserNewWorkerResult(c *gc.C, expectFinished bool) { 735 // TODO(dimitern): Fix this in a follow-up. 736 c.Skip("Test temporarily disabled as flaky - see bug lp:1488576") 737 738 started := make(chan struct{}) 739 s.PatchValue(&newAddresser, func(api *apiaddresser.API) (worker.Worker, error) { 740 close(started) 741 w, err := addresser.NewWorker(api) 742 c.Check(err, jc.ErrorIsNil) 743 if expectFinished { 744 // When the address-allocation feature flag is disabled. 745 c.Check(w, gc.FitsTypeOf, worker.FinishedWorker{}) 746 } else { 747 // When the address-allocation feature flag is enabled. 748 c.Check(w, gc.Not(gc.FitsTypeOf), worker.FinishedWorker{}) 749 } 750 return w, err 751 }) 752 753 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 754 a := s.newAgent(c, m) 755 defer a.Stop() 756 go func() { 757 c.Check(a.Run(nil), jc.ErrorIsNil) 758 }() 759 760 // Wait for the worker that starts before the addresser to start. 761 _ = s.singularRecord.nextRunner(c) 762 r := s.singularRecord.nextRunner(c) 763 r.waitForWorker(c, "cleaner") 764 765 select { 766 case <-started: 767 case <-time.After(coretesting.LongWait): 768 c.Fatalf("timed out waiting for addresser to start") 769 } 770 } 771 772 func (s *MachineSuite) TestAddresserWorkerDoesNotStopWhenAddressDeallocationSupported(c *gc.C) { 773 s.SetFeatureFlags(feature.AddressAllocation) 774 s.testAddresserNewWorkerResult(c, false) 775 } 776 777 func (s *MachineSuite) TestAddresserWorkerStopsWhenAddressDeallocationNotSupported(c *gc.C) { 778 s.SetFeatureFlags() 779 s.testAddresserNewWorkerResult(c, true) 780 } 781 782 func (s *MachineSuite) TestManageEnvironRunsDbLogPrunerIfFeatureFlagEnabled(c *gc.C) { 783 s.SetFeatureFlags("db-log") 784 785 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 786 a := s.newAgent(c, m) 787 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 788 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 789 790 runner := s.singularRecord.nextRunner(c) 791 runner.waitForWorker(c, "dblogpruner") 792 } 793 794 func (s *MachineSuite) TestManageEnvironDoesntRunDbLogPrunerByDefault(c *gc.C) { 795 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 796 a := s.newAgent(c, m) 797 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 798 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 799 800 // Wait for the txnpruner to be started. This is started just after 801 // dblogpruner would be started. 802 runner := s.singularRecord.nextRunner(c) 803 started := set.NewStrings(runner.waitForWorker(c, "txnpruner")...) 804 c.Assert(started.Contains("dblogpruner"), jc.IsFalse) 805 } 806 807 func (s *MachineSuite) TestManageEnvironRunsStatusHistoryPruner(c *gc.C) { 808 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 809 a := s.newAgent(c, m) 810 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 811 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 812 813 runner := s.singularRecord.nextRunner(c) 814 runner.waitForWorker(c, "statushistorypruner") 815 } 816 817 func (s *MachineSuite) TestManageEnvironCallsUseMultipleCPUs(c *gc.C) { 818 // If it has been enabled, the JobManageEnviron agent should call utils.UseMultipleCPUs 819 usefulVersion := version.Current 820 usefulVersion.Series = "quantal" 821 envtesting.AssertUploadFakeToolsVersions( 822 c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), usefulVersion) 823 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 824 calledChan := make(chan struct{}, 1) 825 s.AgentSuite.PatchValue(&useMultipleCPUs, func() { calledChan <- struct{}{} }) 826 // Now, start the agent, and observe that a JobManageEnviron agent 827 // calls UseMultipleCPUs 828 a := s.newAgent(c, m) 829 defer a.Stop() 830 go func() { 831 c.Check(a.Run(nil), jc.ErrorIsNil) 832 }() 833 // Wait for configuration to be finished 834 <-a.WorkersStarted() 835 select { 836 case <-calledChan: 837 case <-time.After(coretesting.LongWait): 838 c.Errorf("we failed to call UseMultipleCPUs()") 839 } 840 c.Check(a.Stop(), jc.ErrorIsNil) 841 // However, an agent that just JobHostUnits doesn't call UseMultipleCPUs 842 m2, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 843 a2 := s.newAgent(c, m2) 844 defer a2.Stop() 845 go func() { 846 c.Check(a2.Run(nil), jc.ErrorIsNil) 847 }() 848 // Wait until all the workers have been started, and then kill everything 849 <-a2.workersStarted 850 c.Check(a2.Stop(), jc.ErrorIsNil) 851 select { 852 case <-calledChan: 853 c.Errorf("we should not have called UseMultipleCPUs()") 854 case <-time.After(coretesting.ShortWait): 855 } 856 } 857 858 func (s *MachineSuite) waitProvisioned(c *gc.C, unit *state.Unit) (*state.Machine, instance.Id) { 859 c.Logf("waiting for unit %q to be provisioned", unit) 860 machineId, err := unit.AssignedMachineId() 861 c.Assert(err, jc.ErrorIsNil) 862 m, err := s.State.Machine(machineId) 863 c.Assert(err, jc.ErrorIsNil) 864 w := m.Watch() 865 defer w.Stop() 866 timeout := time.After(coretesting.LongWait) 867 for { 868 select { 869 case <-timeout: 870 c.Fatalf("timed out waiting for provisioning") 871 case _, ok := <-w.Changes(): 872 c.Assert(ok, jc.IsTrue) 873 err := m.Refresh() 874 c.Assert(err, jc.ErrorIsNil) 875 if instId, err := m.InstanceId(); err == nil { 876 c.Logf("unit provisioned with instance %s", instId) 877 return m, instId 878 } else { 879 c.Check(err, jc.Satisfies, errors.IsNotProvisioned) 880 } 881 } 882 } 883 } 884 885 func (s *MachineSuite) testUpgradeRequest(c *gc.C, agent runner, tag string, currentTools *tools.Tools) { 886 newVers := version.Current 887 newVers.Patch++ 888 newTools := envtesting.AssertUploadFakeToolsVersions( 889 c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), newVers)[0] 890 err := s.State.SetEnvironAgentVersion(newVers.Number) 891 c.Assert(err, jc.ErrorIsNil) 892 err = runWithTimeout(agent) 893 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 894 AgentName: tag, 895 OldTools: currentTools.Version, 896 NewTools: newTools.Version, 897 DataDir: s.DataDir(), 898 }) 899 } 900 901 func (s *MachineSuite) TestUpgradeRequest(c *gc.C) { 902 m, _, currentTools := s.primeAgent(c, version.Current, state.JobManageEnviron, state.JobHostUnits) 903 a := s.newAgent(c, m) 904 s.testUpgradeRequest(c, a, m.Tag().String(), currentTools) 905 c.Assert(a.isAgentUpgradePending(), jc.IsTrue) 906 } 907 908 func (s *MachineSuite) TestNoUpgradeRequired(c *gc.C) { 909 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron, state.JobHostUnits) 910 a := s.newAgent(c, m) 911 done := make(chan error) 912 go func() { done <- a.Run(nil) }() 913 select { 914 case <-a.initialAgentUpgradeCheckComplete: 915 case <-time.After(coretesting.LongWait): 916 c.Fatalf("timeout waiting for upgrade check") 917 } 918 defer a.Stop() // in case of failure 919 s.waitStopped(c, state.JobManageEnviron, a, done) 920 c.Assert(a.isAgentUpgradePending(), jc.IsFalse) 921 } 922 923 var fastDialOpts = api.DialOpts{ 924 Timeout: coretesting.LongWait, 925 RetryDelay: coretesting.ShortWait, 926 } 927 928 func (s *MachineSuite) waitStopped(c *gc.C, job state.MachineJob, a *MachineAgent, done chan error) { 929 err := a.Stop() 930 if job == state.JobManageEnviron { 931 // When shutting down, the API server can be shut down before 932 // the other workers that connect to it, so they get an error so 933 // they then die, causing Stop to return an error. It's not 934 // easy to control the actual error that's received in this 935 // circumstance so we just log it rather than asserting that it 936 // is not nil. 937 if err != nil { 938 c.Logf("error shutting down state manager: %v", err) 939 } 940 } else { 941 c.Assert(err, jc.ErrorIsNil) 942 } 943 944 select { 945 case err := <-done: 946 c.Assert(err, jc.ErrorIsNil) 947 case <-time.After(5 * time.Second): 948 c.Fatalf("timed out waiting for agent to terminate") 949 } 950 } 951 952 func (s *MachineSuite) assertJobWithAPI( 953 c *gc.C, 954 job state.MachineJob, 955 test func(agent.Config, api.Connection), 956 ) { 957 s.assertAgentOpensState(c, &reportOpenedAPI, job, func(cfg agent.Config, st interface{}) { 958 test(cfg, st.(api.Connection)) 959 }) 960 } 961 962 func (s *MachineSuite) assertJobWithState( 963 c *gc.C, 964 job state.MachineJob, 965 test func(agent.Config, *state.State), 966 ) { 967 paramsJob := job.ToParams() 968 if !paramsJob.NeedsState() { 969 c.Fatalf("%v does not use state", paramsJob) 970 } 971 s.assertAgentOpensState(c, &reportOpenedState, job, func(cfg agent.Config, st interface{}) { 972 test(cfg, st.(*state.State)) 973 }) 974 } 975 976 // assertAgentOpensState asserts that a machine agent started with the 977 // given job will call the function pointed to by reportOpened. The 978 // agent's configuration and the value passed to reportOpened are then 979 // passed to the test function for further checking. 980 func (s *MachineSuite) assertAgentOpensState( 981 c *gc.C, 982 reportOpened *func(io.Closer), 983 job state.MachineJob, 984 test func(agent.Config, interface{}), 985 ) { 986 stm, conf, _ := s.primeAgent(c, version.Current, job) 987 a := s.newAgent(c, stm) 988 defer a.Stop() 989 logger.Debugf("new agent %#v", a) 990 991 // All state jobs currently also run an APIWorker, so no 992 // need to check for that here, like in assertJobWithState. 993 994 agentAPIs := make(chan io.Closer, 1) 995 s.AgentSuite.PatchValue(reportOpened, func(st io.Closer) { 996 select { 997 case agentAPIs <- st: 998 default: 999 } 1000 }) 1001 1002 done := make(chan error) 1003 go func() { 1004 done <- a.Run(nil) 1005 }() 1006 1007 select { 1008 case agentAPI := <-agentAPIs: 1009 c.Assert(agentAPI, gc.NotNil) 1010 test(conf, agentAPI) 1011 case <-time.After(coretesting.LongWait): 1012 c.Fatalf("API not opened") 1013 } 1014 1015 s.waitStopped(c, job, a, done) 1016 } 1017 1018 func (s *MachineSuite) TestManageEnvironServesAPI(c *gc.C) { 1019 s.assertJobWithState(c, state.JobManageEnviron, func(conf agent.Config, agentState *state.State) { 1020 st, err := api.Open(conf.APIInfo(), fastDialOpts) 1021 c.Assert(err, jc.ErrorIsNil) 1022 defer st.Close() 1023 m, err := st.Machiner().Machine(conf.Tag().(names.MachineTag)) 1024 c.Assert(err, jc.ErrorIsNil) 1025 c.Assert(m.Life(), gc.Equals, params.Alive) 1026 }) 1027 } 1028 1029 func (s *MachineSuite) assertAgentSetsToolsVersion(c *gc.C, job state.MachineJob) { 1030 vers := version.Current 1031 vers.Minor = version.Current.Minor + 1 1032 m, _, _ := s.primeAgent(c, vers, job) 1033 a := s.newAgent(c, m) 1034 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1035 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1036 1037 timeout := time.After(coretesting.LongWait) 1038 for done := false; !done; { 1039 select { 1040 case <-timeout: 1041 c.Fatalf("timeout while waiting for agent version to be set") 1042 case <-time.After(coretesting.ShortWait): 1043 c.Log("Refreshing") 1044 err := m.Refresh() 1045 c.Assert(err, jc.ErrorIsNil) 1046 c.Log("Fetching agent tools") 1047 agentTools, err := m.AgentTools() 1048 c.Assert(err, jc.ErrorIsNil) 1049 c.Logf("(%v vs. %v)", agentTools.Version, version.Current) 1050 if agentTools.Version.Minor != version.Current.Minor { 1051 continue 1052 } 1053 c.Assert(agentTools.Version, gc.DeepEquals, version.Current) 1054 done = true 1055 } 1056 } 1057 } 1058 1059 func (s *MachineSuite) TestAgentSetsToolsVersionManageEnviron(c *gc.C) { 1060 s.assertAgentSetsToolsVersion(c, state.JobManageEnviron) 1061 } 1062 1063 func (s *MachineSuite) TestAgentSetsToolsVersionHostUnits(c *gc.C) { 1064 s.assertAgentSetsToolsVersion(c, state.JobHostUnits) 1065 } 1066 1067 func (s *MachineSuite) TestManageEnvironRunsCleaner(c *gc.C) { 1068 s.assertJobWithState(c, state.JobManageEnviron, func(conf agent.Config, agentState *state.State) { 1069 // Create a service and unit, and destroy the service. 1070 service := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 1071 unit, err := service.AddUnit() 1072 c.Assert(err, jc.ErrorIsNil) 1073 err = service.Destroy() 1074 c.Assert(err, jc.ErrorIsNil) 1075 1076 // Check the unit was not yet removed. 1077 err = unit.Refresh() 1078 c.Assert(err, jc.ErrorIsNil) 1079 w := unit.Watch() 1080 defer w.Stop() 1081 1082 // Trigger a sync on the state used by the agent, and wait 1083 // for the unit to be removed. 1084 agentState.StartSync() 1085 timeout := time.After(coretesting.LongWait) 1086 for done := false; !done; { 1087 select { 1088 case <-timeout: 1089 c.Fatalf("unit not cleaned up") 1090 case <-time.After(coretesting.ShortWait): 1091 s.State.StartSync() 1092 case <-w.Changes(): 1093 err := unit.Refresh() 1094 if errors.IsNotFound(err) { 1095 done = true 1096 } else { 1097 c.Assert(err, jc.ErrorIsNil) 1098 } 1099 } 1100 } 1101 }) 1102 } 1103 1104 func (s *MachineSuite) TestJobManageEnvironRunsMinUnitsWorker(c *gc.C) { 1105 s.assertJobWithState(c, state.JobManageEnviron, func(conf agent.Config, agentState *state.State) { 1106 // Ensure that the MinUnits worker is alive by doing a simple check 1107 // that it responds to state changes: add a service, set its minimum 1108 // number of units to one, wait for the worker to add the missing unit. 1109 service := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 1110 err := service.SetMinUnits(1) 1111 c.Assert(err, jc.ErrorIsNil) 1112 w := service.Watch() 1113 defer w.Stop() 1114 1115 // Trigger a sync on the state used by the agent, and wait for the unit 1116 // to be created. 1117 agentState.StartSync() 1118 timeout := time.After(coretesting.LongWait) 1119 for { 1120 select { 1121 case <-timeout: 1122 c.Fatalf("unit not created") 1123 case <-time.After(coretesting.ShortWait): 1124 s.State.StartSync() 1125 case <-w.Changes(): 1126 units, err := service.AllUnits() 1127 c.Assert(err, jc.ErrorIsNil) 1128 if len(units) == 1 { 1129 return 1130 } 1131 } 1132 } 1133 }) 1134 } 1135 1136 func (s *MachineSuite) TestMachineAgentRunsAuthorisedKeysWorker(c *gc.C) { 1137 //TODO(bogdanteleaga): Fix once we get authentication worker up on windows 1138 if runtime.GOOS == "windows" { 1139 c.Skip("bug 1403084: authentication worker not yet implemented on windows") 1140 } 1141 // Start the machine agent. 1142 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1143 a := s.newAgent(c, m) 1144 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1145 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1146 1147 // Update the keys in the environment. 1148 sshKey := sshtesting.ValidKeyOne.Key + " user@host" 1149 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": sshKey}, nil, nil) 1150 c.Assert(err, jc.ErrorIsNil) 1151 1152 // Wait for ssh keys file to be updated. 1153 s.State.StartSync() 1154 timeout := time.After(coretesting.LongWait) 1155 sshKeyWithCommentPrefix := sshtesting.ValidKeyOne.Key + " Juju:user@host" 1156 for { 1157 select { 1158 case <-timeout: 1159 c.Fatalf("timeout while waiting for authorised ssh keys to change") 1160 case <-time.After(coretesting.ShortWait): 1161 keys, err := ssh.ListKeys(authenticationworker.SSHUser, ssh.FullKeys) 1162 c.Assert(err, jc.ErrorIsNil) 1163 keysStr := strings.Join(keys, "\n") 1164 if sshKeyWithCommentPrefix != keysStr { 1165 continue 1166 } 1167 return 1168 } 1169 } 1170 } 1171 1172 // opRecvTimeout waits for any of the given kinds of operation to 1173 // be received from ops, and times out if not. 1174 func opRecvTimeout(c *gc.C, st *state.State, opc <-chan dummy.Operation, kinds ...dummy.Operation) dummy.Operation { 1175 st.StartSync() 1176 for { 1177 select { 1178 case op := <-opc: 1179 for _, k := range kinds { 1180 if reflect.TypeOf(op) == reflect.TypeOf(k) { 1181 return op 1182 } 1183 } 1184 c.Logf("discarding unknown event %#v", op) 1185 case <-time.After(15 * time.Second): 1186 c.Fatalf("time out wating for operation") 1187 } 1188 } 1189 } 1190 1191 func (s *MachineSuite) TestOpenStateFailsForJobHostUnits(c *gc.C) { 1192 s.assertJobWithAPI(c, state.JobHostUnits, func(conf agent.Config, st api.Connection) { 1193 s.AssertCannotOpenState(c, conf.Tag(), conf.DataDir()) 1194 }) 1195 } 1196 1197 func (s *MachineSuite) TestOpenStateFailsForJobManageNetworking(c *gc.C) { 1198 s.assertJobWithAPI(c, state.JobManageNetworking, func(conf agent.Config, st api.Connection) { 1199 s.AssertCannotOpenState(c, conf.Tag(), conf.DataDir()) 1200 }) 1201 } 1202 1203 func (s *MachineSuite) TestOpenStateWorksForJobManageEnviron(c *gc.C) { 1204 s.assertJobWithAPI(c, state.JobManageEnviron, func(conf agent.Config, st api.Connection) { 1205 s.AssertCanOpenState(c, conf.Tag(), conf.DataDir()) 1206 }) 1207 } 1208 1209 func (s *MachineSuite) TestOpenAPIStateWorksForJobHostUnits(c *gc.C) { 1210 machine, conf, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1211 s.runOpenAPISTateTest(c, machine, conf) 1212 } 1213 1214 func (s *MachineSuite) TestOpenAPIStateWorksForJobManageNetworking(c *gc.C) { 1215 machine, conf, _ := s.primeAgent(c, version.Current, state.JobManageNetworking) 1216 s.runOpenAPISTateTest(c, machine, conf) 1217 } 1218 1219 func (s *MachineSuite) TestOpenAPIStateWorksForJobManageEnviron(c *gc.C) { 1220 machine, conf, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1221 s.runOpenAPISTateTest(c, machine, conf) 1222 } 1223 1224 func (s *MachineSuite) runOpenAPISTateTest(c *gc.C, machine *state.Machine, conf agent.Config) { 1225 configPath := agent.ConfigPath(conf.DataDir(), conf.Tag()) 1226 1227 // Set a failing password... 1228 confW, err := agent.ReadConfig(configPath) 1229 c.Assert(err, jc.ErrorIsNil) 1230 confW.SetPassword("not-set-on-state-server") 1231 1232 // ...and also make sure the api info points to the testing api 1233 // server (and not, as for JobManageEnviron machines, to the port 1234 // chosen for the agent's own API server to run on. This is usually 1235 // sane, but inconvenient here because we're not running the full 1236 // agent and so the configured API server is not actually there). 1237 apiInfo := s.APIInfo(c) 1238 hostPorts, err := network.ParseHostPorts(apiInfo.Addrs...) 1239 c.Assert(err, jc.ErrorIsNil) 1240 confW.SetAPIHostPorts([][]network.HostPort{hostPorts}) 1241 err = confW.Write() 1242 c.Assert(err, jc.ErrorIsNil) 1243 1244 // Check that it successfully connects with the conf's old password. 1245 assertOpen := func() { 1246 tagString := conf.Tag().String() 1247 agent := NewAgentConf(conf.DataDir()) 1248 err := agent.ReadConfig(tagString) 1249 c.Assert(err, jc.ErrorIsNil) 1250 st, gotEntity, err := apicaller.OpenAPIState(agent) 1251 c.Assert(err, jc.ErrorIsNil) 1252 c.Assert(st, gc.NotNil) 1253 st.Close() 1254 c.Assert(gotEntity.Tag(), gc.Equals, tagString) 1255 } 1256 assertOpen() 1257 1258 // Check that the initial password is no longer valid. 1259 assertPassword := func(password string, valid bool) { 1260 err := machine.Refresh() 1261 c.Assert(err, jc.ErrorIsNil) 1262 c.Check(machine.PasswordValid(password), gc.Equals, valid) 1263 } 1264 assertPassword(initialMachinePassword, false) 1265 1266 // Read the configuration and check that we can connect with it. 1267 confR, err := agent.ReadConfig(configPath) 1268 c.Assert(err, gc.IsNil) 1269 newPassword := confR.APIInfo().Password 1270 assertPassword(newPassword, true) 1271 1272 // Double-check that we can open a fresh connection with the stored 1273 // conf ... and that the password hasn't been changed again. 1274 assertOpen() 1275 assertPassword(newPassword, true) 1276 } 1277 1278 func (s *MachineSuite) TestMachineAgentSymlinkJujuRun(c *gc.C) { 1279 _, err := os.Stat(JujuRun) 1280 c.Assert(err, jc.Satisfies, os.IsNotExist) 1281 s.assertJobWithAPI(c, state.JobManageEnviron, func(conf agent.Config, st api.Connection) { 1282 // juju-run should have been created 1283 _, err := os.Stat(JujuRun) 1284 c.Assert(err, jc.ErrorIsNil) 1285 }) 1286 } 1287 1288 func (s *MachineSuite) TestMachineAgentSymlinkJujuRunExists(c *gc.C) { 1289 if runtime.GOOS == "windows" { 1290 // Cannot make symlink to nonexistent file on windows or 1291 // create a file point a symlink to it then remove it 1292 c.Skip("Cannot test this on windows") 1293 } 1294 err := symlink.New("/nowhere/special", JujuRun) 1295 c.Assert(err, jc.ErrorIsNil) 1296 _, err = os.Stat(JujuRun) 1297 c.Assert(err, jc.Satisfies, os.IsNotExist) 1298 s.assertJobWithAPI(c, state.JobManageEnviron, func(conf agent.Config, st api.Connection) { 1299 // juju-run should have been recreated 1300 _, err := os.Stat(JujuRun) 1301 c.Assert(err, jc.ErrorIsNil) 1302 link, err := symlink.Read(JujuRun) 1303 c.Assert(err, jc.ErrorIsNil) 1304 c.Assert(link, gc.Not(gc.Equals), "/nowhere/special") 1305 }) 1306 } 1307 1308 func (s *MachineSuite) TestProxyUpdater(c *gc.C) { 1309 s.assertProxyUpdater(c, true) 1310 s.assertProxyUpdater(c, false) 1311 } 1312 1313 func (s *MachineSuite) assertProxyUpdater(c *gc.C, expectWriteSystemFiles bool) { 1314 // Patch out the func that decides whether we should write system files. 1315 var gotConf agent.Config 1316 s.AgentSuite.PatchValue(&shouldWriteProxyFiles, func(conf agent.Config) bool { 1317 gotConf = conf 1318 return expectWriteSystemFiles 1319 }) 1320 1321 // Make sure there are some proxy settings to write. 1322 expectSettings := proxy.Settings{ 1323 Http: "http proxy", 1324 Https: "https proxy", 1325 Ftp: "ftp proxy", 1326 } 1327 updateAttrs := config.ProxyConfigMap(expectSettings) 1328 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 1329 c.Assert(err, jc.ErrorIsNil) 1330 1331 // Patch out the actual worker func. 1332 started := make(chan struct{}) 1333 mockNew := func(api *apienvironment.Facade, writeSystemFiles bool) worker.Worker { 1334 // Direct check of the behaviour flag. 1335 c.Check(writeSystemFiles, gc.Equals, expectWriteSystemFiles) 1336 // Indirect check that we get a functional API. 1337 conf, err := api.EnvironConfig() 1338 if c.Check(err, jc.ErrorIsNil) { 1339 actualSettings := conf.ProxySettings() 1340 c.Check(actualSettings, jc.DeepEquals, expectSettings) 1341 } 1342 return worker.NewSimpleWorker(func(_ <-chan struct{}) error { 1343 close(started) 1344 return nil 1345 }) 1346 } 1347 s.AgentSuite.PatchValue(&proxyupdater.New, mockNew) 1348 1349 s.primeAgent(c, version.Current, state.JobHostUnits) 1350 s.assertJobWithAPI(c, state.JobHostUnits, func(conf agent.Config, st api.Connection) { 1351 for { 1352 select { 1353 case <-time.After(coretesting.LongWait): 1354 c.Fatalf("timeout while waiting for proxy updater to start") 1355 case <-started: 1356 c.Assert(gotConf, jc.DeepEquals, conf) 1357 return 1358 } 1359 } 1360 }) 1361 } 1362 1363 func (s *MachineSuite) TestMachineAgentUninstall(c *gc.C) { 1364 m, ac, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1365 err := m.EnsureDead() 1366 c.Assert(err, jc.ErrorIsNil) 1367 a := s.newAgent(c, m) 1368 err = runWithTimeout(a) 1369 c.Assert(err, jc.ErrorIsNil) 1370 // juju-run should have been removed on termination 1371 _, err = os.Stat(JujuRun) 1372 c.Assert(err, jc.Satisfies, os.IsNotExist) 1373 // data-dir should have been removed on termination 1374 _, err = os.Stat(ac.DataDir()) 1375 c.Assert(err, jc.Satisfies, os.IsNotExist) 1376 } 1377 1378 func (s *MachineSuite) TestMachineAgentRsyslogManageEnviron(c *gc.C) { 1379 s.testMachineAgentRsyslogConfigWorker(c, state.JobManageEnviron, rsyslog.RsyslogModeAccumulate) 1380 } 1381 1382 func (s *MachineSuite) TestMachineAgentRsyslogHostUnits(c *gc.C) { 1383 s.testMachineAgentRsyslogConfigWorker(c, state.JobHostUnits, rsyslog.RsyslogModeForwarding) 1384 } 1385 1386 func (s *MachineSuite) testMachineAgentRsyslogConfigWorker(c *gc.C, job state.MachineJob, expectedMode rsyslog.RsyslogMode) { 1387 created := make(chan rsyslog.RsyslogMode, 1) 1388 s.AgentSuite.PatchValue(&cmdutil.NewRsyslogConfigWorker, func(_ *apirsyslog.State, _ agent.Config, mode rsyslog.RsyslogMode) (worker.Worker, error) { 1389 created <- mode 1390 return newDummyWorker(), nil 1391 }) 1392 s.assertJobWithAPI(c, job, func(conf agent.Config, st api.Connection) { 1393 select { 1394 case <-time.After(coretesting.LongWait): 1395 c.Fatalf("timeout while waiting for rsyslog worker to be created") 1396 case mode := <-created: 1397 c.Assert(mode, gc.Equals, expectedMode) 1398 } 1399 }) 1400 } 1401 1402 func (s *MachineSuite) TestMachineAgentRunsAPIAddressUpdaterWorker(c *gc.C) { 1403 // Start the machine agent. 1404 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1405 a := s.newAgent(c, m) 1406 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1407 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1408 1409 // Update the API addresses. 1410 updatedServers := [][]network.HostPort{ 1411 network.NewHostPorts(1234, "localhost"), 1412 } 1413 err := s.BackingState.SetAPIHostPorts(updatedServers) 1414 c.Assert(err, jc.ErrorIsNil) 1415 1416 // Wait for config to be updated. 1417 s.BackingState.StartSync() 1418 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 1419 addrs, err := a.CurrentConfig().APIAddresses() 1420 c.Assert(err, jc.ErrorIsNil) 1421 if reflect.DeepEqual(addrs, []string{"localhost:1234"}) { 1422 return 1423 } 1424 } 1425 c.Fatalf("timeout while waiting for agent config to change") 1426 } 1427 1428 func (s *MachineSuite) TestMachineAgentRunsDiskManagerWorker(c *gc.C) { 1429 // Patch out the worker func before starting the agent. 1430 started := make(chan struct{}) 1431 newWorker := func(diskmanager.ListBlockDevicesFunc, diskmanager.BlockDeviceSetter) worker.Worker { 1432 close(started) 1433 return worker.NewNoOpWorker() 1434 } 1435 s.PatchValue(&newDiskManager, newWorker) 1436 1437 // Start the machine agent. 1438 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1439 a := s.newAgent(c, m) 1440 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1441 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1442 1443 // Wait for worker to be started. 1444 select { 1445 case <-started: 1446 case <-time.After(coretesting.LongWait): 1447 c.Fatalf("timeout while waiting for diskmanager worker to start") 1448 } 1449 } 1450 1451 func (s *MachineSuite) TestDiskManagerWorkerUpdatesState(c *gc.C) { 1452 expected := []storage.BlockDevice{{DeviceName: "whatever"}} 1453 s.PatchValue(&diskmanager.DefaultListBlockDevices, func() ([]storage.BlockDevice, error) { 1454 return expected, nil 1455 }) 1456 1457 // Start the machine agent. 1458 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1459 a := s.newAgent(c, m) 1460 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1461 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1462 1463 // Wait for state to be updated. 1464 s.BackingState.StartSync() 1465 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 1466 devices, err := s.BackingState.BlockDevices(m.MachineTag()) 1467 c.Assert(err, jc.ErrorIsNil) 1468 if len(devices) > 0 { 1469 c.Assert(devices, gc.HasLen, 1) 1470 c.Assert(devices[0].DeviceName, gc.Equals, expected[0].DeviceName) 1471 return 1472 } 1473 } 1474 c.Fatalf("timeout while waiting for block devices to be recorded") 1475 } 1476 1477 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForHostUnits(c *gc.C) { 1478 s.checkMetadataWorkerNotRun(c, state.JobHostUnits, "can host units") 1479 } 1480 1481 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForManageNetworking(c *gc.C) { 1482 s.checkMetadataWorkerNotRun(c, state.JobManageNetworking, "can manage networking") 1483 } 1484 1485 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForManageStateDeprecated(c *gc.C) { 1486 s.checkMetadataWorkerNotRun(c, state.JobManageStateDeprecated, "can manage state (deprecated)") 1487 } 1488 1489 func (s *MachineSuite) checkMetadataWorkerNotRun(c *gc.C, job state.MachineJob, suffix string) { 1490 // Patch out the worker func before starting the agent. 1491 started := make(chan struct{}) 1492 newWorker := func(cl *imagemetadata.Client) worker.Worker { 1493 close(started) 1494 return worker.NewNoOpWorker() 1495 } 1496 s.PatchValue(&newMetadataUpdater, newWorker) 1497 1498 // Start the machine agent. 1499 m, _, _ := s.primeAgent(c, version.Current, job) 1500 a := s.newAgent(c, m) 1501 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1502 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1503 1504 // Wait for worker to be started. 1505 select { 1506 case <-started: 1507 c.Fatalf("metadata update worker unexpectedly started for non-state server machine that %v", suffix) 1508 case <-time.After(coretesting.ShortWait): 1509 } 1510 } 1511 1512 func (s *MachineSuite) TestMachineAgentRunsMetadataWorker(c *gc.C) { 1513 // Patch out the worker func before starting the agent. 1514 started := make(chan struct{}) 1515 newWorker := func(cl *imagemetadata.Client) worker.Worker { 1516 close(started) 1517 return worker.NewNoOpWorker() 1518 } 1519 s.PatchValue(&newMetadataUpdater, newWorker) 1520 1521 // Start the machine agent. 1522 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1523 a := s.newAgent(c, m) 1524 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1525 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1526 1527 // Wait for worker to be started. 1528 select { 1529 case <-started: 1530 case <-time.After(coretesting.LongWait): 1531 c.Fatalf("timeout while waiting for metadata update worker to start") 1532 } 1533 } 1534 1535 func (s *MachineSuite) TestMachineAgentRunsMachineStorageWorker(c *gc.C) { 1536 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1537 1538 started := make(chan struct{}) 1539 newWorker := func( 1540 scope names.Tag, 1541 storageDir string, 1542 _ storageprovisioner.VolumeAccessor, 1543 _ storageprovisioner.FilesystemAccessor, 1544 _ storageprovisioner.LifecycleManager, 1545 _ storageprovisioner.EnvironAccessor, 1546 _ storageprovisioner.MachineAccessor, 1547 _ storageprovisioner.StatusSetter, 1548 _ clock.Clock, 1549 ) worker.Worker { 1550 c.Check(scope, gc.Equals, m.Tag()) 1551 // storageDir is not empty for machine scoped storage provisioners 1552 c.Assert(storageDir, gc.Not(gc.Equals), "") 1553 close(started) 1554 return worker.NewNoOpWorker() 1555 } 1556 s.PatchValue(&newStorageWorker, newWorker) 1557 1558 // Start the machine agent. 1559 a := s.newAgent(c, m) 1560 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1561 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1562 1563 // Wait for worker to be started. 1564 select { 1565 case <-started: 1566 case <-time.After(coretesting.LongWait): 1567 c.Fatalf("timeout while waiting for storage worker to start") 1568 } 1569 } 1570 1571 func (s *MachineSuite) TestMachineAgentRunsEnvironStorageWorker(c *gc.C) { 1572 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1573 1574 var numWorkers, machineWorkers, environWorkers uint32 1575 started := make(chan struct{}) 1576 newWorker := func( 1577 scope names.Tag, 1578 storageDir string, 1579 _ storageprovisioner.VolumeAccessor, 1580 _ storageprovisioner.FilesystemAccessor, 1581 _ storageprovisioner.LifecycleManager, 1582 _ storageprovisioner.EnvironAccessor, 1583 _ storageprovisioner.MachineAccessor, 1584 _ storageprovisioner.StatusSetter, 1585 _ clock.Clock, 1586 ) worker.Worker { 1587 // storageDir is empty for environ storage provisioners 1588 if storageDir == "" { 1589 c.Check(scope, gc.Equals, s.State.EnvironTag()) 1590 c.Check(atomic.AddUint32(&environWorkers, 1), gc.Equals, uint32(1)) 1591 atomic.AddUint32(&numWorkers, 1) 1592 } 1593 if storageDir != "" { 1594 c.Check(scope, gc.Equals, m.Tag()) 1595 c.Check(atomic.AddUint32(&machineWorkers, 1), gc.Equals, uint32(1)) 1596 atomic.AddUint32(&numWorkers, 1) 1597 } 1598 if atomic.LoadUint32(&environWorkers) == 1 && atomic.LoadUint32(&machineWorkers) == 1 { 1599 close(started) 1600 } 1601 return worker.NewNoOpWorker() 1602 } 1603 s.PatchValue(&newStorageWorker, newWorker) 1604 1605 // Start the machine agent. 1606 a := s.newAgent(c, m) 1607 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1608 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1609 1610 // Wait for worker to be started. 1611 select { 1612 case <-started: 1613 c.Assert(atomic.LoadUint32(&numWorkers), gc.Equals, uint32(2)) 1614 case <-time.After(coretesting.LongWait): 1615 c.Fatalf("timeout while waiting for storage worker to start") 1616 } 1617 } 1618 1619 func (s *MachineSuite) TestMachineAgentRunsCertificateUpdateWorkerForStateServer(c *gc.C) { 1620 started := make(chan struct{}) 1621 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.EnvironConfigGetter, 1622 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1623 ) worker.Worker { 1624 close(started) 1625 return worker.NewNoOpWorker() 1626 } 1627 s.PatchValue(&newCertificateUpdater, newUpdater) 1628 1629 // Start the machine agent. 1630 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1631 a := s.newAgent(c, m) 1632 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1633 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1634 1635 // Wait for worker to be started. 1636 select { 1637 case <-started: 1638 case <-time.After(coretesting.LongWait): 1639 c.Fatalf("timeout while waiting for certificate update worker to start") 1640 } 1641 } 1642 1643 func (s *MachineSuite) TestMachineAgentDoesNotRunsCertificateUpdateWorkerForNonStateServer(c *gc.C) { 1644 started := make(chan struct{}) 1645 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.EnvironConfigGetter, 1646 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1647 ) worker.Worker { 1648 close(started) 1649 return worker.NewNoOpWorker() 1650 } 1651 s.PatchValue(&newCertificateUpdater, newUpdater) 1652 1653 // Start the machine agent. 1654 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1655 a := s.newAgent(c, m) 1656 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1657 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1658 1659 // Ensure the worker is not started. 1660 select { 1661 case <-started: 1662 c.Fatalf("certificate update worker unexpectedly started") 1663 case <-time.After(coretesting.ShortWait): 1664 } 1665 } 1666 1667 func (s *MachineSuite) TestCertificateUpdateWorkerUpdatesCertificate(c *gc.C) { 1668 // Set up the machine agent. 1669 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1670 a := s.newAgent(c, m) 1671 a.ReadConfig(names.NewMachineTag(m.Id()).String()) 1672 1673 // Set up check that certificate has been updated. 1674 updated := make(chan struct{}) 1675 go func() { 1676 for { 1677 stateInfo, _ := a.CurrentConfig().StateServingInfo() 1678 srvCert, err := cert.ParseCert(stateInfo.Cert) 1679 c.Assert(err, jc.ErrorIsNil) 1680 sanIPs := make([]string, len(srvCert.IPAddresses)) 1681 for i, ip := range srvCert.IPAddresses { 1682 sanIPs[i] = ip.String() 1683 } 1684 if len(sanIPs) == 1 && sanIPs[0] == "0.1.2.3" { 1685 close(updated) 1686 break 1687 } 1688 time.Sleep(10 * time.Millisecond) 1689 } 1690 }() 1691 1692 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1693 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1694 // Wait for certificate to be updated. 1695 select { 1696 case <-updated: 1697 case <-time.After(coretesting.LongWait): 1698 c.Fatalf("timeout while waiting for certificate to be updated") 1699 } 1700 } 1701 1702 func (s *MachineSuite) TestCertificateDNSUpdated(c *gc.C) { 1703 // Disable the certificate work so it doesn't update the certificate. 1704 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.EnvironConfigGetter, 1705 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1706 ) worker.Worker { 1707 return worker.NewNoOpWorker() 1708 } 1709 s.PatchValue(&newCertificateUpdater, newUpdater) 1710 1711 // Set up the machine agent. 1712 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1713 a := s.newAgent(c, m) 1714 1715 // Set up check that certificate has been updated when the agent starts. 1716 updated := make(chan struct{}) 1717 expectedDnsNames := set.NewStrings("local", "juju-apiserver", "juju-mongodb") 1718 go func() { 1719 for { 1720 stateInfo, _ := a.CurrentConfig().StateServingInfo() 1721 srvCert, err := cert.ParseCert(stateInfo.Cert) 1722 c.Assert(err, jc.ErrorIsNil) 1723 certDnsNames := set.NewStrings(srvCert.DNSNames...) 1724 if !expectedDnsNames.Difference(certDnsNames).IsEmpty() { 1725 continue 1726 } 1727 pemContent, err := ioutil.ReadFile(filepath.Join(s.DataDir(), "server.pem")) 1728 c.Assert(err, jc.ErrorIsNil) 1729 if string(pemContent) == stateInfo.Cert+"\n"+stateInfo.PrivateKey { 1730 close(updated) 1731 break 1732 } 1733 time.Sleep(10 * time.Millisecond) 1734 } 1735 }() 1736 1737 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1738 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1739 // Wait for certificate to be updated. 1740 select { 1741 case <-updated: 1742 case <-time.After(coretesting.LongWait): 1743 c.Fatalf("timeout while waiting for certificate to be updated") 1744 } 1745 } 1746 1747 func (s *MachineSuite) TestMachineAgentNetworkerMode(c *gc.C) { 1748 tests := []struct { 1749 about string 1750 managedNetwork bool 1751 jobs []state.MachineJob 1752 intrusiveMode bool 1753 }{{ 1754 about: "network management enabled, network management job set", 1755 managedNetwork: true, 1756 jobs: []state.MachineJob{state.JobHostUnits, state.JobManageNetworking}, 1757 intrusiveMode: true, 1758 }, { 1759 about: "network management disabled, network management job set", 1760 managedNetwork: false, 1761 jobs: []state.MachineJob{state.JobHostUnits, state.JobManageNetworking}, 1762 intrusiveMode: false, 1763 }, { 1764 about: "network management enabled, network management job not set", 1765 managedNetwork: true, 1766 jobs: []state.MachineJob{state.JobHostUnits}, 1767 intrusiveMode: false, 1768 }, { 1769 about: "network management disabled, network management job not set", 1770 managedNetwork: false, 1771 jobs: []state.MachineJob{state.JobHostUnits}, 1772 intrusiveMode: false, 1773 }} 1774 // Perform tests. 1775 for i, test := range tests { 1776 c.Logf("test #%d: %s", i, test.about) 1777 1778 modeCh := make(chan bool, 1) 1779 s.AgentSuite.PatchValue(&newNetworker, func( 1780 st apinetworker.State, 1781 conf agent.Config, 1782 intrusiveMode bool, 1783 configBaseDir string, 1784 ) (*networker.Networker, error) { 1785 select { 1786 case modeCh <- intrusiveMode: 1787 default: 1788 } 1789 return networker.NewNetworker(st, conf, intrusiveMode, configBaseDir) 1790 }) 1791 1792 attrs := coretesting.Attrs{"disable-network-management": !test.managedNetwork} 1793 err := s.BackingState.UpdateEnvironConfig(attrs, nil, nil) 1794 c.Assert(err, jc.ErrorIsNil) 1795 1796 m, _, _ := s.primeAgent(c, version.Current, test.jobs...) 1797 a := s.newAgent(c, m) 1798 defer a.Stop() 1799 doneCh := make(chan error) 1800 go func() { 1801 doneCh <- a.Run(nil) 1802 }() 1803 1804 select { 1805 case intrusiveMode := <-modeCh: 1806 if intrusiveMode != test.intrusiveMode { 1807 c.Fatalf("expected networker intrusive mode = %v, got mode = %v", test.intrusiveMode, intrusiveMode) 1808 } 1809 case <-time.After(coretesting.LongWait): 1810 c.Fatalf("timed out waiting for the networker to start") 1811 } 1812 s.waitStopped(c, state.JobManageNetworking, a, doneCh) 1813 } 1814 } 1815 1816 func (s *MachineSuite) TestMachineAgentIgnoreAddresses(c *gc.C) { 1817 for _, expectedIgnoreValue := range []bool{true, false} { 1818 ignoreAddressCh := make(chan bool, 1) 1819 s.AgentSuite.PatchValue(&newMachiner, func( 1820 accessor machiner.MachineAccessor, 1821 conf agent.Config, 1822 ignoreMachineAddresses bool, 1823 ) worker.Worker { 1824 select { 1825 case ignoreAddressCh <- ignoreMachineAddresses: 1826 default: 1827 } 1828 return machiner.NewMachiner(accessor, conf, ignoreMachineAddresses) 1829 }) 1830 1831 attrs := coretesting.Attrs{"ignore-machine-addresses": expectedIgnoreValue} 1832 err := s.BackingState.UpdateEnvironConfig(attrs, nil, nil) 1833 c.Assert(err, jc.ErrorIsNil) 1834 1835 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1836 a := s.newAgent(c, m) 1837 defer a.Stop() 1838 doneCh := make(chan error) 1839 go func() { 1840 doneCh <- a.Run(nil) 1841 }() 1842 1843 select { 1844 case ignoreMachineAddresses := <-ignoreAddressCh: 1845 if ignoreMachineAddresses != expectedIgnoreValue { 1846 c.Fatalf("expected ignore-machine-addresses = %v, got = %v", expectedIgnoreValue, ignoreMachineAddresses) 1847 } 1848 case <-time.After(coretesting.LongWait): 1849 c.Fatalf("timed out waiting for the machiner to start") 1850 } 1851 s.waitStopped(c, state.JobHostUnits, a, doneCh) 1852 } 1853 } 1854 1855 func (s *MachineSuite) TestMachineAgentUpgradeMongo(c *gc.C) { 1856 m, agentConfig, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 1857 agentConfig.SetUpgradedToVersion(version.MustParse("1.18.0")) 1858 err := agentConfig.Write() 1859 c.Assert(err, jc.ErrorIsNil) 1860 err = s.State.MongoSession().DB("admin").RemoveUser(m.Tag().String()) 1861 c.Assert(err, jc.ErrorIsNil) 1862 1863 s.fakeEnsureMongo.ServiceInstalled = true 1864 s.fakeEnsureMongo.ReplicasetInitiated = false 1865 1866 s.AgentSuite.PatchValue(&ensureMongoAdminUser, func(p mongo.EnsureAdminUserParams) (bool, error) { 1867 err := s.State.MongoSession().DB("admin").AddUser(p.User, p.Password, false) 1868 c.Assert(err, jc.ErrorIsNil) 1869 return true, nil 1870 }) 1871 1872 stateOpened := make(chan interface{}, 1) 1873 s.AgentSuite.PatchValue(&reportOpenedState, func(st io.Closer) { 1874 select { 1875 case stateOpened <- st: 1876 default: 1877 } 1878 }) 1879 1880 // Start the machine agent, and wait for state to be opened. 1881 a := s.newAgent(c, m) 1882 done := make(chan error) 1883 go func() { done <- a.Run(nil) }() 1884 defer a.Stop() // in case of failure 1885 select { 1886 case st := <-stateOpened: 1887 c.Assert(st, gc.NotNil) 1888 case <-time.After(coretesting.LongWait): 1889 c.Fatalf("state not opened") 1890 } 1891 s.waitStopped(c, state.JobManageEnviron, a, done) 1892 c.Assert(s.fakeEnsureMongo.EnsureCount, gc.Equals, 1) 1893 c.Assert(s.fakeEnsureMongo.InitiateCount, gc.Equals, 1) 1894 } 1895 1896 func (s *MachineSuite) TestMachineAgentSetsPrepareRestore(c *gc.C) { 1897 // Start the machine agent. 1898 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1899 a := s.newAgent(c, m) 1900 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1901 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1902 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1903 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1904 err := a.PrepareRestore() 1905 c.Assert(err, jc.ErrorIsNil) 1906 c.Assert(a.IsRestorePreparing(), jc.IsTrue) 1907 c.Assert(a.IsRestoreRunning(), jc.IsFalse) 1908 err = a.PrepareRestore() 1909 c.Assert(err, gc.ErrorMatches, "already in restore mode") 1910 } 1911 1912 func (s *MachineSuite) TestMachineAgentSetsRestoreInProgress(c *gc.C) { 1913 // Start the machine agent. 1914 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1915 a := s.newAgent(c, m) 1916 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1917 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1918 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1919 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1920 err := a.PrepareRestore() 1921 c.Assert(err, jc.ErrorIsNil) 1922 c.Assert(a.IsRestorePreparing(), jc.IsTrue) 1923 err = a.BeginRestore() 1924 c.Assert(err, jc.ErrorIsNil) 1925 c.Assert(a.IsRestoreRunning(), jc.IsTrue) 1926 err = a.BeginRestore() 1927 c.Assert(err, gc.ErrorMatches, "already restoring") 1928 } 1929 1930 func (s *MachineSuite) TestMachineAgentRestoreRequiresPrepare(c *gc.C) { 1931 // Start the machine agent. 1932 m, _, _ := s.primeAgent(c, version.Current, state.JobHostUnits) 1933 a := s.newAgent(c, m) 1934 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1935 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1936 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1937 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1938 err := a.BeginRestore() 1939 c.Assert(err, gc.ErrorMatches, "not in restore mode, cannot begin restoration") 1940 c.Assert(a.IsRestoreRunning(), jc.IsFalse) 1941 } 1942 1943 func (s *MachineSuite) TestNewEnvironmentStartsNewWorkers(c *gc.C) { 1944 _, closer := s.setUpNewEnvironment(c) 1945 defer closer() 1946 expectedWorkers, closer := s.setUpAgent(c) 1947 defer closer() 1948 1949 r1 := s.singularRecord.nextRunner(c) 1950 workers := r1.waitForWorker(c, "firewaller") 1951 c.Assert(workers, jc.SameContents, expectedWorkers) 1952 } 1953 1954 func (s *MachineSuite) TestNewStorageWorkerIsScopedToNewEnviron(c *gc.C) { 1955 st, closer := s.setUpNewEnvironment(c) 1956 defer closer() 1957 1958 // Check that newStorageWorker is called and the environ tag is scoped to 1959 // that of the new environment tag. 1960 started := make(chan struct{}) 1961 newWorker := func( 1962 scope names.Tag, 1963 storageDir string, 1964 _ storageprovisioner.VolumeAccessor, 1965 _ storageprovisioner.FilesystemAccessor, 1966 _ storageprovisioner.LifecycleManager, 1967 _ storageprovisioner.EnvironAccessor, 1968 _ storageprovisioner.MachineAccessor, 1969 _ storageprovisioner.StatusSetter, 1970 _ clock.Clock, 1971 ) worker.Worker { 1972 // storageDir is empty for environ storage provisioners 1973 if storageDir == "" { 1974 // If this is the worker for the new environment, 1975 // close the channel. 1976 if scope == st.EnvironTag() { 1977 close(started) 1978 } 1979 } 1980 return worker.NewNoOpWorker() 1981 } 1982 s.PatchValue(&newStorageWorker, newWorker) 1983 1984 _, closer = s.setUpAgent(c) 1985 defer closer() 1986 1987 // Wait for newStorageWorker to be started. 1988 select { 1989 case <-started: 1990 case <-time.After(coretesting.LongWait): 1991 c.Fatalf("timeout while waiting for storage worker to start") 1992 } 1993 } 1994 1995 func (s *MachineSuite) setUpNewEnvironment(c *gc.C) (newSt *state.State, closer func()) { 1996 // Create a new environment, tests can now watch if workers start for it. 1997 newSt = s.Factory.MakeEnvironment(c, &factory.EnvParams{ 1998 ConfigAttrs: map[string]interface{}{ 1999 "state-server": false, 2000 }, 2001 Prepare: true, 2002 }) 2003 return newSt, func() { 2004 newSt.Close() 2005 } 2006 } 2007 2008 func (s *MachineSuite) setUpAgent(c *gc.C) (expectedWorkers []string, closer func()) { 2009 expectedWorkers = make([]string, 0, len(perEnvSingularWorkers)+1) 2010 for _, w := range perEnvSingularWorkers { 2011 expectedWorkers = append(expectedWorkers, w) 2012 if w == "environ-provisioner" { 2013 expectedWorkers = append(expectedWorkers, "environ-storageprovisioner") 2014 } 2015 } 2016 s.PatchValue(&watcher.Period, 100*time.Millisecond) 2017 2018 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 2019 a := s.newAgent(c, m) 2020 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 2021 2022 _ = s.singularRecord.nextRunner(c) // Don't care about this one for this test. 2023 2024 // Wait for the workers for the initial env to start. The 2025 // firewaller is the last worker started for a new environment. 2026 r0 := s.singularRecord.nextRunner(c) 2027 workers := r0.waitForWorker(c, "firewaller") 2028 c.Assert(workers, jc.SameContents, expectedWorkers) 2029 2030 return expectedWorkers, func() { 2031 c.Check(a.Stop(), jc.ErrorIsNil) 2032 } 2033 } 2034 2035 func (s *MachineSuite) TestReplicasetInitiation(c *gc.C) { 2036 if runtime.GOOS == "windows" { 2037 c.Skip("state servers on windows aren't supported") 2038 } 2039 2040 s.fakeEnsureMongo.ReplicasetInitiated = false 2041 2042 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 2043 a := s.newAgent(c, m) 2044 agentConfig := a.CurrentConfig() 2045 2046 err := a.ensureMongoServer(agentConfig) 2047 c.Assert(err, jc.ErrorIsNil) 2048 2049 c.Assert(s.fakeEnsureMongo.EnsureCount, gc.Equals, 1) 2050 c.Assert(s.fakeEnsureMongo.InitiateCount, gc.Equals, 1) 2051 } 2052 2053 func (s *MachineSuite) TestReplicasetAlreadyInitiated(c *gc.C) { 2054 if runtime.GOOS == "windows" { 2055 c.Skip("state servers on windows aren't supported") 2056 } 2057 2058 s.fakeEnsureMongo.ReplicasetInitiated = true 2059 2060 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 2061 a := s.newAgent(c, m) 2062 agentConfig := a.CurrentConfig() 2063 2064 err := a.ensureMongoServer(agentConfig) 2065 c.Assert(err, jc.ErrorIsNil) 2066 2067 c.Assert(s.fakeEnsureMongo.EnsureCount, gc.Equals, 1) 2068 c.Assert(s.fakeEnsureMongo.InitiateCount, gc.Equals, 0) 2069 } 2070 2071 func (s *MachineSuite) TestReplicasetInitForNewStateServer(c *gc.C) { 2072 if runtime.GOOS == "windows" { 2073 c.Skip("state servers on windows aren't supported") 2074 } 2075 2076 s.fakeEnsureMongo.ServiceInstalled = false 2077 s.fakeEnsureMongo.ReplicasetInitiated = true 2078 2079 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 2080 a := s.newAgent(c, m) 2081 agentConfig := a.CurrentConfig() 2082 2083 err := a.ensureMongoServer(agentConfig) 2084 c.Assert(err, jc.ErrorIsNil) 2085 2086 c.Assert(s.fakeEnsureMongo.EnsureCount, gc.Equals, 1) 2087 c.Assert(s.fakeEnsureMongo.InitiateCount, gc.Equals, 0) 2088 } 2089 2090 // MachineWithCharmsSuite provides infrastructure for tests which need to 2091 // work with charms. 2092 type MachineWithCharmsSuite struct { 2093 commonMachineSuite 2094 charmtesting.CharmSuite 2095 2096 machine *state.Machine 2097 } 2098 2099 func (s *MachineWithCharmsSuite) SetUpSuite(c *gc.C) { 2100 s.commonMachineSuite.SetUpSuite(c) 2101 s.CharmSuite.SetUpSuite(c, &s.commonMachineSuite.JujuConnSuite) 2102 } 2103 2104 func (s *MachineWithCharmsSuite) TearDownSuite(c *gc.C) { 2105 s.CharmSuite.TearDownSuite(c) 2106 s.commonMachineSuite.TearDownSuite(c) 2107 } 2108 2109 func (s *MachineWithCharmsSuite) SetUpTest(c *gc.C) { 2110 s.commonMachineSuite.SetUpTest(c) 2111 s.CharmSuite.SetUpTest(c) 2112 } 2113 2114 func (s *MachineWithCharmsSuite) TearDownTest(c *gc.C) { 2115 s.CharmSuite.TearDownTest(c) 2116 s.commonMachineSuite.TearDownTest(c) 2117 } 2118 2119 func (s *MachineWithCharmsSuite) TestManageEnvironRunsCharmRevisionUpdater(c *gc.C) { 2120 m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron) 2121 2122 s.SetupScenario(c) 2123 2124 a := s.newAgent(c, m) 2125 go func() { 2126 c.Check(a.Run(nil), jc.ErrorIsNil) 2127 }() 2128 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 2129 2130 checkRevision := func() bool { 2131 curl := charm.MustParseURL("cs:quantal/mysql") 2132 placeholder, err := s.State.LatestPlaceholderCharm(curl) 2133 return err == nil && placeholder.String() == curl.WithRevision(23).String() 2134 } 2135 success := false 2136 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 2137 if success = checkRevision(); success { 2138 break 2139 } 2140 } 2141 c.Assert(success, jc.IsTrue) 2142 } 2143 2144 type mongoSuite struct { 2145 coretesting.BaseSuite 2146 } 2147 2148 func (s *mongoSuite) TestStateWorkerDialSetsWriteMajority(c *gc.C) { 2149 s.testStateWorkerDialSetsWriteMajority(c, true) 2150 } 2151 2152 func (s *mongoSuite) TestStateWorkerDialDoesNotSetWriteMajorityWithoutReplsetConfig(c *gc.C) { 2153 s.testStateWorkerDialSetsWriteMajority(c, false) 2154 } 2155 2156 func (s *mongoSuite) testStateWorkerDialSetsWriteMajority(c *gc.C, configureReplset bool) { 2157 inst := gitjujutesting.MgoInstance{ 2158 EnableJournal: true, 2159 Params: []string{"--replSet", "juju"}, 2160 } 2161 err := inst.Start(coretesting.Certs) 2162 c.Assert(err, jc.ErrorIsNil) 2163 defer inst.Destroy() 2164 2165 var expectedWMode string 2166 dialOpts := stateWorkerDialOpts 2167 if configureReplset { 2168 info := inst.DialInfo() 2169 args := peergrouper.InitiateMongoParams{ 2170 DialInfo: info, 2171 MemberHostPort: inst.Addr(), 2172 } 2173 err = peergrouper.MaybeInitiateMongoServer(args) 2174 c.Assert(err, jc.ErrorIsNil) 2175 expectedWMode = "majority" 2176 } else { 2177 dialOpts.Direct = true 2178 } 2179 2180 mongoInfo := mongo.Info{ 2181 Addrs: []string{inst.Addr()}, 2182 CACert: coretesting.CACert, 2183 } 2184 session, err := mongo.DialWithInfo(mongoInfo, dialOpts) 2185 c.Assert(err, jc.ErrorIsNil) 2186 defer session.Close() 2187 2188 safe := session.Safe() 2189 c.Assert(safe, gc.NotNil) 2190 c.Assert(safe.WMode, gc.Equals, expectedWMode) 2191 c.Assert(safe.J, jc.IsTrue) // always enabled 2192 } 2193 2194 type shouldWriteProxyFilesSuite struct { 2195 coretesting.BaseSuite 2196 } 2197 2198 var _ = gc.Suite(&shouldWriteProxyFilesSuite{}) 2199 2200 func (s *shouldWriteProxyFilesSuite) TestAll(c *gc.C) { 2201 tests := []struct { 2202 description string 2203 providerType string 2204 machineId string 2205 expect bool 2206 }{{ 2207 description: "local provider machine 0 must not write", 2208 providerType: "local", 2209 machineId: "0", 2210 expect: false, 2211 }, { 2212 description: "local provider other machine must write 1", 2213 providerType: "local", 2214 machineId: "0/kvm/0", 2215 expect: true, 2216 }, { 2217 description: "local provider other machine must write 2", 2218 providerType: "local", 2219 machineId: "123", 2220 expect: true, 2221 }, { 2222 description: "other provider machine 0 must write", 2223 providerType: "anything", 2224 machineId: "0", 2225 expect: true, 2226 }, { 2227 description: "other provider other machine must write 1", 2228 providerType: "dummy", 2229 machineId: "0/kvm/0", 2230 expect: true, 2231 }, { 2232 description: "other provider other machine must write 2", 2233 providerType: "blahblahblah", 2234 machineId: "123", 2235 expect: true, 2236 }} 2237 for i, test := range tests { 2238 c.Logf("test %d: %s", i, test.description) 2239 mockConf := &mockAgentConfig{ 2240 providerType: test.providerType, 2241 tag: names.NewMachineTag(test.machineId), 2242 } 2243 c.Check(shouldWriteProxyFiles(mockConf), gc.Equals, test.expect) 2244 } 2245 } 2246 2247 type mockAgentConfig struct { 2248 agent.Config 2249 providerType string 2250 tag names.Tag 2251 } 2252 2253 func (m *mockAgentConfig) Tag() names.Tag { 2254 return m.tag 2255 } 2256 2257 func (m *mockAgentConfig) Value(key string) string { 2258 if key == agent.ProviderType { 2259 return m.providerType 2260 } 2261 return "" 2262 } 2263 2264 type singularRunnerRecord struct { 2265 runnerC chan *fakeSingularRunner 2266 } 2267 2268 func newSingularRunnerRecord() *singularRunnerRecord { 2269 return &singularRunnerRecord{ 2270 runnerC: make(chan *fakeSingularRunner, 5), 2271 } 2272 } 2273 2274 func (r *singularRunnerRecord) newSingularRunner(runner worker.Runner, conn singular.Conn) (worker.Runner, error) { 2275 sr, err := singular.New(runner, conn) 2276 if err != nil { 2277 return nil, err 2278 } 2279 fakeRunner := &fakeSingularRunner{ 2280 Runner: sr, 2281 startC: make(chan string, 64), 2282 } 2283 r.runnerC <- fakeRunner 2284 return fakeRunner, nil 2285 } 2286 2287 // nextRunner blocks until a new singular runner is created. 2288 func (r *singularRunnerRecord) nextRunner(c *gc.C) *fakeSingularRunner { 2289 for { 2290 select { 2291 case r := <-r.runnerC: 2292 return r 2293 case <-time.After(coretesting.LongWait): 2294 c.Fatal("timed out waiting for singular runner to be created") 2295 } 2296 } 2297 } 2298 2299 type fakeSingularRunner struct { 2300 worker.Runner 2301 startC chan string 2302 } 2303 2304 func (r *fakeSingularRunner) StartWorker(name string, start func() (worker.Worker, error)) error { 2305 r.startC <- name 2306 return r.Runner.StartWorker(name, start) 2307 } 2308 2309 // waitForWorker waits for a given worker to be started, returning all 2310 // workers started while waiting. 2311 func (r *fakeSingularRunner) waitForWorker(c *gc.C, target string) []string { 2312 var seen []string 2313 timeout := time.After(coretesting.LongWait) 2314 for { 2315 select { 2316 case workerName := <-r.startC: 2317 seen = append(seen, workerName) 2318 if workerName == target { 2319 return seen 2320 } 2321 case <-timeout: 2322 c.Fatal("timed out waiting for " + target) 2323 } 2324 } 2325 } 2326 2327 // waitForWorkers waits for a given worker to be started, returning all 2328 // workers started while waiting. 2329 func (r *fakeSingularRunner) waitForWorkers(c *gc.C, targets []string) []string { 2330 var seen []string 2331 seenTargets := make(map[string]bool) 2332 numSeenTargets := 0 2333 timeout := time.After(coretesting.LongWait) 2334 for { 2335 select { 2336 case workerName := <-r.startC: 2337 if seenTargets[workerName] == true { 2338 c.Fatal("worker started twice: " + workerName) 2339 } 2340 seenTargets[workerName] = true 2341 numSeenTargets++ 2342 seen = append(seen, workerName) 2343 if numSeenTargets == len(targets) { 2344 return seen 2345 } 2346 case <-timeout: 2347 c.Fatalf("timed out waiting for %v", targets) 2348 } 2349 } 2350 } 2351 2352 type mockMetricAPI struct { 2353 stop chan struct{} 2354 cleanUpCalled chan struct{} 2355 sendCalled chan struct{} 2356 } 2357 2358 func newMockMetricAPI() *mockMetricAPI { 2359 return &mockMetricAPI{ 2360 stop: make(chan struct{}), 2361 cleanUpCalled: make(chan struct{}), 2362 sendCalled: make(chan struct{}), 2363 } 2364 } 2365 2366 func (m *mockMetricAPI) CleanupOldMetrics() error { 2367 go func() { 2368 select { 2369 case m.cleanUpCalled <- struct{}{}: 2370 case <-m.stop: 2371 break 2372 } 2373 }() 2374 return nil 2375 } 2376 2377 func (m *mockMetricAPI) SendMetrics() error { 2378 go func() { 2379 select { 2380 case m.sendCalled <- struct{}{}: 2381 case <-m.stop: 2382 break 2383 } 2384 }() 2385 return nil 2386 } 2387 2388 func (m *mockMetricAPI) SendCalled() <-chan struct{} { 2389 return m.sendCalled 2390 } 2391 2392 func (m *mockMetricAPI) CleanupCalled() <-chan struct{} { 2393 return m.cleanUpCalled 2394 } 2395 2396 func (m *mockMetricAPI) Stop() { 2397 close(m.stop) 2398 } 2399 2400 func mkdtemp(prefix string) string { 2401 d, err := ioutil.TempDir("", prefix) 2402 if err != nil { 2403 panic(err) 2404 } 2405 return d 2406 } 2407 2408 func mktemp(prefix string, content string) string { 2409 f, err := ioutil.TempFile("", prefix) 2410 if err != nil { 2411 panic(err) 2412 } 2413 _, err = f.WriteString(content) 2414 if err != nil { 2415 panic(err) 2416 } 2417 f.Close() 2418 return f.Name() 2419 } 2420 2421 type mockLoopDeviceManager struct { 2422 detachLoopDevicesArgRootfs string 2423 detachLoopDevicesArgPrefix string 2424 } 2425 2426 func (m *mockLoopDeviceManager) DetachLoopDevices(rootfs, prefix string) error { 2427 m.detachLoopDevicesArgRootfs = rootfs 2428 m.detachLoopDevicesArgPrefix = prefix 2429 return nil 2430 }