github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/provisioner/provisioner_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner_test 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/golang/mock/gomock" 11 "github.com/juju/errors" 12 "github.com/juju/os/series" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils" 15 "github.com/juju/utils/arch" 16 "github.com/juju/version" 17 gc "gopkg.in/check.v1" 18 "gopkg.in/juju/charm.v6" 19 "gopkg.in/juju/names.v2" 20 21 "github.com/juju/juju/api" 22 apimocks "github.com/juju/juju/api/base/mocks" 23 apibasetesting "github.com/juju/juju/api/base/testing" 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/container" 29 "github.com/juju/juju/core/constraints" 30 "github.com/juju/juju/core/instance" 31 "github.com/juju/juju/core/status" 32 "github.com/juju/juju/core/watcher/watchertest" 33 "github.com/juju/juju/environs/config" 34 "github.com/juju/juju/juju/testing" 35 "github.com/juju/juju/network" 36 "github.com/juju/juju/state" 37 "github.com/juju/juju/storage/poolmanager" 38 "github.com/juju/juju/storage/provider" 39 coretesting "github.com/juju/juju/testing" 40 coretools "github.com/juju/juju/tools" 41 jujuversion "github.com/juju/juju/version" 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 60 var err error 61 s.machine, err = s.State.AddMachine("quantal", state.JobManageModel) 62 c.Assert(err, jc.ErrorIsNil) 63 password, err := utils.RandomPassword() 64 c.Assert(err, jc.ErrorIsNil) 65 err = s.machine.SetPassword(password) 66 c.Assert(err, jc.ErrorIsNil) 67 err = s.machine.SetInstanceInfo("i-manager", "", "fake_nonce", nil, nil, nil, nil, nil, nil) 68 c.Assert(err, jc.ErrorIsNil) 69 s.st = s.OpenAPIAsMachine(c, s.machine.Tag(), password, "fake_nonce") 70 c.Assert(s.st, gc.NotNil) 71 err = s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 72 c.Assert(err, jc.ErrorIsNil) 73 74 // Create the provisioner API facade. 75 s.provisioner = provisioner.NewState(s.st) 76 c.Assert(s.provisioner, gc.NotNil) 77 78 s.ModelWatcherTests = apitesting.NewModelWatcherTests(s.provisioner, s.BackingState, s.Model) 79 s.APIAddresserTests = apitesting.NewAPIAddresserTests(s.provisioner, s.BackingState) 80 } 81 82 func (s *provisionerSuite) assertGetOneMachine(c *gc.C, tag names.MachineTag) provisioner.MachineProvisioner { 83 result, err := s.provisioner.Machines(tag) 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(len(result), gc.Equals, 1) 86 c.Assert(result[0].Err, gc.IsNil) 87 return result[0].Machine 88 } 89 90 func (s *provisionerSuite) TestMachinesTagAndId(c *gc.C) { 91 result, err := s.provisioner.Machines(names.NewMachineTag("42"), s.machine.MachineTag()) 92 c.Assert(err, jc.ErrorIsNil) 93 c.Assert(len(result), gc.Equals, 2) 94 95 c.Assert(result[0].Err, gc.ErrorMatches, "machine 42 not found") 96 c.Assert(result[0].Err, jc.Satisfies, params.IsCodeNotFound) 97 c.Assert(result[0].Machine, gc.IsNil) 98 99 c.Assert(result[1].Err, gc.IsNil) 100 c.Assert(result[1].Machine.Tag(), gc.Equals, s.machine.Tag()) 101 c.Assert(result[1].Machine.Id(), gc.Equals, s.machine.Id()) 102 } 103 104 func (s *provisionerSuite) TestGetSetStatus(c *gc.C) { 105 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 106 107 machineStatus, info, err := apiMachine.Status() 108 c.Assert(err, jc.ErrorIsNil) 109 c.Assert(machineStatus, gc.Equals, status.Pending) 110 c.Assert(info, gc.Equals, "") 111 112 err = apiMachine.SetStatus(status.Started, "blah", nil) 113 c.Assert(err, jc.ErrorIsNil) 114 115 machineStatus, info, err = apiMachine.Status() 116 c.Assert(err, jc.ErrorIsNil) 117 c.Assert(machineStatus, gc.Equals, status.Started) 118 c.Assert(info, gc.Equals, "blah") 119 statusInfo, err := s.machine.Status() 120 c.Assert(err, jc.ErrorIsNil) 121 c.Assert(statusInfo.Data, gc.HasLen, 0) 122 } 123 124 func (s *provisionerSuite) TestGetSetInstanceStatus(c *gc.C) { 125 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 126 instanceStatus, info, err := apiMachine.InstanceStatus() 127 c.Assert(err, jc.ErrorIsNil) 128 c.Assert(instanceStatus, gc.Equals, status.Pending) 129 c.Assert(info, gc.Equals, "") 130 err = apiMachine.SetInstanceStatus(status.Running, "blah", nil) 131 c.Assert(err, jc.ErrorIsNil) 132 instanceStatus, info, err = apiMachine.InstanceStatus() 133 c.Assert(err, jc.ErrorIsNil) 134 c.Assert(instanceStatus, gc.Equals, status.Running) 135 c.Assert(info, gc.Equals, "blah") 136 statusInfo, err := s.machine.InstanceStatus() 137 c.Assert(err, jc.ErrorIsNil) 138 c.Assert(statusInfo.Data, gc.HasLen, 0) 139 } 140 141 func (s *provisionerSuite) TestGetSetStatusWithData(c *gc.C) { 142 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 143 err := apiMachine.SetStatus(status.Error, "blah", map[string]interface{}{"foo": "bar"}) 144 c.Assert(err, jc.ErrorIsNil) 145 146 machineStatus, info, err := apiMachine.Status() 147 c.Assert(err, jc.ErrorIsNil) 148 c.Assert(machineStatus, gc.Equals, status.Error) 149 c.Assert(info, gc.Equals, "blah") 150 statusInfo, err := s.machine.Status() 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(statusInfo.Data, gc.DeepEquals, map[string]interface{}{"foo": "bar"}) 153 } 154 155 func (s *provisionerSuite) TestMachinesWithTransientErrors(c *gc.C) { 156 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 157 c.Assert(err, jc.ErrorIsNil) 158 now := time.Now() 159 sInfo := status.StatusInfo{ 160 Status: status.ProvisioningError, 161 Message: "blah", 162 Data: map[string]interface{}{"transient": true}, 163 Since: &now, 164 } 165 err = machine.SetInstanceStatus(sInfo) 166 c.Assert(err, jc.ErrorIsNil) 167 result, err := s.provisioner.MachinesWithTransientErrors() 168 c.Assert(err, jc.ErrorIsNil) 169 c.Assert(result, gc.HasLen, 1) 170 171 c.Assert(result[0].Machine.Id(), gc.Equals, "1") 172 c.Assert(result[0].Status, gc.DeepEquals, params.StatusResult{ 173 Id: "1", 174 Life: "alive", 175 Status: "provisioning error", 176 Info: "blah", 177 Data: map[string]interface{}{"transient": true}, 178 }) 179 } 180 181 func (s *provisionerSuite) TestEnsureDeadAndRemove(c *gc.C) { 182 // Create a fresh machine to test the complete scenario. 183 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 186 187 apiMachine := s.assertGetOneMachine(c, otherMachine.MachineTag()) 188 c.Assert(err, jc.ErrorIsNil) 189 190 err = apiMachine.Remove() 191 c.Assert(err, gc.ErrorMatches, `cannot remove entity "machine-1": still alive`) 192 err = apiMachine.EnsureDead() 193 c.Assert(err, jc.ErrorIsNil) 194 195 err = otherMachine.Refresh() 196 c.Assert(err, jc.ErrorIsNil) 197 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 198 199 err = apiMachine.EnsureDead() 200 c.Assert(err, jc.ErrorIsNil) 201 err = otherMachine.Refresh() 202 c.Assert(err, jc.ErrorIsNil) 203 c.Assert(otherMachine.Life(), gc.Equals, state.Dead) 204 205 err = apiMachine.Remove() 206 c.Assert(err, jc.ErrorIsNil) 207 err = otherMachine.Refresh() 208 c.Assert(err, jc.Satisfies, errors.IsNotFound) 209 210 err = apiMachine.EnsureDead() 211 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 212 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 213 214 // Now try to EnsureDead machine 0 - should fail. 215 apiMachine = s.assertGetOneMachine(c, s.machine.MachineTag()) 216 err = apiMachine.EnsureDead() 217 c.Assert(err, gc.ErrorMatches, "machine 0 is still a controller member") 218 } 219 220 func (s *provisionerSuite) TestMarkForRemoval(c *gc.C) { 221 machine, err := s.State.AddMachine("xenial", state.JobHostUnits) 222 c.Assert(err, jc.ErrorIsNil) 223 224 apiMachine := s.assertGetOneMachine(c, machine.MachineTag()) 225 226 err = apiMachine.MarkForRemoval() 227 c.Assert(err, gc.ErrorMatches, "cannot remove machine 1: machine is not dead") 228 229 err = machine.EnsureDead() 230 c.Assert(err, jc.ErrorIsNil) 231 232 err = apiMachine.MarkForRemoval() 233 c.Assert(err, jc.ErrorIsNil) 234 235 removals, err := s.State.AllMachineRemovals() 236 c.Assert(err, jc.ErrorIsNil) 237 c.Assert(removals, jc.SameContents, []string{"1"}) 238 } 239 240 func (s *provisionerSuite) TestRefreshAndLife(c *gc.C) { 241 // Create a fresh machine to test the complete scenario. 242 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 243 c.Assert(err, jc.ErrorIsNil) 244 c.Assert(otherMachine.Life(), gc.Equals, state.Alive) 245 246 apiMachine := s.assertGetOneMachine(c, otherMachine.MachineTag()) 247 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 248 249 err = apiMachine.EnsureDead() 250 c.Assert(err, jc.ErrorIsNil) 251 c.Assert(apiMachine.Life(), gc.Equals, params.Alive) 252 253 err = apiMachine.Refresh() 254 c.Assert(err, jc.ErrorIsNil) 255 c.Assert(apiMachine.Life(), gc.Equals, params.Dead) 256 } 257 258 func (s *provisionerSuite) TestSetInstanceInfo(c *gc.C) { 259 pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders()) 260 _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"}) 261 c.Assert(err, jc.ErrorIsNil) 262 263 // Create a fresh machine, since machine 0 is already provisioned. 264 template := state.MachineTemplate{ 265 Series: "quantal", 266 Jobs: []state.MachineJob{state.JobHostUnits}, 267 Volumes: []state.HostVolumeParams{{ 268 Volume: state.VolumeParams{ 269 Pool: "loop-pool", 270 Size: 123, 271 }}, 272 }, 273 } 274 notProvisionedMachine, err := s.State.AddOneMachine(template) 275 c.Assert(err, jc.ErrorIsNil) 276 277 apiMachine := s.assertGetOneMachine(c, notProvisionedMachine.MachineTag()) 278 279 instanceId, err := apiMachine.InstanceId() 280 c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) 281 c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned") 282 c.Assert(instanceId, gc.Equals, instance.Id("")) 283 284 hwChars := instance.MustParseHardware("cores=123", "mem=4G") 285 286 volumes := []params.Volume{{ 287 VolumeTag: "volume-1-0", 288 Info: params.VolumeInfo{ 289 VolumeId: "vol-123", 290 Size: 124, 291 }, 292 }} 293 volumeAttachments := map[string]params.VolumeAttachmentInfo{ 294 "volume-1-0": { 295 DeviceName: "xvdf1", 296 }, 297 } 298 299 err = apiMachine.SetInstanceInfo( 300 "i-will", "", "fake_nonce", &hwChars, nil, volumes, volumeAttachments, nil, 301 ) 302 c.Assert(err, jc.ErrorIsNil) 303 304 instanceId, err = apiMachine.InstanceId() 305 c.Assert(err, jc.ErrorIsNil) 306 c.Assert(instanceId, gc.Equals, instance.Id("i-will")) 307 308 // Try it again - should fail. 309 err = apiMachine.SetInstanceInfo("i-wont", "", "fake", nil, nil, nil, nil, nil) 310 c.Assert(err, gc.ErrorMatches, `cannot record provisioning info for "i-wont": cannot set instance data for machine "1": already set`) 311 312 // Now try to get machine 0's instance id. 313 apiMachine = s.assertGetOneMachine(c, s.machine.MachineTag()) 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 sb, err := state.NewStorageBackend(s.State) 320 c.Assert(err, jc.ErrorIsNil) 321 volume, err := sb.Volume(names.NewVolumeTag("1/0")) 322 c.Assert(err, jc.ErrorIsNil) 323 volumeInfo, err := volume.Info() 324 c.Assert(err, jc.ErrorIsNil) 325 c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{ 326 VolumeId: "vol-123", 327 Pool: "loop-pool", 328 Size: 124, 329 }) 330 stateVolumeAttachments, err := sb.MachineVolumeAttachments(names.NewMachineTag("1")) 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(stateVolumeAttachments, gc.HasLen, 1) 333 volumeAttachmentInfo, err := stateVolumeAttachments[0].Info() 334 c.Assert(err, jc.ErrorIsNil) 335 c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{ 336 DeviceName: "xvdf1", 337 }) 338 } 339 340 func (s *provisionerSuite) TestAvailabilityZone(c *gc.C) { 341 // Create a fresh machine, since machine 0 is already provisioned. 342 template := state.MachineTemplate{ 343 Series: "xenial", 344 Jobs: []state.MachineJob{state.JobHostUnits}, 345 } 346 notProvisionedMachine, err := s.State.AddOneMachine(template) 347 c.Assert(err, jc.ErrorIsNil) 348 349 apiMachine := s.assertGetOneMachine(c, notProvisionedMachine.MachineTag()) 350 351 instanceId, err := apiMachine.InstanceId() 352 c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) 353 c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned") 354 c.Assert(instanceId, gc.Equals, instance.Id("")) 355 356 availabilityZone := "ru-north-siberia" 357 hwChars := instance.MustParseHardware(fmt.Sprintf("availability-zone=%s", availabilityZone)) 358 359 err = apiMachine.SetInstanceInfo( 360 "azinst", "", "nonce", &hwChars, nil, nil, nil, nil, 361 ) 362 c.Assert(err, jc.ErrorIsNil) 363 364 retAvailabilityZone, err := apiMachine.AvailabilityZone() 365 c.Assert(err, jc.ErrorIsNil) 366 c.Assert(availabilityZone, gc.Equals, retAvailabilityZone) 367 } 368 369 func (s *provisionerSuite) TestSetInstanceInfoProfiles(c *gc.C) { 370 // Create a fresh machine, since machine 0 is already provisioned. 371 template := state.MachineTemplate{ 372 Series: "xenial", 373 Jobs: []state.MachineJob{state.JobHostUnits}, 374 } 375 notProvisionedMachine, err := s.State.AddOneMachine(template) 376 c.Assert(err, jc.ErrorIsNil) 377 378 apiMachine := s.assertGetOneMachine(c, notProvisionedMachine.MachineTag()) 379 380 instanceId, err := apiMachine.InstanceId() 381 c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) 382 c.Assert(err, gc.ErrorMatches, "machine 1 not provisioned") 383 c.Assert(instanceId, gc.Equals, instance.Id("")) 384 385 hwChars := instance.MustParseHardware("cores=123", "mem=4G") 386 387 profiles := []string{"juju-default-profile-0", "juju-default-lxd-2"} 388 err = apiMachine.SetInstanceInfo( 389 "profileinst", "", "nonce", &hwChars, nil, nil, nil, profiles, 390 ) 391 c.Assert(err, jc.ErrorIsNil) 392 393 mach, err := s.State.Machine(apiMachine.Id()) 394 c.Assert(err, jc.ErrorIsNil) 395 obtainedProfiles, err := mach.CharmProfiles() 396 c.Assert(err, jc.ErrorIsNil) 397 c.Assert(profiles, jc.SameContents, obtainedProfiles) 398 } 399 400 func (s *provisionerSuite) TestSetCharmProfiles(c *gc.C) { 401 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 402 403 profiles := []string{"juju-default-profile-0", "juju-default-lxd-2"} 404 err := apiMachine.SetCharmProfiles(profiles) 405 c.Assert(err, jc.ErrorIsNil) 406 407 mach, err := s.State.Machine(apiMachine.Id()) 408 c.Assert(err, jc.ErrorIsNil) 409 obtainedProfiles, err := mach.CharmProfiles() 410 c.Assert(err, jc.ErrorIsNil) 411 c.Assert(profiles, jc.SameContents, obtainedProfiles) 412 } 413 414 func (s *provisionerSuite) TestSetUpgradeCharmProfileComplete(c *gc.C) { 415 application := s.AddTestingApplication(c, "lxd-profile", s.AddTestingCharm(c, "lxd-profile")) 416 curl, _ := application.CharmURL() 417 s.machine.SetUpgradeCharmProfile(application.Name(), curl.String()) 418 419 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 420 421 profiles := []string{"juju-default-profile-0", "juju-default-lxd-2"} 422 err := apiMachine.SetCharmProfiles(profiles) 423 c.Assert(err, jc.ErrorIsNil) 424 425 err = apiMachine.SetUpgradeCharmProfileComplete("testme") 426 c.Assert(err, jc.ErrorIsNil) 427 428 mach, err := s.State.Machine(apiMachine.Id()) 429 c.Assert(err, jc.ErrorIsNil) 430 status, err := mach.UpgradeCharmProfileComplete() 431 c.Assert(err, jc.ErrorIsNil) 432 c.Assert(status, gc.Equals, "testme") 433 } 434 435 func (s *provisionerSuite) TestCharmProfileChangeInfo(c *gc.C) { 436 application := s.AddTestingApplication(c, "lxd-profile", s.AddTestingCharm(c, "lxd-profile")) 437 curl, _ := application.CharmURL() 438 s.machine.SetUpgradeCharmProfile(application.Name(), curl.String()) 439 440 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 441 442 info, err := apiMachine.CharmProfileChangeInfo() 443 c.Assert(err, jc.ErrorIsNil) 444 c.Assert(info, jc.DeepEquals, provisioner.CharmProfileChangeInfo{ 445 OldProfileName: "", 446 NewProfileName: "juju-controller-lxd-profile-0", 447 LXDProfile: &charm.LXDProfile{ 448 Config: map[string]string{ 449 "security.nesting": "true", 450 "security.privileged": "true", 451 "linux.kernel_modules": "openvswitch,nbd,ip_tables,ip6_tables", 452 "environment.http_proxy": "", 453 }, 454 Description: "lxd profile for testing, will pass validation", 455 Devices: map[string]map[string]string{ 456 "tun": { 457 "path": "/dev/net/tun", 458 "type": "unix-char", 459 }, 460 "sony": { 461 "type": "usb", 462 "vendorid": "0fce", 463 "productid": "51da", 464 }, 465 "bdisk": { 466 "source": "/dev/loop0", 467 "type": "unix-block", 468 }, 469 "gpu": { 470 "type": "gpu", 471 }, 472 }, 473 }, 474 Subordinate: false, 475 }) 476 } 477 478 func (s *provisionerSuite) TestCharmProfileChangeInfoSubordinate(c *gc.C) { 479 application := s.AddTestingApplication(c, "lxd-profile-subordinate", s.AddTestingCharm(c, "lxd-profile-subordinate")) 480 curl, _ := application.CharmURL() 481 s.machine.SetUpgradeCharmProfile(application.Name(), curl.String()) 482 483 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 484 485 info, err := apiMachine.CharmProfileChangeInfo() 486 c.Assert(err, jc.ErrorIsNil) 487 c.Assert(info, jc.DeepEquals, provisioner.CharmProfileChangeInfo{ 488 OldProfileName: "", 489 NewProfileName: "juju-controller-lxd-profile-subordinate-0", 490 LXDProfile: &charm.LXDProfile{ 491 Config: map[string]string{ 492 "security.nesting": "false", 493 "security.privileged": "true", 494 "linux.kernel_modules": "openvswitch,nbd,ip_tables,ip6_tables,iptable_nat", 495 "environment.http_proxy": "", 496 }, 497 Description: "lxd profile subordinate for testing", 498 Devices: map[string]map[string]string{ 499 "sandisk": { 500 "type": "usb", 501 "vendorid": "0781", 502 "productid": "8181", 503 }, 504 }, 505 }, 506 Subordinate: true, 507 }) 508 } 509 510 func (s *provisionerSuite) TestRemoveUpgradeCharmProfileData(c *gc.C) { 511 application := s.AddTestingApplication(c, "lxd-profile-subordinate", s.AddTestingCharm(c, "lxd-profile-subordinate")) 512 curl, _ := application.CharmURL() 513 s.machine.SetUpgradeCharmProfile(application.Name(), curl.String()) 514 515 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 516 517 err := apiMachine.RemoveUpgradeCharmProfileData() 518 c.Assert(err, jc.ErrorIsNil) 519 } 520 521 func (s *provisionerSuite) TestKeepInstance(c *gc.C) { 522 err := s.machine.SetKeepInstance(true) 523 c.Assert(err, jc.ErrorIsNil) 524 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 525 keep, err := apiMachine.KeepInstance() 526 c.Assert(err, jc.ErrorIsNil) 527 c.Assert(keep, jc.IsTrue) 528 } 529 530 func (s *provisionerSuite) TestDistributionGroup(c *gc.C) { 531 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 532 instances, err := apiMachine.DistributionGroup() 533 c.Assert(err, jc.ErrorIsNil) 534 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-manager"}) 535 536 machine1, err := s.State.AddMachine("quantal", state.JobHostUnits) 537 c.Assert(err, jc.ErrorIsNil) 538 apiMachine = s.assertGetOneMachine(c, machine1.MachineTag()) 539 wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 540 541 err = apiMachine.SetInstanceInfo("i-d", "", "fake", nil, nil, nil, nil, nil) 542 c.Assert(err, jc.ErrorIsNil) 543 instances, err = apiMachine.DistributionGroup() 544 c.Assert(err, jc.ErrorIsNil) 545 c.Assert(instances, gc.HasLen, 0) // no units assigned 546 547 var unitNames []string 548 for i := 0; i < 3; i++ { 549 unit, err := wordpress.AddUnit(state.AddUnitParams{}) 550 c.Assert(err, jc.ErrorIsNil) 551 unitNames = append(unitNames, unit.Name()) 552 err = unit.AssignToMachine(machine1) 553 c.Assert(err, jc.ErrorIsNil) 554 instances, err := apiMachine.DistributionGroup() 555 c.Assert(err, jc.ErrorIsNil) 556 c.Assert(instances, gc.DeepEquals, []instance.Id{"i-d"}) 557 } 558 } 559 560 func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) { 561 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 562 c.Assert(err, jc.ErrorIsNil) 563 apiMachine := s.assertGetOneMachine(c, stateMachine.MachineTag()) 564 err = apiMachine.EnsureDead() 565 c.Assert(err, jc.ErrorIsNil) 566 err = apiMachine.Remove() 567 c.Assert(err, jc.ErrorIsNil) 568 _, err = apiMachine.DistributionGroup() 569 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 570 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 571 } 572 573 func (s *provisionerSuite) TestDistributionGroupByMachineId(c *gc.C) { 574 results, err := s.provisioner.DistributionGroupByMachineId(s.machine.MachineTag()) 575 c.Assert(err, jc.ErrorIsNil) 576 c.Assert(len(results), gc.Equals, 1) 577 c.Assert(results, gc.DeepEquals, []provisioner.DistributionGroupResult{ 578 {MachineIds: nil, Err: nil}, 579 }) 580 581 machine1, err := s.State.AddMachine("quantal", state.JobHostUnits) 582 c.Assert(err, jc.ErrorIsNil) 583 wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 584 unit, err := wordpress.AddUnit(state.AddUnitParams{}) 585 c.Assert(err, jc.ErrorIsNil) 586 err = unit.AssignToMachine(machine1) 587 c.Assert(err, jc.ErrorIsNil) 588 589 results, err = s.provisioner.DistributionGroupByMachineId( 590 s.machine.MachineTag(), 591 machine1.MachineTag(), 592 ) 593 c.Assert(err, jc.ErrorIsNil) 594 c.Assert(len(results), gc.Equals, 2) 595 c.Assert(results, gc.DeepEquals, []provisioner.DistributionGroupResult{ 596 {MachineIds: nil, Err: nil}, 597 {MachineIds: nil, Err: nil}, 598 }) 599 600 machine2, err := s.State.AddMachine("quantal", state.JobHostUnits) 601 c.Assert(err, jc.ErrorIsNil) 602 unit2, err := wordpress.AddUnit(state.AddUnitParams{}) 603 c.Assert(err, jc.ErrorIsNil) 604 err = unit2.AssignToMachine(machine2) 605 c.Assert(err, jc.ErrorIsNil) 606 607 results, err = s.provisioner.DistributionGroupByMachineId( 608 s.machine.MachineTag(), 609 machine1.MachineTag(), 610 machine2.MachineTag(), 611 ) 612 c.Assert(err, jc.ErrorIsNil) 613 c.Assert(len(results), gc.Equals, 3) 614 c.Assert(results, gc.DeepEquals, []provisioner.DistributionGroupResult{ 615 {MachineIds: nil, Err: nil}, 616 {MachineIds: []string{"2"}, Err: nil}, 617 {MachineIds: []string{"1"}, Err: nil}, 618 }) 619 } 620 621 func (s *provisionerSuite) TestDistributionGroupByMachineIdNotFound(c *gc.C) { 622 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 623 c.Assert(err, jc.ErrorIsNil) 624 machineTag := stateMachine.MachineTag() 625 apiMachine := s.assertGetOneMachine(c, machineTag) 626 err = apiMachine.EnsureDead() 627 c.Assert(err, jc.ErrorIsNil) 628 err = apiMachine.Remove() 629 c.Assert(err, jc.ErrorIsNil) 630 results, err := s.provisioner.DistributionGroupByMachineId(machineTag) 631 c.Assert(err, jc.ErrorIsNil) 632 c.Assert(len(results), gc.Equals, 1) 633 c.Assert(results[0].Err, gc.ErrorMatches, "machine 1 not found") 634 c.Assert(results[0].Err, jc.Satisfies, params.IsCodeNotFound) 635 } 636 637 func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) { 638 // Add a couple of spaces. 639 _, err := s.State.AddSpace("space1", "", nil, true) 640 c.Assert(err, jc.ErrorIsNil) 641 _, err = s.State.AddSpace("space2", "", nil, false) 642 c.Assert(err, jc.ErrorIsNil) 643 // Add 2 subnets into each space. 644 // Each subnet is in a matching zone (e.g "subnet-#" in "zone#"). 645 testing.AddSubnetsWithTemplate(c, s.State, 4, state.SubnetInfo{ 646 CIDR: "10.{{.}}.0.0/16", 647 ProviderId: "subnet-{{.}}", 648 AvailabilityZone: "zone{{.}}", 649 SpaceName: "{{if (lt . 2)}}space1{{else}}space2{{end}}", 650 }) 651 652 cons := constraints.MustParse("cores=12 mem=8G spaces=^space1,space2") 653 template := state.MachineTemplate{ 654 Series: "quantal", 655 Jobs: []state.MachineJob{state.JobHostUnits}, 656 Placement: "valid", 657 Constraints: cons, 658 } 659 machine, err := s.State.AddOneMachine(template) 660 c.Assert(err, jc.ErrorIsNil) 661 apiMachine := s.assertGetOneMachine(c, machine.MachineTag()) 662 provisioningInfo, err := apiMachine.ProvisioningInfo() 663 c.Assert(err, jc.ErrorIsNil) 664 c.Assert(provisioningInfo.Series, gc.Equals, template.Series) 665 c.Assert(provisioningInfo.Placement, gc.Equals, template.Placement) 666 c.Assert(provisioningInfo.Constraints, jc.DeepEquals, template.Constraints) 667 c.Assert(provisioningInfo.SubnetsToZones, jc.DeepEquals, map[string][]string{ 668 "subnet-2": {"zone2"}, 669 "subnet-3": {"zone3"}, 670 }) 671 } 672 673 func (s *provisionerSuite) TestProvisioningInfoMachineNotFound(c *gc.C) { 674 stateMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 675 c.Assert(err, jc.ErrorIsNil) 676 apiMachine := s.assertGetOneMachine(c, stateMachine.MachineTag()) 677 err = apiMachine.EnsureDead() 678 c.Assert(err, jc.ErrorIsNil) 679 err = apiMachine.Remove() 680 c.Assert(err, jc.ErrorIsNil) 681 _, err = apiMachine.ProvisioningInfo() 682 c.Assert(err, gc.ErrorMatches, "machine 1 not found") 683 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 684 // auth tests in apiserver 685 } 686 687 func (s *provisionerSuite) TestWatchContainers(c *gc.C) { 688 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 689 690 // Add one LXD container. 691 template := state.MachineTemplate{ 692 Series: "quantal", 693 Jobs: []state.MachineJob{state.JobHostUnits}, 694 } 695 container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXD) 696 c.Assert(err, jc.ErrorIsNil) 697 698 w, err := apiMachine.WatchContainers(instance.LXD) 699 c.Assert(err, jc.ErrorIsNil) 700 wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync) 701 defer wc.AssertStops() 702 703 // Initial event. 704 wc.AssertChange(container.Id()) 705 706 // Change something other than the containers and make sure it's 707 // not detected. 708 err = apiMachine.SetStatus(status.Started, "not really", nil) 709 c.Assert(err, jc.ErrorIsNil) 710 wc.AssertNoChange() 711 712 // Add a KVM container and make sure it's not detected. 713 container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.KVM) 714 c.Assert(err, jc.ErrorIsNil) 715 wc.AssertNoChange() 716 717 // Add another LXD container and make sure it's detected. 718 container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXD) 719 c.Assert(err, jc.ErrorIsNil) 720 wc.AssertChange(container.Id()) 721 } 722 723 func (s *provisionerSuite) TestWatchContainersCharmProfiles(c *gc.C) { 724 app := s.AddTestingApplication(c, "lxd-profile", s.AddTestingCharm(c, "lxd-profile")) 725 _, err := app.AddUnit(state.AddUnitParams{}) 726 c.Assert(err, jc.ErrorIsNil) 727 728 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 729 730 // Add one LXD container. 731 template := state.MachineTemplate{ 732 Series: "quantal", 733 Jobs: []state.MachineJob{state.JobHostUnits}, 734 } 735 container, err := s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXD) 736 c.Assert(err, jc.ErrorIsNil) 737 738 w, err := apiMachine.WatchContainersCharmProfiles(instance.LXD) 739 c.Assert(err, jc.ErrorIsNil) 740 wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync) 741 defer wc.AssertStops() 742 743 // Update the upgrade-charm charm profile to trigger watcher. 744 container.SetUpgradeCharmProfile("app-name", "local:quantal/lxd-profile-0") 745 c.Assert(err, jc.ErrorIsNil) 746 wc.AssertChange(container.Id()) 747 } 748 749 func (s *provisionerSuite) TestWatchContainersAcceptsSupportedContainers(c *gc.C) { 750 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 751 752 for _, ctype := range instance.ContainerTypes { 753 w, err := apiMachine.WatchContainers(ctype) 754 c.Assert(w, gc.NotNil) 755 c.Assert(err, jc.ErrorIsNil) 756 } 757 } 758 759 func (s *provisionerSuite) TestWatchContainersErrors(c *gc.C) { 760 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 761 762 _, err := apiMachine.WatchContainers(instance.NONE) 763 c.Assert(err, gc.ErrorMatches, `unsupported container type "none"`) 764 765 _, err = apiMachine.WatchContainers("") 766 c.Assert(err, gc.ErrorMatches, "container type must be specified") 767 } 768 769 func (s *provisionerSuite) TestWatchModelMachines(c *gc.C) { 770 w, err := s.provisioner.WatchModelMachines() 771 c.Assert(err, jc.ErrorIsNil) 772 wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync) 773 defer wc.AssertStops() 774 775 // Initial event. 776 wc.AssertChange(s.machine.Id()) 777 778 // Add another 2 machines make sure they are detected. 779 otherMachine, err := s.State.AddMachine("quantal", state.JobHostUnits) 780 c.Assert(err, jc.ErrorIsNil) 781 otherMachine, err = s.State.AddMachine("quantal", state.JobHostUnits) 782 c.Assert(err, jc.ErrorIsNil) 783 wc.AssertChange("1", "2") 784 785 // Change the lifecycle of last machine. 786 err = otherMachine.EnsureDead() 787 c.Assert(err, jc.ErrorIsNil) 788 wc.AssertChange("2") 789 790 // Add a container and make sure it's not detected. 791 template := state.MachineTemplate{ 792 Series: "quantal", 793 Jobs: []state.MachineJob{state.JobHostUnits}, 794 } 795 _, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXD) 796 c.Assert(err, jc.ErrorIsNil) 797 wc.AssertNoChange() 798 } 799 800 func (s *provisionerSuite) TestStateAddresses(c *gc.C) { 801 err := s.machine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 802 c.Assert(err, jc.ErrorIsNil) 803 804 stateAddresses, err := s.State.Addresses() 805 c.Assert(err, jc.ErrorIsNil) 806 807 addresses, err := s.provisioner.StateAddresses() 808 c.Assert(err, jc.ErrorIsNil) 809 c.Assert(addresses, gc.DeepEquals, stateAddresses) 810 } 811 812 func (s *provisionerSuite) getManagerConfig(c *gc.C, typ instance.ContainerType) map[string]string { 813 args := params.ContainerManagerConfigParams{Type: typ} 814 result, err := s.provisioner.ContainerManagerConfig(args) 815 c.Assert(err, jc.ErrorIsNil) 816 return result.ManagerConfig 817 } 818 819 func (s *provisionerSuite) TestContainerManagerConfigKVM(c *gc.C) { 820 cfg := s.getManagerConfig(c, instance.KVM) 821 c.Assert(cfg, jc.DeepEquals, map[string]string{ 822 container.ConfigModelUUID: coretesting.ModelTag.Id(), 823 config.ContainerImageStreamKey: "released", 824 }) 825 } 826 827 func (s *provisionerSuite) TestContainerManagerConfigPermissive(c *gc.C) { 828 // ContainerManagerConfig is permissive of container types, and 829 // will just return the basic type-independent configuration. 830 cfg := s.getManagerConfig(c, "invalid") 831 c.Assert(cfg, jc.DeepEquals, map[string]string{ 832 container.ConfigModelUUID: coretesting.ModelTag.Id(), 833 config.ContainerImageStreamKey: "released", 834 }) 835 } 836 837 func (s *provisionerSuite) TestContainerConfig(c *gc.C) { 838 result, err := s.provisioner.ContainerConfig() 839 c.Assert(err, jc.ErrorIsNil) 840 c.Assert(result.ProviderType, gc.Equals, "dummy") 841 c.Assert(result.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 842 c.Assert(result.SSLHostnameVerification, jc.IsTrue) 843 } 844 845 func (s *provisionerSuite) TestContainerConfigV5(c *gc.C) { 846 caller := apibasetesting.BestVersionCaller{ 847 APICallerFunc: s.st.APICall, 848 BestVersion: 5, 849 } 850 851 provAPI := provisioner.NewState(caller) 852 853 result, err := provAPI.ContainerConfig() 854 c.Assert(err, jc.ErrorIsNil) 855 c.Assert(result.ProviderType, gc.Equals, "dummy") 856 c.Assert(result.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 857 c.Assert(result.SSLHostnameVerification, jc.IsTrue) 858 } 859 860 func (s *provisionerSuite) TestSetSupportedContainers(c *gc.C) { 861 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 862 err := apiMachine.SetSupportedContainers(instance.LXD, instance.KVM) 863 c.Assert(err, jc.ErrorIsNil) 864 865 err = s.machine.Refresh() 866 c.Assert(err, jc.ErrorIsNil) 867 containers, ok := s.machine.SupportedContainers() 868 c.Assert(ok, jc.IsTrue) 869 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXD, instance.KVM}) 870 } 871 872 func (s *provisionerSuite) TestSupportsNoContainers(c *gc.C) { 873 apiMachine := s.assertGetOneMachine(c, s.machine.MachineTag()) 874 err := apiMachine.SupportsNoContainers() 875 c.Assert(err, jc.ErrorIsNil) 876 877 err = s.machine.Refresh() 878 c.Assert(err, jc.ErrorIsNil) 879 containers, ok := s.machine.SupportedContainers() 880 c.Assert(ok, jc.IsTrue) 881 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{}) 882 } 883 884 func (s *provisionerSuite) TestFindToolsNoArch(c *gc.C) { 885 s.testFindTools(c, false, nil, nil) 886 } 887 888 func (s *provisionerSuite) TestFindToolsArch(c *gc.C) { 889 s.testFindTools(c, true, nil, nil) 890 } 891 892 func (s *provisionerSuite) TestFindToolsAPIError(c *gc.C) { 893 apiError := errors.New("everything's broken") 894 s.testFindTools(c, false, apiError, nil) 895 } 896 897 func (s *provisionerSuite) TestFindToolsLogicError(c *gc.C) { 898 logicError := errors.NotFoundf("tools") 899 s.testFindTools(c, false, nil, logicError) 900 } 901 902 func (s *provisionerSuite) testFindTools(c *gc.C, matchArch bool, apiError, logicError error) { 903 current := version.Binary{ 904 Number: jujuversion.Current, 905 Arch: arch.HostArch(), 906 Series: series.MustHostSeries(), 907 } 908 var toolsList = coretools.List{&coretools.Tools{Version: current}} 909 var called bool 910 var a string 911 if matchArch { 912 // if matchArch is true, this will be overwriten with the host's arch, otherwise 913 // leave a blank. 914 a = arch.HostArch() 915 } 916 917 provisioner.PatchFacadeCall(s, s.provisioner, func(request string, args, response interface{}) error { 918 called = true 919 c.Assert(request, gc.Equals, "FindTools") 920 expected := params.FindToolsParams{ 921 Number: jujuversion.Current, 922 Series: series.MustHostSeries(), 923 Arch: a, 924 MinorVersion: -1, 925 MajorVersion: -1, 926 } 927 c.Assert(args, gc.Equals, expected) 928 result := response.(*params.FindToolsResult) 929 result.List = toolsList 930 if logicError != nil { 931 result.Error = common.ServerError(logicError) 932 } 933 return apiError 934 }) 935 apiList, err := s.provisioner.FindTools(jujuversion.Current, series.MustHostSeries(), a) 936 c.Assert(called, jc.IsTrue) 937 if apiError != nil { 938 c.Assert(err, gc.Equals, apiError) 939 } else if logicError != nil { 940 c.Assert(err.Error(), gc.Equals, logicError.Error()) 941 } else { 942 c.Assert(err, jc.ErrorIsNil) 943 c.Assert(apiList, jc.SameContents, toolsList) 944 } 945 } 946 947 func (s *provisionerSuite) TestHostChangesForContainer(c *gc.C) { 948 // Create a machine, put it in "default" space with a single NIC. Create 949 // a container that is also in the "default" space, and request the 950 // HostChangesForContainer to see that it wants to bridge that NIC 951 _, err := s.State.AddSpace("default", network.Id("default"), nil, true) 952 c.Assert(err, jc.ErrorIsNil) 953 _, err = s.State.AddSubnet(state.SubnetInfo{ 954 CIDR: "10.0.0.0/24", 955 SpaceName: "default", 956 }) 957 c.Assert(err, jc.ErrorIsNil) 958 err = s.machine.SetLinkLayerDevices( 959 state.LinkLayerDeviceArgs{ 960 Name: "ens3", 961 Type: state.EthernetDevice, 962 ParentName: "", 963 IsUp: true, 964 }, 965 ) 966 c.Assert(err, jc.ErrorIsNil) 967 err = s.machine.SetDevicesAddresses( 968 state.LinkLayerDeviceAddress{ 969 DeviceName: "ens3", 970 CIDRAddress: "10.0.0.10/24", 971 ConfigMethod: state.StaticAddress, 972 }, 973 ) 974 c.Assert(err, jc.ErrorIsNil) 975 containerTemplate := state.MachineTemplate{ 976 Series: "quantal", 977 Jobs: []state.MachineJob{state.JobHostUnits}, 978 } 979 container, err := s.State.AddMachineInsideMachine(containerTemplate, s.machine.Id(), instance.LXD) 980 c.Assert(err, jc.ErrorIsNil) 981 982 changes, reconfigureDelay, err := s.provisioner.HostChangesForContainer(container.MachineTag()) 983 c.Assert(err, gc.ErrorMatches, "dummy provider network config not supported.*") 984 c.Skip("can't test without network support") 985 c.Assert(err, jc.ErrorIsNil) 986 c.Check(changes, gc.DeepEquals, []network.DeviceToBridge{{ 987 BridgeName: "br-ens3", 988 DeviceName: "ens3", 989 }}) 990 c.Check(reconfigureDelay, gc.Equals, 0) 991 } 992 993 func (s *provisionerSuite) TestWatchModelMachinesCharmProfiles(c *gc.C) { 994 app := s.AddTestingApplication(c, "lxd-profile", s.AddTestingCharm(c, "lxd-profile")) 995 _, err := app.AddUnit(state.AddUnitParams{}) 996 c.Assert(err, jc.ErrorIsNil) 997 998 w, err := s.provisioner.WatchModelMachinesCharmProfiles() 999 c.Assert(err, jc.ErrorIsNil) 1000 wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync) 1001 defer wc.AssertStops() 1002 1003 // Trigger the watcher. 1004 err = s.machine.SetUpgradeCharmProfile("lxd-profile", "local:quantal/lxd-profile-0") 1005 c.Assert(err, jc.ErrorIsNil) 1006 wc.AssertChange(s.machine.Id()) 1007 } 1008 1009 var _ = gc.Suite(&provisionerContainerSuite{}) 1010 1011 type provisionerContainerSuite struct { 1012 containerTag names.MachineTag 1013 } 1014 1015 func (s *provisionerContainerSuite) SetUpTest(c *gc.C) { 1016 s.containerTag = names.NewMachineTag("0/lxd/0") 1017 } 1018 1019 func (s *provisionerContainerSuite) TestPrepareContainerInterfaceInfoNoValues(c *gc.C) { 1020 ctrl := gomock.NewController(c) 1021 defer ctrl.Finish() 1022 1023 args := params.Entities{ 1024 Entities: []params.Entity{{Tag: s.containerTag.String()}}, 1025 } 1026 results := params.MachineNetworkConfigResults{Results: []params.MachineNetworkConfigResult{{ 1027 Config: nil, 1028 Error: nil, 1029 }}} 1030 1031 facadeCaller := apimocks.NewMockFacadeCaller(ctrl) 1032 fExp := facadeCaller.EXPECT() 1033 fExp.FacadeCall("PrepareContainerInterfaceInfo", args, gomock.Any()).SetArg(2, results).Return(nil) 1034 1035 provisionerApi := provisioner.NewStateFromFacade(facadeCaller) 1036 1037 networkInfo, err := provisionerApi.PrepareContainerInterfaceInfo(s.containerTag) 1038 c.Assert(err, gc.IsNil) 1039 c.Check(networkInfo, jc.DeepEquals, []network.InterfaceInfo{}) 1040 } 1041 1042 func (s *provisionerContainerSuite) TestPrepareContainerInterfaceInfoSingleNIC(c *gc.C) { 1043 ctrl := gomock.NewController(c) 1044 defer ctrl.Finish() 1045 1046 args := params.Entities{ 1047 Entities: []params.Entity{{Tag: s.containerTag.String()}}, 1048 } 1049 results := params.MachineNetworkConfigResults{ 1050 Results: []params.MachineNetworkConfigResult{{ 1051 Config: []params.NetworkConfig{{ 1052 DeviceIndex: 1, 1053 MACAddress: "de:ad:be:ff:11:22", 1054 CIDR: "192.168.0.5/24", 1055 MTU: 9000, 1056 ProviderId: "prov-id", 1057 ProviderSubnetId: "prov-sub-id", 1058 ProviderSpaceId: "prov-space-id", 1059 ProviderAddressId: "prov-address-id", 1060 ProviderVLANId: "prov-vlan-id", 1061 VLANTag: 25, 1062 InterfaceName: "eth5", 1063 ParentInterfaceName: "parent#br-eth5", 1064 InterfaceType: "ethernet", 1065 Disabled: false, 1066 NoAutoStart: false, 1067 ConfigType: "static", 1068 Address: "192.168.0.6", 1069 DNSServers: []string{"8.8.8.8"}, 1070 DNSSearchDomains: []string{"mydomain"}, 1071 GatewayAddress: "192.168.0.1", 1072 Routes: []params.NetworkRoute{{ 1073 DestinationCIDR: "10.0.0.0/16", 1074 GatewayIP: "192.168.0.1", 1075 Metric: 55, 1076 }}, 1077 }}, 1078 Error: nil, 1079 }}, 1080 } 1081 1082 facadeCaller := apimocks.NewMockFacadeCaller(ctrl) 1083 fExp := facadeCaller.EXPECT() 1084 fExp.FacadeCall("PrepareContainerInterfaceInfo", args, gomock.Any()).SetArg(2, results).Return(nil) 1085 1086 provisionerApi := provisioner.NewStateFromFacade(facadeCaller) 1087 networkInfo, err := provisionerApi.PrepareContainerInterfaceInfo(s.containerTag) 1088 c.Assert(err, gc.IsNil) 1089 c.Check(networkInfo, jc.DeepEquals, []network.InterfaceInfo{{ 1090 DeviceIndex: 1, 1091 MACAddress: "de:ad:be:ff:11:22", 1092 CIDR: "192.168.0.5/24", 1093 MTU: 9000, 1094 ProviderId: "prov-id", 1095 ProviderSubnetId: "prov-sub-id", 1096 ProviderSpaceId: "prov-space-id", 1097 ProviderAddressId: "prov-address-id", 1098 ProviderVLANId: "prov-vlan-id", 1099 VLANTag: 25, 1100 InterfaceName: "eth5", 1101 ParentInterfaceName: "parent#br-eth5", 1102 InterfaceType: "ethernet", 1103 Disabled: false, 1104 NoAutoStart: false, 1105 ConfigType: "static", 1106 Address: network.NewAddress("192.168.0.6"), 1107 DNSServers: network.NewAddresses("8.8.8.8"), 1108 DNSSearchDomains: []string{"mydomain"}, 1109 GatewayAddress: network.NewAddress("192.168.0.1"), 1110 Routes: []network.Route{{ 1111 DestinationCIDR: "10.0.0.0/16", 1112 GatewayIP: "192.168.0.1", 1113 Metric: 55, 1114 }}, 1115 }}) 1116 } 1117 1118 func (s *provisionerContainerSuite) TestGetContainerProfileInfo(c *gc.C) { 1119 ctrl := gomock.NewController(c) 1120 defer ctrl.Finish() 1121 1122 args := params.Entities{ 1123 Entities: []params.Entity{{Tag: s.containerTag.String()}}, 1124 } 1125 results := params.ContainerProfileResults{ 1126 Results: []params.ContainerProfileResult{ 1127 { 1128 LXDProfiles: []*params.ContainerLXDProfile{ 1129 { 1130 Profile: params.CharmLXDProfile{ 1131 Config: map[string]string{ 1132 "security.nesting": "true", 1133 "security.privileged": "true", 1134 }, 1135 }, 1136 Name: "one", 1137 }, 1138 { 1139 Profile: params.CharmLXDProfile{ 1140 Devices: map[string]map[string]string{ 1141 "bdisk": { 1142 "source": "/dev/loop0", 1143 "type": "unix-block", 1144 }, 1145 }, 1146 }, 1147 Name: "two", 1148 }}, 1149 Error: nil, 1150 }}, 1151 } 1152 1153 facadeCaller := apimocks.NewMockFacadeCaller(ctrl) 1154 fExp := facadeCaller.EXPECT() 1155 fExp.FacadeCall("GetContainerProfileInfo", args, gomock.Any()).SetArg(2, results).Return(nil) 1156 1157 provisionerApi := provisioner.NewStateFromFacade(facadeCaller) 1158 1159 obtainedResults, err := provisionerApi.GetContainerProfileInfo(s.containerTag) 1160 c.Assert(err, jc.ErrorIsNil) 1161 c.Assert(obtainedResults, gc.DeepEquals, []*provisioner.LXDProfileResult{ 1162 { 1163 Config: map[string]string{ 1164 "security.nesting": "true", 1165 "security.privileged": "true", 1166 }, 1167 Name: "one", 1168 }, 1169 { 1170 Devices: map[string]map[string]string{ 1171 "bdisk": { 1172 "source": "/dev/loop0", 1173 "type": "unix-block", 1174 }, 1175 }, 1176 Name: "two", 1177 }}) 1178 1179 }