github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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 gitjujutesting "github.com/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils/arch" 16 "github.com/juju/utils/series" 17 gc "gopkg.in/check.v1" 18 "gopkg.in/juju/names.v2" 19 20 "github.com/juju/juju/agent" 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/instance" 26 "github.com/juju/juju/network" 27 "github.com/juju/juju/state" 28 coretesting "github.com/juju/juju/testing" 29 jujuversion "github.com/juju/juju/version" 30 "github.com/juju/juju/worker/provisioner" 31 ) 32 33 type kvmSuite struct { 34 kvmtesting.TestSuite 35 events chan mock.Event 36 eventsDone chan struct{} 37 } 38 39 type kvmBrokerSuite struct { 40 kvmSuite 41 broker environs.InstanceBroker 42 agentConfig agent.Config 43 api *fakeAPI 44 } 45 46 var _ = gc.Suite(&kvmBrokerSuite{}) 47 48 func (s *kvmSuite) SetUpTest(c *gc.C) { 49 if runtime.GOOS == "windows" { 50 c.Skip("Skipping kvm tests on windows") 51 } 52 s.TestSuite.SetUpTest(c) 53 s.events = make(chan mock.Event) 54 s.eventsDone = make(chan struct{}) 55 go func() { 56 defer close(s.eventsDone) 57 for event := range s.events { 58 c.Output(3, fmt.Sprintf("kvm event: <%s, %s>", event.Action, event.InstanceId)) 59 } 60 }() 61 s.TestSuite.ContainerFactory.AddListener(s.events) 62 } 63 64 func (s *kvmSuite) TearDownTest(c *gc.C) { 65 close(s.events) 66 <-s.eventsDone 67 s.TestSuite.TearDownTest(c) 68 } 69 70 func (s *kvmBrokerSuite) SetUpTest(c *gc.C) { 71 if runtime.GOOS == "windows" { 72 c.Skip("Skipping kvm tests on windows") 73 } 74 s.kvmSuite.SetUpTest(c) 75 var err error 76 s.agentConfig, err = agent.NewAgentConfig( 77 agent.AgentConfigParams{ 78 Paths: agent.NewPathsWithDefaults(agent.Paths{DataDir: "/not/used/here"}), 79 Tag: names.NewUnitTag("ubuntu/1"), 80 UpgradedToVersion: jujuversion.Current, 81 Password: "dummy-secret", 82 Nonce: "nonce", 83 APIAddresses: []string{"10.0.0.1:1234"}, 84 CACert: coretesting.CACert, 85 Controller: coretesting.ControllerTag, 86 Model: coretesting.ModelTag, 87 }) 88 c.Assert(err, jc.ErrorIsNil) 89 s.api = NewFakeAPI() 90 managerConfig := container.ManagerConfig{container.ConfigModelUUID: coretesting.ModelTag.Id()} 91 s.broker, err = provisioner.NewKvmBroker(s.api, s.agentConfig, managerConfig) 92 c.Assert(err, jc.ErrorIsNil) 93 } 94 95 func (s *kvmBrokerSuite) startInstance(c *gc.C, machineId string) *environs.StartInstanceResult { 96 return callStartInstance(c, s, s.broker, machineId) 97 } 98 99 func (s *kvmBrokerSuite) maintainInstance(c *gc.C, machineId string) { 100 callMaintainInstance(c, s, s.broker, machineId) 101 } 102 103 func (s *kvmBrokerSuite) TestStartInstance(c *gc.C) { 104 machineId := "1/kvm/0" 105 result := s.startInstance(c, machineId) 106 s.api.CheckCalls(c, []gitjujutesting.StubCall{{ 107 FuncName: "ContainerConfig", 108 }, { 109 FuncName: "PrepareContainerInterfaceInfo", 110 Args: []interface{}{names.NewMachineTag("1-kvm-0")}, 111 }}) 112 c.Assert(result.Instance.Id(), gc.Equals, instance.Id("juju-06f00d-1-kvm-0")) 113 s.assertResults(c, result) 114 } 115 116 func (s *kvmBrokerSuite) TestMaintainInstanceAddress(c *gc.C) { 117 machineId := "1/kvm/0" 118 result := s.startInstance(c, machineId) 119 s.api.ResetCalls() 120 121 s.maintainInstance(c, machineId) 122 s.api.CheckCalls(c, []gitjujutesting.StubCall{}) 123 c.Assert(result.Instance.Id(), gc.Equals, instance.Id("juju-06f00d-1-kvm-0")) 124 s.assertResults(c, result) 125 } 126 127 func (s *kvmBrokerSuite) TestStopInstance(c *gc.C) { 128 result0 := s.startInstance(c, "1/kvm/0") 129 result1 := s.startInstance(c, "1/kvm/1") 130 result2 := s.startInstance(c, "1/kvm/2") 131 132 err := s.broker.StopInstances(result0.Instance.Id()) 133 c.Assert(err, jc.ErrorIsNil) 134 s.assertResults(c, result1, result2) 135 c.Assert(s.kvmContainerDir(result0), jc.DoesNotExist) 136 c.Assert(s.kvmRemovedContainerDir(result0), jc.IsDirectory) 137 138 err = s.broker.StopInstances(result1.Instance.Id(), result2.Instance.Id()) 139 c.Assert(err, jc.ErrorIsNil) 140 s.assertNoResults(c) 141 } 142 143 func (s *kvmBrokerSuite) TestAllInstances(c *gc.C) { 144 result0 := s.startInstance(c, "1/kvm/0") 145 result1 := s.startInstance(c, "1/kvm/1") 146 s.assertResults(c, result0, result1) 147 148 err := s.broker.StopInstances(result1.Instance.Id()) 149 c.Assert(err, jc.ErrorIsNil) 150 result2 := s.startInstance(c, "1/kvm/2") 151 s.assertResults(c, result0, result2) 152 } 153 154 func (s *kvmBrokerSuite) assertResults(c *gc.C, results ...*environs.StartInstanceResult) { 155 assertInstancesStarted(c, s.broker, results...) 156 } 157 158 func (s *kvmBrokerSuite) assertNoResults(c *gc.C) { 159 s.assertResults(c) 160 } 161 162 func (s *kvmBrokerSuite) kvmContainerDir(result *environs.StartInstanceResult) string { 163 inst := result.Instance 164 return filepath.Join(s.ContainerDir, string(inst.Id())) 165 } 166 167 func (s *kvmBrokerSuite) kvmRemovedContainerDir(result *environs.StartInstanceResult) string { 168 inst := result.Instance 169 return filepath.Join(s.RemovedDir, string(inst.Id())) 170 } 171 172 func (s *kvmBrokerSuite) TestStartInstancePopulatesNetworkInfo(c *gc.C) { 173 patchResolvConf(s, c) 174 175 result := s.startInstance(c, "1/kvm/42") 176 c.Assert(result.NetworkInfo, gc.HasLen, 1) 177 iface := result.NetworkInfo[0] 178 c.Assert(iface, jc.DeepEquals, network.InterfaceInfo{ 179 DeviceIndex: 0, 180 CIDR: "0.1.2.0/24", 181 InterfaceName: "dummy0", 182 ParentInterfaceName: "virbr0", 183 MACAddress: "aa:bb:cc:dd:ee:ff", 184 Address: network.NewAddress("0.1.2.3"), 185 GatewayAddress: network.NewAddress("0.1.2.1"), 186 DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"), 187 DNSSearchDomains: []string{"dummy", "invalid"}, 188 }) 189 } 190 191 func (s *kvmBrokerSuite) TestStartInstancePopulatesFallbackNetworkInfo(c *gc.C) { 192 patchResolvConf(s, c) 193 194 s.api.SetErrors( 195 nil, // ContainerConfig succeeds 196 errors.NotSupportedf("container address allocation"), 197 ) 198 result := s.startInstance(c, "1/kvm/2") 199 200 c.Assert(result.NetworkInfo, jc.DeepEquals, []network.InterfaceInfo{{ 201 DeviceIndex: 0, 202 InterfaceName: "eth0", 203 InterfaceType: network.EthernetInterface, 204 ConfigType: network.ConfigDHCP, 205 ParentInterfaceName: "virbr0", 206 DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"), 207 DNSSearchDomains: []string{"dummy", "invalid"}, 208 }}) 209 } 210 211 type kvmProvisionerSuite struct { 212 CommonProvisionerSuite 213 kvmSuite 214 events chan mock.Event 215 } 216 217 var _ = gc.Suite(&kvmProvisionerSuite{}) 218 219 func (s *kvmProvisionerSuite) SetUpSuite(c *gc.C) { 220 if runtime.GOOS == "windows" { 221 c.Skip("Skipping kvm tests on windows") 222 } 223 s.CommonProvisionerSuite.SetUpSuite(c) 224 s.kvmSuite.SetUpSuite(c) 225 } 226 227 func (s *kvmProvisionerSuite) TearDownSuite(c *gc.C) { 228 s.kvmSuite.TearDownSuite(c) 229 s.CommonProvisionerSuite.TearDownSuite(c) 230 } 231 232 func (s *kvmProvisionerSuite) SetUpTest(c *gc.C) { 233 s.CommonProvisionerSuite.SetUpTest(c) 234 s.kvmSuite.SetUpTest(c) 235 236 s.events = make(chan mock.Event, 25) 237 s.ContainerFactory.AddListener(s.events) 238 } 239 240 func (s *kvmProvisionerSuite) nextEvent(c *gc.C) mock.Event { 241 select { 242 case event := <-s.events: 243 return event 244 case <-time.After(coretesting.LongWait): 245 c.Fatalf("no event arrived") 246 } 247 panic("not reachable") 248 } 249 250 func (s *kvmProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string { 251 s.State.StartSync() 252 event := s.nextEvent(c) 253 c.Assert(event.Action, gc.Equals, mock.Started) 254 err := machine.Refresh() 255 c.Assert(err, jc.ErrorIsNil) 256 s.waitInstanceId(c, machine, instance.Id(event.InstanceId)) 257 return event.InstanceId 258 } 259 260 func (s *kvmProvisionerSuite) expectStopped(c *gc.C, instId string) { 261 s.State.StartSync() 262 event := s.nextEvent(c) 263 c.Assert(event.Action, gc.Equals, mock.Stopped) 264 c.Assert(event.InstanceId, gc.Equals, instId) 265 } 266 267 func (s *kvmProvisionerSuite) expectNoEvents(c *gc.C) { 268 select { 269 case event := <-s.events: 270 c.Fatalf("unexpected event %#v", event) 271 case <-time.After(coretesting.ShortWait): 272 return 273 } 274 } 275 276 func (s *kvmProvisionerSuite) TearDownTest(c *gc.C) { 277 close(s.events) 278 s.kvmSuite.TearDownTest(c) 279 s.CommonProvisionerSuite.TearDownTest(c) 280 } 281 282 func (s *kvmProvisionerSuite) newKvmProvisioner(c *gc.C) provisioner.Provisioner { 283 machineTag := names.NewMachineTag("0") 284 agentConfig := s.AgentConfigForTag(c, machineTag) 285 managerConfig := container.ManagerConfig{container.ConfigModelUUID: coretesting.ModelTag.Id()} 286 broker, err := provisioner.NewKvmBroker(s.provisioner, agentConfig, managerConfig) 287 c.Assert(err, jc.ErrorIsNil) 288 toolsFinder := (*provisioner.GetToolsFinder)(s.provisioner) 289 w, err := provisioner.NewContainerProvisioner(instance.KVM, s.provisioner, agentConfig, broker, toolsFinder) 290 c.Assert(err, jc.ErrorIsNil) 291 return w 292 } 293 294 func (s *kvmProvisionerSuite) TestProvisionerStartStop(c *gc.C) { 295 p := s.newKvmProvisioner(c) 296 stop(c, p) 297 } 298 299 func (s *kvmProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) { 300 p := s.newKvmProvisioner(c) 301 defer stop(c, p) 302 303 // Check that an instance is not provisioned when the machine is created. 304 _, err := s.State.AddMachine(series.LatestLts(), state.JobHostUnits) 305 c.Assert(err, jc.ErrorIsNil) 306 307 s.expectNoEvents(c) 308 } 309 310 func (s *kvmProvisionerSuite) TestDoesNotHaveRetryWatcher(c *gc.C) { 311 p := s.newKvmProvisioner(c) 312 defer stop(c, p) 313 314 w, err := provisioner.GetRetryWatcher(p) 315 c.Assert(w, gc.IsNil) 316 c.Assert(err, jc.Satisfies, errors.IsNotImplemented) 317 } 318 319 func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine { 320 template := state.MachineTemplate{ 321 Series: series.LatestLts(), 322 Jobs: []state.MachineJob{state.JobHostUnits}, 323 } 324 container, err := s.State.AddMachineInsideMachine(template, "0", instance.KVM) 325 c.Assert(err, jc.ErrorIsNil) 326 return container 327 } 328 329 func (s *kvmProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) { 330 if arch.NormaliseArch(runtime.GOARCH) != arch.AMD64 { 331 c.Skip("Test only enabled on amd64, see bug lp:1572145") 332 } 333 p := s.newKvmProvisioner(c) 334 defer stop(c, p) 335 336 container := s.addContainer(c) 337 338 instId := s.expectStarted(c, container) 339 340 // ...and removed, along with the machine, when the machine is Dead. 341 c.Assert(container.EnsureDead(), gc.IsNil) 342 s.expectStopped(c, instId) 343 s.waitForRemovalMark(c, container) 344 } 345 346 func (s *kvmProvisionerSuite) TestKVMProvisionerObservesConfigChanges(c *gc.C) { 347 p := s.newKvmProvisioner(c) 348 defer stop(c, p) 349 s.assertProvisionerObservesConfigChanges(c, p) 350 }