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 }