github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/cmd/jujud/agent/machine_test.go (about) 1 // Copyright 2012-2016 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" 15 "time" 16 17 "github.com/juju/cmd" 18 "github.com/juju/cmd/cmdtesting" 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" 24 "github.com/juju/utils/arch" 25 "github.com/juju/utils/series" 26 "github.com/juju/utils/set" 27 "github.com/juju/utils/ssh" 28 sshtesting "github.com/juju/utils/ssh/testing" 29 "github.com/juju/utils/symlink" 30 "github.com/juju/version" 31 gc "gopkg.in/check.v1" 32 "gopkg.in/juju/charm.v6-unstable" 33 "gopkg.in/juju/charmrepo.v2-unstable" 34 "gopkg.in/natefinch/lumberjack.v2" 35 36 "github.com/juju/juju/agent" 37 "github.com/juju/juju/api" 38 apideployer "github.com/juju/juju/api/deployer" 39 "github.com/juju/juju/api/imagemetadata" 40 apimachiner "github.com/juju/juju/api/machiner" 41 charmtesting "github.com/juju/juju/apiserver/charmrevisionupdater/testing" 42 "github.com/juju/juju/apiserver/params" 43 "github.com/juju/juju/cert" 44 agenttesting "github.com/juju/juju/cmd/jujud/agent/testing" 45 cmdutil "github.com/juju/juju/cmd/jujud/util" 46 lxctesting "github.com/juju/juju/container/lxc/testing" 47 envtesting "github.com/juju/juju/environs/testing" 48 "github.com/juju/juju/feature" 49 "github.com/juju/juju/instance" 50 "github.com/juju/juju/juju" 51 jujutesting "github.com/juju/juju/juju/testing" 52 "github.com/juju/juju/mongo" 53 "github.com/juju/juju/mongo/mongotest" 54 "github.com/juju/juju/network" 55 "github.com/juju/juju/provider/dummy" 56 "github.com/juju/juju/service/upstart" 57 "github.com/juju/juju/state" 58 "github.com/juju/juju/state/watcher" 59 "github.com/juju/juju/status" 60 "github.com/juju/juju/storage" 61 coretesting "github.com/juju/juju/testing" 62 "github.com/juju/juju/tools" 63 jujuversion "github.com/juju/juju/version" 64 "github.com/juju/juju/worker" 65 "github.com/juju/juju/worker/authenticationworker" 66 "github.com/juju/juju/worker/certupdater" 67 "github.com/juju/juju/worker/deployer" 68 "github.com/juju/juju/worker/diskmanager" 69 "github.com/juju/juju/worker/instancepoller" 70 "github.com/juju/juju/worker/logsender" 71 "github.com/juju/juju/worker/machiner" 72 "github.com/juju/juju/worker/mongoupgrader" 73 "github.com/juju/juju/worker/peergrouper" 74 "github.com/juju/juju/worker/resumer" 75 "github.com/juju/juju/worker/singular" 76 "github.com/juju/juju/worker/storageprovisioner" 77 "github.com/juju/juju/worker/upgrader" 78 ) 79 80 var ( 81 _ = gc.Suite(&MachineSuite{}) 82 _ = gc.Suite(&MachineWithCharmsSuite{}) 83 _ = gc.Suite(&mongoSuite{}) 84 ) 85 86 type commonMachineSuite struct { 87 singularRecord *singularRunnerRecord 88 lxctesting.TestSuite 89 fakeEnsureMongo *agenttesting.FakeEnsureMongo 90 AgentSuite 91 } 92 93 func (s *commonMachineSuite) SetUpSuite(c *gc.C) { 94 s.AgentSuite.SetUpSuite(c) 95 s.TestSuite.SetUpSuite(c) 96 s.AgentSuite.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber) 97 s.AgentSuite.PatchValue(&stateWorkerDialOpts, mongotest.DialOpts()) 98 } 99 100 func (s *commonMachineSuite) TearDownSuite(c *gc.C) { 101 s.TestSuite.TearDownSuite(c) 102 s.AgentSuite.TearDownSuite(c) 103 } 104 105 func (s *commonMachineSuite) SetUpTest(c *gc.C) { 106 s.AgentSuite.SetUpTest(c) 107 s.TestSuite.SetUpTest(c) 108 s.AgentSuite.PatchValue(&charmrepo.CacheDir, c.MkDir()) 109 110 // Patch ssh user to avoid touching ~ubuntu/.ssh/authorized_keys. 111 s.AgentSuite.PatchValue(&authenticationworker.SSHUser, "") 112 113 testpath := c.MkDir() 114 s.AgentSuite.PatchEnvPathPrepend(testpath) 115 // mock out the start method so we can fake install services without sudo 116 fakeCmd(filepath.Join(testpath, "start")) 117 fakeCmd(filepath.Join(testpath, "stop")) 118 119 s.AgentSuite.PatchValue(&upstart.InitDir, c.MkDir()) 120 121 s.singularRecord = newSingularRunnerRecord() 122 s.AgentSuite.PatchValue(&newSingularRunner, s.singularRecord.newSingularRunner) 123 s.AgentSuite.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { 124 return newDummyWorker(), nil 125 }) 126 127 s.fakeEnsureMongo = agenttesting.InstallFakeEnsureMongo(s) 128 } 129 130 func (s *commonMachineSuite) assertChannelActive(c *gc.C, aChannel chan struct{}, intent string) { 131 // Wait for channel to be active. 132 select { 133 case <-aChannel: 134 case <-time.After(coretesting.LongWait): 135 c.Fatalf("timeout while waiting for %v", intent) 136 } 137 } 138 139 func (s *commonMachineSuite) assertChannelInactive(c *gc.C, aChannel chan struct{}, intent string) { 140 // Now make sure the channel is not active. 141 select { 142 case <-aChannel: 143 c.Fatalf("%v unexpectedly", intent) 144 case <-time.After(startWorkerWait): 145 } 146 } 147 148 func fakeCmd(path string) { 149 err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 0"), 0755) 150 if err != nil { 151 panic(err) 152 } 153 } 154 155 func (s *commonMachineSuite) TearDownTest(c *gc.C) { 156 s.TestSuite.TearDownTest(c) 157 s.AgentSuite.TearDownTest(c) 158 } 159 160 // primeAgent adds a new Machine to run the given jobs, and sets up the 161 // machine agent's directory. It returns the new machine, the 162 // agent's configuration and the tools currently running. 163 func (s *commonMachineSuite) primeAgent(c *gc.C, jobs ...state.MachineJob) (m *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools) { 164 vers := version.Binary{ 165 Number: jujuversion.Current, 166 Arch: arch.HostArch(), 167 Series: series.HostSeries(), 168 } 169 return s.primeAgentVersion(c, vers, jobs...) 170 } 171 172 // primeAgentVersion is similar to primeAgent, but permits the 173 // caller to specify the version.Binary to prime with. 174 func (s *commonMachineSuite) primeAgentVersion(c *gc.C, vers version.Binary, jobs ...state.MachineJob) (m *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools) { 175 m, err := s.State.AddMachine("quantal", jobs...) 176 c.Assert(err, jc.ErrorIsNil) 177 return s.primeAgentWithMachine(c, m, vers) 178 } 179 180 func (s *commonMachineSuite) primeAgentWithMachine(c *gc.C, m *state.Machine, vers version.Binary) (*state.Machine, agent.ConfigSetterWriter, *tools.Tools) { 181 pinger, err := m.SetAgentPresence() 182 c.Assert(err, jc.ErrorIsNil) 183 s.AddCleanup(func(c *gc.C) { 184 err := pinger.Stop() 185 c.Check(err, jc.ErrorIsNil) 186 }) 187 return s.configureMachine(c, m.Id(), vers) 188 } 189 190 func (s *commonMachineSuite) configureMachine(c *gc.C, machineId string, vers version.Binary) ( 191 machine *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools, 192 ) { 193 m, err := s.State.Machine(machineId) 194 c.Assert(err, jc.ErrorIsNil) 195 196 // Add a machine and ensure it is provisioned. 197 inst, md := jujutesting.AssertStartInstance(c, s.Environ, machineId) 198 c.Assert(m.SetProvisioned(inst.Id(), agent.BootstrapNonce, md), jc.ErrorIsNil) 199 200 // Add an address for the tests in case the initiateMongoServer 201 // codepath is exercised. 202 s.setFakeMachineAddresses(c, m) 203 204 // Set up the new machine. 205 err = m.SetAgentVersion(vers) 206 c.Assert(err, jc.ErrorIsNil) 207 err = m.SetPassword(initialMachinePassword) 208 c.Assert(err, jc.ErrorIsNil) 209 tag := m.Tag() 210 if m.IsManager() { 211 err = m.SetMongoPassword(initialMachinePassword) 212 c.Assert(err, jc.ErrorIsNil) 213 agentConfig, tools = s.PrimeStateAgentVersion(c, tag, initialMachinePassword, vers) 214 info, ok := agentConfig.StateServingInfo() 215 c.Assert(ok, jc.IsTrue) 216 ssi := cmdutil.ParamsStateServingInfoToStateStateServingInfo(info) 217 err = s.State.SetStateServingInfo(ssi) 218 c.Assert(err, jc.ErrorIsNil) 219 } else { 220 agentConfig, tools = s.PrimeAgentVersion(c, tag, initialMachinePassword, vers) 221 } 222 err = agentConfig.Write() 223 c.Assert(err, jc.ErrorIsNil) 224 return m, agentConfig, tools 225 } 226 227 func NewTestMachineAgentFactory( 228 agentConfWriter AgentConfigWriter, 229 bufferedLogs logsender.LogRecordCh, 230 rootDir string, 231 ) func(string) *MachineAgent { 232 return func(machineId string) *MachineAgent { 233 return NewMachineAgent( 234 machineId, 235 agentConfWriter, 236 bufferedLogs, 237 worker.NewRunner(cmdutil.IsFatal, cmdutil.MoreImportant, worker.RestartDelay), 238 &mockLoopDeviceManager{}, 239 rootDir, 240 ) 241 } 242 } 243 244 // newAgent returns a new MachineAgent instance 245 func (s *commonMachineSuite) newAgent(c *gc.C, m *state.Machine) *MachineAgent { 246 agentConf := agentConf{dataDir: s.DataDir()} 247 agentConf.ReadConfig(names.NewMachineTag(m.Id()).String()) 248 machineAgentFactory := NewTestMachineAgentFactory(&agentConf, nil, c.MkDir()) 249 return machineAgentFactory(m.Id()) 250 } 251 252 func (s *MachineSuite) TestParseSuccess(c *gc.C) { 253 create := func() (cmd.Command, AgentConf) { 254 agentConf := agentConf{dataDir: s.DataDir()} 255 a := NewMachineAgentCmd( 256 nil, 257 NewTestMachineAgentFactory(&agentConf, nil, c.MkDir()), 258 &agentConf, 259 &agentConf, 260 ) 261 a.(*machineAgentCmd).logToStdErr = true 262 263 return a, &agentConf 264 } 265 a := CheckAgentCommand(c, create, []string{"--machine-id", "42"}) 266 c.Assert(a.(*machineAgentCmd).machineId, gc.Equals, "42") 267 } 268 269 type MachineSuite struct { 270 commonMachineSuite 271 } 272 273 var perEnvSingularWorkers = []string{ 274 "cleaner", 275 "minunitsworker", 276 "addresserworker", 277 "environ-provisioner", 278 "charm-revision-updater", 279 "discoverspaces", 280 "instancepoller", 281 "firewaller", 282 "unitassigner", 283 } 284 285 const initialMachinePassword = "machine-password-1234567890" 286 287 func (s *MachineSuite) SetUpTest(c *gc.C) { 288 s.commonMachineSuite.SetUpTest(c) 289 // Most of these tests normally finish sub-second on a fast machine. 290 // If any given test hits a minute, we have almost certainly become 291 // wedged, so dump the logs. 292 coretesting.DumpTestLogsAfter(time.Minute, c, s) 293 } 294 295 func (s *MachineSuite) TestParseNonsense(c *gc.C) { 296 for _, args := range [][]string{ 297 {}, 298 {"--machine-id", "-4004"}, 299 } { 300 var agentConf agentConf 301 err := ParseAgentCommand(&machineAgentCmd{agentInitializer: &agentConf}, args) 302 c.Assert(err, gc.ErrorMatches, "--machine-id option must be set, and expects a non-negative integer") 303 } 304 } 305 306 func (s *MachineSuite) TestParseUnknown(c *gc.C) { 307 var agentConf agentConf 308 a := &machineAgentCmd{agentInitializer: &agentConf} 309 err := ParseAgentCommand(a, []string{"--machine-id", "42", "blistering barnacles"}) 310 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["blistering barnacles"\]`) 311 } 312 313 func (s *MachineSuite) TestRunInvalidMachineId(c *gc.C) { 314 c.Skip("agents don't yet distinguish between temporary and permanent errors") 315 m, _, _ := s.primeAgent(c, state.JobHostUnits) 316 err := s.newAgent(c, m).Run(nil) 317 c.Assert(err, gc.ErrorMatches, "some error") 318 } 319 320 func (s *MachineSuite) TestUseLumberjack(c *gc.C) { 321 ctx := cmdtesting.Context(c) 322 agentConf := FakeAgentConfig{} 323 324 a := NewMachineAgentCmd( 325 ctx, 326 NewTestMachineAgentFactory(&agentConf, nil, c.MkDir()), 327 agentConf, 328 agentConf, 329 ) 330 // little hack to set the data that Init expects to already be set 331 a.(*machineAgentCmd).machineId = "42" 332 333 err := a.Init(nil) 334 c.Assert(err, gc.IsNil) 335 336 l, ok := ctx.Stderr.(*lumberjack.Logger) 337 c.Assert(ok, jc.IsTrue) 338 c.Check(l.MaxAge, gc.Equals, 0) 339 c.Check(l.MaxBackups, gc.Equals, 2) 340 c.Check(l.Filename, gc.Equals, filepath.FromSlash("/var/log/juju/machine-42.log")) 341 c.Check(l.MaxSize, gc.Equals, 300) 342 } 343 344 func (s *MachineSuite) TestDontUseLumberjack(c *gc.C) { 345 ctx := cmdtesting.Context(c) 346 agentConf := FakeAgentConfig{} 347 348 a := NewMachineAgentCmd( 349 ctx, 350 NewTestMachineAgentFactory(&agentConf, nil, c.MkDir()), 351 agentConf, 352 agentConf, 353 ) 354 // little hack to set the data that Init expects to already be set 355 a.(*machineAgentCmd).machineId = "42" 356 357 // set the value that normally gets set by the flag parsing 358 a.(*machineAgentCmd).logToStdErr = true 359 360 err := a.Init(nil) 361 c.Assert(err, gc.IsNil) 362 363 _, ok := ctx.Stderr.(*lumberjack.Logger) 364 c.Assert(ok, jc.IsFalse) 365 } 366 367 func (s *MachineSuite) TestRunStop(c *gc.C) { 368 m, ac, _ := s.primeAgent(c, state.JobHostUnits) 369 a := s.newAgent(c, m) 370 done := make(chan error) 371 go func() { 372 done <- a.Run(nil) 373 }() 374 err := a.Stop() 375 c.Assert(err, jc.ErrorIsNil) 376 c.Assert(<-done, jc.ErrorIsNil) 377 c.Assert(charmrepo.CacheDir, gc.Equals, filepath.Join(ac.DataDir(), "charmcache")) 378 } 379 380 func (s *MachineSuite) TestWithDeadMachine(c *gc.C) { 381 m, ac, _ := s.primeAgent(c, state.JobHostUnits) 382 err := m.EnsureDead() 383 c.Assert(err, jc.ErrorIsNil) 384 a := s.newAgent(c, m) 385 err = runWithTimeout(a) 386 c.Assert(err, jc.ErrorIsNil) 387 388 _, err = os.Stat(ac.DataDir()) 389 c.Assert(err, jc.Satisfies, os.IsNotExist) 390 } 391 392 func (s *MachineSuite) TestWithRemovedMachine(c *gc.C) { 393 m, ac, _ := s.primeAgent(c, state.JobHostUnits) 394 err := m.EnsureDead() 395 c.Assert(err, jc.ErrorIsNil) 396 err = m.Remove() 397 c.Assert(err, jc.ErrorIsNil) 398 a := s.newAgent(c, m) 399 err = runWithTimeout(a) 400 c.Assert(err, jc.ErrorIsNil) 401 402 _, err = os.Stat(ac.DataDir()) 403 c.Assert(err, jc.Satisfies, os.IsNotExist) 404 } 405 406 func (s *MachineSuite) TestDyingMachine(c *gc.C) { 407 m, _, _ := s.primeAgent(c, state.JobHostUnits) 408 a := s.newAgent(c, m) 409 done := make(chan error) 410 go func() { 411 done <- a.Run(nil) 412 }() 413 defer func() { 414 c.Check(a.Stop(), jc.ErrorIsNil) 415 }() 416 // Wait for configuration to be finished 417 <-a.WorkersStarted() 418 err := m.Destroy() 419 c.Assert(err, jc.ErrorIsNil) 420 select { 421 case err := <-done: 422 c.Assert(err, jc.ErrorIsNil) 423 case <-time.After(watcher.Period * 5 / 4): 424 // TODO(rog) Fix this so it doesn't wait for so long. 425 // https://bugs.launchpad.net/juju-core/+bug/1163983 426 c.Fatalf("timed out waiting for agent to terminate") 427 } 428 err = m.Refresh() 429 c.Assert(err, jc.ErrorIsNil) 430 c.Assert(m.Life(), gc.Equals, state.Dead) 431 } 432 433 func (s *MachineSuite) TestHostUnits(c *gc.C) { 434 m, _, _ := s.primeAgent(c, state.JobHostUnits) 435 a := s.newAgent(c, m) 436 ctx, reset := patchDeployContext(c, s.BackingState) 437 defer reset() 438 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 439 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 440 441 // check that unassigned units don't trigger any deployments. 442 svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 443 u0, err := svc.AddUnit() 444 c.Assert(err, jc.ErrorIsNil) 445 u1, err := svc.AddUnit() 446 c.Assert(err, jc.ErrorIsNil) 447 448 ctx.waitDeployed(c) 449 450 // assign u0, check it's deployed. 451 err = u0.AssignToMachine(m) 452 c.Assert(err, jc.ErrorIsNil) 453 ctx.waitDeployed(c, u0.Name()) 454 455 // "start the agent" for u0 to prevent short-circuited remove-on-destroy; 456 // check that it's kept deployed despite being Dying. 457 err = u0.SetAgentStatus(status.StatusIdle, "", nil) 458 c.Assert(err, jc.ErrorIsNil) 459 err = u0.Destroy() 460 c.Assert(err, jc.ErrorIsNil) 461 ctx.waitDeployed(c, u0.Name()) 462 463 // add u1 to the machine, check it's deployed. 464 err = u1.AssignToMachine(m) 465 c.Assert(err, jc.ErrorIsNil) 466 ctx.waitDeployed(c, u0.Name(), u1.Name()) 467 468 // make u0 dead; check the deployer recalls the unit and removes it from 469 // state. 470 err = u0.EnsureDead() 471 c.Assert(err, jc.ErrorIsNil) 472 ctx.waitDeployed(c, u1.Name()) 473 474 // The deployer actually removes the unit just after 475 // removing its deployment, so we need to poll here 476 // until it actually happens. 477 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 478 if !attempt.HasNext() { 479 c.Fatalf("timeout waiting for unit %q to be removed", u0.Name()) 480 } 481 if err := u0.Refresh(); err == nil { 482 c.Logf("waiting unit %q to be removed...", u0.Name()) 483 continue 484 } else { 485 c.Assert(err, jc.Satisfies, errors.IsNotFound) 486 break 487 } 488 } 489 490 // short-circuit-remove u1 after it's been deployed; check it's recalled 491 // and removed from state. 492 err = u1.Destroy() 493 c.Assert(err, jc.ErrorIsNil) 494 err = u1.Refresh() 495 c.Assert(err, jc.Satisfies, errors.IsNotFound) 496 ctx.waitDeployed(c) 497 } 498 499 func patchDeployContext(c *gc.C, st *state.State) (*fakeContext, func()) { 500 ctx := &fakeContext{ 501 inited: newSignal(), 502 deployed: make(set.Strings), 503 } 504 orig := newDeployContext 505 newDeployContext = func(dst *apideployer.State, agentConfig agent.Config) deployer.Context { 506 ctx.st = st 507 ctx.agentConfig = agentConfig 508 ctx.inited.trigger() 509 return ctx 510 } 511 return ctx, func() { newDeployContext = orig } 512 } 513 514 func (s *commonMachineSuite) setFakeMachineAddresses(c *gc.C, machine *state.Machine) { 515 addrs := network.NewAddresses("0.1.2.3") 516 err := machine.SetProviderAddresses(addrs...) 517 c.Assert(err, jc.ErrorIsNil) 518 // Set the addresses in the environ instance as well so that if the instance poller 519 // runs it won't overwrite them. 520 instId, err := machine.InstanceId() 521 c.Assert(err, jc.ErrorIsNil) 522 insts, err := s.Environ.Instances([]instance.Id{instId}) 523 c.Assert(err, jc.ErrorIsNil) 524 dummy.SetInstanceAddresses(insts[0], addrs) 525 } 526 527 func (s *MachineSuite) TestManageModel(c *gc.C) { 528 usefulVersion := version.Binary{ 529 Number: jujuversion.Current, 530 Arch: arch.HostArch(), 531 Series: "quantal", // to match the charm created below 532 } 533 envtesting.AssertUploadFakeToolsVersions(c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), usefulVersion) 534 // Prime agent with manage networking in additon to manage model to ensure the former is ignored. 535 m, _, _ := s.primeAgent(c, state.JobManageModel, state.JobManageNetworking) 536 op := make(chan dummy.Operation, 200) 537 dummy.Listen(op) 538 539 a := s.newAgent(c, m) 540 // Make sure the agent is stopped even if the test fails. 541 defer a.Stop() 542 done := make(chan error) 543 go func() { 544 done <- a.Run(nil) 545 }() 546 c.Logf("started test agent, waiting for workers...") 547 r0 := s.singularRecord.nextRunner(c) 548 r0.waitForWorker(c, "txnpruner") 549 550 // Check that the provisioner and firewaller are alive by doing 551 // a rudimentary check that it responds to state changes. 552 553 // Create an exposed service, and add a unit. 554 charm := s.AddTestingCharm(c, "dummy") 555 svc := s.AddTestingService(c, "test-service", charm) 556 err := svc.SetExposed() 557 c.Assert(err, jc.ErrorIsNil) 558 units, err := juju.AddUnits(s.State, svc, 1, nil) 559 c.Assert(err, jc.ErrorIsNil) 560 561 // It should be allocated to a machine, which should then be provisioned. 562 c.Logf("service %q added with 1 unit, waiting for unit %q's machine to be started...", svc.Name(), units[0].Name()) 563 c.Check(opRecvTimeout(c, s.State, op, dummy.OpStartInstance{}), gc.NotNil) 564 c.Logf("machine hosting unit %q started, waiting for the unit to be deployed...", units[0].Name()) 565 s.waitProvisioned(c, units[0]) 566 567 // Open a port on the unit; it should be handled by the firewaller. 568 c.Logf("unit %q deployed, opening port tcp/999...", units[0].Name()) 569 err = units[0].OpenPort("tcp", 999) 570 c.Assert(err, jc.ErrorIsNil) 571 c.Check(opRecvTimeout(c, s.State, op, dummy.OpOpenPorts{}), gc.NotNil) 572 c.Logf("unit %q port tcp/999 opened, cleaning up...", units[0].Name()) 573 574 err = a.Stop() 575 c.Assert(err, jc.ErrorIsNil) 576 select { 577 case err := <-done: 578 c.Assert(err, jc.ErrorIsNil) 579 case <-time.After(coretesting.LongWait): 580 c.Fatalf("timed out waiting for agent to terminate") 581 } 582 c.Logf("test agent stopped successfully.") 583 } 584 585 func (s *MachineSuite) TestManageModelRunsResumer(c *gc.C) { 586 started := newSignal() 587 s.AgentSuite.PatchValue(&resumer.NewResumer, func(st resumer.TransactionResumer) worker.Worker { 588 started.trigger() 589 return newDummyWorker() 590 }) 591 592 m, _, _ := s.primeAgent(c, state.JobManageModel) 593 a := s.newAgent(c, m) 594 defer a.Stop() 595 go func() { 596 c.Check(a.Run(nil), jc.ErrorIsNil) 597 }() 598 started.assertTriggered(c, "resumer worker to start") 599 } 600 601 const startWorkerWait = 250 * time.Millisecond 602 603 func (s *MachineSuite) TestManageModelRunsInstancePoller(c *gc.C) { 604 s.AgentSuite.PatchValue(&instancepoller.ShortPoll, 500*time.Millisecond) 605 usefulVersion := version.Binary{ 606 Number: jujuversion.Current, 607 Arch: arch.HostArch(), 608 Series: "quantal", // to match the charm created below 609 } 610 envtesting.AssertUploadFakeToolsVersions( 611 c, s.DefaultToolsStorage, 612 s.Environ.Config().AgentStream(), 613 s.Environ.Config().AgentStream(), 614 usefulVersion, 615 ) 616 m, _, _ := s.primeAgent(c, state.JobManageModel) 617 a := s.newAgent(c, m) 618 defer a.Stop() 619 go func() { 620 c.Check(a.Run(nil), jc.ErrorIsNil) 621 }() 622 623 // Add one unit to a service; 624 charm := s.AddTestingCharm(c, "dummy") 625 svc := s.AddTestingService(c, "test-service", charm) 626 units, err := juju.AddUnits(s.State, svc, 1, nil) 627 c.Assert(err, jc.ErrorIsNil) 628 629 m, instId := s.waitProvisioned(c, units[0]) 630 insts, err := s.Environ.Instances([]instance.Id{instId}) 631 c.Assert(err, jc.ErrorIsNil) 632 addrs := network.NewAddresses("1.2.3.4") 633 dummy.SetInstanceAddresses(insts[0], addrs) 634 dummy.SetInstanceStatus(insts[0], "running") 635 636 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 637 if !attempt.HasNext() { 638 c.Logf("final machine addresses: %#v", m.Addresses()) 639 c.Fatalf("timed out waiting for machine to get address") 640 } 641 err := m.Refresh() 642 c.Assert(err, jc.ErrorIsNil) 643 instStatus, err := m.InstanceStatus() 644 c.Assert(err, jc.ErrorIsNil) 645 c.Logf("found status is %q %q", instStatus.Status, instStatus.Message) 646 if reflect.DeepEqual(m.Addresses(), addrs) && instStatus.Message == "running" { 647 c.Logf("machine %q address updated: %+v", m.Id(), addrs) 648 break 649 } 650 c.Logf("waiting for machine %q address to be updated", m.Id()) 651 } 652 } 653 654 func (s *MachineSuite) TestManageModelRunsPeergrouper(c *gc.C) { 655 started := newSignal() 656 s.AgentSuite.PatchValue(&peergrouperNew, func(st *state.State) (worker.Worker, error) { 657 c.Check(st, gc.NotNil) 658 started.trigger() 659 return newDummyWorker(), nil 660 }) 661 m, _, _ := s.primeAgent(c, state.JobManageModel) 662 a := s.newAgent(c, m) 663 defer a.Stop() 664 go func() { 665 c.Check(a.Run(nil), jc.ErrorIsNil) 666 }() 667 started.assertTriggered(c, "peergrouperworker to start") 668 } 669 670 func (s *MachineSuite) TestManageModelRunsDbLogPrunerIfFeatureFlagEnabled(c *gc.C) { 671 m, _, _ := s.primeAgent(c, state.JobManageModel) 672 a := s.newAgent(c, m) 673 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 674 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 675 676 runner := s.singularRecord.nextRunner(c) 677 runner.waitForWorker(c, "dblogpruner") 678 } 679 680 func (s *MachineSuite) TestManageModelCallsUseMultipleCPUs(c *gc.C) { 681 // If it has been enabled, the JobManageModel agent should call utils.UseMultipleCPUs 682 usefulVersion := version.Binary{ 683 Number: jujuversion.Current, 684 Arch: arch.HostArch(), 685 Series: "quantal", // to match the charm created below 686 } 687 envtesting.AssertUploadFakeToolsVersions( 688 c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), usefulVersion) 689 m, _, _ := s.primeAgent(c, state.JobManageModel) 690 calledChan := make(chan struct{}, 1) 691 s.AgentSuite.PatchValue(&useMultipleCPUs, func() { calledChan <- struct{}{} }) 692 // Now, start the agent, and observe that a JobManageModel agent 693 // calls UseMultipleCPUs 694 a := s.newAgent(c, m) 695 defer a.Stop() 696 go func() { 697 c.Check(a.Run(nil), jc.ErrorIsNil) 698 }() 699 // Wait for configuration to be finished 700 <-a.WorkersStarted() 701 s.assertChannelActive(c, calledChan, "UseMultipleCPUs() to be called") 702 703 c.Check(a.Stop(), jc.ErrorIsNil) 704 // However, an agent that just JobHostUnits doesn't call UseMultipleCPUs 705 m2, _, _ := s.primeAgent(c, state.JobHostUnits) 706 a2 := s.newAgent(c, m2) 707 defer a2.Stop() 708 go func() { 709 c.Check(a2.Run(nil), jc.ErrorIsNil) 710 }() 711 // Wait until all the workers have been started, and then kill everything 712 <-a2.workersStarted 713 c.Check(a2.Stop(), jc.ErrorIsNil) 714 s.assertChannelInactive(c, calledChan, "UseMultipleCPUs() was called") 715 } 716 717 func (s *MachineSuite) waitProvisioned(c *gc.C, unit *state.Unit) (*state.Machine, instance.Id) { 718 c.Logf("waiting for unit %q to be provisioned", unit) 719 machineId, err := unit.AssignedMachineId() 720 c.Assert(err, jc.ErrorIsNil) 721 m, err := s.State.Machine(machineId) 722 c.Assert(err, jc.ErrorIsNil) 723 w := m.Watch() 724 defer w.Stop() 725 timeout := time.After(coretesting.LongWait) 726 for { 727 select { 728 case <-timeout: 729 c.Fatalf("timed out waiting for provisioning") 730 case <-time.After(coretesting.ShortWait): 731 s.State.StartSync() 732 case _, ok := <-w.Changes(): 733 c.Assert(ok, jc.IsTrue) 734 err := m.Refresh() 735 c.Assert(err, jc.ErrorIsNil) 736 if instId, err := m.InstanceId(); err == nil { 737 c.Logf("unit provisioned with instance %s", instId) 738 return m, instId 739 } else { 740 c.Check(err, jc.Satisfies, errors.IsNotProvisioned) 741 } 742 } 743 } 744 } 745 746 func (s *MachineSuite) testUpgradeRequest(c *gc.C, agent runner, tag string, currentTools *tools.Tools) { 747 newVers := version.Binary{ 748 Number: jujuversion.Current, 749 Arch: arch.HostArch(), 750 Series: series.HostSeries(), 751 } 752 newVers.Patch++ 753 newTools := envtesting.AssertUploadFakeToolsVersions( 754 c, s.DefaultToolsStorage, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), newVers)[0] 755 err := s.State.SetModelAgentVersion(newVers.Number) 756 c.Assert(err, jc.ErrorIsNil) 757 err = runWithTimeout(agent) 758 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 759 AgentName: tag, 760 OldTools: currentTools.Version, 761 NewTools: newTools.Version, 762 DataDir: s.DataDir(), 763 }) 764 } 765 766 func (s *MachineSuite) TestUpgradeRequest(c *gc.C) { 767 m, _, currentTools := s.primeAgent(c, state.JobManageModel, state.JobHostUnits) 768 a := s.newAgent(c, m) 769 s.testUpgradeRequest(c, a, m.Tag().String(), currentTools) 770 c.Assert(a.isInitialUpgradeCheckPending(), jc.IsTrue) 771 } 772 773 func (s *MachineSuite) TestNoUpgradeRequired(c *gc.C) { 774 m, _, _ := s.primeAgent(c, state.JobManageModel, state.JobHostUnits) 775 a := s.newAgent(c, m) 776 done := make(chan error) 777 go func() { done <- a.Run(nil) }() 778 select { 779 case <-a.initialUpgradeCheckComplete.Unlocked(): 780 case <-time.After(coretesting.LongWait): 781 c.Fatalf("timeout waiting for upgrade check") 782 } 783 defer a.Stop() // in case of failure 784 s.waitStopped(c, state.JobManageModel, a, done) 785 c.Assert(a.isInitialUpgradeCheckPending(), jc.IsFalse) 786 } 787 788 var fastDialOpts = api.DialOpts{ 789 Timeout: coretesting.LongWait, 790 RetryDelay: coretesting.ShortWait, 791 } 792 793 func (s *MachineSuite) waitStopped(c *gc.C, job state.MachineJob, a *MachineAgent, done chan error) { 794 err := a.Stop() 795 if job == state.JobManageModel { 796 // When shutting down, the API server can be shut down before 797 // the other workers that connect to it, so they get an error so 798 // they then die, causing Stop to return an error. It's not 799 // easy to control the actual error that's received in this 800 // circumstance so we just log it rather than asserting that it 801 // is not nil. 802 if err != nil { 803 c.Logf("error shutting down state manager: %v", err) 804 } 805 } else { 806 c.Assert(err, jc.ErrorIsNil) 807 } 808 809 select { 810 case err := <-done: 811 c.Assert(err, jc.ErrorIsNil) 812 case <-time.After(coretesting.LongWait): 813 c.Fatalf("timed out waiting for agent to terminate") 814 } 815 } 816 817 func (s *MachineSuite) assertJobWithState( 818 c *gc.C, 819 job state.MachineJob, 820 test func(agent.Config, *state.State), 821 ) { 822 paramsJob := job.ToParams() 823 if !paramsJob.NeedsState() { 824 c.Fatalf("%v does not use state", paramsJob) 825 } 826 s.assertAgentOpensState(c, &reportOpenedState, job, func(cfg agent.Config, st interface{}) { 827 test(cfg, st.(*state.State)) 828 }) 829 } 830 831 // assertAgentOpensState asserts that a machine agent started with the 832 // given job will call the function pointed to by reportOpened. The 833 // agent's configuration and the value passed to reportOpened are then 834 // passed to the test function for further checking. 835 func (s *MachineSuite) assertAgentOpensState(c *gc.C, reportOpened *func(io.Closer), job state.MachineJob, test func(agent.Config, interface{})) { 836 stm, conf, _ := s.primeAgent(c, job) 837 a := s.newAgent(c, stm) 838 defer a.Stop() 839 logger.Debugf("new agent %#v", a) 840 841 // All state jobs currently also run an APIWorker, so no 842 // need to check for that here, like in assertJobWithState. 843 agentAPI, done := s.waitForOpenState(c, reportOpened, a) 844 test(conf, agentAPI) 845 s.waitStopped(c, job, a, done) 846 } 847 848 func (s *MachineSuite) waitForOpenState(c *gc.C, reportOpened *func(io.Closer), a *MachineAgent) (interface{}, chan error) { 849 agentAPIs := make(chan io.Closer, 1) 850 s.AgentSuite.PatchValue(reportOpened, func(st io.Closer) { 851 select { 852 case agentAPIs <- st: 853 default: 854 } 855 }) 856 857 done := make(chan error) 858 go func() { 859 done <- a.Run(nil) 860 }() 861 862 select { 863 case agentAPI := <-agentAPIs: 864 c.Assert(agentAPI, gc.NotNil) 865 return agentAPI, done 866 case <-time.After(coretesting.LongWait): 867 c.Fatalf("API not opened") 868 } 869 panic("can't happen") 870 } 871 872 func (s *MachineSuite) TestManageModelServesAPI(c *gc.C) { 873 s.assertJobWithState(c, state.JobManageModel, func(conf agent.Config, agentState *state.State) { 874 apiInfo, ok := conf.APIInfo() 875 c.Assert(ok, jc.IsTrue) 876 st, err := api.Open(apiInfo, fastDialOpts) 877 c.Assert(err, jc.ErrorIsNil) 878 defer st.Close() 879 m, err := apimachiner.NewState(st).Machine(conf.Tag().(names.MachineTag)) 880 c.Assert(err, jc.ErrorIsNil) 881 c.Assert(m.Life(), gc.Equals, params.Alive) 882 }) 883 } 884 885 func (s *MachineSuite) assertAgentSetsToolsVersion(c *gc.C, job state.MachineJob) { 886 vers := version.Binary{ 887 Number: jujuversion.Current, 888 Arch: arch.HostArch(), 889 Series: series.HostSeries(), 890 } 891 vers.Minor++ 892 m, _, _ := s.primeAgentVersion(c, vers, job) 893 a := s.newAgent(c, m) 894 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 895 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 896 897 timeout := time.After(coretesting.LongWait) 898 for done := false; !done; { 899 select { 900 case <-timeout: 901 c.Fatalf("timeout while waiting for agent version to be set") 902 case <-time.After(coretesting.ShortWait): 903 c.Log("Refreshing") 904 err := m.Refresh() 905 c.Assert(err, jc.ErrorIsNil) 906 c.Log("Fetching agent tools") 907 agentTools, err := m.AgentTools() 908 c.Assert(err, jc.ErrorIsNil) 909 c.Logf("(%v vs. %v)", agentTools.Version, jujuversion.Current) 910 if agentTools.Version.Minor != jujuversion.Current.Minor { 911 continue 912 } 913 c.Assert(agentTools.Version.Number, gc.DeepEquals, jujuversion.Current) 914 done = true 915 } 916 } 917 } 918 919 func (s *MachineSuite) TestAgentSetsToolsVersionManageModel(c *gc.C) { 920 s.assertAgentSetsToolsVersion(c, state.JobManageModel) 921 } 922 923 func (s *MachineSuite) TestAgentSetsToolsVersionHostUnits(c *gc.C) { 924 s.assertAgentSetsToolsVersion(c, state.JobHostUnits) 925 } 926 927 func (s *MachineSuite) TestManageModelRunsCleaner(c *gc.C) { 928 s.assertJobWithState(c, state.JobManageModel, func(conf agent.Config, agentState *state.State) { 929 // Create a service and unit, and destroy the service. 930 service := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 931 unit, err := service.AddUnit() 932 c.Assert(err, jc.ErrorIsNil) 933 err = service.Destroy() 934 c.Assert(err, jc.ErrorIsNil) 935 936 // Check the unit was not yet removed. 937 err = unit.Refresh() 938 c.Assert(err, jc.ErrorIsNil) 939 w := unit.Watch() 940 defer w.Stop() 941 942 // Trigger a sync on the state used by the agent, and wait 943 // for the unit to be removed. 944 agentState.StartSync() 945 timeout := time.After(coretesting.LongWait) 946 for done := false; !done; { 947 select { 948 case <-timeout: 949 c.Fatalf("unit not cleaned up") 950 case <-time.After(coretesting.ShortWait): 951 s.State.StartSync() 952 case <-w.Changes(): 953 err := unit.Refresh() 954 if errors.IsNotFound(err) { 955 done = true 956 } else { 957 c.Assert(err, jc.ErrorIsNil) 958 } 959 } 960 } 961 }) 962 } 963 964 func (s *MachineSuite) TestJobManageModelRunsMinUnitsWorker(c *gc.C) { 965 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, agentState *state.State) { 966 // Ensure that the MinUnits worker is alive by doing a simple check 967 // that it responds to state changes: add a service, set its minimum 968 // number of units to one, wait for the worker to add the missing unit. 969 service := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 970 err := service.SetMinUnits(1) 971 c.Assert(err, jc.ErrorIsNil) 972 w := service.Watch() 973 defer w.Stop() 974 975 // Trigger a sync on the state used by the agent, and wait for the unit 976 // to be created. 977 agentState.StartSync() 978 timeout := time.After(coretesting.LongWait) 979 for { 980 select { 981 case <-timeout: 982 c.Fatalf("unit not created") 983 case <-time.After(coretesting.ShortWait): 984 s.State.StartSync() 985 case <-w.Changes(): 986 units, err := service.AllUnits() 987 c.Assert(err, jc.ErrorIsNil) 988 if len(units) == 1 { 989 return 990 } 991 } 992 } 993 }) 994 } 995 996 func (s *MachineSuite) TestMachineAgentRunsAuthorisedKeysWorker(c *gc.C) { 997 //TODO(bogdanteleaga): Fix once we get authentication worker up on windows 998 if runtime.GOOS == "windows" { 999 c.Skip("bug 1403084: authentication worker not yet implemented on windows") 1000 } 1001 // Start the machine agent. 1002 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1003 a := s.newAgent(c, m) 1004 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1005 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1006 1007 // Update the keys in the environment. 1008 sshKey := sshtesting.ValidKeyOne.Key + " user@host" 1009 err := s.BackingState.UpdateModelConfig(map[string]interface{}{"authorized-keys": sshKey}, nil, nil) 1010 c.Assert(err, jc.ErrorIsNil) 1011 1012 // Wait for ssh keys file to be updated. 1013 s.State.StartSync() 1014 timeout := time.After(coretesting.LongWait) 1015 sshKeyWithCommentPrefix := sshtesting.ValidKeyOne.Key + " Juju:user@host" 1016 for { 1017 select { 1018 case <-timeout: 1019 c.Fatalf("timeout while waiting for authorised ssh keys to change") 1020 case <-time.After(coretesting.ShortWait): 1021 s.State.StartSync() 1022 keys, err := ssh.ListKeys(authenticationworker.SSHUser, ssh.FullKeys) 1023 c.Assert(err, jc.ErrorIsNil) 1024 keysStr := strings.Join(keys, "\n") 1025 if sshKeyWithCommentPrefix != keysStr { 1026 continue 1027 } 1028 return 1029 } 1030 } 1031 } 1032 1033 // opRecvTimeout waits for any of the given kinds of operation to 1034 // be received from ops, and times out if not. 1035 func opRecvTimeout(c *gc.C, st *state.State, opc <-chan dummy.Operation, kinds ...dummy.Operation) dummy.Operation { 1036 st.StartSync() 1037 timeout := time.After(coretesting.LongWait) 1038 for { 1039 select { 1040 case op := <-opc: 1041 for _, k := range kinds { 1042 if reflect.TypeOf(op) == reflect.TypeOf(k) { 1043 return op 1044 } 1045 } 1046 c.Logf("discarding unknown event %#v", op) 1047 case <-time.After(coretesting.ShortWait): 1048 st.StartSync() 1049 case <-timeout: 1050 c.Fatalf("time out wating for operation") 1051 } 1052 } 1053 } 1054 1055 func (s *MachineSuite) TestMachineAgentSymlinks(c *gc.C) { 1056 stm, _, _ := s.primeAgent(c, state.JobManageModel) 1057 a := s.newAgent(c, stm) 1058 defer a.Stop() 1059 _, done := s.waitForOpenState(c, &reportOpenedState, a) 1060 1061 // Symlinks should have been created 1062 for _, link := range []string{jujuRun, jujuDumpLogs} { 1063 _, err := os.Stat(utils.EnsureBaseDir(a.rootDir, link)) 1064 c.Assert(err, jc.ErrorIsNil, gc.Commentf(link)) 1065 } 1066 1067 s.waitStopped(c, state.JobManageModel, a, done) 1068 } 1069 1070 func (s *MachineSuite) TestMachineAgentSymlinkJujuRunExists(c *gc.C) { 1071 if runtime.GOOS == "windows" { 1072 // Cannot make symlink to nonexistent file on windows or 1073 // create a file point a symlink to it then remove it 1074 c.Skip("Cannot test this on windows") 1075 } 1076 1077 stm, _, _ := s.primeAgent(c, state.JobManageModel) 1078 a := s.newAgent(c, stm) 1079 defer a.Stop() 1080 1081 // Pre-create the symlinks, but pointing to the incorrect location. 1082 links := []string{jujuRun, jujuDumpLogs} 1083 a.rootDir = c.MkDir() 1084 for _, link := range links { 1085 fullLink := utils.EnsureBaseDir(a.rootDir, link) 1086 c.Assert(os.MkdirAll(filepath.Dir(fullLink), os.FileMode(0755)), jc.ErrorIsNil) 1087 c.Assert(symlink.New("/nowhere/special", fullLink), jc.ErrorIsNil, gc.Commentf(link)) 1088 } 1089 1090 // Start the agent and wait for it be running. 1091 _, done := s.waitForOpenState(c, &reportOpenedState, a) 1092 1093 // juju-run symlink should have been recreated. 1094 for _, link := range links { 1095 fullLink := utils.EnsureBaseDir(a.rootDir, link) 1096 linkTarget, err := symlink.Read(fullLink) 1097 c.Assert(err, jc.ErrorIsNil) 1098 c.Assert(linkTarget, gc.Not(gc.Equals), "/nowhere/special", gc.Commentf(link)) 1099 } 1100 1101 s.waitStopped(c, state.JobManageModel, a, done) 1102 } 1103 1104 func (s *MachineSuite) TestMachineAgentUninstall(c *gc.C) { 1105 m, ac, _ := s.primeAgent(c, state.JobHostUnits) 1106 err := m.EnsureDead() 1107 c.Assert(err, jc.ErrorIsNil) 1108 a := s.newAgent(c, m) 1109 err = runWithTimeout(a) 1110 c.Assert(err, jc.ErrorIsNil) 1111 1112 // juju-run and juju-dumplogs symlinks should have been removed on 1113 // termination. 1114 for _, link := range []string{jujuRun, jujuDumpLogs} { 1115 _, err = os.Stat(utils.EnsureBaseDir(a.rootDir, link)) 1116 c.Assert(err, jc.Satisfies, os.IsNotExist) 1117 } 1118 1119 // data-dir should have been removed on termination 1120 _, err = os.Stat(ac.DataDir()) 1121 c.Assert(err, jc.Satisfies, os.IsNotExist) 1122 } 1123 1124 func (s *MachineSuite) TestMachineAgentRunsAPIAddressUpdaterWorker(c *gc.C) { 1125 // Start the machine agent. 1126 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1127 a := s.newAgent(c, m) 1128 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1129 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1130 1131 // Update the API addresses. 1132 updatedServers := [][]network.HostPort{ 1133 network.NewHostPorts(1234, "localhost"), 1134 } 1135 err := s.BackingState.SetAPIHostPorts(updatedServers) 1136 c.Assert(err, jc.ErrorIsNil) 1137 1138 // Wait for config to be updated. 1139 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 1140 s.BackingState.StartSync() 1141 if !attempt.HasNext() { 1142 break 1143 } 1144 addrs, err := a.CurrentConfig().APIAddresses() 1145 c.Assert(err, jc.ErrorIsNil) 1146 if reflect.DeepEqual(addrs, []string{"localhost:1234"}) { 1147 return 1148 } 1149 } 1150 c.Fatalf("timeout while waiting for agent config to change") 1151 } 1152 1153 func (s *MachineSuite) TestMachineAgentRunsDiskManagerWorker(c *gc.C) { 1154 // Patch out the worker func before starting the agent. 1155 started := newSignal() 1156 newWorker := func(diskmanager.ListBlockDevicesFunc, diskmanager.BlockDeviceSetter) worker.Worker { 1157 started.trigger() 1158 return worker.NewNoOpWorker() 1159 } 1160 s.PatchValue(&diskmanager.NewWorker, newWorker) 1161 1162 // Start the machine agent. 1163 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1164 a := s.newAgent(c, m) 1165 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1166 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1167 started.assertTriggered(c, "diskmanager worker to start") 1168 } 1169 1170 func (s *MachineSuite) TestMongoUpgradeWorker(c *gc.C) { 1171 // Patch out the worker func before starting the agent. 1172 started := make(chan struct{}) 1173 newWorker := func(*state.State, string, mongoupgrader.StopMongo) (worker.Worker, error) { 1174 close(started) 1175 return worker.NewNoOpWorker(), nil 1176 } 1177 s.PatchValue(&newUpgradeMongoWorker, newWorker) 1178 1179 // Start the machine agent. 1180 m, _, _ := s.primeAgent(c, state.JobManageModel) 1181 a := s.newAgent(c, m) 1182 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1183 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1184 1185 // Wait for worker to be started. 1186 s.State.StartSync() 1187 select { 1188 case <-started: 1189 case <-time.After(coretesting.LongWait): 1190 c.Fatalf("timeout while waiting for mongo upgrader worker to start") 1191 } 1192 } 1193 1194 func (s *MachineSuite) TestDiskManagerWorkerUpdatesState(c *gc.C) { 1195 expected := []storage.BlockDevice{{DeviceName: "whatever"}} 1196 s.PatchValue(&diskmanager.DefaultListBlockDevices, func() ([]storage.BlockDevice, error) { 1197 return expected, nil 1198 }) 1199 1200 // Start the machine agent. 1201 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1202 a := s.newAgent(c, m) 1203 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1204 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1205 1206 // Wait for state to be updated. 1207 s.BackingState.StartSync() 1208 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 1209 devices, err := s.BackingState.BlockDevices(m.MachineTag()) 1210 c.Assert(err, jc.ErrorIsNil) 1211 if len(devices) > 0 { 1212 c.Assert(devices, gc.HasLen, 1) 1213 c.Assert(devices[0].DeviceName, gc.Equals, expected[0].DeviceName) 1214 return 1215 } 1216 } 1217 c.Fatalf("timeout while waiting for block devices to be recorded") 1218 } 1219 1220 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForHostUnits(c *gc.C) { 1221 s.checkMetadataWorkerNotRun(c, state.JobHostUnits, "can host units") 1222 } 1223 1224 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForManageNetworking(c *gc.C) { 1225 s.checkMetadataWorkerNotRun(c, state.JobManageNetworking, "can manage networking") 1226 } 1227 1228 func (s *MachineSuite) TestMachineAgentDoesNotRunMetadataWorkerForNonSimpleStreamDependentProviders(c *gc.C) { 1229 s.checkMetadataWorkerNotRun(c, state.JobManageModel, "has provider which doesn't depend on simple streams") 1230 } 1231 1232 func (s *MachineSuite) checkMetadataWorkerNotRun(c *gc.C, job state.MachineJob, suffix string) { 1233 // Patch out the worker func before starting the agent. 1234 started := newSignal() 1235 newWorker := func(cl *imagemetadata.Client) worker.Worker { 1236 started.trigger() 1237 return worker.NewNoOpWorker() 1238 } 1239 s.PatchValue(&newMetadataUpdater, newWorker) 1240 1241 // Start the machine agent. 1242 m, _, _ := s.primeAgent(c, job) 1243 a := s.newAgent(c, m) 1244 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1245 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1246 started.assertNotTriggered(c, startWorkerWait, "metadata update worker started") 1247 } 1248 1249 func (s *MachineSuite) TestMachineAgentRunsMachineStorageWorker(c *gc.C) { 1250 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1251 1252 started := newSignal() 1253 newWorker := func(config storageprovisioner.Config) (worker.Worker, error) { 1254 c.Check(config.Scope, gc.Equals, m.Tag()) 1255 c.Check(config.Validate(), jc.ErrorIsNil) 1256 started.trigger() 1257 return worker.NewNoOpWorker(), nil 1258 } 1259 s.PatchValue(&storageprovisioner.NewStorageProvisioner, newWorker) 1260 1261 // Start the machine agent. 1262 a := s.newAgent(c, m) 1263 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1264 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1265 started.assertTriggered(c, "storage worker to start") 1266 } 1267 1268 func (s *MachineSuite) TestMachineAgentRunsCertificateUpdateWorkerForController(c *gc.C) { 1269 started := newSignal() 1270 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.ModelConfigGetter, 1271 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1272 ) worker.Worker { 1273 started.trigger() 1274 return worker.NewNoOpWorker() 1275 } 1276 s.PatchValue(&newCertificateUpdater, newUpdater) 1277 1278 // Start the machine agent. 1279 m, _, _ := s.primeAgent(c, state.JobManageModel) 1280 a := s.newAgent(c, m) 1281 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1282 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1283 started.assertTriggered(c, "certificate to be updated") 1284 } 1285 1286 func (s *MachineSuite) TestMachineAgentDoesNotRunsCertificateUpdateWorkerForNonController(c *gc.C) { 1287 started := newSignal() 1288 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.ModelConfigGetter, 1289 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1290 ) worker.Worker { 1291 started.trigger() 1292 return worker.NewNoOpWorker() 1293 } 1294 s.PatchValue(&newCertificateUpdater, newUpdater) 1295 1296 // Start the machine agent. 1297 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1298 a := s.newAgent(c, m) 1299 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1300 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1301 started.assertNotTriggered(c, startWorkerWait, "certificate was updated") 1302 } 1303 1304 func (s *MachineSuite) TestCertificateUpdateWorkerUpdatesCertificate(c *gc.C) { 1305 // Set up the machine agent. 1306 m, _, _ := s.primeAgent(c, state.JobManageModel) 1307 a := s.newAgent(c, m) 1308 a.ReadConfig(names.NewMachineTag(m.Id()).String()) 1309 1310 // Set up check that certificate has been updated. 1311 updated := make(chan struct{}) 1312 go func() { 1313 for { 1314 stateInfo, _ := a.CurrentConfig().StateServingInfo() 1315 srvCert, err := cert.ParseCert(stateInfo.Cert) 1316 c.Assert(err, jc.ErrorIsNil) 1317 sanIPs := make([]string, len(srvCert.IPAddresses)) 1318 for i, ip := range srvCert.IPAddresses { 1319 sanIPs[i] = ip.String() 1320 } 1321 if len(sanIPs) == 1 && sanIPs[0] == "0.1.2.3" { 1322 close(updated) 1323 break 1324 } 1325 time.Sleep(10 * time.Millisecond) 1326 } 1327 }() 1328 1329 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1330 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1331 s.assertChannelActive(c, updated, "certificate to be updated") 1332 } 1333 1334 func (s *MachineSuite) TestCertificateDNSUpdated(c *gc.C) { 1335 // Disable the certificate work so it doesn't update the certificate. 1336 newUpdater := func(certupdater.AddressWatcher, certupdater.StateServingInfoGetter, certupdater.ModelConfigGetter, 1337 certupdater.APIHostPortsGetter, certupdater.StateServingInfoSetter, 1338 ) worker.Worker { 1339 return worker.NewNoOpWorker() 1340 } 1341 s.PatchValue(&newCertificateUpdater, newUpdater) 1342 1343 // Set up the machine agent. 1344 m, _, _ := s.primeAgent(c, state.JobManageModel) 1345 a := s.newAgent(c, m) 1346 1347 // Set up check that certificate has been updated when the agent starts. 1348 updated := make(chan struct{}) 1349 expectedDnsNames := set.NewStrings("local", "juju-apiserver", "juju-mongodb") 1350 go func() { 1351 for { 1352 stateInfo, _ := a.CurrentConfig().StateServingInfo() 1353 srvCert, err := cert.ParseCert(stateInfo.Cert) 1354 c.Assert(err, jc.ErrorIsNil) 1355 certDnsNames := set.NewStrings(srvCert.DNSNames...) 1356 if !expectedDnsNames.Difference(certDnsNames).IsEmpty() { 1357 continue 1358 } 1359 pemContent, err := ioutil.ReadFile(filepath.Join(s.DataDir(), "server.pem")) 1360 c.Assert(err, jc.ErrorIsNil) 1361 if string(pemContent) == stateInfo.Cert+"\n"+stateInfo.PrivateKey { 1362 close(updated) 1363 break 1364 } 1365 time.Sleep(10 * time.Millisecond) 1366 } 1367 }() 1368 1369 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1370 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1371 s.assertChannelActive(c, updated, "certificate to be updated") 1372 } 1373 1374 func (s *MachineSuite) setupIgnoreAddresses(c *gc.C, expectedIgnoreValue bool) chan bool { 1375 ignoreAddressCh := make(chan bool, 1) 1376 s.AgentSuite.PatchValue(&machiner.NewMachiner, func(cfg machiner.Config) (worker.Worker, error) { 1377 select { 1378 case ignoreAddressCh <- cfg.ClearMachineAddressesOnStart: 1379 default: 1380 } 1381 1382 // The test just cares that NewMachiner is called with the correct 1383 // value, nothing else is done with the worker. 1384 return newDummyWorker(), nil 1385 }) 1386 1387 attrs := coretesting.Attrs{"ignore-machine-addresses": expectedIgnoreValue} 1388 err := s.BackingState.UpdateModelConfig(attrs, nil, nil) 1389 c.Assert(err, jc.ErrorIsNil) 1390 return ignoreAddressCh 1391 } 1392 1393 func (s *MachineSuite) TestMachineAgentIgnoreAddresses(c *gc.C) { 1394 for _, expectedIgnoreValue := range []bool{true, false} { 1395 ignoreAddressCh := s.setupIgnoreAddresses(c, expectedIgnoreValue) 1396 1397 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1398 a := s.newAgent(c, m) 1399 defer a.Stop() 1400 doneCh := make(chan error) 1401 go func() { 1402 doneCh <- a.Run(nil) 1403 }() 1404 1405 select { 1406 case ignoreMachineAddresses := <-ignoreAddressCh: 1407 if ignoreMachineAddresses != expectedIgnoreValue { 1408 c.Fatalf("expected ignore-machine-addresses = %v, got = %v", expectedIgnoreValue, ignoreMachineAddresses) 1409 } 1410 case <-time.After(coretesting.LongWait): 1411 c.Fatalf("timed out waiting for the machiner to start") 1412 } 1413 s.waitStopped(c, state.JobHostUnits, a, doneCh) 1414 } 1415 } 1416 1417 func (s *MachineSuite) TestMachineAgentIgnoreAddressesContainer(c *gc.C) { 1418 ignoreAddressCh := s.setupIgnoreAddresses(c, true) 1419 1420 parent, err := s.State.AddMachine("quantal", state.JobHostUnits) 1421 c.Assert(err, jc.ErrorIsNil) 1422 m, err := s.State.AddMachineInsideMachine( 1423 state.MachineTemplate{ 1424 Series: "trusty", 1425 Jobs: []state.MachineJob{state.JobHostUnits}, 1426 }, 1427 parent.Id(), 1428 instance.LXC, 1429 ) 1430 c.Assert(err, jc.ErrorIsNil) 1431 1432 vers := version.Binary{ 1433 Number: jujuversion.Current, 1434 Arch: arch.HostArch(), 1435 Series: series.HostSeries(), 1436 } 1437 s.primeAgentWithMachine(c, m, vers) 1438 a := s.newAgent(c, m) 1439 defer a.Stop() 1440 doneCh := make(chan error) 1441 go func() { 1442 doneCh <- a.Run(nil) 1443 }() 1444 1445 select { 1446 case ignoreMachineAddresses := <-ignoreAddressCh: 1447 if ignoreMachineAddresses { 1448 c.Fatalf("expected ignore-machine-addresses = false, got = true") 1449 } 1450 case <-time.After(coretesting.LongWait): 1451 c.Fatalf("timed out waiting for the machiner to start") 1452 } 1453 s.waitStopped(c, state.JobHostUnits, a, doneCh) 1454 } 1455 1456 func (s *MachineSuite) TestMachineAgentSetsPrepareRestore(c *gc.C) { 1457 // Start the machine agent. 1458 m, _, _ := s.primeAgent(c, 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 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1463 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1464 err := a.PrepareRestore() 1465 c.Assert(err, jc.ErrorIsNil) 1466 c.Assert(a.IsRestorePreparing(), jc.IsTrue) 1467 c.Assert(a.IsRestoreRunning(), jc.IsFalse) 1468 err = a.PrepareRestore() 1469 c.Assert(err, gc.ErrorMatches, "already in restore mode") 1470 } 1471 1472 func (s *MachineSuite) TestMachineAgentSetsRestoreInProgress(c *gc.C) { 1473 // Start the machine agent. 1474 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1475 a := s.newAgent(c, m) 1476 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1477 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1478 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1479 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1480 err := a.PrepareRestore() 1481 c.Assert(err, jc.ErrorIsNil) 1482 c.Assert(a.IsRestorePreparing(), jc.IsTrue) 1483 err = a.BeginRestore() 1484 c.Assert(err, jc.ErrorIsNil) 1485 c.Assert(a.IsRestoreRunning(), jc.IsTrue) 1486 err = a.BeginRestore() 1487 c.Assert(err, gc.ErrorMatches, "already restoring") 1488 } 1489 1490 func (s *MachineSuite) TestMachineAgentRestoreRequiresPrepare(c *gc.C) { 1491 // Start the machine agent. 1492 m, _, _ := s.primeAgent(c, state.JobHostUnits) 1493 a := s.newAgent(c, m) 1494 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 1495 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1496 c.Check(a.IsRestorePreparing(), jc.IsFalse) 1497 c.Check(a.IsRestoreRunning(), jc.IsFalse) 1498 err := a.BeginRestore() 1499 c.Assert(err, gc.ErrorMatches, "not in restore mode, cannot begin restoration") 1500 c.Assert(a.IsRestoreRunning(), jc.IsFalse) 1501 } 1502 1503 func (s *MachineSuite) TestControllerModelWorkers(c *gc.C) { 1504 tracker := newModelTracker(c) 1505 check := modelMatchFunc(c, tracker, append( 1506 alwaysModelWorkers, aliveModelWorkers..., 1507 )) 1508 s.PatchValue(&modelManifolds, tracker.Manifolds) 1509 1510 uuid := s.BackingState.ModelUUID() 1511 timeout := time.After(coretesting.LongWait) 1512 1513 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, _ *state.State) { 1514 for { 1515 if check(uuid) { 1516 break 1517 } 1518 select { 1519 case <-time.After(coretesting.ShortWait): 1520 s.BackingState.StartSync() 1521 case <-timeout: 1522 c.Fatalf("timed out waiting for workers") 1523 } 1524 } 1525 }) 1526 } 1527 1528 func (s *MachineSuite) TestAddressAllocationModelWorkers(c *gc.C) { 1529 s.SetFeatureFlags(feature.AddressAllocation) 1530 1531 tracker := newModelTracker(c) 1532 almostAllWorkers := append(alwaysModelWorkers, aliveModelWorkers...) 1533 check := modelMatchFunc(c, tracker, append( 1534 almostAllWorkers, "address-cleaner", 1535 )) 1536 s.PatchValue(&modelManifolds, tracker.Manifolds) 1537 1538 uuid := s.BackingState.ModelUUID() 1539 timeout := time.After(coretesting.LongWait) 1540 1541 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, _ *state.State) { 1542 for { 1543 if check(uuid) { 1544 break 1545 } 1546 select { 1547 case <-time.After(coretesting.ShortWait): 1548 s.BackingState.StartSync() 1549 case <-timeout: 1550 c.Fatalf("timed out waiting for workers") 1551 } 1552 } 1553 }) 1554 } 1555 1556 func (s *MachineSuite) TestHostedModelWorkers(c *gc.C) { 1557 tracker := newModelTracker(c) 1558 check := modelMatchFunc(c, tracker, append( 1559 alwaysModelWorkers, aliveModelWorkers..., 1560 )) 1561 s.PatchValue(&modelManifolds, tracker.Manifolds) 1562 1563 st, closer := s.setUpNewModel(c) 1564 defer closer() 1565 uuid := st.ModelUUID() 1566 timeout := time.After(ReallyLongWait) 1567 1568 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, _ *state.State) { 1569 for { 1570 if check(uuid) { 1571 break 1572 } 1573 select { 1574 case <-time.After(coretesting.ShortWait): 1575 s.BackingState.StartSync() 1576 case <-timeout: 1577 c.Fatalf("timed out waiting for workers") 1578 } 1579 } 1580 }) 1581 } 1582 1583 func (s *MachineSuite) TestDyingModelCleanedUp(c *gc.C) { 1584 tracker := newModelTracker(c) 1585 check := modelMatchFunc(c, tracker, append( 1586 alwaysModelWorkers, deadModelWorkers..., 1587 )) 1588 s.PatchValue(&modelManifolds, tracker.Manifolds) 1589 1590 st, closer := s.setUpNewModel(c) 1591 defer closer() 1592 uuid := st.ModelUUID() 1593 timeout := time.After(ReallyLongWait) 1594 1595 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, _ *state.State) { 1596 model, err := st.Model() 1597 c.Assert(err, jc.ErrorIsNil) 1598 err = model.Destroy() 1599 c.Assert(err, jc.ErrorIsNil) 1600 1601 // Wait for the running workers to imply that we've 1602 // passed beyond Dying... 1603 for { 1604 if check(uuid) { 1605 break 1606 } 1607 select { 1608 case <-time.After(coretesting.ShortWait): 1609 s.BackingState.StartSync() 1610 case <-timeout: 1611 c.Fatalf("timed out waiting for workers") 1612 } 1613 } 1614 1615 // ...and verify that's reflected in the database. 1616 err = model.Refresh() 1617 c.Check(err, jc.ErrorIsNil) 1618 c.Check(model.Life(), gc.Equals, state.Dead) 1619 }) 1620 } 1621 1622 func (s *MachineSuite) TestModelWorkersRespectSingularResponsibilityFlag(c *gc.C) { 1623 1624 // Grab responsibility for the model on behalf of another machine. 1625 claimer := s.BackingState.SingularClaimer() 1626 uuid := s.BackingState.ModelUUID() 1627 err := claimer.Claim(uuid, "machine-999-lxc-99", time.Hour) 1628 c.Assert(err, jc.ErrorIsNil) 1629 1630 // Then run a normal model-tracking test, just checking for 1631 // a different set of workers. 1632 tracker := newModelTracker(c) 1633 check := modelMatchFunc(c, tracker, alwaysModelWorkers) 1634 s.PatchValue(&modelManifolds, tracker.Manifolds) 1635 1636 timeout := time.After(coretesting.LongWait) 1637 s.assertJobWithState(c, state.JobManageModel, func(_ agent.Config, _ *state.State) { 1638 for { 1639 if check(uuid) { 1640 break 1641 } 1642 select { 1643 case <-time.After(coretesting.ShortWait): 1644 s.BackingState.StartSync() 1645 case <-timeout: 1646 c.Fatalf("timed out waiting for workers") 1647 } 1648 } 1649 }) 1650 } 1651 1652 func (s *MachineSuite) setUpNewModel(c *gc.C) (newSt *state.State, closer func()) { 1653 // Create a new environment, tests can now watch if workers start for it. 1654 newSt = s.Factory.MakeModel(c, nil) 1655 return newSt, func() { 1656 err := newSt.Close() 1657 c.Check(err, jc.ErrorIsNil) 1658 } 1659 } 1660 1661 func (s *MachineSuite) TestReplicasetInitForNewController(c *gc.C) { 1662 if runtime.GOOS == "windows" { 1663 c.Skip("controllers on windows aren't supported") 1664 } 1665 1666 s.fakeEnsureMongo.ServiceInstalled = false 1667 1668 m, _, _ := s.primeAgent(c, state.JobManageModel) 1669 a := s.newAgent(c, m) 1670 agentConfig := a.CurrentConfig() 1671 1672 err := a.ensureMongoServer(agentConfig) 1673 c.Assert(err, jc.ErrorIsNil) 1674 1675 c.Assert(s.fakeEnsureMongo.EnsureCount, gc.Equals, 1) 1676 c.Assert(s.fakeEnsureMongo.InitiateCount, gc.Equals, 0) 1677 } 1678 1679 // MachineWithCharmsSuite provides infrastructure for tests which need to 1680 // work with charms. 1681 type MachineWithCharmsSuite struct { 1682 commonMachineSuite 1683 charmtesting.CharmSuite 1684 1685 machine *state.Machine 1686 } 1687 1688 func (s *MachineWithCharmsSuite) SetUpSuite(c *gc.C) { 1689 s.commonMachineSuite.SetUpSuite(c) 1690 s.CharmSuite.SetUpSuite(c, &s.commonMachineSuite.JujuConnSuite) 1691 } 1692 1693 func (s *MachineWithCharmsSuite) TearDownSuite(c *gc.C) { 1694 s.CharmSuite.TearDownSuite(c) 1695 s.commonMachineSuite.TearDownSuite(c) 1696 } 1697 1698 func (s *MachineWithCharmsSuite) SetUpTest(c *gc.C) { 1699 s.commonMachineSuite.SetUpTest(c) 1700 s.CharmSuite.SetUpTest(c) 1701 } 1702 1703 func (s *MachineWithCharmsSuite) TearDownTest(c *gc.C) { 1704 s.CharmSuite.TearDownTest(c) 1705 s.commonMachineSuite.TearDownTest(c) 1706 } 1707 1708 func (s *MachineWithCharmsSuite) TestManageModelRunsCharmRevisionUpdater(c *gc.C) { 1709 m, _, _ := s.primeAgent(c, state.JobManageModel) 1710 1711 s.SetupScenario(c) 1712 1713 a := s.newAgent(c, m) 1714 go func() { 1715 c.Check(a.Run(nil), jc.ErrorIsNil) 1716 }() 1717 defer func() { c.Check(a.Stop(), jc.ErrorIsNil) }() 1718 1719 checkRevision := func() bool { 1720 curl := charm.MustParseURL("cs:quantal/mysql") 1721 placeholder, err := s.State.LatestPlaceholderCharm(curl) 1722 return err == nil && placeholder.String() == curl.WithRevision(23).String() 1723 } 1724 success := false 1725 for attempt := coretesting.LongAttempt.Start(); attempt.Next(); { 1726 if success = checkRevision(); success { 1727 break 1728 } 1729 } 1730 c.Assert(success, jc.IsTrue) 1731 } 1732 1733 type mongoSuite struct { 1734 coretesting.BaseSuite 1735 } 1736 1737 func (s *mongoSuite) TestStateWorkerDialSetsWriteMajority(c *gc.C) { 1738 s.testStateWorkerDialSetsWriteMajority(c, true) 1739 } 1740 1741 func (s *mongoSuite) TestStateWorkerDialDoesNotSetWriteMajorityWithoutReplsetConfig(c *gc.C) { 1742 s.testStateWorkerDialSetsWriteMajority(c, false) 1743 } 1744 1745 func (s *mongoSuite) testStateWorkerDialSetsWriteMajority(c *gc.C, configureReplset bool) { 1746 inst := gitjujutesting.MgoInstance{ 1747 EnableJournal: true, 1748 Params: []string{"--replSet", "juju"}, 1749 } 1750 err := inst.Start(coretesting.Certs) 1751 c.Assert(err, jc.ErrorIsNil) 1752 defer inst.Destroy() 1753 1754 var expectedWMode string 1755 dialOpts := stateWorkerDialOpts 1756 dialOpts.Timeout = coretesting.LongWait 1757 if configureReplset { 1758 info := inst.DialInfo() 1759 info.Timeout = dialOpts.Timeout 1760 args := peergrouper.InitiateMongoParams{ 1761 DialInfo: info, 1762 MemberHostPort: inst.Addr(), 1763 } 1764 err = peergrouper.InitiateMongoServer(args) 1765 c.Assert(err, jc.ErrorIsNil) 1766 expectedWMode = "majority" 1767 } else { 1768 dialOpts.Direct = true 1769 } 1770 1771 mongoInfo := mongo.Info{ 1772 Addrs: []string{inst.Addr()}, 1773 CACert: coretesting.CACert, 1774 } 1775 session, err := mongo.DialWithInfo(mongoInfo, dialOpts) 1776 c.Assert(err, jc.ErrorIsNil) 1777 defer session.Close() 1778 1779 safe := session.Safe() 1780 c.Assert(safe, gc.NotNil) 1781 c.Assert(safe.WMode, gc.Equals, expectedWMode) 1782 c.Assert(safe.J, jc.IsTrue) // always enabled 1783 } 1784 1785 type mockAgentConfig struct { 1786 agent.Config 1787 providerType string 1788 tag names.Tag 1789 } 1790 1791 func (m *mockAgentConfig) Tag() names.Tag { 1792 return m.tag 1793 } 1794 1795 func (m *mockAgentConfig) Value(key string) string { 1796 if key == agent.ProviderType { 1797 return m.providerType 1798 } 1799 return "" 1800 } 1801 1802 type singularRunnerRecord struct { 1803 runnerC chan *fakeSingularRunner 1804 } 1805 1806 func newSingularRunnerRecord() *singularRunnerRecord { 1807 return &singularRunnerRecord{ 1808 runnerC: make(chan *fakeSingularRunner, 64), 1809 } 1810 } 1811 1812 func (r *singularRunnerRecord) newSingularRunner(runner worker.Runner, conn singular.Conn) (worker.Runner, error) { 1813 sr, err := singular.New(runner, conn) 1814 if err != nil { 1815 return nil, err 1816 } 1817 fakeRunner := &fakeSingularRunner{ 1818 Runner: sr, 1819 startC: make(chan string, 64), 1820 } 1821 r.runnerC <- fakeRunner 1822 return fakeRunner, nil 1823 } 1824 1825 // nextRunner blocks until a new singular runner is created. 1826 func (r *singularRunnerRecord) nextRunner(c *gc.C) *fakeSingularRunner { 1827 timeout := time.After(coretesting.LongWait) 1828 for { 1829 select { 1830 case r := <-r.runnerC: 1831 return r 1832 case <-timeout: 1833 c.Fatal("timed out waiting for singular runner to be created") 1834 } 1835 } 1836 } 1837 1838 type fakeSingularRunner struct { 1839 worker.Runner 1840 startC chan string 1841 } 1842 1843 func (r *fakeSingularRunner) StartWorker(name string, start func() (worker.Worker, error)) error { 1844 logger.Infof("starting fake worker %q", name) 1845 r.startC <- name 1846 return r.Runner.StartWorker(name, start) 1847 } 1848 1849 // waitForWorker waits for a given worker to be started, returning all 1850 // workers started while waiting. 1851 func (r *fakeSingularRunner) waitForWorker(c *gc.C, target string) []string { 1852 var seen []string 1853 timeout := time.After(coretesting.LongWait) 1854 for { 1855 select { 1856 case <-time.After(coretesting.ShortWait): 1857 c.Logf("still waiting for %q; workers seen so far: %+v", target, seen) 1858 case workerName := <-r.startC: 1859 seen = append(seen, workerName) 1860 if workerName == target { 1861 c.Logf("target worker %q started; workers seen so far: %+v", workerName, seen) 1862 return seen 1863 } 1864 c.Logf("worker %q started; still waiting for %q; workers seen so far: %+v", workerName, target, seen) 1865 case <-timeout: 1866 c.Fatal("timed out waiting for " + target) 1867 } 1868 } 1869 } 1870 1871 // waitForWorkers waits for a given worker to be started, returning all 1872 // workers started while waiting. 1873 func (r *fakeSingularRunner) waitForWorkers(c *gc.C, targets []string) []string { 1874 var seen []string 1875 seenTargets := make(map[string]bool) 1876 numSeenTargets := 0 1877 timeout := time.After(coretesting.LongWait) 1878 for { 1879 select { 1880 case workerName := <-r.startC: 1881 c.Logf("worker %q started; workers seen so far: %+v (len: %d, len(targets): %d)", workerName, seen, len(seen), len(targets)) 1882 if seenTargets[workerName] == true { 1883 c.Fatal("worker started twice: " + workerName) 1884 } 1885 seenTargets[workerName] = true 1886 numSeenTargets++ 1887 seen = append(seen, workerName) 1888 if numSeenTargets == len(targets) { 1889 c.Logf("all expected target workers started: %+v", seen) 1890 return seen 1891 } 1892 c.Logf("still waiting for workers %+v to start; numSeenTargets=%d", targets, numSeenTargets) 1893 case <-timeout: 1894 c.Fatalf("timed out waiting for %v", targets) 1895 } 1896 } 1897 } 1898 1899 type mockMetricAPI struct { 1900 stop chan struct{} 1901 cleanUpCalled chan struct{} 1902 sendCalled chan struct{} 1903 } 1904 1905 func newMockMetricAPI() *mockMetricAPI { 1906 return &mockMetricAPI{ 1907 stop: make(chan struct{}), 1908 cleanUpCalled: make(chan struct{}), 1909 sendCalled: make(chan struct{}), 1910 } 1911 } 1912 1913 func (m *mockMetricAPI) CleanupOldMetrics() error { 1914 go func() { 1915 select { 1916 case m.cleanUpCalled <- struct{}{}: 1917 case <-m.stop: 1918 break 1919 } 1920 }() 1921 return nil 1922 } 1923 1924 func (m *mockMetricAPI) SendMetrics() error { 1925 go func() { 1926 select { 1927 case m.sendCalled <- struct{}{}: 1928 case <-m.stop: 1929 break 1930 } 1931 }() 1932 return nil 1933 } 1934 1935 func (m *mockMetricAPI) SendCalled() <-chan struct{} { 1936 return m.sendCalled 1937 } 1938 1939 func (m *mockMetricAPI) CleanupCalled() <-chan struct{} { 1940 return m.cleanUpCalled 1941 } 1942 1943 func (m *mockMetricAPI) Stop() { 1944 close(m.stop) 1945 } 1946 1947 type mockLoopDeviceManager struct { 1948 detachLoopDevicesArgRootfs string 1949 detachLoopDevicesArgPrefix string 1950 } 1951 1952 func (m *mockLoopDeviceManager) DetachLoopDevices(rootfs, prefix string) error { 1953 m.detachLoopDevicesArgRootfs = rootfs 1954 m.detachLoopDevicesArgPrefix = prefix 1955 return nil 1956 } 1957 1958 func newSignal() *signal { 1959 return &signal{ch: make(chan struct{})} 1960 } 1961 1962 type signal struct { 1963 mu sync.Mutex 1964 ch chan struct{} 1965 } 1966 1967 func (s *signal) triggered() <-chan struct{} { 1968 return s.ch 1969 } 1970 1971 func (s *signal) assertTriggered(c *gc.C, thing string) { 1972 select { 1973 case <-s.triggered(): 1974 case <-time.After(coretesting.LongWait): 1975 c.Fatalf("timed out waiting for " + thing) 1976 } 1977 } 1978 1979 func (s *signal) assertNotTriggered(c *gc.C, wait time.Duration, thing string) { 1980 select { 1981 case <-s.triggered(): 1982 c.Fatalf("%v unexpectedly", thing) 1983 case <-time.After(wait): 1984 } 1985 } 1986 1987 func (s *signal) trigger() { 1988 s.mu.Lock() 1989 defer s.mu.Unlock() 1990 1991 select { 1992 case <-s.ch: 1993 // Already closed. 1994 default: 1995 close(s.ch) 1996 } 1997 }