~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/agent/agentbootstrap/bootstrap_test.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package agentbootstrap_test
 
5
 
 
6
import (
 
7
        "io/ioutil"
 
8
        "net"
 
9
        "path/filepath"
 
10
 
 
11
        "github.com/juju/names"
 
12
        gitjujutesting "github.com/juju/testing"
 
13
        jc "github.com/juju/testing/checkers"
 
14
        "github.com/juju/utils"
 
15
        "github.com/juju/utils/series"
 
16
        gc "gopkg.in/check.v1"
 
17
 
 
18
        "github.com/juju/juju/agent"
 
19
        "github.com/juju/juju/agent/agentbootstrap"
 
20
        "github.com/juju/juju/apiserver/params"
 
21
        "github.com/juju/juju/constraints"
 
22
        "github.com/juju/juju/environs"
 
23
        "github.com/juju/juju/environs/config"
 
24
        "github.com/juju/juju/instance"
 
25
        "github.com/juju/juju/mongo"
 
26
        "github.com/juju/juju/network"
 
27
        "github.com/juju/juju/provider/dummy"
 
28
        "github.com/juju/juju/state"
 
29
        "github.com/juju/juju/state/multiwatcher"
 
30
        "github.com/juju/juju/testing"
 
31
        jujuversion "github.com/juju/juju/version"
 
32
)
 
33
 
 
34
type bootstrapSuite struct {
 
35
        testing.BaseSuite
 
36
        mgoInst gitjujutesting.MgoInstance
 
37
}
 
38
 
 
39
var _ = gc.Suite(&bootstrapSuite{})
 
40
 
 
41
func (s *bootstrapSuite) SetUpTest(c *gc.C) {
 
42
        s.BaseSuite.SetUpTest(c)
 
43
        // Don't use MgoSuite, because we need to ensure
 
44
        // we have a fresh mongo for each test case.
 
45
        s.mgoInst.EnableAuth = true
 
46
        err := s.mgoInst.Start(testing.Certs)
 
47
        c.Assert(err, jc.ErrorIsNil)
 
48
}
 
49
 
 
50
func (s *bootstrapSuite) TearDownTest(c *gc.C) {
 
51
        s.mgoInst.Destroy()
 
52
        s.BaseSuite.TearDownTest(c)
 
53
}
 
54
 
 
55
func (s *bootstrapSuite) TestInitializeState(c *gc.C) {
 
56
        dataDir := c.MkDir()
 
57
 
 
58
        lxcFakeNetConfig := filepath.Join(c.MkDir(), "lxc-net")
 
59
        netConf := []byte(`
 
60
  # comments ignored
 
61
LXC_BR= ignored
 
62
LXC_ADDR = "fooo"
 
63
LXC_BRIDGE="foobar" # detected
 
64
anything else ignored
 
65
LXC_BRIDGE="ignored"`[1:])
 
66
        err := ioutil.WriteFile(lxcFakeNetConfig, netConf, 0644)
 
67
        c.Assert(err, jc.ErrorIsNil)
 
68
        s.PatchValue(&network.InterfaceByNameAddrs, func(name string) ([]net.Addr, error) {
 
69
                c.Assert(name, gc.Equals, "foobar")
 
70
                return []net.Addr{
 
71
                        &net.IPAddr{IP: net.IPv4(10, 0, 3, 1)},
 
72
                        &net.IPAddr{IP: net.IPv4(10, 0, 3, 4)},
 
73
                }, nil
 
74
        })
 
75
        s.PatchValue(&network.LXCNetDefaultConfig, lxcFakeNetConfig)
 
76
 
 
77
        configParams := agent.AgentConfigParams{
 
78
                Paths:             agent.Paths{DataDir: dataDir},
 
79
                Tag:               names.NewMachineTag("0"),
 
80
                UpgradedToVersion: jujuversion.Current,
 
81
                StateAddresses:    []string{s.mgoInst.Addr()},
 
82
                CACert:            testing.CACert,
 
83
                Password:          testing.DefaultMongoPassword,
 
84
                Model:             testing.ModelTag,
 
85
        }
 
86
        servingInfo := params.StateServingInfo{
 
87
                Cert:           testing.ServerCert,
 
88
                PrivateKey:     testing.ServerKey,
 
89
                CAPrivateKey:   testing.CAKey,
 
90
                APIPort:        1234,
 
91
                StatePort:      s.mgoInst.Port(),
 
92
                SystemIdentity: "def456",
 
93
        }
 
94
 
 
95
        cfg, err := agent.NewStateMachineConfig(configParams, servingInfo)
 
96
        c.Assert(err, jc.ErrorIsNil)
 
97
 
 
98
        _, available := cfg.StateServingInfo()
 
99
        c.Assert(available, jc.IsTrue)
 
100
        expectBootstrapConstraints := constraints.MustParse("mem=1024M")
 
101
        expectModelConstraints := constraints.MustParse("mem=512M")
 
102
        expectHW := instance.MustParseHardware("mem=2048M")
 
103
        initialAddrs := network.NewAddresses(
 
104
                "zeroonetwothree",
 
105
                "0.1.2.3",
 
106
                "10.0.3.1", // lxc bridge address filtered.
 
107
                "10.0.3.4", // lxc bridge address filtered (-"-).
 
108
                "10.0.3.3", // not a lxc bridge address
 
109
        )
 
110
        mcfg := agentbootstrap.BootstrapMachineConfig{
 
111
                Addresses:            initialAddrs,
 
112
                BootstrapConstraints: expectBootstrapConstraints,
 
113
                ModelConstraints:     expectModelConstraints,
 
114
                Jobs:                 []multiwatcher.MachineJob{multiwatcher.JobManageModel},
 
115
                InstanceId:           "i-bootstrap",
 
116
                Characteristics:      expectHW,
 
117
                SharedSecret:         "abc123",
 
118
        }
 
119
        filteredAddrs := network.NewAddresses(
 
120
                "zeroonetwothree",
 
121
                "0.1.2.3",
 
122
                "10.0.3.3",
 
123
        )
 
124
 
 
125
        // Prepare bootstrap config, so we can use it in the state policy.
 
126
        provider, err := environs.Provider("dummy")
 
127
        c.Assert(err, jc.ErrorIsNil)
 
128
        envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
 
129
                "agent-version":  jujuversion.Current.String(),
 
130
                "not-for-hosted": "foo",
 
131
        })
 
