github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/state/api/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  	stdtesting "testing"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils"
    13  	gc "launchpad.net/gocheck"
    14  
    15  	"github.com/juju/juju/constraints"
    16  	"github.com/juju/juju/container"
    17  	"github.com/juju/juju/instance"
    18  	"github.com/juju/juju/juju/testing"
    19  	"github.com/juju/juju/mongo"
    20  	"github.com/juju/juju/network"
    21  	"github.com/juju/juju/state"
    22  	"github.com/juju/juju/state/api"
    23  	"github.com/juju/juju/state/api/params"
    24  	"github.com/juju/juju/state/api/provisioner"
    25  	apitesting "github.com/juju/juju/state/api/testing"
    26  	statetesting "github.com/juju/juju/state/testing"
    27  	coretesting "github.com/juju/juju/testing"
    28  	"github.com/juju/juju/tools"
    29  	"github.com/juju/juju/version"
    30  )
    31  
    32  func TestAll(t *stdtesting.T) {
    33  	coretesting.MgoTestPackage(t)
    34  }
    35  
    36  type provisionerSuite struct {
    37  	testing.JujuConnSuite
    38  	*apitesting.EnvironWatcherTests
    39  	*apitesting.APIAddresserTests
    40  
    41  	st      *api.State
    42  	machine *state.Machine
    43  
    44  	provisioner *provisioner.State
    45  }
    46  
    47  var _ = gc.Suite(&provisionerSuite{})
    48  
    49  func (s *provisionerSuite) SetUpTest(c *gc.C) {
    50  	s.JujuConnSuite.SetUpTest(c)
    51  
    52  	var err error
    53  	s.machine, err = s.State.AddMachine("quantal", state.JobManageEnviron)
    54  	c.Assert(err, gc.IsNil)
    55  	password, err := utils.RandomPassword()
    56  	c.Assert(err, gc.IsNil)
    57  	err = s.machine.SetPassword(password)
    58  	c.Assert(err, gc.IsNil)
    59  	err = s.machine.SetInstanceInfo("i-manager", "fake_nonce", nil, nil, nil)
    60  	c.Assert(err, gc.IsNil)
    61  	s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce")
    62  	c.Assert(s.st, gc.NotNil)
    63  	err = s.machine.SetAddresses(network.NewAddress("0.1.2.3", network.ScopeUnknown))
    64  	c.Assert(err, gc.IsNil)
    65  
    66  	// Create the provisioner API facade.
    67  	s.provisioner = s.st.Provisioner()
    68  	c.Assert(s.provisioner, gc.NotNil)
    69  
    70  	s.EnvironWatcherTests = apitesting.NewEnvironWatcherTests(s.provisioner, s.BackingState, apitesting.HasSecrets)
    71  	s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState)
    72  }
    73  
    74  func (s *provisionerSuite) TestMachineTagAndId(c *gc.C) {
    75  	apiMachine, err := s.provisioner.Machine("machine-42")
    76  	c.Assert(err, gc.ErrorMatches, "machine 42 not found")
    77  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
    78  	c.Assert(apiMachine, gc.IsNil)
    79  
    80  	apiMachine, err = s.provisioner.Machine(s.machine.Tag())
    81  	c.Assert(err, gc.IsNil)
    82  	c.Assert(apiMachine.Tag(), gc.Equals, s.machine.Tag())
    83  	c.Assert(apiMachine.Id(), gc.Equals, s.machine.Id())
    84  }
    85  
    86  func (s *provisionerSuite) TestGetSetStatus(c *gc.C) {
    87  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
    88  	c.Assert(err, gc.IsNil)
    89  
    90  	status, info, err := apiMachine.Status()
    91  	c.Assert(err, gc.IsNil)
    92  	c.Assert(status, gc.Equals, params.StatusPending)
    93  	c.Assert(info, gc.Equals, "")
    94  
    95  	err = apiMachine.SetStatus(params.StatusStarted, "blah", nil)
    96  	c.Assert(err, gc.IsNil)
    97  
    98  	status, info, err = apiMachine.Status()
    99  	c.Assert(err, gc.IsNil)
   100  	c.Assert(status, gc.Equals, params.StatusStarted)
   101  	c.Assert(info, gc.Equals, "blah")
   102  	_, _, data, err := s.machine.Status()
   103  	c.Assert(err, gc.IsNil)
   104  	c.Assert(data, gc.HasLen, 0)
   105  }
   106  
   107  func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) {
   108  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   109  	c.Assert(err, gc.IsNil)
   110  
   111  	err = apiMachine.SetStatus(params.StatusError, "blah", params.StatusData{"foo": "bar"})
   112  	c.Assert(err, gc.IsNil)
   113  
   114  	status, info, err := apiMachine.Status()
   115  	c.Assert(err, gc.IsNil)
   116  	c.Assert(status, gc.Equals, params.StatusError)
   117  	c.Assert(info, gc.Equals, "blah")
   118  	_, _, data, err := s.machine.Status()
   119  	c.Assert(err, gc.IsNil)
   120  	c.Assert(data, gc.DeepEquals, params.StatusData{"foo": "bar"})
   121  }
   122  
   123  func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) {
   124  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   125  	c.Assert(err, gc.IsNil)
   126  	err = machine.SetStatus(params.StatusError, "blah", params.StatusData{"transient": true})
   127  	c.Assert(err, gc.IsNil)
   128  	machines, info, err := s.provisioner.MachinesWithTransientErrors()
   129  	c.Assert(err, gc.IsNil)
   130  	c.Assert(machines, gc.HasLen, 1)
   131  	c.Assert(machines[0].Id(), gc.Equals, "1")
   132  	c.Assert(info, gc.HasLen, 1)
   133  	c.Assert(info[0], gc.DeepEquals, params.StatusResult{
   134  		Id:     "1",
   135  		Life:   "alive",
   136  		Status: "error",
   137  		Info:   "blah",
   138  		Data:   params.StatusData{"transient": true},
   139  	})
   140  }
   141  
   142  func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) {
   143  	// Create a fresh machine to test the complete scenario.
   144  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   145  	c.Assert(err, gc.IsNil)
   146  	c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
   147  
   148  	apiMachine, err := s.provisioner.Machine(otherMachine.Tag())
   149  	c.Assert(err, gc.IsNil)
   150  
   151  	err = apiMachine.Remove()
   152  	c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`)
   153  	err = apiMachine.EnsureDead()
   154  	c.Assert(err, gc.IsNil)
   155  
   156  	err = otherMachine.Refresh()
   157  	c.Assert(err, gc.IsNil)
   158  	c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
   159  
   160  	err = apiMachine.EnsureDead()
   161  	c.Assert(err, gc.IsNil)
   162  	err = otherMachine.Refresh()
   163  	c.Assert(err, gc.IsNil)
   164  	c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
   165  
   166  	err = apiMachine.Remove()
   167  	c.Assert(err, gc.IsNil)
   168  	err = otherMachine.Refresh()
   169  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   170  
   171  	err = apiMachine.EnsureDead()
   172  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   173  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   174  
   175  	// Now try to EnsureDead machine 0 - should fail.
   176  	apiMachine, err = s.provisioner.Machine(s.machine.Tag())
   177  	c.Assert(err, gc.IsNil)
   178  	err = apiMachine.EnsureDead()
   179  	c.Assert(err, gc.ErrorMatches, "machine 0 is required by the environment")
   180  }
   181  
   182  func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) {
   183  	// Create a fresh machine to test the complete scenario.
   184  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   185  	c.Assert(err, gc.IsNil)
   186  	c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
   187  
   188  	apiMachine, err := s.provisioner.Machine(otherMachine.Tag())
   189  	c.Assert(err, gc.IsNil)
   190  	c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
   191  
   192  	err = apiMachine.EnsureDead()
   193  	c.Assert(err, gc.IsNil)
   194  	c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
   195  
   196  	err = apiMachine.Refresh()
   197  	c.Assert(err, gc.IsNil)
   198  	c.Assert(apiMachine.Life(), gc.Equals, params.Dead)
   199  }
   200  
   201  func (s *provisionerSuite) TestSetInstanceInfo(c *gc.C) {
   202  	// Create a fresh machine, since machine 0 is already provisioned.
   203  	notProvisionedMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   204  	c.Assert(err, gc.IsNil)
   205  
   206  	apiMachine, err := s.provisioner.Machine(notProvisionedMachine.Tag())
   207  	c.Assert(err, gc.IsNil)
   208  
   209  	instanceId, err := apiMachine.InstanceId()
   210  	c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned)
   211  	c.Assert(err, gc.ErrorMatches, "machine 1 is not provisioned")
   212  	c.Assert(instanceId, gc.Equals, instance.Id(""))
   213  
   214  	hwChars := instance.MustParseHardware("cpu-cores=123", "mem=4G")
   215  
   216  	_, err = s.State.Network("net1")
   217  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   218  	_, err = s.State.Network("vlan42")
   219  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   220  
   221  	ifacesMachine, err := notProvisionedMachine.NetworkInterfaces()
   222  	c.Assert(err, gc.IsNil)
   223  	c.Assert(ifacesMachine, gc.HasLen, 0)
   224  
   225  	networks := []params.Network{{
   226  		Tag:        "network-net1",
   227  		ProviderId: "net1",
   228  		CIDR:       "0.1.2.0/24",
   229  		VLANTag:    0,
   230  	}, {
   231  		Tag:        "network-vlan42",
   232  		ProviderId: "vlan42",
   233  		CIDR:       "0.2.2.0/24",
   234  		VLANTag:    42,
   235  	}, {
   236  		Tag:        "network-vlan69",
   237  		ProviderId: "vlan69",
   238  		CIDR:       "0.3.2.0/24",
   239  		VLANTag:    69,
   240  	}, {
   241  		Tag:        "network-vlan42", // duplicated; ignored
   242  		ProviderId: "vlan42",
   243  		CIDR:       "0.2.2.0/24",
   244  		VLANTag:    42,
   245  	}}
   246  	ifaces := []params.NetworkInterface{{
   247  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   248  		NetworkTag:    "network-net1",
   249  		InterfaceName: "eth0",
   250  		IsVirtual:     false,
   251  	}, {
   252  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   253  		NetworkTag:    "network-net1",
   254  		InterfaceName: "eth1",
   255  		IsVirtual:     false,
   256  	}, {
   257  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   258  		NetworkTag:    "network-vlan42",
   259  		InterfaceName: "eth1.42",
   260  		IsVirtual:     true,
   261  	}, {
   262  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   263  		NetworkTag:    "network-vlan69",
   264  		InterfaceName: "eth1.69",
   265  		IsVirtual:     true,
   266  	}, {
   267  		MACAddress:    "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored
   268  		NetworkTag:    "network-vlan42",
   269  		InterfaceName: "eth2",
   270  		IsVirtual:     true,
   271  	}, {
   272  		MACAddress:    "aa:bb:cc:dd:ee:f4",
   273  		NetworkTag:    "network-net1",
   274  		InterfaceName: "eth1", // duplicated name+machine id; ignored
   275  		IsVirtual:     false,
   276  	}}
   277  
   278  	err = apiMachine.SetInstanceInfo("i-will", "fake_nonce", &hwChars, networks, ifaces)
   279  	c.Assert(err, gc.IsNil)
   280  
   281  	instanceId, err = apiMachine.InstanceId()
   282  	c.Assert(err, gc.IsNil)
   283  	c.Assert(instanceId, gc.Equals, instance.Id("i-will"))
   284  
   285  	// Try it again - should fail.
   286  	err = apiMachine.SetInstanceInfo("i-wont", "fake", nil, nil, nil)
   287  	c.Assert(err, gc.ErrorMatches, `aborted instance "i-wont": cannot set instance data for machine "1": already set`)
   288  
   289  	// Now try to get machine 0's instance id.
   290  	apiMachine, err = s.provisioner.Machine(s.machine.Tag())
   291  	c.Assert(err, gc.IsNil)
   292  	instanceId, err = apiMachine.InstanceId()
   293  	c.Assert(err, gc.IsNil)
   294  	c.Assert(instanceId, gc.Equals, instance.Id("i-manager"))
   295  
   296  	// Check the networks are created.
   297  	for i, _ := range networks {
   298  		if i == 3 {
   299  			// Last one was ignored, so skip it.
   300  			break
   301  		}
   302  		tag, err := names.ParseTag(networks[i].Tag, names.NetworkTagKind)
   303  		c.Assert(err, gc.IsNil)
   304  		networkName := tag.Id()
   305  		network, err := s.State.Network(networkName)
   306  		c.Assert(err, gc.IsNil)
   307  		c.Check(network.Name(), gc.Equals, networkName)
   308  		c.Check(network.ProviderId(), gc.Equals, networks[i].ProviderId)
   309  		c.Check(network.Tag(), gc.Equals, networks[i].Tag)
   310  		c.Check(network.VLANTag(), gc.Equals, networks[i].VLANTag)
   311  		c.Check(network.CIDR(), gc.Equals, networks[i].CIDR)
   312  	}
   313  
   314  	// And the network interfaces as well.
   315  	ifacesMachine, err = notProvisionedMachine.NetworkInterfaces()
   316  	c.Assert(err, gc.IsNil)
   317  	c.Assert(ifacesMachine, gc.HasLen, 4)
   318  	actual := make([]params.NetworkInterface, len(ifacesMachine))
   319  	for i, iface := range ifacesMachine {
   320  		actual[i].InterfaceName = iface.InterfaceName()
   321  		actual[i].NetworkTag = iface.NetworkTag()
   322  		actual[i].MACAddress = iface.MACAddress()
   323  		actual[i].IsVirtual = iface.IsVirtual()
   324  		c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag())
   325  		c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id())
   326  	}
   327  	c.Assert(actual, jc.SameContents, ifaces[:4]) // skip the rest as they are ignored.
   328  }
   329  
   330  func (s *provisionerSuite) TestSeries(c *gc.C) {
   331  	// Create a fresh machine with different series.
   332  	foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits)
   333  	c.Assert(err, gc.IsNil)
   334  
   335  	apiMachine, err := s.provisioner.Machine(foobarMachine.Tag())
   336  	c.Assert(err, gc.IsNil)
   337  	series, err := apiMachine.Series()
   338  	c.Assert(err, gc.IsNil)
   339  	c.Assert(series, gc.Equals, "foobar")
   340  
   341  	// Now try machine 0.
   342  	apiMachine, err = s.provisioner.Machine(s.machine.Tag())
   343  	c.Assert(err, gc.IsNil)
   344  	series, err = apiMachine.Series()
   345  	c.Assert(err, gc.IsNil)
   346  	c.Assert(series, gc.Equals, "quantal")
   347  }
   348  
   349  func (s *provisionerSuite) TestDistributionGroup(c *gc.C) {
   350  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   351  	c.Assert(err, gc.IsNil)
   352  	instances, err := apiMachine.DistributionGroup()
   353  	c.Assert(err, gc.IsNil)
   354  	c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"})
   355  
   356  	machine1, err := s.State.AddMachine("quantal", state.JobHostUnits)
   357  	c.Assert(err, gc.IsNil)
   358  	apiMachine, err = s.provisioner.Machine(machine1.Tag())
   359  	c.Assert(err, gc.IsNil)
   360  	wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   361  
   362  	err = apiMachine.SetInstanceInfo("i-d", "fake", nil, nil, nil)
   363  	c.Assert(err, gc.IsNil)
   364  	instances, err = apiMachine.DistributionGroup()
   365  	c.Assert(err, gc.IsNil)
   366  	c.Assert(instances, gc.HasLen, 0) // no units assigned
   367  
   368  	var unitNames []string
   369  	for i := 0; i < 3; i++ {
   370  		unit, err := wordpress.AddUnit()
   371  		c.Assert(err, gc.IsNil)
   372  		unitNames = append(unitNames, unit.Name())
   373  		err = unit.AssignToMachine(machine1)
   374  		c.Assert(err, gc.IsNil)
   375  		instances, err := apiMachine.DistributionGroup()
   376  		c.Assert(err, gc.IsNil)
   377  		c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"})
   378  	}
   379  }
   380  
   381  func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) {
   382  	stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   383  	c.Assert(err, gc.IsNil)
   384  	apiMachine, err := s.provisioner.Machine(stateMachine.Tag())
   385  	c.Assert(err, gc.IsNil)
   386  	err = apiMachine.EnsureDead()
   387  	c.Assert(err, gc.IsNil)
   388  	err = apiMachine.Remove()
   389  	c.Assert(err, gc.IsNil)
   390  	_, err = apiMachine.DistributionGroup()
   391  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   392  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   393  }
   394  
   395  func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) {
   396  	cons := constraints.MustParse("cpu-cores=12 mem=8G networks=^net3,^net4")
   397  	template := state.MachineTemplate{
   398  		Series:            "quantal",
   399  		Jobs:              []state.MachineJob{state.JobHostUnits},
   400  		Placement:         "valid",
   401  		Constraints:       cons,
   402  		RequestedNetworks: []string{"net1", "net2"},
   403  	}
   404  	machine, err := s.State.AddOneMachine(template)
   405  	c.Assert(err, gc.IsNil)
   406  	apiMachine, err := s.provisioner.Machine(machine.Tag())
   407  	c.Assert(err, gc.IsNil)
   408  	provisioningInfo, err := apiMachine.ProvisioningInfo()
   409  	c.Assert(err, gc.IsNil)
   410  	c.Assert(provisioningInfo.Series, gc.Equals, template.Series)
   411  	c.Assert(provisioningInfo.Placement, gc.Equals, template.Placement)
   412  	c.Assert(provisioningInfo.Constraints, gc.DeepEquals, template.Constraints)
   413  	c.Assert(provisioningInfo.Networks, gc.DeepEquals, template.RequestedNetworks)
   414  }
   415  
   416  func (s *provisionerSuite) TestProvisioningInfoMachineNotFound(c *gc.C) {
   417  	stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   418  	c.Assert(err, gc.IsNil)
   419  	apiMachine, err := s.provisioner.Machine(stateMachine.Tag())
   420  	c.Assert(err, gc.IsNil)
   421  	err = apiMachine.EnsureDead()
   422  	c.Assert(err, gc.IsNil)
   423  	err = apiMachine.Remove()
   424  	c.Assert(err, gc.IsNil)
   425  	_, err = apiMachine.ProvisioningInfo()
   426  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   427  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   428  	// auth tests in apiserver
   429  }
   430  
   431  func (s *provisionerSuite) TestWatchContainers(c *gc.C) {
   432  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   433  	c.Assert(err, gc.IsNil)
   434  
   435  	// Add one LXC container.
   436  	template := state.MachineTemplate{
   437  		Series: "quantal",
   438  		Jobs:   []state.MachineJob{state.JobHostUnits},
   439  	}
   440  	container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   441  	c.Assert(err, gc.IsNil)
   442  
   443  	w, err := apiMachine.WatchContainers(instance.LXC)
   444  	c.Assert(err, gc.IsNil)
   445  	defer statetesting.AssertStop(c, w)
   446  	wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
   447  
   448  	// Initial event.
   449  	wc.AssertChange(container.Id())
   450  
   451  	// Change something other than the containers and make sure it's
   452  	// not detected.
   453  	err = apiMachine.SetStatus(params.StatusStarted, "not really", nil)
   454  	c.Assert(err, gc.IsNil)
   455  	wc.AssertNoChange()
   456  
   457  	// Add a KVM container and make sure it's not detected.
   458  	container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.KVM)
   459  	c.Assert(err, gc.IsNil)
   460  	wc.AssertNoChange()
   461  
   462  	// Add another LXC container and make sure it's detected.
   463  	container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   464  	c.Assert(err, gc.IsNil)
   465  	wc.AssertChange(container.Id())
   466  
   467  	statetesting.AssertStop(c, w)
   468  	wc.AssertClosed()
   469  }
   470  
   471  func (s *provisionerSuite) TestWatchContainersAcceptsSupportedContainers(c *gc.C) {
   472  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   473  	c.Assert(err, gc.IsNil)
   474  
   475  	for _, ctype := range instance.ContainerTypes {
   476  		w, err := apiMachine.WatchContainers(ctype)
   477  		c.Assert(w, gc.NotNil)
   478  		c.Assert(err, gc.IsNil)
   479  	}
   480  }
   481  
   482  func (s *provisionerSuite) TestWatchContainersErrors(c *gc.C) {
   483  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   484  	c.Assert(err, gc.IsNil)
   485  
   486  	_, err = apiMachine.WatchContainers(instance.NONE)
   487  	c.Assert(err, gc.ErrorMatches, `unsupported container type "none"`)
   488  
   489  	_, err = apiMachine.WatchContainers("")
   490  	c.Assert(err, gc.ErrorMatches, "container type must be specified")
   491  }
   492  
   493  func (s *provisionerSuite) TestWatchEnvironMachines(c *gc.C) {
   494  	w, err := s.provisioner.WatchEnvironMachines()
   495  	c.Assert(err, gc.IsNil)
   496  	defer statetesting.AssertStop(c, w)
   497  	wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
   498  
   499  	// Initial event.
   500  	wc.AssertChange(s.machine.Id())
   501  
   502  	// Add another 2 machines make sure they are detected.
   503  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   504  	c.Assert(err, gc.IsNil)
   505  	otherMachine, err = s.State.AddMachine("quantal", state.JobHostUnits)
   506  	c.Assert(err, gc.IsNil)
   507  	wc.AssertChange("1", "2")
   508  
   509  	// Change the lifecycle of last machine.
   510  	err = otherMachine.EnsureDead()
   511  	c.Assert(err, gc.IsNil)
   512  	wc.AssertChange("2")
   513  
   514  	// Add a container and make sure it's not detected.
   515  	template := state.MachineTemplate{
   516  		Series: "quantal",
   517  		Jobs:   []state.MachineJob{state.JobHostUnits},
   518  	}
   519  	_, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   520  	c.Assert(err, gc.IsNil)
   521  	wc.AssertNoChange()
   522  
   523  	statetesting.AssertStop(c, w)
   524  	wc.AssertClosed()
   525  }
   526  
   527  func (s *provisionerSuite) TestStateAddresses(c *gc.C) {
   528  	err := s.machine.SetAddresses(network.NewAddress("0.1.2.3", network.ScopeUnknown))
   529  	c.Assert(err, gc.IsNil)
   530  
   531  	stateAddresses, err := s.State.Addresses()
   532  	c.Assert(err, gc.IsNil)
   533  
   534  	addresses, err := s.provisioner.StateAddresses()
   535  	c.Assert(err, gc.IsNil)
   536  	c.Assert(addresses, gc.DeepEquals, stateAddresses)
   537  }
   538  
   539  func (s *provisionerSuite) TestContainerManagerConfigKVM(c *gc.C) {
   540  	args := params.ContainerManagerConfigParams{Type: instance.KVM}
   541  	result, err := s.provisioner.ContainerManagerConfig(args)
   542  	c.Assert(err, gc.IsNil)
   543  	c.Assert(result.ManagerConfig, gc.DeepEquals, map[string]string{
   544  		container.ConfigName: "juju",
   545  	})
   546  }
   547  
   548  func (s *provisionerSuite) TestContainerManagerConfigLXC(c *gc.C) {
   549  	args := params.ContainerManagerConfigParams{Type: instance.LXC}
   550  	st, err := state.Open(s.StateInfo(c), mongo.DialOpts{}, state.Policy(nil))
   551  	c.Assert(err, gc.IsNil)
   552  	defer st.Close()
   553  
   554  	tests := []struct {
   555  		lxcUseClone          bool
   556  		lxcUseCloneAufs      bool
   557  		expectedUseClone     string
   558  		expectedUseCloneAufs string
   559  	}{{
   560  		lxcUseClone:          true,
   561  		expectedUseClone:     "true",
   562  		expectedUseCloneAufs: "false",
   563  	}, {
   564  		lxcUseClone:          false,
   565  		expectedUseClone:     "false",
   566  		expectedUseCloneAufs: "false",
   567  	}, {
   568  		lxcUseCloneAufs:      false,
   569  		expectedUseClone:     "false",
   570  		expectedUseCloneAufs: "false",
   571  	}, {
   572  		lxcUseClone:          true,
   573  		lxcUseCloneAufs:      true,
   574  		expectedUseClone:     "true",
   575  		expectedUseCloneAufs: "true",
   576  	}}
   577  
   578  	result, err := s.provisioner.ContainerManagerConfig(args)
   579  	c.Assert(err, gc.IsNil)
   580  	c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju")
   581  	c.Assert(result.ManagerConfig["use-clone"], gc.Equals, "")
   582  
   583  	// Change lxc-clone, and ensure it gets picked up.
   584  	for i, t := range tests {
   585  		c.Logf("test %d: %+v", i, t)
   586  		err = st.UpdateEnvironConfig(map[string]interface{}{
   587  			"lxc-clone":      t.lxcUseClone,
   588  			"lxc-clone-aufs": t.lxcUseCloneAufs,
   589  		}, nil, nil)
   590  		c.Assert(err, gc.IsNil)
   591  		result, err := s.provisioner.ContainerManagerConfig(args)
   592  		c.Assert(err, gc.IsNil)
   593  		c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju")
   594  		c.Assert(result.ManagerConfig["use-clone"], gc.Equals, t.expectedUseClone)
   595  		c.Assert(result.ManagerConfig["use-aufs"], gc.Equals, t.expectedUseCloneAufs)
   596  	}
   597  }
   598  
   599  func (s *provisionerSuite) TestContainerManagerConfigPermissive(c *gc.C) {
   600  	// ContainerManagerConfig is permissive of container types, and
   601  	// will just return the basic type-independent configuration.
   602  	args := params.ContainerManagerConfigParams{Type: "invalid"}
   603  	result, err := s.provisioner.ContainerManagerConfig(args)
   604  	c.Assert(err, gc.IsNil)
   605  	c.Assert(result.ManagerConfig, gc.DeepEquals, map[string]string{
   606  		container.ConfigName: "juju",
   607  	})
   608  }
   609  
   610  func (s *provisionerSuite) TestContainerConfig(c *gc.C) {
   611  	result, err := s.provisioner.ContainerConfig()
   612  	c.Assert(err, gc.IsNil)
   613  	c.Assert(result.ProviderType, gc.Equals, "dummy")
   614  	c.Assert(result.AuthorizedKeys, gc.Equals, coretesting.FakeAuthKeys)
   615  	c.Assert(result.SSLHostnameVerification, jc.IsTrue)
   616  }
   617  
   618  func (s *provisionerSuite) TestToolsWrongMachine(c *gc.C) {
   619  	tools, err := s.provisioner.Tools("42")
   620  	c.Assert(err, gc.ErrorMatches, "permission denied")
   621  	c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
   622  	c.Assert(tools, gc.IsNil)
   623  }
   624  
   625  func (s *provisionerSuite) TestTools(c *gc.C) {
   626  	cur := version.Current
   627  	curTools := &tools.Tools{Version: cur, URL: ""}
   628  	curTools.Version.Minor++
   629  	s.machine.SetAgentVersion(cur)
   630  	// Provisioner.Tools returns the *desired* set of tools, not the
   631  	// currently running set. We want to be upgraded to cur.Version
   632  	stateTools, err := s.provisioner.Tools(s.machine.Tag())
   633  	c.Assert(err, gc.IsNil)
   634  	c.Assert(stateTools.Version, gc.Equals, cur)
   635  	c.Assert(stateTools.URL, gc.Not(gc.Equals), "")
   636  }
   637  
   638  func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) {
   639  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   640  	c.Assert(err, gc.IsNil)
   641  	err = apiMachine.SetSupportedContainers(instance.LXC, instance.KVM)
   642  	c.Assert(err, gc.IsNil)
   643  
   644  	err = s.machine.Refresh()
   645  	c.Assert(err, gc.IsNil)
   646  	containers, ok := s.machine.SupportedContainers()
   647  	c.Assert(ok, jc.IsTrue)
   648  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM})
   649  }
   650  
   651  func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) {
   652  	apiMachine, err := s.provisioner.Machine(s.machine.Tag())
   653  	c.Assert(err, gc.IsNil)
   654  	err = apiMachine.SupportsNoContainers()
   655  	c.Assert(err, gc.IsNil)
   656  
   657  	err = s.machine.Refresh()
   658  	c.Assert(err, gc.IsNil)
   659  	containers, ok := s.machine.SupportedContainers()
   660  	c.Assert(ok, jc.IsTrue)
   661  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{})
   662  }