~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/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 agent_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/apiserver/params"
20
 
        "github.com/juju/juju/constraints"
21
 
        "github.com/juju/juju/environs"
22
 
        "github.com/juju/juju/environs/config"
23
 
        "github.com/juju/juju/instance"
24
 
        "github.com/juju/juju/mongo"
25
 
        "github.com/juju/juju/network"
26
 
        "github.com/juju/juju/provider/dummy"
27
 
        "github.com/juju/juju/state"
28
 
        "github.com/juju/juju/state/multiwatcher"
29
 
        "github.com/juju/juju/testing"
30
 
        "github.com/juju/juju/version"
31
 
)
32
 
 
33
 
type bootstrapSuite struct {
34
 
        testing.BaseSuite
35
 
        mgoInst gitjujutesting.MgoInstance
36
 
}
37
 
 
38
 
var _ = gc.Suite(&bootstrapSuite{})
39
 
 
40
 
func (s *bootstrapSuite) SetUpTest(c *gc.C) {
41
 
        s.BaseSuite.SetUpTest(c)
42
 
        // Don't use MgoSuite, because we need to ensure
43
 
        // we have a fresh mongo for each test case.
44
 
        s.mgoInst.EnableAuth = true
45
 
        err := s.mgoInst.Start(testing.Certs)
46
 
        c.Assert(err, jc.ErrorIsNil)
47
 
}
48
 
 
49
 
func (s *bootstrapSuite) TearDownTest(c *gc.C) {
50
 
        s.mgoInst.Destroy()
51
 
        s.BaseSuite.TearDownTest(c)
52
 
}
53
 
 
54
 
func (s *bootstrapSuite) TestInitializeState(c *gc.C) {
55
 
        dataDir := c.MkDir()
56
 
 
57
 
        lxcFakeNetConfig := filepath.Join(c.MkDir(), "lxc-net")
58
 
        netConf := []byte(`
59
 
  # comments ignored
60
 
LXC_BR= ignored
61
 
LXC_ADDR = "fooo"
62
 
LXC_BRIDGE="foobar" # detected
63
 
anything else ignored
64
 
LXC_BRIDGE="ignored"`[1:])
65
 
        err := ioutil.WriteFile(lxcFakeNetConfig, netConf, 0644)
66
 
        c.Assert(err, jc.ErrorIsNil)
67
 
        s.PatchValue(&network.InterfaceByNameAddrs, func(name string) ([]net.Addr, error) {
68
 
                c.Assert(name, gc.Equals, "foobar")
69
 
                return []net.Addr{
70
 
                        &net.IPAddr{IP: net.IPv4(10, 0, 3, 1)},
71
 
                        &net.IPAddr{IP: net.IPv4(10, 0, 3, 4)},
72
 
                }, nil
73
 
        })
74
 
        s.PatchValue(&network.LXCNetDefaultConfig, lxcFakeNetConfig)
75
 
 
76
 
        pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt)
77
 
        configParams := agent.AgentConfigParams{
78
 
                Paths:             agent.Paths{DataDir: dataDir},
79
 
                Tag:               names.NewMachineTag("0"),
80
 
                UpgradedToVersion: version.Current,
81
 
                StateAddresses:    []string{s.mgoInst.Addr()},
82
 
                CACert:            testing.CACert,
83
 
                Password:          pwHash,
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 := agent.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
 
        envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
125
 
                "agent-version": version.Current.String(),
126
 
                "state-id":      "1", // needed so policy can Open config
127
 
        })
128
 
        envCfg, err := config.New(config.NoDefaults, envAttrs)
129
 
        c.Assert(err, jc.ErrorIsNil)
130
 
 
131
 
        adminUser := names.NewLocalUserTag("agent-admin")
132
 
        st, m, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DefaultDialOpts(), environs.NewStatePolicy())
133
 
        c.Assert(err, jc.ErrorIsNil)
134
 
        defer st.Close()
135
 
 
136
 
        err = cfg.Write()
137
 
        c.Assert(err, jc.ErrorIsNil)
138
 
 
139
 
        // Check that the environment has been set up.
140
 
        env, err := st.Model()
141
 
        c.Assert(err, jc.ErrorIsNil)
142
 
        uuid, ok := envCfg.UUID()
143
 
        c.Assert(ok, jc.IsTrue)
144
 
        c.Assert(env.UUID(), gc.Equals, uuid)
145
 
 
146
 
        // Check that initial admin user has been set up correctly.
147
 
        modelTag := env.Tag().(names.ModelTag)
148
 
        s.assertCanLogInAsAdmin(c, modelTag, pwHash)