132
        envCfg, err := config.New(config.NoDefaults, envAttrs)
 
133
        c.Assert(err, jc.ErrorIsNil)
 
134
        envCfg, err = provider.BootstrapConfig(environs.BootstrapConfigParams{Config: envCfg})
 
135
        c.Assert(err, jc.ErrorIsNil)
 
136
        defer dummy.Reset()
 
137
 
 
138
        hostedModelUUID := utils.MustNewUUID().String()
 
139
        hostedModelConfigAttrs := map[string]interface{}{
 
140
                "name": "hosted",
 
141
                "uuid": hostedModelUUID,
 
142
        }
 
143
 
 
144
        adminUser := names.NewLocalUserTag("agent-admin")
 
145
        st, m, err := agentbootstrap.InitializeState(
 
146
                adminUser, cfg, envCfg, hostedModelConfigAttrs, mcfg,
 
147
                mongo.DefaultDialOpts(), environs.NewStatePolicy(),
 
148
        )
 
149
        c.Assert(err, jc.ErrorIsNil)
 
150
        defer st.Close()
 
151
 
 
152
        err = cfg.Write()
 
153
        c.Assert(err, jc.ErrorIsNil)
 
154
 
 
155
        // Check that the environment has been set up.
 
156
        env, err := st.Model()
 
157
        c.Assert(err, jc.ErrorIsNil)
 
158
        c.Assert(env.UUID(), gc.Equals, envCfg.UUID())
 
159
 
 
160
        // Check that initial admin user has been set up correctly.
 
161
        modelTag := env.Tag().(names.ModelTag)
 
162
        s.assertCanLogInAsAdmin(c, modelTag, testing.DefaultMongoPassword)
 
163
        user, err := st.User(env.Owner())
 
164
        c.Assert(err, jc.ErrorIsNil)
 
165
        c.Assert(user.PasswordValid(testing.DefaultMongoPassword), jc.IsTrue)
 
166
 
 
167
        // Check that controller model configuration has been added, and
 
168
        // model constraints set.
 
169
        newEnvCfg, err := st.ModelConfig()
 
170
        c.Assert(err, jc.ErrorIsNil)
 
171
        c.Assert(newEnvCfg.AllAttrs(), gc.DeepEquals, envCfg.AllAttrs())
 
172
        gotModelConstraints, err := st.ModelConstraints()
 
173
        c.Assert(err, jc.ErrorIsNil)
 
174
        c.Assert(gotModelConstraints, gc.DeepEquals, expectModelConstraints)
 
175
 
 
176
        // Check that the hosted model has been added, and model constraints
 
177
        // set.
 
178
        hostedModelSt, err := st.ForModel(names.NewModelTag(hostedModelUUID))
 
179
        c.Assert(err, jc.ErrorIsNil)
 
180
        defer hostedModelSt.Close()
 
181
        gotModelConstraints, err = hostedModelSt.ModelConstraints()
 
182
        c.Assert(err, jc.ErrorIsNil)
 
