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