github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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  	gc "launchpad.net/gocheck"
    10  
    11  	"launchpad.net/juju-core/errors"
    12  	"launchpad.net/juju-core/instance"
    13  	"launchpad.net/juju-core/juju/testing"
    14  	"launchpad.net/juju-core/state"
    15  	"launchpad.net/juju-core/state/api/params"
    16  	"launchpad.net/juju-core/state/apiserver/common"
    17  	commontesting "launchpad.net/juju-core/state/apiserver/common/testing"
    18  	"launchpad.net/juju-core/state/apiserver/firewaller"
    19  	apiservertesting "launchpad.net/juju-core/state/apiserver/testing"
    20  	statetesting "launchpad.net/juju-core/state/testing"
    21  	coretesting "launchpad.net/juju-core/testing"
    22  	jc "launchpad.net/juju-core/testing/checkers"
    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.IsNotFoundError)
   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  	result, err := s.firewaller.WatchEnvironMachines()
   193  	c.Assert(err, gc.IsNil)
   194  	c.Assert(result, jc.DeepEquals, params.StringsWatchResult{
   195  		StringsWatcherId: "1",
   196  		Changes:          []string{"0", "1", "2"},
   197  	})
   198  
   199  	// Verify the resources were registered and stop them when done.
   200  	c.Assert(s.resources.Count(), gc.Equals, 1)
   201  	resource := s.resources.Get("1")
   202  	defer statetesting.AssertStop(c, resource)
   203  
   204  	// Check that the Watch has consumed the initial event ("returned"
   205  	// in the Watch call)
   206  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   207  	wc.AssertNoChange()
   208  }
   209  
   210  func (s *firewallerSuite) TestWatch(c *gc.C) {
   211  	c.Assert(s.resources.Count(), gc.Equals, 0)
   212  
   213  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   214  		{Tag: s.machines[0].Tag()},
   215  		{Tag: s.service.Tag()},
   216  		{Tag: s.units[0].Tag()},
   217  	}})
   218  	result, err := s.firewaller.Watch(args)
   219  	c.Assert(err, gc.IsNil)
   220  	c.Assert(result, jc.DeepEquals, params.NotifyWatchResults{
   221  		Results: []params.NotifyWatchResult{
   222  			{Error: apiservertesting.ErrUnauthorized},
   223  			{NotifyWatcherId: "1"},
   224  			{NotifyWatcherId: "2"},
   225  			{Error: apiservertesting.ErrUnauthorized},
   226  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   227  			{Error: apiservertesting.NotFoundError(`service "bar"`)},
   228  			{Error: apiservertesting.ErrUnauthorized},
   229  			{Error: apiservertesting.ErrUnauthorized},
   230  			{Error: apiservertesting.ErrUnauthorized},
   231  		},
   232  	})
   233  
   234  	// Verify the resources were registered and stop when done.
   235  	c.Assert(s.resources.Count(), gc.Equals, 2)
   236  	c.Assert(result.Results[1].NotifyWatcherId, gc.Equals, "1")
   237  	watcher1 := s.resources.Get("1")
   238  	defer statetesting.AssertStop(c, watcher1)
   239  	c.Assert(result.Results[2].NotifyWatcherId, gc.Equals, "2")
   240  	watcher2 := s.resources.Get("2")
   241  	defer statetesting.AssertStop(c, watcher2)
   242  
   243  	// Check that the Watch has consumed the initial event ("returned" in
   244  	// the Watch call)
   245  	wc1 := statetesting.NewNotifyWatcherC(c, s.State, watcher1.(state.NotifyWatcher))
   246  	wc1.AssertNoChange()
   247  	wc2 := statetesting.NewNotifyWatcherC(c, s.State, watcher2.(state.NotifyWatcher))
   248  	wc2.AssertNoChange()
   249  }
   250  
   251  func (s *firewallerSuite) TestWatchUnits(c *gc.C) {
   252  	c.Assert(s.resources.Count(), gc.Equals, 0)
   253  
   254  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   255  		{Tag: s.machines[0].Tag()},
   256  		{Tag: s.service.Tag()},
   257  		{Tag: s.units[0].Tag()},
   258  	}})
   259  	result, err := s.firewaller.WatchUnits(args)
   260  	c.Assert(err, gc.IsNil)
   261  	c.Assert(result, jc.DeepEquals, params.StringsWatchResults{
   262  		Results: []params.StringsWatchResult{
   263  			{Changes: []string{"wordpress/0"}, StringsWatcherId: "1"},
   264  			{Error: apiservertesting.ErrUnauthorized},
   265  			{Error: apiservertesting.ErrUnauthorized},
   266  			{Error: apiservertesting.NotFoundError("machine 42")},
   267  			{Error: apiservertesting.ErrUnauthorized},
   268  			{Error: apiservertesting.ErrUnauthorized},
   269  			{Error: apiservertesting.ErrUnauthorized},
   270  			{Error: apiservertesting.ErrUnauthorized},
   271  			{Error: apiservertesting.ErrUnauthorized},
   272  		},
   273  	})
   274  
   275  	// Verify the resource was registered and stop when done
   276  	c.Assert(s.resources.Count(), gc.Equals, 1)
   277  	c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1")
   278  	resource := s.resources.Get("1")
   279  	defer statetesting.AssertStop(c, resource)
   280  
   281  	// Check that the Watch has consumed the initial event ("returned" in
   282  	// the Watch call)
   283  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   284  	wc.AssertNoChange()
   285  }
   286  
   287  func (s *firewallerSuite) TestGetExposed(c *gc.C) {
   288  	// Set the service to exposed first.
   289  	err := s.service.SetExposed()
   290  	c.Assert(err, gc.IsNil)
   291  
   292  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   293  		{Tag: s.service.Tag()},
   294  	}})
   295  	result, err := s.firewaller.GetExposed(args)
   296  	c.Assert(err, gc.IsNil)
   297  	c.Assert(result, jc.DeepEquals, params.BoolResults{
   298  		Results: []params.BoolResult{
   299  			{Result: true},
   300  			{Error: apiservertesting.ErrUnauthorized},
   301  			{Error: apiservertesting.ErrUnauthorized},
   302  			{Error: apiservertesting.NotFoundError(`service "bar"`)},
   303  			{Error: apiservertesting.ErrUnauthorized},
   304  			{Error: apiservertesting.ErrUnauthorized},
   305  			{Error: apiservertesting.ErrUnauthorized},
   306  		},
   307  	})
   308  
   309  	// Now reset the exposed flag for the service and check again.
   310  	err = s.service.ClearExposed()
   311  	c.Assert(err, gc.IsNil)
   312  
   313  	args = params.Entities{Entities: []params.Entity{
   314  		{Tag: s.service.Tag()},
   315  	}}
   316  	result, err = s.firewaller.GetExposed(args)
   317  	c.Assert(err, gc.IsNil)
   318  	c.Assert(result, jc.DeepEquals, params.BoolResults{
   319  		Results: []params.BoolResult{
   320  			{Result: false},
   321  		},
   322  	})
   323  }
   324  
   325  func (s *firewallerSuite) TestOpenedPorts(c *gc.C) {
   326  	// Open some ports on two of the units.
   327  	err := s.units[0].OpenPort("foo", 1234)
   328  	c.Assert(err, gc.IsNil)
   329  	err = s.units[0].OpenPort("bar", 4321)
   330  	c.Assert(err, gc.IsNil)
   331  	err = s.units[2].OpenPort("baz", 1111)
   332  	c.Assert(err, gc.IsNil)
   333  
   334  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   335  		{Tag: s.units[0].Tag()},
   336  		{Tag: s.units[1].Tag()},
   337  		{Tag: s.units[2].Tag()},
   338  	}})
   339  	result, err := s.firewaller.OpenedPorts(args)
   340  	c.Assert(err, gc.IsNil)
   341  	c.Assert(result, jc.DeepEquals, params.PortsResults{
   342  		Results: []params.PortsResult{
   343  			{Ports: []instance.Port{{"bar", 4321}, {"foo", 1234}}},
   344  			{Ports: []instance.Port{}},
   345  			{Ports: []instance.Port{{"baz", 1111}}},
   346  			{Error: apiservertesting.ErrUnauthorized},
   347  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   348  			{Error: apiservertesting.ErrUnauthorized},
   349  			{Error: apiservertesting.ErrUnauthorized},
   350  			{Error: apiservertesting.ErrUnauthorized},
   351  			{Error: apiservertesting.ErrUnauthorized},
   352  		},
   353  	})
   354  
   355  	// Now close unit 2's port and check again.
   356  	err = s.units[2].ClosePort("baz", 1111)
   357  	c.Assert(err, gc.IsNil)
   358  
   359  	args = params.Entities{Entities: []params.Entity{
   360  		{Tag: s.units[2].Tag()},
   361  	}}
   362  	result, err = s.firewaller.OpenedPorts(args)
   363  	c.Assert(err, gc.IsNil)
   364  	c.Assert(result, jc.DeepEquals, params.PortsResults{
   365  		Results: []params.PortsResult{
   366  			{Ports: []instance.Port{}},
   367  		},
   368  	})
   369  }
   370  
   371  func (s *firewallerSuite) TestGetAssignedMachine(c *gc.C) {
   372  	// Unassign a unit first.
   373  	err := s.units[2].UnassignFromMachine()
   374  	c.Assert(err, gc.IsNil)
   375  
   376  	args := addFakeEntities(params.Entities{Entities: []params.Entity{
   377  		{Tag: s.units[0].Tag()},
   378  		{Tag: s.units[1].Tag()},
   379  		{Tag: s.units[2].Tag()},
   380  	}})
   381  	result, err := s.firewaller.GetAssignedMachine(args)
   382  	c.Assert(err, gc.IsNil)
   383  	c.Assert(result, jc.DeepEquals, params.StringResults{
   384  		Results: []params.StringResult{
   385  			{Result: s.machines[0].Tag()},
   386  			{Result: s.machines[1].Tag()},
   387  			{Error: apiservertesting.NotAssignedError("wordpress/2")},
   388  			{Error: apiservertesting.ErrUnauthorized},
   389  			{Error: apiservertesting.NotFoundError(`unit "foo/0"`)},
   390  			{Error: apiservertesting.ErrUnauthorized},
   391  			{Error: apiservertesting.ErrUnauthorized},
   392  			{Error: apiservertesting.ErrUnauthorized},
   393  			{Error: apiservertesting.ErrUnauthorized},
   394  		},
   395  	})
   396  
   397  	// Now reset assign unit 2 again and check.
   398  	err = s.units[2].AssignToMachine(s.machines[0])
   399  	c.Assert(err, gc.IsNil)
   400  
   401  	args = params.Entities{Entities: []params.Entity{
   402  		{Tag: s.units[2].Tag()},
   403  	}}
   404  	result, err = s.firewaller.GetAssignedMachine(args)
   405  	c.Assert(err, gc.IsNil)
   406  	c.Assert(result, jc.DeepEquals, params.StringResults{
   407  		Results: []params.StringResult{
   408  			{Result: s.machines[0].Tag()},
   409  		},
   410  	})
   411  }
   412  
   413  func (s *firewallerSuite) assertLife(c *gc.C, index int, expectLife state.Life) {
   414  	err := s.machines[index].Refresh()
   415  	c.Assert(err, gc.IsNil)
   416  	c.Assert(s.machines[index].Life(), gc.Equals, expectLife)
   417  }
   418  
   419  var commonFakeEntities = []params.Entity{
   420  	{Tag: "machine-42"},
   421  	{Tag: "unit-foo-0"},
   422  	{Tag: "service-bar"},
   423  	{Tag: "user-foo"},
   424  	{Tag: "foo-bar"},
   425  	{Tag: ""},
   426  }
   427  
   428  func addFakeEntities(actual params.Entities) params.Entities {
   429  	for _, entity := range commonFakeEntities {
   430  		actual.Entities = append(actual.Entities, entity)
   431  	}
   432  	return actual
   433  }