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