github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/highavailability/highavailability_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package highavailability_test 5 6 import ( 7 "fmt" 8 stdtesting "testing" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/worker.v1" 14 15 "github.com/juju/juju/apiserver/common" 16 commontesting "github.com/juju/juju/apiserver/common/testing" 17 "github.com/juju/juju/apiserver/facades/client/highavailability" 18 "github.com/juju/juju/apiserver/params" 19 apiservertesting "github.com/juju/juju/apiserver/testing" 20 "github.com/juju/juju/controller" 21 "github.com/juju/juju/core/constraints" 22 "github.com/juju/juju/juju/testing" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/state/presence" 26 coretesting "github.com/juju/juju/testing" 27 "github.com/juju/juju/testing/factory" 28 ) 29 30 func TestAll(t *stdtesting.T) { 31 coretesting.MgoTestPackage(t) 32 } 33 34 type clientSuite struct { 35 testing.JujuConnSuite 36 37 resources *common.Resources 38 authoriser apiservertesting.FakeAuthorizer 39 haServer *highavailability.HighAvailabilityAPI 40 machine0Pinger *presence.Pinger 41 42 commontesting.BlockHelper 43 } 44 45 var _ = gc.Suite(&clientSuite{}) 46 47 var ( 48 emptyCons = constraints.Value{} 49 controllerCons = constraints.MustParse("mem=16G cores=16") 50 defaultSeries = "" 51 ) 52 53 func (s *clientSuite) SetUpTest(c *gc.C) { 54 s.JujuConnSuite.SetUpTest(c) 55 s.resources = common.NewResources() 56 err := s.resources.RegisterNamed("machineID", common.StringResource("0")) 57 c.Assert(err, jc.ErrorIsNil) 58 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 59 60 s.authoriser = apiservertesting.FakeAuthorizer{ 61 Tag: s.AdminUserTag(c), 62 Controller: true, 63 } 64 65 s.haServer, err = highavailability.NewHighAvailabilityAPI(s.State, s.resources, s.authoriser) 66 c.Assert(err, jc.ErrorIsNil) 67 68 _, err = s.State.AddMachines(state.MachineTemplate{ 69 Series: "quantal", 70 Jobs: []state.MachineJob{state.JobManageModel}, 71 Constraints: controllerCons, 72 Addresses: []network.Address{ 73 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 74 network.NewScopedAddress("cloud-local0.internal", network.ScopeCloudLocal), 75 network.NewScopedAddress("fc00::0", network.ScopePublic), 76 }, 77 }) 78 c.Assert(err, jc.ErrorIsNil) 79 80 // We have to ensure the agents are alive, or EnableHA will 81 // create more to replace them. 82 s.machine0Pinger = s.setAgentPresence(c, "0") 83 s.BlockHelper = commontesting.NewBlockHelper(s.APIState) 84 s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() }) 85 } 86 87 func (s *clientSuite) setAgentPresence(c *gc.C, machineId string) *presence.Pinger { 88 m, err := s.State.Machine(machineId) 89 c.Assert(err, jc.ErrorIsNil) 90 pinger, err := m.SetAgentPresence() 91 c.Assert(err, jc.ErrorIsNil) 92 s.AddCleanup(func(c *gc.C) { 93 c.Assert(worker.Stop(pinger), jc.ErrorIsNil) 94 }) 95 96 s.State.StartSync() 97 err = m.WaitAgentPresence(coretesting.LongWait) 98 c.Assert(err, jc.ErrorIsNil) 99 return pinger 100 } 101 102 func (s *clientSuite) setMachineAddresses(c *gc.C, machineId string) { 103 m, err := s.State.Machine(machineId) 104 c.Assert(err, jc.ErrorIsNil) 105 err = m.SetMachineAddresses( 106 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 107 network.NewScopedAddress(fmt.Sprintf("cloud-local%s.internal", machineId), network.ScopeCloudLocal), 108 network.NewScopedAddress(fmt.Sprintf("fc0%s::1", machineId), network.ScopePublic), 109 ) 110 c.Assert(err, jc.ErrorIsNil) 111 } 112 113 func (s *clientSuite) enableHA( 114 c *gc.C, numControllers int, cons constraints.Value, series string, placement []string, 115 ) (params.ControllersChanges, error) { 116 return enableHA(c, s.haServer, numControllers, cons, series, placement) 117 } 118 119 func enableHA( 120 c *gc.C, 121 haServer *highavailability.HighAvailabilityAPI, 122 numControllers int, 123 cons constraints.Value, 124 series string, 125 placement []string, 126 ) (params.ControllersChanges, error) { 127 arg := params.ControllersSpecs{ 128 Specs: []params.ControllersSpec{{ 129 NumControllers: numControllers, 130 Constraints: cons, 131 Series: series, 132 Placement: placement, 133 }}} 134 results, err := haServer.EnableHA(arg) 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(results.Results, gc.HasLen, 1) 137 result := results.Results[0] 138 // We explicitly return nil here so we can do typed nil checking 139 // of the result like normal. 140 err = nil 141 if result.Error != nil { 142 err = result.Error 143 } 144 return result.Result, err 145 } 146 147 func (s *clientSuite) TestEnableHASeries(c *gc.C) { 148 machines, err := s.State.AllMachines() 149 c.Assert(err, jc.ErrorIsNil) 150 c.Assert(machines, gc.HasLen, 1) 151 c.Assert(machines[0].Series(), gc.Equals, "quantal") 152 153 enableHAResult, err := s.enableHA(c, 3, emptyCons, defaultSeries, nil) 154 c.Assert(err, jc.ErrorIsNil) 155 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 156 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 157 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 158 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 159 160 machines, err = s.State.AllMachines() 161 c.Assert(err, jc.ErrorIsNil) 162 c.Assert(machines, gc.HasLen, 3) 163 c.Assert(machines[0].Series(), gc.Equals, "quantal") 164 c.Assert(machines[1].Series(), gc.Equals, "quantal") 165 c.Assert(machines[2].Series(), gc.Equals, "quantal") 166 167 s.setAgentPresence(c, "1") 168 s.setAgentPresence(c, "2") 169 s.setMachineAddresses(c, "1") 170 s.setMachineAddresses(c, "2") 171 172 enableHAResult, err = s.enableHA(c, 5, emptyCons, "non-default", nil) 173 c.Assert(err, jc.ErrorIsNil) 174 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0", "machine-1", "machine-2"}) 175 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-3", "machine-4"}) 176 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 177 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 178 179 c.Assert(err, jc.ErrorIsNil) 180 machines, err = s.State.AllMachines() 181 c.Assert(err, jc.ErrorIsNil) 182 c.Assert(machines, gc.HasLen, 5) 183 c.Assert(machines[0].Series(), gc.Equals, "quantal") 184 c.Assert(machines[1].Series(), gc.Equals, "quantal") 185 c.Assert(machines[2].Series(), gc.Equals, "quantal") 186 c.Assert(machines[3].Series(), gc.Equals, "non-default") 187 c.Assert(machines[4].Series(), gc.Equals, "non-default") 188 } 189 190 func (s *clientSuite) TestEnableHAErrorForMultiCloudLocal(c *gc.C) { 191 machines, err := s.State.AllMachines() 192 c.Assert(err, jc.ErrorIsNil) 193 c.Assert(machines, gc.HasLen, 1) 194 c.Assert(machines[0].Series(), gc.Equals, "quantal") 195 196 err = machines[0].SetMachineAddresses( 197 network.NewScopedAddress("cloud-local2.internal", network.ScopeCloudLocal), 198 network.NewScopedAddress("cloud-local22.internal", network.ScopeCloudLocal), 199 ) 200 c.Assert(err, jc.ErrorIsNil) 201 202 _, err = s.enableHA(c, 3, emptyCons, defaultSeries, nil) 203 c.Assert(err, gc.ErrorMatches, 204 "juju-ha-space is not set and a unique usable address was not found for machines: 0"+ 205 "\nrun \"juju config juju-ha-space=<name>\" to set a space for Mongo peer communication") 206 } 207 208 func (s *clientSuite) TestEnableHAErrorForNoCloudLocal(c *gc.C) { 209 m0, err := s.State.Machine("0") 210 c.Assert(err, jc.ErrorIsNil) 211 c.Assert(m0.Series(), gc.Equals, "quantal") 212 213 // remove the extra provider addresses, so we have no valid CloudLocal addresses 214 c.Assert(m0.SetProviderAddresses( 215 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 216 ), jc.ErrorIsNil) 217 218 _, err = s.enableHA(c, 3, emptyCons, defaultSeries, nil) 219 c.Assert(err, gc.ErrorMatches, 220 "juju-ha-space is not set and a unique usable address was not found for machines: 0"+ 221 "\nrun \"juju config juju-ha-space=<name>\" to set a space for Mongo peer communication") 222 } 223 224 func (s *clientSuite) TestEnableHANoErrorForNoAddresses(c *gc.C) { 225 enableHAResult, err := s.enableHA(c, 0, emptyCons, defaultSeries, nil) 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 228 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 229 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 230 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 231 232 s.setMachineAddresses(c, "0") 233 s.setMachineAddresses(c, "1") 234 // 0 and 1 are up, but 2 hasn't finished booting yet, so has no addresses set 235 236 _, err = s.enableHA(c, 3, emptyCons, defaultSeries, nil) 237 c.Assert(err, jc.ErrorIsNil) 238 } 239 240 func (s *clientSuite) TestEnableHAAddMachinesErrorForMultiCloudLocal(c *gc.C) { 241 machines, err := s.State.AllMachines() 242 c.Assert(err, jc.ErrorIsNil) 243 c.Assert(machines, gc.HasLen, 1) 244 c.Assert(machines[0].Series(), gc.Equals, "quantal") 245 246 enableHAResult, err := s.enableHA(c, 3, emptyCons, defaultSeries, nil) 247 c.Assert(err, jc.ErrorIsNil) 248 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 249 250 s.setMachineAddresses(c, "1") 251 252 m, err := s.State.Machine("2") 253 c.Assert(err, jc.ErrorIsNil) 254 err = m.SetMachineAddresses( 255 network.NewScopedAddress("cloud-local2.internal", network.ScopeCloudLocal), 256 network.NewScopedAddress("cloud-local22.internal", network.ScopeCloudLocal), 257 ) 258 c.Assert(err, jc.ErrorIsNil) 259 260 _, err = s.enableHA(c, 5, emptyCons, defaultSeries, nil) 261 c.Assert(err, gc.ErrorMatches, 262 "juju-ha-space is not set and a unique usable address was not found for machines: 2"+ 263 "\nrun \"juju config juju-ha-space=<name>\" to set a space for Mongo peer communication") 264 } 265 266 func (s *clientSuite) TestEnableHAConstraints(c *gc.C) { 267 enableHAResult, err := s.enableHA(c, 3, constraints.MustParse("mem=4G"), defaultSeries, nil) 268 c.Assert(err, jc.ErrorIsNil) 269 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 270 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 271 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 272 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 273 274 machines, err := s.State.AllMachines() 275 c.Assert(err, jc.ErrorIsNil) 276 c.Assert(machines, gc.HasLen, 3) 277 expectedCons := []constraints.Value{ 278 controllerCons, 279 constraints.MustParse("mem=4G"), 280 constraints.MustParse("mem=4G"), 281 } 282 for i, m := range machines { 283 cons, err := m.Constraints() 284 c.Assert(err, jc.ErrorIsNil) 285 c.Check(cons, gc.DeepEquals, expectedCons[i]) 286 } 287 } 288 289 func (s *clientSuite) TestEnableHAEmptyConstraints(c *gc.C) { 290 enableHAResult, err := s.enableHA(c, 3, emptyCons, defaultSeries, nil) 291 c.Assert(err, jc.ErrorIsNil) 292 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 293 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 294 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 295 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 296 297 machines, err := s.State.AllMachines() 298 c.Assert(err, jc.ErrorIsNil) 299 c.Assert(machines, gc.HasLen, 3) 300 for _, m := range machines { 301 cons, err := m.Constraints() 302 c.Assert(err, jc.ErrorIsNil) 303 c.Check(cons, gc.DeepEquals, controllerCons) 304 } 305 } 306 307 func (s *clientSuite) TestEnableHAControllerConfigConstraints(c *gc.C) { 308 controllerSettings, _ := s.State.ReadSettings("controllers", "controllerSettings") 309 controllerSettings.Set(controller.JujuHASpace, "ha-space") 310 controllerSettings.Write() 311 312 enableHAResult, err := s.enableHA(c, 3, constraints.MustParse("spaces=random-space"), defaultSeries, nil) 313 c.Assert(err, jc.ErrorIsNil) 314 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 315 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 316 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 317 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 318 319 machines, err := s.State.AllMachines() 320 c.Assert(err, jc.ErrorIsNil) 321 c.Assert(machines, gc.HasLen, 3) 322 expectedCons := []constraints.Value{ 323 controllerCons, 324 constraints.MustParse("spaces=ha-space,random-space"), 325 constraints.MustParse("spaces=ha-space,random-space"), 326 } 327 for i, m := range machines { 328 cons, err := m.Constraints() 329 c.Assert(err, jc.ErrorIsNil) 330 c.Check(cons, gc.DeepEquals, expectedCons[i]) 331 } 332 } 333 334 func (s *clientSuite) TestBlockMakeHA(c *gc.C) { 335 // Block all changes. 336 s.BlockAllChanges(c, "TestBlockEnableHA") 337 338 enableHAResult, err := s.enableHA(c, 3, constraints.MustParse("mem=4G"), defaultSeries, nil) 339 s.AssertBlocked(c, err, "TestBlockEnableHA") 340 341 c.Assert(enableHAResult.Maintained, gc.HasLen, 0) 342 c.Assert(enableHAResult.Added, gc.HasLen, 0) 343 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 344 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 345 346 machines, err := s.State.AllMachines() 347 c.Assert(err, jc.ErrorIsNil) 348 c.Assert(machines, gc.HasLen, 1) 349 } 350 351 func (s *clientSuite) TestEnableHAPlacement(c *gc.C) { 352 placement := []string{"valid"} 353 enableHAResult, err := s.enableHA(c, 3, constraints.MustParse("mem=4G tags=foobar"), defaultSeries, placement) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 356 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 357 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 358 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 359 360 machines, err := s.State.AllMachines() 361 c.Assert(err, jc.ErrorIsNil) 362 c.Assert(machines, gc.HasLen, 3) 363 expectedCons := []constraints.Value{ 364 controllerCons, 365 {}, 366 constraints.MustParse("mem=4G tags=foobar"), 367 } 368 expectedPlacement := []string{"", "valid", ""} 369 for i, m := range machines { 370 cons, err := m.Constraints() 371 c.Assert(err, jc.ErrorIsNil) 372 c.Check(cons, gc.DeepEquals, expectedCons[i]) 373 c.Check(m.Placement(), gc.Equals, expectedPlacement[i]) 374 } 375 } 376 377 func (s *clientSuite) TestEnableHAPlacementTo(c *gc.C) { 378 machine1Cons := constraints.MustParse("mem=8G") 379 _, err := s.State.AddMachines(state.MachineTemplate{ 380 Series: "quantal", 381 Jobs: []state.MachineJob{state.JobHostUnits}, 382 Constraints: machine1Cons, 383 }) 384 c.Assert(err, jc.ErrorIsNil) 385 s.setAgentPresence(c, "1") 386 387 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 388 c.Assert(err, jc.ErrorIsNil) 389 s.setAgentPresence(c, "2") 390 391 placement := []string{"1", "2"} 392 enableHAResult, err := s.enableHA(c, 3, emptyCons, defaultSeries, placement) 393 c.Assert(err, jc.ErrorIsNil) 394 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 395 c.Assert(enableHAResult.Added, gc.HasLen, 0) 396 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 397 c.Assert(enableHAResult.Converted, gc.DeepEquals, []string{"machine-1", "machine-2"}) 398 399 machines, err := s.State.AllMachines() 400 c.Assert(err, jc.ErrorIsNil) 401 c.Assert(machines, gc.HasLen, 3) 402 expectedCons := []constraints.Value{ 403 controllerCons, 404 machine1Cons, 405 {}, 406 } 407 expectedPlacement := []string{"", "", ""} 408 for i, m := range machines { 409 cons, err := m.Constraints() 410 c.Assert(err, jc.ErrorIsNil) 411 c.Check(cons, gc.DeepEquals, expectedCons[i]) 412 c.Check(m.Placement(), gc.Equals, expectedPlacement[i]) 413 } 414 } 415 416 func (s *clientSuite) TestEnableHAPlacementToWithAddressInSpace(c *gc.C) { 417 controllerSettings, _ := s.State.ReadSettings("controllers", "controllerSettings") 418 controllerSettings.Set(controller.JujuHASpace, "ha-space") 419 controllerSettings.Write() 420 421 m1, err := s.State.AddMachine("quantal", state.JobHostUnits) 422 c.Assert(err, jc.ErrorIsNil) 423 s.setAgentPresence(c, "1") 424 m1.SetProviderAddresses(network.NewAddressOnSpace("ha-space", "192.168.6.6")) 425 426 m2, err := s.State.AddMachine("quantal", state.JobHostUnits) 427 c.Assert(err, jc.ErrorIsNil) 428 s.setAgentPresence(c, "2") 429 m2.SetProviderAddresses(network.NewAddressOnSpace("ha-space", "192.168.6.7")) 430 431 placement := []string{"1", "2"} 432 _, err = s.enableHA(c, 3, emptyCons, defaultSeries, placement) 433 c.Assert(err, jc.ErrorIsNil) 434 } 435 436 func (s *clientSuite) TestEnableHAPlacementToErrorForInaccessibleSpace(c *gc.C) { 437 controllerSettings, _ := s.State.ReadSettings("controllers", "controllerSettings") 438 controllerSettings.Set(controller.JujuHASpace, "ha-space") 439 controllerSettings.Write() 440 441 _, err := s.State.AddMachine("quantal", state.JobHostUnits) 442 c.Assert(err, jc.ErrorIsNil) 443 s.setAgentPresence(c, "1") 444 445 placement := []string{"1", "2"} 446 _, err = s.enableHA(c, 3, emptyCons, defaultSeries, placement) 447 c.Assert(err, gc.ErrorMatches, `machine "1" has no addresses in space "ha-space"`) 448 } 449 450 func (s *clientSuite) TestEnableHA0Preserves(c *gc.C) { 451 // A value of 0 says either "if I'm not HA, make me HA" or "preserve my 452 // current HA settings". 453 enableHAResult, err := s.enableHA(c, 0, emptyCons, defaultSeries, nil) 454 c.Assert(err, jc.ErrorIsNil) 455 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 456 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 457 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 458 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 459 460 machines, err := s.State.AllMachines() 461 c.Assert(err, jc.ErrorIsNil) 462 c.Assert(machines, gc.HasLen, 3) 463 464 s.setAgentPresence(c, "1") 465 s.setMachineAddresses(c, "1") 466 s.setMachineAddresses(c, "2") 467 468 // Now, we keep agent 1 alive, but not agent 2, calling 469 // EnableHA(0) again will cause us to start another machine 470 c.Assert(machines[2].Destroy(), jc.ErrorIsNil) 471 c.Assert(machines[2].Refresh(), jc.ErrorIsNil) 472 c.Assert(machines[2].SetHasVote(false), jc.ErrorIsNil) 473 c.Assert(s.State.RemoveControllerMachine(machines[2]), jc.ErrorIsNil) 474 c.Assert(machines[2].EnsureDead(), jc.ErrorIsNil) 475 enableHAResult, err = s.enableHA(c, 0, emptyCons, defaultSeries, nil) 476 c.Assert(err, jc.ErrorIsNil) 477 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0", "machine-1"}) 478 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-3"}) 479 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 480 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 481 482 machines, err = s.State.AllMachines() 483 c.Assert(err, jc.ErrorIsNil) 484 c.Assert(machines, gc.HasLen, 4) 485 } 486 487 func (s *clientSuite) TestEnableHA0Preserves5(c *gc.C) { 488 // Start off with 5 servers 489 enableHAResult, err := s.enableHA(c, 5, emptyCons, defaultSeries, nil) 490 c.Assert(err, jc.ErrorIsNil) 491 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 492 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2", "machine-3", "machine-4"}) 493 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 494 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 495 496 machines, err := s.State.AllMachines() 497 c.Assert(err, jc.ErrorIsNil) 498 c.Assert(machines, gc.HasLen, 5) 499 for _, m := range machines { 500 m.SetHasVote(true) 501 } 502 503 s.setMachineAddresses(c, "1") 504 s.setMachineAddresses(c, "2") 505 s.setMachineAddresses(c, "3") 506 s.setMachineAddresses(c, "4") 507 c.Assert(machines[4].SetHasVote(false), jc.ErrorIsNil) 508 c.Assert(machines[4].Destroy(), jc.ErrorIsNil) 509 c.Assert(machines[4].Refresh(), jc.ErrorIsNil) 510 c.Assert(s.State.RemoveControllerMachine(machines[4]), jc.ErrorIsNil) 511 c.Assert(machines[4].EnsureDead(), jc.ErrorIsNil) 512 513 // Keeping all alive but one, will bring up 1 more server to preserve 5 514 enableHAResult, err = s.enableHA(c, 0, emptyCons, defaultSeries, nil) 515 c.Assert(err, jc.ErrorIsNil) 516 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0", "machine-1", 517 "machine-2", "machine-3"}) 518 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-5"}) 519 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 520 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 521 522 machines, err = s.State.AllMachines() 523 c.Assert(machines, gc.HasLen, 6) 524 c.Assert(err, jc.ErrorIsNil) 525 } 526 527 func (s *clientSuite) TestEnableHAErrors(c *gc.C) { 528 enableHAResult, err := s.enableHA(c, -1, emptyCons, defaultSeries, nil) 529 c.Assert(err, gc.ErrorMatches, "number of controllers must be odd and non-negative") 530 531 enableHAResult, err = s.enableHA(c, 3, emptyCons, defaultSeries, nil) 532 c.Assert(err, jc.ErrorIsNil) 533 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 534 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 535 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 536 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 537 538 s.setMachineAddresses(c, "1") 539 s.setMachineAddresses(c, "2") 540 541 _, err = s.enableHA(c, 1, emptyCons, defaultSeries, nil) 542 c.Assert(err, gc.ErrorMatches, "failed to create new controller machines: cannot reduce controller count") 543 } 544 545 func (s *clientSuite) TestEnableHAHostedModelErrors(c *gc.C) { 546 st2 := s.Factory.MakeModel(c, &factory.ModelParams{ConfigAttrs: coretesting.Attrs{"controller": false}}) 547 defer st2.Close() 548 549 haServer, err := highavailability.NewHighAvailabilityAPI(st2, s.resources, s.authoriser) 550 c.Assert(err, jc.ErrorIsNil) 551 552 enableHAResult, err := enableHA(c, haServer, 3, constraints.MustParse("mem=4G"), defaultSeries, nil) 553 c.Assert(errors.Cause(err), gc.ErrorMatches, "unsupported with hosted models") 554 555 c.Assert(enableHAResult.Maintained, gc.HasLen, 0) 556 c.Assert(enableHAResult.Added, gc.HasLen, 0) 557 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 558 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 559 560 machines, err := st2.AllMachines() 561 c.Assert(err, jc.ErrorIsNil) 562 c.Assert(machines, gc.HasLen, 0) 563 } 564 565 func (s *clientSuite) TestEnableHAMultipleSpecs(c *gc.C) { 566 arg := params.ControllersSpecs{ 567 Specs: []params.ControllersSpec{ 568 {NumControllers: 3}, 569 {NumControllers: 5}, 570 }, 571 } 572 results, err := s.haServer.EnableHA(arg) 573 c.Check(err, gc.ErrorMatches, "only one controller spec is supported") 574 c.Check(results.Results, gc.HasLen, 0) 575 } 576 577 func (s *clientSuite) TestEnableHANoSpecs(c *gc.C) { 578 arg := params.ControllersSpecs{ 579 Specs: []params.ControllersSpec{}, 580 } 581 results, err := s.haServer.EnableHA(arg) 582 c.Check(err, jc.ErrorIsNil) 583 c.Check(results.Results, gc.HasLen, 0) 584 } 585 586 func (s *clientSuite) TestEnableHABootstrap(c *gc.C) { 587 // Testing based on lp:1748275 - Juju HA fails due to demotion of Machine 0 588 s.machine0Pinger.KillForTesting() 589 590 machines, err := s.State.AllMachines() 591 c.Assert(err, jc.ErrorIsNil) 592 c.Assert(machines, gc.HasLen, 1) 593 594 enableHAResult, err := s.enableHA(c, 3, emptyCons, defaultSeries, nil) 595 c.Assert(err, jc.ErrorIsNil) 596 c.Assert(enableHAResult.Maintained, gc.DeepEquals, []string{"machine-0"}) 597 c.Assert(enableHAResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"}) 598 c.Assert(enableHAResult.Removed, gc.HasLen, 0) 599 c.Assert(enableHAResult.Converted, gc.HasLen, 0) 600 c.Assert(enableHAResult.Demoted, gc.HasLen, 0) 601 }