github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils/proxy"
    14  	gc "launchpad.net/gocheck"
    15  
    16  	"github.com/juju/juju/constraints"
    17  	"github.com/juju/juju/container"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/state"
    21  	"github.com/juju/juju/state/api/params"
    22  	"github.com/juju/juju/state/apiserver/common"
    23  	commontesting "github.com/juju/juju/state/apiserver/common/testing"
    24  	"github.com/juju/juju/state/apiserver/provisioner"
    25  	apiservertesting "github.com/juju/juju/state/apiserver/testing"
    26  	statetesting "github.com/juju/juju/state/testing"
    27  	coretesting "github.com/juju/juju/testing"
    28  	"github.com/juju/juju/version"
    29  )
    30  
    31  func Test(t *stdtesting.T) {
    32  	coretesting.MgoTestPackage(t)
    33  }
    34  
    35  type provisionerSuite struct {
    36  	testing.JujuConnSuite
    37  
    38  	machines []*state.Machine
    39  
    40  	authorizer  apiservertesting.FakeAuthorizer
    41  	resources   *common.Resources
    42  	provisioner *provisioner.ProvisionerAPI
    43  }
    44  
    45  var _ = gc.Suite(&provisionerSuite{})
    46  
    47  func (s *provisionerSuite) SetUpTest(c *gc.C) {
    48  	s.setUpTest(c, false)
    49  }
    50  
    51  func (s *provisionerSuite) setUpTest(c *gc.C, withStateServer bool) {
    52  	s.JujuConnSuite.SetUpTest(c)
    53  
    54  	// Reset previous machines (if any) and create 3 machines
    55  	// for the tests, plus an optional state server machine.
    56  	s.machines = nil
    57  	// Note that the specific machine ids allocated are assumed
    58  	// to be numerically consecutive from zero.
    59  	if withStateServer {
    60  		s.machines = append(s.machines, testing.AddStateServerMachine(c, s.State))
    61  	}
    62  	for i := 0; i < 5; i++ {
    63  		machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
    64  		c.Check(err, gc.IsNil)
    65  		s.machines = append(s.machines, machine)
    66  	}
    67  
    68  	// Create a FakeAuthorizer so we can check permissions,
    69  	// set up assuming we logged in as the environment manager.
    70  	s.authorizer = apiservertesting.FakeAuthorizer{
    71  		LoggedIn:       true,
    72  		EnvironManager: true,
    73  	}
    74  
    75  	// Create the resource registry separately to track invocations to
    76  	// Register.
    77  	s.resources = common.NewResources()
    78  
    79  	// Create a provisioner API for the machine.
    80  	provisionerAPI, err := provisioner.NewProvisionerAPI(
    81  		s.State,
    82  		s.resources,
    83  		s.authorizer,
    84  	)
    85  	c.Assert(err, gc.IsNil)
    86  	s.provisioner = provisionerAPI
    87  }
    88  
    89  type withoutStateServerSuite struct {
    90  	provisionerSuite
    91  	*commontesting.EnvironWatcherTest
    92  }
    93  
    94  var _ = gc.Suite(&withoutStateServerSuite{})
    95  
    96  func (s *withoutStateServerSuite) SetUpTest(c *gc.C) {
    97  	s.setUpTest(c, false)
    98  	s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.provisioner, s.State, s.resources, commontesting.HasSecrets)
    99  }
   100  
   101  func (s *withoutStateServerSuite) TestProvisionerFailsWithNonMachineAgentNonManagerUser(c *gc.C) {
   102  	anAuthorizer := s.authorizer
   103  	anAuthorizer.MachineAgent = false
   104  	anAuthorizer.EnvironManager = true
   105  	// Works with an environment manager, which is not a machine agent.
   106  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   107  	c.Assert(err, gc.IsNil)
   108  	c.Assert(aProvisioner, gc.NotNil)
   109  
   110  	// But fails with neither a machine agent or an environment manager.
   111  	anAuthorizer.EnvironManager = false
   112  	aProvisioner, err = provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   113  	c.Assert(err, gc.NotNil)
   114  	c.Assert(aProvisioner, gc.IsNil)
   115  	c.Assert(err, gc.ErrorMatches, "permission denied")
   116  }
   117  
   118  func (s *withoutStateServerSuite) TestSetPasswords(c *gc.C) {
   119  	args := params.EntityPasswords{
   120  		Changes: []params.EntityPassword{
   121  			{Tag: s.machines[0].Tag(), Password: "xxx0-1234567890123457890"},
   122  			{Tag: s.machines[1].Tag(), Password: "xxx1-1234567890123457890"},
   123  			{Tag: s.machines[2].Tag(), Password: "xxx2-1234567890123457890"},
   124  			{Tag: s.machines[3].Tag(), Password: "xxx3-1234567890123457890"},
   125  			{Tag: s.machines[4].Tag(), Password: "xxx4-1234567890123457890"},
   126  			{Tag: "machine-42", Password: "foo"},
   127  			{Tag: "unit-foo-0", Password: "zzz"},
   128  			{Tag: "service-bar", Password: "abc"},
   129  		},
   130  	}
   131  	results, err := s.provisioner.SetPasswords(args)
   132  	c.Assert(err, gc.IsNil)
   133  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   134  		Results: []params.ErrorResult{
   135  			{nil},
   136  			{nil},
   137  			{nil},
   138  			{nil},
   139  			{nil},
   140  			{apiservertesting.NotFoundError("machine 42")},
   141  			{apiservertesting.ErrUnauthorized},
   142  			{apiservertesting.ErrUnauthorized},
   143  		},
   144  	})
   145  
   146  	// Verify the changes to both machines succeeded.
   147  	for i, machine := range s.machines {
   148  		c.Logf("trying %q password", machine.Tag())
   149  		err = machine.Refresh()
   150  		c.Assert(err, gc.IsNil)
   151  		changed := machine.PasswordValid(fmt.Sprintf("xxx%d-1234567890123457890", i))
   152  		c.Assert(changed, jc.IsTrue)
   153  	}
   154  }
   155  
   156  func (s *withoutStateServerSuite) TestShortSetPasswords(c *gc.C) {
   157  	args := params.EntityPasswords{
   158  		Changes: []params.EntityPassword{
   159  			{Tag: s.machines[1].Tag(), Password: "xxx1"},
   160  		},
   161  	}
   162  	results, err := s.provisioner.SetPasswords(args)
   163  	c.Assert(err, gc.IsNil)
   164  	c.Assert(results.Results, gc.HasLen, 1)
   165  	c.Assert(results.Results[0].Error, gc.ErrorMatches,
   166  		"password is only 4 bytes long, and is not a valid Agent password")
   167  }
   168  
   169  func (s *withoutStateServerSuite) TestLifeAsMachineAgent(c *gc.C) {
   170  	// NOTE: This and the next call serve to test the two
   171  	// different authorization schemes:
   172  	// 1. Machine agents can access their own machine and
   173  	// any container that has their own machine as parent;
   174  	// 2. Environment managers can access any machine without
   175  	// a parent.
   176  	// There's no need to repeat this test for each method,
   177  	// because the authorization logic is common.
   178  
   179  	// Login as a machine agent for machine 0.
   180  	anAuthorizer := s.authorizer
   181  	anAuthorizer.MachineAgent = true
   182  	anAuthorizer.EnvironManager = false
   183  	anAuthorizer.Tag = s.machines[0].Tag()
   184  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   185  	c.Assert(err, gc.IsNil)
   186  	c.Assert(aProvisioner, gc.NotNil)
   187  
   188  	// Make the machine dead before trying to add containers.
   189  	err = s.machines[0].EnsureDead()
   190  	c.Assert(err, gc.IsNil)
   191  
   192  	// Create some containers to work on.
   193  	template := state.MachineTemplate{
   194  		Series: "quantal",
   195  		Jobs:   []state.MachineJob{state.JobHostUnits},
   196  	}
   197  	var containers []*state.Machine
   198  	for i := 0; i < 3; i++ {
   199  		container, err := s.State.AddMachineInsideMachine(template, s.machines[0].Id(), instance.LXC)
   200  		c.Check(err, gc.IsNil)
   201  		containers = append(containers, container)
   202  	}
   203  	// Make one container dead.
   204  	err = containers[1].EnsureDead()
   205  	c.Assert(err, gc.IsNil)
   206  
   207  	args := params.Entities{Entities: []params.Entity{
   208  		{Tag: s.machines[0].Tag()},
   209  		{Tag: s.machines[1].Tag()},
   210  		{Tag: containers[0].Tag()},
   211  		{Tag: containers[1].Tag()},
   212  		{Tag: containers[2].Tag()},
   213  		{Tag: "machine-42"},
   214  		{Tag: "unit-foo-0"},
   215  		{Tag: "service-bar"},
   216  	}}
   217  	result, err := aProvisioner.Life(args)
   218  	c.Assert(err, gc.IsNil)
   219  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   220  		Results: []params.LifeResult{
   221  			{Life: "dead"},
   222  			{Error: apiservertesting.ErrUnauthorized},
   223  			{Life: "alive"},
   224  			{Life: "dead"},
   225  			{Life: "alive"},
   226  			{Error: apiservertesting.ErrUnauthorized},
   227  			{Error: apiservertesting.ErrUnauthorized},
   228  			{Error: apiservertesting.ErrUnauthorized},
   229  		},
   230  	})
   231  }
   232  
   233  func (s *withoutStateServerSuite) TestLifeAsEnvironManager(c *gc.C) {
   234  	err := s.machines[1].EnsureDead()
   235  	c.Assert(err, gc.IsNil)
   236  	err = s.machines[1].Refresh()
   237  	c.Assert(err, gc.IsNil)
   238  	c.Assert(s.machines[0].Life(), gc.Equals, state.Alive)
   239  	c.Assert(s.machines[1].Life(), gc.Equals, state.Dead)
   240  	c.Assert(s.machines[2].Life(), gc.Equals, state.Alive)
   241  
   242  	args := params.Entities{Entities: []params.Entity{
   243  		{Tag: s.machines[0].Tag()},
   244  		{Tag: s.machines[1].Tag()},
   245  		{Tag: s.machines[2].Tag()},
   246  		{Tag: "machine-42"},
   247  		{Tag: "unit-foo-0"},
   248  		{Tag: "service-bar"},
   249  	}}
   250  	result, err := s.provisioner.Life(args)
   251  	c.Assert(err, gc.IsNil)
   252  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   253  		Results: []params.LifeResult{
   254  			{Life: "alive"},
   255  			{Life: "dead"},
   256  			{Life: "alive"},
   257  			{Error: apiservertesting.NotFoundError("machine 42")},
   258  			{Error: apiservertesting.ErrUnauthorized},
   259  			{Error: apiservertesting.ErrUnauthorized},
   260  		},
   261  	})
   262  
   263  	// Remove the subordinate and make sure it's detected.
   264  	err = s.machines[1].Remove()
   265  	c.Assert(err, gc.IsNil)
   266  	err = s.machines[1].Refresh()
   267  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   268  
   269  	result, err = s.provisioner.Life(params.Entities{
   270  		Entities: []params.Entity{
   271  			{Tag: s.machines[1].Tag()},
   272  		},
   273  	})
   274  	c.Assert(err, gc.IsNil)
   275  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   276  		Results: []params.LifeResult{
   277  			{Error: apiservertesting.NotFoundError("machine 1")},
   278  		},
   279  	})
   280  }
   281  
   282  func (s *withoutStateServerSuite) TestRemove(c *gc.C) {
   283  	err := s.machines[1].EnsureDead()
   284  	c.Assert(err, gc.IsNil)
   285  	s.assertLife(c, 0, state.Alive)
   286  	s.assertLife(c, 1, state.Dead)
   287  	s.assertLife(c, 2, state.Alive)
   288  
   289  	args := params.Entities{Entities: []params.Entity{
   290  		{Tag: s.machines[0].Tag()},
   291  		{Tag: s.machines[1].Tag()},
   292  		{Tag: s.machines[2].Tag()},
   293  		{Tag: "machine-42"},
   294  		{Tag: "unit-foo-0"},
   295  		{Tag: "service-bar"},
   296  	}}
   297  	result, err := s.provisioner.Remove(args)
   298  	c.Assert(err, gc.IsNil)
   299  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   300  		Results: []params.ErrorResult{
   301  			{&params.Error{Message: `cannot remove entity "machine-0": still alive`}},
   302  			{nil},
   303  			{&params.Error{Message: `cannot remove entity "machine-2": still alive`}},
   304  			{apiservertesting.NotFoundError("machine 42")},
   305  			{apiservertesting.ErrUnauthorized},
   306  			{apiservertesting.ErrUnauthorized},
   307  		},
   308  	})
   309  
   310  	// Verify the changes.
   311  	s.assertLife(c, 0, state.Alive)
   312  	err = s.machines[1].Refresh()
   313  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   314  	s.assertLife(c, 2, state.Alive)
   315  }
   316  
   317  func (s *withoutStateServerSuite) TestSetStatus(c *gc.C) {
   318  	err := s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   319  	c.Assert(err, gc.IsNil)
   320  	err = s.machines[1].SetStatus(params.StatusStopped, "foo", nil)
   321  	c.Assert(err, gc.IsNil)
   322  	err = s.machines[2].SetStatus(params.StatusError, "not really", nil)
   323  	c.Assert(err, gc.IsNil)
   324  
   325  	args := params.SetStatus{
   326  		Entities: []params.EntityStatus{
   327  			{Tag: s.machines[0].Tag(), Status: params.StatusError, Info: "not really",
   328  				Data: params.StatusData{"foo": "bar"}},
   329  			{Tag: s.machines[1].Tag(), Status: params.StatusStopped, Info: "foobar"},
   330  			{Tag: s.machines[2].Tag(), Status: params.StatusStarted, Info: "again"},
   331  			{Tag: "machine-42", Status: params.StatusStarted, Info: "blah"},
   332  			{Tag: "unit-foo-0", Status: params.StatusStopped, Info: "foobar"},
   333  			{Tag: "service-bar", Status: params.StatusStopped, Info: "foobar"},
   334  		}}
   335  	result, err := s.provisioner.SetStatus(args)
   336  	c.Assert(err, gc.IsNil)
   337  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   338  		Results: []params.ErrorResult{
   339  			{nil},
   340  			{nil},
   341  			{nil},
   342  			{apiservertesting.NotFoundError("machine 42")},
   343  			{apiservertesting.ErrUnauthorized},
   344  			{apiservertesting.ErrUnauthorized},
   345  		},
   346  	})
   347  
   348  	// Verify the changes.
   349  	s.assertStatus(c, 0, params.StatusError, "not really", params.StatusData{"foo": "bar"})
   350  	s.assertStatus(c, 1, params.StatusStopped, "foobar", params.StatusData{})
   351  	s.assertStatus(c, 2, params.StatusStarted, "again", params.StatusData{})
   352  }
   353  
   354  func (s *withoutStateServerSuite) TestMachinesWithTransientErrors(c *gc.C) {
   355  	err := s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   356  	c.Assert(err, gc.IsNil)
   357  	err = s.machines[1].SetStatus(params.StatusError, "transient error",
   358  		params.StatusData{"transient": true, "foo": "bar"})
   359  	c.Assert(err, gc.IsNil)
   360  	err = s.machines[2].SetStatus(params.StatusError, "error", params.StatusData{"transient": false})
   361  	c.Assert(err, gc.IsNil)
   362  	err = s.machines[3].SetStatus(params.StatusError, "error", nil)
   363  	c.Assert(err, gc.IsNil)
   364  	// Machine 4 is provisioned but error not reset yet.
   365  	err = s.machines[4].SetStatus(params.StatusError, "transient error",
   366  		params.StatusData{"transient": true, "foo": "bar"})
   367  	c.Assert(err, gc.IsNil)
   368  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   369  	err = s.machines[4].SetProvisioned("i-am", "fake_nonce", &hwChars)
   370  	c.Assert(err, gc.IsNil)
   371  
   372  	result, err := s.provisioner.MachinesWithTransientErrors()
   373  	c.Assert(err, gc.IsNil)
   374  	c.Assert(result, gc.DeepEquals, params.StatusResults{
   375  		Results: []params.StatusResult{
   376  			{Id: "1", Life: "alive", Status: "error", Info: "transient error",
   377  				Data: params.StatusData{"transient": true, "foo": "bar"}},
   378  		},
   379  	})
   380  }
   381  
   382  func (s *withoutStateServerSuite) TestMachinesWithTransientErrorsPermission(c *gc.C) {
   383  	// Machines where there's permission issues are omitted.
   384  	anAuthorizer := s.authorizer
   385  	anAuthorizer.MachineAgent = true
   386  	anAuthorizer.EnvironManager = false
   387  	anAuthorizer.Tag = "machine-1"
   388  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources,
   389  		anAuthorizer)
   390  	err = s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   391  	c.Assert(err, gc.IsNil)
   392  	err = s.machines[1].SetStatus(params.StatusError, "transient error",
   393  		params.StatusData{"transient": true, "foo": "bar"})
   394  	c.Assert(err, gc.IsNil)
   395  	err = s.machines[2].SetStatus(params.StatusError, "error", params.StatusData{"transient": false})
   396  	c.Assert(err, gc.IsNil)
   397  	err = s.machines[3].SetStatus(params.StatusError, "error", nil)
   398  	c.Assert(err, gc.IsNil)
   399  
   400  	result, err := aProvisioner.MachinesWithTransientErrors()
   401  	c.Assert(err, gc.IsNil)
   402  	c.Assert(result, gc.DeepEquals, params.StatusResults{
   403  		Results: []params.StatusResult{
   404  			{Id: "1", Life: "alive", Status: "error", Info: "transient error",
   405  				Data: params.StatusData{"transient": true, "foo": "bar"}},
   406  		},
   407  	})
   408  }
   409  
   410  func (s *withoutStateServerSuite) TestEnsureDead(c *gc.C) {
   411  	err := s.machines[1].EnsureDead()
   412  	c.Assert(err, gc.IsNil)
   413  	s.assertLife(c, 0, state.Alive)
   414  	s.assertLife(c, 1, state.Dead)
   415  	s.assertLife(c, 2, state.Alive)
   416  
   417  	args := params.Entities{Entities: []params.Entity{
   418  		{Tag: s.machines[0].Tag()},
   419  		{Tag: s.machines[1].Tag()},
   420  		{Tag: s.machines[2].Tag()},
   421  		{Tag: "machine-42"},
   422  		{Tag: "unit-foo-0"},
   423  		{Tag: "service-bar"},
   424  	}}
   425  	result, err := s.provisioner.EnsureDead(args)
   426  	c.Assert(err, gc.IsNil)
   427  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   428  		Results: []params.ErrorResult{
   429  			{nil},
   430  			{nil},
   431  			{nil},
   432  			{apiservertesting.NotFoundError("machine 42")},
   433  			{apiservertesting.ErrUnauthorized},
   434  			{apiservertesting.ErrUnauthorized},
   435  		},
   436  	})
   437  
   438  	// Verify the changes.
   439  	s.assertLife(c, 0, state.Dead)
   440  	s.assertLife(c, 1, state.Dead)
   441  	s.assertLife(c, 2, state.Dead)
   442  }
   443  
   444  func (s *withoutStateServerSuite) assertLife(c *gc.C, index int, expectLife state.Life) {
   445  	err := s.machines[index].Refresh()
   446  	c.Assert(err, gc.IsNil)
   447  	c.Assert(s.machines[index].Life(), gc.Equals, expectLife)
   448  }
   449  
   450  func (s *withoutStateServerSuite) assertStatus(c *gc.C, index int, expectStatus params.Status, expectInfo string,
   451  	expectData params.StatusData) {
   452  
   453  	status, info, data, err := s.machines[index].Status()
   454  	c.Assert(err, gc.IsNil)
   455  	c.Assert(status, gc.Equals, expectStatus)
   456  	c.Assert(info, gc.Equals, expectInfo)
   457  	c.Assert(data, gc.DeepEquals, expectData)
   458  }
   459  
   460  func (s *withoutStateServerSuite) TestWatchContainers(c *gc.C) {
   461  	c.Assert(s.resources.Count(), gc.Equals, 0)
   462  
   463  	args := params.WatchContainers{Params: []params.WatchContainer{
   464  		{MachineTag: s.machines[0].Tag(), ContainerType: string(instance.LXC)},
   465  		{MachineTag: s.machines[1].Tag(), ContainerType: string(instance.KVM)},
   466  		{MachineTag: "machine-42", ContainerType: ""},
   467  		{MachineTag: "unit-foo-0", ContainerType: ""},
   468  		{MachineTag: "service-bar", ContainerType: ""},
   469  	}}
   470  	result, err := s.provisioner.WatchContainers(args)
   471  	c.Assert(err, gc.IsNil)
   472  	c.Assert(result, gc.DeepEquals, params.StringsWatchResults{
   473  		Results: []params.StringsWatchResult{
   474  			{StringsWatcherId: "1", Changes: []string{}},
   475  			{StringsWatcherId: "2", Changes: []string{}},
   476  			{Error: apiservertesting.NotFoundError("machine 42")},
   477  			{Error: apiservertesting.ErrUnauthorized},
   478  			{Error: apiservertesting.ErrUnauthorized},
   479  		},
   480  	})
   481  
   482  	// Verify the resources were registered and stop them when done.
   483  	c.Assert(s.resources.Count(), gc.Equals, 2)
   484  	m0Watcher := s.resources.Get("1")
   485  	defer statetesting.AssertStop(c, m0Watcher)
   486  	m1Watcher := s.resources.Get("2")
   487  	defer statetesting.AssertStop(c, m1Watcher)
   488  
   489  	// Check that the Watch has consumed the initial event ("returned"
   490  	// in the Watch call)
   491  	wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher))
   492  	wc0.AssertNoChange()
   493  	wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher))
   494  	wc1.AssertNoChange()
   495  }
   496  
   497  func (s *withoutStateServerSuite) TestWatchAllContainers(c *gc.C) {
   498  	c.Assert(s.resources.Count(), gc.Equals, 0)
   499  
   500  	args := params.WatchContainers{Params: []params.WatchContainer{
   501  		{MachineTag: s.machines[0].Tag()},
   502  		{MachineTag: s.machines[1].Tag()},
   503  		{MachineTag: "machine-42"},
   504  		{MachineTag: "unit-foo-0"},
   505  		{MachineTag: "service-bar"},
   506  	}}
   507  	result, err := s.provisioner.WatchAllContainers(args)
   508  	c.Assert(err, gc.IsNil)
   509  	c.Assert(result, gc.DeepEquals, params.StringsWatchResults{
   510  		Results: []params.StringsWatchResult{
   511  			{StringsWatcherId: "1", Changes: []string{}},
   512  			{StringsWatcherId: "2", Changes: []string{}},
   513  			{Error: apiservertesting.NotFoundError("machine 42")},
   514  			{Error: apiservertesting.ErrUnauthorized},
   515  			{Error: apiservertesting.ErrUnauthorized},
   516  		},
   517  	})
   518  
   519  	// Verify the resources were registered and stop them when done.
   520  	c.Assert(s.resources.Count(), gc.Equals, 2)
   521  	m0Watcher := s.resources.Get("1")
   522  	defer statetesting.AssertStop(c, m0Watcher)
   523  	m1Watcher := s.resources.Get("2")
   524  	defer statetesting.AssertStop(c, m1Watcher)
   525  
   526  	// Check that the Watch has consumed the initial event ("returned"
   527  	// in the Watch call)
   528  	wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher))
   529  	wc0.AssertNoChange()
   530  	wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher))
   531  	wc1.AssertNoChange()
   532  }
   533  
   534  func (s *withoutStateServerSuite) TestEnvironConfigNonManager(c *gc.C) {
   535  	// Now test it with a non-environment manager and make sure
   536  	// the secret attributes are masked.
   537  	anAuthorizer := s.authorizer
   538  	anAuthorizer.MachineAgent = true
   539  	anAuthorizer.EnvironManager = false
   540  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources,
   541  		anAuthorizer)
   542  	c.Assert(err, gc.IsNil)
   543  	s.AssertEnvironConfig(c, aProvisioner, commontesting.NoSecrets)
   544  }
   545  
   546  func (s *withoutStateServerSuite) TestStatus(c *gc.C) {
   547  	err := s.machines[0].SetStatus(params.StatusStarted, "blah", nil)
   548  	c.Assert(err, gc.IsNil)
   549  	err = s.machines[1].SetStatus(params.StatusStopped, "foo", nil)
   550  	c.Assert(err, gc.IsNil)
   551  	err = s.machines[2].SetStatus(params.StatusError, "not really", params.StatusData{"foo": "bar"})
   552  	c.Assert(err, gc.IsNil)
   553  
   554  	args := params.Entities{Entities: []params.Entity{
   555  		{Tag: s.machines[0].Tag()},
   556  		{Tag: s.machines[1].Tag()},
   557  		{Tag: s.machines[2].Tag()},
   558  		{Tag: "machine-42"},
   559  		{Tag: "unit-foo-0"},
   560  		{Tag: "service-bar"},
   561  	}}
   562  	result, err := s.provisioner.Status(args)
   563  	c.Assert(err, gc.IsNil)
   564  	c.Assert(result, gc.DeepEquals, params.StatusResults{
   565  		Results: []params.StatusResult{
   566  			{Status: params.StatusStarted, Info: "blah", Data: params.StatusData{}},
   567  			{Status: params.StatusStopped, Info: "foo", Data: params.StatusData{}},
   568  			{Status: params.StatusError, Info: "not really", Data: params.StatusData{"foo": "bar"}},
   569  			{Error: apiservertesting.NotFoundError("machine 42")},
   570  			{Error: apiservertesting.ErrUnauthorized},
   571  			{Error: apiservertesting.ErrUnauthorized},
   572  		},
   573  	})
   574  }
   575  
   576  func (s *withoutStateServerSuite) TestSeries(c *gc.C) {
   577  	// Add a machine with different series.
   578  	foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits)
   579  	c.Assert(err, gc.IsNil)
   580  
   581  	args := params.Entities{Entities: []params.Entity{
   582  		{Tag: s.machines[0].Tag()},
   583  		{Tag: foobarMachine.Tag()},
   584  		{Tag: s.machines[2].Tag()},
   585  		{Tag: "machine-42"},
   586  		{Tag: "unit-foo-0"},
   587  		{Tag: "service-bar"},
   588  	}}
   589  	result, err := s.provisioner.Series(args)
   590  	c.Assert(err, gc.IsNil)
   591  	c.Assert(result, gc.DeepEquals, params.StringResults{
   592  		Results: []params.StringResult{
   593  			{Result: s.machines[0].Series()},
   594  			{Result: foobarMachine.Series()},
   595  			{Result: s.machines[2].Series()},
   596  			{Error: apiservertesting.NotFoundError("machine 42")},
   597  			{Error: apiservertesting.ErrUnauthorized},
   598  			{Error: apiservertesting.ErrUnauthorized},
   599  		},
   600  	})
   601  }
   602  
   603  func (s *withoutStateServerSuite) TestDistributionGroup(c *gc.C) {
   604  	addUnits := func(name string, machines ...*state.Machine) (units []*state.Unit) {
   605  		svc := s.AddTestingService(c, name, s.AddTestingCharm(c, name))
   606  		for _, m := range machines {
   607  			unit, err := svc.AddUnit()
   608  			c.Assert(err, gc.IsNil)
   609  			err = unit.AssignToMachine(m)
   610  			c.Assert(err, gc.IsNil)
   611  			units = append(units, unit)
   612  		}
   613  		return units
   614  	}
   615  	setProvisioned := func(id string) {
   616  		m, err := s.State.Machine(id)
   617  		c.Assert(err, gc.IsNil)
   618  		err = m.SetProvisioned(instance.Id("machine-"+id+"-inst"), "nonce", nil)
   619  		c.Assert(err, gc.IsNil)
   620  	}
   621  
   622  	mysqlUnit := addUnits("mysql", s.machines[0], s.machines[3])[0]
   623  	wordpressUnits := addUnits("wordpress", s.machines[0], s.machines[1], s.machines[2])
   624  
   625  	// Unassign wordpress/1 from machine-1.
   626  	// The unit should not show up in the results.
   627  	err := wordpressUnits[1].UnassignFromMachine()
   628  	c.Assert(err, gc.IsNil)
   629  
   630  	// Provision machines 1, 2 and 3. Machine-0 remains
   631  	// unprovisioned, and machine-1 has no units, and so
   632  	// neither will show up in the results.
   633  	setProvisioned("1")
   634  	setProvisioned("2")
   635  	setProvisioned("3")
   636  
   637  	// Add a few state servers, provision two of them.
   638  	err = s.State.EnsureAvailability(3, constraints.Value{}, "quantal")
   639  	c.Assert(err, gc.IsNil)
   640  	setProvisioned("5")
   641  	setProvisioned("7")
   642  
   643  	// Create a logging service, subordinate to mysql.
   644  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
   645  	eps, err := s.State.InferEndpoints([]string{"mysql", "logging"})
   646  	c.Assert(err, gc.IsNil)
   647  	rel, err := s.State.AddRelation(eps...)
   648  	c.Assert(err, gc.IsNil)
   649  	ru, err := rel.Unit(mysqlUnit)
   650  	c.Assert(err, gc.IsNil)
   651  	err = ru.EnterScope(nil)
   652  	c.Assert(err, gc.IsNil)
   653  
   654  	args := params.Entities{Entities: []params.Entity{
   655  		{Tag: s.machines[0].Tag()},
   656  		{Tag: s.machines[1].Tag()},
   657  		{Tag: s.machines[2].Tag()},
   658  		{Tag: s.machines[3].Tag()},
   659  		{Tag: "machine-5"},
   660  	}}
   661  	result, err := s.provisioner.DistributionGroup(args)
   662  	c.Assert(err, gc.IsNil)
   663  	c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{
   664  		Results: []params.DistributionGroupResult{
   665  			{Result: []instance.Id{"machine-2-inst", "machine-3-inst"}},
   666  			{Result: []instance.Id{}},
   667  			{Result: []instance.Id{"machine-2-inst"}},
   668  			{Result: []instance.Id{"machine-3-inst"}},
   669  			{Result: []instance.Id{"machine-5-inst", "machine-7-inst"}},
   670  		},
   671  	})
   672  }
   673  
   674  func (s *withoutStateServerSuite) TestDistributionGroupEnvironManagerAuth(c *gc.C) {
   675  	args := params.Entities{Entities: []params.Entity{
   676  		{Tag: "machine-0"},
   677  		{Tag: "machine-42"},
   678  		{Tag: "machine-0-lxc-99"},
   679  		{Tag: "unit-foo-0"},
   680  		{Tag: "service-bar"},
   681  	}}
   682  	result, err := s.provisioner.DistributionGroup(args)
   683  	c.Assert(err, gc.IsNil)
   684  	c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{
   685  		Results: []params.DistributionGroupResult{
   686  			// environ manager may access any top-level machines.
   687  			{Result: []instance.Id{}},
   688  			{Error: apiservertesting.NotFoundError("machine 42")},
   689  			// only a machine agent for the container or its
   690  			// parent may access it.
   691  			{Error: apiservertesting.ErrUnauthorized},
   692  			// non-machines always unauthorized
   693  			{Error: apiservertesting.ErrUnauthorized},
   694  			{Error: apiservertesting.ErrUnauthorized},
   695  		},
   696  	})
   697  }
   698  
   699  func (s *withoutStateServerSuite) TestDistributionGroupMachineAgentAuth(c *gc.C) {
   700  	anAuthorizer := s.authorizer
   701  	anAuthorizer.Tag = "machine-1"
   702  	anAuthorizer.EnvironManager = false
   703  	anAuthorizer.MachineAgent = true
   704  	provisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   705  	c.Check(err, gc.IsNil)
   706  	args := params.Entities{Entities: []params.Entity{
   707  		{Tag: "machine-0"},
   708  		{Tag: "machine-1"},
   709  		{Tag: "machine-42"},
   710  		{Tag: "machine-0-lxc-99"},
   711  		{Tag: "machine-1-lxc-99"},
   712  		{Tag: "machine-1-lxc-99-lxc-100"},
   713  	}}
   714  	result, err := provisioner.DistributionGroup(args)
   715  	c.Assert(err, gc.IsNil)
   716  	c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{
   717  		Results: []params.DistributionGroupResult{
   718  			{Error: apiservertesting.ErrUnauthorized},
   719  			{Result: []instance.Id{}},
   720  			{Error: apiservertesting.ErrUnauthorized},
   721  			// only a machine agent for the container or its
   722  			// parent may access it.
   723  			{Error: apiservertesting.ErrUnauthorized},
   724  			{Error: apiservertesting.NotFoundError("machine 1/lxc/99")},
   725  			{Error: apiservertesting.ErrUnauthorized},
   726  		},
   727  	})
   728  }
   729  
   730  func (s *withoutStateServerSuite) TestProvisioningInfo(c *gc.C) {
   731  	cons := constraints.MustParse("cpu-cores=123 mem=8G networks=^net3,^net4")
   732  	template := state.MachineTemplate{
   733  		Series:            "quantal",
   734  		Jobs:              []state.MachineJob{state.JobHostUnits},
   735  		Constraints:       cons,
   736  		Placement:         "valid",
   737  		RequestedNetworks: []string{"net1", "net2"},
   738  	}
   739  	placementMachine, err := s.State.AddOneMachine(template)
   740  	c.Assert(err, gc.IsNil)
   741  
   742  	args := params.Entities{Entities: []params.Entity{
   743  		{Tag: s.machines[0].Tag()},
   744  		{Tag: placementMachine.Tag()},
   745  		{Tag: "machine-42"},
   746  		{Tag: "unit-foo-0"},
   747  		{Tag: "service-bar"},
   748  	}}
   749  	result, err := s.provisioner.ProvisioningInfo(args)
   750  	c.Assert(err, gc.IsNil)
   751  	c.Assert(result, gc.DeepEquals, params.ProvisioningInfoResults{
   752  		Results: []params.ProvisioningInfoResult{
   753  			{Result: &params.ProvisioningInfo{
   754  				Series:   "quantal",
   755  				Networks: []string{},
   756  			}},
   757  			{Result: &params.ProvisioningInfo{
   758  				Series:      "quantal",
   759  				Constraints: template.Constraints,
   760  				Placement:   template.Placement,
   761  				Networks:    template.RequestedNetworks,
   762  			}},
   763  			{Error: apiservertesting.NotFoundError("machine 42")},
   764  			{Error: apiservertesting.ErrUnauthorized},
   765  			{Error: apiservertesting.ErrUnauthorized},
   766  		},
   767  	})
   768  }
   769  
   770  func (s *withoutStateServerSuite) TestProvisioningInfoPermissions(c *gc.C) {
   771  	// Login as a machine agent for machine 0.
   772  	anAuthorizer := s.authorizer
   773  	anAuthorizer.MachineAgent = true
   774  	anAuthorizer.EnvironManager = false
   775  	anAuthorizer.Tag = s.machines[0].Tag()
   776  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
   777  	c.Assert(err, gc.IsNil)
   778  	c.Assert(aProvisioner, gc.NotNil)
   779  
   780  	args := params.Entities{Entities: []params.Entity{
   781  		{Tag: s.machines[0].Tag()},
   782  		{Tag: s.machines[0].Tag() + "-lxc-0"},
   783  		{Tag: "machine-42"},
   784  		{Tag: s.machines[1].Tag()},
   785  		{Tag: "service-bar"},
   786  	}}
   787  
   788  	// Only machine 0 and containers therein can be accessed.
   789  	results, err := aProvisioner.ProvisioningInfo(args)
   790  	c.Assert(results, gc.DeepEquals, params.ProvisioningInfoResults{
   791  		Results: []params.ProvisioningInfoResult{
   792  			{Result: &params.ProvisioningInfo{
   793  				Series:   "quantal",
   794  				Networks: []string{},
   795  			}},
   796  			{Error: apiservertesting.NotFoundError("machine 0/lxc/0")},
   797  			{Error: apiservertesting.ErrUnauthorized},
   798  			{Error: apiservertesting.ErrUnauthorized},
   799  			{Error: apiservertesting.ErrUnauthorized},
   800  		},
   801  	})
   802  }
   803  
   804  func (s *withoutStateServerSuite) TestConstraints(c *gc.C) {
   805  	// Add a machine with some constraints.
   806  	cons := constraints.MustParse("cpu-cores=123", "mem=8G", "networks=net3,^net4")
   807  	template := state.MachineTemplate{
   808  		Series:      "quantal",
   809  		Jobs:        []state.MachineJob{state.JobHostUnits},
   810  		Constraints: cons,
   811  	}
   812  	consMachine, err := s.State.AddOneMachine(template)
   813  	c.Assert(err, gc.IsNil)
   814  
   815  	machine0Constraints, err := s.machines[0].Constraints()
   816  	c.Assert(err, gc.IsNil)
   817  
   818  	args := params.Entities{Entities: []params.Entity{
   819  		{Tag: s.machines[0].Tag()},
   820  		{Tag: consMachine.Tag()},
   821  		{Tag: "machine-42"},
   822  		{Tag: "unit-foo-0"},
   823  		{Tag: "service-bar"},
   824  	}}
   825  	result, err := s.provisioner.Constraints(args)
   826  	c.Assert(err, gc.IsNil)
   827  	c.Assert(result, gc.DeepEquals, params.ConstraintsResults{
   828  		Results: []params.ConstraintsResult{
   829  			{Constraints: machine0Constraints},
   830  			{Constraints: template.Constraints},
   831  			{Error: apiservertesting.NotFoundError("machine 42")},
   832  			{Error: apiservertesting.ErrUnauthorized},
   833  			{Error: apiservertesting.ErrUnauthorized},
   834  		},
   835  	})
   836  }
   837  
   838  func (s *withoutStateServerSuite) TestRequestedNetworks(c *gc.C) {
   839  	// Add a machine with some requested networks.
   840  	template := state.MachineTemplate{
   841  		Series:            "quantal",
   842  		Jobs:              []state.MachineJob{state.JobHostUnits},
   843  		RequestedNetworks: []string{"net1", "net2"},
   844  	}
   845  	netsMachine, err := s.State.AddOneMachine(template)
   846  	c.Assert(err, gc.IsNil)
   847  
   848  	networksMachine0, err := s.machines[0].RequestedNetworks()
   849  	c.Assert(err, gc.IsNil)
   850  
   851  	args := params.Entities{Entities: []params.Entity{
   852  		{Tag: s.machines[0].Tag()},
   853  		{Tag: netsMachine.Tag()},
   854  		{Tag: "machine-42"},
   855  		{Tag: "unit-foo-0"},
   856  		{Tag: "service-bar"},
   857  	}}
   858  	result, err := s.provisioner.RequestedNetworks(args)
   859  	c.Assert(err, gc.IsNil)
   860  	c.Assert(result, gc.DeepEquals, params.RequestedNetworksResults{
   861  		Results: []params.RequestedNetworkResult{
   862  			{
   863  				Networks: networksMachine0,
   864  			},
   865  			{
   866  				Networks: template.RequestedNetworks,
   867  			},
   868  			{Error: apiservertesting.NotFoundError("machine 42")},
   869  			{Error: apiservertesting.ErrUnauthorized},
   870  			{Error: apiservertesting.ErrUnauthorized},
   871  		},
   872  	})
   873  }
   874  
   875  func (s *withoutStateServerSuite) TestSetProvisioned(c *gc.C) {
   876  	// Provision machine 0 first.
   877  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   878  	err := s.machines[0].SetProvisioned("i-am", "fake_nonce", &hwChars)
   879  	c.Assert(err, gc.IsNil)
   880  
   881  	args := params.SetProvisioned{Machines: []params.MachineSetProvisioned{
   882  		{Tag: s.machines[0].Tag(), InstanceId: "i-was", Nonce: "fake_nonce", Characteristics: nil},
   883  		{Tag: s.machines[1].Tag(), InstanceId: "i-will", Nonce: "fake_nonce", Characteristics: &hwChars},
   884  		{Tag: s.machines[2].Tag(), InstanceId: "i-am-too", Nonce: "fake", Characteristics: nil},
   885  		{Tag: "machine-42", InstanceId: "", Nonce: "", Characteristics: nil},
   886  		{Tag: "unit-foo-0", InstanceId: "", Nonce: "", Characteristics: nil},
   887  		{Tag: "service-bar", InstanceId: "", Nonce: "", Characteristics: nil},
   888  	}}
   889  	result, err := s.provisioner.SetProvisioned(args)
   890  	c.Assert(err, gc.IsNil)
   891  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   892  		Results: []params.ErrorResult{
   893  			{&params.Error{
   894  				Message: `cannot set instance data for machine "0": already set`,
   895  			}},
   896  			{nil},
   897  			{nil},
   898  			{apiservertesting.NotFoundError("machine 42")},
   899  			{apiservertesting.ErrUnauthorized},
   900  			{apiservertesting.ErrUnauthorized},
   901  		},
   902  	})
   903  
   904  	// Verify machine 1 and 2 were provisioned.
   905  	c.Assert(s.machines[1].Refresh(), gc.IsNil)
   906  	c.Assert(s.machines[2].Refresh(), gc.IsNil)
   907  
   908  	instanceId, err := s.machines[1].InstanceId()
   909  	c.Assert(err, gc.IsNil)
   910  	c.Check(instanceId, gc.Equals, instance.Id("i-will"))
   911  	instanceId, err = s.machines[2].InstanceId()
   912  	c.Assert(err, gc.IsNil)
   913  	c.Check(instanceId, gc.Equals, instance.Id("i-am-too"))
   914  	c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue)
   915  	c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue)
   916  	gotHardware, err := s.machines[1].HardwareCharacteristics()
   917  	c.Assert(err, gc.IsNil)
   918  	c.Check(gotHardware, gc.DeepEquals, &hwChars)
   919  }
   920  
   921  func (s *withoutStateServerSuite) TestSetInstanceInfo(c *gc.C) {
   922  	// Provision machine 0 first.
   923  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   924  	err := s.machines[0].SetInstanceInfo("i-am", "fake_nonce", &hwChars, nil, nil)
   925  	c.Assert(err, gc.IsNil)
   926  
   927  	networks := []params.Network{{
   928  		Tag:        "network-net1",
   929  		ProviderId: "net1",
   930  		CIDR:       "0.1.2.0/24",
   931  		VLANTag:    0,
   932  	}, {
   933  		Tag:        "network-vlan42",
   934  		ProviderId: "vlan42",
   935  		CIDR:       "0.2.2.0/24",
   936  		VLANTag:    42,
   937  	}, {
   938  		Tag:        "network-vlan69",
   939  		ProviderId: "vlan69",
   940  		CIDR:       "0.3.2.0/24",
   941  		VLANTag:    69,
   942  	}, {
   943  		Tag:        "network-vlan42", // duplicated; ignored
   944  		ProviderId: "vlan42",
   945  		CIDR:       "0.2.2.0/24",
   946  		VLANTag:    42,
   947  	}}
   948  	ifaces := []params.NetworkInterface{{
   949  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   950  		NetworkTag:    "network-net1",
   951  		InterfaceName: "eth0",
   952  		IsVirtual:     false,
   953  	}, {
   954  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   955  		NetworkTag:    "network-net1",
   956  		InterfaceName: "eth1",
   957  		IsVirtual:     false,
   958  	}, {
   959  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   960  		NetworkTag:    "network-vlan42",
   961  		InterfaceName: "eth1.42",
   962  		IsVirtual:     true,
   963  	}, {
   964  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   965  		NetworkTag:    "network-vlan69",
   966  		InterfaceName: "eth0.69",
   967  		IsVirtual:     true,
   968  	}, {
   969  		MACAddress:    "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored
   970  		NetworkTag:    "network-vlan42",
   971  		InterfaceName: "eth2",
   972  		IsVirtual:     true,
   973  	}, {
   974  		MACAddress:    "aa:bb:cc:dd:ee:f2",
   975  		NetworkTag:    "network-net1",
   976  		InterfaceName: "eth1", // duplicated name+machine id; ignored for machine 1.
   977  		IsVirtual:     false,
   978  	}}
   979  	args := params.InstancesInfo{Machines: []params.InstanceInfo{{
   980  		Tag:        s.machines[0].Tag(),
   981  		InstanceId: "i-was",
   982  		Nonce:      "fake_nonce",
   983  	}, {
   984  		Tag:             s.machines[1].Tag(),
   985  		InstanceId:      "i-will",
   986  		Nonce:           "fake_nonce",
   987  		Characteristics: &hwChars,
   988  		Networks:        networks,
   989  		Interfaces:      ifaces,
   990  	}, {
   991  		Tag:             s.machines[2].Tag(),
   992  		InstanceId:      "i-am-too",
   993  		Nonce:           "fake",
   994  		Characteristics: nil,
   995  		Networks:        networks,
   996  		Interfaces:      ifaces,
   997  	},
   998  		{Tag: "machine-42"},
   999  		{Tag: "unit-foo-0"},
  1000  		{Tag: "service-bar"},
  1001  	}}
  1002  	result, err := s.provisioner.SetInstanceInfo(args)
  1003  	c.Assert(err, gc.IsNil)
  1004  	c.Assert(result, jc.DeepEquals, params.ErrorResults{
  1005  		Results: []params.ErrorResult{
  1006  			{&params.Error{
  1007  				Message: `aborted instance "i-was": cannot set instance data for machine "0": already set`,
  1008  			}},
  1009  			{nil},
  1010  			{nil},
  1011  			{apiservertesting.NotFoundError("machine 42")},
  1012  			{apiservertesting.ErrUnauthorized},
  1013  			{apiservertesting.ErrUnauthorized},
  1014  		},
  1015  	})
  1016  
  1017  	// Verify machine 1 and 2 were provisioned.
  1018  	c.Assert(s.machines[1].Refresh(), gc.IsNil)
  1019  	c.Assert(s.machines[2].Refresh(), gc.IsNil)
  1020  
  1021  	instanceId, err := s.machines[1].InstanceId()
  1022  	c.Assert(err, gc.IsNil)
  1023  	c.Check(instanceId, gc.Equals, instance.Id("i-will"))
  1024  	instanceId, err = s.machines[2].InstanceId()
  1025  	c.Assert(err, gc.IsNil)
  1026  	c.Check(instanceId, gc.Equals, instance.Id("i-am-too"))
  1027  	c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue)
  1028  	c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue)
  1029  	gotHardware, err := s.machines[1].HardwareCharacteristics()
  1030  	c.Assert(err, gc.IsNil)
  1031  	c.Check(gotHardware, gc.DeepEquals, &hwChars)
  1032  	ifacesMachine1, err := s.machines[1].NetworkInterfaces()
  1033  	c.Assert(err, gc.IsNil)
  1034  	c.Assert(ifacesMachine1, gc.HasLen, 4)
  1035  	actual := make([]params.NetworkInterface, len(ifacesMachine1))
  1036  	for i, iface := range ifacesMachine1 {
  1037  		actual[i].InterfaceName = iface.InterfaceName()
  1038  		actual[i].NetworkTag = iface.NetworkTag()
  1039  		actual[i].MACAddress = iface.MACAddress()
  1040  		actual[i].IsVirtual = iface.IsVirtual()
  1041  		c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id())
  1042  		c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag())
  1043  	}
  1044  	c.Assert(actual, jc.SameContents, ifaces[:4])
  1045  	ifacesMachine2, err := s.machines[2].NetworkInterfaces()
  1046  	c.Assert(err, gc.IsNil)
  1047  	c.Assert(ifacesMachine2, gc.HasLen, 1)
  1048  	c.Assert(ifacesMachine2[0].InterfaceName(), gc.Equals, ifaces[5].InterfaceName)
  1049  	c.Assert(ifacesMachine2[0].MACAddress(), gc.Equals, ifaces[5].MACAddress)
  1050  	c.Assert(ifacesMachine2[0].NetworkTag(), gc.Equals, ifaces[5].NetworkTag)
  1051  	c.Assert(ifacesMachine2[0].MachineId(), gc.Equals, s.machines[2].Id())
  1052  	for i, _ := range networks {
  1053  		if i == 3 {
  1054  			// Last one was ignored, so don't check.
  1055  			break
  1056  		}
  1057  		_, networkName, err := names.ParseTag(networks[i].Tag, names.NetworkTagKind)
  1058  		c.Assert(err, gc.IsNil)
  1059  		network, err := s.State.Network(networkName)
  1060  		c.Assert(err, gc.IsNil)
  1061  		c.Check(network.Name(), gc.Equals, networkName)
  1062  		c.Check(network.ProviderId(), gc.Equals, networks[i].ProviderId)
  1063  		c.Check(network.Tag(), gc.Equals, networks[i].Tag)
  1064  		c.Check(network.VLANTag(), gc.Equals, networks[i].VLANTag)
  1065  		c.Check(network.CIDR(), gc.Equals, networks[i].CIDR)
  1066  	}
  1067  }
  1068  
  1069  func (s *withoutStateServerSuite) TestInstanceId(c *gc.C) {
  1070  	// Provision 2 machines first.
  1071  	err := s.machines[0].SetProvisioned("i-am", "fake_nonce", nil)
  1072  	c.Assert(err, gc.IsNil)
  1073  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
  1074  	err = s.machines[1].SetProvisioned("i-am-not", "fake_nonce", &hwChars)
  1075  	c.Assert(err, gc.IsNil)
  1076  
  1077  	args := params.Entities{Entities: []params.Entity{
  1078  		{Tag: s.machines[0].Tag()},
  1079  		{Tag: s.machines[1].Tag()},
  1080  		{Tag: s.machines[2].Tag()},
  1081  		{Tag: "machine-42"},
  1082  		{Tag: "unit-foo-0"},
  1083  		{Tag: "service-bar"},
  1084  	}}
  1085  	result, err := s.provisioner.InstanceId(args)
  1086  	c.Assert(err, gc.IsNil)
  1087  	c.Assert(result, gc.DeepEquals, params.StringResults{
  1088  		Results: []params.StringResult{
  1089  			{Result: "i-am"},
  1090  			{Result: "i-am-not"},
  1091  			{Error: apiservertesting.NotProvisionedError("2")},
  1092  			{Error: apiservertesting.NotFoundError("machine 42")},
  1093  			{Error: apiservertesting.ErrUnauthorized},
  1094  			{Error: apiservertesting.ErrUnauthorized},
  1095  		},
  1096  	})
  1097  }
  1098  
  1099  func (s *withoutStateServerSuite) TestWatchEnvironMachines(c *gc.C) {
  1100  	c.Assert(s.resources.Count(), gc.Equals, 0)
  1101  
  1102  	got, err := s.provisioner.WatchEnvironMachines()
  1103  	c.Assert(err, gc.IsNil)
  1104  	want := params.StringsWatchResult{
  1105  		StringsWatcherId: "1",
  1106  		Changes:          []string{"0", "1", "2", "3", "4"},
  1107  	}
  1108  	c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId)
  1109  	c.Assert(got.Changes, jc.SameContents, want.Changes)
  1110  
  1111  	// Verify the resources were registered and stop them when done.
  1112  	c.Assert(s.resources.Count(), gc.Equals, 1)
  1113  	resource := s.resources.Get("1")
  1114  	defer statetesting.AssertStop(c, resource)
  1115  
  1116  	// Check that the Watch has consumed the initial event ("returned"
  1117  	// in the Watch call)
  1118  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
  1119  	wc.AssertNoChange()
  1120  
  1121  	// Make sure WatchEnvironMachines fails with a machine agent login.
  1122  	anAuthorizer := s.authorizer
  1123  	anAuthorizer.MachineAgent = true
  1124  	anAuthorizer.EnvironManager = false
  1125  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
  1126  	c.Assert(err, gc.IsNil)
  1127  
  1128  	result, err := aProvisioner.WatchEnvironMachines()
  1129  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1130  	c.Assert(result, gc.DeepEquals, params.StringsWatchResult{})
  1131  }
  1132  
  1133  func (s *withoutStateServerSuite) TestToolsNothing(c *gc.C) {
  1134  	// Not an error to watch nothing
  1135  	results, err := s.provisioner.Tools(params.Entities{})
  1136  	c.Assert(err, gc.IsNil)
  1137  	c.Check(results.Results, gc.HasLen, 0)
  1138  }
  1139  
  1140  func (s *withoutStateServerSuite) TestContainerManagerConfig(c *gc.C) {
  1141  	args := params.ContainerManagerConfigParams{Type: instance.KVM}
  1142  	results, err := s.provisioner.ContainerManagerConfig(args)
  1143  	c.Check(err, gc.IsNil)
  1144  	c.Assert(results.ManagerConfig, gc.DeepEquals, map[string]string{
  1145  		container.ConfigName: "juju",
  1146  	})
  1147  }
  1148  
  1149  func (s *withoutStateServerSuite) TestContainerConfig(c *gc.C) {
  1150  	attrs := map[string]interface{}{
  1151  		"http-proxy": "http://proxy.example.com:9000",
  1152  	}
  1153  	err := s.State.UpdateEnvironConfig(attrs, nil, nil)
  1154  	c.Assert(err, gc.IsNil)
  1155  	expectedProxy := proxy.Settings{
  1156  		Http: "http://proxy.example.com:9000",
  1157  	}
  1158  
  1159  	results, err := s.provisioner.ContainerConfig()
  1160  	c.Check(err, gc.IsNil)
  1161  	c.Check(results.ProviderType, gc.Equals, "dummy")
  1162  	c.Check(results.AuthorizedKeys, gc.Equals, coretesting.FakeAuthKeys)
  1163  	c.Check(results.SSLHostnameVerification, jc.IsTrue)
  1164  	c.Check(results.Proxy, gc.DeepEquals, expectedProxy)
  1165  	c.Check(results.AptProxy, gc.DeepEquals, expectedProxy)
  1166  }
  1167  
  1168  func (s *withoutStateServerSuite) TestToolsRefusesWrongAgent(c *gc.C) {
  1169  	anAuthorizer := s.authorizer
  1170  	anAuthorizer.Tag = "machine-12354"
  1171  	anAuthorizer.EnvironManager = false
  1172  	anAuthorizer.MachineAgent = true
  1173  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
  1174  	c.Check(err, gc.IsNil)
  1175  	args := params.Entities{
  1176  		Entities: []params.Entity{{Tag: s.machines[0].Tag()}},
  1177  	}
  1178  	results, err := aProvisioner.Tools(args)
  1179  	// It is not an error to make the request, but the specific item is rejected
  1180  	c.Assert(err, gc.IsNil)
  1181  	c.Check(results.Results, gc.HasLen, 1)
  1182  	toolResult := results.Results[0]
  1183  	c.Assert(toolResult.Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
  1184  }
  1185  
  1186  func (s *withoutStateServerSuite) TestToolsForAgent(c *gc.C) {
  1187  	cur := version.Current
  1188  	agent := params.Entity{Tag: s.machines[0].Tag()}
  1189  
  1190  	// The machine must have its existing tools set before we query for the
  1191  	// next tools. This is so that we can grab Arch and Series without
  1192  	// having to pass it in again
  1193  	err := s.machines[0].SetAgentVersion(version.Current)
  1194  	c.Assert(err, gc.IsNil)
  1195  
  1196  	args := params.Entities{Entities: []params.Entity{agent}}
  1197  	results, err := s.provisioner.Tools(args)
  1198  	c.Assert(err, gc.IsNil)
  1199  	c.Check(results.Results, gc.HasLen, 1)
  1200  	c.Assert(results.Results[0].Error, gc.IsNil)
  1201  	agentTools := results.Results[0].Tools
  1202  	c.Check(agentTools.URL, gc.Not(gc.Equals), "")
  1203  	c.Check(agentTools.Version, gc.DeepEquals, cur)
  1204  }
  1205  
  1206  func (s *withoutStateServerSuite) TestSetSupportedContainers(c *gc.C) {
  1207  	args := params.MachineContainersParams{
  1208  		Params: []params.MachineContainers{
  1209  			{
  1210  				MachineTag:     "machine-0",
  1211  				ContainerTypes: []instance.ContainerType{instance.LXC},
  1212  			},
  1213  			{
  1214  				MachineTag:     "machine-1",
  1215  				ContainerTypes: []instance.ContainerType{instance.LXC, instance.KVM},
  1216  			},
  1217  		},
  1218  	}
  1219  	results, err := s.provisioner.SetSupportedContainers(args)
  1220  	c.Assert(err, gc.IsNil)
  1221  	c.Assert(results.Results, gc.HasLen, 2)
  1222  	for _, result := range results.Results {
  1223  		c.Assert(result.Error, gc.IsNil)
  1224  	}
  1225  	m0, err := s.State.Machine("0")
  1226  	c.Assert(err, gc.IsNil)
  1227  	containers, ok := m0.SupportedContainers()
  1228  	c.Assert(ok, jc.IsTrue)
  1229  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC})
  1230  	m1, err := s.State.Machine("1")
  1231  	c.Assert(err, gc.IsNil)
  1232  	containers, ok = m1.SupportedContainers()
  1233  	c.Assert(ok, jc.IsTrue)
  1234  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM})
  1235  }
  1236  
  1237  func (s *withoutStateServerSuite) TestSetSupportedContainersPermissions(c *gc.C) {
  1238  	// Login as a machine agent for machine 0.
  1239  	anAuthorizer := s.authorizer
  1240  	anAuthorizer.MachineAgent = true
  1241  	anAuthorizer.EnvironManager = false
  1242  	anAuthorizer.Tag = s.machines[0].Tag()
  1243  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
  1244  	c.Assert(err, gc.IsNil)
  1245  	c.Assert(aProvisioner, gc.NotNil)
  1246  
  1247  	args := params.MachineContainersParams{
  1248  		Params: []params.MachineContainers{{
  1249  			MachineTag:     "machine-0",
  1250  			ContainerTypes: []instance.ContainerType{instance.LXC},
  1251  		}, {
  1252  			MachineTag:     "machine-1",
  1253  			ContainerTypes: []instance.ContainerType{instance.LXC},
  1254  		}, {
  1255  			MachineTag:     "machine-42",
  1256  			ContainerTypes: []instance.ContainerType{instance.LXC},
  1257  		},
  1258  		},
  1259  	}
  1260  	// Only machine 0 can have it's containers updated.
  1261  	results, err := aProvisioner.SetSupportedContainers(args)
  1262  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
  1263  		Results: []params.ErrorResult{
  1264  			{Error: nil},
  1265  			{Error: apiservertesting.ErrUnauthorized},
  1266  			{Error: apiservertesting.ErrUnauthorized},
  1267  		},
  1268  	})
  1269  }
  1270  
  1271  func (s *withoutStateServerSuite) TestSupportsNoContainers(c *gc.C) {
  1272  	args := params.MachineContainersParams{
  1273  		Params: []params.MachineContainers{
  1274  			{
  1275  				MachineTag: "machine-0",
  1276  			},
  1277  		},
  1278  	}
  1279  	results, err := s.provisioner.SetSupportedContainers(args)
  1280  	c.Assert(err, gc.IsNil)
  1281  	c.Assert(results.Results, gc.HasLen, 1)
  1282  	c.Assert(results.Results[0].Error, gc.IsNil)
  1283  	m0, err := s.State.Machine("0")
  1284  	c.Assert(err, gc.IsNil)
  1285  	containers, ok := m0.SupportedContainers()
  1286  	c.Assert(ok, jc.IsTrue)
  1287  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{})
  1288  }
  1289  
  1290  var _ = gc.Suite(&withStateServerSuite{})
  1291  
  1292  type withStateServerSuite struct {
  1293  	provisionerSuite
  1294  }
  1295  
  1296  func (s *withStateServerSuite) SetUpTest(c *gc.C) {
  1297  	s.provisionerSuite.setUpTest(c, true)
  1298  }
  1299  
  1300  func (s *withStateServerSuite) TestAPIAddresses(c *gc.C) {
  1301  	hostPorts := [][]instance.HostPort{{{
  1302  		Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown),
  1303  		Port:    1234,
  1304  	}}}
  1305  
  1306  	err := s.State.SetAPIHostPorts(hostPorts)
  1307  	c.Assert(err, gc.IsNil)
  1308  
  1309  	result, err := s.provisioner.APIAddresses()
  1310  	c.Assert(err, gc.IsNil)
  1311  	c.Assert(result, gc.DeepEquals, params.StringsResult{
  1312  		Result: []string{"0.1.2.3:1234"},
  1313  	})
  1314  }
  1315  
  1316  func (s *withStateServerSuite) TestStateAddresses(c *gc.C) {
  1317  	addresses, err := s.State.Addresses()
  1318  	c.Assert(err, gc.IsNil)
  1319  
  1320  	result, err := s.provisioner.StateAddresses()
  1321  	c.Assert(err, gc.IsNil)
  1322  	c.Assert(result, gc.DeepEquals, params.StringsResult{
  1323  		Result: addresses,
  1324  	})
  1325  }
  1326  
  1327  func (s *withStateServerSuite) TestCACert(c *gc.C) {
  1328  	result := s.provisioner.CACert()
  1329  	c.Assert(result, gc.DeepEquals, params.BytesResult{
  1330  		Result: []byte(s.State.CACert()),
  1331  	})
  1332  }
  1333  
  1334  func (s *withoutStateServerSuite) TestWatchMachineErrorRetry(c *gc.C) {
  1335  	s.PatchValue(&provisioner.ErrorRetryWaitDelay, 2*coretesting.ShortWait)
  1336  	c.Assert(s.resources.Count(), gc.Equals, 0)
  1337  
  1338  	_, err := s.provisioner.WatchMachineErrorRetry()
  1339  	c.Assert(err, gc.IsNil)
  1340  
  1341  	// Verify the resources were registered and stop them when done.
  1342  	c.Assert(s.resources.Count(), gc.Equals, 1)
  1343  	resource := s.resources.Get("1")
  1344  	defer statetesting.AssertStop(c, resource)
  1345  
  1346  	// Check that the Watch has consumed the initial event ("returned"
  1347  	// in the Watch call)
  1348  	wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher))
  1349  	wc.AssertNoChange()
  1350  
  1351  	// We should now get a time triggered change.
  1352  	wc.AssertOneChange()
  1353  
  1354  	// Make sure WatchMachineErrorRetry fails with a machine agent login.
  1355  	anAuthorizer := s.authorizer
  1356  	anAuthorizer.MachineAgent = true
  1357  	anAuthorizer.EnvironManager = false
  1358  	aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer)
  1359  	c.Assert(err, gc.IsNil)
  1360  
  1361  	result, err := aProvisioner.WatchMachineErrorRetry()
  1362  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1363  	c.Assert(result, gc.DeepEquals, params.NotifyWatchResult{})
  1364  }