149
 
        user, err := st.User(env.Owner())
150
 
        c.Assert(err, jc.ErrorIsNil)
151
 
        c.Assert(user.PasswordValid(testing.DefaultMongoPassword), jc.IsTrue)
152
 
 
153
 
        // Check that model configuration has been added, and
154
 
        // model constraints set.
155
 
        newEnvCfg, err := st.ModelConfig()
156
 
        c.Assert(err, jc.ErrorIsNil)
157
 
        c.Assert(newEnvCfg.AllAttrs(), gc.DeepEquals, envCfg.AllAttrs())
158
 
        gotModelConstraints, err := st.ModelConstraints()
159
 
        c.Assert(err, jc.ErrorIsNil)
160
 
        c.Assert(gotModelConstraints, gc.DeepEquals, expectModelConstraints)
161
 
 
162
 
        // Check that the bootstrap machine looks correct.
163
 
        c.Assert(m.Id(), gc.Equals, "0")
164
 
        c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageModel})
165
 
        c.Assert(m.Series(), gc.Equals, series.HostSeries())
166
 
        c.Assert(m.CheckProvisioned(agent.BootstrapNonce), jc.IsTrue)
167
 
        c.Assert(m.Addresses(), jc.DeepEquals, filteredAddrs)
168
 
        gotBootstrapConstraints, err := m.Constraints()
169
 
        c.Assert(err, jc.ErrorIsNil)
170
 
        c.Assert(gotBootstrapConstraints, gc.DeepEquals, expectBootstrapConstraints)
171
 
        c.Assert(err, jc.ErrorIsNil)
172
 
        gotHW, err := m.HardwareCharacteristics()
173
 
        c.Assert(err, jc.ErrorIsNil)
174
 
        c.Assert(*gotHW, gc.DeepEquals, expectHW)
175
 
 
176
 
        // Check that the API host ports are initialised correctly.
177
 
        apiHostPorts, err := st.APIHostPorts()
178
 
        c.Assert(err, jc.ErrorIsNil)
179
 
        c.Assert(apiHostPorts, jc.DeepEquals, [][]network.HostPort{
180
 
                network.AddressesWithPort(filteredAddrs, 1234),
181
 
        })
182
 
 
183
 
        // Check that the state serving info is initialised correctly.
184
 
        stateServingInfo, err := st.StateServingInfo()
185
 
        c.Assert(err, jc.ErrorIsNil)
186
 
        c.Assert(stateServingInfo, jc.DeepEquals, state.StateServingInfo{
187
 
                APIPort:        1234,
188
 
                StatePort:      s.mgoInst.Port(),
189
 
                Cert:           testing.ServerCert,
190
 
                PrivateKey:     testing.ServerKey,
191
 
                CAPrivateKey:   testing.CAKey,
192
 
                SharedSecret:   "abc123",
193
 
                SystemIdentity: "def456",
194
 
        })
195
 
 
196
 
        // Check that the machine agent's config has been written
197
 
        // and that we can use it to connect to the state.
198
 
        machine0 := names.NewMachineTag("0")
199
 
        newCfg, err := agent.ReadConfig(agent.ConfigPath(dataDir, machine0))
200
 
        c.Assert(err, jc.ErrorIsNil)
201
 
        c.Assert(newCfg.Tag(), gc.Equals, machine0)
202
 
        c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), pwHash)
203
 
        c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), testing.DefaultMongoPassword)
204
 
        info, ok := cfg.MongoInfo()
205
 
        c.Assert(ok, jc.IsTrue)
206
 
        st1, err := state.Open(newCfg.Model(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
207
 
        c.Assert(err, jc.ErrorIsNil)
208
 
        defer st1.Close()
209
 
}
210
 
 
211
 
func (s *bootstrapSuite) TestInitializeStateWithStateServingInfoNotAvailable(c *gc.C) {
212
 
        configParams := agent.AgentConfigParams{
213
 
                Paths:             agent.Paths{DataDir: c.MkDir()},
214
 
                Tag:               names.NewMachineTag("0"),
215
 
                UpgradedToVersion: version.Current,
216
 
                StateAddresses:    []string{s.mgoInst.Addr()},
217
 
                CACert:            testing.CACert,
218
 
                Password:          "fake",
219
 
                Model:             testing.ModelTag,
220
 
        }
221
 
        cfg, err := agent.NewAgentConfig(configParams)
222
 
        c.Assert(err, jc.ErrorIsNil)
223
 
 
224
 
        _, available := cfg.StateServingInfo()
225
 
        c.Assert(available, jc.IsFalse)
226
 
 
227
 
        adminUser := names.NewLocalUserTag("agent-admin")
228
 
        _, _, err = agent.InitializeState(adminUser, cfg, nil, agent.BootstrapMachineConfig{}, mongo.DefaultDialOpts(), environs.NewStatePolicy())
229
 
        // InitializeState will fail attempting to get the api port information
230
 
        c.Assert(err, gc.ErrorMatches, "state serving information not available")
231
 
}
232
 
 
233
 
func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
234
 
        dataDir := c.MkDir()
235
 
 
236
 
        pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt)
