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