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