~juju-qa/ubuntu/yakkety/juju/2.0-rc3-again

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/cmd/jujud/machine_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-04-24 22:34:47 UTC
  • Revision ID: package-import@ubuntu.com-20130424223447-f0qdji7ubnyo0s71
Tags: upstream-1.10.0.1
ImportĀ upstreamĀ versionĀ 1.10.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package main
 
2
 
 
3
import (
 
4
        "fmt"
 
5
        . "launchpad.net/gocheck"
 
6
        "launchpad.net/juju-core/charm"
 
7
        "launchpad.net/juju-core/cmd"
 
8
        "launchpad.net/juju-core/environs/agent"
 
9
        "launchpad.net/juju-core/environs/dummy"
 
10
        envtesting "launchpad.net/juju-core/environs/testing"
 
11
        "launchpad.net/juju-core/state"
 
12
        "launchpad.net/juju-core/state/api"
 
13
        "launchpad.net/juju-core/state/watcher"
 
14
        "launchpad.net/juju-core/testing"
 
15
        "launchpad.net/juju-core/version"
 
16
        "path/filepath"
 
17
        "reflect"
 
18
        "time"
 
19
)
 
20
 
 
21
type MachineSuite struct {
 
22
        agentSuite
 
23
        oldCacheDir string
 
24
}
 
25
 
 
26
var _ = Suite(&MachineSuite{})
 
27
 
 
28
func (s *MachineSuite) SetUpSuite(c *C) {
 
29
        s.agentSuite.SetUpSuite(c)
 
30
        s.oldCacheDir = charm.CacheDir
 
31
}
 
32
 
 
33
func (s *MachineSuite) TearDownSuite(c *C) {
 
34
        charm.CacheDir = s.oldCacheDir
 
35
        s.agentSuite.TearDownSuite(c)
 
36
}
 
37
 
 
38
// primeAgent adds a new Machine to run the given jobs, and sets up the
 
39
// machine agent's directory.  It returns the new machine, the
 
40
// agent's configuration and the tools currently running.
 
41
func (s *MachineSuite) primeAgent(c *C, jobs ...state.MachineJob) (*state.Machine, *agent.Conf, *state.Tools) {
 
42
        m, err := s.State.InjectMachine("series", "ardbeg-0", jobs...)
 
43
        c.Assert(err, IsNil)
 
44
        err = m.SetMongoPassword("machine-password")
 
45
        c.Assert(err, IsNil)
 
46
        err = m.SetPassword("machine-api-password")
 
47
        c.Assert(err, IsNil)
 
48
        conf, tools := s.agentSuite.primeAgent(c, state.MachineTag(m.Id()), "machine-password")
 
49
        conf.MachineNonce = state.BootstrapNonce
 
50
        conf.Write()
 
51
        c.Assert(err, IsNil)
 
52
        return m, conf, tools
 
53
}
 
54
 
 
55
// newAgent returns a new MachineAgent instance
 
56
func (s *MachineSuite) newAgent(c *C, m *state.Machine) *MachineAgent {
 
57
        a := &MachineAgent{}
 
58
        s.initAgent(c, a, "--machine-id", m.Id())
 
59
        return a
 
60
}
 
61
 
 
62
func (s *MachineSuite) TestParseSuccess(c *C) {
 
63
        create := func() (cmd.Command, *AgentConf) {
 
64
                a := &MachineAgent{}
 
65
                return a, &a.Conf
 
66
        }
 
67
        a := CheckAgentCommand(c, create, []string{"--machine-id", "42"})
 
68
        c.Assert(a.(*MachineAgent).MachineId, Equals, "42")
 
69
}
 
70
 
 
71
func (s *MachineSuite) TestParseNonsense(c *C) {
 
72
        for _, args := range [][]string{
 
73
                {},
 
74
                {"--machine-id", "-4004"},
 
75
        } {
 
76
                err := ParseAgentCommand(&MachineAgent{}, args)
 
77
                c.Assert(err, ErrorMatches, "--machine-id option must be set, and expects a non-negative integer")
 
78
        }
 
79
}
 
