github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/state/apiserver/firewaller/firewaller_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package firewaller_test
     5  
     6  import (
     7  	stdtesting "testing"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "launchpad.net/gocheck"
    12  
    13  	"github.com/juju/juju/instance"
    14  	"github.com/juju/juju/juju/testing"
    15  	"github.com/juju/juju/network"
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/state/api/params"
    18  	"github.com/juju/juju/state/apiserver/common"
    19  	commontesting "github.com/juju/juju/state/apiserver/common/testing"
    20  	"github.com/juju/juju/state/apiserver/firewaller"
    21  	apiservertesting "github.com/juju/juju/state/apiserver/testing"
    22  	statetesting "github.com/juju/juju/state/testing"
    23  	coretesting "github.com/juju/juju/testing"
    24  )
    25  
    26  func Test(t *stdtesting.T) {
    27  	coretesting.MgoTestPackage(t)
    28  }
    29  
    30  type firewallerSuite struct {
    31  	testing.JujuConnSuite
    32  	*commontesting.EnvironWatcherTest
    33  
    34  	machines []*state.Machine
    35  	service  *state.Service
    36  	charm    *state.Charm
    37  	units    []*state.Unit
    38  
    39  	authorizer apiservertesting.FakeAuthorizer
    40  	resources  *common.Resources
    41  	firewaller *firewaller.FirewallerAPI
    42  }
    43  
    44  var _ = gc.Suite(&firewallerSuite{})
    45  
    46  func (s *firewallerSuite) SetUpTest(c *gc.C) {
    47  	s.JujuConnSuite.SetUpTest(c)
    48  
    49  	// Reset previous machines and units (if any) and create 3
    50  	// machines for the tests.
    51  	s.machines = nil
    52  	s.units = nil
    53  	// Note that the specific machine ids allocated are assumed
    54  	// to be numerically consecutive from zero.
    55  	for i := 0; i <= 2; i++ {
    56  		machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
    57  		c.Check(err, gc.IsNil)
    58  		s.machines = append(s.machines, machine)
    59  	}
    60  	// Create a service and three units for these machines.
    61  	s.charm = s.AddTestingCharm(c, "wordpress")
    62  	s.service = s.AddTestingService(c, "wordpress", s.charm)
    63  	// Add the rest of the units and assign them.
    64  	for i := 0; i <= 2; i++ {
    65  		unit, err := s.service.AddUnit()
    66  		c.Check(err, gc.IsNil)
    67  		err = unit.AssignToMachine(s.machines[i])
    68  		c.Check(err, gc.IsNil)
    69  		s.units = append(s.units, unit)
    70  	}
    71  
    72  	// Create a FakeAuthorizer so we can check permissions,
    73  	// set up assuming we logged in as the environment manager.
    74  	s.authorizer = apiservertesting.FakeAuthorizer{
    75  		LoggedIn:       true,
    76  		EnvironManager: true,
    77  	}
    78  
    79  	// Create the resource registry separately to track invocations to
    80  	// Register.
    81  	s.resources = common.NewResources()
    82  
    83  	// Create a firewaller API for the machine.
    84  	firewallerAPI, err := firewaller.NewFirewallerAPI(
    85  		s.State,
    86  		s.resources,
    87  		s.authorizer,
    88  	)
    89  	c.Assert(err, gc.IsNil)
    90  	s.firewaller = firewallerAPI
    91  	s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.firewaller, s.State, s.resources, commontesting.HasSecrets)
    92  }
    93  
    94  func (s *firewallerSuite) TestFirewallerFailsWithNonEnvironManagerUser(c *gc.C) {
    95  	anAuthorizer := s.authorizer
    96  	anAuthorizer.MachineAgent = true
    97  	anAuthorizer.EnvironManager = false
    98  	aFirewaller, err := firewaller.NewFirewallerAPI(s.State, s.resources, anAuthorizer)
    99  	c.Assert(err, gc.NotNil)
   100  	c.Assert(err, gc.ErrorMatches, "permission denied")
   101  	c.Assert(aFirewaller, gc.IsNil)
   102  }
   103  
   104  func (s *firewallerSuite) TestLife(c *gc.C) {
   105  	// Unassign unit 1 from its machine, so we can change its life cycle.
   106  	err := s.units[1].UnassignFromMachine()
   107  	c.Assert(err, gc.IsNil)
   108  
   109  	err = s.machines[1].EnsureDead()
   110  	c.Assert(err, gc.IsNil)
   111  	s.assertLife(c, 0, state.Alive)
   112  	s.assertLife(c, 1, state.Dead)
   113  	s.assertLife(c, 2, state.Alive)
   114  
   115  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   116  		{Tag: s.machines[0].Tag()},
   117  		{Tag: s.machines[1].Tag()},
   118  		{Tag: s.machines[2].Tag()},
   119  	}})
   120  	result, err := s.firewaller.Life(args)
   121  	c.Assert(err, gc.IsNil)
   122  	c.Assert(result, jc.DeepEquals, params.LifeResults{
   123  		Results: []params.LifeResult{
   124  			{Life: "alive"},
   125  			{Life: "dead"},
   126  			{Life: "alive"},
   127  			{Error: apiservertesting.NotFoundError("machine 42")},
   128  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   129  			{Error: apiservertesting.NotFoundError(`service "bar"`)},
   130  			{Error: apiservertesting.ErrUnauthorized},
   131  			{Error: apiservertesting.ErrUnauthorized},
   132  			{Error: apiservertesting.ErrUnauthorized},
   133  		},
   134  	})
   135  
   136  	// Remove a machine and make sure it's detected.
   137  	err = s.machines[1].Remove()
   138  	c.Assert(err, gc.IsNil)
   139  	err = s.machines[1].Refresh()
   140  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   141  
   142  	args = params.Entities{
   143  		Entities: []params.Entity{
   144  			{Tag: s.machines[1].Tag()},
   145  		},
   146  	}
   147  	result, err = s.firewaller.Life(args)
   148  	c.Assert(err, gc.IsNil)
   149  	c.Assert(result, jc.DeepEquals, params.LifeResults{
   150  		Results: []params.LifeResult{
   151  			{Error: apiservertesting.NotFoundError("machine 1")},
   152  		},
   153  	})
   154  }
   155  
   156  func (s *firewallerSuite) TestInstanceId(c *gc.C) {
   157  	// Provision 2 machines first.
   158  	err := s.machines[0].SetProvisioned("i-am", "fake_nonce", nil)
   159  	c.Assert(err, gc.IsNil)
   160  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   161  	err = s.machines[1].SetProvisioned("i-am-not", "fake_nonce", &hwChars)
   162  	c.Assert(err, gc.IsNil)
   163  
   164  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   165  		{Tag: s.machines[0].Tag()},
   166  		{Tag: s.machines[1].Tag()},
   167  		{Tag: s.machines[2].Tag()},
   168  		{Tag: s.service.Tag()},
   169  		{Tag: s.units[2].Tag()},
   170  	}})
   171  	result, err := s.firewaller.InstanceId(args)
   172  	c.Assert(err, gc.IsNil)
   173  	c.Assert(result, jc.DeepEquals, params.StringResults{
   174  		Results: []params.StringResult{
   175  			{Result: "i-am"},
   176  			{Result: "i-am-not"},
   177  			{Error: apiservertesting.NotProvisionedError("2")},
   178  			{Error: apiservertesting.ErrUnauthorized},
   179  			{Error: apiservertesting.ErrUnauthorized},
   180  			{Error: apiservertesting.NotFoundError("machine 42")},
   181  			{Error: apiservertesting.ErrUnauthorized},
   182  			{Error: apiservertesting.ErrUnauthorized},
   183  			{Error: apiservertesting.ErrUnauthorized},
   184  			{Error: apiservertesting.ErrUnauthorized},
   185  			{Error: apiservertesting.ErrUnauthorized},
   186  		},
   187  	})
   188  }
   189  
   190  func (s *firewallerSuite) TestWatchEnvironMachines(c *gc.C) {
   191  	c.Assert(s.resources.Count(), gc.Equals, 0)
   192  
   193  	got, err := s.firewaller.WatchEnvironMachines()
   194  	c.Assert(err, gc.IsNil)
   195  	want := params.StringsWatchResult{
   196  		StringsWatcherId: "1",
   197  		Changes:          []string{"0", "1", "2"},
   198  	}
   199  	c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId)
   200  	c.Assert(got.Changes, jc.SameContents, want.Changes)
   201  
   202  	// Verify the resources were registered and stop them when done.
   203  	c.Assert(s.resources.Count(), gc.Equals, 1)
   204  	resource := s.resources.Get("1")
   205  	defer statetesting.AssertStop(c, resource)
   206  
   207  	// Check that the Watch has consumed the initial event ("returned"
   208  	// in the Watch call)
   209  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   210  	wc.AssertNoChange()
   211  }
   212  
   213  func (s *firewallerSuite) TestWatch(c *gc.C) {
   214  	c.Assert(s.resources.Count(), gc.Equals, 0)
   215  
   216  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   217  		{Tag: s.machines[0].Tag()},
   218  		{Tag: s.service.Tag()},
   219  		{Tag: s.units[0].Tag()},
   220  	}})
   221  	result, err := s.firewaller.Watch(args)
   222  	c.Assert(err, gc.IsNil)
   223  	c.Assert(result, jc.DeepEquals, params.NotifyWatchResults{
   224  		Results: []params.NotifyWatchResult{
   225  			{Error: apiservertesting.ErrUnauthorized},
   226  			{NotifyWatcherId: "1"},
   227  			{NotifyWatcherId: "2"},
   228  			{Error: apiservertesting.ErrUnauthorized},
   229  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   230  			{Error: apiservertesting.NotFoundError(`service "bar"`)},
   231  			{Error: apiservertesting.ErrUnauthorized},
   232  			{Error: apiservertesting.ErrUnauthorized},
   233  			{Error: apiservertesting.ErrUnauthorized},
   234  		},
   235  	})
   236  
   237  	// Verify the resources were registered and stop when done.
   238  	c.Assert(s.resources.Count(), gc.Equals, 2)
   239  	c.Assert(result.Results[1].NotifyWatcherId, gc.Equals, "1")
   240  	watcher1 := s.resources.Get("1")
   241  	defer statetesting.AssertStop(c, watcher1)
   242  	c.Assert(result.Results[2].NotifyWatcherId, gc.Equals, "2")
   243  	watcher2 := s.resources.Get("2")
   244  	defer statetesting.AssertStop(c, watcher2)
   245  
   246  	// Check that the Watch has consumed the initial event ("returned" in
   247  	// the Watch call)
   248  	wc1 := statetesting.NewNotifyWatcherC(c, s.State, watcher1.(state.NotifyWatcher))
   249  	wc1.AssertNoChange()
   250  	wc2 := statetesting.NewNotifyWatcherC(c, s.State, watcher2.(state.NotifyWatcher))
   251  	wc2.AssertNoChange()
   252  }
   253  
   254  func (s *firewallerSuite) TestWatchUnits(c *gc.C) {
   255  	c.Assert(s.resources.Count(), gc.Equals, 0)
   256  
   257  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   258  		{Tag: s.machines[0].Tag()},
   259  		{Tag: s.service.Tag()},
   260  		{Tag: s.units[0].Tag()},
   261  	}})
   262  	result, err := s.firewaller.WatchUnits(args)
   263  	c.Assert(err, gc.IsNil)
   264  	c.Assert(result, jc.DeepEquals, params.StringsWatchResults{
   265  		Results: []params.StringsWatchResult{
   266  			{Changes: []string{"wordpress/0"}, StringsWatcherId: "1"},
   267  			{Error: apiservertesting.ErrUnauthorized},
   268  			{Error: apiservertesting.ErrUnauthorized},
   269  			{Error: apiservertesting.NotFoundError("machine 42")},
   270  			{Error: apiservertesting.ErrUnauthorized},
   271  			{Error: apiservertesting.ErrUnauthorized},
   272  			{Error: apiservertesting.ErrUnauthorized},
   273  			{Error: apiservertesting.ErrUnauthorized},
   274  			{Error: apiservertesting.ErrUnauthorized},
   275  		},
   276  	})
   277  
   278  	// Verify the resource was registered and stop when done
   279  	c.Assert(s.resources.Count(), gc.Equals, 1)
   280  	c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1")
   281  	resource := s.resources.Get("1")
   282  	defer statetesting.AssertStop(c, resource)
   283  
   284  	// Check that the Watch has consumed the initial event ("returned" in
   285  	// the Watch call)
   286  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   287  	wc.AssertNoChange()
   288  }
   289  
   290  func (s *firewallerSuite) TestGetExposed(c *gc.C) {
   291  	// Set the service to exposed first.
   292  	err := s.service.SetExposed()
   293  	c.Assert(err, gc.IsNil)
   294  
   295  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   296  		{Tag: s.service.Tag()},
   297  	}})
   298  	result, err := s.firewaller.GetExposed(args)
   299  	c.Assert(err, gc.IsNil)
   300  	c.Assert(result, jc.DeepEquals, params.BoolResults{
   301  		Results: []params.BoolResult{
   302  			{Result: true},
   303  			{Error: apiservertesting.ErrUnauthorized},
   304  			{Error: apiservertesting.ErrUnauthorized},
   305  			{Error: apiservertesting.NotFoundError(`service "bar"`)},
   306  			{Error: apiservertesting.ErrUnauthorized},
   307  			{Error: apiservertesting.ErrUnauthorized},
   308  			{Error: apiservertesting.ErrUnauthorized},
   309  		},
   310  	})
   311  
   312  	// Now reset the exposed flag for the service and check again.
   313  	err = s.service.ClearExposed()
   314  	c.Assert(err, gc.IsNil)
   315  
   316  	args = params.Entities{Entities: []params.Entity{
   317  		{Tag: s.service.Tag()},
   318  	}}
   319  	result, err = s.firewaller.GetExposed(args)
   320  	c.Assert(err, gc.IsNil)
   321  	c.Assert(result, jc.DeepEquals, params.BoolResults{
   322  		Results: []params.BoolResult{
   323  			{Result: false},
   324  		},
   325  	})
   326  }
   327  
   328  func (s *firewallerSuite) TestOpenedPorts(c *gc.C) {
   329  	// Open some ports on two of the units.
   330  	err := s.units[0].OpenPort("foo", 1234)
   331  	c.Assert(err, gc.IsNil)
   332  	err = s.units[0].OpenPort("bar", 4321)
   333  	c.Assert(err, gc.IsNil)
   334  	err = s.units[2].OpenPort("baz", 1111)
   335  	c.Assert(err, gc.IsNil)
   336  
   337  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   338  		{Tag: s.units[0].Tag()},
   339  		{Tag: s.units[1].Tag()},
   340  		{Tag: s.units[2].Tag()},
   341  	}})
   342  	result, err := s.firewaller.OpenedPorts(args)
   343  	c.Assert(err, gc.IsNil)
   344  	c.Assert(result, jc.DeepEquals, params.PortsResults{
   345  		Results: []params.PortsResult{
   346  			{Ports: []network.Port{{"bar", 4321}, {"foo", 1234}}},
   347  			{Ports: []network.Port{}},
   348  			{Ports: []network.Port{{"baz", 1111}}},
   349  			{Error: apiservertesting.ErrUnauthorized},
   350  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   351  			{Error: apiservertesting.ErrUnauthorized},
   352  			{Error: apiservertesting.ErrUnauthorized},
   353  			{Error: apiservertesting.ErrUnauthorized},
   354  			{Error: apiservertesting.ErrUnauthorized},
   355  		},
   356  	})
   357  
   358  	// Now close unit 2's port and check again.
   359  	err = s.units[2].ClosePort("baz", 1111)
   360  	c.Assert(err, gc.IsNil)
   361  
   362  	args = params.Entities{Entities: []params.Entity{
   363  		{Tag: s.units[2].Tag()},
   364  	}}
   365  	result, err = s.firewaller.OpenedPorts(args)
   366  	c.Assert(err, gc.IsNil)
   367  	c.Assert(result, jc.DeepEquals, params.PortsResults{
   368  		Results: []params.PortsResult{
   369  			{Ports: []network.Port{}},
   370  		},
   371  	})
   372  }
   373  
   374  func (s *firewallerSuite) TestGetAssignedMachine(c *gc.C) {
   375  	// Unassign a unit first.
   376  	err := s.units[2].UnassignFromMachine()
   377  	c.Assert(err, gc.IsNil)
   378  
   379  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   380  		{Tag: s.units[0].Tag()},
   381  		{Tag: s.units[1].Tag()},
   382  		{Tag: s.units[2].Tag()},
   383  	}})
   384  	result, err := s.firewaller.GetAssignedMachine(args)
   385  	c.Assert(err, gc.IsNil)
   386  	c.Assert(result, jc.DeepEquals, params.StringResults{
   387  		Results: []params.StringResult{
   388  			{Result: s.machines[0].Tag()},
   389  			{Result: s.machines[1].Tag()},
   390  			{Error: apiservertesting.NotAssignedError("wordpress/2")},
   391  			{Error: apiservertesting.ErrUnauthorized},
   392  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   393  			{Error: apiservertesting.ErrUnauthorized},
   394  			{Error: apiservertesting.ErrUnauthorized},
   395  			{Error: apiservertesting.ErrUnauthorized},
   396  			{Error: apiservertesting.ErrUnauthorized},
   397  		},
   398  	})
   399  
   400  	// Now reset assign unit 2 again and check.
   401  	err = s.units[2].AssignToMachine(s.machines[0])
   402  	c.Assert(err, gc.IsNil)
   403  
   404  	args = params.Entities{Entities: []params.Entity{
   405  		{Tag: s.units[2].Tag()},
   406  	}}
   407  	result, err = s.firewaller.GetAssignedMachine(args)
   408  	c.Assert(err, gc.IsNil)
   409  	c.Assert(result, jc.DeepEquals, params.StringResults{
   410  		Results: []params.StringResult{
   411  			{Result: s.machines[0].Tag()},
   412  		},
   413  	})
   414  }
   415  
   416  func (s *firewallerSuite) assertLife(c *gc.C, index int, expectLife state.Life) {
   417  	err := s.machines[index].Refresh()
   418  	c.Assert(err, gc.IsNil)
   419  	c.Assert(s.machines[index].Life(), gc.Equals, expectLife)
   420  }
   421  
   422  var commonFakeEntities = []params.Entity{
   423  	{Tag: "machine-42"},
   424  	{Tag: "unit-foo-0"},
   425  	{Tag: "service-bar"},
   426  	{Tag: "user-foo"},
   427  	{Tag: "foo-bar"},
   428  	{Tag: ""},
   429  }
   430  
   431  func addFakeEntities(actual params.Entities) params.Entities {
   432  	for _, entity := range commonFakeEntities {
   433  		actual.Entities = append(actual.Entities, entity)
   434  	}
   435  	return actual
   436  }