github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/firewall/egressaddresswatcher_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewall_test 5 6 import ( 7 "github.com/juju/names/v5" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/common/firewall" 13 apiservertesting "github.com/juju/juju/apiserver/testing" 14 "github.com/juju/juju/core/network" 15 "github.com/juju/juju/core/watcher" 16 statetesting "github.com/juju/juju/state/testing" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 var _ = gc.Suite(&addressWatcherSuite{}) 21 22 type addressWatcherSuite struct { 23 coretesting.BaseSuite 24 25 resources *common.Resources 26 authorizer *apiservertesting.FakeAuthorizer 27 st *mockState 28 } 29 30 func (s *addressWatcherSuite) SetUpTest(c *gc.C) { 31 s.BaseSuite.SetUpTest(c) 32 33 s.resources = common.NewResources() 34 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 35 36 s.authorizer = &apiservertesting.FakeAuthorizer{ 37 Tag: names.NewMachineTag("0"), 38 Controller: true, 39 } 40 41 s.st = newMockState(coretesting.ModelTag.Id()) 42 } 43 44 func (s *addressWatcherSuite) setupRelation(c *gc.C, addr string) *mockRelation { 45 rel := newMockRelation(123) 46 rel.ruwApp = "django" 47 // Initial event. 48 rel.ew.changes <- []string{} 49 s.st.relations["remote-db2:db django:db"] = rel 50 unit := newMockUnit("django/0") 51 unit.publicAddress = network.NewSpaceAddress(addr) 52 unit.machineId = "0" 53 s.st.units["django/0"] = unit 54 app := newMockApplication("django") 55 app.units = []*mockUnit{unit} 56 s.st.applications["django"] = app 57 s.st.machines["0"] = newMockMachine("0") 58 return rel 59 } 60 61 func (s *addressWatcherSuite) TestInitial(c *gc.C) { 62 rel := s.setupRelation(c, "54.1.2.3") 63 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 64 c.Assert(err, jc.ErrorIsNil) 65 defer statetesting.AssertStop(c, w) 66 wc := statetesting.NewStringsWatcherC(c, w) 67 // django/0 is initially in scope 68 rel.ruw.changes <- watcher.RelationUnitsChange{ 69 Changed: map[string]watcher.UnitSettings{ 70 "django/0": {}, 71 }, 72 } 73 74 wc.AssertChange("54.1.2.3/32") 75 wc.AssertNoChange() 76 } 77 78 func (s *addressWatcherSuite) TestUnitEntersScope(c *gc.C) { 79 rel := s.setupRelation(c, "54.1.2.3") 80 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 81 c.Assert(err, jc.ErrorIsNil) 82 defer statetesting.AssertStop(c, w) 83 wc := statetesting.NewStringsWatcherC(c, w) 84 rel.ruw.changes <- watcher.RelationUnitsChange{} 85 86 // Initial event. 87 wc.AssertChange() 88 wc.AssertNoChange() 89 90 rel.ruw.changes <- watcher.RelationUnitsChange{ 91 Changed: map[string]watcher.UnitSettings{ 92 "django/0": {}, 93 }, 94 } 95 wc.AssertChange("54.1.2.3/32") 96 wc.AssertNoChange() 97 98 // A not found unit doesn't trigger an event. 99 rel.ruw.changes <- watcher.RelationUnitsChange{ 100 Changed: map[string]watcher.UnitSettings{ 101 "unknown/0": {}, 102 }, 103 } 104 wc.AssertNoChange() 105 } 106 107 func (s *addressWatcherSuite) TestTwoUnitsEntersScope(c *gc.C) { 108 rel := s.setupRelation(c, "54.1.2.3") 109 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 110 c.Assert(err, jc.ErrorIsNil) 111 defer statetesting.AssertStop(c, w) 112 wc := statetesting.NewStringsWatcherC(c, w) 113 rel.ruw.changes <- watcher.RelationUnitsChange{} 114 115 unit := newMockUnit("django/1") 116 unit.publicAddress = network.NewSpaceAddress("54.4.5.6") 117 unit.machineId = "1" 118 s.st.units["django/1"] = unit 119 s.st.machines["1"] = newMockMachine("1") 120 121 // Initial event. 122 wc.AssertChange() 123 wc.AssertNoChange() 124 125 rel.ruw.changes <- watcher.RelationUnitsChange{ 126 Changed: map[string]watcher.UnitSettings{ 127 "django/0": {}, 128 "django/1": {}, 129 }, 130 } 131 wc.AssertChange("54.1.2.3/32", "54.4.5.6/32") 132 wc.AssertNoChange() 133 } 134 135 func (s *addressWatcherSuite) TestAnotherUnitsEntersScope(c *gc.C) { 136 rel := s.setupRelation(c, "54.1.2.3") 137 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 138 c.Assert(err, jc.ErrorIsNil) 139 defer statetesting.AssertStop(c, w) 140 wc := statetesting.NewStringsWatcherC(c, w) 141 rel.ruw.changes <- watcher.RelationUnitsChange{} 142 143 // Initial event. 144 wc.AssertChange() 145 wc.AssertNoChange() 146 147 rel.ruw.changes <- watcher.RelationUnitsChange{ 148 Changed: map[string]watcher.UnitSettings{ 149 "django/0": {}, 150 }, 151 } 152 wc.AssertChange("54.1.2.3/32") 153 wc.AssertNoChange() 154 155 unit := newMockUnit("django/1") 156 unit.publicAddress = network.NewSpaceAddress("54.4.5.6") 157 unit.machineId = "1" 158 s.st.units["django/1"] = unit 159 s.st.machines["1"] = newMockMachine("1") 160 rel.ruw.changes <- watcher.RelationUnitsChange{ 161 Changed: map[string]watcher.UnitSettings{ 162 "django/1": {}, 163 }, 164 } 165 wc.AssertChange("54.1.2.3/32", "54.4.5.6/32") 166 wc.AssertNoChange() 167 } 168 169 func (s *addressWatcherSuite) TestUnitEntersScopeNoPublicAddress(c *gc.C) { 170 rel := s.setupRelation(c, "") 171 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 172 c.Assert(err, jc.ErrorIsNil) 173 defer statetesting.AssertStop(c, w) 174 wc := statetesting.NewStringsWatcherC(c, w) 175 rel.ruw.changes <- watcher.RelationUnitsChange{ 176 Changed: map[string]watcher.UnitSettings{ 177 "django/0": {}, 178 }, 179 } 180 181 // Even though the unit has no public address, 182 // we still expect the initial event. 183 wc.AssertChange() 184 wc.AssertNoChange() 185 186 // This time no event. 187 rel.ruw.changes <- watcher.RelationUnitsChange{ 188 Changed: map[string]watcher.UnitSettings{ 189 "django/0": {}, 190 }, 191 } 192 wc.AssertNoChange() 193 } 194 195 func (s *addressWatcherSuite) TestUnitEntersScopeNotAssigned(c *gc.C) { 196 rel := s.setupRelation(c, "") 197 s.st.units["django/0"].assigned = false 198 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 199 c.Assert(err, jc.ErrorIsNil) 200 defer statetesting.AssertStop(c, w) 201 wc := statetesting.NewStringsWatcherC(c, w) 202 203 rel.ruw.changes <- watcher.RelationUnitsChange{ 204 Changed: map[string]watcher.UnitSettings{ 205 "django/0": {}, 206 }, 207 } 208 209 // Even though the unit is not assigned, 210 // we still expect the initial event. 211 wc.AssertChange() 212 wc.AssertNoChange() 213 214 // This time no event. 215 rel.ruw.changes <- watcher.RelationUnitsChange{ 216 Changed: map[string]watcher.UnitSettings{ 217 "django/0": {}, 218 }, 219 } 220 wc.AssertNoChange() 221 } 222 223 func (s *addressWatcherSuite) TestUnitLeavesScopeInitial(c *gc.C) { 224 rel := s.setupRelation(c, "54.1.2.3") 225 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 226 c.Assert(err, jc.ErrorIsNil) 227 defer statetesting.AssertStop(c, w) 228 wc := statetesting.NewStringsWatcherC(c, w) 229 230 rel.ruw.changes <- watcher.RelationUnitsChange{ 231 Departed: []string{"django/0"}, 232 } 233 234 // Even though the unit has not been seen via enter scope, 235 // we still expect the initial event. 236 wc.AssertChange() 237 wc.AssertNoChange() 238 } 239 240 func (s *addressWatcherSuite) TestUnitLeavesScope(c *gc.C) { 241 rel := s.setupRelation(c, "54.1.2.3") 242 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 243 c.Assert(err, jc.ErrorIsNil) 244 defer statetesting.AssertStop(c, w) 245 wc := statetesting.NewStringsWatcherC(c, w) 246 rel.ruw.changes <- watcher.RelationUnitsChange{} 247 248 unit := newMockUnit("django/1") 249 unit.publicAddress = network.NewSpaceAddress("54.4.5.6") 250 unit.machineId = "1" 251 s.st.units["django/1"] = unit 252 s.st.machines["1"] = newMockMachine("1") 253 254 // Initial event. 255 wc.AssertChange() 256 wc.AssertNoChange() 257 258 rel.ruw.changes <- watcher.RelationUnitsChange{ 259 Changed: map[string]watcher.UnitSettings{ 260 "django/0": {}, 261 "django/1": {}, 262 }, 263 } 264 wc.AssertChange("54.1.2.3/32", "54.4.5.6/32") 265 wc.AssertNoChange() 266 267 rel.ruw.changes <- watcher.RelationUnitsChange{ 268 Departed: []string{"django/0"}, 269 } 270 271 wc.AssertChange("54.4.5.6/32") 272 wc.AssertNoChange() 273 } 274 275 func (s *addressWatcherSuite) TestTwoUnitsSameAddressOneLeaves(c *gc.C) { 276 rel := s.setupRelation(c, "54.1.2.3") 277 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 278 c.Assert(err, jc.ErrorIsNil) 279 defer statetesting.AssertStop(c, w) 280 wc := statetesting.NewStringsWatcherC(c, w) 281 rel.ruw.changes <- watcher.RelationUnitsChange{} 282 283 unit := newMockUnit("django/1") 284 unit.publicAddress = network.NewSpaceAddress("54.1.2.3") 285 unit.machineId = "0" 286 s.st.units["django/1"] = unit 287 288 // Initial event. 289 wc.AssertChange() 290 wc.AssertNoChange() 291 292 rel.ruw.changes <- watcher.RelationUnitsChange{ 293 Changed: map[string]watcher.UnitSettings{ 294 "django/0": {}, 295 "django/1": {}, 296 }, 297 } 298 wc.AssertChange("54.1.2.3/32") 299 wc.AssertNoChange() 300 301 // One leaves, no change. 302 rel.ruw.changes <- watcher.RelationUnitsChange{ 303 Departed: []string{"django/0"}, 304 } 305 306 wc.AssertNoChange() 307 308 // Last one leaves. 309 rel.ruw.changes <- watcher.RelationUnitsChange{ 310 Departed: []string{"django/1"}, 311 } 312 313 wc.AssertChange() 314 wc.AssertNoChange() 315 } 316 317 func (s *addressWatcherSuite) TestSecondUnitJoinsOnSameMachine(c *gc.C) { 318 rel := s.setupRelation(c, "55.1.2.3") 319 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 320 c.Assert(err, jc.ErrorIsNil) 321 defer statetesting.AssertStop(c, w) 322 wc := statetesting.NewStringsWatcherC(c, w) 323 // django/0 is initially in scope 324 rel.ruw.changes <- watcher.RelationUnitsChange{ 325 Changed: map[string]watcher.UnitSettings{ 326 "django/0": {}, 327 }, 328 } 329 330 wc.AssertChange("55.1.2.3/32") 331 wc.AssertNoChange() 332 333 // Another unit joins on the same machine. 334 unit := newMockUnit("django/1") 335 unit.machineId = "0" 336 s.st.units["django/1"] = unit 337 338 rel.ruw.changes <- watcher.RelationUnitsChange{ 339 Changed: map[string]watcher.UnitSettings{ 340 "django/1": {}, 341 }, 342 } 343 // No new addresses. 344 wc.AssertNoChange() 345 346 // Machine 0 changes address. 347 s.st.units["django/0"].updateAddress("56.1.2.3") 348 s.st.units["django/1"].updateAddress("56.1.2.3") 349 s.st.machines["0"].watcher.changes <- struct{}{} 350 351 wc.AssertChange("56.1.2.3/32") 352 wc.AssertNoChange() 353 } 354 355 func (s *addressWatcherSuite) TestSeesMachineAddressChanges(c *gc.C) { 356 rel := s.setupRelation(c, "2.3.4.5") 357 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 358 c.Assert(err, jc.ErrorIsNil) 359 defer statetesting.AssertStop(c, w) 360 wc := statetesting.NewStringsWatcherC(c, w) 361 // django/0 is initially in scope 362 rel.ruw.changes <- watcher.RelationUnitsChange{ 363 Changed: map[string]watcher.UnitSettings{ 364 "django/0": {}, 365 }, 366 } 367 368 wc.AssertChange("2.3.4.5/32") 369 wc.AssertNoChange() 370 371 s.st.units["django/0"].updateAddress("5.4.3.3") 372 s.st.machines["0"].watcher.changes <- struct{}{} 373 374 wc.AssertChange("5.4.3.3/32") 375 wc.AssertNoChange() 376 } 377 378 func (s *addressWatcherSuite) TestHandlesMachineAddressChangesWithNoEffect(c *gc.C) { 379 rel := s.setupRelation(c, "2.3.4.5") 380 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 381 c.Assert(err, jc.ErrorIsNil) 382 defer statetesting.AssertStop(c, w) 383 wc := statetesting.NewStringsWatcherC(c, w) 384 // django/0 is initially in scope 385 rel.ruw.changes <- watcher.RelationUnitsChange{ 386 Changed: map[string]watcher.UnitSettings{ 387 "django/0": {}, 388 }, 389 } 390 391 wc.AssertChange("2.3.4.5/32") 392 wc.AssertNoChange() 393 394 // Public address for the unit stays the same (maybe some other address changed). 395 s.st.machines["0"].watcher.changes <- struct{}{} 396 397 wc.AssertNoChange() 398 } 399 400 func (s *addressWatcherSuite) TestHandlesUnitGoneWhenMachineAddressChanges(c *gc.C) { 401 rel := s.setupRelation(c, "2.3.4.5") 402 unit := newMockUnit("django/1") 403 unit.publicAddress = network.NewSpaceAddress("2.3.4.5") 404 unit.machineId = "0" 405 s.st.units["django/1"] = unit 406 rel.ruw.changes <- watcher.RelationUnitsChange{ 407 Changed: map[string]watcher.UnitSettings{ 408 "django/0": {}, 409 "django/1": {}, 410 }, 411 } 412 413 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 414 c.Assert(err, jc.ErrorIsNil) 415 defer statetesting.AssertStop(c, w) 416 wc := statetesting.NewStringsWatcherC(c, w) 417 418 wc.AssertChange("2.3.4.5/32") 419 wc.AssertNoChange() 420 421 rel.ruw.changes <- watcher.RelationUnitsChange{ 422 Departed: []string{"django/1"}, 423 } 424 s.st.units["django/0"].updateAddress("6.7.8.9") 425 s.st.machines["0"].watcher.changes <- struct{}{} 426 427 wc.AssertChange("6.7.8.9/32") 428 wc.AssertNoChange() 429 } 430 431 func (s *addressWatcherSuite) TestModelEgressAddressUsed(c *gc.C) { 432 s.st.configAttrs["egress-subnets"] = "10.0.0.1/16" 433 rel := s.setupRelation(c, "54.1.2.3") 434 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 435 c.Assert(err, jc.ErrorIsNil) 436 defer statetesting.AssertStop(c, w) 437 wc := statetesting.NewStringsWatcherC(c, w) 438 rel.ruw.changes <- watcher.RelationUnitsChange{} 439 440 // Initial event. 441 wc.AssertChange() 442 wc.AssertNoChange() 443 444 rel.ruw.changes <- watcher.RelationUnitsChange{ 445 Changed: map[string]watcher.UnitSettings{ 446 "django/0": {}, 447 }, 448 } 449 wc.AssertChange("10.0.0.1/16") 450 wc.AssertNoChange() 451 452 // Change user configured egress addresses. 453 s.st.configAttrs["egress-subnets"] = "192.168.0.1/16" 454 s.st.modelWatcher.changes <- struct{}{} 455 wc.AssertChange("192.168.0.1/16") 456 wc.AssertNoChange() 457 458 // Reset user configured egress addresses. 459 s.st.configAttrs["egress-subnets"] = "" 460 s.st.modelWatcher.changes <- struct{}{} 461 wc.AssertChange("54.1.2.3/32") 462 wc.AssertNoChange() 463 464 // A not found unit doesn't trigger an event. 465 rel.ruw.changes <- watcher.RelationUnitsChange{ 466 Changed: map[string]watcher.UnitSettings{ 467 "unknown/0": {}, 468 }, 469 } 470 wc.AssertNoChange() 471 } 472 473 func (s *addressWatcherSuite) TestRelationEgressAddressUsed(c *gc.C) { 474 // Set up a model egress-address to ensure it is ignored when a relation one is used. 475 s.st.configAttrs["egress-subnets"] = "10.0.0.1/16" 476 rel := s.setupRelation(c, "54.1.2.3") 477 w, err := firewall.NewEgressAddressWatcher(s.st, rel, "django") 478 c.Assert(err, jc.ErrorIsNil) 479 defer statetesting.AssertStop(c, w) 480 wc := statetesting.NewStringsWatcherC(c, w) 481 rel.ruw.changes <- watcher.RelationUnitsChange{} 482 483 // Initial event. 484 wc.AssertChange() 485 wc.AssertNoChange() 486 487 // New relation ingress cidr. 488 rel.ew.changes <- []string{"192.168.0.0/8"} 489 490 rel.ruw.changes <- watcher.RelationUnitsChange{ 491 Changed: map[string]watcher.UnitSettings{ 492 "django/0": {}, 493 }, 494 } 495 wc.AssertChange("192.168.0.0/8") 496 wc.AssertNoChange() 497 498 // Change model egress addresses, no change since relation overrides. 499 s.st.configAttrs["egress-subnets"] = "192.168.0.1/16" 500 s.st.modelWatcher.changes <- struct{}{} 501 wc.AssertNoChange() 502 503 rel.ew.changes <- []string{"10.1.2.0/8"} 504 wc.AssertChange("10.1.2.0/8") 505 wc.AssertNoChange() 506 507 // A not found unit doesn't trigger an event. 508 rel.ruw.changes <- watcher.RelationUnitsChange{ 509 Changed: map[string]watcher.UnitSettings{ 510 "unknown/0": {}, 511 }, 512 } 513 wc.AssertNoChange() 514 }