github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/provisioner/kvm-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 "path/filepath" 9 "runtime" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/names" 14 gitjujutesting "github.com/juju/testing" 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/agent" 19 "github.com/juju/juju/cloudconfig/instancecfg" 20 "github.com/juju/juju/constraints" 21 "github.com/juju/juju/container" 22 "github.com/juju/juju/container/kvm/mock" 23 kvmtesting "github.com/juju/juju/container/kvm/testing" 24 "github.com/juju/juju/environs" 25 "github.com/juju/juju/feature" 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 kvmSuite struct { 37 kvmtesting.TestSuite 38 events chan mock.Event 39 eventsDone chan struct{} 40 } 41 42 type kvmBrokerSuite struct { 43 kvmSuite 44 broker environs.InstanceBroker 45 agentConfig agent.Config 46 api *fakeAPI 47 } 48 49 var _ = gc.Suite(&kvmBrokerSuite{}) 50 51 func (s *kvmSuite) SetUpTest(c *gc.C) { 52 if runtime.GOOS == "windows" { 53 c.Skip("Skipping kvm tests on windows") 54 } 55 s.TestSuite.SetUpTest(c) 56 s.events = make(chan mock.Event) 57 s.eventsDone = make(chan struct{}) 58 go func() { 59 defer close(s.eventsDone) 60 for event := range s.events { 61 c.Output(3, fmt.Sprintf("kvm event: <%s, %s>", event.Action, event.InstanceId)) 62 } 63 }() 64 s.TestSuite.ContainerFactory.AddListener(s.events) 65 } 66 67 func (s *kvmSuite) TearDownTest(c *gc.C) { 68 close(s.events) 69 <-s.eventsDone 70 s.TestSuite.TearDownTest(c) 71 } 72 73 func (s *kvmBrokerSuite) SetUpTest(c *gc.C) { 74 if runtime.GOOS == "windows" { 75 c.Skip("Skipping kvm tests on windows") 76 } 77 s.kvmSuite.SetUpTest(c) 78 var err error 79 s.agentConfig, err = agent.NewAgentConfig( 80 agent.AgentConfigParams{ 81 DataDir: "/not/used/here", 82 Tag: names.NewUnitTag("ubuntu/1"), 83 UpgradedToVersion: version.Current.Number, 84 Password: "dummy-secret", 85 Nonce: "nonce", 86 APIAddresses: []string{"10.0.0.1:1234"}, 87 CACert: coretesting.CACert, 88 Environment: coretesting.EnvironmentTag, 89 }) 90 c.Assert(err, jc.ErrorIsNil) 91 s.api = NewFakeAPI() 92 managerConfig := container.ManagerConfig{container.ConfigName: "juju"} 93 s.broker, err = provisioner.NewKvmBroker(s.api, s.agentConfig, managerConfig, false) 94 c.Assert(err, jc.ErrorIsNil) 95 } 96 97 func (s *kvmBrokerSuite) startInstance(c *gc.C, machineId string) instance.Instance { 98 machineNonce := "fake-nonce" 99 stateInfo := jujutesting.FakeStateInfo(machineId) 100 apiInfo := jujutesting.FakeAPIInfo(machineId) 101 instanceConfig, err := instancecfg.NewInstanceConfig(machineId, machineNonce, "released", "quantal", true, nil, stateInfo, apiInfo) 102 c.Assert(err, jc.ErrorIsNil) 103 cons := constraints.Value{} 104 possibleTools := coretools.List{&coretools.Tools{ 105 Version: version.MustParseBinary("2.3.4-quantal-amd64"), 106 URL: "http://tools.testing.invalid/2.3.4-quantal-amd64.tgz", 107 }} 108 result, err := s.broker.StartInstance(environs.StartInstanceParams{ 109 Constraints: cons, 110 Tools: possibleTools, 111 InstanceConfig: instanceConfig, 112 }) 113 c.Assert(err, jc.ErrorIsNil) 114 return result.Instance 115 } 116 117 func (s *kvmBrokerSuite) maintainInstance(c *gc.C, machineId string) { 118 machineNonce := "fake-nonce" 119 stateInfo := jujutesting.FakeStateInfo(machineId) 120 apiInfo := jujutesting.FakeAPIInfo(machineId) 121 instanceConfig, err := instancecfg.NewInstanceConfig(machineId, machineNonce, "released", "quantal", true, nil, stateInfo, apiInfo) 122 c.Assert(err, jc.ErrorIsNil) 123 cons := constraints.Value{} 124 possibleTools := coretools.List{&coretools.Tools{ 125 Version: version.MustParseBinary("2.3.4-quantal-amd64"), 126 URL: "http://tools.testing.invalid/2.3.4-quantal-amd64.tgz", 127 }} 128 err = s.broker.MaintainInstance(environs.StartInstanceParams{ 129 Constraints: cons, 130 Tools: possibleTools, 131 InstanceConfig: instanceConfig, 132 }) 133 c.Assert(err, jc.ErrorIsNil) 134 } 135 136 func (s *kvmBrokerSuite) TestStartInstance(c *gc.C) { 137 machineId := "1/kvm/0" 138 s.SetFeatureFlags(feature.AddressAllocation) 139 kvm := s.startInstance(c, machineId) 140 s.api.CheckCalls(c, []gitjujutesting.StubCall{{ 141 FuncName: "PrepareContainerInterfaceInfo", 142 Args: []interface{}{names.NewMachineTag("1-kvm-0")}, 143 }, { 144 FuncName: "ContainerConfig", 145 }}) 146 c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0")) 147 s.assertInstances(c, kvm) 148 } 149 150 func (s *kvmBrokerSuite) TestStartInstanceAddressAllocationDisabled(c *gc.C) { 151 machineId := "1/kvm/0" 152 kvm := s.startInstance(c, machineId) 153 s.api.CheckCalls(c, []gitjujutesting.StubCall{{ 154 FuncName: "ContainerConfig", 155 }}) 156 c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0")) 157 s.assertInstances(c, kvm) 158 } 159 160 func (s *kvmBrokerSuite) TestMaintainInstance(c *gc.C) { 161 machineId := "1/kvm/0" 162 s.SetFeatureFlags(feature.AddressAllocation) 163 kvm := s.startInstance(c, machineId) 164 s.api.ResetCalls() 165 166 s.maintainInstance(c, machineId) 167 s.api.CheckCalls(c, []gitjujutesting.StubCall{{ 168 FuncName: "GetContainerInterfaceInfo", 169 Args: []interface{}{names.NewMachineTag("1-kvm-0")}, 170 }}) 171 c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0")) 172 s.assertInstances(c, kvm) 173 } 174 175 func (s *kvmBrokerSuite) TestMaintainInstanceAddressAllocationDisabled(c *gc.C) { 176 machineId := "1/kvm/0" 177 kvm := s.startInstance(c, machineId) 178 s.api.ResetCalls() 179 180 s.maintainInstance(c, machineId) 181 s.api.CheckCalls(c, []gitjujutesting.StubCall{}) 182 c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0")) 183 s.assertInstances(c, kvm) 184 } 185 186 func (s *kvmBrokerSuite) TestStopInstance(c *gc.C) { 187 kvm0 := s.startInstance(c, "1/kvm/0") 188 kvm1 := s.startInstance(c, "1/kvm/1") 189 kvm2 := s.startInstance(c, "1/kvm/2") 190 191 err := s.broker.StopInstances(kvm0.Id()) 192 c.Assert(err, jc.ErrorIsNil) 193 s.assertInstances(c, kvm1, kvm2) 194 c.Assert(s.kvmContainerDir(kvm0), jc.DoesNotExist) 195 c.Assert(s.kvmRemovedContainerDir(kvm0), jc.IsDirectory) 196 197 err = s.broker.StopInstances(kvm1.Id(), kvm2.Id()) 198 c.Assert(err, jc.ErrorIsNil) 199 s.assertInstances(c) 200 } 201 202 func (s *kvmBrokerSuite) TestAllInstances(c *gc.C) { 203 kvm0 := s.startInstance(c, "1/kvm/0") 204 kvm1 := s.startInstance(c, "1/kvm/1") 205 s.assertInstances(c, kvm0, kvm1) 206 207 err := s.broker.StopInstances(kvm1.Id()) 208 c.Assert(err, jc.ErrorIsNil) 209 kvm2 := s.startInstance(c, "1/kvm/2") 210 s.assertInstances(c, kvm0, kvm2) 211 } 212 213 func (s *kvmBrokerSuite) assertInstances(c *gc.C, inst ...instance.Instance) { 214 results, err := s.broker.AllInstances() 215 c.Assert(err, jc.ErrorIsNil) 216 instancetest.MatchInstances(c, results, inst...) 217 } 218 219 func (s *kvmBrokerSuite) kvmContainerDir(inst instance.Instance) string { 220 return filepath.Join(s.ContainerDir, string(inst.Id())) 221 } 222 223 func (s *kvmBrokerSuite) kvmRemovedContainerDir(inst instance.Instance) string { 224 return filepath.Join(s.RemovedDir, string(inst.Id())) 225 } 226 227 type kvmProvisionerSuite struct { 228 CommonProvisionerSuite 229 kvmSuite 230 events chan mock.Event 231 } 232 233 var _ = gc.Suite(&kvmProvisionerSuite{}) 234 235 func (s *kvmProvisionerSuite) SetUpSuite(c *gc.C) { 236 if runtime.GOOS == "windows" { 237 c.Skip("Skipping kvm tests on windows") 238 } 239 s.CommonProvisionerSuite.SetUpSuite(c) 240 s.kvmSuite.SetUpSuite(c) 241 } 242 243 func (s *kvmProvisionerSuite) TearDownSuite(c *gc.C) { 244 s.kvmSuite.TearDownSuite(c) 245 s.CommonProvisionerSuite.TearDownSuite(c) 246 } 247 248 func (s *kvmProvisionerSuite) SetUpTest(c *gc.C) { 249 s.CommonProvisionerSuite.SetUpTest(c) 250 s.kvmSuite.SetUpTest(c) 251 252 s.events = make(chan mock.Event, 25) 253 s.ContainerFactory.AddListener(s.events) 254 } 255 256 func (s *kvmProvisionerSuite) nextEvent(c *gc.C) mock.Event { 257 select { 258 case event := <-s.events: 259 return event 260 case <-time.After(coretesting.LongWait): 261 c.Fatalf("no event arrived") 262 } 263 panic("not reachable") 264 } 265 266 func (s *kvmProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string { 267 // This check in particular leads to tests just hanging 268 // indefinitely quite often on i386. 269 coretesting.SkipIfI386(c, "lp:1425569") 270 271 s.State.StartSync() 272 event := s.nextEvent(c) 273 c.Assert(event.Action, gc.Equals, mock.Started) 274 err := machine.Refresh() 275 c.Assert(err, jc.ErrorIsNil) 276 s.waitInstanceId(c, machine, instance.Id(event.InstanceId)) 277 return event.InstanceId 278 } 279 280 func (s *kvmProvisionerSuite) expectStopped(c *gc.C, instId string) { 281 // This check in particular leads to tests just hanging 282 // indefinitely quite often on i386. 283 coretesting.SkipIfI386(c, "lp:1425569") 284 285 s.State.StartSync() 286 event := s.nextEvent(c) 287 c.Assert(event.Action, gc.Equals, mock.Stopped) 288 c.Assert(event.InstanceId, gc.Equals, instId) 289 } 290 291 func (s *kvmProvisionerSuite) expectNoEvents(c *gc.C) { 292 select { 293 case event := <-s.events: 294 c.Fatalf("unexpected event %#v", event) 295 case <-time.After(coretesting.ShortWait): 296 return 297 } 298 } 299 300 func (s *kvmProvisionerSuite) TearDownTest(c *gc.C) { 301 close(s.events) 302 s.kvmSuite.TearDownTest(c) 303 s.CommonProvisionerSuite.TearDownTest(c) 304 } 305 306 func (s *kvmProvisionerSuite) newKvmProvisioner(c *gc.C) provisioner.Provisioner { 307 machineTag := names.NewMachineTag("0") 308 agentConfig := s.AgentConfigForTag(c, machineTag) 309 managerConfig := container.ManagerConfig{container.ConfigName: "juju"} 310 broker, err := provisioner.NewKvmBroker(s.provisioner, agentConfig, managerConfig, false) 311 c.Assert(err, jc.ErrorIsNil) 312 toolsFinder := (*provisioner.GetToolsFinder)(s.provisioner) 313 return provisioner.NewContainerProvisioner(instance.KVM, s.provisioner, agentConfig, broker, toolsFinder) 314 } 315 316 func (s *kvmProvisionerSuite) TestProvisionerStartStop(c *gc.C) { 317 p := s.newKvmProvisioner(c) 318 c.Assert(p.Stop(), gc.IsNil) 319 } 320 321 func (s *kvmProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) { 322 p := s.newKvmProvisioner(c) 323 defer stop(c, p) 324 325 // Check that an instance is not provisioned when the machine is created. 326 _, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits) 327 c.Assert(err, jc.ErrorIsNil) 328 329 s.expectNoEvents(c) 330 } 331 332 func (s *kvmProvisionerSuite) TestDoesNotHaveRetryWatcher(c *gc.C) { 333 p := s.newKvmProvisioner(c) 334 defer stop(c, p) 335 336 w, err := provisioner.GetRetryWatcher(p) 337 c.Assert(w, gc.IsNil) 338 c.Assert(err, jc.Satisfies, errors.IsNotImplemented) 339 } 340 341 func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine { 342 template := state.MachineTemplate{ 343 Series: coretesting.FakeDefaultSeries, 344 Jobs: []state.MachineJob{state.JobHostUnits}, 345 } 346 container, err := s.State.AddMachineInsideMachine(template, "0", instance.KVM) 347 c.Assert(err, jc.ErrorIsNil) 348 return container 349 } 350 351 func (s *kvmProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) { 352 coretesting.SkipIfI386(c, "lp:1425569") 353 354 p := s.newKvmProvisioner(c) 355 defer stop(c, p) 356 357 container := s.addContainer(c) 358 359 instId := s.expectStarted(c, container) 360 361 // ...and removed, along with the machine, when the machine is Dead. 362 c.Assert(container.EnsureDead(), gc.IsNil) 363 s.expectStopped(c, instId) 364 s.waitRemoved(c, container) 365 } 366 367 func (s *kvmProvisionerSuite) TestKVMProvisionerObservesConfigChanges(c *gc.C) { 368 p := s.newKvmProvisioner(c) 369 defer stop(c, p) 370 s.assertProvisionerObservesConfigChanges(c, p) 371 }