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