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  }