github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "time" 13 14 "github.com/juju/errors" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/utils" 17 "github.com/juju/utils/arch" 18 "github.com/juju/utils/series" 19 "github.com/juju/version" 20 gc "gopkg.in/check.v1" 21 "gopkg.in/juju/names.v2" 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/instance" 31 "github.com/juju/juju/juju/testing" 32 "github.com/juju/juju/network" 33 "github.com/juju/juju/state" 34 "github.com/juju/juju/status" 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 jujuversion "github.com/juju/juju/version" 40 "github.com/juju/juju/watcher/watchertest" 41 ) 42 43 type provisionerSuite struct { 44 testing.JujuConnSuite 45 *apitesting.ModelWatcherTests 46 *apitesting.APIAddresserTests 47 48 st api.Connection 49 machine *state.Machine 50 51 provisioner *provisioner.State 52 } 53 54 var _ = gc.Suite(&provisionerSuite{}) 55 56 func (s *provisionerSuite) SetUpTest(c *gc.C) { 57 s.JujuConnSuite.SetUpTest(c) 58 59 var err error 60 s.machine, err = s.State.AddMachine("quantal", state.JobManageModel) 61 c.Assert(err, jc.ErrorIsNil) 62 password, err := utils.RandomPassword() 63 c.Assert(err, jc.ErrorIsNil) 64 err = s.machine.SetPassword(password) 65 c.Assert(err, jc.ErrorIsNil) 66 err = s.machine.SetInstanceInfo("i-manager", "fake_nonce", nil, nil, nil, nil, nil) 67 c.Assert(err, jc.ErrorIsNil) 68 s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce") 69 c.Assert(s.st, gc.NotNil) 70 err = s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 71 c.Assert(err, jc.ErrorIsNil) 72 73 // Create the provisioner API facade. 74 s.provisioner = provisioner.NewState(s.st) 75 c.Assert(s.provisioner, gc.NotNil) 76 77 s.ModelWatcherTests = apitesting.NewModelWatcherTests(s.provisioner, s.BackingState) 78 s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState) 79 } 80 81 func (s *provisionerSuite) TestMachineTagAndId(c *gc.C) { 82 apiMachine, err := s.provisioner.Machine(names.NewMachineTag("42")) 83 c.Assert(err, gc.ErrorMatches, "machine 42 not found") 84 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 85 c.Assert(apiMachine, gc.IsNil) 86 87 // TODO(dfc) fix this type assertion 88 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 89 c.Assert(err, jc.ErrorIsNil) 90 c.Assert(apiMachine.Tag(), gc.Equals, s.machine.Tag()) 91 c.Assert(apiMachine.Id(), gc.Equals, s.machine.Id()) 92 } 93 94 func (s *provisionerSuite) TestGetSetStatus(c *gc.C) { 95 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 96 c.Assert(err, jc.ErrorIsNil) 97 98 machineStatus, info, err := apiMachine.Status() 99 c.Assert(err, jc.ErrorIsNil) 100 c.Assert(machineStatus, gc.Equals, status.Pending) 101 c.Assert(info, gc.Equals, "") 102 103 err = apiMachine.SetStatus(status.Started, "blah", nil) 104 c.Assert(err, jc.ErrorIsNil) 105 106 machineStatus, info, err = apiMachine.Status() 107 c.Assert(err, jc.ErrorIsNil) 108 c.Assert(machineStatus, gc.Equals, status.Started) 109 c.Assert(info, gc.Equals, "blah") 110 statusInfo, err := s.machine.Status() 111 c.Assert(err, jc.ErrorIsNil) 112 c.Assert(statusInfo.Data, gc.HasLen, 0) 113 } 114 115 func (s *provisionerSuite) TestGetSetInstanceStatus(c *gc.C) { 116 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 117 c.Assert(err, jc.ErrorIsNil) 118 119 instanceStatus, info, err := apiMachine.InstanceStatus() 120 c.Assert(err, jc.ErrorIsNil) 121 c.Assert(instanceStatus, gc.Equals, status.Pending) 122 c.Assert(info, gc.Equals, "") 123 err = apiMachine.SetInstanceStatus(status.Started, "blah", nil) 124 c.Assert(err, jc.ErrorIsNil) 125 instanceStatus, info, err = apiMachine.InstanceStatus() 126 c.Assert(err, jc.ErrorIsNil) 127 c.Assert(instanceStatus, gc.Equals, status.Started) 128 c.Assert(info, gc.Equals, "blah") 129 statusInfo, err := s.machine.InstanceStatus() 130 c.Assert(err, jc.ErrorIsNil) 131 c.Assert(statusInfo.Data, gc.HasLen, 0) 132 } 133 134 func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) { 135 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 136 c.Assert(err, jc.ErrorIsNil) 137 138 err = apiMachine.SetStatus(status.Error, "blah", map[string]interface{}{"foo": "bar"}) 139 c.Assert(err, jc.ErrorIsNil) 140 141 machineStatus, info, err := apiMachine.Status() 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(machineStatus, gc.Equals, status.Error) 144 c.Assert(info, gc.Equals, "blah") 145 statusInfo, err := s.machine.Status() 146 c.Assert(err, jc.ErrorIsNil) 147 c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"foo": "bar"}) 148 } 149 150 func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) { 151 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 152 c.Assert(err, jc.ErrorIsNil) 153 now := time.Now() 154 sInfo := status.StatusInfo{ 155 Status: status.Error, 156 Message: "blah", 157 Data: map[string]interface{}{"transient": true}, 158 Since: &now, 159 } 160 err = machine.SetStatus(sInfo) 161 c.Assert(err, jc.ErrorIsNil) 162 machines, info, err := s.provisioner.MachinesWithTransientErrors() 163 c.Assert(err, jc.ErrorIsNil) 164 c.Assert(machines, gc.HasLen, 1) 165 c.Assert(machines[0].Id(), gc.Equals, "1") 166 c.Assert(info, gc.HasLen, 1) 167 c.Assert(info[0], gc.DeepEquals, params.StatusResult{ 168 Id: "1", 169 Life: "alive", 170 Status: "error", 171 Info: "blah", 172 Data: map[string]interface{}{"transient": true}, 173 }) 174 } 175 176 func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) { 177 // Create a fresh machine to test the complete scenario. 178 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 179 c.Assert(err, jc.ErrorIsNil) 180 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 181 182 apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag)) 183 c.Assert(err, jc.ErrorIsNil) 184 185 err = apiMachine.Remove() 186 c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`) 187 err = apiMachine.EnsureDead() 188 c.Assert(err, jc.ErrorIsNil) 189 190 err = otherMachine.Refresh() 191 c.Assert(err, jc.ErrorIsNil) 192 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 193 194 err = apiMachine.EnsureDead() 195 c.Assert(err, jc.ErrorIsNil) 196 err = otherMachine.Refresh() 197 c.Assert(err, jc.ErrorIsNil) 198 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 199 200 err = apiMachine.Remove() 201 c.Assert(err, jc.ErrorIsNil) 202 err = otherMachine.Refresh() 203 c.Assert(err, jc.Satisfies, errors.IsNotFound) 204 205 err = apiMachine.EnsureDead() 206 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 207 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 208 209 // Now try to EnsureDead machine 0 - should fail. 210 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 211 c.Assert(err, jc.ErrorIsNil) 212 err = apiMachine.EnsureDead() 213 c.Assert(err, gc.ErrorMatches, "machine 0 is required by the model") 214 } 215 216 func (s *provisionerSuite) TestMarkForRemoval(c *gc.C) { 217 machine, err := s.State.AddMachine("xenial", state.JobHostUnits) 218 c.Assert(err, jc.ErrorIsNil) 219 220 apiMachine, err := s.provisioner.Machine(machine.Tag().(names.MachineTag)) 221 c.Assert(err, jc.ErrorIsNil) 222 223 err = apiMachine.MarkForRemoval() 224 c.Assert(err, gc.ErrorMatches, "cannot remove machine 1: machine is not dead") 225 226 err = machine.EnsureDead() 227 c.Assert(err, jc.ErrorIsNil) 228 229 err = apiMachine.MarkForRemoval() 230 c.Assert(err, jc.ErrorIsNil) 231 232 removals, err := s.State.AllMachineRemovals() 233 c.Assert(err, jc.ErrorIsNil) 234 c.Assert(removals, jc.SameContents, []string{"1"}) 235 } 236 237 func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) { 238 // Create a fresh machine to test the complete scenario. 239 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 240 c.Assert(err, jc.ErrorIsNil) 241 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 242 243 apiMachine, err := s.provisioner.Machine(otherMachine.Tag().(names.MachineTag)) 244 c.Assert(err, jc.ErrorIsNil) 245 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 246 247 err = apiMachine.EnsureDead() 248 c.Assert(err, jc.ErrorIsNil) 249 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 250 251 err = apiMachine.Refresh() 252 c.Assert(err, jc.ErrorIsNil) 253 c.Assert(apiMachine.Life(), gc.Equals, params.Dead) 254 } 255 256 func (s *provisionerSuite) TestSetInstanceInfo(c *gc.C) { 257 pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders()) 258 _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"}) 259 c.Assert(err, jc.ErrorIsNil) 260 261 // Create a fresh machine, since machine 0 is already provisioned. 262 template := state.MachineTemplate{ 263 Series: "quantal", 264 Jobs: []state.MachineJob{state.JobHostUnits}, 265 Volumes: []state.MachineVolumeParams{{ 266 Volume: state.VolumeParams{ 267 Pool: "loop-pool", 268 Size: 123, 269 }}, 270 }, 271 } 272 notProvisionedMachine, err := s.State.AddOneMachine(template) 273 c.Assert(err, jc.ErrorIsNil) 274 275 apiMachine, err := s.provisioner.Machine(notProvisionedMachine.Tag().(names.MachineTag)) 276 c.Assert(err, jc.ErrorIsNil) 277 278 instanceId, err := apiMachine.InstanceId() 279 c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) 280 c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned") 281 c.Assert(instanceId, gc.Equals, instance.Id("")) 282 283 hwChars := instance.MustParseHardware("cores=123", "mem=4G") 284 285 volumes := []params.Volume{{ 286 VolumeTag: "volume-1-0", 287 Info: params.VolumeInfo{ 288 VolumeId: "vol-123", 289 Size: 124, 290 }, 291 }} 292 volumeAttachments := map[string]params.VolumeAttachmentInfo{ 293 "volume-1-0": { 294 DeviceName: "xvdf1", 295 }, 296 } 297 298 err = apiMachine.SetInstanceInfo( 299 "i-will", "fake_nonce", &hwChars, nil, volumes, volumeAttachments, 300 ) 301 c.Assert(err, jc.ErrorIsNil) 302 303 instanceId, err = apiMachine.InstanceId() 304 c.Assert(err, jc.ErrorIsNil) 305 c.Assert(instanceId, gc.Equals, instance.Id("i-will")) 306 307 // Try it again - should fail. 308 err = apiMachine.SetInstanceInfo("i-wont", "fake", nil, nil, nil, nil) 309 c.Assert(err, gc.ErrorMatches, `cannot record provisioning info for "i-wont": cannot set instance data for machine "1": already set`) 310 311 // Now try to get machine 0's instance id. 312 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 313 c.Assert(err, jc.ErrorIsNil) 314 instanceId, err = apiMachine.InstanceId() 315 c.Assert(err, jc.ErrorIsNil) 316 c.Assert(instanceId, gc.Equals, instance.Id("i-manager")) 317 318 // Now check volumes and volume attachments. 319 volume, err := s.State.Volume(names.NewVolumeTag("1/0")) 320 c.Assert(err, jc.ErrorIsNil) 321 volumeInfo, err := volume.Info() 322 c.Assert(err, jc.ErrorIsNil) 323 c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{ 324 VolumeId: "vol-123", 325 Pool: "loop-pool", 326 Size: 124, 327 }) 328 stateVolumeAttachments, err := s.State.MachineVolumeAttachments(names.NewMachineTag("1")) 329 c.Assert(err, jc.ErrorIsNil) 330 c.Assert(stateVolumeAttachments, gc.HasLen, 1) 331 volumeAttachmentInfo, err := stateVolumeAttachments[0].Info() 332 c.Assert(err, jc.ErrorIsNil) 333 c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{ 334 DeviceName: "xvdf1", 335 }) 336 } 337 338 func (s *provisionerSuite) TestSeries(c *gc.C) { 339 // Create a fresh machine with different series. 340 foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits) 341 c.Assert(err, jc.ErrorIsNil) 342 343 apiMachine, err := s.provisioner.Machine(foobarMachine.Tag().(names.MachineTag)) 344 c.Assert(err, jc.ErrorIsNil) 345 series, err := apiMachine.Series() 346 c.Assert(err, jc.ErrorIsNil) 347 c.Assert(series, gc.Equals, "foobar") 348 349 // Now try machine 0. 350 apiMachine, err = s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 351 c.Assert(err, jc.ErrorIsNil) 352 series, err = apiMachine.Series() 353 c.Assert(err, jc.ErrorIsNil) 354 c.Assert(series, gc.Equals, "quantal") 355 } 356 357 func (s *provisionerSuite) TestDistributionGroup(c *gc.C) { 358 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 359 c.Assert(err, jc.ErrorIsNil) 360 instances, err := apiMachine.DistributionGroup() 361 c.Assert(err, jc.ErrorIsNil) 362 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"}) 363 364 machine1, err := s.State.AddMachine("quantal", state.JobHostUnits) 365 c.Assert(err, jc.ErrorIsNil) 366 apiMachine, err = s.provisioner.Machine(machine1.Tag().(names.MachineTag)) 367 c.Assert(err, jc.ErrorIsNil) 368 wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 369 370 err = apiMachine.SetInstanceInfo("i-d", "fake", nil, nil, nil, nil) 371 c.Assert(err, jc.ErrorIsNil) 372 instances, err = apiMachine.DistributionGroup() 373 c.Assert(err, jc.ErrorIsNil) 374 c.Assert(instances, gc.HasLen, 0) // no units assigned 375 376 var unitNames []string 377 for i := 0; i < 3; i++ { 378 unit, err := wordpress.AddUnit() 379 c.Assert(err, jc.ErrorIsNil) 380 unitNames = append(unitNames, unit.Name()) 381 err = unit.AssignToMachine(machine1) 382 c.Assert(err, jc.ErrorIsNil) 383 instances, err := apiMachine.DistributionGroup() 384 c.Assert(err, jc.ErrorIsNil) 385 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"}) 386 } 387 } 388 389 func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) { 390 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 391 c.Assert(err, jc.ErrorIsNil) 392 apiMachine, err := s.provisioner.Machine(stateMachine.Tag().(names.MachineTag)) 393 c.Assert(err, jc.ErrorIsNil) 394 err = apiMachine.EnsureDead() 395 c.Assert(err, jc.ErrorIsNil) 396 err = apiMachine.Remove() 397 c.Assert(err, jc.ErrorIsNil) 398 _, err = apiMachine.DistributionGroup() 399 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 400 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 401 } 402 403 func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) { 404 // Add a couple of spaces. 405 _, err := s.State.AddSpace("space1", "", nil, true) 406 c.Assert(err, jc.ErrorIsNil) 407 _, err = s.State.AddSpace("space2", "", nil, false) 408 c.Assert(err, jc.ErrorIsNil) 409 // Add 2 subnets into each space. 410 // Each subnet is in a matching zone (e.g "subnet-#" in "zone#"). 411 testing.AddSubnetsWithTemplate(c, s.State, 4, state.SubnetInfo{ 412 CIDR: "10.{{.}}.0.0/16", 413 ProviderId: "subnet-{{.}}", 414 AvailabilityZone: "zone{{.}}", 415 SpaceName: "{{if (lt . 2)}}space1{{else}}space2{{end}}", 416 }) 417 418 cons := constraints.MustParse("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 LXD 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.LXD) 465 c.Assert(err, jc.ErrorIsNil) 466 467 w, err := apiMachine.WatchContainers(instance.LXD) 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.Started, "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 LXD container and make sure it's detected. 487 container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXD) 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.LXD) 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) TestContainerManagerConfigKVM(c *gc.C) { 565 cfg := s.getManagerConfig(c, instance.KVM) 566 c.Assert(cfg, jc.DeepEquals, map[string]string{ 567 container.ConfigModelUUID: coretesting.ModelTag.Id(), 568 }) 569 } 570 571 func (s *provisionerSuite) TestContainerManagerConfigPermissive(c *gc.C) { 572 // ContainerManagerConfig is permissive of container types, and 573 // will just return the basic type-independent configuration. 574 cfg := s.getManagerConfig(c, "invalid") 575 c.Assert(cfg, jc.DeepEquals, map[string]string{ 576 container.ConfigModelUUID: coretesting.ModelTag.Id(), 577 }) 578 } 579 580 func (s *provisionerSuite) TestContainerConfig(c *gc.C) { 581 result, err := s.provisioner.ContainerConfig() 582 c.Assert(err, jc.ErrorIsNil) 583 c.Assert(result.ProviderType, gc.Equals, "dummy") 584 c.Assert(result.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 585 c.Assert(result.SSLHostnameVerification, jc.IsTrue) 586 } 587 588 func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) { 589 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 590 c.Assert(err, jc.ErrorIsNil) 591 err = apiMachine.SetSupportedContainers(instance.LXD, instance.KVM) 592 c.Assert(err, jc.ErrorIsNil) 593 594 err = s.machine.Refresh() 595 c.Assert(err, jc.ErrorIsNil) 596 containers, ok := s.machine.SupportedContainers() 597 c.Assert(ok, jc.IsTrue) 598 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXD, instance.KVM}) 599 } 600 601 func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) { 602 apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag)) 603 c.Assert(err, jc.ErrorIsNil) 604 err = apiMachine.SupportsNoContainers() 605 c.Assert(err, jc.ErrorIsNil) 606 607 err = s.machine.Refresh() 608 c.Assert(err, jc.ErrorIsNil) 609 containers, ok := s.machine.SupportedContainers() 610 c.Assert(ok, jc.IsTrue) 611 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{}) 612 } 613 614 func (s *provisionerSuite) TestFindToolsNoArch(c *gc.C) { 615 s.testFindTools(c, false, nil, nil) 616 } 617 618 func (s *provisionerSuite) TestFindToolsArch(c *gc.C) { 619 s.testFindTools(c, true, nil, nil) 620 } 621 622 func (s *provisionerSuite) TestFindToolsAPIError(c *gc.C) { 623 apiError := errors.New("everything's broken") 624 s.testFindTools(c, false, apiError, nil) 625 } 626 627 func (s *provisionerSuite) TestFindToolsLogicError(c *gc.C) { 628 logicError := errors.NotFoundf("tools") 629 s.testFindTools(c, false, nil, logicError) 630 } 631 632 func (s *provisionerSuite) testFindTools(c *gc.C, matchArch bool, apiError, logicError error) { 633 current := version.Binary{ 634 Number: jujuversion.Current, 635 Arch: arch.HostArch(), 636 Series: series.HostSeries(), 637 } 638 var toolsList = coretools.List{&coretools.Tools{Version: current}} 639 var called bool 640 var a string 641 if matchArch { 642 // if matchArch is true, this will be overwriten with the host's arch, otherwise 643 // leave a blank. 644 a = arch.HostArch() 645 } 646 647 provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error { 648 called = true 649 c.Assert(request, gc.Equals, "FindTools") 650 expected := params.FindToolsParams{ 651 Number: jujuversion.Current, 652 Series: series.HostSeries(), 653 Arch: a, 654 MinorVersion: -1, 655 MajorVersion: -1, 656 } 657 c.Assert(args, gc.Equals, expected) 658 result := response.(*params.FindToolsResult) 659 result.List = toolsList 660 if logicError != nil { 661 result.Error = common.ServerError(logicError) 662 } 663 return apiError 664 }) 665 apiList, err := s.provisioner.FindTools(jujuversion.Current, series.HostSeries(), a) 666 c.Assert(called, jc.IsTrue) 667 if apiError != nil { 668 c.Assert(err, gc.Equals, apiError) 669 } else if logicError != nil { 670 c.Assert(err.Error(), gc.Equals, logicError.Error()) 671 } else { 672 c.Assert(err, jc.ErrorIsNil) 673 c.Assert(apiList, jc.SameContents, toolsList) 674 } 675 }