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