183
        c.Assert(gotModelConstraints, gc.DeepEquals, expectModelConstraints)
 
184
        hostedModel, err := hostedModelSt.Model()
 
185
        c.Assert(err, jc.ErrorIsNil)
 
186
        c.Assert(hostedModel.Name(), gc.Equals, "hosted")
 
187
        hostedCfg, err := hostedModelSt.ModelConfig()
 
188
        c.Assert(err, jc.ErrorIsNil)
 
189
        _, hasUnexpected := hostedCfg.AllAttrs()["not-for-hosted"]
 
190
        c.Assert(hasUnexpected, jc.IsFalse)
 
191
 
 
192
        // Check that the bootstrap machine looks correct.
 
193
        c.Assert(m.Id(), gc.Equals, "0")
 
194
        c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageModel})
 
195
        c.Assert(m.Series(), gc.Equals, series.HostSeries())
 
196
        c.Assert(m.CheckProvisioned(agent.BootstrapNonce), jc.IsTrue)
 
197
        c.Assert(m.Addresses(), jc.DeepEquals, filteredAddrs)
 
198
        gotBootstrapConstraints, err := m.Constraints()
 
199
        c.Assert(err, jc.ErrorIsNil)
 
200
        c.Assert(gotBootstrapConstraints, gc.DeepEquals, expectBootstrapConstraints)
 
201
        c.Assert(err, jc.ErrorIsNil)
 
202
        gotHW, err := m.HardwareCharacteristics()
 
203
        c.Assert(err, jc.ErrorIsNil)
 
204
        c.Assert(*gotHW, gc.DeepEquals, expectHW)
 
205
 
 
206
        // Check that the API host ports are initialised correctly.
 
207
        apiHostPorts, err := st.APIHostPorts()
 
208
        c.Assert(err, jc.ErrorIsNil)
 
209
        c.Assert(apiHostPorts, jc.DeepEquals, [][]network.HostPort{
 
210
                network.AddressesWithPort(filteredAddrs, 1234),
 
211
        })
 
212
 
 
213
        // Check that the state serving info is initialised correctly.
 
214
        stateServingInfo, err := st.StateServingInfo()
 
215
        c.Assert(err, jc.ErrorIsNil)
 
216
        c.Assert(stateServingInfo, jc.DeepEquals, state.StateServingInfo{
 
217
                APIPort:        1234,
 
218
                StatePort:      s.mgoInst.Port(),
 
219
                Cert:           testing.ServerCert,
 
220
                PrivateKey:     testing.ServerKey,
 
221
                CAPrivateKey:   testing.CAKey,
 
222
                SharedSecret:   "abc123",
 
223
                SystemIdentity: "def456",
 
224
        })
 
225
 
 
226
        // Check that the machine agent's config has been written
 
227
        // and that we can use it to connect to the state.
 
228
        machine0 := names.NewMachineTag("0")
 
229
        newCfg, err := agent.ReadConfig(agent.ConfigPath(dataDir, machine0))
 
230
        c.Assert(err, jc.ErrorIsNil)
 
231
        c.Assert(newCfg.Tag(), gc.Equals, machine0)
 
232
        info, ok := cfg.MongoInfo()
 
233
        c.Assert(ok, jc.IsTrue)
 
234
        c.Assert(info.Password, gc.Not(gc.Equals), testing.DefaultMongoPassword)
 
