github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/provisioner/provisioner_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner_test
     5  
     6  import (
     7  	"fmt"
     8  	stdtesting "testing"
     9  
    10  	gc "launchpad.net/gocheck"
    11  
    12  	"launchpad.net/juju-core/constraints"
    13  	"launchpad.net/juju-core/errors"
    14  	"launchpad.net/juju-core/instance"
    15  	"launchpad.net/juju-core/juju/osenv"
    16  	"launchpad.net/juju-core/juju/testing"
    17  	"launchpad.net/juju-core/state"
    18  	"launchpad.net/juju-core/state/api/params"
    19  	"launchpad.net/juju-core/state/apiserver/common"
    20  	commontesting "launchpad.net/juju-core/state/apiserver/common/testing"
    21  	"launchpad.net/juju-core/state/apiserver/provisioner"
    22  	apiservertesting "launchpad.net/juju-core/state/apiserver/testing"
    23  	statetesting "launchpad.net/juju-core/state/testing"
    24  	coretesting "launchpad.net/juju-core/testing"
    25  	jc "launchpad.net/juju-core/testing/checkers"
    26  	"launchpad.net/juju-core/version"
    27  )
    28  
    29  func Test(t *stdtesting.T) {
    30  	coretesting.MgoTestPackage(t)
    31  }
    32  
    33  type provisionerSuite struct {
    34  	testing.JujuConnSuite
    35  
    36  	machines []*state.Machine
    37  
    38  	authorizer  apiservertesting.FakeAuthorizer
    39  	resources   *common.Resources
    40  	provisioner *provisioner.ProvisionerAPI
    41  }
    42  
    43  var _ = gc.Suite(&provisionerSuite{})
    44  
    45  func (s *provisionerSuite) SetUpTest(c *gc.C) {
    46  	s.setUpTest(c, false)
    47  }
    48  
    49  func (s *provisionerSuite) setUpTest(c *gc.C, withStateServer bool) {
    50  	s.JujuConnSuite.SetUpTest(c)
    51  
    52  	// Reset previous machines (if any) and create 3 machines
    53  	// for the tests, plus an optional state server machine.
    54  	s.machines = nil
    55  	// Note that the specific machine ids allocated are assumed
    56  	// to be numerically consecutive from zero.
    57  	if withStateServer {
    58  		s.machines = append(s.machines, testing.AddStateServerMachine(c, s.State))
    59  	}
    60  	for i := 0; i < 3; i++ {
    61  		machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
    62  		c.Check(err, gc.IsNil)
    63  		s.machines = append(s.machines, machine)
    64  	}
    65  
    66  	// Create a FakeAuthorizer so we can check permissions,
    67  	// set up assuming we logged in as the environment manager.
    68  	s.authorizer = apiservertesting.FakeAuthorizer{
    69  		LoggedIn:       true,
    70  		EnvironManager: true,
    71  	}
    72  
    73  	// Create the resource registry separately to track invocations to
    74  	// Register.
    75  	s.resources = common.NewResources()
    76  
    77  	// Create a provisioner API for the machine.
    78  	provisionerAPI, err := provisioner.NewProvisionerAPI(
    79  		s.State,
    80  		s.resources,
    81  		s.authorizer,
    82  	)
    83  	c.Assert(err, gc.IsNil)
    84  	s.provisioner = provisionerAPI
    85  }
    86  
    87  type withoutStateServerSuite struct {
    88  	provisionerSuite
    89  	*commontesting.EnvironWatcherTest
    90  }
    91  
    92  var _ = gc.Suite(&withoutStateServerSuite{})
    93  
    94  func (s *withoutStateServerSuite) SetUpTest(c *gc.C) {
    95  	s.setUpTest(c, false)
    96  	s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.provisioner, s.State, s.resources, commontesting.HasSecrets)
    97  }
    98  
    99  func (s *withoutStateServerSuite) TestProvisionerFailsWithNonMachineAgentNonManagerUser(c *gc.C) {
   100  	anAuthorizer := s.authorizer
   101  	anAuthorizer.MachineAgent = false
   102  	anAuthorizer.EnvironManager = true
   103  	// Works with an environment manager, which is not a machine agent.
   104  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   105  	c.Assert(err, gc.IsNil)
   106  	c.Assert(aProvisioner, gc.NotNil)
   107  
   108  	// But fails with neither a machine agent or an environment manager.
   109  	anAuthorizer.EnvironManager = false
   110  	aProvisioner, err = provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   111  	c.Assert(err, gc.NotNil)
   112  	c.Assert(aProvisioner, gc.IsNil)
   113  	c.Assert(err, gc.ErrorMatches, "permission denied")
   114  }
   115  
   116  func (s *withoutStateServerSuite) TestSetPasswords(c *gc.C) {
   117  	args := params.PasswordChanges{
   118  		Changes: []params.PasswordChange{
   119  			{Tag: s.machines[0].Tag(), Password: "xxx0-1234567890123457890"},
   120  			{Tag: s.machines[1].Tag(), Password: "xxx1-1234567890123457890"},
   121  			{Tag: s.machines[2].Tag(), Password: "xxx2-1234567890123457890"},
   122  			{Tag: "machine-42", Password: "foo"},
   123  			{Tag: "unit-foo-0", Password: "zzz"},
   124  			{Tag: "service-bar", Password: "abc"},
   125  		},
   126  	}
   127  	results, err := s.provisioner.SetPasswords(args)
   128  	c.Assert(err, gc.IsNil)
   129  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   130  		Results: []params.ErrorResult{
   131  			{nil},
   132  			{nil},
   133  			{nil},
   134  			{apiservertesting.NotFoundError("machine 42")},
   135  			{apiservertesting.ErrUnauthorized},
   136  			{apiservertesting.ErrUnauthorized},
   137  		},
   138  	})
   139  
   140  	// Verify the changes to both machines succeeded.
   141  	for i, machine := range s.machines {
   142  		c.Logf("trying %q password", machine.Tag())
   143  		err = machine.Refresh()
   144  		c.Assert(err, gc.IsNil)
   145  		changed := machine.PasswordValid(fmt.Sprintf("xxx%d-1234567890123457890", i))
   146  		c.Assert(changed, jc.IsTrue)
   147  	}
   148  }
   149  
   150  func (s *withoutStateServerSuite) TestShortSetPasswords(c *gc.C) {
   151  	args := params.PasswordChanges{
   152  		Changes: []params.PasswordChange{
   153  			{Tag: s.machines[1].Tag(), Password: "xxx1"},
   154  		},
   155  	}
   156  	results, err := s.provisioner.SetPasswords(args)
   157  	c.Assert(err, gc.IsNil)
   158  	c.Assert(results.Results, gc.HasLen, 1)
   159  	c.Assert(results.Results[0].Error, gc.ErrorMatches,
   160  		"password is only 4 bytes long, and is not a valid Agent password")
   161  }
   162  
   163  func (s *withoutStateServerSuite) TestLifeAsMachineAgent(c *gc.C) {
   164  	// NOTE: This and the next call serve to test the two
   165  	// different authorization schemes:
   166  	// 1. Machine agents can access their own machine and
   167  	// any container that has their own machine as parent;
   168  	// 2. Environment managers can access any machine without
   169  	// a parent.
   170  	// There's no need to repeat this test for each method,
   171  	// because the authorization logic is common.
   172  
   173  	// Login as a machine agent for machine 0.
   174  	anAuthorizer := s.authorizer
   175  	anAuthorizer.MachineAgent = true
   176  	anAuthorizer.EnvironManager = false
   177  	anAuthorizer.Tag = s.machines[0].Tag()
   178  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   179  	c.Assert(err, gc.IsNil)
   180  	c.Assert(aProvisioner, gc.NotNil)
   181  
   182  	// Make the machine dead before trying to add containers.
   183  	err = s.machines[0].EnsureDead()
   184  	c.Assert(err, gc.IsNil)
   185  
   186  	// Create some containers to work on.
   187  	template := state.MachineTemplate{
   188  		Series: "quantal",
   189  		Jobs:   []state.MachineJob{state.JobHostUnits},
   190  	}
   191  	var containers []*state.Machine
   192  	for i := 0; i < 3; i++ {
   193  		container, err := s.State.AddMachineInsideMachine(template, s.machines[0].Id(), instance.LXC)
   194  		c.Check(err, gc.IsNil)
   195  		containers = append(containers, container)
   196  	}
   197  	// Make one container dead.
   198  	err = containers[1].EnsureDead()
   199  	c.Assert(err, gc.IsNil)
   200  
   201  	args := params.Entities{Entities: []params.Entity{
   202  		{Tag: s.machines[0].Tag()},
   203  		{Tag: s.machines[1].Tag()},
   204  		{Tag: containers[0].Tag()},
   205  		{Tag: containers[1].Tag()},
   206  		{Tag: containers[2].Tag()},
   207  		{Tag: "machine-42"},
   208  		{Tag: "unit-foo-0"},
   209  		{Tag: "service-bar"},
   210  	}}
   211  	result, err := aProvisioner.Life(args)
   212  	c.Assert(err, gc.IsNil)
   213  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   214  		Results: []params.LifeResult{
   215  			{Life: "dead"},
   216  			{Error: apiservertesting.ErrUnauthorized},
   217  			{Life: "alive"},
   218  			{Life: "dead"},
   219  			{Life: "alive"},
   220  			{Error: apiservertesting.ErrUnauthorized},
   221  			{Error: apiservertesting.ErrUnauthorized},
   222  			{Error: apiservertesting.ErrUnauthorized},
   223  		},
   224  	})
   225  }
   226  
   227  func (s *withoutStateServerSuite) TestLifeAsEnvironManager(c *gc.C) {
   228  	err := s.machines[1].EnsureDead()
   229  	c.Assert(err, gc.IsNil)
   230  	err = s.machines[1].Refresh()
   231  	c.Assert(err, gc.IsNil)
   232  	c.Assert(s.machines[0].Life(), gc.Equals, state.Alive)
   233  	c.Assert(s.machines[1].Life(), gc.Equals, state.Dead)
   234  	c.Assert(s.machines[2].Life(), gc.Equals, state.Alive)
   235  
   236  	args := params.Entities{Entities: []params.Entity{
   237  		{Tag: s.machines[0].Tag()},
   238  		{Tag: s.machines[1].Tag()},
   239  		{Tag: s.machines[2].Tag()},
   240  		{Tag: "machine-42"},
   241  		{Tag: "unit-foo-0"},
   242  		{Tag: "service-bar"},
   243  	}}
   244  	result, err := s.provisioner.Life(args)
   245  	c.Assert(err, gc.IsNil)
   246  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   247  		Results: []params.LifeResult{
   248  			{Life: "alive"},
   249  			{Life: "dead"},
   250  			{Life: "alive"},
   251  			{Error: apiservertesting.NotFoundError("machine 42")},
   252  			{Error: apiservertesting.ErrUnauthorized},
   253  			{Error: apiservertesting.ErrUnauthorized},
   254  		},
   255  	})
   256  
   257  	// Remove the subordinate and make sure it's detected.
   258  	err = s.machines[1].Remove()
   259  	c.Assert(err, gc.IsNil)
   260  	err = s.machines[1].Refresh()
   261  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   262  
   263  	result, err = s.provisioner.Life(params.Entities{
   264  		Entities: []params.Entity{
   265  			{Tag: s.machines[1].Tag()},
   266  		},
   267  	})
   268  	c.Assert(err, gc.IsNil)
   269  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   270  		Results: []params.LifeResult{
   271  			{Error: apiservertesting.NotFoundError("machine 1")},
   272  		},
   273  	})
   274  }
   275  
   276  func (s *withoutStateServerSuite) TestRemove(c *gc.C) {
   277  	err := s.machines[1].EnsureDead()
   278  	c.Assert(err, gc.IsNil)
   279  	s.assertLife(c, 0, state.Alive)
   280  	s.assertLife(c, 1, state.Dead)
   281  	s.assertLife(c, 2, state.Alive)
   282  
   283  	args := params.Entities{Entities: []params.Entity{
   284  		{Tag: s.machines[0].Tag()},
   285  		{Tag: s.machines[1].Tag()},
   286  		{Tag: s.machines[2].Tag()},
   287  		{Tag: "machine-42"},
   288  		{Tag: "unit-foo-0"},
   289  		{Tag: "service-bar"},
   290  	}}
   291  	result, err := s.provisioner.Remove(args)
   292  	c.Assert(err, gc.IsNil)
   293  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   294  		Results: []params.ErrorResult{
   295  			{&params.Error{Message: `cannot remove entity "machine-0": still alive`}},
   296  			{nil},
   297  			{&params.Error{Message: `cannot remove entity "machine-2": still alive`}},
   298  			{apiservertesting.NotFoundError("machine 42")},
   299  			{apiservertesting.ErrUnauthorized},
   300  			{apiservertesting.ErrUnauthorized},
   301  		},
   302  	})
   303  
   304  	// Verify the changes.
   305  	s.assertLife(c, 0, state.Alive)
   306  	err = s.machines[1].Refresh()
   307  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   308  	s.assertLife(c, 2, state.Alive)
   309  }
   310  
   311  func (s *withoutStateServerSuite) TestSetStatus(c *gc.C) {
   312  	err := s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   313  	c.Assert(err, gc.IsNil)
   314  	err = s.machines[1].SetStatus(params.StatusStopped, "foo", nil)
   315  	c.Assert(err, gc.IsNil)
   316  	err = s.machines[2].SetStatus(params.StatusError, "not really", nil)
   317  	c.Assert(err, gc.IsNil)
   318  
   319  	args := params.SetStatus{
   320  		Entities: []params.SetEntityStatus{
   321  			{Tag: s.machines[0].Tag(), Status: params.StatusError, Info: "not really"},
   322  			{Tag: s.machines[1].Tag(), Status: params.StatusStopped, Info: "foobar"},
   323  			{Tag: s.machines[2].Tag(), Status: params.StatusStarted, Info: "again"},
   324  			{Tag: "machine-42", Status: params.StatusStarted, Info: "blah"},
   325  			{Tag: "unit-foo-0", Status: params.StatusStopped, Info: "foobar"},
   326  			{Tag: "service-bar", Status: params.StatusStopped, Info: "foobar"},
   327  		}}
   328  	result, err := s.provisioner.SetStatus(args)
   329  	c.Assert(err, gc.IsNil)
   330  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   331  		Results: []params.ErrorResult{
   332  			{nil},
   333  			{nil},
   334  			{nil},
   335  			{apiservertesting.NotFoundError("machine 42")},
   336  			{apiservertesting.ErrUnauthorized},
   337  			{apiservertesting.ErrUnauthorized},
   338  		},
   339  	})
   340  
   341  	// Verify the changes.
   342  	s.assertStatus(c, 0, params.StatusError, "not really")
   343  	s.assertStatus(c, 1, params.StatusStopped, "foobar")
   344  	s.assertStatus(c, 2, params.StatusStarted, "again")
   345  }
   346  
   347  func (s *withoutStateServerSuite) TestEnsureDead(c *gc.C) {
   348  	err := s.machines[1].EnsureDead()
   349  	c.Assert(err, gc.IsNil)
   350  	s.assertLife(c, 0, state.Alive)
   351  	s.assertLife(c, 1, state.Dead)
   352  	s.assertLife(c, 2, state.Alive)
   353  
   354  	args := params.Entities{Entities: []params.Entity{
   355  		{Tag: s.machines[0].Tag()},
   356  		{Tag: s.machines[1].Tag()},
   357  		{Tag: s.machines[2].Tag()},
   358  		{Tag: "machine-42"},
   359  		{Tag: "unit-foo-0"},
   360  		{Tag: "service-bar"},
   361  	}}
   362  	result, err := s.provisioner.EnsureDead(args)
   363  	c.Assert(err, gc.IsNil)
   364  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   365  		Results: []params.ErrorResult{
   366  			{nil},
   367  			{nil},
   368  			{nil},
   369  			{apiservertesting.NotFoundError("machine 42")},
   370  			{apiservertesting.ErrUnauthorized},
   371  			{apiservertesting.ErrUnauthorized},
   372  		},
   373  	})
   374  
   375  	// Verify the changes.
   376  	s.assertLife(c, 0, state.Dead)
   377  	s.assertLife(c, 1, state.Dead)
   378  	s.assertLife(c, 2, state.Dead)
   379  }
   380  
   381  func (s *withoutStateServerSuite) assertLife(c *gc.C, index int, expectLife state.Life) {
   382  	err := s.machines[index].Refresh()
   383  	c.Assert(err, gc.IsNil)
   384  	c.Assert(s.machines[index].Life(), gc.Equals, expectLife)
   385  }
   386  
   387  func (s *withoutStateServerSuite) assertStatus(c *gc.C, index int, expectStatus params.Status, expectInfo string) {
   388  	status, info, _, err := s.machines[index].Status()
   389  	c.Assert(err, gc.IsNil)
   390  	c.Assert(status, gc.Equals, expectStatus)
   391  	c.Assert(info, gc.Equals, expectInfo)
   392  }
   393  
   394  func (s *withoutStateServerSuite) TestWatchContainers(c *gc.C) {
   395  	c.Assert(s.resources.Count(), gc.Equals, 0)
   396  
   397  	args := params.WatchContainers{Params: []params.WatchContainer{
   398  		{MachineTag: s.machines[0].Tag(), ContainerType: string(instance.LXC)},
   399  		{MachineTag: s.machines[1].Tag(), ContainerType: string(instance.KVM)},
   400  		{MachineTag: "machine-42", ContainerType: ""},
   401  		{MachineTag: "unit-foo-0", ContainerType: ""},
   402  		{MachineTag: "service-bar", ContainerType: ""},
   403  	}}
   404  	result, err := s.provisioner.WatchContainers(args)
   405  	c.Assert(err, gc.IsNil)
   406  	c.Assert(result, gc.DeepEquals, params.StringsWatchResults{
   407  		Results: []params.StringsWatchResult{
   408  			{StringsWatcherId: "1", Changes: []string{}},
   409  			{StringsWatcherId: "2", Changes: []string{}},
   410  			{Error: apiservertesting.NotFoundError("machine 42")},
   411  			{Error: apiservertesting.ErrUnauthorized},
   412  			{Error: apiservertesting.ErrUnauthorized},
   413  		},
   414  	})
   415  
   416  	// Verify the resources were registered and stop them when done.
   417  	c.Assert(s.resources.Count(), gc.Equals, 2)
   418  	m0Watcher := s.resources.Get("1")
   419  	defer statetesting.AssertStop(c, m0Watcher)
   420  	m1Watcher := s.resources.Get("2")
   421  	defer statetesting.AssertStop(c, m1Watcher)
   422  
   423  	// Check that the Watch has consumed the initial event ("returned"
   424  	// in the Watch call)
   425  	wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher))
   426  	wc0.AssertNoChange()
   427  	wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher))
   428  	wc1.AssertNoChange()
   429  }
   430  
   431  func (s *withoutStateServerSuite) TestWatchAllContainers(c *gc.C) {
   432  	c.Assert(s.resources.Count(), gc.Equals, 0)
   433  
   434  	args := params.WatchContainers{Params: []params.WatchContainer{
   435  		{MachineTag: s.machines[0].Tag()},
   436  		{MachineTag: s.machines[1].Tag()},
   437  		{MachineTag: "machine-42"},
   438  		{MachineTag: "unit-foo-0"},
   439  		{MachineTag: "service-bar"},
   440  	}}
   441  	result, err := s.provisioner.WatchAllContainers(args)
   442  	c.Assert(err, gc.IsNil)
   443  	c.Assert(result, gc.DeepEquals, params.StringsWatchResults{
   444  		Results: []params.StringsWatchResult{
   445  			{StringsWatcherId: "1", Changes: []string{}},
   446  			{StringsWatcherId: "2", Changes: []string{}},
   447  			{Error: apiservertesting.NotFoundError("machine 42")},
   448  			{Error: apiservertesting.ErrUnauthorized},
   449  			{Error: apiservertesting.ErrUnauthorized},
   450  		},
   451  	})
   452  
   453  	// Verify the resources were registered and stop them when done.
   454  	c.Assert(s.resources.Count(), gc.Equals, 2)
   455  	m0Watcher := s.resources.Get("1")
   456  	defer statetesting.AssertStop(c, m0Watcher)
   457  	m1Watcher := s.resources.Get("2")
   458  	defer statetesting.AssertStop(c, m1Watcher)
   459  
   460  	// Check that the Watch has consumed the initial event ("returned"
   461  	// in the Watch call)
   462  	wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher))
   463  	wc0.AssertNoChange()
   464  	wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher))
   465  	wc1.AssertNoChange()
   466  }
   467  
   468  func (s *withoutStateServerSuite) TestEnvironConfigNonManager(c *gc.C) {
   469  	// Now test it with a non-environment manager and make sure
   470  	// the secret attributes are masked.
   471  	anAuthorizer := s.authorizer
   472  	anAuthorizer.MachineAgent = true
   473  	anAuthorizer.EnvironManager = false
   474  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources,
   475  		anAuthorizer)
   476  	c.Assert(err, gc.IsNil)
   477  	s.AssertEnvironConfig(c, aProvisioner, commontesting.NoSecrets)
   478  }
   479  
   480  func (s *withoutStateServerSuite) TestStatus(c *gc.C) {
   481  	err := s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   482  	c.Assert(err, gc.IsNil)
   483  	err = s.machines[1].SetStatus(params.StatusStopped, "foo", nil)
   484  	c.Assert(err, gc.IsNil)
   485  	err = s.machines[2].SetStatus(params.StatusError, "not really", nil)
   486  	c.Assert(err, gc.IsNil)
   487  
   488  	args := params.Entities{Entities: []params.Entity{
   489  		{Tag: s.machines[0].Tag()},
   490  		{Tag: s.machines[1].Tag()},
   491  		{Tag: s.machines[2].Tag()},
   492  		{Tag: "machine-42"},
   493  		{Tag: "unit-foo-0"},
   494  		{Tag: "service-bar"},
   495  	}}
   496  	result, err := s.provisioner.Status(args)
   497  	c.Assert(err, gc.IsNil)
   498  	c.Assert(result, gc.DeepEquals, params.StatusResults{
   499  		Results: []params.StatusResult{
   500  			{Status: params.StatusStarted, Info: "blah"},
   501  			{Status: params.StatusStopped, Info: "foo"},
   502  			{Status: params.StatusError, Info: "not really"},
   503  			{Error: apiservertesting.NotFoundError("machine 42")},
   504  			{Error: apiservertesting.ErrUnauthorized},
   505  			{Error: apiservertesting.ErrUnauthorized},
   506  		},
   507  	})
   508  }
   509  
   510  func (s *withoutStateServerSuite) TestSeries(c *gc.C) {
   511  	// Add a machine with different series.
   512  	foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits)
   513  	c.Assert(err, gc.IsNil)
   514  
   515  	args := params.Entities{Entities: []params.Entity{
   516  		{Tag: s.machines[0].Tag()},
   517  		{Tag: foobarMachine.Tag()},
   518  		{Tag: s.machines[2].Tag()},
   519  		{Tag: "machine-42"},
   520  		{Tag: "unit-foo-0"},
   521  		{Tag: "service-bar"},
   522  	}}
   523  	result, err := s.provisioner.Series(args)
   524  	c.Assert(err, gc.IsNil)
   525  	c.Assert(result, gc.DeepEquals, params.StringResults{
   526  		Results: []params.StringResult{
   527  			{Result: s.machines[0].Series()},
   528  			{Result: foobarMachine.Series()},
   529  			{Result: s.machines[2].Series()},
   530  			{Error: apiservertesting.NotFoundError("machine 42")},
   531  			{Error: apiservertesting.ErrUnauthorized},
   532  			{Error: apiservertesting.ErrUnauthorized},
   533  		},
   534  	})
   535  }
   536  
   537  func (s *withoutStateServerSuite) TestConstraints(c *gc.C) {
   538  	// Add a machine with some constraints.
   539  	template := state.MachineTemplate{
   540  		Series:      "quantal",
   541  		Jobs:        []state.MachineJob{state.JobHostUnits},
   542  		Constraints: constraints.MustParse("cpu-cores=123", "mem=8G"),
   543  	}
   544  	consMachine, err := s.State.AddOneMachine(template)
   545  	c.Assert(err, gc.IsNil)
   546  
   547  	machine0Constraints, err := s.machines[0].Constraints()
   548  	c.Assert(err, gc.IsNil)
   549  
   550  	args := params.Entities{Entities: []params.Entity{
   551  		{Tag: s.machines[0].Tag()},
   552  		{Tag: consMachine.Tag()},
   553  		{Tag: "machine-42"},
   554  		{Tag: "unit-foo-0"},
   555  		{Tag: "service-bar"},
   556  	}}
   557  	result, err := s.provisioner.Constraints(args)
   558  	c.Assert(err, gc.IsNil)
   559  	c.Assert(result, gc.DeepEquals, params.ConstraintsResults{
   560  		Results: []params.ConstraintsResult{
   561  			{Constraints: machine0Constraints},
   562  			{Constraints: template.Constraints},
   563  			{Error: apiservertesting.NotFoundError("machine 42")},
   564  			{Error: apiservertesting.ErrUnauthorized},
   565  			{Error: apiservertesting.ErrUnauthorized},
   566  		},
   567  	})
   568  }
   569  
   570  func (s *withoutStateServerSuite) TestSetProvisioned(c *gc.C) {
   571  	// Provision machine 0 first.
   572  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   573  	err := s.machines[0].SetProvisioned("i-am", "fake_nonce", &hwChars)
   574  	c.Assert(err, gc.IsNil)
   575  
   576  	args := params.SetProvisioned{Machines: []params.MachineSetProvisioned{
   577  		{Tag: s.machines[0].Tag(), InstanceId: "i-was", Nonce: "fake_nonce", Characteristics: nil},
   578  		{Tag: s.machines[1].Tag(), InstanceId: "i-will", Nonce: "fake_nonce", Characteristics: &hwChars},
   579  		{Tag: s.machines[2].Tag(), InstanceId: "i-am-too", Nonce: "fake", Characteristics: nil},
   580  		{Tag: "machine-42", InstanceId: "", Nonce: "", Characteristics: nil},
   581  		{Tag: "unit-foo-0", InstanceId: "", Nonce: "", Characteristics: nil},
   582  		{Tag: "service-bar", InstanceId: "", Nonce: "", Characteristics: nil},
   583  	}}
   584  	result, err := s.provisioner.SetProvisioned(args)
   585  	c.Assert(err, gc.IsNil)
   586  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   587  		Results: []params.ErrorResult{
   588  			{&params.Error{
   589  				Message: `cannot set instance data for machine "0": already set`,
   590  			}},
   591  			{nil},
   592  			{nil},
   593  			{apiservertesting.NotFoundError("machine 42")},
   594  			{apiservertesting.ErrUnauthorized},
   595  			{apiservertesting.ErrUnauthorized},
   596  		},
   597  	})
   598  
   599  	// Verify machine 1 and 2 were provisioned.
   600  	c.Assert(s.machines[1].Refresh(), gc.IsNil)
   601  	c.Assert(s.machines[2].Refresh(), gc.IsNil)
   602  
   603  	instanceId, err := s.machines[1].InstanceId()
   604  	c.Assert(err, gc.IsNil)
   605  	c.Check(instanceId, gc.Equals, instance.Id("i-will"))
   606  	instanceId, err = s.machines[2].InstanceId()
   607  	c.Assert(err, gc.IsNil)
   608  	c.Check(instanceId, gc.Equals, instance.Id("i-am-too"))
   609  	c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue)
   610  	c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue)
   611  	gotHardware, err := s.machines[1].HardwareCharacteristics()
   612  	c.Assert(err, gc.IsNil)
   613  	c.Check(gotHardware, gc.DeepEquals, &hwChars)
   614  }
   615  
   616  func (s *withoutStateServerSuite) TestInstanceId(c *gc.C) {
   617  	// Provision 2 machines first.
   618  	err := s.machines[0].SetProvisioned("i-am", "fake_nonce", nil)
   619  	c.Assert(err, gc.IsNil)
   620  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   621  	err = s.machines[1].SetProvisioned("i-am-not", "fake_nonce", &hwChars)
   622  	c.Assert(err, gc.IsNil)
   623  
   624  	args := params.Entities{Entities: []params.Entity{
   625  		{Tag: s.machines[0].Tag()},
   626  		{Tag: s.machines[1].Tag()},
   627  		{Tag: s.machines[2].Tag()},
   628  		{Tag: "machine-42"},
   629  		{Tag: "unit-foo-0"},
   630  		{Tag: "service-bar"},
   631  	}}
   632  	result, err := s.provisioner.InstanceId(args)
   633  	c.Assert(err, gc.IsNil)
   634  	c.Assert(result, gc.DeepEquals, params.StringResults{
   635  		Results: []params.StringResult{
   636  			{Result: "i-am"},
   637  			{Result: "i-am-not"},
   638  			{Error: apiservertesting.NotProvisionedError("2")},
   639  			{Error: apiservertesting.NotFoundError("machine 42")},
   640  			{Error: apiservertesting.ErrUnauthorized},
   641  			{Error: apiservertesting.ErrUnauthorized},
   642  		},
   643  	})
   644  }
   645  
   646  func (s *withoutStateServerSuite) TestWatchEnvironMachines(c *gc.C) {
   647  	c.Assert(s.resources.Count(), gc.Equals, 0)
   648  
   649  	result, err := s.provisioner.WatchEnvironMachines()
   650  	c.Assert(err, gc.IsNil)
   651  	c.Assert(result, gc.DeepEquals, params.StringsWatchResult{
   652  		StringsWatcherId: "1",
   653  		Changes:          []string{"0", "1", "2"},
   654  	})
   655  
   656  	// Verify the resources were registered and stop them when done.
   657  	c.Assert(s.resources.Count(), gc.Equals, 1)
   658  	resource := s.resources.Get("1")
   659  	defer statetesting.AssertStop(c, resource)
   660  
   661  	// Check that the Watch has consumed the initial event ("returned"
   662  	// in the Watch call)
   663  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   664  	wc.AssertNoChange()
   665  
   666  	// Make sure WatchEnvironMachines fails with a machine agent login.
   667  	anAuthorizer := s.authorizer
   668  	anAuthorizer.MachineAgent = true
   669  	anAuthorizer.EnvironManager = false
   670  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   671  	c.Assert(err, gc.IsNil)
   672  
   673  	result, err = aProvisioner.WatchEnvironMachines()
   674  	c.Assert(err, gc.ErrorMatches, "permission denied")
   675  	c.Assert(result, gc.DeepEquals, params.StringsWatchResult{})
   676  }
   677  
   678  func (s *withoutStateServerSuite) TestToolsNothing(c *gc.C) {
   679  	// Not an error to watch nothing
   680  	results, err := s.provisioner.Tools(params.Entities{})
   681  	c.Assert(err, gc.IsNil)
   682  	c.Check(results.Results, gc.HasLen, 0)
   683  }
   684  
   685  func (s *withoutStateServerSuite) TestContainerConfig(c *gc.C) {
   686  	cfg, err := s.State.EnvironConfig()
   687  	c.Assert(err, gc.IsNil)
   688  	newCfg, err := cfg.Apply(map[string]interface{}{
   689  		"http-proxy": "http://proxy.example.com:9000",
   690  	})
   691  	c.Assert(err, gc.IsNil)
   692  	err = s.State.SetEnvironConfig(newCfg, cfg)
   693  	c.Assert(err, gc.IsNil)
   694  	expectedProxy := osenv.ProxySettings{
   695  		Http: "http://proxy.example.com:9000",
   696  	}
   697  
   698  	results, err := s.provisioner.ContainerConfig()
   699  	c.Check(err, gc.IsNil)
   700  	c.Check(results.ProviderType, gc.Equals, "dummy")
   701  	c.Check(results.AuthorizedKeys, gc.Equals, coretesting.FakeAuthKeys)
   702  	c.Check(results.SSLHostnameVerification, jc.IsTrue)
   703  	c.Check(results.Proxy, gc.DeepEquals, expectedProxy)
   704  	c.Check(results.AptProxy, gc.DeepEquals, expectedProxy)
   705  }
   706  
   707  func (s *withoutStateServerSuite) TestToolsRefusesWrongAgent(c *gc.C) {
   708  	anAuthorizer := s.authorizer
   709  	anAuthorizer.Tag = "machine-12354"
   710  	anAuthorizer.EnvironManager = false
   711  	anAuthorizer.MachineAgent = true
   712  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   713  	c.Check(err, gc.IsNil)
   714  	args := params.Entities{
   715  		Entities: []params.Entity{{Tag: s.machines[0].Tag()}},
   716  	}
   717  	results, err := aProvisioner.Tools(args)
   718  	// It is not an error to make the request, but the specific item is rejected
   719  	c.Assert(err, gc.IsNil)
   720  	c.Check(results.Results, gc.HasLen, 1)
   721  	toolResult := results.Results[0]
   722  	c.Assert(toolResult.Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
   723  }
   724  
   725  func (s *withoutStateServerSuite) TestToolsForAgent(c *gc.C) {
   726  	cur := version.Current
   727  	agent := params.Entity{Tag: s.machines[0].Tag()}
   728  
   729  	// The machine must have its existing tools set before we query for the
   730  	// next tools. This is so that we can grab Arch and Series without
   731  	// having to pass it in again
   732  	err := s.machines[0].SetAgentVersion(version.Current)
   733  	c.Assert(err, gc.IsNil)
   734  
   735  	args := params.Entities{Entities: []params.Entity{agent}}
   736  	results, err := s.provisioner.Tools(args)
   737  	c.Assert(err, gc.IsNil)
   738  	c.Check(results.Results, gc.HasLen, 1)
   739  	c.Assert(results.Results[0].Error, gc.IsNil)
   740  	agentTools := results.Results[0].Tools
   741  	c.Check(agentTools.URL, gc.Not(gc.Equals), "")
   742  	c.Check(agentTools.Version, gc.DeepEquals, cur)
   743  }
   744  
   745  func (s *withoutStateServerSuite) TestSetSupportedContainers(c *gc.C) {
   746  	args := params.MachineContainersParams{
   747  		Params: []params.MachineContainers{
   748  			{
   749  				MachineTag:     "machine-0",
   750  				ContainerTypes: []instance.ContainerType{instance.LXC},
   751  			},
   752  			{
   753  				MachineTag:     "machine-1",
   754  				ContainerTypes: []instance.ContainerType{instance.LXC, instance.KVM},
   755  			},
   756  		},
   757  	}
   758  	results, err := s.provisioner.SetSupportedContainers(args)
   759  	c.Assert(err, gc.IsNil)
   760  	c.Assert(results.Results, gc.HasLen, 2)
   761  	for _, result := range results.Results {
   762  		c.Assert(result.Error, gc.IsNil)
   763  	}
   764  	m0, err := s.State.Machine("0")
   765  	c.Assert(err, gc.IsNil)
   766  	containers, ok := m0.SupportedContainers()
   767  	c.Assert(ok, jc.IsTrue)
   768  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC})
   769  	m1, err := s.State.Machine("1")
   770  	c.Assert(err, gc.IsNil)
   771  	containers, ok = m1.SupportedContainers()
   772  	c.Assert(ok, jc.IsTrue)
   773  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM})
   774  }
   775  
   776  func (s *withoutStateServerSuite) TestSetSupportedContainersPermissions(c *gc.C) {
   777  	// Login as a machine agent for machine 0.
   778  	anAuthorizer := s.authorizer
   779  	anAuthorizer.MachineAgent = true
   780  	anAuthorizer.EnvironManager = false
   781  	anAuthorizer.Tag = s.machines[0].Tag()
   782  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   783  	c.Assert(err, gc.IsNil)
   784  	c.Assert(aProvisioner, gc.NotNil)
   785  
   786  	args := params.MachineContainersParams{
   787  		Params: []params.MachineContainers{{
   788  			MachineTag:     "machine-0",
   789  			ContainerTypes: []instance.ContainerType{instance.LXC},
   790  		}, {
   791  			MachineTag:     "machine-1",
   792  			ContainerTypes: []instance.ContainerType{instance.LXC},
   793  		}, {
   794  			MachineTag:     "machine-42",
   795  			ContainerTypes: []instance.ContainerType{instance.LXC},
   796  		},
   797  		},
   798  	}
   799  	// Only machine 0 can have it's containers updated.
   800  	results, err := aProvisioner.SetSupportedContainers(args)
   801  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   802  		Results: []params.ErrorResult{
   803  			{Error: nil},
   804  			{Error: apiservertesting.ErrUnauthorized},
   805  			{Error: apiservertesting.ErrUnauthorized},
   806  		},
   807  	})
   808  }
   809  
   810  func (s *withoutStateServerSuite) TestSupportsNoContainers(c *gc.C) {
   811  	args := params.MachineContainersParams{
   812  		Params: []params.MachineContainers{
   813  			{
   814  				MachineTag: "machine-0",
   815  			},
   816  		},
   817  	}
   818  	results, err := s.provisioner.SetSupportedContainers(args)
   819  	c.Assert(err, gc.IsNil)
   820  	c.Assert(results.Results, gc.HasLen, 1)
   821  	c.Assert(results.Results[0].Error, gc.IsNil)
   822  	m0, err := s.State.Machine("0")
   823  	c.Assert(err, gc.IsNil)
   824  	containers, ok := m0.SupportedContainers()
   825  	c.Assert(ok, jc.IsTrue)
   826  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{})
   827  }
   828  
   829  var _ = gc.Suite(&withStateServerSuite{})
   830  
   831  type withStateServerSuite struct {
   832  	provisionerSuite
   833  }
   834  
   835  func (s *withStateServerSuite) SetUpTest(c *gc.C) {
   836  	s.provisionerSuite.setUpTest(c, true)
   837  }
   838  
   839  func (s *withStateServerSuite) TestAPIAddresses(c *gc.C) {
   840  	addrs, err := s.State.APIAddresses()
   841  	c.Assert(err, gc.IsNil)
   842  
   843  	result, err := s.provisioner.APIAddresses()
   844  	c.Assert(err, gc.IsNil)
   845  	c.Assert(result, gc.DeepEquals, params.StringsResult{
   846  		Result: addrs,
   847  	})
   848  }
   849  
   850  func (s *withStateServerSuite) TestStateAddresses(c *gc.C) {
   851  	addresses, err := s.State.Addresses()
   852  	c.Assert(err, gc.IsNil)
   853  
   854  	result, err := s.provisioner.StateAddresses()
   855  	c.Assert(err, gc.IsNil)
   856  	c.Assert(result, gc.DeepEquals, params.StringsResult{
   857  		Result: addresses,
   858  	})
   859  }
   860  
   861  func (s *withStateServerSuite) TestCACert(c *gc.C) {
   862  	result := s.provisioner.CACert()
   863  	c.Assert(result, gc.DeepEquals, params.BytesResult{
   864  		Result: s.State.CACert(),
   865  	})
   866  }