github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/firewaller/firewaller_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package firewaller_test
     5  
     6  import (
     7  	"fmt"
     8  	"reflect"
     9  	"sync/atomic"
    10  	"time"
    11  
    12  	"github.com/juju/clock"
    13  	"github.com/juju/clock/testclock"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/testing"
    16  	jc "github.com/juju/testing/checkers"
    17  	"github.com/juju/utils"
    18  	gc "gopkg.in/check.v1"
    19  	"gopkg.in/juju/charm.v6"
    20  	"gopkg.in/juju/names.v2"
    21  	"gopkg.in/juju/worker.v1"
    22  
    23  	"github.com/juju/juju/api"
    24  	basetesting "github.com/juju/juju/api/base/testing"
    25  	"github.com/juju/juju/api/credentialvalidator"
    26  	"github.com/juju/juju/api/crossmodelrelations"
    27  	apifirewaller "github.com/juju/juju/api/firewaller"
    28  	"github.com/juju/juju/api/remoterelations"
    29  	apitesting "github.com/juju/juju/api/testing"
    30  	"github.com/juju/juju/apiserver/params"
    31  	"github.com/juju/juju/core/crossmodel"
    32  	"github.com/juju/juju/core/status"
    33  	"github.com/juju/juju/environs"
    34  	"github.com/juju/juju/environs/config"
    35  	"github.com/juju/juju/environs/context"
    36  	"github.com/juju/juju/environs/instances"
    37  	jujutesting "github.com/juju/juju/juju/testing"
    38  	"github.com/juju/juju/network"
    39  	"github.com/juju/juju/provider/dummy"
    40  	"github.com/juju/juju/state"
    41  	statetesting "github.com/juju/juju/state/testing"
    42  	coretesting "github.com/juju/juju/testing"
    43  	"github.com/juju/juju/testing/factory"
    44  	"github.com/juju/juju/worker/firewaller"
    45  )
    46  
    47  // firewallerBaseSuite implements common functionality for embedding
    48  // into each of the other per-mode suites.
    49  type firewallerBaseSuite struct {
    50  	jujutesting.JujuConnSuite
    51  	testing.OsEnvSuite
    52  	op                 <-chan dummy.Operation
    53  	charm              *state.Charm
    54  	controllerMachine  *state.Machine
    55  	controllerPassword string
    56  
    57  	st                   api.Connection
    58  	firewaller           *apifirewaller.Client
    59  	remoteRelations      *remoterelations.Client
    60  	crossmodelFirewaller *crossmodelrelations.Client
    61  	clock                clock.Clock
    62  
    63  	callCtx           context.ProviderCallContext
    64  	credentialsFacade *credentialvalidator.Facade
    65  }
    66  
    67  func (s *firewallerBaseSuite) SetUpSuite(c *gc.C) {
    68  	s.OsEnvSuite.SetUpSuite(c)
    69  	s.JujuConnSuite.SetUpSuite(c)
    70  }
    71  
    72  func (s *firewallerBaseSuite) TearDownSuite(c *gc.C) {
    73  	s.JujuConnSuite.TearDownSuite(c)
    74  	s.OsEnvSuite.TearDownSuite(c)
    75  }
    76  
    77  func (s *firewallerBaseSuite) SetUpTest(c *gc.C) {
    78  	s.OsEnvSuite.SetUpTest(c)
    79  	s.JujuConnSuite.SetUpTest(c)
    80  
    81  	s.callCtx = context.NewCloudCallContext()
    82  }
    83  
    84  func (s *firewallerBaseSuite) TearDownTest(c *gc.C) {
    85  	s.JujuConnSuite.TearDownTest(c)
    86  	s.OsEnvSuite.TearDownTest(c)
    87  }
    88  
    89  var _ worker.Worker = (*firewaller.Firewaller)(nil)
    90  
    91  func (s *firewallerBaseSuite) setUpTest(c *gc.C, firewallMode string) {
    92  	add := map[string]interface{}{"firewall-mode": firewallMode}
    93  	s.DummyConfig = dummy.SampleConfig().Merge(add).Delete("admin-secret")
    94  
    95  	s.JujuConnSuite.SetUpTest(c)
    96  	s.charm = s.AddTestingCharm(c, "dummy")
    97  
    98  	// Create a manager machine and login to the API.
    99  	var err error
   100  	s.controllerMachine, err = s.State.AddMachine("quantal", state.JobManageModel)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	s.controllerPassword, err = utils.RandomPassword()
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	err = s.controllerMachine.SetPassword(s.controllerPassword)
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	err = s.controllerMachine.SetProvisioned("i-manager", "", "fake_nonce", nil)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  	s.st = s.OpenAPIAsMachine(c, s.controllerMachine.Tag(), s.controllerPassword, "fake_nonce")
   109  	c.Assert(s.st, gc.NotNil)
   110  
   111  	// Create the API facades.
   112  	firewallerClient, err := apifirewaller.NewClient(s.st)
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	s.firewaller = firewallerClient
   115  	s.remoteRelations = remoterelations.NewClient(s.st)
   116  	c.Assert(s.remoteRelations, gc.NotNil)
   117  
   118  	s.credentialsFacade = credentialvalidator.NewFacade(s.st)
   119  }
   120  
   121  // assertPorts retrieves the open ports of the instance and compares them
   122  // to the expected.
   123  func (s *firewallerBaseSuite) assertPorts(c *gc.C, inst instances.Instance, machineId string, expected []network.IngressRule) {
   124  	fwInst, ok := inst.(instances.InstanceFirewaller)
   125  	c.Assert(ok, gc.Equals, true)
   126  
   127  	start := time.Now()
   128  	for {
   129  		s.BackingState.StartSync()
   130  		got, err := fwInst.IngressRules(s.callCtx, machineId)
   131  		if err != nil {
   132  			c.Fatal(err)
   133  			return
   134  		}
   135  		network.SortIngressRules(got)
   136  		network.SortIngressRules(expected)
   137  		if reflect.DeepEqual(got, expected) {
   138  			c.Succeed()
   139  			return
   140  		}
   141  		if time.Since(start) > coretesting.LongWait {
   142  			c.Fatalf("timed out: expected %q; got %q", expected, got)
   143  			return
   144  		}
   145  		time.Sleep(coretesting.ShortWait)
   146  	}
   147  }
   148  
   149  // assertEnvironPorts retrieves the open ports of environment and compares them
   150  // to the expected.
   151  func (s *firewallerBaseSuite) assertEnvironPorts(c *gc.C, expected []network.IngressRule) {
   152  	fwEnv, ok := s.Environ.(environs.Firewaller)
   153  	c.Assert(ok, gc.Equals, true)
   154  
   155  	start := time.Now()
   156  	for {
   157  		s.BackingState.StartSync()
   158  		got, err := fwEnv.IngressRules(s.callCtx)
   159  		if err != nil {
   160  			c.Fatal(err)
   161  			return
   162  		}
   163  		network.SortIngressRules(got)
   164  		network.SortIngressRules(expected)
   165  		if reflect.DeepEqual(got, expected) {
   166  			c.Succeed()
   167  			return
   168  		}
   169  		if time.Since(start) > coretesting.LongWait {
   170  			c.Fatalf("timed out: expected %q; got %q", expected, got)
   171  			return
   172  		}
   173  		time.Sleep(coretesting.ShortWait)
   174  	}
   175  }
   176  
   177  func (s *firewallerBaseSuite) addUnit(c *gc.C, app *state.Application) (*state.Unit, *state.Machine) {
   178  	u, err := app.AddUnit(state.AddUnitParams{})
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	err = s.State.AssignUnit(u, state.AssignCleanEmpty)
   181  	c.Assert(err, jc.ErrorIsNil)
   182  	id, err := u.AssignedMachineId()
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	m, err := s.State.Machine(id)
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	return u, m
   187  }
   188  
   189  // startInstance starts a new instance for the given machine.
   190  func (s *firewallerBaseSuite) startInstance(c *gc.C, m *state.Machine) instances.Instance {
   191  	inst, hc := jujutesting.AssertStartInstance(c, s.Environ, s.callCtx, s.ControllerConfig.ControllerUUID(), m.Id())
   192  	err := m.SetProvisioned(inst.Id(), "", "fake_nonce", hc)
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	return inst
   195  }
   196  
   197  type InstanceModeSuite struct {
   198  	firewallerBaseSuite
   199  }
   200  
   201  var _ = gc.Suite(&InstanceModeSuite{})
   202  
   203  func (s *InstanceModeSuite) SetUpTest(c *gc.C) {
   204  	s.firewallerBaseSuite.setUpTest(c, config.FwInstance)
   205  }
   206  
   207  func (s *InstanceModeSuite) TearDownTest(c *gc.C) {
   208  	s.firewallerBaseSuite.JujuConnSuite.TearDownTest(c)
   209  }
   210  
   211  // mockClock will panic if anything but After is called
   212  type mockClock struct {
   213  	clock.Clock
   214  	wait time.Duration
   215  	c    *gc.C
   216  }
   217  
   218  func (m *mockClock) Now() time.Time {
   219  	return time.Now()
   220  }
   221  
   222  func (m *mockClock) After(duration time.Duration) <-chan time.Time {
   223  	m.wait = duration
   224  	return time.After(time.Millisecond)
   225  }
   226  
   227  func (s *InstanceModeSuite) newFirewaller(c *gc.C) worker.Worker {
   228  	return s.newFirewallerWithClock(c, &mockClock{c: c})
   229  }
   230  
   231  func (s *InstanceModeSuite) newFirewallerWithClock(c *gc.C, clock clock.Clock) worker.Worker {
   232  	s.clock = clock
   233  	fwEnv, ok := s.Environ.(environs.Firewaller)
   234  	c.Assert(ok, gc.Equals, true)
   235  
   236  	cfg := firewaller.Config{
   237  		ModelUUID:          s.State.ModelUUID(),
   238  		Mode:               config.FwInstance,
   239  		EnvironFirewaller:  fwEnv,
   240  		EnvironInstances:   s.Environ,
   241  		FirewallerAPI:      s.firewaller,
   242  		RemoteRelationsApi: s.remoteRelations,
   243  		NewCrossModelFacadeFunc: func(*api.Info) (firewaller.CrossModelFirewallerFacadeCloser, error) {
   244  			return s.crossmodelFirewaller, nil
   245  		},
   246  		Clock:         s.clock,
   247  		CredentialAPI: s.credentialsFacade,
   248  	}
   249  	fw, err := firewaller.NewFirewaller(cfg)
   250  	c.Assert(err, jc.ErrorIsNil)
   251  	return fw
   252  }
   253  
   254  func (s *InstanceModeSuite) TestStartStop(c *gc.C) {
   255  	fw := s.newFirewaller(c)
   256  	statetesting.AssertKillAndWait(c, fw)
   257  }
   258  
   259  func (s *InstanceModeSuite) TestNotExposedApplication(c *gc.C) {
   260  	fw := s.newFirewaller(c)
   261  	defer statetesting.AssertKillAndWait(c, fw)
   262  
   263  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   264  	u, m := s.addUnit(c, app)
   265  	inst := s.startInstance(c, m)
   266  
   267  	err := u.OpenPort("tcp", 80)
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	err = u.OpenPort("tcp", 8080)
   270  	c.Assert(err, jc.ErrorIsNil)
   271  
   272  	s.assertPorts(c, inst, m.Id(), nil)
   273  
   274  	err = u.ClosePort("tcp", 80)
   275  	c.Assert(err, jc.ErrorIsNil)
   276  
   277  	s.assertPorts(c, inst, m.Id(), nil)
   278  }
   279  
   280  func (s *InstanceModeSuite) TestExposedApplication(c *gc.C) {
   281  	fw := s.newFirewaller(c)
   282  	defer statetesting.AssertKillAndWait(c, fw)
   283  
   284  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   285  
   286  	err := app.SetExposed()
   287  	c.Assert(err, jc.ErrorIsNil)
   288  	u, m := s.addUnit(c, app)
   289  	inst := s.startInstance(c, m)
   290  
   291  	err = u.OpenPorts("tcp", 80, 90)
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	err = u.OpenPort("tcp", 8080)
   294  	c.Assert(err, jc.ErrorIsNil)
   295  
   296  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   297  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
   298  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   299  	})
   300  
   301  	err = u.ClosePorts("tcp", 80, 90)
   302  	c.Assert(err, jc.ErrorIsNil)
   303  
   304  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   305  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   306  	})
   307  }
   308  
   309  func (s *InstanceModeSuite) TestMultipleExposedApplications(c *gc.C) {
   310  	fw := s.newFirewaller(c)
   311  	defer statetesting.AssertKillAndWait(c, fw)
   312  
   313  	app1 := s.AddTestingApplication(c, "wordpress", s.charm)
   314  	err := app1.SetExposed()
   315  	c.Assert(err, jc.ErrorIsNil)
   316  
   317  	u1, m1 := s.addUnit(c, app1)
   318  	inst1 := s.startInstance(c, m1)
   319  	err = u1.OpenPort("tcp", 80)
   320  	c.Assert(err, jc.ErrorIsNil)
   321  	err = u1.OpenPort("tcp", 8080)
   322  	c.Assert(err, jc.ErrorIsNil)
   323  
   324  	app2 := s.AddTestingApplication(c, "mysql", s.charm)
   325  	c.Assert(err, jc.ErrorIsNil)
   326  	err = app2.SetExposed()
   327  	c.Assert(err, jc.ErrorIsNil)
   328  
   329  	u2, m2 := s.addUnit(c, app2)
   330  	inst2 := s.startInstance(c, m2)
   331  	err = u2.OpenPort("tcp", 3306)
   332  	c.Assert(err, jc.ErrorIsNil)
   333  
   334  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   335  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   336  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   337  	})
   338  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   339  		network.MustNewIngressRule("tcp", 3306, 3306, "0.0.0.0/0"),
   340  	})
   341  
   342  	err = u1.ClosePort("tcp", 80)
   343  	c.Assert(err, jc.ErrorIsNil)
   344  	err = u2.ClosePort("tcp", 3306)
   345  	c.Assert(err, jc.ErrorIsNil)
   346  
   347  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   348  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   349  	})
   350  	s.assertPorts(c, inst2, m2.Id(), nil)
   351  }
   352  
   353  func (s *InstanceModeSuite) TestMachineWithoutInstanceId(c *gc.C) {
   354  	fw := s.newFirewaller(c)
   355  	defer statetesting.AssertKillAndWait(c, fw)
   356  
   357  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   358  	err := app.SetExposed()
   359  	c.Assert(err, jc.ErrorIsNil)
   360  	// add a unit but don't start its instance yet.
   361  	u1, m1 := s.addUnit(c, app)
   362  
   363  	// add another unit and start its instance, so that
   364  	// we're sure the firewaller has seen the first instance.
   365  	u2, m2 := s.addUnit(c, app)
   366  	inst2 := s.startInstance(c, m2)
   367  	err = u2.OpenPort("tcp", 80)
   368  	c.Assert(err, jc.ErrorIsNil)
   369  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   370  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   371  	})
   372  
   373  	inst1 := s.startInstance(c, m1)
   374  	err = u1.OpenPort("tcp", 8080)
   375  	c.Assert(err, jc.ErrorIsNil)
   376  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   377  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   378  	})
   379  }
   380  
   381  func (s *InstanceModeSuite) TestMultipleUnits(c *gc.C) {
   382  	fw := s.newFirewaller(c)
   383  	defer statetesting.AssertKillAndWait(c, fw)
   384  
   385  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   386  	err := app.SetExposed()
   387  	c.Assert(err, jc.ErrorIsNil)
   388  
   389  	u1, m1 := s.addUnit(c, app)
   390  	inst1 := s.startInstance(c, m1)
   391  	err = u1.OpenPort("tcp", 80)
   392  	c.Assert(err, jc.ErrorIsNil)
   393  
   394  	u2, m2 := s.addUnit(c, app)
   395  	inst2 := s.startInstance(c, m2)
   396  	err = u2.OpenPort("tcp", 80)
   397  	c.Assert(err, jc.ErrorIsNil)
   398  
   399  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   400  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   401  	})
   402  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   403  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   404  	})
   405  
   406  	err = u1.ClosePort("tcp", 80)
   407  	c.Assert(err, jc.ErrorIsNil)
   408  	err = u2.ClosePort("tcp", 80)
   409  	c.Assert(err, jc.ErrorIsNil)
   410  
   411  	s.assertPorts(c, inst1, m1.Id(), nil)
   412  	s.assertPorts(c, inst2, m2.Id(), nil)
   413  }
   414  
   415  func (s *InstanceModeSuite) TestStartWithState(c *gc.C) {
   416  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   417  	err := app.SetExposed()
   418  	c.Assert(err, jc.ErrorIsNil)
   419  	u, m := s.addUnit(c, app)
   420  	inst := s.startInstance(c, m)
   421  
   422  	err = u.OpenPort("tcp", 80)
   423  	c.Assert(err, jc.ErrorIsNil)
   424  	err = u.OpenPort("tcp", 8080)
   425  	c.Assert(err, jc.ErrorIsNil)
   426  
   427  	// Nothing open without firewaller.
   428  	s.assertPorts(c, inst, m.Id(), nil)
   429  
   430  	// Starting the firewaller opens the ports.
   431  	fw := s.newFirewaller(c)
   432  	defer statetesting.AssertKillAndWait(c, fw)
   433  
   434  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   435  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   436  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   437  	})
   438  
   439  	err = app.SetExposed()
   440  	c.Assert(err, jc.ErrorIsNil)
   441  }
   442  
   443  func (s *InstanceModeSuite) TestStartWithPartialState(c *gc.C) {
   444  	m, err := s.State.AddMachine("quantal", state.JobHostUnits)
   445  	c.Assert(err, jc.ErrorIsNil)
   446  	inst := s.startInstance(c, m)
   447  
   448  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   449  	err = app.SetExposed()
   450  	c.Assert(err, jc.ErrorIsNil)
   451  
   452  	// Starting the firewaller, no open ports.
   453  	fw := s.newFirewaller(c)
   454  	defer statetesting.AssertKillAndWait(c, fw)
   455  
   456  	s.assertPorts(c, inst, m.Id(), nil)
   457  
   458  	// Complete steps to open port.
   459  	u, err := app.AddUnit(state.AddUnitParams{})
   460  	c.Assert(err, jc.ErrorIsNil)
   461  	err = u.AssignToMachine(m)
   462  	c.Assert(err, jc.ErrorIsNil)
   463  	err = u.OpenPort("tcp", 80)
   464  	c.Assert(err, jc.ErrorIsNil)
   465  
   466  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   467  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   468  	})
   469  }
   470  
   471  func (s *InstanceModeSuite) TestStartWithUnexposedApplication(c *gc.C) {
   472  	m, err := s.State.AddMachine("quantal", state.JobHostUnits)
   473  	c.Assert(err, jc.ErrorIsNil)
   474  	inst := s.startInstance(c, m)
   475  
   476  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   477  	u, err := app.AddUnit(state.AddUnitParams{})
   478  	c.Assert(err, jc.ErrorIsNil)
   479  	err = u.AssignToMachine(m)
   480  	c.Assert(err, jc.ErrorIsNil)
   481  	err = u.OpenPort("tcp", 80)
   482  	c.Assert(err, jc.ErrorIsNil)
   483  
   484  	// Starting the firewaller, no open ports.
   485  	fw := s.newFirewaller(c)
   486  	defer statetesting.AssertKillAndWait(c, fw)
   487  
   488  	s.assertPorts(c, inst, m.Id(), nil)
   489  
   490  	// Expose service.
   491  	err = app.SetExposed()
   492  	c.Assert(err, jc.ErrorIsNil)
   493  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   494  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   495  	})
   496  }
   497  
   498  func assertMachineInMachineds(c *gc.C, fw *firewaller.Firewaller, tag names.MachineTag, find bool) {
   499  	machineds := firewaller.GetMachineds(fw)
   500  	_, found := machineds[tag]
   501  	c.Assert(found, gc.Equals, find)
   502  }
   503  
   504  func (s *InstanceModeSuite) TestStartMachineWithManualMachine(c *gc.C) {
   505  	fw := s.newFirewaller(c)
   506  	defer statetesting.AssertKillAndWait(c, fw)
   507  
   508  	m, err := s.State.AddOneMachine(state.MachineTemplate{
   509  		Series:     "quantal",
   510  		Jobs:       []state.MachineJob{state.JobHostUnits},
   511  		InstanceId: "2",
   512  		Nonce:      "manual:",
   513  	})
   514  	c.Assert(err, jc.ErrorIsNil)
   515  	err = firewaller.StartMachine(fw.(*firewaller.Firewaller), m.MachineTag())
   516  	c.Assert(err, jc.ErrorIsNil)
   517  	assertMachineInMachineds(c, fw.(*firewaller.Firewaller), m.MachineTag(), false)
   518  
   519  	m2, err := s.State.AddOneMachine(state.MachineTemplate{
   520  		Series: "quantal",
   521  		Jobs:   []state.MachineJob{state.JobHostUnits},
   522  	})
   523  	c.Assert(err, jc.ErrorIsNil)
   524  	err = firewaller.StartMachine(fw.(*firewaller.Firewaller), m2.MachineTag())
   525  	c.Assert(err, jc.ErrorIsNil)
   526  	assertMachineInMachineds(c, fw.(*firewaller.Firewaller), m2.MachineTag(), true)
   527  }
   528  
   529  func (s *InstanceModeSuite) TestSetClearExposedApplication(c *gc.C) {
   530  	fw := s.newFirewaller(c)
   531  	defer statetesting.AssertKillAndWait(c, fw)
   532  
   533  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   534  
   535  	u, m := s.addUnit(c, app)
   536  	inst := s.startInstance(c, m)
   537  	err := u.OpenPort("tcp", 80)
   538  	c.Assert(err, jc.ErrorIsNil)
   539  	err = u.OpenPort("tcp", 8080)
   540  	c.Assert(err, jc.ErrorIsNil)
   541  
   542  	// Not exposed service, so no open port.
   543  	s.assertPorts(c, inst, m.Id(), nil)
   544  
   545  	// SeExposed opens the ports.
   546  	err = app.SetExposed()
   547  	c.Assert(err, jc.ErrorIsNil)
   548  
   549  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   550  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   551  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
   552  	})
   553  
   554  	// ClearExposed closes the ports again.
   555  	err = app.ClearExposed()
   556  	c.Assert(err, jc.ErrorIsNil)
   557  
   558  	s.assertPorts(c, inst, m.Id(), nil)
   559  }
   560  
   561  func (s *InstanceModeSuite) TestRemoveUnit(c *gc.C) {
   562  	fw := s.newFirewaller(c)
   563  	defer statetesting.AssertKillAndWait(c, fw)
   564  
   565  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   566  	err := app.SetExposed()
   567  	c.Assert(err, jc.ErrorIsNil)
   568  
   569  	u1, m1 := s.addUnit(c, app)
   570  	inst1 := s.startInstance(c, m1)
   571  	err = u1.OpenPort("tcp", 80)
   572  	c.Assert(err, jc.ErrorIsNil)
   573  
   574  	u2, m2 := s.addUnit(c, app)
   575  	inst2 := s.startInstance(c, m2)
   576  	err = u2.OpenPort("tcp", 80)
   577  	c.Assert(err, jc.ErrorIsNil)
   578  
   579  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   580  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   581  	})
   582  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   583  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   584  	})
   585  
   586  	// Remove unit.
   587  	err = u1.EnsureDead()
   588  	c.Assert(err, jc.ErrorIsNil)
   589  	err = u1.Remove()
   590  	c.Assert(err, jc.ErrorIsNil)
   591  
   592  	s.assertPorts(c, inst1, m1.Id(), nil)
   593  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   594  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   595  	})
   596  }
   597  
   598  func (s *InstanceModeSuite) TestRemoveApplication(c *gc.C) {
   599  	fw := s.newFirewaller(c)
   600  	defer statetesting.AssertKillAndWait(c, fw)
   601  
   602  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   603  	err := app.SetExposed()
   604  	c.Assert(err, jc.ErrorIsNil)
   605  
   606  	u, m := s.addUnit(c, app)
   607  	inst := s.startInstance(c, m)
   608  	err = u.OpenPort("tcp", 80)
   609  	c.Assert(err, jc.ErrorIsNil)
   610  
   611  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   612  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   613  	})
   614  
   615  	// Remove application.
   616  	err = u.EnsureDead()
   617  	c.Assert(err, jc.ErrorIsNil)
   618  	err = u.Remove()
   619  	c.Assert(err, jc.ErrorIsNil)
   620  	err = app.Destroy()
   621  	c.Assert(err, jc.ErrorIsNil)
   622  	s.assertPorts(c, inst, m.Id(), nil)
   623  }
   624  
   625  func (s *InstanceModeSuite) TestRemoveMultipleApplications(c *gc.C) {
   626  	fw := s.newFirewaller(c)
   627  	defer statetesting.AssertKillAndWait(c, fw)
   628  
   629  	app1 := s.AddTestingApplication(c, "wordpress", s.charm)
   630  	err := app1.SetExposed()
   631  	c.Assert(err, jc.ErrorIsNil)
   632  
   633  	u1, m1 := s.addUnit(c, app1)
   634  	inst1 := s.startInstance(c, m1)
   635  	err = u1.OpenPort("tcp", 80)
   636  	c.Assert(err, jc.ErrorIsNil)
   637  
   638  	app2 := s.AddTestingApplication(c, "mysql", s.charm)
   639  	err = app2.SetExposed()
   640  	c.Assert(err, jc.ErrorIsNil)
   641  
   642  	u2, m2 := s.addUnit(c, app2)
   643  	inst2 := s.startInstance(c, m2)
   644  	err = u2.OpenPort("tcp", 3306)
   645  	c.Assert(err, jc.ErrorIsNil)
   646  
   647  	s.assertPorts(c, inst1, m1.Id(), []network.IngressRule{
   648  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   649  	})
   650  	s.assertPorts(c, inst2, m2.Id(), []network.IngressRule{
   651  		network.MustNewIngressRule("tcp", 3306, 3306, "0.0.0.0/0"),
   652  	})
   653  
   654  	// Remove applications.
   655  	err = u2.EnsureDead()
   656  	c.Assert(err, jc.ErrorIsNil)
   657  	err = u2.Remove()
   658  	c.Assert(err, jc.ErrorIsNil)
   659  	err = app2.Destroy()
   660  	c.Assert(err, jc.ErrorIsNil)
   661  
   662  	err = u1.EnsureDead()
   663  	c.Assert(err, jc.ErrorIsNil)
   664  	err = u1.Remove()
   665  	c.Assert(err, jc.ErrorIsNil)
   666  	err = app1.Destroy()
   667  	c.Assert(err, jc.ErrorIsNil)
   668  
   669  	s.assertPorts(c, inst1, m1.Id(), nil)
   670  	s.assertPorts(c, inst2, m2.Id(), nil)
   671  }
   672  
   673  func (s *InstanceModeSuite) TestDeadMachine(c *gc.C) {
   674  	fw := s.newFirewaller(c)
   675  	defer statetesting.AssertKillAndWait(c, fw)
   676  
   677  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   678  	err := app.SetExposed()
   679  	c.Assert(err, jc.ErrorIsNil)
   680  
   681  	u, m := s.addUnit(c, app)
   682  	inst := s.startInstance(c, m)
   683  	err = u.OpenPort("tcp", 80)
   684  	c.Assert(err, jc.ErrorIsNil)
   685  
   686  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   687  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   688  	})
   689  
   690  	// Remove unit and application, also tested without. Has no effect.
   691  	err = u.EnsureDead()
   692  	c.Assert(err, jc.ErrorIsNil)
   693  	err = u.Remove()
   694  	c.Assert(err, jc.ErrorIsNil)
   695  	err = app.Destroy()
   696  	c.Assert(err, jc.ErrorIsNil)
   697  
   698  	// Kill machine.
   699  	err = m.Refresh()
   700  	c.Assert(err, jc.ErrorIsNil)
   701  	err = m.EnsureDead()
   702  	c.Assert(err, jc.ErrorIsNil)
   703  
   704  	s.assertPorts(c, inst, m.Id(), nil)
   705  }
   706  
   707  func (s *InstanceModeSuite) TestRemoveMachine(c *gc.C) {
   708  	fw := s.newFirewaller(c)
   709  
   710  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   711  	err := app.SetExposed()
   712  	c.Assert(err, jc.ErrorIsNil)
   713  
   714  	u, m := s.addUnit(c, app)
   715  	inst := s.startInstance(c, m)
   716  	err = u.OpenPort("tcp", 80)
   717  	c.Assert(err, jc.ErrorIsNil)
   718  
   719  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
   720  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
   721  	})
   722  
   723  	// Remove unit.
   724  	err = u.EnsureDead()
   725  	c.Assert(err, jc.ErrorIsNil)
   726  	err = u.Remove()
   727  	c.Assert(err, jc.ErrorIsNil)
   728  
   729  	// Remove machine. Nothing bad should happen, but can't
   730  	// assert port state since the machine must have been
   731  	// destroyed and we lost its reference.
   732  	err = m.Refresh()
   733  	c.Assert(err, jc.ErrorIsNil)
   734  	err = m.EnsureDead()
   735  	c.Assert(err, jc.ErrorIsNil)
   736  	err = m.Remove()
   737  	c.Assert(err, jc.ErrorIsNil)
   738  
   739  	// TODO (manadart 2019-02-01): This fails intermittently with a "not found"
   740  	// error for the machine. This is not a huge problem in production, as the
   741  	// worker will restart and proceed happily thereafter.
   742  	// That error is detected here for expediency, but the ideal mitigation is
   743  	// a refactoring of the worker logic as per LP:1814277.
   744  	fw.Kill()
   745  	err = fw.Wait()
   746  	c.Assert(err == nil || params.IsCodeNotFound(err), jc.IsTrue)
   747  }
   748  
   749  func (s *InstanceModeSuite) TestStartWithStateOpenPortsBroken(c *gc.C) {
   750  	app := s.AddTestingApplication(c, "wordpress", s.charm)
   751  	err := app.SetExposed()
   752  	c.Assert(err, jc.ErrorIsNil)
   753  	u, m := s.addUnit(c, app)
   754  	inst := s.startInstance(c, m)
   755  
   756  	err = u.OpenPort("tcp", 80)
   757  	c.Assert(err, jc.ErrorIsNil)
   758  
   759  	// Nothing open without firewaller.
   760  	s.assertPorts(c, inst, m.Id(), nil)
   761  	dummy.SetInstanceBroken(inst, "OpenPorts")
   762  
   763  	// Starting the firewaller should attempt to open the ports,
   764  	// and fail due to the method being broken.
   765  	fw := s.newFirewaller(c)
   766  
   767  	errc := make(chan error, 1)
   768  	go func() { errc <- fw.Wait() }()
   769  	s.BackingState.StartSync()
   770  	select {
   771  	case err := <-errc:
   772  		c.Assert(err, gc.ErrorMatches,
   773  			`cannot respond to units changes for "machine-1": dummyInstance.OpenPorts is broken`)
   774  	case <-time.After(coretesting.LongWait):
   775  		fw.Kill()
   776  		fw.Wait()
   777  		c.Fatal("timed out waiting for firewaller to stop")
   778  	}
   779  }
   780  
   781  func (s *InstanceModeSuite) setupRemoteRelationRequirerRoleConsumingSide(
   782  	c *gc.C, published chan bool, apiErr *bool, ingressRequired *bool, clock clock.Clock,
   783  ) (worker.Worker, *state.RelationUnit) {
   784  	// Set up the consuming model - create the local app.
   785  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   786  	// Set up the consuming model - create the remote app.
   787  	offeringModelTag := names.NewModelTag(utils.MustNewUUID().String())
   788  	appToken := utils.MustNewUUID().String()
   789  	app, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   790  		Name: "mysql", SourceModel: offeringModelTag,
   791  		Endpoints: []charm.Relation{{Name: "database", Interface: "mysql", Role: "provider", Scope: "global"}},
   792  	})
   793  	c.Assert(err, jc.ErrorIsNil)
   794  	// Create the external controller info.
   795  	ec := state.NewExternalControllers(s.State)
   796  	_, err = ec.Save(crossmodel.ControllerInfo{
   797  		ControllerTag: coretesting.ControllerTag,
   798  		Addrs:         []string{"1.2.3.4:1234"},
   799  		CACert:        coretesting.CACert}, offeringModelTag.Id())
   800  	c.Assert(err, jc.ErrorIsNil)
   801  
   802  	mac, err := apitesting.NewMacaroon("apimac")
   803  	c.Assert(err, jc.ErrorIsNil)
   804  	var relToken string
   805  	apiCaller := basetesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
   806  		c.Check(objType, gc.Equals, "CrossModelRelations")
   807  		c.Check(version, gc.Equals, 0)
   808  		c.Check(id, gc.Equals, "")
   809  		c.Check(request, gc.Equals, "PublishIngressNetworkChanges")
   810  		expected := params.IngressNetworksChanges{
   811  			Changes: []params.IngressNetworksChangeEvent{{
   812  				RelationToken:    relToken,
   813  				ApplicationToken: appToken,
   814  			}},
   815  		}
   816  
   817  		// Extract macaroons so we can compare them separately
   818  		// (as they can't be compared using DeepEquals due to 'UnmarshaledAs')
   819  		expectedMacs := arg.(params.IngressNetworksChanges).Changes[0].Macaroons
   820  		arg.(params.IngressNetworksChanges).Changes[0].Macaroons = nil
   821  		c.Assert(len(expectedMacs), gc.Equals, 1)
   822  		apitesting.MacaroonEquals(c, expectedMacs[0], mac)
   823  
   824  		// Networks may be empty or not, depending on coalescing of watcher events.
   825  		// We may get an initial empty event followed by an event with a network.
   826  		// Or we may get just the event with a network.
   827  		// Set the arg networks to empty and compare below.
   828  		changes := arg.(params.IngressNetworksChanges)
   829  		argNetworks := changes.Changes[0].Networks
   830  		argIngressRequired := changes.Changes[0].IngressRequired
   831  
   832  		changes.Changes[0].Networks = nil
   833  		expected.Changes[0].IngressRequired = argIngressRequired
   834  		c.Check(arg, gc.DeepEquals, expected)
   835  
   836  		if !*ingressRequired {
   837  			c.Assert(changes.Changes[0].Networks, gc.HasLen, 0)
   838  		}
   839  		if *ingressRequired && len(argNetworks) > 0 {
   840  			c.Assert(argIngressRequired, jc.IsTrue)
   841  			c.Assert(argNetworks, jc.DeepEquals, []string{"10.0.0.4/32"})
   842  		}
   843  		changes.Changes[0].Macaroons = expectedMacs
   844  		c.Assert(result, gc.FitsTypeOf, &params.ErrorResults{})
   845  		*(result.(*params.ErrorResults)) = params.ErrorResults{
   846  			Results: []params.ErrorResult{{}},
   847  		}
   848  		if *apiErr {
   849  			return errors.New("fail")
   850  		}
   851  		if !*ingressRequired || len(argNetworks) > 0 {
   852  			published <- true
   853  		}
   854  		return nil
   855  	})
   856  
   857  	s.crossmodelFirewaller = crossmodelrelations.NewClient(apiCaller)
   858  	c.Assert(s.crossmodelFirewaller, gc.NotNil)
   859  
   860  	// Create the firewaller facade on the consuming model.
   861  	fw := s.newFirewallerWithClock(c, clock)
   862  
   863  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
   864  	c.Assert(err, jc.ErrorIsNil)
   865  	rel, err := s.State.AddRelation(eps...)
   866  	c.Assert(err, jc.ErrorIsNil)
   867  
   868  	// Export the relation details so the firewaller knows it's ready to be processed.
   869  	re := s.State.RemoteEntities()
   870  	relToken, err = re.ExportLocalEntity(rel.Tag())
   871  	c.Assert(err, jc.ErrorIsNil)
   872  	err = re.SaveMacaroon(rel.Tag(), mac)
   873  	c.Assert(err, jc.ErrorIsNil)
   874  	err = re.ImportRemoteEntity(app.Tag(), appToken)
   875  	c.Assert(err, jc.ErrorIsNil)
   876  
   877  	// We should not have published any ingress events yet - no unit has entered scope.
   878  	select {
   879  	case <-time.After(coretesting.ShortWait):
   880  	case <-published:
   881  		c.Fatal("unexpected ingress change to be published")
   882  	}
   883  
   884  	// Add a public address to the consuming unit so the firewaller can use it.
   885  	wpm := s.Factory.MakeMachine(c, &factory.MachineParams{
   886  		Addresses: []network.Address{network.NewAddress("10.0.0.4")},
   887  	})
   888  	u, err := wordpress.AddUnit(state.AddUnitParams{})
   889  	c.Assert(err, jc.ErrorIsNil)
   890  	err = u.AssignToMachine(wpm)
   891  	c.Assert(err, jc.ErrorIsNil)
   892  	ru, err := rel.Unit(u)
   893  	c.Assert(err, jc.ErrorIsNil)
   894  	return fw, ru
   895  }
   896  
   897  func (s *InstanceModeSuite) TestRemoteRelationRequirerRoleConsumingSide(c *gc.C) {
   898  	published := make(chan bool)
   899  	ingressRequired := true
   900  	apiErr := false
   901  	fw, ru := s.setupRemoteRelationRequirerRoleConsumingSide(c, published, &apiErr, &ingressRequired, &mockClock{c: c})
   902  	defer statetesting.AssertKillAndWait(c, fw)
   903  
   904  	// Add a unit on the consuming app and have it enter the relation scope.
   905  	// This will trigger the firewaller to publish the changes.
   906  	err := ru.EnterScope(map[string]interface{}{})
   907  	c.Assert(err, jc.ErrorIsNil)
   908  	s.BackingState.StartSync()
   909  	select {
   910  	case <-time.After(coretesting.LongWait):
   911  		c.Fatal("time out waiting for ingress change to be published on enter scope")
   912  	case <-published:
   913  	}
   914  
   915  	// Check the relation ready poll time is as expected.
   916  	c.Assert(s.clock.(*mockClock).wait, gc.Equals, 3*time.Second)
   917  
   918  	// Change should be sent when unit leaves scope.
   919  	ingressRequired = false
   920  	err = ru.LeaveScope()
   921  	c.Assert(err, jc.ErrorIsNil)
   922  	s.BackingState.StartSync()
   923  	select {
   924  	case <-time.After(coretesting.LongWait):
   925  		c.Fatal("time out waiting for ingress change to be published on leave scope")
   926  	case <-published:
   927  	}
   928  }
   929  
   930  func (s *InstanceModeSuite) TestRemoteRelationWorkerError(c *gc.C) {
   931  	published := make(chan bool)
   932  	ingressRequired := true
   933  	apiErr := true
   934  	fw, ru := s.setupRemoteRelationRequirerRoleConsumingSide(c, published, &apiErr, &ingressRequired, testclock.NewClock(time.Time{}))
   935  	defer statetesting.AssertKillAndWait(c, fw)
   936  
   937  	// Add a unit on the consuming app and have it enter the relation scope.
   938  	// This will trigger the firewaller to try and publish the changes.
   939  	err := ru.EnterScope(map[string]interface{}{})
   940  	c.Assert(err, jc.ErrorIsNil)
   941  	s.BackingState.StartSync()
   942  
   943  	// We should not have published any ingress events yet - no changed published.
   944  	select {
   945  	case <-time.After(coretesting.ShortWait):
   946  	case <-published:
   947  		c.Fatal("unexpected ingress change to be published")
   948  	}
   949  
   950  	// Give the worker time to restart and try again.
   951  	apiErr = false
   952  	s.clock.(*testclock.Clock).WaitAdvance(60*time.Second, coretesting.LongWait, 1)
   953  	select {
   954  	case <-time.After(coretesting.LongWait):
   955  		c.Fatal("time out waiting for ingress change to be published on enter scope")
   956  	case <-published:
   957  	}
   958  }
   959  
   960  func (s *InstanceModeSuite) TestRemoteRelationProviderRoleConsumingSide(c *gc.C) {
   961  	// Set up the consuming model - create the local app.
   962  	s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
   963  	// Set up the consuming model - create the remote app.
   964  	offeringModelTag := names.NewModelTag(utils.MustNewUUID().String())
   965  	appToken := utils.MustNewUUID().String()
   966  	app, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   967  		Name: "wordpress", SourceModel: offeringModelTag,
   968  		Endpoints: []charm.Relation{{Name: "database", Interface: "mysql", Role: "requirer", Scope: "global"}},
   969  	})
   970  	c.Assert(err, jc.ErrorIsNil)
   971  	// Create the external controller info.
   972  	ec := state.NewExternalControllers(s.State)
   973  	_, err = ec.Save(crossmodel.ControllerInfo{
   974  		ControllerTag: coretesting.ControllerTag,
   975  		Addrs:         []string{"1.2.3.4:1234"},
   976  		CACert:        coretesting.CACert}, offeringModelTag.Id())
   977  	c.Assert(err, jc.ErrorIsNil)
   978  
   979  	mac, err := apitesting.NewMacaroon("apimac")
   980  	c.Assert(err, jc.ErrorIsNil)
   981  	watched := make(chan bool)
   982  	var relToken string
   983  	callCount := int32(0)
   984  	apiCaller := basetesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
   985  		switch atomic.LoadInt32(&callCount) {
   986  		case 0:
   987  			c.Check(objType, gc.Equals, "CrossModelRelations")
   988  			c.Check(version, gc.Equals, 0)
   989  			c.Check(id, gc.Equals, "")
   990  			c.Check(request, gc.Equals, "WatchEgressAddressesForRelations")
   991  			expected := params.RemoteEntityArgs{
   992  				Args: []params.RemoteEntityArg{{
   993  					Token: relToken,
   994  				}},
   995  			}
   996  			// Extract macaroons so we can compare them separately
   997  			// (as they can't be compared using DeepEquals due to 'UnmarshaledAs')
   998  			rArgs := arg.(params.RemoteEntityArgs)
   999  			newMacs := rArgs.Args[0].Macaroons
  1000  			rArgs.Args[0].Macaroons = nil
  1001  			apitesting.MacaroonEquals(c, newMacs[0], mac)
  1002  			c.Check(arg, gc.DeepEquals, expected)
  1003  			c.Assert(result, gc.FitsTypeOf, &params.StringsWatchResults{})
  1004  			*(result.(*params.StringsWatchResults)) = params.StringsWatchResults{
  1005  				Results: []params.StringsWatchResult{{StringsWatcherId: "1"}},
  1006  			}
  1007  			watched <- true
  1008  		default:
  1009  			c.Check(objType, gc.Equals, "StringsWatcher")
  1010  		}
  1011  		atomic.AddInt32(&callCount, 1)
  1012  		return nil
  1013  	})
  1014  
  1015  	s.crossmodelFirewaller = crossmodelrelations.NewClient(apiCaller)
  1016  	c.Assert(s.crossmodelFirewaller, gc.NotNil)
  1017  
  1018  	// Create the firewaller facade on the consuming model.
  1019  	fw := s.newFirewaller(c)
  1020  	defer statetesting.AssertKillAndWait(c, fw)
  1021  
  1022  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1023  	c.Assert(err, jc.ErrorIsNil)
  1024  	rel, err := s.State.AddRelation(eps...)
  1025  	c.Assert(err, jc.ErrorIsNil)
  1026  
  1027  	// Export the relation details so the firewaller knows it's ready to be processed.
  1028  	re := s.State.RemoteEntities()
  1029  	relToken, err = re.ExportLocalEntity(rel.Tag())
  1030  	c.Assert(err, jc.ErrorIsNil)
  1031  	err = re.SaveMacaroon(rel.Tag(), mac)
  1032  	c.Assert(err, jc.ErrorIsNil)
  1033  	err = re.ImportRemoteEntity(app.Tag(), appToken)
  1034  	c.Assert(err, jc.ErrorIsNil)
  1035  
  1036  	select {
  1037  	case <-time.After(coretesting.LongWait):
  1038  		c.Fatal("time out waiting for watcher call")
  1039  	case <-watched:
  1040  	}
  1041  
  1042  	// Check the relation ready poll time is as expected.
  1043  	c.Assert(s.clock.(*mockClock).wait, gc.Equals, 3*time.Second)
  1044  }
  1045  
  1046  func (s *InstanceModeSuite) TestRemoteRelationIngressRejected(c *gc.C) {
  1047  	// Set up the consuming model - create the local app.
  1048  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1049  	// Set up the consuming model - create the remote app.
  1050  	offeringModelTag := names.NewModelTag(utils.MustNewUUID().String())
  1051  	appToken := utils.MustNewUUID().String()
  1052  
  1053  	app, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  1054  		Name: "mysql", SourceModel: offeringModelTag,
  1055  		Endpoints: []charm.Relation{{Name: "database", Interface: "mysql", Role: "provider", Scope: "global"}},
  1056  	})
  1057  	c.Assert(err, jc.ErrorIsNil)
  1058  	// Create the external controller info.
  1059  	ec := state.NewExternalControllers(s.State)
  1060  	_, err = ec.Save(crossmodel.ControllerInfo{
  1061  		ControllerTag: coretesting.ControllerTag,
  1062  		Addrs:         []string{"1.2.3.4:1234"},
  1063  		CACert:        coretesting.CACert}, offeringModelTag.Id())
  1064  	c.Assert(err, jc.ErrorIsNil)
  1065  
  1066  	mac, err := apitesting.NewMacaroon("apimac")
  1067  	c.Assert(err, jc.ErrorIsNil)
  1068  
  1069  	published := make(chan bool)
  1070  	done := false
  1071  	apiCaller := basetesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
  1072  		c.Assert(result, gc.FitsTypeOf, &params.ErrorResults{})
  1073  		*(result.(*params.ErrorResults)) = params.ErrorResults{
  1074  			Results: []params.ErrorResult{{Error: &params.Error{Code: params.CodeForbidden, Message: "error"}}},
  1075  		}
  1076  		// We can get more than one api call depending on the
  1077  		// granularity of watcher events.
  1078  		if !done {
  1079  			done = true
  1080  			published <- true
  1081  		}
  1082  		return nil
  1083  	})
  1084  
  1085  	s.crossmodelFirewaller = crossmodelrelations.NewClient(apiCaller)
  1086  	c.Assert(s.crossmodelFirewaller, gc.NotNil)
  1087  
  1088  	// Create the firewaller facade on the consuming model.
  1089  	fw := s.newFirewaller(c)
  1090  	defer statetesting.AssertKillAndWait(c, fw)
  1091  
  1092  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1093  	c.Assert(err, jc.ErrorIsNil)
  1094  	rel, err := s.State.AddRelation(eps...)
  1095  	c.Assert(err, jc.ErrorIsNil)
  1096  
  1097  	// Export the relation details so the firewaller knows it's ready to be processed.
  1098  	re := s.State.RemoteEntities()
  1099  	_, err = re.ExportLocalEntity(rel.Tag())
  1100  	c.Assert(err, jc.ErrorIsNil)
  1101  	err = re.SaveMacaroon(rel.Tag(), mac)
  1102  	c.Assert(err, jc.ErrorIsNil)
  1103  	err = re.ImportRemoteEntity(app.Tag(), appToken)
  1104  	c.Assert(err, jc.ErrorIsNil)
  1105  
  1106  	// Add a public address to the consuming unit so the firewaller can use it.
  1107  	wpm := s.Factory.MakeMachine(c, &factory.MachineParams{
  1108  		Addresses: []network.Address{network.NewAddress("10.0.0.4")},
  1109  	})
  1110  	u, err := wordpress.AddUnit(state.AddUnitParams{})
  1111  	c.Assert(err, jc.ErrorIsNil)
  1112  	err = u.AssignToMachine(wpm)
  1113  	c.Assert(err, jc.ErrorIsNil)
  1114  	ru, err := rel.Unit(u)
  1115  	c.Assert(err, jc.ErrorIsNil)
  1116  
  1117  	// Add a unit on the consuming app and have it enter the relation scope.
  1118  	// This will trigger the firewaller to publish the changes.
  1119  	err = ru.EnterScope(map[string]interface{}{})
  1120  	c.Assert(err, jc.ErrorIsNil)
  1121  	s.BackingState.StartSync()
  1122  	select {
  1123  	case <-time.After(coretesting.LongWait):
  1124  		c.Fatal("time out waiting for ingress change to be published on enter scope")
  1125  	case <-published:
  1126  	}
  1127  
  1128  	// Check that the relation status is set to error.
  1129  	s.BackingState.StartSync()
  1130  	for attempt := coretesting.LongAttempt.Start(); attempt.Next(); {
  1131  		relStatus, err := rel.Status()
  1132  		c.Check(err, jc.ErrorIsNil)
  1133  		if relStatus.Status != status.Error {
  1134  			continue
  1135  		}
  1136  		c.Check(relStatus.Message, gc.Equals, "error")
  1137  		return
  1138  	}
  1139  	c.Fatal("time out waiting for relation status to be updated")
  1140  }
  1141  
  1142  func (s *InstanceModeSuite) assertIngressCidrs(c *gc.C, ingress []string, expected []string) {
  1143  	// Set up the offering model - create the local app.
  1144  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1145  	u, m := s.addUnit(c, mysql)
  1146  	inst := s.startInstance(c, m)
  1147  	err := u.OpenPort("tcp", 3306)
  1148  	c.Assert(err, jc.ErrorIsNil)
  1149  
  1150  	// Set up the offering model - create the remote app.
  1151  	consumingModelTag := names.NewModelTag(utils.MustNewUUID().String())
  1152  	relToken := utils.MustNewUUID().String()
  1153  	appToken := utils.MustNewUUID().String()
  1154  	app, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  1155  		Name: "wordpress", SourceModel: consumingModelTag, IsConsumerProxy: true,
  1156  		Endpoints: []charm.Relation{{Name: "db", Interface: "mysql", Role: "requirer", Scope: "global"}},
  1157  	})
  1158  	c.Assert(err, jc.ErrorIsNil)
  1159  
  1160  	// Create the firewaller facade on the offering model.
  1161  	fw := s.newFirewaller(c)
  1162  	defer statetesting.AssertKillAndWait(c, fw)
  1163  
  1164  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1165  	c.Assert(err, jc.ErrorIsNil)
  1166  	rel, err := s.State.AddRelation(eps...)
  1167  	c.Assert(err, jc.ErrorIsNil)
  1168  
  1169  	// Export the relation details so the firewaller knows it's ready to be processed.
  1170  	re := s.State.RemoteEntities()
  1171  	err = re.ImportRemoteEntity(rel.Tag(), relToken)
  1172  	c.Assert(err, jc.ErrorIsNil)
  1173  	err = re.ImportRemoteEntity(app.Tag(), appToken)
  1174  	c.Assert(err, jc.ErrorIsNil)
  1175  
  1176  	// No port changes yet.
  1177  	s.assertPorts(c, inst, m.Id(), nil)
  1178  
  1179  	// Save a new ingress network against the relation.
  1180  	rin := state.NewRelationIngressNetworks(s.State)
  1181  	_, err = rin.Save(rel.Tag().Id(), false, ingress)
  1182  	c.Assert(err, jc.ErrorIsNil)
  1183  
  1184  	//Ports opened.
  1185  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
  1186  		network.MustNewIngressRule("tcp", 3306, 3306, expected...),
  1187  	})
  1188  
  1189  	// Check the relation ready poll time is as expected.
  1190  	c.Assert(s.clock.(*mockClock).wait, gc.Equals, 3*time.Second)
  1191  
  1192  	// Change should be sent when ingress networks disappear.
  1193  	_, err = rin.Save(rel.Tag().Id(), false, nil)
  1194  	c.Assert(err, jc.ErrorIsNil)
  1195  	s.assertPorts(c, inst, m.Id(), nil)
  1196  
  1197  	_, err = rin.Save(rel.Tag().Id(), false, ingress)
  1198  	c.Assert(err, jc.ErrorIsNil)
  1199  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
  1200  		network.MustNewIngressRule("tcp", 3306, 3306, expected...),
  1201  	})
  1202  
  1203  	// And again when relation is suspended.
  1204  	err = rel.SetSuspended(true, "")
  1205  	c.Assert(err, jc.ErrorIsNil)
  1206  	s.assertPorts(c, inst, m.Id(), nil)
  1207  
  1208  	// And again when relation is resumed.
  1209  	err = rel.SetSuspended(false, "")
  1210  	c.Assert(err, jc.ErrorIsNil)
  1211  	s.assertPorts(c, inst, m.Id(), []network.IngressRule{
  1212  		network.MustNewIngressRule("tcp", 3306, 3306, expected...),
  1213  	})
  1214  
  1215  	// And again when relation is destroyed.
  1216  	err = rel.Destroy()
  1217  	c.Assert(err, jc.ErrorIsNil)
  1218  	s.assertPorts(c, inst, m.Id(), nil)
  1219  }
  1220  
  1221  func (s *InstanceModeSuite) TestRemoteRelationProviderRoleOffering(c *gc.C) {
  1222  	s.assertIngressCidrs(c, []string{"10.0.0.4/16"}, []string{"10.0.0.4/16"})
  1223  }
  1224  
  1225  func (s *InstanceModeSuite) TestRemoteRelationIngressFallbackToPublic(c *gc.C) {
  1226  	var ingress []string
  1227  	for i := 1; i < 30; i++ {
  1228  		ingress = append(ingress, fmt.Sprintf("10.%d.0.1/32", i))
  1229  	}
  1230  	s.assertIngressCidrs(c, ingress, []string{"0.0.0.0/0"})
  1231  }
  1232  
  1233  func (s *InstanceModeSuite) TestRemoteRelationIngressFallbackToWhitelist(c *gc.C) {
  1234  	fwRules := state.NewFirewallRules(s.State)
  1235  	err := fwRules.Save(state.FirewallRule{
  1236  		WellKnownService: state.JujuApplicationOfferRule,
  1237  		WhitelistCIDRs:   []string{"192.168.1.0/16"},
  1238  	})
  1239  	c.Assert(err, jc.ErrorIsNil)
  1240  	var ingress []string
  1241  	for i := 1; i < 30; i++ {
  1242  		ingress = append(ingress, fmt.Sprintf("10.%d.0.1/32", i))
  1243  	}
  1244  	s.assertIngressCidrs(c, ingress, []string{"192.168.1.0/16"})
  1245  }
  1246  
  1247  func (s *InstanceModeSuite) TestRemoteRelationIngressMergesCIDRS(c *gc.C) {
  1248  	ingress := []string{
  1249  		"192.0.1.254/31",
  1250  		"192.0.2.0/28",
  1251  		"192.0.2.16/28",
  1252  		"192.0.2.32/28",
  1253  		"192.0.2.48/28",
  1254  		"192.0.2.64/28",
  1255  		"192.0.2.80/28",
  1256  		"192.0.2.96/28",
  1257  		"192.0.2.112/28",
  1258  		"192.0.2.128/28",
  1259  		"192.0.2.144/28",
  1260  		"192.0.2.160/28",
  1261  		"192.0.2.176/28",
  1262  		"192.0.2.192/28",
  1263  		"192.0.2.208/28",
  1264  		"192.0.2.224/28",
  1265  		"192.0.2.240/28",
  1266  		"192.0.3.0/28",
  1267  		"192.0.4.0/28",
  1268  		"192.0.5.0/28",
  1269  		"192.0.6.0/28",
  1270  	}
  1271  	expected := []string{
  1272  		"192.0.1.254/31",
  1273  		"192.0.2.0/24",
  1274  		"192.0.3.0/28",
  1275  		"192.0.4.0/28",
  1276  		"192.0.5.0/28",
  1277  		"192.0.6.0/28",
  1278  	}
  1279  	s.assertIngressCidrs(c, ingress, expected)
  1280  }
  1281  
  1282  type GlobalModeSuite struct {
  1283  	firewallerBaseSuite
  1284  }
  1285  
  1286  var _ = gc.Suite(&GlobalModeSuite{})
  1287  
  1288  func (s *GlobalModeSuite) SetUpTest(c *gc.C) {
  1289  	s.firewallerBaseSuite.setUpTest(c, config.FwGlobal)
  1290  }
  1291  
  1292  func (s *GlobalModeSuite) TearDownTest(c *gc.C) {
  1293  	s.firewallerBaseSuite.JujuConnSuite.TearDownTest(c)
  1294  }
  1295  
  1296  func (s *GlobalModeSuite) newFirewaller(c *gc.C) worker.Worker {
  1297  	fwEnv, ok := s.Environ.(environs.Firewaller)
  1298  	c.Assert(ok, gc.Equals, true)
  1299  
  1300  	cfg := firewaller.Config{
  1301  		ModelUUID:          s.State.ModelUUID(),
  1302  		Mode:               config.FwGlobal,
  1303  		EnvironFirewaller:  fwEnv,
  1304  		EnvironInstances:   s.Environ,
  1305  		FirewallerAPI:      s.firewaller,
  1306  		RemoteRelationsApi: s.remoteRelations,
  1307  		NewCrossModelFacadeFunc: func(*api.Info) (firewaller.CrossModelFirewallerFacadeCloser, error) {
  1308  			return s.crossmodelFirewaller, nil
  1309  		},
  1310  		CredentialAPI: s.credentialsFacade,
  1311  	}
  1312  	fw, err := firewaller.NewFirewaller(cfg)
  1313  	c.Assert(err, jc.ErrorIsNil)
  1314  	return fw
  1315  }
  1316  
  1317  func (s *GlobalModeSuite) TestStartStop(c *gc.C) {
  1318  	fw := s.newFirewaller(c)
  1319  	statetesting.AssertKillAndWait(c, fw)
  1320  }
  1321  
  1322  func (s *GlobalModeSuite) TestGlobalMode(c *gc.C) {
  1323  	// Start firewaller and open ports.
  1324  	fw := s.newFirewaller(c)
  1325  	defer statetesting.AssertKillAndWait(c, fw)
  1326  
  1327  	app1 := s.AddTestingApplication(c, "wordpress", s.charm)
  1328  	err := app1.SetExposed()
  1329  	c.Assert(err, jc.ErrorIsNil)
  1330  
  1331  	u1, m1 := s.addUnit(c, app1)
  1332  	s.startInstance(c, m1)
  1333  	err = u1.OpenPorts("tcp", 80, 90)
  1334  	c.Assert(err, jc.ErrorIsNil)
  1335  	err = u1.OpenPort("tcp", 8080)
  1336  	c.Assert(err, jc.ErrorIsNil)
  1337  
  1338  	app2 := s.AddTestingApplication(c, "moinmoin", s.charm)
  1339  	c.Assert(err, jc.ErrorIsNil)
  1340  	err = app2.SetExposed()
  1341  	c.Assert(err, jc.ErrorIsNil)
  1342  
  1343  	u2, m2 := s.addUnit(c, app2)
  1344  	s.startInstance(c, m2)
  1345  	err = u2.OpenPorts("tcp", 80, 90)
  1346  	c.Assert(err, jc.ErrorIsNil)
  1347  
  1348  	s.assertEnvironPorts(c, []network.IngressRule{
  1349  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
  1350  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1351  	})
  1352  
  1353  	// Closing a port opened by a different unit won't touch the environment.
  1354  	err = u1.ClosePorts("tcp", 80, 90)
  1355  	c.Assert(err, jc.ErrorIsNil)
  1356  	s.assertEnvironPorts(c, []network.IngressRule{
  1357  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
  1358  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1359  	})
  1360  
  1361  	// Closing a port used just once changes the environment.
  1362  	err = u1.ClosePort("tcp", 8080)
  1363  	c.Assert(err, jc.ErrorIsNil)
  1364  	s.assertEnvironPorts(c, []network.IngressRule{
  1365  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
  1366  	})
  1367  
  1368  	// Closing the last port also modifies the environment.
  1369  	err = u2.ClosePorts("tcp", 80, 90)
  1370  	c.Assert(err, jc.ErrorIsNil)
  1371  	s.assertEnvironPorts(c, nil)
  1372  }
  1373  
  1374  func (s *GlobalModeSuite) TestStartWithUnexposedApplication(c *gc.C) {
  1375  	m, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1376  	c.Assert(err, jc.ErrorIsNil)
  1377  	s.startInstance(c, m)
  1378  
  1379  	app := s.AddTestingApplication(c, "wordpress", s.charm)
  1380  	u, err := app.AddUnit(state.AddUnitParams{})
  1381  	c.Assert(err, jc.ErrorIsNil)
  1382  	err = u.AssignToMachine(m)
  1383  	c.Assert(err, jc.ErrorIsNil)
  1384  	err = u.OpenPort("tcp", 80)
  1385  	c.Assert(err, jc.ErrorIsNil)
  1386  
  1387  	// Starting the firewaller, no open ports.
  1388  	fw := s.newFirewaller(c)
  1389  	defer statetesting.AssertKillAndWait(c, fw)
  1390  
  1391  	s.assertEnvironPorts(c, nil)
  1392  
  1393  	// Expose application.
  1394  	err = app.SetExposed()
  1395  	c.Assert(err, jc.ErrorIsNil)
  1396  	s.assertEnvironPorts(c, []network.IngressRule{
  1397  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1398  	})
  1399  }
  1400  
  1401  func (s *GlobalModeSuite) TestRestart(c *gc.C) {
  1402  	// Start firewaller and open ports.
  1403  	fw := s.newFirewaller(c)
  1404  
  1405  	app := s.AddTestingApplication(c, "wordpress", s.charm)
  1406  	err := app.SetExposed()
  1407  	c.Assert(err, jc.ErrorIsNil)
  1408  
  1409  	u, m := s.addUnit(c, app)
  1410  	s.startInstance(c, m)
  1411  	err = u.OpenPorts("tcp", 80, 90)
  1412  	c.Assert(err, jc.ErrorIsNil)
  1413  	err = u.OpenPort("tcp", 8080)
  1414  	c.Assert(err, jc.ErrorIsNil)
  1415  
  1416  	s.assertEnvironPorts(c, []network.IngressRule{
  1417  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
  1418  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1419  	})
  1420  
  1421  	// Stop firewaller and close one and open a different port.
  1422  	err = worker.Stop(fw)
  1423  	c.Assert(err, jc.ErrorIsNil)
  1424  
  1425  	err = u.ClosePort("tcp", 8080)
  1426  	c.Assert(err, jc.ErrorIsNil)
  1427  	err = u.OpenPort("tcp", 8888)
  1428  	c.Assert(err, jc.ErrorIsNil)
  1429  
  1430  	// Start firewaller and check port.
  1431  	fw = s.newFirewaller(c)
  1432  	defer statetesting.AssertKillAndWait(c, fw)
  1433  
  1434  	s.assertEnvironPorts(c, []network.IngressRule{
  1435  		network.MustNewIngressRule("tcp", 80, 90, "0.0.0.0/0"),
  1436  		network.MustNewIngressRule("tcp", 8888, 8888, "0.0.0.0/0"),
  1437  	})
  1438  }
  1439  
  1440  func (s *GlobalModeSuite) TestRestartUnexposedApplication(c *gc.C) {
  1441  	// Start firewaller and open ports.
  1442  	fw := s.newFirewaller(c)
  1443  
  1444  	app := s.AddTestingApplication(c, "wordpress", s.charm)
  1445  	err := app.SetExposed()
  1446  	c.Assert(err, jc.ErrorIsNil)
  1447  
  1448  	u, m := s.addUnit(c, app)
  1449  	s.startInstance(c, m)
  1450  	err = u.OpenPort("tcp", 80)
  1451  	c.Assert(err, jc.ErrorIsNil)
  1452  	err = u.OpenPort("tcp", 8080)
  1453  	c.Assert(err, jc.ErrorIsNil)
  1454  
  1455  	s.assertEnvironPorts(c, []network.IngressRule{
  1456  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1457  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1458  	})
  1459  
  1460  	// Stop firewaller and clear exposed flag on application.
  1461  	err = worker.Stop(fw)
  1462  	c.Assert(err, jc.ErrorIsNil)
  1463  
  1464  	err = app.ClearExposed()
  1465  	c.Assert(err, jc.ErrorIsNil)
  1466  
  1467  	// Start firewaller and check port.
  1468  	fw = s.newFirewaller(c)
  1469  	defer statetesting.AssertKillAndWait(c, fw)
  1470  
  1471  	s.assertEnvironPorts(c, nil)
  1472  }
  1473  
  1474  func (s *GlobalModeSuite) TestRestartPortCount(c *gc.C) {
  1475  	// Start firewaller and open ports.
  1476  	fw := s.newFirewaller(c)
  1477  
  1478  	app1 := s.AddTestingApplication(c, "wordpress", s.charm)
  1479  	err := app1.SetExposed()
  1480  	c.Assert(err, jc.ErrorIsNil)
  1481  
  1482  	u1, m1 := s.addUnit(c, app1)
  1483  	s.startInstance(c, m1)
  1484  	err = u1.OpenPort("tcp", 80)
  1485  	c.Assert(err, jc.ErrorIsNil)
  1486  	err = u1.OpenPort("tcp", 8080)
  1487  	c.Assert(err, jc.ErrorIsNil)
  1488  
  1489  	s.assertEnvironPorts(c, []network.IngressRule{
  1490  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1491  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1492  	})
  1493  
  1494  	// Stop firewaller and add another application using the port.
  1495  	err = worker.Stop(fw)
  1496  	c.Assert(err, jc.ErrorIsNil)
  1497  
  1498  	app2 := s.AddTestingApplication(c, "moinmoin", s.charm)
  1499  	err = app2.SetExposed()
  1500  	c.Assert(err, jc.ErrorIsNil)
  1501  
  1502  	u2, m2 := s.addUnit(c, app2)
  1503  	s.startInstance(c, m2)
  1504  	err = u2.OpenPort("tcp", 80)
  1505  	c.Assert(err, jc.ErrorIsNil)
  1506  
  1507  	// Start firewaller and check port.
  1508  	fw = s.newFirewaller(c)
  1509  	defer statetesting.AssertKillAndWait(c, fw)
  1510  
  1511  	s.assertEnvironPorts(c, []network.IngressRule{
  1512  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1513  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1514  	})
  1515  
  1516  	// Closing a port opened by a different unit won't touch the environment.
  1517  	err = u1.ClosePort("tcp", 80)
  1518  	c.Assert(err, jc.ErrorIsNil)
  1519  	s.assertEnvironPorts(c, []network.IngressRule{
  1520  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1521  		network.MustNewIngressRule("tcp", 8080, 8080, "0.0.0.0/0"),
  1522  	})
  1523  
  1524  	// Closing a port used just once changes the environment.
  1525  	err = u1.ClosePort("tcp", 8080)
  1526  	c.Assert(err, jc.ErrorIsNil)
  1527  	s.assertEnvironPorts(c, []network.IngressRule{
  1528  		network.MustNewIngressRule("tcp", 80, 80, "0.0.0.0/0"),
  1529  	})
  1530  
  1531  	// Closing the last port also modifies the environment.
  1532  	err = u2.ClosePort("tcp", 80)
  1533  	c.Assert(err, jc.ErrorIsNil)
  1534  	s.assertEnvironPorts(c, nil)
  1535  }
  1536  
  1537  type NoneModeSuite struct {
  1538  	firewallerBaseSuite
  1539  }
  1540  
  1541  var _ = gc.Suite(&NoneModeSuite{})
  1542  
  1543  func (s *NoneModeSuite) SetUpTest(c *gc.C) {
  1544  	s.firewallerBaseSuite.setUpTest(c, config.FwNone)
  1545  }
  1546  
  1547  func (s *NoneModeSuite) TestStopImmediately(c *gc.C) {
  1548  	fwEnv, ok := s.Environ.(environs.Firewaller)
  1549  	c.Assert(ok, gc.Equals, true)
  1550  
  1551  	cfg := firewaller.Config{
  1552  		ModelUUID:          s.State.ModelUUID(),
  1553  		Mode:               config.FwNone,
  1554  		EnvironFirewaller:  fwEnv,
  1555  		EnvironInstances:   s.Environ,
  1556  		FirewallerAPI:      s.firewaller,
  1557  		RemoteRelationsApi: s.remoteRelations,
  1558  		NewCrossModelFacadeFunc: func(*api.Info) (firewaller.CrossModelFirewallerFacadeCloser, error) {
  1559  			return s.crossmodelFirewaller, nil
  1560  		},
  1561  		CredentialAPI: s.credentialsFacade,
  1562  	}
  1563  	_, err := firewaller.NewFirewaller(cfg)
  1564  	c.Assert(err, gc.ErrorMatches, `invalid firewall-mode "none"`)
  1565  }