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 }