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