~juju-qa/ubuntu/trusty/juju/juju-1.25.8

« back to all changes in this revision

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

  • Committer: Nicholas Skaggs
  • Date: 2016-12-02 18:01:10 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161202180110-dl1helep8qfebmhx
ImportĀ upstreamĀ 1.25.6

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