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