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