80
 
 
81
func (s *MachineSuite) TestParseUnknown(c *C) {
 
82
        a := &MachineAgent{}
 
83
        err := ParseAgentCommand(a, []string{"--machine-id", "42", "blistering barnacles"})
 
84
        c.Assert(err, ErrorMatches, `unrecognized args: \["blistering barnacles"\]`)
 
85
}
 
86
 
 
87
func (s *MachineSuite) TestRunInvalidMachineId(c *C) {
 
88
        c.Skip("agents don't yet distinguish between temporary and permanent errors")
 
89
        m, _, _ := s.primeAgent(c, state.JobHostUnits)
 
90
        err := s.newAgent(c, m).Run(nil)
 
91
        c.Assert(err, ErrorMatches, "some error")
 
92
}
 
93
 
 
94
func (s *MachineSuite) TestRunStop(c *C) {
 
95
        m, ac, _ := s.primeAgent(c, state.JobHostUnits)
 
96
        a := s.newAgent(c, m)
 
97
        done := make(chan error)
 
98
        go func() {
 
99
                done <- a.Run(nil)
 
100
        }()
 
101
        err := a.Stop()
 
102
        c.Assert(err, IsNil)
 
103
        c.Assert(<-done, IsNil)
 
104
        c.Assert(charm.CacheDir, Equals, filepath.Join(ac.DataDir, "charmcache"))
 
105
}
 
106
 
 
107
func (s *MachineSuite) TestWithDeadMachine(c *C) {
 
108
        m, _, _ := s.primeAgent(c, state.JobHostUnits, state.JobServeAPI)
 
109
        err := m.EnsureDead()
 
110
        c.Assert(err, IsNil)
 
111
        a := s.newAgent(c, m)
 
112
        err = runWithTimeout(a)
 
113
        c.Assert(err, IsNil)
 
114
 
 
115
        // try again with the machine removed.
 
116
        err = m.Remove()
 
117
        c.Assert(err, IsNil)
 
118
        a = s.newAgent(c, m)
 
119
        err = runWithTimeout(a)
 
120
        c.Assert(err, IsNil)
 
121
}
 
122
 
 
123
func (s *MachineSuite) TestDyingMachine(c *C) {
 
124
        m, _, _ := s.primeAgent(c, state.JobHostUnits)
 
125
        a := s.newAgent(c, m)
 
126
        done := make(chan error)
 
127
        go func() {
 
128
                done <- a.Run(nil)
 
129
        }()
 
130
        defer func() {
 
131
                c.Check(a.Stop(), IsNil)
 
132
        }()
 
133
        time.Sleep(1 * time.Second)
 
134
        err := m.Destroy()
 
135
        c.Assert(err, IsNil)
 
136
        select {
 
137
        case err := <-done:
 
138
                c.Assert(err, IsNil)
 
139
        case <-time.After(watcher.Period * 5 / 4):
 
140
                // TODO(rog) Fix this so it doesn't wait for so long.
 
141
                // https://bugs.launchpad.net/juju-core/+bug/1163983
 
142
                c.Fatalf("timed out waiting for agent to terminate")
 
143
        }
 
144
        err = m.Refresh()
 
145
        c.Assert(err, IsNil)
 
146
        c.Assert(m.Life(), Equals, state.Dead)
 
147
}
 
148
 
 
149
func (s *MachineSuite) TestHostUnits(c *C) {
 
150
        m, conf, _ := s.primeAgent(c, state.JobHostUnits)
 
151
        a := s.newAgent(c, m)
 
152
        ctx, reset := patchDeployContext(c, conf.StateInfo, conf.DataDir)
 
153
        defer reset()
 
154
        go func() { c.Check(a.Run(nil), IsNil) }()
 
155
        defer func() { c.Check(a.Stop(), IsNil) }()
 
156
 
 
157
        svc, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
 
158
        c.Assert(err, IsNil)
 
159
        u0, err := svc.AddUnit()
 
160
        c.Assert(err, IsNil)
 
161
        u1, err := svc.AddUnit()
 
162
        c.Assert(err, IsNil)
 
163
        ctx.waitDeployed(c)
 
164
 
 
165
        err = u0.AssignToMachine(m)
 
166
        c.Assert(err, IsNil)
 
167
        ctx.waitDeployed(c, u0.Name())
 
168
 
 
169
        err = u0.Destroy()
 
170
        c.Assert(err, IsNil)
 
171
        ctx.waitDeployed(c, u0.Name())
 
172
 
 
173
        err = u1.AssignToMachine(m)
 
174
        c.Assert(err, IsNil)
 
175
        ctx.waitDeployed(c, u0.Name(), u1.Name())
 
176
 
 
177
        err = u0.EnsureDead()
 
178
        c.Assert(err, IsNil)
 
179
        ctx.waitDeployed(c, u1.Name())
 
180
 
 
181
        err = u0.Refresh()
 
182
        c.Assert(state.IsNotFound(err), Equals, true)
 
183
}
 
