1
// Copyright 2012-2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
15
jc "github.com/juju/testing/checkers"
16
"github.com/juju/utils/arch"
17
"github.com/juju/utils/series"
18
"github.com/juju/utils/set"
19
"github.com/juju/version"
20
gc "gopkg.in/check.v1"
21
"gopkg.in/juju/charmrepo.v2-unstable"
22
"gopkg.in/juju/names.v2"
24
"github.com/juju/juju/agent"
25
"github.com/juju/juju/api"
26
apideployer "github.com/juju/juju/api/deployer"
27
"github.com/juju/juju/cmd/jujud/agent/agenttest"
28
cmdutil "github.com/juju/juju/cmd/jujud/util"
29
"github.com/juju/juju/environs"
30
"github.com/juju/juju/environs/config"
31
"github.com/juju/juju/instance"
32
jujutesting "github.com/juju/juju/juju/testing"
33
"github.com/juju/juju/mongo/mongotest"
34
"github.com/juju/juju/network"
35
"github.com/juju/juju/provider/dummy"
36
"github.com/juju/juju/service/upstart"
37
"github.com/juju/juju/state"
38
coretesting "github.com/juju/juju/testing"
39
"github.com/juju/juju/tools"
40
jujuversion "github.com/juju/juju/version"
41
"github.com/juju/juju/worker"
42
"github.com/juju/juju/worker/authenticationworker"
43
"github.com/juju/juju/worker/deployer"
44
"github.com/juju/juju/worker/logsender"
45
"github.com/juju/juju/worker/singular"
49
initialMachinePassword = "machine-password-1234567890"
50
initialUnitPassword = "unit-password-1234567890"
51
startWorkerWait = 250 * time.Millisecond
54
var fastDialOpts = api.DialOpts{
55
Timeout: coretesting.LongWait,
56
RetryDelay: coretesting.ShortWait,
59
type commonMachineSuite struct {
60
singularRecord *singularRunnerRecord
61
fakeEnsureMongo *agenttest.FakeEnsureMongo
65
func (s *commonMachineSuite) SetUpSuite(c *gc.C) {
66
s.AgentSuite.SetUpSuite(c)
67
s.AgentSuite.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber)
68
s.AgentSuite.PatchValue(&stateWorkerDialOpts, mongotest.DialOpts())
71
func (s *commonMachineSuite) TearDownSuite(c *gc.C) {
72
s.AgentSuite.TearDownSuite(c)
75
func (s *commonMachineSuite) SetUpTest(c *gc.C) {
76
s.AgentSuite.SetUpTest(c)
77
s.AgentSuite.PatchValue(&charmrepo.CacheDir, c.MkDir())
79
// Patch ssh user to avoid touching ~ubuntu/.ssh/authorized_keys.
80
s.AgentSuite.PatchValue(&authenticationworker.SSHUser, "")
83
s.AgentSuite.PatchEnvPathPrepend(testpath)
84
// mock out the start method so we can fake install services without sudo
85
fakeCmd(filepath.Join(testpath, "start"))
86
fakeCmd(filepath.Join(testpath, "stop"))
88
s.AgentSuite.PatchValue(&upstart.InitDir, c.MkDir())
90
s.singularRecord = newSingularRunnerRecord()
91
s.AgentSuite.PatchValue(&newSingularRunner, s.singularRecord.newSingularRunner)
92
s.AgentSuite.PatchValue(&peergrouperNew, func(*state.State, bool) (worker.Worker, error) {
93
return newDummyWorker(), nil
96
s.fakeEnsureMongo = agenttest.InstallFakeEnsureMongo(s)
99
func (s *commonMachineSuite) assertChannelActive(c *gc.C, aChannel chan struct{}, intent string) {
100
// Wait for channel to be active.
103
case <-time.After(coretesting.LongWait):
104
c.Fatalf("timeout while waiting for %v", intent)
108
func (s *commonMachineSuite) assertChannelInactive(c *gc.C, aChannel chan struct{}, intent string) {
109
// Now make sure the channel is not active.
112
c.Fatalf("%v unexpectedly", intent)
113
case <-time.After(startWorkerWait):
117
func fakeCmd(path string) {
118
err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 0"), 0755)
124
func (s *commonMachineSuite) TearDownTest(c *gc.C) {
125
s.AgentSuite.TearDownTest(c)
128
// primeAgent adds a new Machine to run the given jobs, and sets up the
129
// machine agent's directory. It returns the new machine, the
130
// agent's configuration and the tools currently running.
131
func (s *commonMachineSuite) primeAgent(c *gc.C, jobs ...state.MachineJob) (m *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools) {
132
vers := version.Binary{
133
Number: jujuversion.Current,
134
Arch: arch.HostArch(),
135
Series: series.HostSeries(),
137
return s.primeAgentVersion(c, vers, jobs...)
140
// primeAgentVersion is similar to primeAgent, but permits the
141
// caller to specify the version.Binary to prime with.
142
func (s *commonMachineSuite) primeAgentVersion(c *gc.C, vers version.Binary, jobs ...state.MachineJob) (m *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools) {
143
m, err := s.State.AddMachine("quantal", jobs...)
144
c.Assert(err, jc.ErrorIsNil)
145
return s.primeAgentWithMachine(c, m, vers)
148
func (s *commonMachineSuite) primeAgentWithMachine(c *gc.C, m *state.Machine, vers version.Binary) (*state.Machine, agent.ConfigSetterWriter, *tools.Tools) {
149
pinger, err := m.SetAgentPresence()
150
c.Assert(err, jc.ErrorIsNil)
151
s.AddCleanup(func(c *gc.C) {
152
c.Assert(worker.Stop(pinger), jc.ErrorIsNil)
154
return s.configureMachine(c, m.Id(), vers)
157
func (s *commonMachineSuite) configureMachine(c *gc.C, machineId string, vers version.Binary) (
158
machine *state.Machine, agentConfig agent.ConfigSetterWriter, tools *tools.Tools,
160
m, err := s.State.Machine(machineId)
161
c.Assert(err, jc.ErrorIsNil)
163
// Add a machine and ensure it is provisioned.
164
inst, md := jujutesting.AssertStartInstance(c, s.Environ, s.ControllerConfig.ControllerUUID(), machineId)
165
c.Assert(m.SetProvisioned(inst.Id(), agent.BootstrapNonce, md), jc.ErrorIsNil)
167
// Add an address for the tests in case the initiateMongoServer
168
// codepath is exercised.
169
s.setFakeMachineAddresses(c, m)
171
// Set up the new machine.
172
err = m.SetAgentVersion(vers)
173
c.Assert(err, jc.ErrorIsNil)
174
err = m.SetPassword(initialMachinePassword)
175
c.Assert(err, jc.ErrorIsNil)
178
err = m.SetMongoPassword(initialMachinePassword)
179
c.Assert(err, jc.ErrorIsNil)
180
agentConfig, tools = s.PrimeStateAgentVersion(c, tag, initialMachinePassword, vers)
181
info, ok := agentConfig.StateServingInfo()
182
c.Assert(ok, jc.IsTrue)
183
ssi := cmdutil.ParamsStateServingInfoToStateStateServingInfo(info)
184
err = s.State.SetStateServingInfo(ssi)
185
c.Assert(err, jc.ErrorIsNil)
187
agentConfig, tools = s.PrimeAgentVersion(c, tag, initialMachinePassword, vers)
189
err = agentConfig.Write()
190
c.Assert(err, jc.ErrorIsNil)
191
return m, agentConfig, tools
194
func NewTestMachineAgentFactory(
195
agentConfWriter AgentConfigWriter,
196
bufferedLogs logsender.LogRecordCh,
198
) func(string) *MachineAgent {
199
return func(machineId string) *MachineAgent {
200
return NewMachineAgent(
204
worker.NewRunner(cmdutil.IsFatal, cmdutil.MoreImportant, worker.RestartDelay),
205
&mockLoopDeviceManager{},
211
// newAgent returns a new MachineAgent instance
212
func (s *commonMachineSuite) newAgent(c *gc.C, m *state.Machine) *MachineAgent {
213
agentConf := agentConf{dataDir: s.DataDir()}
214
agentConf.ReadConfig(names.NewMachineTag(m.Id()).String())
215
machineAgentFactory := NewTestMachineAgentFactory(&agentConf, nil, c.MkDir())
216
return machineAgentFactory(m.Id())
219
func patchDeployContext(c *gc.C, st *state.State) (*fakeContext, func()) {
222
deployed: make(set.Strings),
224
orig := newDeployContext
225
newDeployContext = func(dst *apideployer.State, agentConfig agent.Config) deployer.Context {
227
ctx.agentConfig = agentConfig
231
return ctx, func() { newDeployContext = orig }
234
func (s *commonMachineSuite) setFakeMachineAddresses(c *gc.C, machine *state.Machine) {
235
addrs := network.NewAddresses("0.1.2.3")
236
err := machine.SetProviderAddresses(addrs...)
237
c.Assert(err, jc.ErrorIsNil)
238
// Set the addresses in the environ instance as well so that if the instance poller
239
// runs it won't overwrite them.
240
instId, err := machine.InstanceId()
241
c.Assert(err, jc.ErrorIsNil)
242
insts, err := s.Environ.Instances([]instance.Id{instId})
243
c.Assert(err, jc.ErrorIsNil)
244
dummy.SetInstanceAddresses(insts[0], addrs)
247
// opRecvTimeout waits for any of the given kinds of operation to
248
// be received from ops, and times out if not.
249
func opRecvTimeout(c *gc.C, st *state.State, opc <-chan dummy.Operation, kinds ...dummy.Operation) dummy.Operation {
251
timeout := time.After(coretesting.LongWait)
255
for _, k := range kinds {
256
if reflect.TypeOf(op) == reflect.TypeOf(k) {
260
c.Logf("discarding unknown event %#v", op)
261
case <-time.After(coretesting.ShortWait):
264
c.Fatalf("time out wating for operation")
269
type mockAgentConfig struct {
275
func (m *mockAgentConfig) Tag() names.Tag {
279
func (m *mockAgentConfig) Value(key string) string {
280
if key == agent.ProviderType {
281
return m.providerType
286
type singularRunnerRecord struct {
287
runnerC chan *fakeSingularRunner
290
func newSingularRunnerRecord() *singularRunnerRecord {
291
return &singularRunnerRecord{
292
runnerC: make(chan *fakeSingularRunner, 64),
296
func (r *singularRunnerRecord) newSingularRunner(runner worker.Runner, conn singular.Conn) (worker.Runner, error) {
297
sr, err := singular.New(runner, conn)
301
fakeRunner := &fakeSingularRunner{
303
startC: make(chan string, 64),
305
r.runnerC <- fakeRunner
306
return fakeRunner, nil
309
// nextRunner blocks until a new singular runner is created.
310
func (r *singularRunnerRecord) nextRunner(c *gc.C) *fakeSingularRunner {
311
timeout := time.After(coretesting.LongWait)
314
case r := <-r.runnerC:
317
c.Fatal("timed out waiting for singular runner to be created")
322
type fakeSingularRunner struct {
327
func (r *fakeSingularRunner) StartWorker(name string, start func() (worker.Worker, error)) error {
328
logger.Infof("starting fake worker %q", name)
330
return r.Runner.StartWorker(name, start)
333
// waitForWorker waits for a given worker to be started, returning all
334
// workers started while waiting.
335
func (r *fakeSingularRunner) waitForWorker(c *gc.C, target string) []string {
337
timeout := time.After(coretesting.LongWait)
340
case <-time.After(coretesting.ShortWait):
341
c.Logf("still waiting for %q; workers seen so far: %+v", target, seen)
342
case workerName := <-r.startC:
343
seen = append(seen, workerName)
344
if workerName == target {
345
c.Logf("target worker %q started; workers seen so far: %+v", workerName, seen)
348
c.Logf("worker %q started; still waiting for %q; workers seen so far: %+v", workerName, target, seen)
350
c.Fatal("timed out waiting for " + target)
355
// waitForWorkers waits for a given worker to be started, returning all
356
// workers started while waiting.
357
func (r *fakeSingularRunner) waitForWorkers(c *gc.C, targets []string) []string {
359
seenTargets := make(map[string]bool)
361
timeout := time.After(coretesting.LongWait)
364
case workerName := <-r.startC:
365
c.Logf("worker %q started; workers seen so far: %+v (len: %d, len(targets): %d)", workerName, seen, len(seen), len(targets))
366
if seenTargets[workerName] == true {
367
c.Fatal("worker started twice: " + workerName)
369
seenTargets[workerName] = true
371
seen = append(seen, workerName)
372
if numSeenTargets == len(targets) {
373
c.Logf("all expected target workers started: %+v", seen)
376
c.Logf("still waiting for workers %+v to start; numSeenTargets=%d", targets, numSeenTargets)
378
c.Fatalf("timed out waiting for %v", targets)
383
type mockMetricAPI struct {
385
cleanUpCalled chan struct{}
386
sendCalled chan struct{}
389
func newMockMetricAPI() *mockMetricAPI {
390
return &mockMetricAPI{
391
stop: make(chan struct{}),
392
cleanUpCalled: make(chan struct{}),
393
sendCalled: make(chan struct{}),
397
func (m *mockMetricAPI) CleanupOldMetrics() error {
400
case m.cleanUpCalled <- struct{}{}:
408
func (m *mockMetricAPI) SendMetrics() error {
411
case m.sendCalled <- struct{}{}:
419
func (m *mockMetricAPI) SendCalled() <-chan struct{} {
423
func (m *mockMetricAPI) CleanupCalled() <-chan struct{} {
424
return m.cleanUpCalled
427
func (m *mockMetricAPI) Stop() {
431
type mockLoopDeviceManager struct {
432
detachLoopDevicesArgRootfs string
433
detachLoopDevicesArgPrefix string
436
func (m *mockLoopDeviceManager) DetachLoopDevices(rootfs, prefix string) error {
437
m.detachLoopDevicesArgRootfs = rootfs
438
m.detachLoopDevicesArgPrefix = prefix
442
func newSignal() *signal {
443
return &signal{ch: make(chan struct{})}
451
func (s *signal) triggered() <-chan struct{} {
455
func (s *signal) assertTriggered(c *gc.C, thing string) {
457
case <-s.triggered():
458
case <-time.After(coretesting.LongWait):
459
c.Fatalf("timed out waiting for " + thing)
463
func (s *signal) assertNotTriggered(c *gc.C, wait time.Duration, thing string) {
465
case <-s.triggered():
466
c.Fatalf("%v unexpectedly", thing)
467
case <-time.After(wait):
471
func (s *signal) trigger() {
483
type runner interface {
484
Run(*cmd.Context) error
488
// runWithTimeout runs an agent and waits
489
// for it to complete within a reasonable time.
490
func runWithTimeout(r runner) error {
491
done := make(chan error)
498
case <-time.After(coretesting.LongWait):
501
return fmt.Errorf("timed out waiting for agent to finish; stop error: %v", err)
504
func newDummyWorker() worker.Worker {
505
return worker.NewSimpleWorker(func(stop <-chan struct{}) error {
511
type FakeConfig struct {
515
func (FakeConfig) LogDir() string {
516
return filepath.FromSlash("/var/log/juju/")
519
func (FakeConfig) Tag() names.Tag {
520
return names.NewMachineTag("42")
523
type FakeAgentConfig struct {
527
func (FakeAgentConfig) ReadConfig(string) error { return nil }
529
func (FakeAgentConfig) CurrentConfig() agent.Config {
533
func (FakeAgentConfig) ChangeConfig(mutate agent.ConfigMutator) error {
534
return mutate(FakeConfig{})
537
func (FakeAgentConfig) CheckArgs([]string) error { return nil }
539
// minModelWorkersEnviron implements just enough of environs.Environ
540
// to allow model workers to run.
541
type minModelWorkersEnviron struct {
545
func (e *minModelWorkersEnviron) Config() *config.Config {
546
attrs := coretesting.FakeConfig()
547
cfg, err := config.New(config.NoDefaults, attrs)
554
func (e *minModelWorkersEnviron) SetConfig(*config.Config) error {
558
func (e *minModelWorkersEnviron) AllInstances() ([]instance.Instance, error) {