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