github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/apiserver/deployer/deployer_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package deployer_test
     5  
     6  import (
     7  	"sort"
     8  	stdtesting "testing"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "launchpad.net/gocheck"
    14  
    15  	"github.com/juju/juju/instance"
    16  	"github.com/juju/juju/juju/testing"
    17  	"github.com/juju/juju/state"
    18  	"github.com/juju/juju/state/api/params"
    19  	"github.com/juju/juju/state/apiserver/common"
    20  	"github.com/juju/juju/state/apiserver/deployer"
    21  	apiservertesting "github.com/juju/juju/state/apiserver/testing"
    22  	statetesting "github.com/juju/juju/state/testing"
    23  	coretesting "github.com/juju/juju/testing"
    24  )
    25  
    26  func Test(t *stdtesting.T) {
    27  	coretesting.MgoTestPackage(t)
    28  }
    29  
    30  type deployerSuite struct {
    31  	testing.JujuConnSuite
    32  
    33  	authorizer apiservertesting.FakeAuthorizer
    34  
    35  	service0     *state.Service
    36  	service1     *state.Service
    37  	machine0     *state.Machine
    38  	machine1     *state.Machine
    39  	principal0   *state.Unit
    40  	principal1   *state.Unit
    41  	subordinate0 *state.Unit
    42  
    43  	resources *common.Resources
    44  	deployer  *deployer.DeployerAPI
    45  }
    46  
    47  var _ = gc.Suite(&deployerSuite{})
    48  
    49  func (s *deployerSuite) SetUpTest(c *gc.C) {
    50  	s.JujuConnSuite.SetUpTest(c)
    51  
    52  	// The two known machines now contain the following units:
    53  	// machine 0 (not authorized): mysql/1 (principal1)
    54  	// machine 1 (authorized): mysql/0 (principal0), logging/0 (subordinate0)
    55  
    56  	var err error
    57  	s.machine0, err = s.State.AddMachine("quantal", state.JobManageEnviron, state.JobHostUnits)
    58  	c.Assert(err, gc.IsNil)
    59  
    60  	s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits)
    61  	c.Assert(err, gc.IsNil)
    62  
    63  	s.service0 = s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
    64  
    65  	s.service1 = s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
    66  	eps, err := s.State.InferEndpoints([]string{"mysql", "logging"})
    67  	c.Assert(err, gc.IsNil)
    68  	rel, err := s.State.AddRelation(eps...)
    69  	c.Assert(err, gc.IsNil)
    70  
    71  	s.principal0, err = s.service0.AddUnit()
    72  	c.Assert(err, gc.IsNil)
    73  	err = s.principal0.AssignToMachine(s.machine1)
    74  	c.Assert(err, gc.IsNil)
    75  
    76  	s.principal1, err = s.service0.AddUnit()
    77  	c.Assert(err, gc.IsNil)
    78  	err = s.principal1.AssignToMachine(s.machine0)
    79  	c.Assert(err, gc.IsNil)
    80  
    81  	relUnit0, err := rel.Unit(s.principal0)
    82  	c.Assert(err, gc.IsNil)
    83  	err = relUnit0.EnterScope(nil)
    84  	c.Assert(err, gc.IsNil)
    85  	s.subordinate0, err = s.service1.Unit("logging/0")
    86  	c.Assert(err, gc.IsNil)
    87  
    88  	// Create a FakeAuthorizer so we can check permissions,
    89  	// set up assuming machine 1 has logged in.
    90  	s.authorizer = apiservertesting.FakeAuthorizer{
    91  		Tag:          names.MachineTag(s.machine1.Id()),
    92  		LoggedIn:     true,
    93  		MachineAgent: true,
    94  	}
    95  
    96  	// Create the resource registry separately to track invocations to
    97  	// Register.
    98  	s.resources = common.NewResources()
    99  
   100  	// Create a deployer API for machine 1.
   101  	deployer, err := deployer.NewDeployerAPI(
   102  		s.State,
   103  		s.resources,
   104  		s.authorizer,
   105  	)
   106  	c.Assert(err, gc.IsNil)
   107  	s.deployer = deployer
   108  }
   109  
   110  func (s *deployerSuite) TestDeployerFailsWithNonMachineAgentUser(c *gc.C) {
   111  	anAuthorizer := s.authorizer
   112  	anAuthorizer.MachineAgent = false
   113  	aDeployer, err := deployer.NewDeployerAPI(s.State, s.resources, anAuthorizer)
   114  	c.Assert(err, gc.NotNil)
   115  	c.Assert(aDeployer, gc.IsNil)
   116  	c.Assert(err, gc.ErrorMatches, "permission denied")
   117  }
   118  
   119  func (s *deployerSuite) TestWatchUnits(c *gc.C) {
   120  	c.Assert(s.resources.Count(), gc.Equals, 0)
   121  
   122  	args := params.Entities{Entities: []params.Entity{
   123  		{Tag: "machine-1"},
   124  		{Tag: "machine-0"},
   125  		{Tag: "machine-42"},
   126  	}}
   127  	result, err := s.deployer.WatchUnits(args)
   128  	c.Assert(err, gc.IsNil)
   129  	sort.Strings(result.Results[0].Changes)
   130  	c.Assert(result, gc.DeepEquals, params.StringsWatchResults{
   131  		Results: []params.StringsWatchResult{
   132  			{Changes: []string{"logging/0", "mysql/0"}, StringsWatcherId: "1"},
   133  			{Error: apiservertesting.ErrUnauthorized},
   134  			{Error: apiservertesting.ErrUnauthorized},
   135  		},
   136  	})
   137  
   138  	// Verify the resource was registered and stop when done
   139  	c.Assert(s.resources.Count(), gc.Equals, 1)
   140  	c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1")
   141  	resource := s.resources.Get("1")
   142  	defer statetesting.AssertStop(c, resource)
   143  
   144  	// Check that the Watch has consumed the initial event ("returned" in
   145  	// the Watch call)
   146  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   147  	wc.AssertNoChange()
   148  }
   149  
   150  func (s *deployerSuite) TestSetPasswords(c *gc.C) {
   151  	args := params.EntityPasswords{
   152  		Changes: []params.EntityPassword{
   153  			{Tag: "unit-mysql-0", Password: "xxx-12345678901234567890"},
   154  			{Tag: "unit-mysql-1", Password: "yyy-12345678901234567890"},
   155  			{Tag: "unit-logging-0", Password: "zzz-12345678901234567890"},
   156  			{Tag: "unit-fake-42", Password: "abc-12345678901234567890"},
   157  		},
   158  	}
   159  	results, err := s.deployer.SetPasswords(args)
   160  	c.Assert(err, gc.IsNil)
   161  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   162  		Results: []params.ErrorResult{
   163  			{nil},
   164  			{apiservertesting.ErrUnauthorized},
   165  			{nil},
   166  			{apiservertesting.ErrUnauthorized},
   167  		},
   168  	})
   169  	err = s.principal0.Refresh()
   170  	c.Assert(err, gc.IsNil)
   171  	changed := s.principal0.PasswordValid("xxx-12345678901234567890")
   172  	c.Assert(changed, gc.Equals, true)
   173  	err = s.subordinate0.Refresh()
   174  	c.Assert(err, gc.IsNil)
   175  	changed = s.subordinate0.PasswordValid("zzz-12345678901234567890")
   176  	c.Assert(changed, gc.Equals, true)
   177  
   178  	// Remove the subordinate and make sure it's detected.
   179  	err = s.subordinate0.EnsureDead()
   180  	c.Assert(err, gc.IsNil)
   181  	err = s.subordinate0.Remove()
   182  	c.Assert(err, gc.IsNil)
   183  	err = s.subordinate0.Refresh()
   184  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   185  
   186  	results, err = s.deployer.SetPasswords(params.EntityPasswords{
   187  		Changes: []params.EntityPassword{
   188  			{Tag: "unit-logging-0", Password: "blah-12345678901234567890"},
   189  		},
   190  	})
   191  	c.Assert(err, gc.IsNil)
   192  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   193  		Results: []params.ErrorResult{
   194  			{apiservertesting.ErrUnauthorized},
   195  		},
   196  	})
   197  }
   198  
   199  func (s *deployerSuite) TestLife(c *gc.C) {
   200  	err := s.subordinate0.EnsureDead()
   201  	c.Assert(err, gc.IsNil)
   202  	err = s.subordinate0.Refresh()
   203  	c.Assert(err, gc.IsNil)
   204  	c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead)
   205  	err = s.principal0.Refresh()
   206  	c.Assert(err, gc.IsNil)
   207  	c.Assert(s.principal0.Life(), gc.Equals, state.Alive)
   208  
   209  	args := params.Entities{Entities: []params.Entity{
   210  		{Tag: "unit-mysql-0"},
   211  		{Tag: "unit-mysql-1"},
   212  		{Tag: "unit-logging-0"},
   213  		{Tag: "unit-fake-42"},
   214  	}}
   215  	result, err := s.deployer.Life(args)
   216  	c.Assert(err, gc.IsNil)
   217  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   218  		Results: []params.LifeResult{
   219  			{Life: "alive"},
   220  			{Error: apiservertesting.ErrUnauthorized},
   221  			{Life: "dead"},
   222  			{Error: apiservertesting.ErrUnauthorized},
   223  		},
   224  	})
   225  
   226  	// Remove the subordinate and make sure it's detected.
   227  	err = s.subordinate0.EnsureDead()
   228  	c.Assert(err, gc.IsNil)
   229  	err = s.subordinate0.Remove()
   230  	c.Assert(err, gc.IsNil)
   231  	err = s.subordinate0.Refresh()
   232  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   233  
   234  	result, err = s.deployer.Life(params.Entities{
   235  		Entities: []params.Entity{
   236  			{Tag: "unit-logging-0"},
   237  		},
   238  	})
   239  	c.Assert(err, gc.IsNil)
   240  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   241  		Results: []params.LifeResult{
   242  			{Error: apiservertesting.ErrUnauthorized},
   243  		},
   244  	})
   245  }
   246  
   247  func (s *deployerSuite) TestRemove(c *gc.C) {
   248  	c.Assert(s.principal0.Life(), gc.Equals, state.Alive)
   249  	c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive)
   250  
   251  	// Try removing alive units - should fail.
   252  	args := params.Entities{Entities: []params.Entity{
   253  		{Tag: "unit-mysql-0"},
   254  		{Tag: "unit-mysql-1"},
   255  		{Tag: "unit-logging-0"},
   256  		{Tag: "unit-fake-42"},
   257  	}}
   258  	result, err := s.deployer.Remove(args)
   259  	c.Assert(err, gc.IsNil)
   260  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   261  		Results: []params.ErrorResult{
   262  			{&params.Error{Message: `cannot remove entity "unit-mysql-0": still alive`}},
   263  			{apiservertesting.ErrUnauthorized},
   264  			{&params.Error{Message: `cannot remove entity "unit-logging-0": still alive`}},
   265  			{apiservertesting.ErrUnauthorized},
   266  		},
   267  	})
   268  
   269  	err = s.principal0.Refresh()
   270  	c.Assert(err, gc.IsNil)
   271  	c.Assert(s.principal0.Life(), gc.Equals, state.Alive)
   272  	err = s.subordinate0.Refresh()
   273  	c.Assert(err, gc.IsNil)
   274  	c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive)
   275  
   276  	// Now make the subordinate dead and try again.
   277  	err = s.subordinate0.EnsureDead()
   278  	c.Assert(err, gc.IsNil)
   279  	err = s.subordinate0.Refresh()
   280  	c.Assert(err, gc.IsNil)
   281  	c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead)
   282  
   283  	args = params.Entities{
   284  		Entities: []params.Entity{{Tag: "unit-logging-0"}},
   285  	}
   286  	result, err = s.deployer.Remove(args)
   287  	c.Assert(err, gc.IsNil)
   288  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   289  		Results: []params.ErrorResult{{nil}},
   290  	})
   291  
   292  	err = s.subordinate0.Refresh()
   293  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   294  
   295  	// Make sure the subordinate is detected as removed.
   296  	result, err = s.deployer.Remove(args)
   297  	c.Assert(err, gc.IsNil)
   298  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   299  		Results: []params.ErrorResult{{apiservertesting.ErrUnauthorized}},
   300  	})
   301  }
   302  
   303  func (s *deployerSuite) TestStateAddresses(c *gc.C) {
   304  	err := s.machine0.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
   305  	c.Assert(err, gc.IsNil)
   306  
   307  	addresses, err := s.State.Addresses()
   308  	c.Assert(err, gc.IsNil)
   309  
   310  	result, err := s.deployer.StateAddresses()
   311  	c.Assert(err, gc.IsNil)
   312  	c.Assert(result, gc.DeepEquals, params.StringsResult{
   313  		Result: addresses,
   314  	})
   315  }
   316  
   317  func (s *deployerSuite) TestAPIAddresses(c *gc.C) {
   318  	hostPorts := [][]instance.HostPort{{{
   319  		Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown),
   320  		Port:    1234,
   321  	}}}
   322  
   323  	err := s.State.SetAPIHostPorts(hostPorts)
   324  	c.Assert(err, gc.IsNil)
   325  
   326  	result, err := s.deployer.APIAddresses()
   327  	c.Assert(err, gc.IsNil)
   328  	c.Assert(result, gc.DeepEquals, params.StringsResult{
   329  		Result: []string{"0.1.2.3:1234"},
   330  	})
   331  }
   332  
   333  func (s *deployerSuite) TestCACert(c *gc.C) {
   334  	result := s.deployer.CACert()
   335  	c.Assert(result, gc.DeepEquals, params.BytesResult{
   336  		Result: []byte(s.State.CACert()),
   337  	})
   338  }