github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/agent/agentbootstrap/bootstrap_test.go (about) 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(c) 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 }