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