github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/provisioner/lxc-broker_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "path/filepath" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/names" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils/set" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/agent" 19 "github.com/juju/juju/apiserver/params" 20 "github.com/juju/juju/constraints" 21 "github.com/juju/juju/container" 22 "github.com/juju/juju/container/lxc/mock" 23 lxctesting "github.com/juju/juju/container/lxc/testing" 24 containertesting "github.com/juju/juju/container/testing" 25 "github.com/juju/juju/environs" 26 "github.com/juju/juju/instance" 27 instancetest "github.com/juju/juju/instance/testing" 28 jujutesting "github.com/juju/juju/juju/testing" 29 "github.com/juju/juju/state" 30 coretesting "github.com/juju/juju/testing" 31 coretools "github.com/juju/juju/tools" 32 "github.com/juju/juju/version" 33 "github.com/juju/juju/worker/provisioner" 34 ) 35 36 type lxcSuite struct { 37 lxctesting.TestSuite 38 events chan mock.Event 39 eventsDone chan struct{} 40 } 41 42 type lxcBrokerSuite struct { 43 lxcSuite 44 broker environs.InstanceBroker 45 agentConfig agent.ConfigSetterWriter 46 } 47 48 var _ = gc.Suite(&lxcBrokerSuite{}) 49 50 func (s *lxcSuite) SetUpTest(c *gc.C) { 51 s.TestSuite.SetUpTest(c) 52 s.events = make(chan mock.Event) 53 s.eventsDone = make(chan struct{}) 54 go func() { 55 defer close(s.eventsDone) 56 for event := range s.events { 57 c.Output(3, fmt.Sprintf("lxc event: <%s, %s>", event.Action, event.InstanceId)) 58 } 59 }() 60 s.TestSuite.ContainerFactory.AddListener(s.events) 61 } 62 63 func (s *lxcSuite) TearDownTest(c *gc.C) { 64 close(s.events) 65 <-s.eventsDone 66 s.TestSuite.TearDownTest(c) 67 } 68 69 func (s *lxcBrokerSuite) SetUpTest(c *gc.C) { 70 s.lxcSuite.SetUpTest(c) 71 var err error 72 s.agentConfig, err = agent.NewAgentConfig( 73 agent.AgentConfigParams{ 74 DataDir: "/not/used/here", 75 Tag: names.NewMachineTag("1"), 76 UpgradedToVersion: version.Current.Number, 77 Password: "dummy-secret", 78 Nonce: "nonce", 79 APIAddresses: []string{"10.0.0.1:1234"}, 80 CACert: coretesting.CACert, 81 Environment: coretesting.EnvironmentTag, 82 }) 83 c.Assert(err, jc.ErrorIsNil) 84 managerConfig := container.ManagerConfig{ 85 container.ConfigName: "juju", 86 "log-dir": c.MkDir(), 87 "use-clone": "false", 88 } 89 s.broker, err = provisioner.NewLxcBroker(&fakeAPI{}, s.agentConfig, managerConfig, nil) 90 c.Assert(err, jc.ErrorIsNil) 91 } 92 93 func (s *lxcBrokerSuite) startInstance(c *gc.C, machineId string) instance.Instance { 94 machineNonce := "fake-nonce" 95 stateInfo := jujutesting.FakeStateInfo(machineId) 96 apiInfo := jujutesting.FakeAPIInfo(machineId) 97 machineConfig, err := environs.NewMachineConfig(machineId, machineNonce, "released", "quantal", true, nil, stateInfo, apiInfo) 98 c.Assert(err, jc.ErrorIsNil) 99 cons := constraints.Value{} 100 possibleTools := coretools.List{&coretools.Tools{ 101 Version: version.MustParseBinary("2.3.4-quantal-amd64"), 102 URL: "http://tools.testing.invalid/2.3.4-quantal-amd64.tgz", 103 }} 104 result, err := s.broker.StartInstance(environs.StartInstanceParams{ 105 Constraints: cons, 106 Tools: possibleTools, 107 MachineConfig: machineConfig, 108 }) 109 c.Assert(err, jc.ErrorIsNil) 110 return result.Instance 111 } 112 113 func (s *lxcBrokerSuite) TestStartInstance(c *gc.C) { 114 machineId := "1/lxc/0" 115 lxc := s.startInstance(c, machineId) 116 c.Assert(lxc.Id(), gc.Equals, instance.Id("juju-machine-1-lxc-0")) 117 c.Assert(s.lxcContainerDir(lxc), jc.IsDirectory) 118 s.assertInstances(c, lxc) 119 // Uses default network config 120 lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, string(lxc.Id()), "lxc.conf")) 121 c.Assert(err, jc.ErrorIsNil) 122 c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.type = veth") 123 c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = lxcbr0") 124 } 125 126 func (s *lxcBrokerSuite) TestStartInstanceWithBridgeEnviron(c *gc.C) { 127 s.agentConfig.SetValue(agent.LxcBridge, "br0") 128 machineId := "1/lxc/0" 129 lxc := s.startInstance(c, machineId) 130 c.Assert(lxc.Id(), gc.Equals, instance.Id("juju-machine-1-lxc-0")) 131 c.Assert(s.lxcContainerDir(lxc), jc.IsDirectory) 132 s.assertInstances(c, lxc) 133 // Uses default network config 134 lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, string(lxc.Id()), "lxc.conf")) 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.type = veth") 137 c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = br0") 138 } 139 140 func (s *lxcBrokerSuite) TestStopInstance(c *gc.C) { 141 lxc0 := s.startInstance(c, "1/lxc/0") 142 lxc1 := s.startInstance(c, "1/lxc/1") 143 lxc2 := s.startInstance(c, "1/lxc/2") 144 145 err := s.broker.StopInstances(lxc0.Id()) 146 c.Assert(err, jc.ErrorIsNil) 147 s.assertInstances(c, lxc1, lxc2) 148 c.Assert(s.lxcContainerDir(lxc0), jc.DoesNotExist) 149 c.Assert(s.lxcRemovedContainerDir(lxc0), jc.IsDirectory) 150 151 err = s.broker.StopInstances(lxc1.Id(), lxc2.Id()) 152 c.Assert(err, jc.ErrorIsNil) 153 s.assertInstances(c) 154 } 155 156 func (s *lxcBrokerSuite) TestAllInstances(c *gc.C) { 157 lxc0 := s.startInstance(c, "1/lxc/0") 158 lxc1 := s.startInstance(c, "1/lxc/1") 159 s.assertInstances(c, lxc0, lxc1) 160 161 err := s.broker.StopInstances(lxc1.Id()) 162 c.Assert(err, jc.ErrorIsNil) 163 lxc2 := s.startInstance(c, "1/lxc/2") 164 s.assertInstances(c, lxc0, lxc2) 165 } 166 167 func (s *lxcBrokerSuite) assertInstances(c *gc.C, inst ...instance.Instance) { 168 results, err := s.broker.AllInstances() 169 c.Assert(err, jc.ErrorIsNil) 170 instancetest.MatchInstances(c, results, inst...) 171 } 172 173 func (s *lxcBrokerSuite) lxcContainerDir(inst instance.Instance) string { 174 return filepath.Join(s.ContainerDir, string(inst.Id())) 175 } 176 177 func (s *lxcBrokerSuite) lxcRemovedContainerDir(inst instance.Instance) string { 178 return filepath.Join(s.RemovedDir, string(inst.Id())) 179 } 180 181 type lxcProvisionerSuite struct { 182 CommonProvisionerSuite 183 lxcSuite 184 events chan mock.Event 185 } 186 187 var _ = gc.Suite(&lxcProvisionerSuite{}) 188 189 func (s *lxcProvisionerSuite) SetUpSuite(c *gc.C) { 190 s.CommonProvisionerSuite.SetUpSuite(c) 191 s.lxcSuite.SetUpSuite(c) 192 } 193 194 func (s *lxcProvisionerSuite) TearDownSuite(c *gc.C) { 195 s.lxcSuite.TearDownSuite(c) 196 s.CommonProvisionerSuite.TearDownSuite(c) 197 } 198 199 func (s *lxcProvisionerSuite) SetUpTest(c *gc.C) { 200 s.CommonProvisionerSuite.SetUpTest(c) 201 s.lxcSuite.SetUpTest(c) 202 203 s.events = make(chan mock.Event, 25) 204 s.ContainerFactory.AddListener(s.events) 205 } 206 207 func (s *lxcProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string { 208 s.State.StartSync() 209 event := <-s.events 210 c.Assert(event.Action, gc.Equals, mock.Created) 211 argsSet := set.NewStrings(event.TemplateArgs...) 212 c.Assert(argsSet.Contains("imageURL"), jc.IsTrue) 213 event = <-s.events 214 c.Assert(event.Action, gc.Equals, mock.Started) 215 err := machine.Refresh() 216 c.Assert(err, jc.ErrorIsNil) 217 s.waitInstanceId(c, machine, instance.Id(event.InstanceId)) 218 return event.InstanceId 219 } 220 221 func (s *lxcProvisionerSuite) expectStopped(c *gc.C, instId string) { 222 s.State.StartSync() 223 event := <-s.events 224 c.Assert(event.Action, gc.Equals, mock.Stopped) 225 event = <-s.events 226 c.Assert(event.Action, gc.Equals, mock.Destroyed) 227 c.Assert(event.InstanceId, gc.Equals, instId) 228 } 229 230 func (s *lxcProvisionerSuite) expectNoEvents(c *gc.C) { 231 select { 232 case event := <-s.events: 233 c.Fatalf("unexpected event %#v", event) 234 case <-time.After(coretesting.ShortWait): 235 return 236 } 237 } 238 239 func (s *lxcProvisionerSuite) TearDownTest(c *gc.C) { 240 close(s.events) 241 s.lxcSuite.TearDownTest(c) 242 s.CommonProvisionerSuite.TearDownTest(c) 243 } 244 245 func (s *lxcProvisionerSuite) newLxcProvisioner(c *gc.C) provisioner.Provisioner { 246 parentMachineTag := names.NewMachineTag("0") 247 agentConfig := s.AgentConfigForTag(c, parentMachineTag) 248 managerConfig := container.ManagerConfig{ 249 container.ConfigName: "juju", 250 "log-dir": c.MkDir(), 251 "use-clone": "false", 252 } 253 broker, err := provisioner.NewLxcBroker(s.provisioner, agentConfig, managerConfig, &containertesting.MockURLGetter{}) 254 c.Assert(err, jc.ErrorIsNil) 255 return provisioner.NewContainerProvisioner(instance.LXC, s.provisioner, agentConfig, broker) 256 } 257 258 func (s *lxcProvisionerSuite) TestProvisionerStartStop(c *gc.C) { 259 p := s.newLxcProvisioner(c) 260 c.Assert(p.Stop(), gc.IsNil) 261 } 262 263 func (s *lxcProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) { 264 p := s.newLxcProvisioner(c) 265 defer stop(c, p) 266 267 // Check that an instance is not provisioned when the machine is created. 268 _, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits) 269 c.Assert(err, jc.ErrorIsNil) 270 271 s.expectNoEvents(c) 272 } 273 274 func (s *lxcProvisionerSuite) TestDoesNotHaveRetryWatcher(c *gc.C) { 275 p := s.newLxcProvisioner(c) 276 defer stop(c, p) 277 278 w, err := provisioner.GetRetryWatcher(p) 279 c.Assert(w, gc.IsNil) 280 c.Assert(err, jc.Satisfies, errors.IsNotImplemented) 281 } 282 283 func (s *lxcProvisionerSuite) addContainer(c *gc.C) *state.Machine { 284 template := state.MachineTemplate{ 285 Series: coretesting.FakeDefaultSeries, 286 Jobs: []state.MachineJob{state.JobHostUnits}, 287 } 288 container, err := s.State.AddMachineInsideMachine(template, "0", instance.LXC) 289 c.Assert(err, jc.ErrorIsNil) 290 return container 291 } 292 293 func (s *lxcProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) { 294 p := s.newLxcProvisioner(c) 295 defer stop(c, p) 296 297 container := s.addContainer(c) 298 instId := s.expectStarted(c, container) 299 300 // ...and removed, along with the machine, when the machine is Dead. 301 c.Assert(container.EnsureDead(), gc.IsNil) 302 s.expectStopped(c, instId) 303 s.waitRemoved(c, container) 304 } 305 306 type fakeAPI struct{} 307 308 func (*fakeAPI) ContainerConfig() (params.ContainerConfig, error) { 309 return params.ContainerConfig{ 310 UpdateBehavior: ¶ms.UpdateBehavior{true, true}, 311 ProviderType: "fake", 312 AuthorizedKeys: coretesting.FakeAuthKeys, 313 SSLHostnameVerification: true}, nil 314 }