github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/firewaller/firewaller_base_test.go (about)

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