237
 
        configParams := agent.AgentConfigParams{
238
 
                Paths:             agent.Paths{DataDir: dataDir},
239
 
                Tag:               names.NewMachineTag("0"),
240
 
                UpgradedToVersion: version.Current,
241
 
                StateAddresses:    []string{s.mgoInst.Addr()},
242
 
                CACert:            testing.CACert,
243
 
                Password:          pwHash,
244
 
                Model:             testing.ModelTag,
245
 
        }
246
 
        cfg, err := agent.NewAgentConfig(configParams)
247
 
        c.Assert(err, jc.ErrorIsNil)
248
 
        cfg.SetStateServingInfo(params.StateServingInfo{
249
 
                APIPort:        5555,
250
 
                StatePort:      s.mgoInst.Port(),
251
 
                Cert:           "foo",
252
 
                PrivateKey:     "bar",
253
 
                SharedSecret:   "baz",
254
 
                SystemIdentity: "qux",
255
 
        })
256
 
        expectHW := instance.MustParseHardware("mem=2048M")
257
 
        mcfg := agent.BootstrapMachineConfig{
258
 
                BootstrapConstraints: constraints.MustParse("mem=1024M"),
259
 
                Jobs:                 []multiwatcher.MachineJob{multiwatcher.JobManageModel},
260
 
                InstanceId:           "i-bootstrap",
261
 
                Characteristics:      expectHW,
262
 
        }
263
 
        envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
264
 
                "agent-version": version.Current.String(),
265
 
                "state-id":      "1", // needed so policy can Open config
266
 
        })
267
 
        envCfg, err := config.New(config.NoDefaults, envAttrs)
268
 
        c.Assert(err, jc.ErrorIsNil)
269
 
 
270
 
        adminUser := names.NewLocalUserTag("agent-admin")
271
 
        st, _, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DefaultDialOpts(), environs.NewStatePolicy())
272
 
        c.Assert(err, jc.ErrorIsNil)
273
 
        st.Close()
274
 
 
275
 
        st, _, err = agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DefaultDialOpts(), environs.NewStatePolicy())
276
 
        if err == nil {
277
 
                st.Close()
278
 
        }
279
 
        c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*")
280
 
}
281
 
 
282
 
func (s *bootstrapSuite) TestMachineJobFromParams(c *gc.C) {
283
 
        var tests = []struct {
284
 
                name multiwatcher.MachineJob
285
 
                want state.MachineJob
286
 
                err  string
287
 
        }{{
288
 
                name: multiwatcher.JobHostUnits,
289
 
                want: state.JobHostUnits,
290
 
        }, {
291
 
                name: multiwatcher.JobManageModel,
292
 
                want: state.JobManageModel,
293
 
        }, {
294
 
                name: multiwatcher.JobManageNetworking,
295
 
                want: state.JobManageNetworking,
296
 
        }, {
297
 
                name: "invalid",
298
 
                want: -1,
299
 
                err:  `invalid machine job "invalid"`,
300
 
        }}
301
 
        for _, test := range tests {
302
 
                got, err := agent.MachineJobFromParams(test.name)
303
 
                if err != nil {
304
 
                        c.Check(err, gc.ErrorMatches, test.err)
305
 
                }
306
 
                c.Check(got, gc.Equals, test.want)
307
 
        }
308
 
}
309
 
 
310
 
func (s *bootstrapSuite) assertCanLogInAsAdmin(c *gc.C, modelTag names.ModelTag, password string) {
311
 
        info := &mongo.MongoInfo{
312
 
                Info: mongo.Info{
313
 
                        Addrs:  []string{s.mgoInst.Addr()},
314
 
                        CACert: testing.CACert,
315
 
                },
316
 
                Tag:      nil, // admin user
317
 
                Password: password,
318
 
        }
319
 
        st, err := state.Open(modelTag, info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
320
 
        c.Assert(err, jc.ErrorIsNil)
321
 
        defer st.Close()
322
 
        _, err = st.Machine("0")
323
 
        c.Assert(err, jc.ErrorIsNil)
324
 
}