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