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