github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/provisioner/container_initialisation_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"runtime"
    13  	"sync/atomic"
    14  
    15  	"github.com/juju/names"
    16  	"github.com/juju/testing"
    17  	jc "github.com/juju/testing/checkers"
    18  	"github.com/juju/utils/arch"
    19  	"github.com/juju/utils/featureflag"
    20  	"github.com/juju/utils/fslock"
    21  	jujuos "github.com/juju/utils/os"
    22  	"github.com/juju/utils/packaging/manager"
    23  	"github.com/juju/utils/series"
    24  	"github.com/juju/version"
    25  	gc "gopkg.in/check.v1"
    26  
    27  	"github.com/juju/juju/agent"
    28  	apiprovisioner "github.com/juju/juju/api/provisioner"
    29  	"github.com/juju/juju/container"
    30  	containertesting "github.com/juju/juju/container/testing"
    31  	"github.com/juju/juju/environs"
    32  	"github.com/juju/juju/feature"
    33  	"github.com/juju/juju/instance"
    34  	"github.com/juju/juju/juju/osenv"
    35  	"github.com/juju/juju/provider/dummy"
    36  	"github.com/juju/juju/state"
    37  	coretesting "github.com/juju/juju/testing"
    38  	"github.com/juju/juju/tools"
    39  	jujuversion "github.com/juju/juju/version"
    40  	"github.com/juju/juju/watcher"
    41  	"github.com/juju/juju/worker"
    42  	"github.com/juju/juju/worker/provisioner"
    43  )
    44  
    45  type ContainerSetupSuite struct {
    46  	CommonProvisionerSuite
    47  	p           provisioner.Provisioner
    48  	agentConfig agent.ConfigSetter
    49  	// Record the apt commands issued as part of container initialisation
    50  	aptCmdChan  <-chan *exec.Cmd
    51  	initLockDir string
    52  	initLock    *fslock.Lock
    53  	fakeLXCNet  string
    54  }
    55  
    56  var _ = gc.Suite(&ContainerSetupSuite{})
    57  
    58  func (s *ContainerSetupSuite) SetUpSuite(c *gc.C) {
    59  	// TODO(bogdanteleaga): Fix this on windows
    60  	if runtime.GOOS == "windows" {
    61  		c.Skip("bug 1403084: Skipping container tests on windows")
    62  	}
    63  	s.CommonProvisionerSuite.SetUpSuite(c)
    64  }
    65  
    66  func (s *ContainerSetupSuite) TearDownSuite(c *gc.C) {
    67  	s.CommonProvisionerSuite.TearDownSuite(c)
    68  }
    69  
    70  func allFatal(error) bool {
    71  	return true
    72  }
    73  
    74  func noImportance(err0, err1 error) bool {
    75  	return false
    76  }
    77  
    78  func (s *ContainerSetupSuite) SetUpTest(c *gc.C) {
    79  	s.CommonProvisionerSuite.SetUpTest(c)
    80  	aptCmdChan := s.HookCommandOutput(&manager.CommandOutput, []byte{}, nil)
    81  	s.aptCmdChan = aptCmdChan
    82  
    83  	// Set up provisioner for the state machine.
    84  	s.agentConfig = s.AgentConfigForTag(c, names.NewMachineTag("0"))
    85  	var err error
    86  	s.p, err = provisioner.NewEnvironProvisioner(s.provisioner, s.agentConfig)
    87  	c.Assert(err, jc.ErrorIsNil)
    88  
    89  	// Create a new container initialisation lock.
    90  	s.initLockDir = c.MkDir()
    91  	initLock, err := fslock.NewLock(s.initLockDir, "container-init", fslock.Defaults())
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	s.initLock = initLock
    94  
    95  	// Patch to isolate the test from the host machine.
    96  	s.fakeLXCNet = filepath.Join(c.MkDir(), "lxc-net")
    97  	s.PatchValue(provisioner.EtcDefaultLXCNetPath, s.fakeLXCNet)
    98  }
    99  
   100  func (s *ContainerSetupSuite) TearDownTest(c *gc.C) {
   101  	if s.p != nil {
   102  		stop(c, s.p)
   103  	}
   104  	s.CommonProvisionerSuite.TearDownTest(c)
   105  }
   106  
   107  func (s *ContainerSetupSuite) setupContainerWorker(c *gc.C, tag names.MachineTag) (watcher.StringsHandler, worker.Runner) {
   108  	testing.PatchExecutable(c, s, "ubuntu-cloudimg-query", containertesting.FakeLxcURLScript)
   109  	runner := worker.NewRunner(allFatal, noImportance, worker.RestartDelay)
   110  	pr := s.st.Provisioner()
   111  	machine, err := pr.Machine(tag)
   112  	c.Assert(err, jc.ErrorIsNil)
   113  	err = machine.SetSupportedContainers(instance.ContainerTypes...)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  	cfg := s.AgentConfigForTag(c, tag)
   116  
   117  	watcherName := fmt.Sprintf("%s-container-watcher", machine.Id())
   118  	params := provisioner.ContainerSetupParams{
   119  		Runner:              runner,
   120  		WorkerName:          watcherName,
   121  		SupportedContainers: instance.ContainerTypes,
   122  		ImageURLGetter:      &containertesting.MockURLGetter{},
   123  		Machine:             machine,
   124  		Provisioner:         pr,
   125  		Config:              cfg,
   126  		InitLock:            s.initLock,
   127  	}
   128  	handler := provisioner.NewContainerSetupHandler(params)
   129  	runner.StartWorker(watcherName, func() (worker.Worker, error) {
   130  		return watcher.NewStringsWorker(watcher.StringsConfig{
   131  			Handler: handler,
   132  		})
   133  	})
   134  	return handler, runner
   135  }
   136  
   137  func (s *ContainerSetupSuite) createContainer(c *gc.C, host *state.Machine, ctype instance.ContainerType) {
   138  	inst := s.checkStartInstanceNoSecureConnection(c, host)
   139  	s.setupContainerWorker(c, host.Tag().(names.MachineTag))
   140  
   141  	// make a container on the host machine
   142  	template := state.MachineTemplate{
   143  		Series: coretesting.FakeDefaultSeries,
   144  		Jobs:   []state.MachineJob{state.JobHostUnits},
   145  	}
   146  	container, err := s.State.AddMachineInsideMachine(template, host.Id(), ctype)
   147  	c.Assert(err, jc.ErrorIsNil)
   148  
   149  	// the host machine agent should not attempt to create the container
   150  	s.checkNoOperations(c)
   151  
   152  	// cleanup
   153  	c.Assert(container.EnsureDead(), gc.IsNil)
   154  	c.Assert(container.Remove(), gc.IsNil)
   155  	c.Assert(host.EnsureDead(), gc.IsNil)
   156  	s.checkStopInstances(c, inst)
   157  	s.waitRemoved(c, host)
   158  }
   159  
   160  func (s *ContainerSetupSuite) assertContainerProvisionerStarted(
   161  	c *gc.C, host *state.Machine, ctype instance.ContainerType) {
   162  
   163  	// A stub worker callback to record what happens.
   164  	var provisionerStarted uint32
   165  	startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType,
   166  		pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker,
   167  		toolsFinder provisioner.ToolsFinder) error {
   168  		c.Assert(containerType, gc.Equals, ctype)
   169  		c.Assert(cfg.Tag(), gc.Equals, host.Tag())
   170  		atomic.StoreUint32(&provisionerStarted, 1)
   171  		return nil
   172  	}
   173  	s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker)
   174  
   175  	s.createContainer(c, host, ctype)
   176  	// Consume the apt command used to initialise the container.
   177  	<-s.aptCmdChan
   178  
   179  	// the container worker should have created the provisioner
   180  	c.Assert(atomic.LoadUint32(&provisionerStarted) > 0, jc.IsTrue)
   181  }
   182  
   183  func (s *ContainerSetupSuite) TestContainerProvisionerStarted(c *gc.C) {
   184  	// Specifically ignore LXD here, if present in instance.ContainerTypes.
   185  	containerTypes := []instance.ContainerType{instance.LXC, instance.KVM}
   186  	for _, ctype := range containerTypes {
   187  		// create a machine to host the container.
   188  		m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   189  			Series:      coretesting.FakeDefaultSeries,
   190  			Jobs:        []state.MachineJob{state.JobHostUnits},
   191  			Constraints: s.defaultConstraints,
   192  		})
   193  		c.Assert(err, jc.ErrorIsNil)
   194  		err = m.SetSupportedContainers(containerTypes)
   195  		c.Assert(err, jc.ErrorIsNil)
   196  		current := version.Binary{
   197  			Number: jujuversion.Current,
   198  			Arch:   arch.HostArch(),
   199  			Series: series.HostSeries(),
   200  		}
   201  		err = m.SetAgentVersion(current)
   202  		c.Assert(err, jc.ErrorIsNil)
   203  		s.assertContainerProvisionerStarted(c, m, ctype)
   204  	}
   205  }
   206  
   207  func (s *ContainerSetupSuite) TestLxcContainerUsesConstraintsArch(c *gc.C) {
   208  	// LXC should override the architecture in constraints with the
   209  	// host's architecture.
   210  	s.PatchValue(&arch.HostArch, func() string { return arch.PPC64EL })
   211  	s.testContainerConstraintsArch(c, instance.LXC, arch.PPC64EL)
   212  }
   213  
   214  func (s *ContainerSetupSuite) TestKvmContainerUsesHostArch(c *gc.C) {
   215  	// KVM should do what it's told, and use the architecture in
   216  	// constraints.
   217  	s.PatchValue(&arch.HostArch, func() string { return arch.PPC64EL })
   218  	s.testContainerConstraintsArch(c, instance.KVM, arch.AMD64)
   219  }
   220  
   221  func (s *ContainerSetupSuite) testContainerConstraintsArch(c *gc.C, containerType instance.ContainerType, expectArch string) {
   222  	var called uint32
   223  	s.PatchValue(provisioner.GetToolsFinder, func(*apiprovisioner.State) provisioner.ToolsFinder {
   224  		return toolsFinderFunc(func(v version.Number, series string, arch string) (tools.List, error) {
   225  			atomic.StoreUint32(&called, 1)
   226  			c.Assert(arch, gc.Equals, expectArch)
   227  			result := version.Binary{
   228  				Number: v,
   229  				Arch:   arch,
   230  				Series: series,
   231  			}
   232  			return tools.List{{Version: result}}, nil
   233  		})
   234  	})
   235  
   236  	s.PatchValue(&provisioner.StartProvisioner, func(runner worker.Runner, containerType instance.ContainerType,
   237  		pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker,
   238  		toolsFinder provisioner.ToolsFinder) error {
   239  		toolsFinder.FindTools(jujuversion.Current, series.HostSeries(), arch.AMD64)
   240  		return nil
   241  	})
   242  
   243  	// create a machine to host the container.
   244  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   245  		Series:      coretesting.FakeDefaultSeries,
   246  		Jobs:        []state.MachineJob{state.JobHostUnits},
   247  		Constraints: s.defaultConstraints,
   248  	})
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	err = m.SetSupportedContainers([]instance.ContainerType{containerType})
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	current := version.Binary{
   253  		Number: jujuversion.Current,
   254  		Arch:   arch.HostArch(),
   255  		Series: series.HostSeries(),
   256  	}
   257  	err = m.SetAgentVersion(current)
   258  	c.Assert(err, jc.ErrorIsNil)
   259  
   260  	s.createContainer(c, m, containerType)
   261  	<-s.aptCmdChan
   262  	c.Assert(atomic.LoadUint32(&called) > 0, jc.IsTrue)
   263  }
   264  
   265  func (s *ContainerSetupSuite) TestLxcContainerUsesImageURL(c *gc.C) {
   266  	// create a machine to host the container.
   267  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   268  		Series:      coretesting.FakeDefaultSeries,
   269  		Jobs:        []state.MachineJob{state.JobHostUnits},
   270  		Constraints: s.defaultConstraints,
   271  	})
   272  	c.Assert(err, jc.ErrorIsNil)
   273  	err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM})
   274  	c.Assert(err, jc.ErrorIsNil)
   275  	current := version.Binary{
   276  		Number: jujuversion.Current,
   277  		Arch:   arch.HostArch(),
   278  		Series: series.HostSeries(),
   279  	}
   280  	err = m.SetAgentVersion(current)
   281  	c.Assert(err, jc.ErrorIsNil)
   282  
   283  	brokerCalled := false
   284  	newlxcbroker := func(api provisioner.APICalls, agentConfig agent.Config, managerConfig container.ManagerConfig,
   285  		imageURLGetter container.ImageURLGetter, enableNAT bool, defaultMTU int) (environs.InstanceBroker, error) {
   286  		imageURL, err := imageURLGetter.ImageURL(instance.LXC, "trusty", "amd64")
   287  		c.Assert(err, jc.ErrorIsNil)
   288  		c.Assert(imageURL, gc.Equals, "imageURL")
   289  		c.Assert(imageURLGetter.CACert(), gc.DeepEquals, []byte("cert"))
   290  		brokerCalled = true
   291  		return nil, fmt.Errorf("lxc broker error")
   292  	}
   293  	s.PatchValue(&provisioner.NewLxcBroker, newlxcbroker)
   294  	s.createContainer(c, m, instance.LXC)
   295  	c.Assert(brokerCalled, jc.IsTrue)
   296  }
   297  
   298  func (s *ContainerSetupSuite) TestContainerManagerConfigName(c *gc.C) {
   299  	pr := s.st.Provisioner()
   300  	expect := func(expect string) {
   301  		cfg, err := provisioner.ContainerManagerConfig(instance.KVM, pr, s.agentConfig)
   302  		c.Assert(err, jc.ErrorIsNil)
   303  		c.Assert(cfg[container.ConfigName], gc.Equals, expect)
   304  	}
   305  	expect("juju")
   306  	s.agentConfig.SetValue(agent.Namespace, "any-old-thing")
   307  	expect("any-old-thing")
   308  }
   309  
   310  type ContainerInstance struct {
   311  	ctype    instance.ContainerType
   312  	packages [][]string
   313  }
   314  
   315  func (s *ContainerSetupSuite) assertContainerInitialised(c *gc.C, cont ContainerInstance, addressable bool) {
   316  	// A noop worker callback.
   317  	startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType,
   318  		pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker,
   319  		toolsFinder provisioner.ToolsFinder) error {
   320  		return nil
   321  	}
   322  	s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker)
   323  
   324  	current_os, err := series.GetOSFromSeries(series.HostSeries())
   325  	c.Assert(err, jc.ErrorIsNil)
   326  
   327  	var ser string
   328  	var expected_initial []string
   329  	switch current_os {
   330  	case jujuos.CentOS:
   331  		ser = "centos7"
   332  		expected_initial = []string{
   333  			"yum", "--assumeyes", "--debuglevel=1", "install"}
   334  	default:
   335  		ser = "precise"
   336  		expected_initial = []string{
   337  			"apt-get", "--option=Dpkg::Options::=--force-confold",
   338  			"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
   339  			"install"}
   340  	}
   341  
   342  	// create a machine to host the container.
   343  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   344  		Series:      ser, // precise requires special apt parameters, so we use that series here.
   345  		Jobs:        []state.MachineJob{state.JobHostUnits},
   346  		Constraints: s.defaultConstraints,
   347  	})
   348  	c.Assert(err, jc.ErrorIsNil)
   349  	err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM})
   350  	c.Assert(err, jc.ErrorIsNil)
   351  	current := version.Binary{
   352  		Number: jujuversion.Current,
   353  		Arch:   arch.HostArch(),
   354  		Series: series.HostSeries(),
   355  	}
   356  	err = m.SetAgentVersion(current)
   357  	c.Assert(err, jc.ErrorIsNil)
   358  
   359  	// Before starting /etc/default/lxc-net should be missing.
   360  	c.Assert(s.fakeLXCNet, jc.DoesNotExist)
   361  
   362  	s.createContainer(c, m, cont.ctype)
   363  
   364  	// Only feature-flagged addressable containers modify lxc-net.
   365  	if addressable {
   366  		// After initialisation starts, but before running the
   367  		// initializer, lxc-net should be created if cont.ctype is LXC, as the
   368  		// dummy provider supports static address allocation by default.
   369  		if cont.ctype == instance.LXC {
   370  			AssertFileContains(c, s.fakeLXCNet, provisioner.EtcDefaultLXCNet)
   371  			defer os.Remove(s.fakeLXCNet)
   372  		} else {
   373  			c.Assert(s.fakeLXCNet, jc.DoesNotExist)
   374  		}
   375  	}
   376  
   377  	for _, pack := range cont.packages {
   378  		cmd := <-s.aptCmdChan
   379  
   380  		expected := append(expected_initial, pack...)
   381  		c.Assert(cmd.Args, gc.DeepEquals, expected)
   382  	}
   383  }
   384  
   385  func (s *ContainerSetupSuite) TestContainerInitialised(c *gc.C) {
   386  	cont, err := getContainerInstance()
   387  	c.Assert(err, jc.ErrorIsNil)
   388  
   389  	for _, test := range cont {
   390  		s.assertContainerInitialised(c, test, false)
   391  	}
   392  }
   393  
   394  func (s *ContainerSetupSuite) TestContainerInitLockError(c *gc.C) {
   395  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   396  		Series:      coretesting.FakeDefaultSeries,
   397  		Jobs:        []state.MachineJob{state.JobHostUnits},
   398  		Constraints: s.defaultConstraints,
   399  	})
   400  	c.Assert(err, jc.ErrorIsNil)
   401  	current := version.Binary{
   402  		Number: jujuversion.Current,
   403  		Arch:   arch.HostArch(),
   404  		Series: series.HostSeries(),
   405  	}
   406  	err = m.SetAgentVersion(current)
   407  	c.Assert(err, jc.ErrorIsNil)
   408  
   409  	err = os.RemoveAll(s.initLockDir)
   410  	c.Assert(err, jc.ErrorIsNil)
   411  	handler, runner := s.setupContainerWorker(c, m.Tag().(names.MachineTag))
   412  	runner.Kill()
   413  	err = runner.Wait()
   414  	c.Assert(err, jc.ErrorIsNil)
   415  
   416  	_, err = handler.SetUp()
   417  	c.Assert(err, jc.ErrorIsNil)
   418  	err = handler.Handle(nil, []string{"0/lxc/0"})
   419  	c.Assert(err, gc.ErrorMatches, ".*failed to acquire initialization lock:.*")
   420  
   421  }
   422  
   423  func (s *ContainerSetupSuite) TestMaybeOverrideDefaultLXCNet(c *gc.C) {
   424  	for i, test := range []struct {
   425  		ctype          instance.ContainerType
   426  		addressable    bool
   427  		expectOverride bool
   428  	}{
   429  		{instance.KVM, false, false},
   430  		{instance.KVM, true, false},
   431  		{instance.LXC, false, false},
   432  		{instance.LXC, true, true}, // the only case when we override; also last
   433  	} {
   434  		c.Logf(
   435  			"test %d: ctype: %q, addressable: %v -> expectOverride: %v",
   436  			i, test.ctype, test.addressable, test.expectOverride,
   437  		)
   438  		err := provisioner.MaybeOverrideDefaultLXCNet(test.ctype, test.addressable)
   439  		if !c.Check(err, jc.ErrorIsNil) {
   440  			continue
   441  		}
   442  		if !test.expectOverride {
   443  			c.Check(s.fakeLXCNet, jc.DoesNotExist)
   444  		} else {
   445  			AssertFileContains(c, s.fakeLXCNet, provisioner.EtcDefaultLXCNet)
   446  		}
   447  	}
   448  }
   449  
   450  func AssertFileContains(c *gc.C, filename string, expectedContent ...string) {
   451  	// TODO(dimitern): We should put this in juju/testing repo and
   452  	// replace all similar checks with it.
   453  	data, err := ioutil.ReadFile(filename)
   454  	c.Assert(err, jc.ErrorIsNil)
   455  	for _, s := range expectedContent {
   456  		c.Assert(string(data), jc.Contains, s)
   457  	}
   458  }
   459  
   460  func AssertFileContents(c *gc.C, checker gc.Checker, filename string, expectedContent ...string) {
   461  	// TODO(dimitern): We should put this in juju/testing repo and
   462  	// replace all similar checks with it.
   463  	data, err := ioutil.ReadFile(filename)
   464  	c.Assert(err, jc.ErrorIsNil)
   465  	for _, s := range expectedContent {
   466  		c.Assert(string(data), checker, s)
   467  	}
   468  }
   469  
   470  type SetIPAndARPForwardingSuite struct {
   471  	coretesting.BaseSuite
   472  }
   473  
   474  func (s *SetIPAndARPForwardingSuite) SetUpSuite(c *gc.C) {
   475  	if runtime.GOOS == "windows" {
   476  		c.Skip("bug 1403084: Skipping for now")
   477  	}
   478  	s.BaseSuite.SetUpSuite(c)
   479  }
   480  
   481  var _ = gc.Suite(&SetIPAndARPForwardingSuite{})
   482  
   483  func (s *SetIPAndARPForwardingSuite) TestSuccess(c *gc.C) {
   484  	// NOTE: Because PatchExecutableAsEchoArgs does not allow us to
   485  	// assert on earlier invocations of the same binary (each run
   486  	// overwrites the last args used), we only check sysctl was called
   487  	// for the second key (arpProxySysctlKey). We do check the config
   488  	// contains both though.
   489  	fakeConfig := filepath.Join(c.MkDir(), "sysctl.conf")
   490  	testing.PatchExecutableAsEchoArgs(c, s, "sysctl")
   491  	s.PatchValue(provisioner.SysctlConfig, fakeConfig)
   492  
   493  	err := provisioner.SetIPAndARPForwarding(true)
   494  	c.Assert(err, jc.ErrorIsNil)
   495  	expectConf := fmt.Sprintf(
   496  		"%s=1\n%s=1",
   497  		provisioner.IPForwardSysctlKey,
   498  		provisioner.ARPProxySysctlKey,
   499  	)
   500  	AssertFileContains(c, fakeConfig, expectConf)
   501  	expectKeyVal := fmt.Sprintf("%s=1", provisioner.IPForwardSysctlKey)
   502  	testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal)
   503  	expectKeyVal = fmt.Sprintf("%s=1", provisioner.ARPProxySysctlKey)
   504  	testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal)
   505  
   506  	err = provisioner.SetIPAndARPForwarding(false)
   507  	c.Assert(err, jc.ErrorIsNil)
   508  	expectConf = fmt.Sprintf(
   509  		"%s=0\n%s=0",
   510  		provisioner.IPForwardSysctlKey,
   511  		provisioner.ARPProxySysctlKey,
   512  	)
   513  	AssertFileContains(c, fakeConfig, expectConf)
   514  	expectKeyVal = fmt.Sprintf("%s=0", provisioner.IPForwardSysctlKey)
   515  	testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal)
   516  	expectKeyVal = fmt.Sprintf("%s=0", provisioner.ARPProxySysctlKey)
   517  	testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal)
   518  }
   519  
   520  func (s *SetIPAndARPForwardingSuite) TestFailure(c *gc.C) {
   521  	fakeConfig := filepath.Join(c.MkDir(), "sysctl.conf")
   522  	testing.PatchExecutableThrowError(c, s, "sysctl", 123)
   523  	s.PatchValue(provisioner.SysctlConfig, fakeConfig)
   524  	expectKeyVal := fmt.Sprintf("%s=1", provisioner.IPForwardSysctlKey)
   525  
   526  	err := provisioner.SetIPAndARPForwarding(true)
   527  	c.Assert(err, gc.ErrorMatches, fmt.Sprintf(
   528  		`cannot set %s: unexpected exit code 123`, expectKeyVal),
   529  	)
   530  	_, err = os.Stat(fakeConfig)
   531  	c.Assert(err, jc.Satisfies, os.IsNotExist)
   532  }
   533  
   534  type toolsFinderFunc func(v version.Number, series string, arch string) (tools.List, error)
   535  
   536  func (t toolsFinderFunc) FindTools(v version.Number, series string, arch string) (tools.List, error) {
   537  	return t(v, series, arch)
   538  }
   539  
   540  // AddressableContainerSetupSuite only contains tests depending on the
   541  // address allocation feature flag being enabled.
   542  type AddressableContainerSetupSuite struct {
   543  	ContainerSetupSuite
   544  }
   545  
   546  var _ = gc.Suite(&AddressableContainerSetupSuite{})
   547  
   548  func (s *AddressableContainerSetupSuite) enableFeatureFlag() {
   549  	s.SetFeatureFlags(feature.AddressAllocation)
   550  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
   551  }
   552  
   553  func (s *AddressableContainerSetupSuite) TestContainerInitialised(c *gc.C) {
   554  	cont, err := getContainerInstance()
   555  	c.Assert(err, jc.ErrorIsNil)
   556  
   557  	for _, test := range cont {
   558  		s.enableFeatureFlag()
   559  		s.assertContainerInitialised(c, test, true)
   560  	}
   561  }
   562  
   563  func getContainerInstance() (cont []ContainerInstance, err error) {
   564  	current_os, err := series.GetOSFromSeries(series.HostSeries())
   565  	if err != nil {
   566  		return nil, err
   567  	}
   568  
   569  	switch current_os {
   570  	case jujuos.CentOS:
   571  		cont = []ContainerInstance{
   572  			{instance.LXC, [][]string{
   573  				{"lxc"},
   574  				{"cloud-image-utils"},
   575  			}},
   576  			{instance.KVM, [][]string{
   577  				{"uvtool-libvirt"},
   578  				{"uvtool"},
   579  			}},
   580  		}
   581  	default:
   582  		cont = []ContainerInstance{
   583  			{instance.LXC, [][]string{
   584  				{"--target-release", "precise-updates/cloud-tools", "lxc"},
   585  				{"--target-release", "precise-updates/cloud-tools", "cloud-image-utils"},
   586  			}},
   587  			{instance.KVM, [][]string{
   588  				{"uvtool-libvirt"},
   589  				{"uvtool"},
   590  			}},
   591  		}
   592  	}
   593  
   594  	return cont, nil
   595  }
   596  
   597  // LXCDefaultMTUSuite only contains tests depending on the
   598  // lxc-default-mtu environment setting being set explicitly.
   599  type LXCDefaultMTUSuite struct {
   600  	ContainerSetupSuite
   601  }
   602  
   603  var _ = gc.Suite(&LXCDefaultMTUSuite{})
   604  
   605  func (s *LXCDefaultMTUSuite) SetUpTest(c *gc.C) {
   606  	// Explicitly set lxc-default-mtu before JujuConnSuite constructs
   607  	// the environment, as the setting is immutable.
   608  	s.DummyConfig = dummy.SampleConfig()
   609  	s.DummyConfig["lxc-default-mtu"] = 9000
   610  	s.ContainerSetupSuite.SetUpTest(c)
   611  }
   612  
   613  func (s *LXCDefaultMTUSuite) TestDefaultMTUPropagatedToNewLXCBroker(c *gc.C) {
   614  	// create a machine to host the container.
   615  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   616  		Series:      coretesting.FakeDefaultSeries,
   617  		Jobs:        []state.MachineJob{state.JobHostUnits},
   618  		Constraints: s.defaultConstraints,
   619  	})
   620  	c.Assert(err, jc.ErrorIsNil)
   621  	err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM})
   622  	c.Assert(err, jc.ErrorIsNil)
   623  	current := version.Binary{
   624  		Number: jujuversion.Current,
   625  		Arch:   arch.HostArch(),
   626  		Series: series.HostSeries(),
   627  	}
   628  	err = m.SetAgentVersion(current)
   629  	c.Assert(err, jc.ErrorIsNil)
   630  
   631  	brokerCalled := false
   632  	newlxcbroker := func(api provisioner.APICalls, agentConfig agent.Config, managerConfig container.ManagerConfig, imageURLGetter container.ImageURLGetter, enableNAT bool, defaultMTU int) (environs.InstanceBroker, error) {
   633  		brokerCalled = true
   634  		c.Assert(defaultMTU, gc.Equals, 9000)
   635  		return nil, fmt.Errorf("lxc broker error")
   636  	}
   637  	s.PatchValue(&provisioner.NewLxcBroker, newlxcbroker)
   638  	s.createContainer(c, m, instance.LXC)
   639  	c.Assert(brokerCalled, jc.IsTrue)
   640  }