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