184
 
 
185
func (s *MachineSuite) TestManageEnviron(c *C) {
 
186
        usefulVersion := version.Current
 
187
        usefulVersion.Series = "series" // to match the charm created below
 
188
        envtesting.UploadFakeToolsVersion(c, s.Conn.Environ.Storage(), usefulVersion)
 
189
        m, _, _ := s.primeAgent(c, state.JobManageEnviron)
 
190
        op := make(chan dummy.Operation, 200)
 
191
        dummy.Listen(op)
 
192
 
 
193
        a := s.newAgent(c, m)
 
194
        // Make sure the agent is stopped even if the test fails.
 
195
        defer a.Stop()
 
196
        done := make(chan error)
 
197
        go func() {
 
198
                done <- a.Run(nil)
 
199
        }()
 
200
 
 
201
        // Check that the provisioner and firewaller are alive by doing
 
202
        // a rudimentary check that it responds to state changes.
 
203
 
 
204
        // Add one unit to a service; it should get allocated a machine
 
205
        // and then its ports should be opened.
 
206
        charm := s.AddTestingCharm(c, "dummy")
 
207
        svc, err := s.State.AddService("test-service", charm)
 
208
        c.Assert(err, IsNil)
 
209
        err = svc.SetExposed()
 
210
        c.Assert(err, IsNil)
 
211
        units, err := s.Conn.AddUnits(svc, 1, "")
 
212
        c.Assert(err, IsNil)
 
213
        c.Check(opRecvTimeout(c, s.State, op, dummy.OpStartInstance{}), NotNil)
 
214
 
 
215
        // Wait for the instance id to show up in the state.
 
216
        id1, err := units[0].AssignedMachineId()
 
217
        c.Assert(err, IsNil)
 
218
        m1, err := s.State.Machine(id1)
 
219
        c.Assert(err, IsNil)
 
220
        w := m1.Watch()
 
221
        defer w.Stop()
 
222
        for _ = range w.Changes() {
 
223
                err = m1.Refresh()
 
224
                c.Assert(err, IsNil)
 
225
                if _, ok := m1.InstanceId(); ok {
 
226
                        break
 
227
                }
 
228
        }
 
229
        err = units[0].OpenPort("tcp", 999)
 
230
        c.Assert(err, IsNil)
 
231
 
 
232
        c.Check(opRecvTimeout(c, s.State, op, dummy.OpOpenPorts{}), NotNil)
 
233
 
 
234
        err = a.Stop()
 
235
        c.Assert(err, IsNil)
 
236
 
 
237
        select {
 
238
        case err := <-done:
 
239
                c.Assert(err, IsNil)
 
240
        case <-time.After(5 * time.Second):
 
241
                c.Fatalf("timed out waiting for agent to terminate")
 
242
        }
 
243
}
 
244
 
 
245
func (s *MachineSuite) TestUpgrade(c *C) {
 
246
        m, conf, currentTools := s.primeAgent(c, state.JobServeAPI, state.JobManageEnviron, state.JobHostUnits)
 
247
        addAPIInfo(conf, m)
 
248
        err := conf.Write()
 
249
        c.Assert(err, IsNil)
 
250
        a := s.newAgent(c, m)
 
251
        s.testUpgrade(c, a, currentTools)
 
252
}
 