235
        st1, err := state.Open(newCfg.Model(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
 
236
        c.Assert(err, jc.ErrorIsNil)
 
237
        defer st1.Close()
 
238
}
 
239
 
 
240
func (s *bootstrapSuite) TestInitializeStateWithStateServingInfoNotAvailable(c *gc.C) {
 
241
        configParams := agent.AgentConfigParams{
 
242
                Paths:             agent.Paths{DataDir: c.MkDir()},
 
243
                Tag:               names.NewMachineTag("0"),
 
244
                UpgradedToVersion: jujuversion.Current,
 
245
                StateAddresses:    []string{s.mgoInst.Addr()},
 
246
                CACert:            testing.CACert,
 
247
                Password:          "fake",
 
248
                Model:             testing.ModelTag,
 
249
        }
 
250
        cfg, err := agent.NewAgentConfig(configParams)
 
251
        c.Assert(err, jc.ErrorIsNil)
 
252
 
 
253
        _, available := cfg.StateServingInfo()
 
254
        c.Assert(available, jc.IsFalse)
 
255
 
 
256
        adminUser := names.NewLocalUserTag("agent-admin")
 
257
        _, _, err = agentbootstrap.InitializeState(adminUser, cfg, nil, nil, agentbootstrap.BootstrapMachineConfig{}, mongo.DefaultDialOpts(), environs.NewStatePolicy())
 
258
        // InitializeState will fail attempting to get the api port information
 
259
        c.Assert(err, gc.ErrorMatches, "state serving information not available")
 
260
}
 
261
 
 
262
func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
 
263
        dataDir := c.MkDir()
 
264
 
 
265
        configParams := agent.AgentConfigParams{
 
266
                Paths:             agent.Paths{DataDir: dataDir},
 
267
                Tag:               names.NewMachineTag("0"),
 
268
                UpgradedToVersion: jujuversion.Current,
 
269
                StateAddresses:    []string{s.mgoInst.Addr()},
 
270
                CACert:            testing.CACert,
 
271
                Password:          testing.DefaultMongoPassword,
 
272
                Model:             testing.ModelTag,
 
273
        }
 
274
        cfg, err := agent.NewAgentConfig(configParams)
 
275
        c.Assert(err, jc.ErrorIsNil)
 
276
        cfg.SetStateServingInfo(params.StateServingInfo{
 
277
                APIPort:        5555,
 
278
                StatePort:      s.mgoInst.Port(),
 
279
                Cert:           "foo",
 
280
                PrivateKey:     "bar",
 
281
                SharedSecret:   "baz",
 
282
                SystemIdentity: "qux",
 
283
        })
 
284
        expectHW := instance.MustParseHardware("mem=2048M")
 
285
        mcfg := agentbootstrap.BootstrapMachineConfig{
 
286
                BootstrapConstraints: constraints.MustParse("mem=1024M"),
 
287
                Jobs:                 []multiwatcher.MachineJob{multiwatcher.JobManageModel},
 
288
                InstanceId:           "i-bootstrap",
 
289
                Characteristics:      expectHW,
 
290
        }
 
291
        envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
 
292
                "agent-version": jujuversion.Current.String(),
 
293
        })
 
294
        envCfg, err := config.New(config.NoDefaults, envAttrs)
 
295
        c.Assert(err, jc.ErrorIsNil)
 
296
 
 
297
        hostedModelConfigAttrs := map[string]interface{}{
 
298
                "name": "hosted",
 
299
                "uuid": utils.MustNewUUID().String(),
 
300
        }
 
301
 
 
302
        adminUser := names.NewLocalUserTag("agent-admin")
 
303
        st, _, err := agentbootstrap.InitializeState(
 
304
                adminUser, cfg, envCfg, hostedModelConfigAttrs, mcfg,
 
305
                mongo.DefaultDialOpts(), state.Policy(nil),
 
306
        )
 
307
        c.Assert(err, jc.ErrorIsNil)
 
308
        st.Close()
 
309
 
 
310
        st, _, err = agentbootstrap.InitializeState(adminUser, cfg, envCfg, nil, mcfg, mongo.DefaultDialOpts(), environs.NewStatePolicy())
 
311
        if err == nil {
 
312
                st.Close()
 
313
        }
 
314
        c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*")
 
315
}
 
316
 
 
317
func (s *bootstrapSuite) TestMachineJobFromParams(c *gc.C) {
 
318
        var tests = []struct {
 
319
                name multiwatcher.MachineJob
 
320
                want state.MachineJob
 
321
                err  string
 
322
        }{{
 
323
                name: multiwatcher.JobHostUnits,
 
324
                want: state.JobHostUnits,
 
325
        }, {
 
326
                name: multiwatcher.JobManageModel,
 
327
                want: state.JobManageModel,
 
328
        }, {
 
329
                name: multiwatcher.JobManageNetworking,
 
330
                want: state.JobManageNetworking,
 
331
        }, {
 
332
                name: "invalid",
 
333
                want: -1,
 
334
                err:  `invalid machine job "invalid"`,
 
335
        }}
 
336
        for _, test := range tests {
 
337
                got, err := agentbootstrap.MachineJobFromParams(test.name)
 
338
                if err != nil {
 
339
                        c.Check(err, gc.ErrorMatches, test.err)
 
340
                }
 
341
                c.Check(got, gc.Equals, test.want)
 
342
        }
 
343
}
 
344
 
 
345
func (s *bootstrapSuite) assertCanLogInAsAdmin(c *gc.C, modelTag names.ModelTag, password string) {
 
346
        info := &mongo.MongoInfo{
 
347
                Info: mongo.Info{
 
348
                        Addrs:  []string{s.mgoInst.Addr()},
 
349
                        CACert: testing.CACert,
 
350
                },
 
351
                Tag:      nil, // admin user
 
352
                Password: password,
 
353
        }
 
354
        st, err := state.Open(modelTag, info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
 
355
        c.Assert(err, jc.ErrorIsNil)
 
356
        defer st.Close()
 
357
        _, err = st.Machine("0")
 
358
        c.Assert(err, jc.ErrorIsNil)
 
359
}