github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/featuretests/leadership_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package featuretests 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "time" 10 11 "github.com/juju/names" 12 gitjujutesting "github.com/juju/testing" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/agent" 16 "github.com/juju/juju/api/base" 17 "github.com/juju/juju/api/leadership" 18 "github.com/juju/juju/api/uniter" 19 leadershipapi "github.com/juju/juju/apiserver/leadership" 20 "github.com/juju/juju/apiserver/params" 21 agentcmd "github.com/juju/juju/cmd/jujud/agent" 22 agenttesting "github.com/juju/juju/cmd/jujud/agent/testing" 23 cmdutil "github.com/juju/juju/cmd/jujud/util" 24 "github.com/juju/juju/mongo" 25 "github.com/juju/juju/state" 26 coretesting "github.com/juju/juju/testing" 27 "github.com/juju/juju/testing/factory" 28 "github.com/juju/juju/version" 29 ) 30 31 type leadershipSuite struct { 32 agenttesting.AgentSuite 33 34 clientFacade base.ClientFacade 35 facadeCaller base.FacadeCaller 36 machineAgent *agentcmd.MachineAgent 37 unitId string 38 serviceId string 39 } 40 41 func (s *leadershipSuite) SetUpTest(c *gc.C) { 42 43 s.AgentSuite.SetUpTest(c) 44 45 file, _ := ioutil.TempFile("", "juju-run") 46 defer file.Close() 47 s.AgentSuite.PatchValue(&agentcmd.JujuRun, file.Name()) 48 49 fakeEnsureMongo := agenttesting.FakeEnsure{} 50 s.AgentSuite.PatchValue(&cmdutil.EnsureMongoServer, fakeEnsureMongo.FakeEnsureMongo) 51 52 // Create a machine to manage the environment. 53 stateServer, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{ 54 InstanceId: "id-1", 55 Nonce: agent.BootstrapNonce, 56 Jobs: []state.MachineJob{state.JobManageEnviron}, 57 }) 58 c.Assert(stateServer.PasswordValid(password), gc.Equals, true) 59 c.Assert(stateServer.SetMongoPassword(password), gc.IsNil) 60 61 // Create a machine to host some units. 62 unitHostMachine := s.Factory.MakeMachine(c, &factory.MachineParams{ 63 Nonce: agent.BootstrapNonce, 64 Password: password, 65 }) 66 67 // Create a service and an instance of that service so that we can 68 // create a client. 69 service := s.Factory.MakeService(c, &factory.ServiceParams{}) 70 s.serviceId = service.Tag().Id() 71 72 unit := s.Factory.MakeUnit(c, &factory.UnitParams{Machine: unitHostMachine, Service: service}) 73 s.unitId = unit.UnitTag().Id() 74 75 c.Assert(unit.SetPassword(password), gc.IsNil) 76 unitState := s.OpenAPIAs(c, unit.Tag(), password) 77 78 // Create components needed to construct a client. 79 s.clientFacade, s.facadeCaller = base.NewClientFacade(unitState, leadershipapi.FacadeName) 80 c.Assert(s.clientFacade, gc.NotNil) 81 c.Assert(s.facadeCaller, gc.NotNil) 82 83 // Tweak and write out the config file for the state server. 84 writeStateAgentConfig( 85 c, 86 s.MongoInfo(c), 87 s.DataDir(), 88 stateServer.Tag(), 89 s.State.EnvironTag(), 90 password, 91 version.Current, 92 ) 93 94 // Create & start a machine agent so the tests have something to call into. 95 agentConf := agentcmd.AgentConf{DataDir: s.DataDir()} 96 machineAgentFactory := agentcmd.MachineAgentFactoryFn(&agentConf, &agentConf) 97 s.machineAgent = machineAgentFactory(stateServer.Id()) 98 99 c.Log("Starting machine agent...") 100 go func() { 101 err := s.machineAgent.Run(coretesting.Context(c)) 102 c.Assert(err, gc.IsNil) 103 }() 104 } 105 106 func (s *leadershipSuite) TearDownTest(c *gc.C) { 107 c.Log("Stopping machine agent...") 108 err := s.machineAgent.Stop() 109 c.Assert(err, gc.IsNil) 110 111 s.AgentSuite.TearDownTest(c) 112 } 113 114 func (s *leadershipSuite) TestClaimLeadership(c *gc.C) { 115 116 client := leadership.NewClient(s.clientFacade, s.facadeCaller) 117 defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }() 118 119 duration, err := client.ClaimLeadership(s.serviceId, s.unitId) 120 121 c.Assert(err, gc.IsNil) 122 c.Check(duration, gc.Equals, 30*time.Second) 123 } 124 125 func (s *leadershipSuite) TestReleaseLeadership(c *gc.C) { 126 127 client := leadership.NewClient(s.clientFacade, s.facadeCaller) 128 defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }() 129 130 _, err := client.ClaimLeadership(s.serviceId, s.unitId) 131 c.Assert(err, gc.IsNil) 132 133 err = client.ReleaseLeadership(s.serviceId, s.unitId) 134 c.Assert(err, gc.IsNil) 135 } 136 137 func (s *leadershipSuite) TestUnblock(c *gc.C) { 138 139 client := leadership.NewClient(s.clientFacade, s.facadeCaller) 140 defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }() 141 142 _, err := client.ClaimLeadership(s.serviceId, s.unitId) 143 c.Assert(err, gc.IsNil) 144 145 unblocked := make(chan struct{}) 146 go func() { 147 err := client.BlockUntilLeadershipReleased(s.serviceId) 148 c.Check(err, gc.IsNil) 149 unblocked <- struct{}{} 150 }() 151 152 time.Sleep(coretesting.ShortWait) 153 154 err = client.ReleaseLeadership(s.serviceId, s.unitId) 155 c.Assert(err, gc.IsNil) 156 157 select { 158 case <-time.After(coretesting.LongWait): 159 c.Errorf("Timed out waiting for leadership to release.") 160 case <-unblocked: 161 } 162 } 163 164 type uniterLeadershipSuite struct { 165 agenttesting.AgentSuite 166 167 factory *factory.Factory 168 clientFacade base.ClientFacade 169 facadeCaller base.FacadeCaller 170 machineAgent *agentcmd.MachineAgent 171 unitId string 172 serviceId string 173 } 174 175 func (s *uniterLeadershipSuite) TestReadLeadershipSettings(c *gc.C) { 176 177 // First, the unit must be elected leader; otherwise merges will be denied. 178 leaderClient := leadership.NewClient(s.clientFacade, s.facadeCaller) 179 defer func() { err := leaderClient.Close(); c.Assert(err, gc.IsNil) }() 180 _, err := leaderClient.ClaimLeadership(s.serviceId, s.unitId) 181 c.Assert(err, gc.IsNil) 182 183 client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId)) 184 185 // Toss a few settings in. 186 desiredSettings := map[string]string{ 187 "foo": "bar", 188 "baz": "biz", 189 } 190 191 err = client.LeadershipSettings.Merge(s.serviceId, desiredSettings) 192 c.Assert(err, gc.IsNil) 193 194 settings, err := client.LeadershipSettings.Read(s.serviceId) 195 c.Assert(err, gc.IsNil) 196 c.Check(settings, gc.DeepEquals, desiredSettings) 197 } 198 199 func (s *uniterLeadershipSuite) TestMergeLeadershipSettings(c *gc.C) { 200 201 // First, the unit must be elected leader; otherwise merges will be denied. 202 leaderClient := leadership.NewClient(s.clientFacade, s.facadeCaller) 203 defer func() { err := leaderClient.Close(); c.Assert(err, gc.IsNil) }() 204 _, err := leaderClient.ClaimLeadership(s.serviceId, s.unitId) 205 c.Assert(err, gc.IsNil) 206 207 client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId)) 208 209 // Grab what settings exist. 210 settings, err := client.LeadershipSettings.Read(s.serviceId) 211 c.Assert(err, gc.IsNil) 212 // Double check that it's empty so that we don't pass the test by 213 // happenstance. 214 c.Assert(settings, gc.HasLen, 0) 215 216 // Toss a few settings in. 217 settings["foo"] = "bar" 218 settings["baz"] = "biz" 219 220 err = client.LeadershipSettings.Merge(s.serviceId, settings) 221 c.Assert(err, gc.IsNil) 222 223 settings, err = client.LeadershipSettings.Read(s.serviceId) 224 c.Assert(err, gc.IsNil) 225 c.Check(settings["foo"], gc.Equals, "bar") 226 c.Check(settings["baz"], gc.Equals, "biz") 227 } 228 229 func (s *uniterLeadershipSuite) TestSettingsChangeNotifier(c *gc.C) { 230 231 // First, the unit must be elected leader; otherwise merges will be denied. 232 leadershipClient := leadership.NewClient(s.clientFacade, s.facadeCaller) 233 defer func() { err := leadershipClient.Close(); c.Assert(err, gc.IsNil) }() 234 _, err := leadershipClient.ClaimLeadership(s.serviceId, s.unitId) 235 c.Assert(err, gc.IsNil) 236 237 client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId)) 238 239 // Listen for changes 240 sawChanges := make(chan struct{}) 241 go func() { 242 watcher, err := client.LeadershipSettings.WatchLeadershipSettings(s.serviceId) 243 c.Assert(err, gc.IsNil) 244 sawChanges <- <-watcher.Changes() 245 }() 246 247 err = client.LeadershipSettings.Merge(s.serviceId, map[string]string{"foo": "bar"}) 248 c.Assert(err, gc.IsNil) 249 250 <-sawChanges 251 } 252 253 func (s *uniterLeadershipSuite) SetUpTest(c *gc.C) { 254 255 s.AgentSuite.SetUpTest(c) 256 257 file, _ := ioutil.TempFile("", "juju-run") 258 defer file.Close() 259 s.AgentSuite.PatchValue(&agentcmd.JujuRun, file.Name()) 260 261 fakeEnsureMongo := agenttesting.FakeEnsure{} 262 s.AgentSuite.PatchValue(&cmdutil.EnsureMongoServer, fakeEnsureMongo.FakeEnsureMongo) 263 264 s.factory = factory.NewFactory(s.State) 265 266 // Create a machine to manage the environment, and set all 267 // passwords to something known. 268 stateServer, password := s.factory.MakeMachineReturningPassword(c, &factory.MachineParams{ 269 InstanceId: "id-1", 270 Nonce: agent.BootstrapNonce, 271 Jobs: []state.MachineJob{state.JobManageEnviron}, 272 }) 273 c.Assert(stateServer.PasswordValid(password), gc.Equals, true) 274 c.Assert(stateServer.SetMongoPassword(password), gc.IsNil) 275 276 // Create a machine to host some units. 277 unitHostMachine := s.factory.MakeMachine(c, &factory.MachineParams{ 278 Nonce: agent.BootstrapNonce, 279 Password: password, 280 }) 281 282 // Create a service and an instance of that service so that we can 283 // create a client. 284 service := s.factory.MakeService(c, &factory.ServiceParams{}) 285 s.serviceId = service.Tag().Id() 286 287 unit := s.factory.MakeUnit(c, &factory.UnitParams{Machine: unitHostMachine, Service: service}) 288 s.unitId = unit.UnitTag().Id() 289 290 c.Assert(unit.SetPassword(password), gc.IsNil) 291 unitState := s.OpenAPIAs(c, unit.Tag(), password) 292 293 // Create components needed to construct a client. 294 s.clientFacade, s.facadeCaller = base.NewClientFacade(unitState, leadershipapi.FacadeName) 295 c.Assert(s.clientFacade, gc.NotNil) 296 c.Assert(s.facadeCaller, gc.NotNil) 297 298 // Tweak and write out the config file for the state server. 299 writeStateAgentConfig( 300 c, 301 s.MongoInfo(c), 302 s.DataDir(), 303 names.NewMachineTag(stateServer.Id()), 304 s.State.EnvironTag(), 305 password, 306 version.Current, 307 ) 308 309 // Create & start a machine agent so the tests have something to call into. 310 agentConf := agentcmd.AgentConf{DataDir: s.DataDir()} 311 machineAgentFactory := agentcmd.MachineAgentFactoryFn(&agentConf, &agentConf) 312 s.machineAgent = machineAgentFactory(stateServer.Id()) 313 314 c.Log("Starting machine agent...") 315 go func() { 316 err := s.machineAgent.Run(coretesting.Context(c)) 317 c.Assert(err, gc.IsNil) 318 }() 319 } 320 321 func (s *uniterLeadershipSuite) TearDownTest(c *gc.C) { 322 c.Log("Stopping machine agent...") 323 err := s.machineAgent.Stop() 324 c.Assert(err, gc.IsNil) 325 326 s.AgentSuite.TearDownTest(c) 327 } 328 329 func writeStateAgentConfig( 330 c *gc.C, 331 stateInfo *mongo.MongoInfo, 332 dataDir string, 333 tag names.Tag, 334 environTag names.EnvironTag, 335 password string, 336 vers version.Binary, 337 ) agent.ConfigSetterWriter { 338 339 port := gitjujutesting.FindTCPPort() 340 apiAddr := []string{fmt.Sprintf("localhost:%d", port)} 341 conf, err := agent.NewStateMachineConfig( 342 agent.AgentConfigParams{ 343 DataDir: dataDir, 344 Tag: tag, 345 Environment: environTag, 346 UpgradedToVersion: vers.Number, 347 Password: password, 348 Nonce: agent.BootstrapNonce, 349 StateAddresses: stateInfo.Addrs, 350 APIAddresses: apiAddr, 351 CACert: stateInfo.CACert, 352 }, 353 params.StateServingInfo{ 354 Cert: coretesting.ServerCert, 355 PrivateKey: coretesting.ServerKey, 356 CAPrivateKey: coretesting.CAKey, 357 StatePort: gitjujutesting.MgoServer.Port(), 358 APIPort: port, 359 }) 360 c.Assert(err, gc.IsNil) 361 conf.SetPassword(password) 362 c.Assert(conf.Write(), gc.IsNil) 363 return conf 364 }