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