253
 
 
254
func addAPIInfo(conf *agent.Conf, m *state.Machine) {
 
255
        port := testing.FindTCPPort()
 
256
        conf.APIInfo = &api.Info{
 
257
                Addrs:    []string{fmt.Sprintf("localhost:%d", port)},
 
258
                CACert:   []byte(testing.CACert),
 
259
                Tag:      m.Tag(),
 
260
                Password: "machine-api-password",
 
261
        }
 
262
        conf.StateServerCert = []byte(testing.ServerCert)
 
263
        conf.StateServerKey = []byte(testing.ServerKey)
 
264
        conf.APIPort = port
 
265
}
 
266
 
 
267
func (s *MachineSuite) TestServeAPI(c *C) {
 
268
        stm, conf, _ := s.primeAgent(c, state.JobServeAPI)
 
269
        addAPIInfo(conf, stm)
 
270
        err := conf.Write()
 
271
        c.Assert(err, IsNil)
 
272
        a := s.newAgent(c, stm)
 
273
        done := make(chan error)
 
274
        go func() {
 
275
                done <- a.Run(nil)
 
276
        }()
 
277
 
 
278
        st, err := api.Open(conf.APIInfo)
 
279
        c.Assert(err, IsNil)
 
280
        defer st.Close()
 
281
 
 
282
        m, err := st.Machine(stm.Id())
 
283
        c.Assert(err, IsNil)
 
284
 
 
285
        instId, ok := m.InstanceId()
 
286
        c.Assert(ok, Equals, true)
 
287
        c.Assert(instId, Equals, "ardbeg-0")
 
288
 
 
289
        err = a.Stop()
 
290
        c.Assert(err, IsNil)
 
291
 
 
292
        select {
 
293
        case err := <-done:
 
294
                c.Assert(err, IsNil)
 
295
        case <-time.After(5 * time.Second):
 
296
                c.Fatalf("timed out waiting for agent to terminate")
 
297
        }
 
298
}
 
299
 
 
300
var serveAPIWithBadConfTests = []struct {
 
301
        change func(c *agent.Conf)
 
302
        err    string
 
303
}{{
 
304
        func(c *agent.Conf) {
 
305
                c.StateServerCert = nil
 
306
        },
 
307
        "configuration does not have state server cert/key",
 
308
}, {
 
309
        func(c *agent.Conf) {
 
310
                c.StateServerKey = nil
 
311
        },
 
312
        "configuration does not have state server cert/key",
 
313
}}
 
314
 
 
315
func (s *MachineSuite) TestServeAPIWithBadConf(c *C) {
 
316
        m, conf, _ := s.primeAgent(c, state.JobServeAPI)
 
317
        addAPIInfo(conf, m)
 
318
        for i, t := range serveAPIWithBadConfTests {
 
319
                c.Logf("test %d: %q", i, t.err)
 
320
                conf1 := *conf
 
321
                t.change(&conf1)
 
322
                err := conf1.Write()
 
323
                c.Assert(err, IsNil)
 
324
                a := s.newAgent(c, m)
 
325
                err = runWithTimeout(a)
 
326
                c.Assert(err, ErrorMatches, t.err)
 
327
                err = refreshConfig(conf)
 
328
                c.Assert(err, IsNil)
 
329
        }
 
330
}
 
331
 
 
332
// opRecvTimeout waits for any of the given kinds of operation to
 
333
// be received from ops, and times out if not.
 
334
func opRecvTimeout(c *C, st *state.State, opc <-chan dummy.Operation, kinds ...dummy.Operation) dummy.Operation {
 
335
        st.StartSync()
 
336
        for {
 
337
                select {
 
338
                case op := <-opc:
 
339
                        for _, k := range kinds {
 
340
                                if reflect.TypeOf(op) == reflect.TypeOf(k) {
 
341
                                        return op
 
342
                                }
 
343
                        }
 
344
                        c.Logf("discarding unknown event %#v", op)
 
345
                case <-time.After(15 * time.Second):
 
346
                        c.Fatalf("time out wating for operation")
 
347
                }
 
348
        }
 
349
        panic("not reached")
 
350
}
 
351
 
 
352
func (s *MachineSuite) TestChangePasswordChanging(c *C) {
 
353
        m, _, _ := s.primeAgent(c, state.JobHostUnits)
 
354
        newAgent := func() runner {
 
355
                return s.newAgent(c, m)
 
356
        }
 
357
        s.testAgentPasswordChanging(c, m, newAgent)
 
358
}