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