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