github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/api/provisioner/provisioner_test.go (about)

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