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