github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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  	"fmt"
    13  	stdtesting "testing"
    14  
    15  	"github.com/juju/errors"
    16  	"github.com/juju/names"
    17  	jc "github.com/juju/testing/checkers"
    18  	"github.com/juju/utils"
    19  	gc "gopkg.in/check.v1"
    20  
    21  	"github.com/juju/juju/api"
    22  	"github.com/juju/juju/api/provisioner"
    23  	apitesting "github.com/juju/juju/api/testing"
    24  	"github.com/juju/juju/apiserver/common"
    25  	"github.com/juju/juju/apiserver/params"
    26  	"github.com/juju/juju/constraints"
    27  	"github.com/juju/juju/container"
    28  	"github.com/juju/juju/feature"
    29  	"github.com/juju/juju/instance"
    30  	"github.com/juju/juju/juju/testing"
    31  	"github.com/juju/juju/mongo"
    32  	"github.com/juju/juju/network"
    33  	"github.com/juju/juju/state"
    34  	statetesting "github.com/juju/juju/state/testing"
    35  	"github.com/juju/juju/storage/poolmanager"
    36  	"github.com/juju/juju/storage/provider"
    37  	coretesting "github.com/juju/juju/testing"
    38  	coretools "github.com/juju/juju/tools"
    39  	"github.com/juju/juju/version"
    40  )
    41  
    42  func TestAll(t *stdtesting.T) {
    43  	coretesting.MgoTestPackage(t)
    44  }
    45  
    46  type provisionerSuite struct {
    47  	testing.JujuConnSuite
    48  	*apitesting.EnvironWatcherTests
    49  	*apitesting.APIAddresserTests
    50  
    51  	st      *api.State
    52  	machine *state.Machine
    53  
    54  	provisioner *provisioner.State
    55  }
    56  
    57  var _ = gc.Suite(&provisionerSuite{})
    58  
    59  func (s *provisionerSuite) SetUpTest(c *gc.C) {
    60  	s.JujuConnSuite.SetUpTest(c)
    61  	// We're testing with address allocation on by default. There are
    62  	// separate tests to check the behavior when the flag is not
    63  	// enabled.
    64  	s.SetFeatureFlags(feature.AddressAllocation)
    65  
    66  	var err error
    67  	s.machine, err = s.State.AddMachine("quantal", state.JobManageEnviron)
    68  	c.Assert(err, jc.ErrorIsNil)
    69  	password, err := utils.RandomPassword()
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	err = s.machine.SetPassword(password)
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	err = s.machine.SetInstanceInfo("i-manager", "fake_nonce", nil, nil, nil, nil, nil)
    74  	c.Assert(err, jc.ErrorIsNil)
    75  	s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce")
    76  	c.Assert(s.st, gc.NotNil)
    77  	err = s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3"))
    78  	c.Assert(err, jc.ErrorIsNil)
    79  
    80  	// Create the provisioner API facade.
    81  	s.provisioner = s.st.Provisioner()
    82  	c.Assert(s.provisioner, gc.NotNil)
    83  
    84  	s.EnvironWatcherTests = apitesting.NewEnvironWatcherTests(s.provisioner, s.BackingState, apitesting.HasSecrets)
    85  	s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState)
    86  }
    87  
    88  func (s *provisionerSuite) TestPrepareContainerInterfaceInfoNoFeatureFlag(c *gc.C) {
    89  	s.SetFeatureFlags() // clear the flag
    90  	ifaceInfo, err := s.provisioner.PrepareContainerInterfaceInfo(names.NewMachineTag("42"))
    91  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
    92  	c.Assert(ifaceInfo, gc.HasLen, 0)
    93  }
    94  
    95  func (s *provisionerSuite) TestReleaseContainerAddressNoFeatureFlag(c *gc.C) {
    96  	s.SetFeatureFlags() // clear the flag
    97  	err := s.provisioner.ReleaseContainerAddresses(names.NewMachineTag("42"))
    98  	c.Assert(err, gc.ErrorMatches,
    99  		`cannot release static addresses for "42": address allocation not supported`,
   100  	)
   101  }
   102  
   103  func (s *provisionerSuite) TestMachineTagAndId(c *gc.C) {
   104  	apiMachine, err := s.provisioner.Machine(names.NewMachineTag("42"))
   105  	c.Assert(err, gc.ErrorMatches, "machine 42 not found")
   106  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   107  	c.Assert(apiMachine, gc.IsNil)
   108  
   109  	// TODO(dfc) fix this type assertion
   110  	apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	c.Assert(apiMachine.Tag(), gc.Equals, s.machine.Tag())
   113  	c.Assert(apiMachine.Id(), gc.Equals, s.machine.Id())
   114  }
   115  
   116  func (s *provisionerSuite) TestGetSetStatus(c *gc.C) {
   117  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   118  	c.Assert(err, jc.ErrorIsNil)
   119  
   120  	status, info, err := apiMachine.Status()
   121  	c.Assert(err, jc.ErrorIsNil)
   122  	c.Assert(status, gc.Equals, params.StatusPending)
   123  	c.Assert(info, gc.Equals, "")
   124  
   125  	err = apiMachine.SetStatus(params.StatusStarted, "blah", nil)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  
   128  	status, info, err = apiMachine.Status()
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	c.Assert(status, gc.Equals, params.StatusStarted)
   131  	c.Assert(info, gc.Equals, "blah")
   132  	statusInfo, err := s.machine.Status()
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   135  }
   136  
   137  func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) {
   138  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   139  	c.Assert(err, jc.ErrorIsNil)
   140  
   141  	err = apiMachine.SetStatus(params.StatusError, "blah", map[string]interface{}{"foo": "bar"})
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	status, info, err := apiMachine.Status()
   145  	c.Assert(err, jc.ErrorIsNil)
   146  	c.Assert(status, gc.Equals, params.StatusError)
   147  	c.Assert(info, gc.Equals, "blah")
   148  	statusInfo, err := s.machine.Status()
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"foo": "bar"})
   151  }
   152  
   153  func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) {
   154  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	err = machine.SetStatus(state.StatusError, "blah", map[string]interface{}{"transient": true})
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	machines, info, err := s.provisioner.MachinesWithTransientErrors()
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	c.Assert(machines, gc.HasLen, 1)
   161  	c.Assert(machines[0].Id(), gc.Equals, "1")
   162  	c.Assert(info, gc.HasLen, 1)
   163  	c.Assert(info[0], gc.DeepEquals, params.StatusResult{
   164  		Id:     "1",
   165  		Life:   "alive",
   166  		Status: "error",
   167  		Info:   "blah",
   168  		Data:   map[string]interface{}{"transient": true},
   169  	})
   170  }
   171  
   172  func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) {
   173  	// Create a fresh machine to test the complete scenario.
   174  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
   177  
   178  	apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag))
   179  	c.Assert(err, jc.ErrorIsNil)
   180  
   181  	err = apiMachine.Remove()
   182  	c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`)
   183  	err = apiMachine.EnsureDead()
   184  	c.Assert(err, jc.ErrorIsNil)
   185  
   186  	err = otherMachine.Refresh()
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
   189  
   190  	err = apiMachine.EnsureDead()
   191  	c.Assert(err, jc.ErrorIsNil)
   192  	err = otherMachine.Refresh()
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	c.Assert(otherMachine.Life(), gc.Equals, state.Dead)
   195  
   196  	err = apiMachine.Remove()
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	err = otherMachine.Refresh()
   199  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   200  
   201  	err = apiMachine.EnsureDead()
   202  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   203  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   204  
   205  	// Now try to EnsureDead machine 0 - should fail.
   206  	apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	err = apiMachine.EnsureDead()
   209  	c.Assert(err, gc.ErrorMatches, "machine 0 is required by the environment")
   210  }
   211  
   212  func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) {
   213  	// Create a fresh machine to test the complete scenario.
   214  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	c.Assert(otherMachine.Life(), gc.Equals, state.Alive)
   217  
   218  	apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag))
   219  	c.Assert(err, jc.ErrorIsNil)
   220  	c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
   221  
   222  	err = apiMachine.EnsureDead()
   223  	c.Assert(err, jc.ErrorIsNil)
   224  	c.Assert(apiMachine.Life(), gc.Equals, params.Alive)
   225  
   226  	err = apiMachine.Refresh()
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	c.Assert(apiMachine.Life(), gc.Equals, params.Dead)
   229  }
   230  
   231  func (s *provisionerSuite) TestSetInstanceInfo(c *gc.C) {
   232  	pm := poolmanager.New(state.NewStateSettings(s.State))
   233  	_, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"})
   234  	c.Assert(err, jc.ErrorIsNil)
   235  
   236  	// Create a fresh machine, since machine 0 is already provisioned.
   237  	template := state.MachineTemplate{
   238  		Series: "quantal",
   239  		Jobs:   []state.MachineJob{state.JobHostUnits},
   240  		Volumes: []state.MachineVolumeParams{{
   241  			Volume: state.VolumeParams{
   242  				Pool: "loop-pool",
   243  				Size: 123,
   244  			}},
   245  		},
   246  	}
   247  	notProvisionedMachine, err := s.State.AddOneMachine(template)
   248  	c.Assert(err, jc.ErrorIsNil)
   249  
   250  	apiMachine, err := s.provisioner.Machine(notProvisionedMachine.Tag().(names.MachineTag))
   251  	c.Assert(err, jc.ErrorIsNil)
   252  
   253  	instanceId, err := apiMachine.InstanceId()
   254  	c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned)
   255  	c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned")
   256  	c.Assert(instanceId, gc.Equals, instance.Id(""))
   257  
   258  	hwChars := instance.MustParseHardware("cpu-cores=123", "mem=4G")
   259  
   260  	_, err = s.State.Network("net1")
   261  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   262  	_, err = s.State.Network("vlan42")
   263  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   264  
   265  	ifacesMachine, err := notProvisionedMachine.NetworkInterfaces()
   266  	c.Assert(err, jc.ErrorIsNil)
   267  	c.Assert(ifacesMachine, gc.HasLen, 0)
   268  
   269  	networks := []params.Network{{
   270  		Tag:        "network-net1",
   271  		ProviderId: "net1",
   272  		CIDR:       "0.1.2.0/24",
   273  		VLANTag:    0,
   274  	}, {
   275  		Tag:        "network-vlan42",
   276  		ProviderId: "vlan42",
   277  		CIDR:       "0.2.2.0/24",
   278  		VLANTag:    42,
   279  	}, {
   280  		Tag:        "network-vlan69",
   281  		ProviderId: "vlan69",
   282  		CIDR:       "0.3.2.0/24",
   283  		VLANTag:    69,
   284  	}, {
   285  		Tag:        "network-vlan42", // duplicated; ignored
   286  		ProviderId: "vlan42",
   287  		CIDR:       "0.2.2.0/24",
   288  		VLANTag:    42,
   289  	}}
   290  	ifaces := []params.NetworkInterface{{
   291  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   292  		NetworkTag:    "network-net1",
   293  		InterfaceName: "eth0",
   294  		IsVirtual:     false,
   295  	}, {
   296  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   297  		NetworkTag:    "network-net1",
   298  		InterfaceName: "eth1",
   299  		IsVirtual:     false,
   300  	}, {
   301  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   302  		NetworkTag:    "network-vlan42",
   303  		InterfaceName: "eth1.42",
   304  		IsVirtual:     true,
   305  	}, {
   306  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   307  		NetworkTag:    "network-vlan69",
   308  		InterfaceName: "eth1.69",
   309  		IsVirtual:     true,
   310  	}, {
   311  		MACAddress:    "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored
   312  		NetworkTag:    "network-vlan42",
   313  		InterfaceName: "eth2",
   314  		IsVirtual:     true,
   315  	}, {
   316  		MACAddress:    "aa:bb:cc:dd:ee:f4",
   317  		NetworkTag:    "network-net1",
   318  		InterfaceName: "eth1", // duplicated name+machine id; ignored
   319  		IsVirtual:     false,
   320  	}}
   321  	volumes := []params.Volume{{
   322  		VolumeTag: "volume-1-0",
   323  		Info: params.VolumeInfo{
   324  			VolumeId: "vol-123",
   325  			Size:     124,
   326  		},
   327  	}}
   328  	volumeAttachments := map[string]params.VolumeAttachmentInfo{
   329  		"volume-1-0": {
   330  			DeviceName: "xvdf1",
   331  		},
   332  	}
   333  
   334  	err = apiMachine.SetInstanceInfo(
   335  		"i-will", "fake_nonce", &hwChars, networks, ifaces, volumes, volumeAttachments,
   336  	)
   337  	c.Assert(err, jc.ErrorIsNil)
   338  
   339  	instanceId, err = apiMachine.InstanceId()
   340  	c.Assert(err, jc.ErrorIsNil)
   341  	c.Assert(instanceId, gc.Equals, instance.Id("i-will"))
   342  
   343  	// Try it again - should fail.
   344  	err = apiMachine.SetInstanceInfo("i-wont", "fake", nil, nil, nil, nil, nil)
   345  	c.Assert(err, gc.ErrorMatches, `cannot record provisioning info for "i-wont": cannot set instance data for machine "1": already set`)
   346  
   347  	// Now try to get machine 0's instance id.
   348  	apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   349  	c.Assert(err, jc.ErrorIsNil)
   350  	instanceId, err = apiMachine.InstanceId()
   351  	c.Assert(err, jc.ErrorIsNil)
   352  	c.Assert(instanceId, gc.Equals, instance.Id("i-manager"))
   353  
   354  	// Check the networks are created.
   355  	for i := range networks {
   356  		if i == 3 {
   357  			// Last one was ignored, so skip it.
   358  			break
   359  		}
   360  		tag, err := names.ParseNetworkTag(networks[i].Tag)
   361  		c.Assert(err, jc.ErrorIsNil)
   362  		networkName := tag.Id()
   363  		nw, err := s.State.Network(networkName)
   364  		c.Assert(err, jc.ErrorIsNil)
   365  		c.Check(nw.Name(), gc.Equals, networkName)
   366  		c.Check(nw.ProviderId(), gc.Equals, network.Id(networks[i].ProviderId))
   367  		c.Check(nw.Tag().String(), gc.Equals, networks[i].Tag)
   368  		c.Check(nw.VLANTag(), gc.Equals, networks[i].VLANTag)
   369  		c.Check(nw.CIDR(), gc.Equals, networks[i].CIDR)
   370  	}
   371  
   372  	// And the network interfaces as well.
   373  	ifacesMachine, err = notProvisionedMachine.NetworkInterfaces()
   374  	c.Assert(err, jc.ErrorIsNil)
   375  	c.Assert(ifacesMachine, gc.HasLen, 4)
   376  	actual := make([]params.NetworkInterface, len(ifacesMachine))
   377  	for i, iface := range ifacesMachine {
   378  		actual[i].InterfaceName = iface.InterfaceName()
   379  		actual[i].NetworkTag = iface.NetworkTag().String()
   380  		actual[i].MACAddress = iface.MACAddress()
   381  		actual[i].IsVirtual = iface.IsVirtual()
   382  		c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag())
   383  		c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id())
   384  	}
   385  	c.Assert(actual, jc.SameContents, ifaces[:4]) // skip the rest as they are ignored.
   386  
   387  	// Now check volumes and volume attachments.
   388  	volume, err := s.State.Volume(names.NewVolumeTag("1/0"))
   389  	c.Assert(err, jc.ErrorIsNil)
   390  	volumeInfo, err := volume.Info()
   391  	c.Assert(err, jc.ErrorIsNil)
   392  	c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{
   393  		VolumeId: "vol-123",
   394  		Pool:     "loop-pool",
   395  		Size:     124,
   396  	})
   397  	stateVolumeAttachments, err := s.State.MachineVolumeAttachments(names.NewMachineTag("1"))
   398  	c.Assert(err, jc.ErrorIsNil)
   399  	c.Assert(stateVolumeAttachments, gc.HasLen, 1)
   400  	volumeAttachmentInfo, err := stateVolumeAttachments[0].Info()
   401  	c.Assert(err, jc.ErrorIsNil)
   402  	c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{
   403  		DeviceName: "xvdf1",
   404  	})
   405  }
   406  
   407  func (s *provisionerSuite) TestSeries(c *gc.C) {
   408  	// Create a fresh machine with different series.
   409  	foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits)
   410  	c.Assert(err, jc.ErrorIsNil)
   411  
   412  	apiMachine, err := s.provisioner.Machine(foobarMachine.Tag().(names.MachineTag))
   413  	c.Assert(err, jc.ErrorIsNil)
   414  	series, err := apiMachine.Series()
   415  	c.Assert(err, jc.ErrorIsNil)
   416  	c.Assert(series, gc.Equals, "foobar")
   417  
   418  	// Now try machine 0.
   419  	apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   420  	c.Assert(err, jc.ErrorIsNil)
   421  	series, err = apiMachine.Series()
   422  	c.Assert(err, jc.ErrorIsNil)
   423  	c.Assert(series, gc.Equals, "quantal")
   424  }
   425  
   426  func (s *provisionerSuite) TestDistributionGroup(c *gc.C) {
   427  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   428  	c.Assert(err, jc.ErrorIsNil)
   429  	instances, err := apiMachine.DistributionGroup()
   430  	c.Assert(err, jc.ErrorIsNil)
   431  	c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"})
   432  
   433  	machine1, err := s.State.AddMachine("quantal", state.JobHostUnits)
   434  	c.Assert(err, jc.ErrorIsNil)
   435  	apiMachine, err = s.provisioner.Machine(machine1.Tag().(names.MachineTag))
   436  	c.Assert(err, jc.ErrorIsNil)
   437  	wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   438  
   439  	err = apiMachine.SetInstanceInfo("i-d", "fake", nil, nil, nil, nil, nil)
   440  	c.Assert(err, jc.ErrorIsNil)
   441  	instances, err = apiMachine.DistributionGroup()
   442  	c.Assert(err, jc.ErrorIsNil)
   443  	c.Assert(instances, gc.HasLen, 0) // no units assigned
   444  
   445  	var unitNames []string
   446  	for i := 0; i < 3; i++ {
   447  		unit, err := wordpress.AddUnit()
   448  		c.Assert(err, jc.ErrorIsNil)
   449  		unitNames = append(unitNames, unit.Name())
   450  		err = unit.AssignToMachine(machine1)
   451  		c.Assert(err, jc.ErrorIsNil)
   452  		instances, err := apiMachine.DistributionGroup()
   453  		c.Assert(err, jc.ErrorIsNil)
   454  		c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"})
   455  	}
   456  }
   457  
   458  func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) {
   459  	stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   460  	c.Assert(err, jc.ErrorIsNil)
   461  	apiMachine, err := s.provisioner.Machine(stateMachine.Tag().(names.MachineTag))
   462  	c.Assert(err, jc.ErrorIsNil)
   463  	err = apiMachine.EnsureDead()
   464  	c.Assert(err, jc.ErrorIsNil)
   465  	err = apiMachine.Remove()
   466  	c.Assert(err, jc.ErrorIsNil)
   467  	_, err = apiMachine.DistributionGroup()
   468  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   469  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   470  }
   471  
   472  func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) {
   473  	cons := constraints.MustParse("cpu-cores=12 mem=8G networks=^net3,^net4")
   474  	template := state.MachineTemplate{
   475  		Series:            "quantal",
   476  		Jobs:              []state.MachineJob{state.JobHostUnits},
   477  		Placement:         "valid",
   478  		Constraints:       cons,
   479  		RequestedNetworks: []string{"net1", "net2"},
   480  	}
   481  	machine, err := s.State.AddOneMachine(template)
   482  	c.Assert(err, jc.ErrorIsNil)
   483  	apiMachine, err := s.provisioner.Machine(machine.Tag().(names.MachineTag))
   484  	c.Assert(err, jc.ErrorIsNil)
   485  	provisioningInfo, err := apiMachine.ProvisioningInfo()
   486  	c.Assert(err, jc.ErrorIsNil)
   487  	c.Assert(provisioningInfo.Series, gc.Equals, template.Series)
   488  	c.Assert(provisioningInfo.Placement, gc.Equals, template.Placement)
   489  	c.Assert(provisioningInfo.Constraints, gc.DeepEquals, template.Constraints)
   490  	c.Assert(provisioningInfo.Networks, gc.DeepEquals, template.RequestedNetworks)
   491  }
   492  
   493  func (s *provisionerSuite) TestProvisioningInfoMachineNotFound(c *gc.C) {
   494  	stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   495  	c.Assert(err, jc.ErrorIsNil)
   496  	apiMachine, err := s.provisioner.Machine(stateMachine.Tag().(names.MachineTag))
   497  	c.Assert(err, jc.ErrorIsNil)
   498  	err = apiMachine.EnsureDead()
   499  	c.Assert(err, jc.ErrorIsNil)
   500  	err = apiMachine.Remove()
   501  	c.Assert(err, jc.ErrorIsNil)
   502  	_, err = apiMachine.ProvisioningInfo()
   503  	c.Assert(err, gc.ErrorMatches, "machine 1 not found")
   504  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   505  	// auth tests in apiserver
   506  }
   507  
   508  func (s *provisionerSuite) TestWatchContainers(c *gc.C) {
   509  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   510  	c.Assert(err, jc.ErrorIsNil)
   511  
   512  	// Add one LXC container.
   513  	template := state.MachineTemplate{
   514  		Series: "quantal",
   515  		Jobs:   []state.MachineJob{state.JobHostUnits},
   516  	}
   517  	container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   518  	c.Assert(err, jc.ErrorIsNil)
   519  
   520  	w, err := apiMachine.WatchContainers(instance.LXC)
   521  	c.Assert(err, jc.ErrorIsNil)
   522  	defer statetesting.AssertStop(c, w)
   523  	wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
   524  
   525  	// Initial event.
   526  	wc.AssertChange(container.Id())
   527  
   528  	// Change something other than the containers and make sure it's
   529  	// not detected.
   530  	err = apiMachine.SetStatus(params.StatusStarted, "not really", nil)
   531  	c.Assert(err, jc.ErrorIsNil)
   532  	wc.AssertNoChange()
   533  
   534  	// Add a KVM container and make sure it's not detected.
   535  	container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.KVM)
   536  	c.Assert(err, jc.ErrorIsNil)
   537  	wc.AssertNoChange()
   538  
   539  	// Add another LXC container and make sure it's detected.
   540  	container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   541  	c.Assert(err, jc.ErrorIsNil)
   542  	wc.AssertChange(container.Id())
   543  
   544  	statetesting.AssertStop(c, w)
   545  	wc.AssertClosed()
   546  }
   547  
   548  func (s *provisionerSuite) TestWatchContainersAcceptsSupportedContainers(c *gc.C) {
   549  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   550  	c.Assert(err, jc.ErrorIsNil)
   551  
   552  	for _, ctype := range instance.ContainerTypes {
   553  		w, err := apiMachine.WatchContainers(ctype)
   554  		c.Assert(w, gc.NotNil)
   555  		c.Assert(err, jc.ErrorIsNil)
   556  	}
   557  }
   558  
   559  func (s *provisionerSuite) TestWatchContainersErrors(c *gc.C) {
   560  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   561  	c.Assert(err, jc.ErrorIsNil)
   562  
   563  	_, err = apiMachine.WatchContainers(instance.NONE)
   564  	c.Assert(err, gc.ErrorMatches, `unsupported container type "none"`)
   565  
   566  	_, err = apiMachine.WatchContainers("")
   567  	c.Assert(err, gc.ErrorMatches, "container type must be specified")
   568  }
   569  
   570  func (s *provisionerSuite) TestWatchEnvironMachines(c *gc.C) {
   571  	w, err := s.provisioner.WatchEnvironMachines()
   572  	c.Assert(err, jc.ErrorIsNil)
   573  	defer statetesting.AssertStop(c, w)
   574  	wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
   575  
   576  	// Initial event.
   577  	wc.AssertChange(s.machine.Id())
   578  
   579  	// Add another 2 machines make sure they are detected.
   580  	otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   581  	c.Assert(err, jc.ErrorIsNil)
   582  	otherMachine, err = s.State.AddMachine("quantal", state.JobHostUnits)
   583  	c.Assert(err, jc.ErrorIsNil)
   584  	wc.AssertChange("1", "2")
   585  
   586  	// Change the lifecycle of last machine.
   587  	err = otherMachine.EnsureDead()
   588  	c.Assert(err, jc.ErrorIsNil)
   589  	wc.AssertChange("2")
   590  
   591  	// Add a container and make sure it's not detected.
   592  	template := state.MachineTemplate{
   593  		Series: "quantal",
   594  		Jobs:   []state.MachineJob{state.JobHostUnits},
   595  	}
   596  	_, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   597  	c.Assert(err, jc.ErrorIsNil)
   598  	wc.AssertNoChange()
   599  
   600  	statetesting.AssertStop(c, w)
   601  	wc.AssertClosed()
   602  }
   603  
   604  func (s *provisionerSuite) TestStateAddresses(c *gc.C) {
   605  	err := s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3"))
   606  	c.Assert(err, jc.ErrorIsNil)
   607  
   608  	stateAddresses, err := s.State.Addresses()
   609  	c.Assert(err, jc.ErrorIsNil)
   610  
   611  	addresses, err := s.provisioner.StateAddresses()
   612  	c.Assert(err, jc.ErrorIsNil)
   613  	c.Assert(addresses, gc.DeepEquals, stateAddresses)
   614  }
   615  
   616  func (s *provisionerSuite) getManagerConfig(c *gc.C, typ instance.ContainerType) map[string]string {
   617  	args := params.ContainerManagerConfigParams{Type: typ}
   618  	result, err := s.provisioner.ContainerManagerConfig(args)
   619  	c.Assert(err, jc.ErrorIsNil)
   620  	return result.ManagerConfig
   621  }
   622  
   623  func (s *provisionerSuite) TestContainerManagerConfigKNoIPForwarding(c *gc.C) {
   624  	// Break dummy provider's SupportsAddressAllocation method to
   625  	// ensure ConfigIPForwarding is not set below.
   626  	s.AssertConfigParameterUpdated(c, "broken", "SupportsAddressAllocation")
   627  
   628  	cfg := s.getManagerConfig(c, instance.KVM)
   629  	c.Assert(cfg, jc.DeepEquals, map[string]string{
   630  		container.ConfigName: "juju",
   631  	})
   632  }
   633  
   634  func (s *provisionerSuite) TestContainerManagerConfigKVM(c *gc.C) {
   635  	cfg := s.getManagerConfig(c, instance.KVM)
   636  	c.Assert(cfg, jc.DeepEquals, map[string]string{
   637  		container.ConfigName: "juju",
   638  
   639  		// dummy provider supports both networking and address
   640  		// allocation by default, so IP forwarding should be enabled.
   641  		container.ConfigIPForwarding: "true",
   642  	})
   643  }
   644  
   645  func (s *provisionerSuite) TestContainerManagerConfigLXC(c *gc.C) {
   646  	args := params.ContainerManagerConfigParams{Type: instance.LXC}
   647  	st, err := state.Open(s.MongoInfo(c), mongo.DialOpts{}, state.Policy(nil))
   648  	c.Assert(err, jc.ErrorIsNil)
   649  	defer st.Close()
   650  
   651  	tests := []struct {
   652  		lxcUseClone          bool
   653  		lxcUseCloneAufs      bool
   654  		expectedUseClone     string
   655  		expectedUseCloneAufs string
   656  	}{{
   657  		lxcUseClone:          true,
   658  		expectedUseClone:     "true",
   659  		expectedUseCloneAufs: "false",
   660  	}, {
   661  		lxcUseClone:          false,
   662  		expectedUseClone:     "false",
   663  		expectedUseCloneAufs: "false",
   664  	}, {
   665  		lxcUseCloneAufs:      false,
   666  		expectedUseClone:     "false",
   667  		expectedUseCloneAufs: "false",
   668  	}, {
   669  		lxcUseClone:          true,
   670  		lxcUseCloneAufs:      true,
   671  		expectedUseClone:     "true",
   672  		expectedUseCloneAufs: "true",
   673  	}}
   674  
   675  	result, err := s.provisioner.ContainerManagerConfig(args)
   676  	c.Assert(err, jc.ErrorIsNil)
   677  	c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju")
   678  	c.Assert(result.ManagerConfig["use-clone"], gc.Equals, "")
   679  
   680  	// Change lxc-clone, and ensure it gets picked up.
   681  	for i, t := range tests {
   682  		c.Logf("test %d: %+v", i, t)
   683  		err = st.UpdateEnvironConfig(map[string]interface{}{
   684  			"lxc-clone":      t.lxcUseClone,
   685  			"lxc-clone-aufs": t.lxcUseCloneAufs,
   686  		}, nil, nil)
   687  		c.Assert(err, jc.ErrorIsNil)
   688  		result, err := s.provisioner.ContainerManagerConfig(args)
   689  		c.Assert(err, jc.ErrorIsNil)
   690  		c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju")
   691  		c.Assert(result.ManagerConfig["use-clone"], gc.Equals, t.expectedUseClone)
   692  		c.Assert(result.ManagerConfig["use-aufs"], gc.Equals, t.expectedUseCloneAufs)
   693  	}
   694  }
   695  
   696  func (s *provisionerSuite) TestContainerManagerConfigPermissive(c *gc.C) {
   697  	// ContainerManagerConfig is permissive of container types, and
   698  	// will just return the basic type-independent configuration.
   699  	cfg := s.getManagerConfig(c, "invalid")
   700  	c.Assert(cfg, jc.DeepEquals, map[string]string{
   701  		container.ConfigName: "juju",
   702  
   703  		// dummy provider supports both networking and address
   704  		// allocation by default, so IP forwarding should be enabled.
   705  		container.ConfigIPForwarding: "true",
   706  	})
   707  }
   708  
   709  func (s *provisionerSuite) TestContainerManagerConfigLXCDefaultMTU(c *gc.C) {
   710  	var resultConfig = map[string]string{
   711  		"lxc-default-mtu": "9000",
   712  	}
   713  	var called bool
   714  	provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error {
   715  		called = true
   716  		c.Assert(request, gc.Equals, "ContainerManagerConfig")
   717  		expected := params.ContainerManagerConfigParams{
   718  			Type: instance.LXC,
   719  		}
   720  		c.Assert(args, gc.Equals, expected)
   721  		result := response.(*params.ContainerManagerConfig)
   722  		result.ManagerConfig = resultConfig
   723  		return nil
   724  	})
   725  
   726  	args := params.ContainerManagerConfigParams{Type: instance.LXC}
   727  	result, err := s.provisioner.ContainerManagerConfig(args)
   728  	c.Assert(called, jc.IsTrue)
   729  	c.Assert(err, jc.ErrorIsNil)
   730  	c.Assert(result.ManagerConfig, jc.DeepEquals, resultConfig)
   731  }
   732  
   733  func (s *provisionerSuite) TestContainerConfig(c *gc.C) {
   734  	result, err := s.provisioner.ContainerConfig()
   735  	c.Assert(err, jc.ErrorIsNil)
   736  	c.Assert(result.ProviderType, gc.Equals, "dummy")
   737  	c.Assert(result.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys())
   738  	c.Assert(result.SSLHostnameVerification, jc.IsTrue)
   739  	c.Assert(result.PreferIPv6, jc.IsTrue)
   740  }
   741  
   742  func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) {
   743  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   744  	c.Assert(err, jc.ErrorIsNil)
   745  	err = apiMachine.SetSupportedContainers(instance.LXC, instance.KVM)
   746  	c.Assert(err, jc.ErrorIsNil)
   747  
   748  	err = s.machine.Refresh()
   749  	c.Assert(err, jc.ErrorIsNil)
   750  	containers, ok := s.machine.SupportedContainers()
   751  	c.Assert(ok, jc.IsTrue)
   752  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM})
   753  }
   754  
   755  func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) {
   756  	apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
   757  	c.Assert(err, jc.ErrorIsNil)
   758  	err = apiMachine.SupportsNoContainers()
   759  	c.Assert(err, jc.ErrorIsNil)
   760  
   761  	err = s.machine.Refresh()
   762  	c.Assert(err, jc.ErrorIsNil)
   763  	containers, ok := s.machine.SupportedContainers()
   764  	c.Assert(ok, jc.IsTrue)
   765  	c.Assert(containers, gc.DeepEquals, []instance.ContainerType{})
   766  }
   767  
   768  func (s *provisionerSuite) TestFindToolsNoArch(c *gc.C) {
   769  	s.testFindTools(c, false, nil, nil)
   770  }
   771  
   772  func (s *provisionerSuite) TestFindToolsArch(c *gc.C) {
   773  	s.testFindTools(c, true, nil, nil)
   774  }
   775  
   776  func (s *provisionerSuite) TestFindToolsAPIError(c *gc.C) {
   777  	apiError := errors.New("everything's broken")
   778  	s.testFindTools(c, false, apiError, nil)
   779  }
   780  
   781  func (s *provisionerSuite) TestFindToolsLogicError(c *gc.C) {
   782  	logicError := errors.NotFoundf("tools")
   783  	s.testFindTools(c, false, nil, logicError)
   784  }
   785  
   786  func (s *provisionerSuite) testFindTools(c *gc.C, matchArch bool, apiError, logicError error) {
   787  	var toolsList = coretools.List{&coretools.Tools{Version: version.Current}}
   788  	var called bool
   789  	provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error {
   790  		called = true
   791  		c.Assert(request, gc.Equals, "FindTools")
   792  		expected := params.FindToolsParams{
   793  			Number:       version.Current.Number,
   794  			Series:       version.Current.Series,
   795  			MinorVersion: -1,
   796  			MajorVersion: -1,
   797  		}
   798  		if matchArch {
   799  			expected.Arch = version.Current.Arch
   800  		}
   801  		c.Assert(args, gc.Equals, expected)
   802  		result := response.(*params.FindToolsResult)
   803  		result.List = toolsList
   804  		if logicError != nil {
   805  			result.Error = common.ServerError(logicError)
   806  		}
   807  		return apiError
   808  	})
   809  
   810  	var arch *string
   811  	if matchArch {
   812  		arch = &version.Current.Arch
   813  	}
   814  	apiList, err := s.provisioner.FindTools(version.Current.Number, version.Current.Series, arch)
   815  	c.Assert(called, jc.IsTrue)
   816  	if apiError != nil {
   817  		c.Assert(err, gc.Equals, apiError)
   818  	} else if logicError != nil {
   819  		c.Assert(err.Error(), gc.Equals, logicError.Error())
   820  	} else {
   821  		c.Assert(err, jc.ErrorIsNil)
   822  		c.Assert(apiList, jc.SameContents, toolsList)
   823  	}
   824  }
   825  
   826  func (s *provisionerSuite) TestPrepareContainerInterfaceInfo(c *gc.C) {
   827  	// This test exercises just the success path, all the other cases
   828  	// are already tested in the apiserver package.
   829  	template := state.MachineTemplate{
   830  		Series: "quantal",
   831  		Jobs:   []state.MachineJob{state.JobHostUnits},
   832  	}
   833  	container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   834  	c.Assert(err, jc.ErrorIsNil)
   835  
   836  	expectInfo := []network.InterfaceInfo{{
   837  		DeviceIndex:      0,
   838  		MACAddress:       "aa:bb:cc:dd:ee:f0",
   839  		CIDR:             "0.10.0.0/24",
   840  		NetworkName:      "juju-private",
   841  		ProviderId:       "dummy-eth0",
   842  		ProviderSubnetId: "dummy-private",
   843  		VLANTag:          0,
   844  		InterfaceName:    "eth0",
   845  		Disabled:         false,
   846  		NoAutoStart:      false,
   847  		ConfigType:       network.ConfigStatic,
   848  		// Overwrite the Address field below with the actual one, as
   849  		// it's chosen randomly.
   850  		Address:        network.Address{},
   851  		DNSServers:     network.NewAddresses("ns1.dummy", "ns2.dummy"),
   852  		GatewayAddress: network.NewAddress("0.10.0.2"),
   853  		ExtraConfig:    nil,
   854  	}}
   855  	ifaceInfo, err := s.provisioner.PrepareContainerInterfaceInfo(container.MachineTag())
   856  	c.Assert(err, jc.ErrorIsNil)
   857  	c.Assert(ifaceInfo, gc.HasLen, 1)
   858  	c.Assert(ifaceInfo[0].Address, gc.Not(gc.DeepEquals), network.Address{})
   859  	expectInfo[0].Address = ifaceInfo[0].Address
   860  	c.Assert(ifaceInfo, jc.DeepEquals, expectInfo)
   861  }
   862  
   863  func (s *provisionerSuite) TestReleaseContainerAddresses(c *gc.C) {
   864  	// This test exercises just the success path, all the other cases
   865  	// are already tested in the apiserver package.
   866  	template := state.MachineTemplate{
   867  		Series: "quantal",
   868  		Jobs:   []state.MachineJob{state.JobHostUnits},
   869  	}
   870  	container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   871  
   872  	// allocate some addresses to release
   873  	subInfo := state.SubnetInfo{
   874  		ProviderId:        "dummy-private",
   875  		CIDR:              "0.10.0.0/24",
   876  		VLANTag:           0,
   877  		AllocatableIPLow:  "0.10.0.0",
   878  		AllocatableIPHigh: "0.10.0.10",
   879  	}
   880  	sub, err := s.State.AddSubnet(subInfo)
   881  	c.Assert(err, jc.ErrorIsNil)
   882  	for i := 0; i < 3; i++ {
   883  		addr := network.NewAddress(fmt.Sprintf("0.10.0.%d", i))
   884  		ipaddr, err := s.State.AddIPAddress(addr, sub.ID())
   885  		c.Check(err, jc.ErrorIsNil)
   886  		err = ipaddr.AllocateTo(container.Id(), "")
   887  		c.Check(err, jc.ErrorIsNil)
   888  	}
   889  	c.Assert(err, jc.ErrorIsNil)
   890  	password, err := utils.RandomPassword()
   891  	c.Assert(err, jc.ErrorIsNil)
   892  	err = container.SetPassword(password)
   893  	c.Assert(err, jc.ErrorIsNil)
   894  	err = container.SetProvisioned("foo", "fake_nonce", nil)
   895  	c.Assert(err, jc.ErrorIsNil)
   896  
   897  	err = s.provisioner.ReleaseContainerAddresses(container.MachineTag())
   898  	c.Assert(err, jc.ErrorIsNil)
   899  
   900  	addresses, err := s.State.AllocatedIPAddresses(container.Id())
   901  	c.Assert(err, jc.ErrorIsNil)
   902  	c.Assert(addresses, gc.HasLen, 3)
   903  	for _, addr := range addresses {
   904  		c.Assert(addr.Life(), gc.Equals, state.Dead)
   905  	}
   906  }