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