github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/agent/bootstrap_test.go (about) 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.DialOpts{}, 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 s.assertCanLogInAsAdmin(c, pwHash) 161 user, err := st.User(env.Owner()) 162 c.Assert(err, jc.ErrorIsNil) 163 c.Assert(user.PasswordValid(testing.DefaultMongoPassword), jc.IsTrue) 164 165 // Check that environment configuration has been added. 166 newEnvCfg, err := st.EnvironConfig() 167 c.Assert(err, jc.ErrorIsNil) 168 c.Assert(newEnvCfg.AllAttrs(), gc.DeepEquals, envCfg.AllAttrs()) 169 170 // Check that the bootstrap machine looks correct. 171 c.Assert(m.Id(), gc.Equals, "0") 172 c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageEnviron}) 173 c.Assert(m.Series(), gc.Equals, version.Current.Series) 174 c.Assert(m.CheckProvisioned(agent.BootstrapNonce), jc.IsTrue) 175 c.Assert(m.Addresses(), jc.DeepEquals, filteredAddrs) 176 gotConstraints, err := m.Constraints() 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(gotConstraints, gc.DeepEquals, expectConstraints) 179 c.Assert(err, jc.ErrorIsNil) 180 gotHW, err := m.HardwareCharacteristics() 181 c.Assert(err, jc.ErrorIsNil) 182 c.Assert(*gotHW, gc.DeepEquals, expectHW) 183 184 // Check that the API host ports are initialised correctly. 185 apiHostPorts, err := st.APIHostPorts() 186 c.Assert(err, jc.ErrorIsNil) 187 c.Assert(apiHostPorts, jc.DeepEquals, [][]network.HostPort{ 188 network.AddressesWithPort(filteredAddrs, 1234), 189 }) 190 191 // Check that the state serving info is initialised correctly. 192 stateServingInfo, err := st.StateServingInfo() 193 c.Assert(err, jc.ErrorIsNil) 194 c.Assert(stateServingInfo, jc.DeepEquals, state.StateServingInfo{ 195 APIPort: 1234, 196 StatePort: s.mgoInst.Port(), 197 Cert: testing.ServerCert, 198 PrivateKey: testing.ServerKey, 199 CAPrivateKey: testing.CAKey, 200 SharedSecret: "abc123", 201 SystemIdentity: "def456", 202 }) 203 204 // Check that the machine agent's config has been written 205 // and that we can use it to connect to the state. 206 machine0 := names.NewMachineTag("0") 207 newCfg, err := agent.ReadConfig(agent.ConfigPath(dataDir, machine0)) 208 c.Assert(err, jc.ErrorIsNil) 209 c.Assert(newCfg.Tag(), gc.Equals, machine0) 210 c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), pwHash) 211 c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), testing.DefaultMongoPassword) 212 info, ok := cfg.MongoInfo() 213 c.Assert(ok, jc.IsTrue) 214 st1, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) 215 c.Assert(err, jc.ErrorIsNil) 216 defer st1.Close() 217 } 218 219 func (s *bootstrapSuite) TestInitializeStateWithStateServingInfoNotAvailable(c *gc.C) { 220 configParams := agent.AgentConfigParams{ 221 DataDir: c.MkDir(), 222 Tag: names.NewMachineTag("0"), 223 UpgradedToVersion: version.Current.Number, 224 StateAddresses: []string{s.mgoInst.Addr()}, 225 CACert: testing.CACert, 226 Password: "fake", 227 Environment: testing.EnvironmentTag, 228 } 229 cfg, err := agent.NewAgentConfig(configParams) 230 c.Assert(err, jc.ErrorIsNil) 231 232 _, available := cfg.StateServingInfo() 233 c.Assert(available, jc.IsFalse) 234 235 adminUser := names.NewLocalUserTag("agent-admin") 236 _, _, err = agent.InitializeState(adminUser, cfg, nil, agent.BootstrapMachineConfig{}, mongo.DialOpts{}, environs.NewStatePolicy()) 237 // InitializeState will fail attempting to get the api port information 238 c.Assert(err, gc.ErrorMatches, "state serving information not available") 239 } 240 241 func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) { 242 dataDir := c.MkDir() 243 244 pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt) 245 configParams := agent.AgentConfigParams{ 246 DataDir: dataDir, 247 Tag: names.NewMachineTag("0"), 248 UpgradedToVersion: version.Current.Number, 249 StateAddresses: []string{s.mgoInst.Addr()}, 250 CACert: testing.CACert, 251 Password: pwHash, 252 Environment: testing.EnvironmentTag, 253 } 254 cfg, err := agent.NewAgentConfig(configParams) 255 c.Assert(err, jc.ErrorIsNil) 256 cfg.SetStateServingInfo(params.StateServingInfo{ 257 APIPort: 5555, 258 StatePort: s.mgoInst.Port(), 259 Cert: "foo", 260 PrivateKey: "bar", 261 SharedSecret: "baz", 262 SystemIdentity: "qux", 263 }) 264 expectConstraints := constraints.MustParse("mem=1024M") 265 expectHW := instance.MustParseHardware("mem=2048M") 266 mcfg := agent.BootstrapMachineConfig{ 267 Constraints: expectConstraints, 268 Jobs: []multiwatcher.MachineJob{multiwatcher.JobManageEnviron}, 269 InstanceId: "i-bootstrap", 270 Characteristics: expectHW, 271 } 272 envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{ 273 "agent-version": version.Current.Number.String(), 274 "state-id": "1", // needed so policy can Open config 275 }) 276 envCfg, err := config.New(config.NoDefaults, envAttrs) 277 c.Assert(err, jc.ErrorIsNil) 278 279 adminUser := names.NewLocalUserTag("agent-admin") 280 st, _, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) 281 c.Assert(err, jc.ErrorIsNil) 282 st.Close() 283 284 st, _, err = agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) 285 if err == nil { 286 st.Close() 287 } 288 c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*") 289 } 290 291 func (s *bootstrapSuite) TestMachineJobFromParams(c *gc.C) { 292 var tests = []struct { 293 name multiwatcher.MachineJob 294 want state.MachineJob 295 err string 296 }{{ 297 name: multiwatcher.JobHostUnits, 298 want: state.JobHostUnits, 299 }, { 300 name: multiwatcher.JobManageEnviron, 301 want: state.JobManageEnviron, 302 }, { 303 name: multiwatcher.JobManageNetworking, 304 want: state.JobManageNetworking, 305 }, { 306 name: multiwatcher.JobManageStateDeprecated, 307 want: state.JobManageStateDeprecated, 308 }, { 309 name: "invalid", 310 want: -1, 311 err: `invalid machine job "invalid"`, 312 }} 313 for _, test := range tests { 314 got, err := agent.MachineJobFromParams(test.name) 315 if err != nil { 316 c.Check(err, gc.ErrorMatches, test.err) 317 } 318 c.Check(got, gc.Equals, test.want) 319 } 320 } 321 322 func (s *bootstrapSuite) assertCanLogInAsAdmin(c *gc.C, password string) { 323 info := &mongo.MongoInfo{ 324 Info: mongo.Info{ 325 Addrs: []string{s.mgoInst.Addr()}, 326 CACert: testing.CACert, 327 }, 328 Tag: nil, // admin user 329 Password: password, 330 } 331 st, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) 332 c.Assert(err, jc.ErrorIsNil) 333 defer st.Close() 334 _, err = st.Machine("0") 335 c.Assert(err, jc.ErrorIsNil) 336 }