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 }