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