github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/spaces_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "net" 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/core/life" 15 "github.com/juju/juju/core/network" 16 "github.com/juju/juju/state" 17 ) 18 19 type SpacesSuite struct { 20 ConnSuite 21 } 22 23 var _ = gc.Suite(&SpacesSuite{}) 24 25 func (s *SpacesSuite) addSubnets(c *gc.C, CIDRs []string) []string { 26 return s.addSubnetsForState(c, CIDRs, s.State) 27 } 28 29 func (s *SpacesSuite) addSubnetsForState(c *gc.C, CIDRs []string, st *state.State) []string { 30 if len(CIDRs) == 0 { 31 return nil 32 } 33 subnetIDs := make([]string, len(CIDRs)) 34 for i, info := range s.makeSubnetInfosForCIDRs(c, CIDRs) { 35 subnet, err := st.AddSubnet(info) 36 c.Assert(err, jc.ErrorIsNil) 37 subnetIDs[i] = subnet.ID() 38 } 39 return subnetIDs 40 } 41 42 func (s *SpacesSuite) makeSubnetInfosForCIDRs(c *gc.C, CIDRs []string) []network.SubnetInfo { 43 infos := make([]network.SubnetInfo, len(CIDRs)) 44 for i, cidr := range CIDRs { 45 _, _, err := net.ParseCIDR(cidr) 46 c.Assert(err, jc.ErrorIsNil) 47 48 infos[i] = network.SubnetInfo{ 49 CIDR: cidr, 50 VLANTag: 79, 51 AvailabilityZones: []string{"AvailabilityZone"}, 52 } 53 54 } 55 return infos 56 } 57 58 type addSpaceArgs struct { 59 Name string 60 ProviderId network.Id 61 SubnetCIDRs []string 62 IsPublic bool 63 ForState *state.State 64 } 65 66 func (s *SpacesSuite) addSpaceWithSubnets(c *gc.C, args addSpaceArgs) (*state.Space, error) { 67 if args.ForState == nil { 68 args.ForState = s.State 69 } 70 subnetIDs := s.addSubnetsForState(c, args.SubnetCIDRs, args.ForState) 71 return args.ForState.AddSpace(args.Name, args.ProviderId, subnetIDs, args.IsPublic) 72 } 73 74 func (s *SpacesSuite) assertSpaceNotFound(c *gc.C, name string) { 75 s.assertSpaceNotFoundForState(c, name, s.State) 76 } 77 78 func (s *SpacesSuite) assertSpaceNotFoundForState(c *gc.C, name string, st *state.State) { 79 _, err := st.SpaceByName(name) 80 s.assertSpaceNotFoundError(c, err, name) 81 } 82 83 func (s *SpacesSuite) assertSpaceNotFoundError(c *gc.C, err error, name string) { 84 c.Assert(err, gc.ErrorMatches, fmt.Sprintf("space %q not found", name)) 85 86 c.Assert(err, jc.Satisfies, errors.IsNotFound) 87 } 88 89 func (s *SpacesSuite) assertSpaceMatchesArgs(c *gc.C, space *state.Space, args addSpaceArgs) { 90 c.Assert(space.Name(), gc.Equals, args.Name) 91 c.Assert(space.ProviderId(), gc.Equals, args.ProviderId) 92 93 actualSpaceInfo, err := space.NetworkSpace() 94 c.Assert(err, jc.ErrorIsNil) 95 actualSubnetIds := make([]string, len(actualSpaceInfo.Subnets)) 96 for i, subnet := range actualSpaceInfo.Subnets { 97 actualSubnetIds[i] = subnet.CIDR 98 } 99 c.Assert(actualSubnetIds, jc.SameContents, args.SubnetCIDRs) 100 c.Assert(state.SpaceDoc(space).IsPublic, gc.Equals, args.IsPublic) 101 102 c.Assert(space.Life(), gc.Equals, state.Alive) 103 c.Assert(space.String(), gc.Equals, args.Name) 104 105 // The space ID is not empty and not equivalent to the default space. 106 c.Assert(space.Id(), gc.Not(gc.Equals), "") 107 c.Assert(space.Id(), gc.Not(gc.Equals), "0") 108 } 109 110 func (s *SpacesSuite) TestAddSpaceWithNoSubnetsAndEmptyProviderId(c *gc.C) { 111 args := addSpaceArgs{ 112 Name: "my-space", 113 ProviderId: "", 114 SubnetCIDRs: nil, 115 } 116 space, err := s.addSpaceWithSubnets(c, args) 117 c.Assert(err, jc.ErrorIsNil) 118 s.assertSpaceMatchesArgs(c, space, args) 119 } 120 121 func (s *SpacesSuite) TestAddSpaceWithNoSubnetsAndNonEmptyProviderId(c *gc.C) { 122 args := addSpaceArgs{ 123 Name: "my-space", 124 ProviderId: network.Id("my provider id"), 125 SubnetCIDRs: nil, 126 } 127 space, err := s.addSpaceWithSubnets(c, args) 128 c.Assert(err, jc.ErrorIsNil) 129 s.assertSpaceMatchesArgs(c, space, args) 130 } 131 132 func (s *SpacesSuite) TestAddSpaceWithOneIPv4SubnetAndEmptyProviderId(c *gc.C) { 133 args := addSpaceArgs{ 134 Name: "my-space", 135 ProviderId: "", 136 SubnetCIDRs: []string{"1.1.1.0/24"}, 137 } 138 space, err := s.addSpaceWithSubnets(c, args) 139 c.Assert(err, jc.ErrorIsNil) 140 s.assertSpaceMatchesArgs(c, space, args) 141 } 142 143 func (s *SpacesSuite) TestAddSpaceWithOneIPv4SubnetAndNonEmptyProviderId(c *gc.C) { 144 args := addSpaceArgs{ 145 Name: "my-space", 146 ProviderId: network.Id("some id"), 147 SubnetCIDRs: []string{"1.1.1.0/24"}, 148 } 149 space, err := s.addSpaceWithSubnets(c, args) 150 c.Assert(err, jc.ErrorIsNil) 151 s.assertSpaceMatchesArgs(c, space, args) 152 } 153 154 func (s *SpacesSuite) TestAddSpaceWithOneIPv6SubnetAndEmptyProviderId(c *gc.C) { 155 args := addSpaceArgs{ 156 Name: "my-space", 157 ProviderId: "", 158 SubnetCIDRs: []string{"fc00:123::/64"}, 159 } 160 space, err := s.addSpaceWithSubnets(c, args) 161 c.Assert(err, jc.ErrorIsNil) 162 s.assertSpaceMatchesArgs(c, space, args) 163 } 164 165 func (s *SpacesSuite) TestAddSpaceWithOneIPv6SubnetAndNonEmptyProviderId(c *gc.C) { 166 args := addSpaceArgs{ 167 Name: "my-space", 168 ProviderId: network.Id("provider id"), 169 SubnetCIDRs: []string{"fc00:123::/64"}, 170 } 171 space, err := s.addSpaceWithSubnets(c, args) 172 c.Assert(err, jc.ErrorIsNil) 173 s.assertSpaceMatchesArgs(c, space, args) 174 } 175 176 func (s *SpacesSuite) TestAddSpaceWithOneIPv4AndOneIPv6SubnetAndEmptyProviderId(c *gc.C) { 177 args := addSpaceArgs{ 178 Name: "my-space", 179 ProviderId: "", 180 SubnetCIDRs: []string{"1.1.1.0/24", "fc00::/64"}, 181 } 182 space, err := s.addSpaceWithSubnets(c, args) 183 c.Assert(err, jc.ErrorIsNil) 184 s.assertSpaceMatchesArgs(c, space, args) 185 } 186 187 func (s *SpacesSuite) TestAddSpaceWithOneIPv4AndOneIPv6SubnetAndNonEmptyProviderId(c *gc.C) { 188 args := addSpaceArgs{ 189 Name: "my-space", 190 ProviderId: network.Id("foo bar"), 191 SubnetCIDRs: []string{"1.1.1.0/24", "fc00::/64"}, 192 } 193 space, err := s.addSpaceWithSubnets(c, args) 194 c.Assert(err, jc.ErrorIsNil) 195 s.assertSpaceMatchesArgs(c, space, args) 196 } 197 198 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv4SubnetsAndEmptyProviderId(c *gc.C) { 199 args := addSpaceArgs{ 200 Name: "my-space", 201 ProviderId: "", 202 SubnetCIDRs: []string{"1.1.1.0/24", "1.2.2.0/24"}, 203 } 204 space, err := s.addSpaceWithSubnets(c, args) 205 c.Assert(err, jc.ErrorIsNil) 206 s.assertSpaceMatchesArgs(c, space, args) 207 } 208 209 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv4SubnetsAndNonEmptyProviderId(c *gc.C) { 210 args := addSpaceArgs{ 211 Name: "my-space", 212 ProviderId: network.Id("My Provider ID"), 213 SubnetCIDRs: []string{"1.1.1.0/24", "1.2.2.0/24"}, 214 } 215 space, err := s.addSpaceWithSubnets(c, args) 216 c.Assert(err, jc.ErrorIsNil) 217 s.assertSpaceMatchesArgs(c, space, args) 218 } 219 220 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv6SubnetsAndEmptyProviderId(c *gc.C) { 221 args := addSpaceArgs{ 222 Name: "my-space", 223 ProviderId: "", 224 SubnetCIDRs: []string{"fc00:123::/64", "fc00:321::/64"}, 225 } 226 space, err := s.addSpaceWithSubnets(c, args) 227 c.Assert(err, jc.ErrorIsNil) 228 s.assertSpaceMatchesArgs(c, space, args) 229 } 230 231 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv6SubnetsAndNonEmptyProviderId(c *gc.C) { 232 args := addSpaceArgs{ 233 Name: "my-space", 234 ProviderId: network.Id("My Provider ID"), 235 SubnetCIDRs: []string{"fc00:123::/64", "fc00:321::/64"}, 236 } 237 space, err := s.addSpaceWithSubnets(c, args) 238 239 c.Assert(err, jc.ErrorIsNil) 240 s.assertSpaceMatchesArgs(c, space, args) 241 } 242 243 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv4AndIPv6SubnetsAndEmptyProviderId(c *gc.C) { 244 args := addSpaceArgs{ 245 Name: "my-space", 246 ProviderId: "", 247 SubnetCIDRs: []string{"fc00:123::/64", "2.2.0.0/20", "fc00:321::/64", "1.1.1.0/24"}, 248 } 249 space, err := s.addSpaceWithSubnets(c, args) 250 251 c.Assert(err, jc.ErrorIsNil) 252 s.assertSpaceMatchesArgs(c, space, args) 253 254 } 255 256 func (s *SpacesSuite) TestAddSpaceWithMultipleIPv4AndIPv6SubnetsAndNonEmptyProviderId(c *gc.C) { 257 args := addSpaceArgs{ 258 Name: "my-space", 259 ProviderId: network.Id("My Provider ID"), 260 SubnetCIDRs: []string{"fc00:123::/64", "2.2.0.0/20", "fc00:321::/64", "1.1.1.0/24"}, 261 } 262 space, err := s.addSpaceWithSubnets(c, args) 263 c.Assert(err, jc.ErrorIsNil) 264 s.assertSpaceMatchesArgs(c, space, args) 265 } 266 267 func (s *SpacesSuite) addTwoSpacesReturnSecond(c *gc.C, args1, args2 addSpaceArgs) (*state.Space, error) { 268 space1, err := s.addSpaceWithSubnets(c, args1) 269 270 c.Assert(err, jc.ErrorIsNil) 271 s.assertSpaceMatchesArgs(c, space1, args1) 272 273 return s.addSpaceWithSubnets(c, args2) 274 } 275 276 func (s *SpacesSuite) TestAddTwoSpacesWithDifferentNamesButSameProviderIdFailsInSameModel(c *gc.C) { 277 args1 := addSpaceArgs{ 278 Name: "my-space", 279 ProviderId: network.Id("provider id"), 280 } 281 args2 := args1 282 args2.Name = "different" 283 284 _, err := s.addTwoSpacesReturnSecond(c, args1, args2) 285 s.assertProviderIdNotUniqueErrorForArgs(c, err, args2) 286 } 287 288 func (s *SpacesSuite) assertProviderIdNotUniqueErrorForArgs(c *gc.C, err error, args addSpaceArgs) { 289 expectedError := fmt.Sprintf("adding space %q: provider ID %q not unique", args.Name, args.ProviderId) 290 c.Assert(err, gc.ErrorMatches, expectedError) 291 } 292 293 func (s *SpacesSuite) TestAddTwoSpacesWithDifferentNamesButSameProviderIdSucceedsInDifferentModels(c *gc.C) { 294 args1 := addSpaceArgs{ 295 Name: "my-space", 296 ProviderId: network.Id("provider id"), 297 ForState: s.State, 298 } 299 args2 := args1 300 args2.Name = "different" 301 args2.ForState = s.NewStateForModelNamed(c, "other") 302 303 space2, err := s.addTwoSpacesReturnSecond(c, args1, args2) 304 305 c.Assert(err, jc.ErrorIsNil) 306 s.assertSpaceMatchesArgs(c, space2, args2) 307 } 308 309 func (s *SpacesSuite) TestAddTwoSpacesWithDifferentNamesAndEmptyProviderIdSucceedsInSameModel(c *gc.C) { 310 args1 := addSpaceArgs{ 311 Name: "my-space", 312 ProviderId: "", 313 } 314 args2 := args1 315 args2.Name = "different" 316 317 space2, err := s.addTwoSpacesReturnSecond(c, args1, args2) 318 c.Assert(err, jc.ErrorIsNil) 319 s.assertSpaceMatchesArgs(c, space2, args2) 320 } 321 322 func (s *SpacesSuite) TestAddTwoSpacesWithDifferentNamesAndEmptyProviderIdSucceedsInDifferentModels(c *gc.C) { 323 args1 := addSpaceArgs{ 324 Name: "my-space", 325 ProviderId: "", 326 ForState: s.State, 327 } 328 args2 := args1 329 args2.Name = "different" 330 args2.ForState = s.NewStateForModelNamed(c, "other") 331 332 space2, err := s.addTwoSpacesReturnSecond(c, args1, args2) 333 334 c.Assert(err, jc.ErrorIsNil) 335 s.assertSpaceMatchesArgs(c, space2, args2) 336 } 337 338 func (s *SpacesSuite) TestAddTwoSpacesWithSameNamesAndEmptyProviderIdsFailsInSameModel(c *gc.C) { 339 args := addSpaceArgs{ 340 Name: "my-space", 341 ProviderId: "", 342 } 343 344 _, err := s.addTwoSpacesReturnSecond(c, args, args) 345 s.assertSpaceAlreadyExistsErrorForArgs(c, err, args) 346 } 347 348 func (s *SpacesSuite) assertSpaceAlreadyExistsErrorForArgs(c *gc.C, err error, args addSpaceArgs) { 349 expectedError := fmt.Sprintf("adding space %q: space %q already exists", args.Name, args.Name) 350 c.Assert(err, gc.ErrorMatches, expectedError) 351 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 352 } 353 354 func (s *SpacesSuite) TestAddTwoSpacesWithSameNamesAndProviderIdsFailsInTheSameModel(c *gc.C) { 355 args := addSpaceArgs{ 356 Name: "my-space", 357 ProviderId: network.Id("does not matter if not empty"), 358 } 359 360 _, err := s.addTwoSpacesReturnSecond(c, args, args) 361 s.assertSpaceAlreadyExistsErrorForArgs(c, err, args) 362 } 363 364 func (s *SpacesSuite) TestAddTwoSpacesWithSameNamesAndEmptyProviderIdsSuccedsInDifferentModels(c *gc.C) { 365 args1 := addSpaceArgs{ 366 Name: "my-space", 367 ProviderId: "", 368 ForState: s.State, 369 } 370 args2 := args1 371 args2.ForState = s.NewStateForModelNamed(c, "other") 372 373 space2, err := s.addTwoSpacesReturnSecond(c, args1, args2) 374 c.Assert(err, jc.ErrorIsNil) 375 s.assertSpaceMatchesArgs(c, space2, args2) 376 } 377 378 func (s *SpacesSuite) TestAddTwoSpacesWithSameNamesAndProviderIdsSuccedsInDifferentModels(c *gc.C) { 379 args1 := addSpaceArgs{ 380 Name: "my-space", 381 ProviderId: network.Id("same provider id"), 382 ForState: s.State, 383 } 384 args2 := args1 385 args2.ForState = s.NewStateForModelNamed(c, "other") 386 387 space2, err := s.addTwoSpacesReturnSecond(c, args1, args2) 388 c.Assert(err, jc.ErrorIsNil) 389 s.assertSpaceMatchesArgs(c, space2, args2) 390 } 391 392 func (s *SpacesSuite) TestAddSpaceWhenSubnetNotFound(c *gc.C) { 393 name := "my-space" 394 subnets := []string{"1.1.1.0/24"} 395 isPublic := false 396 397 _, err := s.State.AddSpace(name, "", subnets, isPublic) 398 c.Assert(err, gc.ErrorMatches, `adding space "my-space": subnet "1.1.1.0/24" not found`) 399 s.assertSpaceNotFound(c, name) 400 } 401 402 func (s *SpacesSuite) TestAddSpaceWithNonEmptyProviderIdAndInvalidNameFails(c *gc.C) { 403 args := addSpaceArgs{ 404 Name: "-bad name-", 405 ProviderId: network.Id("My Provider ID"), 406 } 407 _, err := s.addSpaceWithSubnets(c, args) 408 s.assertInvalidSpaceNameErrorAndWasNotAdded(c, err, args.Name) 409 } 410 411 func (s *SpacesSuite) assertInvalidSpaceNameErrorAndWasNotAdded(c *gc.C, err error, name string) { 412 expectedError := fmt.Sprintf("adding space %q: invalid space name", name) 413 c.Assert(err, gc.ErrorMatches, expectedError) 414 415 // The default space will be present, although we cannot add it. 416 // Only check non-default names. 417 if name != network.AlphaSpaceName { 418 s.assertSpaceNotFound(c, name) 419 } 420 } 421 422 func (s *SpacesSuite) TestAddSpaceWithEmptyProviderIdAndInvalidNameFails(c *gc.C) { 423 args := addSpaceArgs{ 424 Name: "-bad name-", 425 ProviderId: "", 426 } 427 _, err := s.addSpaceWithSubnets(c, args) 428 s.assertInvalidSpaceNameErrorAndWasNotAdded(c, err, args.Name) 429 } 430 431 func (s *SpacesSuite) TestAddSpaceWithEmptyNameAndProviderIdFails(c *gc.C) { 432 args := addSpaceArgs{ 433 Name: "", 434 ProviderId: "", 435 } 436 _, err := s.addSpaceWithSubnets(c, args) 437 s.assertInvalidSpaceNameErrorAndWasNotAdded(c, err, args.Name) 438 } 439 440 func (s *SpacesSuite) TestAddSpaceWithEmptyNameAndNonEmptyProviderIdFails(c *gc.C) { 441 args := addSpaceArgs{ 442 Name: "", 443 ProviderId: network.Id("doesn't matter"), 444 } 445 _, err := s.addSpaceWithSubnets(c, args) 446 s.assertInvalidSpaceNameErrorAndWasNotAdded(c, err, args.Name) 447 } 448 449 func (s *SpacesSuite) TestAllSpaces(c *gc.C) { 450 alphaSpace, err := s.State.SpaceByName(network.AlphaSpaceName) 451 c.Assert(err, jc.ErrorIsNil) 452 453 spaces, err := s.State.AllSpaces() 454 c.Assert(err, jc.ErrorIsNil) 455 c.Assert(spaces, jc.DeepEquals, []*state.Space{alphaSpace}) 456 457 subnets := []string{"1.1.1.0/24", "2.1.1.0/24", "3.1.1.0/24"} 458 isPublic := false 459 subnetIDs := s.addSubnets(c, subnets) 460 461 first, err := s.State.AddSpace("first", "", []string{subnetIDs[0]}, isPublic) 462 c.Assert(err, jc.ErrorIsNil) 463 second, err := s.State.AddSpace("second", "", []string{subnetIDs[1]}, isPublic) 464 c.Assert(err, jc.ErrorIsNil) 465 third, err := s.State.AddSpace("third", "", []string{subnetIDs[2]}, isPublic) 466 c.Assert(err, jc.ErrorIsNil) 467 468 actual, err := s.State.AllSpaces() 469 c.Assert(err, jc.ErrorIsNil) 470 c.Assert(actual, jc.SameContents, []*state.Space{first, second, third, alphaSpace}) 471 } 472 473 func (s *SpacesSuite) TestSpaceByID(c *gc.C) { 474 _, err := s.State.Space(network.AlphaSpaceId) 475 c.Assert(err, jc.ErrorIsNil) 476 } 477 478 func (s *SpacesSuite) TestSpaceByIDNotFound(c *gc.C) { 479 _, err := s.State.Space("42") 480 c.Assert(err, gc.ErrorMatches, "space id \"42\" not found") 481 } 482 483 func (s *SpacesSuite) TestEnsureDeadSetsLifeToDeadWhenAlive(c *gc.C) { 484 space := s.addAliveSpace(c, "alive") 485 486 s.ensureDeadAndAssertLifeIsDead(c, space) 487 s.refreshAndAssertSpaceLifeIs(c, space, state.Dead) 488 } 489 490 func (s *SpacesSuite) addAliveSpace(c *gc.C, name string) *state.Space { 491 space, err := s.State.AddSpace(name, "", nil, false) 492 c.Assert(err, jc.ErrorIsNil) 493 c.Assert(space.Life(), gc.Equals, state.Alive) 494 return space 495 } 496 497 func (s *SpacesSuite) ensureDeadAndAssertLifeIsDead(c *gc.C, space *state.Space) { 498 err := space.EnsureDead() 499 c.Assert(err, jc.ErrorIsNil) 500 c.Assert(space.Life(), gc.Equals, state.Dead) 501 } 502 503 func (s *SpacesSuite) refreshAndAssertSpaceLifeIs(c *gc.C, space *state.Space, expectedLife state.Life) { 504 err := space.Refresh() 505 c.Assert(err, jc.ErrorIsNil) 506 c.Assert(space.Life(), gc.Equals, expectedLife) 507 } 508 509 func (s *SpacesSuite) TestEnsureDeadSetsLifeToDeadWhenNotAlive(c *gc.C) { 510 space := s.addAliveSpace(c, "soon-dead") 511 s.ensureDeadAndAssertLifeIsDead(c, space) 512 513 s.ensureDeadAndAssertLifeIsDead(c, space) 514 } 515 516 func (s *SpacesSuite) TestRemoveFailsIfStillAlive(c *gc.C) { 517 space := s.addAliveSpace(c, "still-alive") 518 519 err := space.Remove() 520 c.Assert(err, gc.ErrorMatches, `cannot remove space "still-alive": space is not dead`) 521 522 s.refreshAndAssertSpaceLifeIs(c, space, state.Alive) 523 } 524 525 func (s *SpacesSuite) TestRemoveSucceedsWhenSpaceIsNotAlive(c *gc.C) { 526 space := s.addAliveSpace(c, "not-alive-soon") 527 s.ensureDeadAndAssertLifeIsDead(c, space) 528 529 s.removeSpaceAndAssertNotFound(c, space) 530 } 531 532 func (s *SpacesSuite) removeSpaceAndAssertNotFound(c *gc.C, space *state.Space) { 533 err := space.Remove() 534 c.Assert(err, jc.ErrorIsNil) 535 s.assertSpaceNotFound(c, space.Name()) 536 } 537 538 func (s *SpacesSuite) TestRemoveSucceedsWhenCalledTwice(c *gc.C) { 539 space := s.addAliveSpace(c, "twice-deleted") 540 s.ensureDeadAndAssertLifeIsDead(c, space) 541 s.removeSpaceAndAssertNotFound(c, space) 542 543 err := space.Remove() 544 c.Assert(err, gc.ErrorMatches, `cannot remove space "twice-deleted": not found or not dead`) 545 } 546 547 func (s *SpacesSuite) TestRefreshUpdatesStaleDocData(c *gc.C) { 548 space := s.addAliveSpace(c, "original") 549 spaceCopy, err := s.State.SpaceByName(space.Name()) 550 c.Assert(err, jc.ErrorIsNil) 551 552 s.ensureDeadAndAssertLifeIsDead(c, space) 553 c.Assert(spaceCopy.Life(), gc.Equals, state.Alive) 554 555 err = spaceCopy.Refresh() 556 c.Assert(err, jc.ErrorIsNil) 557 c.Assert(spaceCopy.Life(), gc.Equals, state.Dead) 558 } 559 560 func (s *SpacesSuite) TestRefreshFailsWithNotFoundWhenRemoved(c *gc.C) { 561 space := s.addAliveSpace(c, "soon-removed") 562 s.ensureDeadAndAssertLifeIsDead(c, space) 563 s.removeSpaceAndAssertNotFound(c, space) 564 565 err := space.Refresh() 566 s.assertSpaceNotFoundError(c, err, "soon-removed") 567 } 568 569 func (s *SpacesSuite) TestFanSubnetInheritsSpace(c *gc.C) { 570 args := addSpaceArgs{ 571 Name: "space1", 572 ProviderId: network.Id("some id 2"), 573 SubnetCIDRs: []string{"1.1.1.0/24", "2001:cbd0::/32"}, 574 } 575 space, err := s.addSpaceWithSubnets(c, args) 576 c.Assert(err, jc.ErrorIsNil) 577 s.assertSpaceMatchesArgs(c, space, args) 578 info := network.SubnetInfo{ 579 CIDR: "253.1.0.0/16", 580 VLANTag: 79, 581 AvailabilityZones: []string{"AvailabilityZone"}, 582 } 583 info.SetFan("1.1.1.0/24", "253.0.0.0/8") 584 _, err = s.State.AddSubnet(info) 585 c.Assert(err, jc.ErrorIsNil) 586 587 err = space.Refresh() 588 c.Assert(err, jc.ErrorIsNil) 589 spaceInfo, err := space.NetworkSpace() 590 c.Assert(err, jc.ErrorIsNil) 591 subnets := spaceInfo.Subnets 592 var foundSubnet network.SubnetInfo 593 for _, subnet := range subnets { 594 if subnet.CIDR == "253.1.0.0/16" { 595 foundSubnet = subnet 596 break 597 } 598 } 599 c.Assert(foundSubnet, gc.NotNil) 600 c.Assert(foundSubnet.SpaceID, gc.Equals, space.Id()) 601 } 602 603 func (s *SpacesSuite) TestSpaceToNetworkSpace(c *gc.C) { 604 args := addSpaceArgs{ 605 Name: "space1", 606 ProviderId: network.Id("some id 2"), 607 SubnetCIDRs: []string{"1.1.1.0/24", "2001:cbd0::/32"}, 608 } 609 space, err := s.addSpaceWithSubnets(c, args) 610 c.Assert(err, jc.ErrorIsNil) 611 s.assertSpaceMatchesArgs(c, space, args) 612 info := network.SubnetInfo{ 613 CIDR: "253.1.0.0/16", 614 VLANTag: 79, 615 AvailabilityZones: []string{"AvailabilityZone"}, 616 } 617 info.SetFan("1.1.1.0/24", "253.0.0.0/8") 618 _, err = s.State.AddSubnet(info) 619 c.Assert(err, jc.ErrorIsNil) 620 621 err = space.Refresh() 622 c.Assert(err, jc.ErrorIsNil) 623 624 spaceInfo, err := space.NetworkSpace() 625 c.Assert(err, jc.ErrorIsNil) 626 627 expSpaceInfo := network.SpaceInfo{ 628 Name: "space1", 629 ID: space.Id(), 630 ProviderId: args.ProviderId, 631 Subnets: []network.SubnetInfo{ 632 { 633 ID: "0", 634 SpaceID: space.Id(), 635 SpaceName: "space1", 636 CIDR: "1.1.1.0/24", 637 VLANTag: 79, 638 AvailabilityZones: []string{"AvailabilityZone"}, 639 ProviderSpaceId: "some id 2", 640 Life: life.Alive, 641 }, 642 { 643 ID: "2", 644 SpaceID: space.Id(), 645 SpaceName: "space1", 646 CIDR: "253.1.0.0/16", 647 VLANTag: 79, 648 AvailabilityZones: []string{"AvailabilityZone"}, 649 FanInfo: &network.FanCIDRs{ 650 FanLocalUnderlay: "1.1.1.0/24", 651 FanOverlay: "253.0.0.0/8", 652 }, 653 ProviderSpaceId: "some id 2", 654 Life: life.Alive, 655 }, 656 { 657 ID: "1", 658 SpaceID: space.Id(), 659 SpaceName: "space1", 660 CIDR: "2001:cbd0::/32", 661 VLANTag: 79, 662 AvailabilityZones: []string{"AvailabilityZone"}, 663 ProviderSpaceId: "some id 2", 664 Life: life.Alive, 665 }, 666 }, 667 } 668 669 // Sort subnets by CIDR for test consistency. 670 network.SortSubnetInfos(spaceInfo.Subnets) 671 network.SortSubnetInfos(expSpaceInfo.Subnets) 672 673 c.Assert(spaceInfo, gc.DeepEquals, expSpaceInfo) 674 675 // Test that AllSpaceInfos works the same way. 676 allSpaceInfos, err := s.State.AllSpaceInfos() 677 c.Assert(err, jc.ErrorIsNil) 678 679 space1 := allSpaceInfos.GetByName("space1") 680 c.Assert(space1, gc.NotNil) 681 682 network.SortSubnetInfos(space1.Subnets) 683 c.Assert(*space1, gc.DeepEquals, expSpaceInfo) 684 } 685 686 type SpacesDiscoverySuite struct { 687 ConnSuite 688 } 689 690 var _ = gc.Suite(&SpacesDiscoverySuite{}) 691 692 var twoSubnets = []network.SubnetInfo{ 693 { 694 ProviderId: "1", 695 AvailabilityZones: []string{"1", "2"}, 696 CIDR: "10.0.0.1/24", 697 }, 698 { 699 ProviderId: "2", 700 AvailabilityZones: []string{"3", "4"}, 701 CIDR: "10.100.30.1/24", 702 }, 703 } 704 705 var twoSubnetsAndIgnored = []network.SubnetInfo{ 706 { 707 ProviderId: "1", 708 AvailabilityZones: []string{"1", "2"}, 709 CIDR: "10.0.0.1/24", 710 }, 711 { 712 ProviderId: "2", 713 AvailabilityZones: []string{"3", "4"}, 714 CIDR: "10.100.30.1/24", 715 }, 716 // Interface-local multicast: 717 { 718 ProviderId: "foo", 719 AvailabilityZones: []string{"bar", "baz"}, 720 CIDR: "ff51:dead:beef::/48", 721 }, 722 // Link-local multicast: 723 { 724 ProviderId: "moo", 725 AvailabilityZones: []string{"bar", "baz"}, 726 CIDR: "ff32:dead:beef::/48", 727 }, 728 // IPv6 link-local unicast: 729 { 730 ProviderId: "baa", 731 AvailabilityZones: []string{"bar", "baz"}, 732 CIDR: "fe80:dead:beef::/48", 733 }, 734 // IPv4 link-local unicast: 735 { 736 ProviderId: "maa", 737 AvailabilityZones: []string{"bar", "baz"}, 738 CIDR: "169.254.13.0/24", 739 }, 740 } 741 742 var anotherTwoSubnets = []network.SubnetInfo{ 743 { 744 ProviderId: "3", 745 AvailabilityZones: []string{"5", "6"}, 746 CIDR: "10.101.0.1/24", 747 }, 748 { 749 ProviderId: "4", 750 AvailabilityZones: []string{"7", "8"}, 751 CIDR: "10.105.0.1/24", 752 }, 753 } 754 755 var fourSubnets = []network.SubnetInfo{ 756 { 757 ProviderId: "1", 758 AvailabilityZones: []string{"1", "2"}, 759 CIDR: "10.0.0.1/24", 760 }, 761 { 762 ProviderId: "2", 763 AvailabilityZones: []string{"3", "4"}, 764 CIDR: "10.100.30.1/24", 765 }, 766 { 767 ProviderId: "3", 768 AvailabilityZones: []string{"5", "6"}, 769 CIDR: "10.101.0.1/24", 770 }, 771 { 772 ProviderId: "4", 773 AvailabilityZones: []string{"7", "8"}, 774 CIDR: "10.105.0.1/24", 775 }, 776 } 777 778 var twoSubnetsAfterFAN = []network.SubnetInfo{ 779 { 780 ProviderId: "1", 781 AvailabilityZones: []string{"1", "2"}, 782 CIDR: "10.0.0.1/24", 783 }, 784 { 785 ProviderId: "2", 786 AvailabilityZones: []string{"3", "4"}, 787 CIDR: "10.100.30.1/24", 788 }, 789 { 790 ProviderId: network.Id(fmt.Sprintf("2-%s-10-100-30-0-24", network.InFan)), 791 AvailabilityZones: []string{"3", "4"}, 792 CIDR: "253.30.0.0/16", 793 }, 794 } 795 796 func checkSubnetsEqual(c *gc.C, subnets []*state.Subnet, subnetInfos []network.SubnetInfo) { 797 c.Assert(len(subnetInfos), gc.Equals, len(subnets)) 798 for i, subnetInfo := range subnetInfos { 799 subnet := subnets[i] 800 c.Check(subnetInfo.CIDR, gc.Equals, subnet.CIDR()) 801 c.Check(subnetInfo.AvailabilityZones, gc.DeepEquals, subnet.AvailabilityZones()) 802 c.Check(subnetInfo.ProviderId, gc.Equals, subnet.ProviderId()) 803 c.Check(subnetInfo.ProviderNetworkId, gc.Equals, subnet.ProviderNetworkId()) 804 c.Check(subnetInfo.VLANTag, gc.Equals, subnet.VLANTag()) 805 } 806 } 807 808 func (s *SpacesDiscoverySuite) TestSaveProviderSubnets(c *gc.C) { 809 err := s.State.SaveProviderSubnets(twoSubnets, "") 810 c.Check(err, jc.ErrorIsNil) 811 812 subnets, err := s.State.AllSubnets() 813 c.Assert(err, jc.ErrorIsNil) 814 checkSubnetsEqual(c, subnets, twoSubnets) 815 } 816 817 // TODO(wpk) 2017-05-24 this test will have to be rewritten when we support removing spaces/subnets in discovery. 818 func (s *SpacesDiscoverySuite) TestSaveProviderSubnetsOnlyAddsSubnets(c *gc.C) { 819 err := s.State.SaveProviderSubnets(twoSubnets, "") 820 c.Check(err, jc.ErrorIsNil) 821 822 err = s.State.SaveProviderSubnets(anotherTwoSubnets, "") 823 c.Check(err, jc.ErrorIsNil) 824 825 subnets, err := s.State.AllSubnets() 826 c.Assert(err, jc.ErrorIsNil) 827 checkSubnetsEqual(c, subnets, fourSubnets) 828 } 829 830 func (s *SpacesDiscoverySuite) TestSaveProviderSubnetsOnlyIdempotent(c *gc.C) { 831 err := s.State.SaveProviderSubnets(twoSubnets, "") 832 c.Check(err, jc.ErrorIsNil) 833 834 subnets1, err := s.State.AllSubnets() 835 c.Assert(err, jc.ErrorIsNil) 836 837 err = s.State.SaveProviderSubnets(twoSubnets, "") 838 c.Check(err, jc.ErrorIsNil) 839 840 subnets2, err := s.State.AllSubnets() 841 c.Assert(err, jc.ErrorIsNil) 842 c.Check(subnets1, jc.DeepEquals, subnets2) 843 } 844 845 func (s *SpacesDiscoverySuite) TestSaveProviderSubnetsWithFAN(c *gc.C) { 846 err := s.Model.UpdateModelConfig(map[string]interface{}{"fan-config": "10.100.0.0/16=253.0.0.0/8"}, nil) 847 c.Assert(err, jc.ErrorIsNil) 848 849 err = s.State.SaveProviderSubnets(twoSubnets, "") 850 c.Check(err, jc.ErrorIsNil) 851 852 subnets, err := s.State.AllSubnets() 853 c.Assert(err, jc.ErrorIsNil) 854 855 checkSubnetsEqual(c, subnets, twoSubnetsAfterFAN) 856 } 857 858 func (s *SpacesDiscoverySuite) TestSaveProviderSubnetsIgnoredWithFAN(c *gc.C) { 859 // This is just a test configuration. This configuration may be 860 // considered invalid in the future. Here we show that this 861 // configuration is ignored. 862 err := s.Model.UpdateModelConfig( 863 map[string]interface{}{"fan-config": "fe80:dead:beef::/48=fe80:dead:beef::/24"}, nil) 864 c.Assert(err, jc.ErrorIsNil) 865 866 err = s.State.SaveProviderSubnets(twoSubnetsAndIgnored, "") 867 c.Check(err, jc.ErrorIsNil) 868 869 subnets, err := s.State.AllSubnets() 870 c.Assert(err, jc.ErrorIsNil) 871 872 checkSubnetsEqual(c, subnets, twoSubnets) 873 } 874 875 func (s *SpacesDiscoverySuite) TestSaveProviderSubnetsIgnored(c *gc.C) { 876 err := s.State.SaveProviderSubnets(twoSubnetsAndIgnored, "") 877 c.Check(err, jc.ErrorIsNil) 878 879 subnets, err := s.State.AllSubnets() 880 c.Assert(err, jc.ErrorIsNil) 881 882 checkSubnetsEqual(c, subnets, twoSubnets) 883 }