github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/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  	"os"
     9  	"os/exec"
    10  
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils/apt"
    13  	"github.com/juju/utils/fslock"
    14  	gc "launchpad.net/gocheck"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/container"
    18  	"github.com/juju/juju/environs"
    19  	"github.com/juju/juju/instance"
    20  	"github.com/juju/juju/state"
    21  	apiprovisioner "github.com/juju/juju/state/api/provisioner"
    22  	coretesting "github.com/juju/juju/testing"
    23  	"github.com/juju/juju/version"
    24  	"github.com/juju/juju/worker"
    25  	"github.com/juju/juju/worker/provisioner"
    26  )
    27  
    28  type ContainerSetupSuite struct {
    29  	CommonProvisionerSuite
    30  	p           provisioner.Provisioner
    31  	agentConfig agent.ConfigSetter
    32  	// Record the apt commands issued as part of container initialisation
    33  	aptCmdChan  <-chan *exec.Cmd
    34  	initLockDir string
    35  	initLock    *fslock.Lock
    36  }
    37  
    38  var _ = gc.Suite(&ContainerSetupSuite{})
    39  
    40  func (s *ContainerSetupSuite) SetUpSuite(c *gc.C) {
    41  	s.CommonProvisionerSuite.SetUpSuite(c)
    42  }
    43  
    44  func (s *ContainerSetupSuite) TearDownSuite(c *gc.C) {
    45  	s.CommonProvisionerSuite.TearDownSuite(c)
    46  }
    47  
    48  func allFatal(error) bool {
    49  	return true
    50  }
    51  
    52  func noImportance(err0, err1 error) bool {
    53  	return false
    54  }
    55  
    56  func (s *ContainerSetupSuite) SetUpTest(c *gc.C) {
    57  	s.CommonProvisionerSuite.SetUpTest(c)
    58  	s.CommonProvisionerSuite.setupEnvironmentManager(c)
    59  	aptCmdChan := s.HookCommandOutput(&apt.CommandOutput, []byte{}, nil)
    60  	s.aptCmdChan = aptCmdChan
    61  
    62  	// Set up provisioner for the state machine.
    63  	s.agentConfig = s.AgentConfigForTag(c, "machine-0")
    64  	s.p = provisioner.NewEnvironProvisioner(s.provisioner, s.agentConfig)
    65  
    66  	// Create a new container initialisation lock.
    67  	s.initLockDir = c.MkDir()
    68  	initLock, err := fslock.NewLock(s.initLockDir, "container-init")
    69  	c.Assert(err, gc.IsNil)
    70  	s.initLock = initLock
    71  }
    72  
    73  func (s *ContainerSetupSuite) TearDownTest(c *gc.C) {
    74  	stop(c, s.p)
    75  	s.CommonProvisionerSuite.TearDownTest(c)
    76  }
    77  
    78  func (s *ContainerSetupSuite) setupContainerWorker(c *gc.C, tag string) worker.StringsWatchHandler {
    79  	runner := worker.NewRunner(allFatal, noImportance)
    80  	pr := s.st.Provisioner()
    81  	machine, err := pr.Machine(tag)
    82  	c.Assert(err, gc.IsNil)
    83  	err = machine.SetSupportedContainers(instance.ContainerTypes...)
    84  	c.Assert(err, gc.IsNil)
    85  	cfg := s.AgentConfigForTag(c, tag)
    86  
    87  	watcherName := fmt.Sprintf("%s-container-watcher", machine.Id())
    88  	handler := provisioner.NewContainerSetupHandler(runner, watcherName, instance.ContainerTypes, machine, pr, cfg, s.initLock)
    89  	runner.StartWorker(watcherName, func() (worker.Worker, error) {
    90  		return worker.NewStringsWorker(handler), nil
    91  	})
    92  	return handler
    93  }
    94  
    95  func (s *ContainerSetupSuite) createContainer(c *gc.C, host *state.Machine, ctype instance.ContainerType) {
    96  	inst := s.checkStartInstance(c, host)
    97  	s.setupContainerWorker(c, host.Tag())
    98  
    99  	// make a container on the host machine
   100  	template := state.MachineTemplate{
   101  		Series: coretesting.FakeDefaultSeries,
   102  		Jobs:   []state.MachineJob{state.JobHostUnits},
   103  	}
   104  	container, err := s.State.AddMachineInsideMachine(template, host.Id(), ctype)
   105  	c.Assert(err, gc.IsNil)
   106  
   107  	// the host machine agent should not attempt to create the container
   108  	s.checkNoOperations(c)
   109  
   110  	// cleanup
   111  	c.Assert(container.EnsureDead(), gc.IsNil)
   112  	c.Assert(container.Remove(), gc.IsNil)
   113  	c.Assert(host.EnsureDead(), gc.IsNil)
   114  	s.checkStopInstances(c, inst)
   115  	s.waitRemoved(c, host)
   116  }
   117  
   118  func (s *ContainerSetupSuite) assertContainerProvisionerStarted(
   119  	c *gc.C, host *state.Machine, ctype instance.ContainerType) {
   120  
   121  	// A stub worker callback to record what happens.
   122  	provisionerStarted := false
   123  	startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType,
   124  		pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker) error {
   125  		c.Assert(containerType, gc.Equals, ctype)
   126  		c.Assert(cfg.Tag(), gc.Equals, host.Tag())
   127  		provisionerStarted = true
   128  		return nil
   129  	}
   130  	s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker)
   131  
   132  	s.createContainer(c, host, ctype)
   133  	// Consume the apt command used to initialise the container.
   134  	<-s.aptCmdChan
   135  
   136  	// the container worker should have created the provisioner
   137  	c.Assert(provisionerStarted, jc.IsTrue)
   138  }
   139  
   140  func (s *ContainerSetupSuite) TestContainerProvisionerStarted(c *gc.C) {
   141  	for _, ctype := range instance.ContainerTypes {
   142  		// create a machine to host the container.
   143  		m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   144  			Series:      coretesting.FakeDefaultSeries,
   145  			Jobs:        []state.MachineJob{state.JobHostUnits},
   146  			Constraints: s.defaultConstraints,
   147  		})
   148  		c.Assert(err, gc.IsNil)
   149  		err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM})
   150  		c.Assert(err, gc.IsNil)
   151  		err = m.SetAgentVersion(version.Current)
   152  		c.Assert(err, gc.IsNil)
   153  		s.assertContainerProvisionerStarted(c, m, ctype)
   154  	}
   155  }
   156  
   157  func (s *ContainerSetupSuite) TestContainerManagerConfigName(c *gc.C) {
   158  	pr := s.st.Provisioner()
   159  	expect := func(expect string) {
   160  		cfg, err := provisioner.ContainerManagerConfig(instance.KVM, pr, s.agentConfig)
   161  		c.Assert(err, gc.IsNil)
   162  		c.Assert(cfg[container.ConfigName], gc.Equals, expect)
   163  	}
   164  	expect("juju")
   165  	s.agentConfig.SetValue(agent.Namespace, "any-old-thing")
   166  	expect("any-old-thing")
   167  }
   168  
   169  func (s *ContainerSetupSuite) assertContainerInitialised(c *gc.C, ctype instance.ContainerType, packages []string) {
   170  	// A noop worker callback.
   171  	startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType,
   172  		pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker) error {
   173  		return nil
   174  	}
   175  	s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker)
   176  
   177  	// create a machine to host the container.
   178  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   179  		Series:      coretesting.FakeDefaultSeries,
   180  		Jobs:        []state.MachineJob{state.JobHostUnits},
   181  		Constraints: s.defaultConstraints,
   182  	})
   183  	c.Assert(err, gc.IsNil)
   184  	err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM})
   185  	c.Assert(err, gc.IsNil)
   186  	err = m.SetAgentVersion(version.Current)
   187  	c.Assert(err, gc.IsNil)
   188  	s.createContainer(c, m, ctype)
   189  
   190  	cmd := <-s.aptCmdChan
   191  	c.Assert(cmd.Env[len(cmd.Env)-1], gc.Equals, "DEBIAN_FRONTEND=noninteractive")
   192  	expected := []string{
   193  		"apt-get", "--option=Dpkg::Options::=--force-confold",
   194  		"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
   195  		"install"}
   196  	expected = append(expected, packages...)
   197  	c.Assert(cmd.Args, gc.DeepEquals, expected)
   198  }
   199  
   200  func (s *ContainerSetupSuite) TestContainerInitialised(c *gc.C) {
   201  	for _, test := range []struct {
   202  		ctype    instance.ContainerType
   203  		packages []string
   204  	}{
   205  		{instance.LXC, []string{"--target-release", "precise-updates/cloud-tools", "lxc", "cloud-image-utils"}},
   206  		{instance.KVM, []string{"uvtool-libvirt", "uvtool"}},
   207  	} {
   208  		s.assertContainerInitialised(c, test.ctype, test.packages)
   209  	}
   210  }
   211  
   212  func (s *ContainerSetupSuite) TestContainerInitLockError(c *gc.C) {
   213  	m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
   214  		Series:      coretesting.FakeDefaultSeries,
   215  		Jobs:        []state.MachineJob{state.JobHostUnits},
   216  		Constraints: s.defaultConstraints,
   217  	})
   218  	c.Assert(err, gc.IsNil)
   219  	err = m.SetAgentVersion(version.Current)
   220  	c.Assert(err, gc.IsNil)
   221  
   222  	err = os.RemoveAll(s.initLockDir)
   223  	c.Assert(err, gc.IsNil)
   224  	handler := s.setupContainerWorker(c, m.Tag())
   225  	_, err = handler.SetUp()
   226  	c.Assert(err, gc.IsNil)
   227  	err = handler.Handle([]string{"0/lxc/0"})
   228  	c.Assert(err, gc.ErrorMatches, ".*failed to acquire initialization lock:.*")
   229  
   230  }