github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/api/provisioner/provisioner_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // TODO(anastasia) 2014-10-08 #1378716 5 // Re-enable tests for PPC64/ARM64 when the fixed gccgo has been backported to trusty and the CI machines have been updated. 6 7 // +build !gccgo 8 9 package provisioner_test 10 11 import ( 12 "fmt" 13 stdtesting "testing" 14 15 "github.com/juju/errors" 16 "github.com/juju/names" 17 jc "github.com/juju/testing/checkers" 18 "github.com/juju/utils" 19 "github.com/juju/utils/arch" 20 "github.com/juju/utils/series" 21 gc "gopkg.in/check.v1" 22 23 "github.com/juju/juju/api" 24 "github.com/juju/juju/api/provisioner" 25 apitesting "github.com/juju/juju/api/testing" 26 "github.com/juju/juju/apiserver/common" 27 "github.com/juju/juju/apiserver/params" 28 "github.com/juju/juju/constraints" 29 "github.com/juju/juju/container" 30 "github.com/juju/juju/feature" 31 "github.com/juju/juju/instance" 32 "github.com/juju/juju/juju/testing" 33 "github.com/juju/juju/mongo" 34 "github.com/juju/juju/network" 35 "github.com/juju/juju/state" 36 statetesting "github.com/juju/juju/state/testing" 37 "github.com/juju/juju/storage/poolmanager" 38 "github.com/juju/juju/storage/provider" 39 coretesting "github.com/juju/juju/testing" 40 coretools "github.com/juju/juju/tools" 41 "github.com/juju/juju/version" 42 ) 43 44 func TestAll(t *stdtesting.T) { 45 coretesting.MgoTestPackage(t) 46 } 47 48 type provisionerSuite struct { 49 testing.JujuConnSuite 50 *apitesting.EnvironWatcherTests 51 *apitesting.APIAddresserTests 52 53 st api.Connection 54 machine *state.Machine 55 56 provisioner *provisioner.State 57 } 58 59 var _ = gc.Suite(&provisionerSuite{}) 60 61 func (s *provisionerSuite) SetUpTest(c *gc.C) { 62 s.JujuConnSuite.SetUpTest(c) 63 // We're testing with address allocation on by default. There are 64 // separate tests to check the behavior when the flag is not 65 // enabled. 66 s.SetFeatureFlags(feature.AddressAllocation) 67 68 var err error 69 s.machine, err = s.State.AddMachine("quantal", state.JobManageEnviron) 70 c.Assert(err, jc.ErrorIsNil) 71 password, err := utils.RandomPassword() 72 c.Assert(err, jc.ErrorIsNil) 73 err = s.machine.SetPassword(password) 74 c.Assert(err, jc.ErrorIsNil) 75 err = s.machine.SetInstanceInfo("i-manager", "fake_nonce", nil, nil, nil, nil, nil) 76 c.Assert(err, jc.ErrorIsNil) 77 s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce") 78 c.Assert(s.st, gc.NotNil) 79 err = s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 80 c.Assert(err, jc.ErrorIsNil) 81 82 // Create the provisioner API facade. 83 s.provisioner = s.st.Provisioner() 84 c.Assert(s.provisioner, gc.NotNil) 85 86 s.EnvironWatcherTests = apitesting.NewEnvironWatcherTests(s.provisioner, s.BackingState, apitesting.HasSecrets) 87 s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState) 88 } 89 90 func (s *provisionerSuite) TestPrepareContainerInterfaceInfoNoFeatureFlag(c *gc.C) { 91 s.SetFeatureFlags() // clear the flag 92 ifaceInfo, err := s.provisioner.PrepareContainerInterfaceInfo(names.NewMachineTag("42")) 93 c.Assert(err, gc.ErrorMatches, "address allocation not supported") 94 c.Assert(ifaceInfo, gc.HasLen, 0) 95 } 96 97 func (s *provisionerSuite) TestReleaseContainerAddressNoFeatureFlag(c *gc.C) { 98 s.SetFeatureFlags() // clear the flag 99 err := s.provisioner.ReleaseContainerAddresses(names.NewMachineTag("42")) 100 c.Assert(err, gc.ErrorMatches, 101 `cannot release static addresses for "42": address allocation not supported`, 102 ) 103 } 104 105 func (s *provisionerSuite) TestMachineTagAndId(c *gc.C) { 106 apiMachine, err := s.provisioner.Machine(names.NewMachineTag("42")) 107 c.Assert(err, gc.ErrorMatches, "machine 42 not found") 108 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 109 c.Assert(apiMachine, gc.IsNil) 110 111 // TODO(dfc) fix this type assertion 112 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 113 c.Assert(err, jc.ErrorIsNil) 114 c.Assert(apiMachine.Tag(), gc.Equals, s.machine.Tag()) 115 c.Assert(apiMachine.Id(), gc.Equals, s.machine.Id()) 116 } 117 118 func (s *provisionerSuite) TestGetSetStatus(c *gc.C) { 119 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 120 c.Assert(err, jc.ErrorIsNil) 121 122 status, info, err := apiMachine.Status() 123 c.Assert(err, jc.ErrorIsNil) 124 c.Assert(status, gc.Equals, params.StatusPending) 125 c.Assert(info, gc.Equals, "") 126 127 err = apiMachine.SetStatus(params.StatusStarted, "blah", nil) 128 c.Assert(err, jc.ErrorIsNil) 129 130 status, info, err = apiMachine.Status() 131 c.Assert(err, jc.ErrorIsNil) 132 c.Assert(status, gc.Equals, params.StatusStarted) 133 c.Assert(info, gc.Equals, "blah") 134 statusInfo, err := s.machine.Status() 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(statusInfo.Data, gc.HasLen, 0) 137 } 138 139 func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) { 140 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 141 c.Assert(err, jc.ErrorIsNil) 142 143 err = apiMachine.SetStatus(params.StatusError, "blah", map[string]interface{}{"foo": "bar"}) 144 c.Assert(err, jc.ErrorIsNil) 145 146 status, info, err := apiMachine.Status() 147 c.Assert(err, jc.ErrorIsNil) 148 c.Assert(status, gc.Equals, params.StatusError) 149 c.Assert(info, gc.Equals, "blah") 150 statusInfo, err := s.machine.Status() 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"foo": "bar"}) 153 } 154 155 func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) { 156 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 157 c.Assert(err, jc.ErrorIsNil) 158 err = machine.SetStatus(state.StatusError, "blah", map[string]interface{}{"transient": true}) 159 c.Assert(err, jc.ErrorIsNil) 160 machines, info, err := s.provisioner.MachinesWithTransientErrors() 161 c.Assert(err, jc.ErrorIsNil) 162 c.Assert(machines, gc.HasLen, 1) 163 c.Assert(machines[0].Id(), gc.Equals, "1") 164 c.Assert(info, gc.HasLen, 1) 165 c.Assert(info[0], gc.DeepEquals, params.StatusResult{ 166 Id: "1", 167 Life: "alive", 168 Status: "error", 169 Info: "blah", 170 Data: map[string]interface{}{"transient": true}, 171 }) 172 } 173 174 func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) { 175 // Create a fresh machine to test the complete scenario. 176 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 179 180 apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag)) 181 c.Assert(err, jc.ErrorIsNil) 182 183 err = apiMachine.Remove() 184 c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`) 185 err = apiMachine.EnsureDead() 186 c.Assert(err, jc.ErrorIsNil) 187 188 err = otherMachine.Refresh() 189 c.Assert(err, jc.ErrorIsNil) 190 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 191 192 err = apiMachine.EnsureDead() 193 c.Assert(err, jc.ErrorIsNil) 194 err = otherMachine.Refresh() 195 c.Assert(err, jc.ErrorIsNil) 196 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 197 198 err = apiMachine.Remove() 199 c.Assert(err, jc.ErrorIsNil) 200 err = otherMachine.Refresh() 201 c.Assert(err, jc.Satisfies, errors.IsNotFound) 202 203 err = apiMachine.EnsureDead() 204 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 205 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 206 207 // Now try to EnsureDead machine 0 - should fail. 208 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 209 c.Assert(err, jc.ErrorIsNil) 210 err = apiMachine.EnsureDead() 211 c.Assert(err, gc.ErrorMatches, "machine 0 is required by the environment") 212 } 213 214 func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) { 215 // Create a fresh machine to test the complete scenario. 216 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 217 c.Assert(err, jc.ErrorIsNil) 218 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 219 220 apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag)) 221 c.Assert(err, jc.ErrorIsNil) 222 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 223 224 err = apiMachine.EnsureDead() 225 c.Assert(err, jc.ErrorIsNil) 226 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 227 228 err = apiMachine.Refresh() 229 c.Assert(err, jc.ErrorIsNil) 230 c.Assert(apiMachine.Life(), gc.Equals, params.Dead) 231 } 232 233 func (s *provisionerSuite) TestSetInstanceInfo(c *gc.C) { 234 pm := poolmanager.New(state.NewStateSettings(s.State)) 235 _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"}) 236 c.Assert(err, jc.ErrorIsNil) 237 238 // Create a fresh machine, since machine 0 is already provisioned. 239 template := state.MachineTemplate{ 240 Series: "quantal", 241 Jobs: []state.MachineJob{state.JobHostUnits}, 242 Volumes: []state.MachineVolumeParams{{ 243 Volume: state.VolumeParams{ 244 Pool: "loop-pool", 245 Size: 123, 246 }}, 247 }, 248 } 249 notProvisionedMachine, err := s.State.AddOneMachine(template) 250 c.Assert(err, jc.ErrorIsNil) 251 252 apiMachine, err := s.provisioner.Machine(notProvisionedMachine.Tag().(names.MachineTag)) 253 c.Assert(err, jc.ErrorIsNil) 254 255 instanceId, err := apiMachine.InstanceId() 256 c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) 257 c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned") 258 c.Assert(instanceId, gc.Equals, instance.Id("")) 259 260 hwChars := instance.MustParseHardware("cpu-cores=123", "mem=4G") 261 262 _, err = s.State.Network("net1") 263 c.Assert(err, jc.Satisfies, errors.IsNotFound) 264 _, err = s.State.Network("vlan42") 265 c.Assert(err, jc.Satisfies, errors.IsNotFound) 266 267 ifacesMachine, err := notProvisionedMachine.NetworkInterfaces() 268 c.Assert(err, jc.ErrorIsNil) 269 c.Assert(ifacesMachine, gc.HasLen, 0) 270 271 networks := []params.Network{{ 272 Tag: "network-net1", 273 ProviderId: "net1", 274 CIDR: "0.1.2.0/24", 275 VLANTag: 0, 276 }, { 277 Tag: "network-vlan42", 278 ProviderId: "vlan42", 279 CIDR: "0.2.2.0/24", 280 VLANTag: 42, 281 }, { 282 Tag: "network-vlan69", 283 ProviderId: "vlan69", 284 CIDR: "0.3.2.0/24", 285 VLANTag: 69, 286 }, { 287 Tag: "network-vlan42", // duplicated; ignored 288 ProviderId: "vlan42", 289 CIDR: "0.2.2.0/24", 290 VLANTag: 42, 291 }} 292 ifaces := []params.NetworkInterface{{ 293 MACAddress: "aa:bb:cc:dd:ee:f0", 294 NetworkTag: "network-net1", 295 InterfaceName: "eth0", 296 IsVirtual: false, 297 }, { 298 MACAddress: "aa:bb:cc:dd:ee:f1", 299 NetworkTag: "network-net1", 300 InterfaceName: "eth1", 301 IsVirtual: false, 302 }, { 303 MACAddress: "aa:bb:cc:dd:ee:f1", 304 NetworkTag: "network-vlan42", 305 InterfaceName: "eth1.42", 306 IsVirtual: true, 307 }, { 308 MACAddress: "aa:bb:cc:dd:ee:f1", 309 NetworkTag: "network-vlan69", 310 InterfaceName: "eth1.69", 311 IsVirtual: true, 312 }, { 313 MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored 314 NetworkTag: "network-vlan42", 315 InterfaceName: "eth2", 316 IsVirtual: true, 317 }, { 318 MACAddress: "aa:bb:cc:dd:ee:f4", 319 NetworkTag: "network-net1", 320 InterfaceName: "eth1", // duplicated name+machine id; ignored 321 IsVirtual: false, 322 }} 323 volumes := []params.Volume{{ 324 VolumeTag: "volume-1-0", 325 Info: params.VolumeInfo{ 326 VolumeId: "vol-123", 327 Size: 124, 328 }, 329 }} 330 volumeAttachments := map[string]params.VolumeAttachmentInfo{ 331 "volume-1-0": { 332 DeviceName: "xvdf1", 333 }, 334 } 335 336 err = apiMachine.SetInstanceInfo( 337 "i-will", "fake_nonce", &hwChars, networks, ifaces, volumes, volumeAttachments, 338 ) 339 c.Assert(err, jc.ErrorIsNil) 340 341 instanceId, err = apiMachine.InstanceId() 342 c.Assert(err, jc.ErrorIsNil) 343 c.Assert(instanceId, gc.Equals, instance.Id("i-will")) 344 345 // Try it again - should fail. 346 err = apiMachine.SetInstanceInfo("i-wont", "fake", nil, nil, nil, nil, nil) 347 c.Assert(err, gc.ErrorMatches, `cannot record provisioning info for "i-wont": cannot set instance data for machine "1": already set`) 348 349 // Now try to get machine 0's instance id. 350 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 351 c.Assert(err, jc.ErrorIsNil) 352 instanceId, err = apiMachine.InstanceId() 353 c.Assert(err, jc.ErrorIsNil) 354 c.Assert(instanceId, gc.Equals, instance.Id("i-manager")) 355 356 // Check the networks are created. 357 for i := range networks { 358 if i == 3 { 359 // Last one was ignored, so skip it. 360 break 361 } 362 tag, err := names.ParseNetworkTag(networks[i].Tag) 363 c.Assert(err, jc.ErrorIsNil) 364 networkName := tag.Id() 365 nw, err := s.State.Network(networkName) 366 c.Assert(err, jc.ErrorIsNil) 367 c.Check(nw.Name(), gc.Equals, networkName) 368 c.Check(nw.ProviderId(), gc.Equals, network.Id(networks[i].ProviderId)) 369 c.Check(nw.Tag().String(), gc.Equals, networks[i].Tag) 370 c.Check(nw.VLANTag(), gc.Equals, networks[i].VLANTag) 371 c.Check(nw.CIDR(), gc.Equals, networks[i].CIDR) 372 } 373 374 // And the network interfaces as well. 375 ifacesMachine, err = notProvisionedMachine.NetworkInterfaces() 376 c.Assert(err, jc.ErrorIsNil) 377 c.Assert(ifacesMachine, gc.HasLen, 4) 378 actual := make([]params.NetworkInterface, len(ifacesMachine)) 379 for i, iface := range ifacesMachine { 380 actual[i].InterfaceName = iface.InterfaceName() 381 actual[i].NetworkTag = iface.NetworkTag().String() 382 actual[i].MACAddress = iface.MACAddress() 383 actual[i].IsVirtual = iface.IsVirtual() 384 c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag()) 385 c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id()) 386 } 387 c.Assert(actual, jc.SameContents, ifaces[:4]) // skip the rest as they are ignored. 388 389 // Now check volumes and volume attachments. 390 volume, err := s.State.Volume(names.NewVolumeTag("1/0")) 391 c.Assert(err, jc.ErrorIsNil) 392 volumeInfo, err := volume.Info() 393 c.Assert(err, jc.ErrorIsNil) 394 c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{ 395 VolumeId: "vol-123", 396 Pool: "loop-pool", 397 Size: 124, 398 }) 399 stateVolumeAttachments, err := s.State.MachineVolumeAttachments(names.NewMachineTag("1")) 400 c.Assert(err, jc.ErrorIsNil) 401 c.Assert(stateVolumeAttachments, gc.HasLen, 1) 402 volumeAttachmentInfo, err := stateVolumeAttachments[0].Info() 403 c.Assert(err, jc.ErrorIsNil) 404 c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{ 405 DeviceName: "xvdf1", 406 }) 407 } 408 409 func (s *provisionerSuite) TestSeries(c *gc.C) { 410 // Create a fresh machine with different series. 411 foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits) 412 c.Assert(err, jc.ErrorIsNil) 413 414 apiMachine, err := s.provisioner.Machine(foobarMachine.Tag().(names.MachineTag)) 415 c.Assert(err, jc.ErrorIsNil) 416 series, err := apiMachine.Series() 417 c.Assert(err, jc.ErrorIsNil) 418 c.Assert(series, gc.Equals, "foobar") 419 420 // Now try machine 0. 421 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 422 c.Assert(err, jc.ErrorIsNil) 423 series, err = apiMachine.Series() 424 c.Assert(err, jc.ErrorIsNil) 425 c.Assert(series, gc.Equals, "quantal") 426 } 427 428 func (s *provisionerSuite) TestDistributionGroup(c *gc.C) { 429 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 430 c.Assert(err, jc.ErrorIsNil) 431 instances, err := apiMachine.DistributionGroup() 432 c.Assert(err, jc.ErrorIsNil) 433 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"}) 434 435 machine1, err := s.State.AddMachine("quantal", state.JobHostUnits) 436 c.Assert(err, jc.ErrorIsNil) 437 apiMachine, err = s.provisioner.Machine(machine1.Tag().(names.MachineTag)) 438 c.Assert(err, jc.ErrorIsNil) 439 wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 440 441 err = apiMachine.SetInstanceInfo("i-d", "fake", nil, nil, nil, nil, nil) 442 c.Assert(err, jc.ErrorIsNil) 443 instances, err = apiMachine.DistributionGroup() 444 c.Assert(err, jc.ErrorIsNil) 445 c.Assert(instances, gc.HasLen, 0) // no units assigned 446 447 var unitNames []string 448 for i := 0; i < 3; i++ { 449 unit, err := wordpress.AddUnit() 450 c.Assert(err, jc.ErrorIsNil) 451 unitNames = append(unitNames, unit.Name()) 452 err = unit.AssignToMachine(machine1) 453 c.Assert(err, jc.ErrorIsNil) 454 instances, err := apiMachine.DistributionGroup() 455 c.Assert(err, jc.ErrorIsNil) 456 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"}) 457 } 458 } 459 460 func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) { 461 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 462 c.Assert(err, jc.ErrorIsNil) 463 apiMachine, err := s.provisioner.Machine(stateMachine.Tag().(names.MachineTag)) 464 c.Assert(err, jc.ErrorIsNil) 465 err = apiMachine.EnsureDead() 466 c.Assert(err, jc.ErrorIsNil) 467 err = apiMachine.Remove() 468 c.Assert(err, jc.ErrorIsNil) 469 _, err = apiMachine.DistributionGroup() 470 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 471 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 472 } 473 474 func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) { 475 // Add a couple of spaces. 476 _, err := s.State.AddSpace("space1", nil, true) 477 c.Assert(err, jc.ErrorIsNil) 478 _, err = s.State.AddSpace("space2", nil, false) 479 c.Assert(err, jc.ErrorIsNil) 480 // Add 2 subnets into each space. 481 // Only the first subnet of space2 has AllocatableIPLow|High set. 482 // Each subnet is in a matching zone (e.g "subnet-#" in "zone#"). 483 testing.AddSubnetsWithTemplate(c, s.State, 4, state.SubnetInfo{ 484 CIDR: "10.{{.}}.0.0/16", 485 ProviderId: "subnet-{{.}}", 486 AllocatableIPLow: "{{if (eq . 2)}}10.{{.}}.0.5{{end}}", 487 AllocatableIPHigh: "{{if (eq . 2)}}10.{{.}}.254.254{{end}}", 488 AvailabilityZone: "zone{{.}}", 489 SpaceName: "{{if (lt . 2)}}space1{{else}}space2{{end}}", 490 }) 491 492 cons := constraints.MustParse("cpu-cores=12 mem=8G spaces=^space1,space2") 493 template := state.MachineTemplate{ 494 Series: "quantal", 495 Jobs: []state.MachineJob{state.JobHostUnits}, 496 Placement: "valid", 497 Constraints: cons, 498 } 499 machine, err := s.State.AddOneMachine(template) 500 c.Assert(err, jc.ErrorIsNil) 501 apiMachine, err := s.provisioner.Machine(machine.Tag().(names.MachineTag)) 502 c.Assert(err, jc.ErrorIsNil) 503 provisioningInfo, err := apiMachine.ProvisioningInfo() 504 c.Assert(err, jc.ErrorIsNil) 505 c.Assert(provisioningInfo.Series, gc.Equals, template.Series) 506 c.Assert(provisioningInfo.Placement, gc.Equals, template.Placement) 507 c.Assert(provisioningInfo.Constraints, jc.DeepEquals, template.Constraints) 508 c.Assert(provisioningInfo.Networks, gc.HasLen, 0) 509 c.Assert(provisioningInfo.SubnetsToZones, jc.DeepEquals, map[string][]string{ 510 "subnet-2": []string{"zone2"}, 511 "subnet-3": []string{"zone3"}, 512 }) 513 } 514 515 func (s *provisionerSuite) TestProvisioningInfoMachineNotFound(c *gc.C) { 516 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 517 c.Assert(err, jc.ErrorIsNil) 518 apiMachine, err := s.provisioner.Machine(stateMachine.Tag().(names.MachineTag)) 519 c.Assert(err, jc.ErrorIsNil) 520 err = apiMachine.EnsureDead() 521 c.Assert(err, jc.ErrorIsNil) 522 err = apiMachine.Remove() 523 c.Assert(err, jc.ErrorIsNil) 524 _, err = apiMachine.ProvisioningInfo() 525 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 526 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 527 // auth tests in apiserver 528 } 529 530 func (s *provisionerSuite) TestWatchContainers(c *gc.C) { 531 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 532 c.Assert(err, jc.ErrorIsNil) 533 534 // Add one LXC container. 535 template := state.MachineTemplate{ 536 Series: "quantal", 537 Jobs: []state.MachineJob{state.JobHostUnits}, 538 } 539 container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC) 540 c.Assert(err, jc.ErrorIsNil) 541 542 w, err := apiMachine.WatchContainers(instance.LXC) 543 c.Assert(err, jc.ErrorIsNil) 544 defer statetesting.AssertStop(c, w) 545 wc := statetesting.NewStringsWatcherC(c, s.BackingState, w) 546 547 // Initial event. 548 wc.AssertChange(container.Id()) 549 550 // Change something other than the containers and make sure it's 551 // not detected. 552 err = apiMachine.SetStatus(params.StatusStarted, "not really", nil) 553 c.Assert(err, jc.ErrorIsNil) 554 wc.AssertNoChange() 555 556 // Add a KVM container and make sure it's not detected. 557 container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.KVM) 558 c.Assert(err, jc.ErrorIsNil) 559 wc.AssertNoChange() 560 561 // Add another LXC container and make sure it's detected. 562 container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC) 563 c.Assert(err, jc.ErrorIsNil) 564 wc.AssertChange(container.Id()) 565 566 statetesting.AssertStop(c, w) 567 wc.AssertClosed() 568 } 569 570 func (s *provisionerSuite) TestWatchContainersAcceptsSupportedContainers(c *gc.C) { 571 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 572 c.Assert(err, jc.ErrorIsNil) 573 574 for _, ctype := range instance.ContainerTypes { 575 w, err := apiMachine.WatchContainers(ctype) 576 c.Assert(w, gc.NotNil) 577 c.Assert(err, jc.ErrorIsNil) 578 } 579 } 580 581 func (s *provisionerSuite) TestWatchContainersErrors(c *gc.C) { 582 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 583 c.Assert(err, jc.ErrorIsNil) 584 585 _, err = apiMachine.WatchContainers(instance.NONE) 586 c.Assert(err, gc.ErrorMatches, `unsupported container type "none"`) 587 588 _, err = apiMachine.WatchContainers("") 589 c.Assert(err, gc.ErrorMatches, "container type must be specified") 590 } 591 592 func (s *provisionerSuite) TestWatchEnvironMachines(c *gc.C) { 593 w, err := s.provisioner.WatchEnvironMachines() 594 c.Assert(err, jc.ErrorIsNil) 595 defer statetesting.AssertStop(c, w) 596 wc := statetesting.NewStringsWatcherC(c, s.BackingState, w) 597 598 // Initial event. 599 wc.AssertChange(s.machine.Id()) 600 601 // Add another 2 machines make sure they are detected. 602 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 603 c.Assert(err, jc.ErrorIsNil) 604 otherMachine, err = s.State.AddMachine("quantal", state.JobHostUnits) 605 c.Assert(err, jc.ErrorIsNil) 606 wc.AssertChange("1", "2") 607 608 // Change the lifecycle of last machine. 609 err = otherMachine.EnsureDead() 610 c.Assert(err, jc.ErrorIsNil) 611 wc.AssertChange("2") 612 613 // Add a container and make sure it's not detected. 614 template := state.MachineTemplate{ 615 Series: "quantal", 616 Jobs: []state.MachineJob{state.JobHostUnits}, 617 } 618 _, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC) 619 c.Assert(err, jc.ErrorIsNil) 620 wc.AssertNoChange() 621 622 statetesting.AssertStop(c, w) 623 wc.AssertClosed() 624 } 625 626 func (s *provisionerSuite) TestStateAddresses(c *gc.C) { 627 err := s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 628 c.Assert(err, jc.ErrorIsNil) 629 630 stateAddresses, err := s.State.Addresses() 631 c.Assert(err, jc.ErrorIsNil) 632 633 addresses, err := s.provisioner.StateAddresses() 634 c.Assert(err, jc.ErrorIsNil) 635 c.Assert(addresses, gc.DeepEquals, stateAddresses) 636 } 637 638 func (s *provisionerSuite) getManagerConfig(c *gc.C, typ instance.ContainerType) map[string]string { 639 args := params.ContainerManagerConfigParams{Type: typ} 640 result, err := s.provisioner.ContainerManagerConfig(args) 641 c.Assert(err, jc.ErrorIsNil) 642 return result.ManagerConfig 643 } 644 645 func (s *provisionerSuite) TestContainerManagerConfigKNoIPForwarding(c *gc.C) { 646 // Break dummy provider's SupportsAddressAllocation method to 647 // ensure ConfigIPForwarding is not set below. 648 s.AssertConfigParameterUpdated(c, "broken", "SupportsAddressAllocation") 649 650 cfg := s.getManagerConfig(c, instance.KVM) 651 c.Assert(cfg, jc.DeepEquals, map[string]string{ 652 container.ConfigName: "juju", 653 }) 654 } 655 656 func (s *provisionerSuite) TestContainerManagerConfigKVM(c *gc.C) { 657 cfg := s.getManagerConfig(c, instance.KVM) 658 c.Assert(cfg, jc.DeepEquals, map[string]string{ 659 container.ConfigName: "juju", 660 661 // dummy provider supports both networking and address 662 // allocation by default, so IP forwarding should be enabled. 663 container.ConfigIPForwarding: "true", 664 }) 665 } 666 667 func (s *provisionerSuite) TestContainerManagerConfigLXC(c *gc.C) { 668 args := params.ContainerManagerConfigParams{Type: instance.LXC} 669 st, err := state.Open(s.State.EnvironTag(), s.MongoInfo(c), mongo.DefaultDialOpts(), state.Policy(nil)) 670 c.Assert(err, jc.ErrorIsNil) 671 defer st.Close() 672 673 tests := []struct { 674 lxcUseClone bool 675 lxcUseCloneAufs bool 676 expectedUseClone string 677 expectedUseCloneAufs string 678 }{{ 679 lxcUseClone: true, 680 expectedUseClone: "true", 681 expectedUseCloneAufs: "false", 682 }, { 683 lxcUseClone: false, 684 expectedUseClone: "false", 685 expectedUseCloneAufs: "false", 686 }, { 687 lxcUseCloneAufs: false, 688 expectedUseClone: "false", 689 expectedUseCloneAufs: "false", 690 }, { 691 lxcUseClone: true, 692 lxcUseCloneAufs: true, 693 expectedUseClone: "true", 694 expectedUseCloneAufs: "true", 695 }} 696 697 result, err := s.provisioner.ContainerManagerConfig(args) 698 c.Assert(err, jc.ErrorIsNil) 699 c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju") 700 c.Assert(result.ManagerConfig["use-clone"], gc.Equals, "") 701 702 // Change lxc-clone, and ensure it gets picked up. 703 for i, t := range tests { 704 c.Logf("test %d: %+v", i, t) 705 err = st.UpdateEnvironConfig(map[string]interface{}{ 706 "lxc-clone": t.lxcUseClone, 707 "lxc-clone-aufs": t.lxcUseCloneAufs, 708 }, nil, nil) 709 c.Assert(err, jc.ErrorIsNil) 710 result, err := s.provisioner.ContainerManagerConfig(args) 711 c.Assert(err, jc.ErrorIsNil) 712 c.Assert(result.ManagerConfig[container.ConfigName], gc.Equals, "juju") 713 c.Assert(result.ManagerConfig["use-clone"], gc.Equals, t.expectedUseClone) 714 c.Assert(result.ManagerConfig["use-aufs"], gc.Equals, t.expectedUseCloneAufs) 715 } 716 } 717 718 func (s *provisionerSuite) TestContainerManagerConfigPermissive(c *gc.C) { 719 // ContainerManagerConfig is permissive of container types, and 720 // will just return the basic type-independent configuration. 721 cfg := s.getManagerConfig(c, "invalid") 722 c.Assert(cfg, jc.DeepEquals, map[string]string{ 723 container.ConfigName: "juju", 724 725 // dummy provider supports both networking and address 726 // allocation by default, so IP forwarding should be enabled. 727 container.ConfigIPForwarding: "true", 728 }) 729 } 730 731 func (s *provisionerSuite) TestContainerManagerConfigLXCDefaultMTU(c *gc.C) { 732 var resultConfig = map[string]string{ 733 "lxc-default-mtu": "9000", 734 } 735 var called bool 736 provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error { 737 called = true 738 c.Assert(request, gc.Equals, "ContainerManagerConfig") 739 expected := params.ContainerManagerConfigParams{ 740 Type: instance.LXC, 741 } 742 c.Assert(args, gc.Equals, expected) 743 result := response.(*params.ContainerManagerConfig) 744 result.ManagerConfig = resultConfig 745 return nil 746 }) 747 748 args := params.ContainerManagerConfigParams{Type: instance.LXC} 749 result, err := s.provisioner.ContainerManagerConfig(args) 750 c.Assert(called, jc.IsTrue) 751 c.Assert(err, jc.ErrorIsNil) 752 c.Assert(result.ManagerConfig, jc.DeepEquals, resultConfig) 753 } 754 755 func (s *provisionerSuite) TestContainerConfig(c *gc.C) { 756 result, err := s.provisioner.ContainerConfig() 757 c.Assert(err, jc.ErrorIsNil) 758 c.Assert(result.ProviderType, gc.Equals, "dummy") 759 c.Assert(result.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 760 c.Assert(result.SSLHostnameVerification, jc.IsTrue) 761 c.Assert(result.PreferIPv6, jc.IsTrue) 762 } 763 764 func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) { 765 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 766 c.Assert(err, jc.ErrorIsNil) 767 err = apiMachine.SetSupportedContainers(instance.LXC, instance.KVM) 768 c.Assert(err, jc.ErrorIsNil) 769 770 err = s.machine.Refresh() 771 c.Assert(err, jc.ErrorIsNil) 772 containers, ok := s.machine.SupportedContainers() 773 c.Assert(ok, jc.IsTrue) 774 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM}) 775 } 776 777 func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) { 778 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 779 c.Assert(err, jc.ErrorIsNil) 780 err = apiMachine.SupportsNoContainers() 781 c.Assert(err, jc.ErrorIsNil) 782 783 err = s.machine.Refresh() 784 c.Assert(err, jc.ErrorIsNil) 785 containers, ok := s.machine.SupportedContainers() 786 c.Assert(ok, jc.IsTrue) 787 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{}) 788 } 789 790 func (s *provisionerSuite) TestFindToolsNoArch(c *gc.C) { 791 s.testFindTools(c, false, nil, nil) 792 } 793 794 func (s *provisionerSuite) TestFindToolsArch(c *gc.C) { 795 s.testFindTools(c, true, nil, nil) 796 } 797 798 func (s *provisionerSuite) TestFindToolsAPIError(c *gc.C) { 799 apiError := errors.New("everything's broken") 800 s.testFindTools(c, false, apiError, nil) 801 } 802 803 func (s *provisionerSuite) TestFindToolsLogicError(c *gc.C) { 804 logicError := errors.NotFoundf("tools") 805 s.testFindTools(c, false, nil, logicError) 806 } 807 808 func (s *provisionerSuite) testFindTools(c *gc.C, matchArch bool, apiError, logicError error) { 809 var toolsList = coretools.List{&coretools.Tools{Version: version.Current}} 810 var called bool 811 var a string 812 if matchArch { 813 // if matchArch is true, this will be overwriten with the host's arch, otherwise 814 // leave a blank. 815 a = arch.HostArch() 816 } 817 818 provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error { 819 called = true 820 c.Assert(request, gc.Equals, "FindTools") 821 expected := params.FindToolsParams{ 822 Number: version.Current.Number, 823 Series: series.HostSeries(), 824 Arch: a, 825 MinorVersion: -1, 826 MajorVersion: -1, 827 } 828 c.Assert(args, gc.Equals, expected) 829 result := response.(*params.FindToolsResult) 830 result.List = toolsList 831 if logicError != nil { 832 result.Error = common.ServerError(logicError) 833 } 834 return apiError 835 }) 836 apiList, err := s.provisioner.FindTools(version.Current.Number, series.HostSeries(), a) 837 c.Assert(called, jc.IsTrue) 838 if apiError != nil { 839 c.Assert(err, gc.Equals, apiError) 840 } else if logicError != nil { 841 c.Assert(err.Error(), gc.Equals, logicError.Error()) 842 } else { 843 c.Assert(err, jc.ErrorIsNil) 844 c.Assert(apiList, jc.SameContents, toolsList) 845 } 846 } 847 848 func (s *provisionerSuite) TestPrepareContainerInterfaceInfo(c *gc.C) { 849 // This test exercises just the success path, all the other cases 850 // are already tested in the apiserver package. 851 template := state.MachineTemplate{ 852 Series: "quantal", 853 Jobs: []state.MachineJob{state.JobHostUnits}, 854 } 855 container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC) 856 c.Assert(err, jc.ErrorIsNil) 857 858 ifaceInfo, err := s.provisioner.PrepareContainerInterfaceInfo(container.MachineTag()) 859 c.Assert(err, jc.ErrorIsNil) 860 c.Assert(ifaceInfo, gc.HasLen, 1) 861 862 expectInfo := []network.InterfaceInfo{{ 863 DeviceIndex: 0, 864 CIDR: "0.10.0.0/24", 865 NetworkName: "juju-private", 866 ProviderId: "dummy-eth0", 867 ProviderSubnetId: "dummy-private", 868 VLANTag: 0, 869 InterfaceName: "eth0", 870 Disabled: false, 871 NoAutoStart: false, 872 ConfigType: network.ConfigStatic, 873 // Overwrite the Address field below with the actual one, as 874 // it's chosen randomly. 875 Address: network.Address{}, 876 DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"), 877 GatewayAddress: network.NewAddress("0.10.0.2"), 878 ExtraConfig: nil, 879 }} 880 c.Assert(ifaceInfo[0].Address, gc.Not(gc.DeepEquals), network.Address{}) 881 c.Assert(ifaceInfo[0].MACAddress, gc.Not(gc.DeepEquals), "") 882 expectInfo[0].Address = ifaceInfo[0].Address 883 expectInfo[0].MACAddress = ifaceInfo[0].MACAddress 884 c.Assert(ifaceInfo, jc.DeepEquals, expectInfo) 885 } 886 887 func (s *provisionerSuite) TestReleaseContainerAddresses(c *gc.C) { 888 // This test exercises just the success path, all the other cases 889 // are already tested in the apiserver package. 890 template := state.MachineTemplate{ 891 Series: "quantal", 892 Jobs: []state.MachineJob{state.JobHostUnits}, 893 } 894 container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC) 895 896 // allocate some addresses to release 897 subInfo := state.SubnetInfo{ 898 ProviderId: "dummy-private", 899 CIDR: "0.10.0.0/24", 900 VLANTag: 0, 901 AllocatableIPLow: "0.10.0.0", 902 AllocatableIPHigh: "0.10.0.10", 903 } 904 sub, err := s.State.AddSubnet(subInfo) 905 c.Assert(err, jc.ErrorIsNil) 906 for i := 0; i < 3; i++ { 907 addr := network.NewAddress(fmt.Sprintf("0.10.0.%d", i)) 908 ipaddr, err := s.State.AddIPAddress(addr, sub.ID()) 909 c.Check(err, jc.ErrorIsNil) 910 err = ipaddr.AllocateTo(container.Id(), "", "") 911 c.Check(err, jc.ErrorIsNil) 912 } 913 c.Assert(err, jc.ErrorIsNil) 914 password, err := utils.RandomPassword() 915 c.Assert(err, jc.ErrorIsNil) 916 err = container.SetPassword(password) 917 c.Assert(err, jc.ErrorIsNil) 918 err = container.SetProvisioned("foo", "fake_nonce", nil) 919 c.Assert(err, jc.ErrorIsNil) 920 921 err = s.provisioner.ReleaseContainerAddresses(container.MachineTag()) 922 c.Assert(err, jc.ErrorIsNil) 923 924 addresses, err := s.State.AllocatedIPAddresses(container.Id()) 925 c.Assert(err, jc.ErrorIsNil) 926 c.Assert(addresses, gc.HasLen, 3) 927 for _, addr := range addresses { 928 c.Assert(addr.Life(), gc.Equals, state.Dead) 929 } 930 }