github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/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 stdtesting "testing" 9 "time" 10 11 "github.com/juju/errors" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils/proxy" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/names.v2" 16 17 "github.com/juju/juju/apiserver/common" 18 commontesting "github.com/juju/juju/apiserver/common/testing" 19 "github.com/juju/juju/apiserver/params" 20 "github.com/juju/juju/apiserver/provisioner" 21 apiservertesting "github.com/juju/juju/apiserver/testing" 22 "github.com/juju/juju/constraints" 23 "github.com/juju/juju/container" 24 "github.com/juju/juju/instance" 25 "github.com/juju/juju/juju/testing" 26 "github.com/juju/juju/network" 27 "github.com/juju/juju/provider/dummy" 28 "github.com/juju/juju/state" 29 statetesting "github.com/juju/juju/state/testing" 30 "github.com/juju/juju/status" 31 "github.com/juju/juju/storage/poolmanager" 32 coretesting "github.com/juju/juju/testing" 33 ) 34 35 func TestPackage(t *stdtesting.T) { 36 coretesting.MgoTestPackage(t) 37 } 38 39 type provisionerSuite struct { 40 testing.JujuConnSuite 41 42 machines []*state.Machine 43 44 authorizer apiservertesting.FakeAuthorizer 45 resources *common.Resources 46 provisioner *provisioner.ProvisionerAPI 47 } 48 49 var _ = gc.Suite(&provisionerSuite{}) 50 51 func (s *provisionerSuite) SetUpTest(c *gc.C) { 52 s.setUpTest(c, false) 53 } 54 55 func (s *provisionerSuite) setUpTest(c *gc.C, withController bool) { 56 s.JujuConnSuite.ConfigAttrs = map[string]interface{}{ 57 "image-stream": "daily", 58 } 59 s.JujuConnSuite.SetUpTest(c) 60 61 // Reset previous machines (if any) and create 3 machines 62 // for the tests, plus an optional controller machine. 63 s.machines = nil 64 // Note that the specific machine ids allocated are assumed 65 // to be numerically consecutive from zero. 66 if withController { 67 s.machines = append(s.machines, testing.AddControllerMachine(c, s.State)) 68 } 69 for i := 0; i < 5; i++ { 70 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 71 c.Check(err, jc.ErrorIsNil) 72 s.machines = append(s.machines, machine) 73 } 74 75 // Create a FakeAuthorizer so we can check permissions, 76 // set up assuming we logged in as the environment manager. 77 s.authorizer = apiservertesting.FakeAuthorizer{ 78 EnvironManager: true, 79 } 80 81 // Create the resource registry separately to track invocations to 82 // Register, and to register the root for tools URLs. 83 s.resources = common.NewResources() 84 85 // Create a provisioner API for the machine. 86 provisionerAPI, err := provisioner.NewProvisionerAPI( 87 s.State, 88 s.resources, 89 s.authorizer, 90 ) 91 c.Assert(err, jc.ErrorIsNil) 92 s.provisioner = provisionerAPI 93 } 94 95 type withoutControllerSuite struct { 96 provisionerSuite 97 *commontesting.ModelWatcherTest 98 } 99 100 var _ = gc.Suite(&withoutControllerSuite{}) 101 102 func (s *withoutControllerSuite) SetUpTest(c *gc.C) { 103 s.setUpTest(c, false) 104 s.ModelWatcherTest = commontesting.NewModelWatcherTest(s.provisioner, s.State, s.resources) 105 } 106 107 func (s *withoutControllerSuite) TestProvisionerFailsWithNonMachineAgentNonManagerUser(c *gc.C) { 108 anAuthorizer := s.authorizer 109 anAuthorizer.EnvironManager = true 110 // Works with an environment manager, which is not a machine agent. 111 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 112 c.Assert(err, jc.ErrorIsNil) 113 c.Assert(aProvisioner, gc.NotNil) 114 115 // But fails with neither a machine agent or an environment manager. 116 anAuthorizer.EnvironManager = false 117 aProvisioner, err = provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 118 c.Assert(err, gc.NotNil) 119 c.Assert(aProvisioner, gc.IsNil) 120 c.Assert(err, gc.ErrorMatches, "permission denied") 121 } 122 123 func (s *withoutControllerSuite) TestSetPasswords(c *gc.C) { 124 args := params.EntityPasswords{ 125 Changes: []params.EntityPassword{ 126 {Tag: s.machines[0].Tag().String(), Password: "xxx0-1234567890123457890"}, 127 {Tag: s.machines[1].Tag().String(), Password: "xxx1-1234567890123457890"}, 128 {Tag: s.machines[2].Tag().String(), Password: "xxx2-1234567890123457890"}, 129 {Tag: s.machines[3].Tag().String(), Password: "xxx3-1234567890123457890"}, 130 {Tag: s.machines[4].Tag().String(), Password: "xxx4-1234567890123457890"}, 131 {Tag: "machine-42", Password: "foo"}, 132 {Tag: "unit-foo-0", Password: "zzz"}, 133 {Tag: "application-bar", Password: "abc"}, 134 }, 135 } 136 results, err := s.provisioner.SetPasswords(args) 137 c.Assert(err, jc.ErrorIsNil) 138 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 139 Results: []params.ErrorResult{ 140 {nil}, 141 {nil}, 142 {nil}, 143 {nil}, 144 {nil}, 145 {apiservertesting.NotFoundError("machine 42")}, 146 {apiservertesting.ErrUnauthorized}, 147 {apiservertesting.ErrUnauthorized}, 148 }, 149 }) 150 151 // Verify the changes to both machines succeeded. 152 for i, machine := range s.machines { 153 c.Logf("trying %q password", machine.Tag()) 154 err = machine.Refresh() 155 c.Assert(err, jc.ErrorIsNil) 156 changed := machine.PasswordValid(fmt.Sprintf("xxx%d-1234567890123457890", i)) 157 c.Assert(changed, jc.IsTrue) 158 } 159 } 160 161 func (s *withoutControllerSuite) TestShortSetPasswords(c *gc.C) { 162 args := params.EntityPasswords{ 163 Changes: []params.EntityPassword{ 164 {Tag: s.machines[1].Tag().String(), Password: "xxx1"}, 165 }, 166 } 167 results, err := s.provisioner.SetPasswords(args) 168 c.Assert(err, jc.ErrorIsNil) 169 c.Assert(results.Results, gc.HasLen, 1) 170 c.Assert(results.Results[0].Error, gc.ErrorMatches, 171 "password is only 4 bytes long, and is not a valid Agent password") 172 } 173 174 func (s *withoutControllerSuite) TestLifeAsMachineAgent(c *gc.C) { 175 // NOTE: This and the next call serve to test the two 176 // different authorization schemes: 177 // 1. Machine agents can access their own machine and 178 // any container that has their own machine as parent; 179 // 2. Environment managers can access any machine without 180 // a parent. 181 // There's no need to repeat this test for each method, 182 // because the authorization logic is common. 183 184 // Login as a machine agent for machine 0. 185 anAuthorizer := s.authorizer 186 anAuthorizer.EnvironManager = false 187 anAuthorizer.Tag = s.machines[0].Tag() 188 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 189 c.Assert(err, jc.ErrorIsNil) 190 c.Assert(aProvisioner, gc.NotNil) 191 192 // Make the machine dead before trying to add containers. 193 err = s.machines[0].EnsureDead() 194 c.Assert(err, jc.ErrorIsNil) 195 196 // Create some containers to work on. 197 template := state.MachineTemplate{ 198 Series: "quantal", 199 Jobs: []state.MachineJob{state.JobHostUnits}, 200 } 201 var containers []*state.Machine 202 for i := 0; i < 3; i++ { 203 container, err := s.State.AddMachineInsideMachine(template, s.machines[0].Id(), instance.LXD) 204 c.Check(err, jc.ErrorIsNil) 205 containers = append(containers, container) 206 } 207 // Make one container dead. 208 err = containers[1].EnsureDead() 209 c.Assert(err, jc.ErrorIsNil) 210 211 args := params.Entities{Entities: []params.Entity{ 212 {Tag: s.machines[0].Tag().String()}, 213 {Tag: s.machines[1].Tag().String()}, 214 {Tag: containers[0].Tag().String()}, 215 {Tag: containers[1].Tag().String()}, 216 {Tag: containers[2].Tag().String()}, 217 {Tag: "machine-42"}, 218 {Tag: "unit-foo-0"}, 219 {Tag: "application-bar"}, 220 }} 221 result, err := aProvisioner.Life(args) 222 c.Assert(err, jc.ErrorIsNil) 223 c.Assert(result, gc.DeepEquals, params.LifeResults{ 224 Results: []params.LifeResult{ 225 {Life: "dead"}, 226 {Error: apiservertesting.ErrUnauthorized}, 227 {Life: "alive"}, 228 {Life: "dead"}, 229 {Life: "alive"}, 230 {Error: apiservertesting.ErrUnauthorized}, 231 {Error: apiservertesting.ErrUnauthorized}, 232 {Error: apiservertesting.ErrUnauthorized}, 233 }, 234 }) 235 } 236 237 func (s *withoutControllerSuite) TestLifeAsEnvironManager(c *gc.C) { 238 err := s.machines[1].EnsureDead() 239 c.Assert(err, jc.ErrorIsNil) 240 err = s.machines[1].Refresh() 241 c.Assert(err, jc.ErrorIsNil) 242 c.Assert(s.machines[0].Life(), gc.Equals, state.Alive) 243 c.Assert(s.machines[1].Life(), gc.Equals, state.Dead) 244 c.Assert(s.machines[2].Life(), gc.Equals, state.Alive) 245 246 args := params.Entities{Entities: []params.Entity{ 247 {Tag: s.machines[0].Tag().String()}, 248 {Tag: s.machines[1].Tag().String()}, 249 {Tag: s.machines[2].Tag().String()}, 250 {Tag: "machine-42"}, 251 {Tag: "unit-foo-0"}, 252 {Tag: "application-bar"}, 253 }} 254 result, err := s.provisioner.Life(args) 255 c.Assert(err, jc.ErrorIsNil) 256 c.Assert(result, gc.DeepEquals, params.LifeResults{ 257 Results: []params.LifeResult{ 258 {Life: "alive"}, 259 {Life: "dead"}, 260 {Life: "alive"}, 261 {Error: apiservertesting.NotFoundError("machine 42")}, 262 {Error: apiservertesting.ErrUnauthorized}, 263 {Error: apiservertesting.ErrUnauthorized}, 264 }, 265 }) 266 267 // Remove the subordinate and make sure it's detected. 268 err = s.machines[1].Remove() 269 c.Assert(err, jc.ErrorIsNil) 270 err = s.machines[1].Refresh() 271 c.Assert(err, jc.Satisfies, errors.IsNotFound) 272 273 result, err = s.provisioner.Life(params.Entities{ 274 Entities: []params.Entity{ 275 {Tag: s.machines[1].Tag().String()}, 276 }, 277 }) 278 c.Assert(err, jc.ErrorIsNil) 279 c.Assert(result, gc.DeepEquals, params.LifeResults{ 280 Results: []params.LifeResult{ 281 {Error: apiservertesting.NotFoundError("machine 1")}, 282 }, 283 }) 284 } 285 286 func (s *withoutControllerSuite) TestRemove(c *gc.C) { 287 err := s.machines[1].EnsureDead() 288 c.Assert(err, jc.ErrorIsNil) 289 s.assertLife(c, 0, state.Alive) 290 s.assertLife(c, 1, state.Dead) 291 s.assertLife(c, 2, state.Alive) 292 293 args := params.Entities{Entities: []params.Entity{ 294 {Tag: s.machines[0].Tag().String()}, 295 {Tag: s.machines[1].Tag().String()}, 296 {Tag: s.machines[2].Tag().String()}, 297 {Tag: "machine-42"}, 298 {Tag: "unit-foo-0"}, 299 {Tag: "application-bar"}, 300 }} 301 result, err := s.provisioner.Remove(args) 302 c.Assert(err, jc.ErrorIsNil) 303 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 304 Results: []params.ErrorResult{ 305 {¶ms.Error{Message: `cannot remove entity "machine-0": still alive`}}, 306 {nil}, 307 {¶ms.Error{Message: `cannot remove entity "machine-2": still alive`}}, 308 {apiservertesting.NotFoundError("machine 42")}, 309 {apiservertesting.ErrUnauthorized}, 310 {apiservertesting.ErrUnauthorized}, 311 }, 312 }) 313 314 // Verify the changes. 315 s.assertLife(c, 0, state.Alive) 316 err = s.machines[2].Refresh() 317 c.Assert(err, jc.ErrorIsNil) 318 s.assertLife(c, 2, state.Alive) 319 } 320 321 func (s *withoutControllerSuite) TestSetStatus(c *gc.C) { 322 now := time.Now() 323 sInfo := status.StatusInfo{ 324 Status: status.Started, 325 Message: "blah", 326 Since: &now, 327 } 328 err := s.machines[0].SetStatus(sInfo) 329 c.Assert(err, jc.ErrorIsNil) 330 sInfo = status.StatusInfo{ 331 Status: status.Stopped, 332 Message: "foo", 333 Since: &now, 334 } 335 err = s.machines[1].SetStatus(sInfo) 336 c.Assert(err, jc.ErrorIsNil) 337 sInfo = status.StatusInfo{ 338 Status: status.Error, 339 Message: "not really", 340 Since: &now, 341 } 342 err = s.machines[2].SetStatus(sInfo) 343 c.Assert(err, jc.ErrorIsNil) 344 345 args := params.SetStatus{ 346 Entities: []params.EntityStatusArgs{ 347 {Tag: s.machines[0].Tag().String(), Status: status.Error.String(), Info: "not really", 348 Data: map[string]interface{}{"foo": "bar"}}, 349 {Tag: s.machines[1].Tag().String(), Status: status.Stopped.String(), Info: "foobar"}, 350 {Tag: s.machines[2].Tag().String(), Status: status.Started.String(), Info: "again"}, 351 {Tag: "machine-42", Status: status.Started.String(), Info: "blah"}, 352 {Tag: "unit-foo-0", Status: status.Stopped.String(), Info: "foobar"}, 353 {Tag: "application-bar", Status: status.Stopped.String(), Info: "foobar"}, 354 }} 355 result, err := s.provisioner.SetStatus(args) 356 c.Assert(err, jc.ErrorIsNil) 357 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 358 Results: []params.ErrorResult{ 359 {nil}, 360 {nil}, 361 {nil}, 362 {apiservertesting.NotFoundError("machine 42")}, 363 {apiservertesting.ErrUnauthorized}, 364 {apiservertesting.ErrUnauthorized}, 365 }, 366 }) 367 368 // Verify the changes. 369 s.assertStatus(c, 0, status.Error, "not really", map[string]interface{}{"foo": "bar"}) 370 s.assertStatus(c, 1, status.Stopped, "foobar", map[string]interface{}{}) 371 s.assertStatus(c, 2, status.Started, "again", map[string]interface{}{}) 372 } 373 374 func (s *withoutControllerSuite) TestMachinesWithTransientErrors(c *gc.C) { 375 now := time.Now() 376 sInfo := status.StatusInfo{ 377 Status: status.Started, 378 Message: "blah", 379 Since: &now, 380 } 381 err := s.machines[0].SetStatus(sInfo) 382 c.Assert(err, jc.ErrorIsNil) 383 sInfo = status.StatusInfo{ 384 Status: status.Error, 385 Message: "transient error", 386 Data: map[string]interface{}{"transient": true, "foo": "bar"}, 387 Since: &now, 388 } 389 err = s.machines[1].SetStatus(sInfo) 390 c.Assert(err, jc.ErrorIsNil) 391 sInfo = status.StatusInfo{ 392 Status: status.Error, 393 Message: "error", 394 Data: map[string]interface{}{"transient": false}, 395 Since: &now, 396 } 397 err = s.machines[2].SetStatus(sInfo) 398 c.Assert(err, jc.ErrorIsNil) 399 sInfo = status.StatusInfo{ 400 Status: status.Error, 401 Message: "error", 402 Since: &now, 403 } 404 err = s.machines[3].SetStatus(sInfo) 405 c.Assert(err, jc.ErrorIsNil) 406 // Machine 4 is provisioned but error not reset yet. 407 sInfo = status.StatusInfo{ 408 Status: status.Error, 409 Message: "transient error", 410 Data: map[string]interface{}{"transient": true, "foo": "bar"}, 411 Since: &now, 412 } 413 err = s.machines[4].SetStatus(sInfo) 414 c.Assert(err, jc.ErrorIsNil) 415 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 416 err = s.machines[4].SetProvisioned("i-am", "fake_nonce", &hwChars) 417 c.Assert(err, jc.ErrorIsNil) 418 419 result, err := s.provisioner.MachinesWithTransientErrors() 420 c.Assert(err, jc.ErrorIsNil) 421 c.Assert(result, gc.DeepEquals, params.StatusResults{ 422 Results: []params.StatusResult{ 423 {Id: "1", Life: "alive", Status: "error", Info: "transient error", 424 Data: map[string]interface{}{"transient": true, "foo": "bar"}}, 425 }, 426 }) 427 } 428 429 func (s *withoutControllerSuite) TestMachinesWithTransientErrorsPermission(c *gc.C) { 430 // Machines where there's permission issues are omitted. 431 anAuthorizer := s.authorizer 432 anAuthorizer.EnvironManager = false 433 anAuthorizer.Tag = names.NewMachineTag("1") 434 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, 435 anAuthorizer) 436 now := time.Now() 437 sInfo := status.StatusInfo{ 438 Status: status.Started, 439 Message: "blah", 440 Since: &now, 441 } 442 err = s.machines[0].SetStatus(sInfo) 443 c.Assert(err, jc.ErrorIsNil) 444 sInfo = status.StatusInfo{ 445 Status: status.Error, 446 Message: "transient error", 447 Data: map[string]interface{}{"transient": true, "foo": "bar"}, 448 Since: &now, 449 } 450 err = s.machines[1].SetStatus(sInfo) 451 c.Assert(err, jc.ErrorIsNil) 452 sInfo = status.StatusInfo{ 453 Status: status.Error, 454 Message: "error", 455 Data: map[string]interface{}{"transient": false}, 456 Since: &now, 457 } 458 err = s.machines[2].SetStatus(sInfo) 459 c.Assert(err, jc.ErrorIsNil) 460 sInfo = status.StatusInfo{ 461 Status: status.Error, 462 Message: "error", 463 Since: &now, 464 } 465 err = s.machines[3].SetStatus(sInfo) 466 c.Assert(err, jc.ErrorIsNil) 467 468 result, err := aProvisioner.MachinesWithTransientErrors() 469 c.Assert(err, jc.ErrorIsNil) 470 c.Assert(result, gc.DeepEquals, params.StatusResults{ 471 Results: []params.StatusResult{ 472 {Id: "1", Life: "alive", Status: "error", Info: "transient error", 473 Data: map[string]interface{}{"transient": true, "foo": "bar"}}, 474 }, 475 }) 476 } 477 478 func (s *withoutControllerSuite) TestEnsureDead(c *gc.C) { 479 err := s.machines[1].EnsureDead() 480 c.Assert(err, jc.ErrorIsNil) 481 s.assertLife(c, 0, state.Alive) 482 s.assertLife(c, 1, state.Dead) 483 s.assertLife(c, 2, state.Alive) 484 485 args := params.Entities{Entities: []params.Entity{ 486 {Tag: s.machines[0].Tag().String()}, 487 {Tag: s.machines[1].Tag().String()}, 488 {Tag: s.machines[2].Tag().String()}, 489 {Tag: "machine-42"}, 490 {Tag: "unit-foo-0"}, 491 {Tag: "application-bar"}, 492 }} 493 result, err := s.provisioner.EnsureDead(args) 494 c.Assert(err, jc.ErrorIsNil) 495 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 496 Results: []params.ErrorResult{ 497 {nil}, 498 {nil}, 499 {nil}, 500 {apiservertesting.NotFoundError("machine 42")}, 501 {apiservertesting.ErrUnauthorized}, 502 {apiservertesting.ErrUnauthorized}, 503 }, 504 }) 505 506 // Verify the changes. 507 s.assertLife(c, 0, state.Dead) 508 s.assertLife(c, 1, state.Dead) 509 s.assertLife(c, 2, state.Dead) 510 } 511 512 func (s *withoutControllerSuite) assertLife(c *gc.C, index int, expectLife state.Life) { 513 err := s.machines[index].Refresh() 514 c.Assert(err, jc.ErrorIsNil) 515 c.Assert(s.machines[index].Life(), gc.Equals, expectLife) 516 } 517 518 func (s *withoutControllerSuite) assertStatus(c *gc.C, index int, expectStatus status.Status, expectInfo string, 519 expectData map[string]interface{}) { 520 521 statusInfo, err := s.machines[index].Status() 522 c.Assert(err, jc.ErrorIsNil) 523 c.Assert(statusInfo.Status, gc.Equals, expectStatus) 524 c.Assert(statusInfo.Message, gc.Equals, expectInfo) 525 c.Assert(statusInfo.Data, gc.DeepEquals, expectData) 526 } 527 528 func (s *withoutControllerSuite) TestWatchContainers(c *gc.C) { 529 c.Assert(s.resources.Count(), gc.Equals, 0) 530 531 args := params.WatchContainers{Params: []params.WatchContainer{ 532 {MachineTag: s.machines[0].Tag().String(), ContainerType: string(instance.LXD)}, 533 {MachineTag: s.machines[1].Tag().String(), ContainerType: string(instance.KVM)}, 534 {MachineTag: "machine-42", ContainerType: ""}, 535 {MachineTag: "unit-foo-0", ContainerType: ""}, 536 {MachineTag: "application-bar", ContainerType: ""}, 537 }} 538 result, err := s.provisioner.WatchContainers(args) 539 c.Assert(err, jc.ErrorIsNil) 540 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 541 Results: []params.StringsWatchResult{ 542 {StringsWatcherId: "1", Changes: []string{}}, 543 {StringsWatcherId: "2", Changes: []string{}}, 544 {Error: apiservertesting.NotFoundError("machine 42")}, 545 {Error: apiservertesting.ErrUnauthorized}, 546 {Error: apiservertesting.ErrUnauthorized}, 547 }, 548 }) 549 550 // Verify the resources were registered and stop them when done. 551 c.Assert(s.resources.Count(), gc.Equals, 2) 552 m0Watcher := s.resources.Get("1") 553 defer statetesting.AssertStop(c, m0Watcher) 554 m1Watcher := s.resources.Get("2") 555 defer statetesting.AssertStop(c, m1Watcher) 556 557 // Check that the Watch has consumed the initial event ("returned" 558 // in the Watch call) 559 wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher)) 560 wc0.AssertNoChange() 561 wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher)) 562 wc1.AssertNoChange() 563 } 564 565 func (s *withoutControllerSuite) TestWatchAllContainers(c *gc.C) { 566 c.Assert(s.resources.Count(), gc.Equals, 0) 567 568 args := params.WatchContainers{Params: []params.WatchContainer{ 569 {MachineTag: s.machines[0].Tag().String()}, 570 {MachineTag: s.machines[1].Tag().String()}, 571 {MachineTag: "machine-42"}, 572 {MachineTag: "unit-foo-0"}, 573 {MachineTag: "application-bar"}, 574 }} 575 result, err := s.provisioner.WatchAllContainers(args) 576 c.Assert(err, jc.ErrorIsNil) 577 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 578 Results: []params.StringsWatchResult{ 579 {StringsWatcherId: "1", Changes: []string{}}, 580 {StringsWatcherId: "2", Changes: []string{}}, 581 {Error: apiservertesting.NotFoundError("machine 42")}, 582 {Error: apiservertesting.ErrUnauthorized}, 583 {Error: apiservertesting.ErrUnauthorized}, 584 }, 585 }) 586 587 // Verify the resources were registered and stop them when done. 588 c.Assert(s.resources.Count(), gc.Equals, 2) 589 m0Watcher := s.resources.Get("1") 590 defer statetesting.AssertStop(c, m0Watcher) 591 m1Watcher := s.resources.Get("2") 592 defer statetesting.AssertStop(c, m1Watcher) 593 594 // Check that the Watch has consumed the initial event ("returned" 595 // in the Watch call) 596 wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher)) 597 wc0.AssertNoChange() 598 wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher)) 599 wc1.AssertNoChange() 600 } 601 602 func (s *withoutControllerSuite) TestModelConfigNonManager(c *gc.C) { 603 // Now test it with a non-environment manager and make sure 604 // the secret attributes are masked. 605 anAuthorizer := s.authorizer 606 anAuthorizer.Tag = names.NewMachineTag("1") 607 anAuthorizer.EnvironManager = false 608 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, 609 anAuthorizer) 610 c.Assert(err, jc.ErrorIsNil) 611 s.AssertModelConfig(c, aProvisioner) 612 } 613 614 func (s *withoutControllerSuite) TestStatus(c *gc.C) { 615 now := time.Now() 616 sInfo := status.StatusInfo{ 617 Status: status.Started, 618 Message: "blah", 619 Since: &now, 620 } 621 err := s.machines[0].SetStatus(sInfo) 622 c.Assert(err, jc.ErrorIsNil) 623 sInfo = status.StatusInfo{ 624 Status: status.Stopped, 625 Message: "foo", 626 Since: &now, 627 } 628 err = s.machines[1].SetStatus(sInfo) 629 c.Assert(err, jc.ErrorIsNil) 630 sInfo = status.StatusInfo{ 631 Status: status.Error, 632 Message: "not really", 633 Data: map[string]interface{}{"foo": "bar"}, 634 Since: &now, 635 } 636 err = s.machines[2].SetStatus(sInfo) 637 c.Assert(err, jc.ErrorIsNil) 638 639 args := params.Entities{Entities: []params.Entity{ 640 {Tag: s.machines[0].Tag().String()}, 641 {Tag: s.machines[1].Tag().String()}, 642 {Tag: s.machines[2].Tag().String()}, 643 {Tag: "machine-42"}, 644 {Tag: "unit-foo-0"}, 645 {Tag: "application-bar"}, 646 }} 647 result, err := s.provisioner.Status(args) 648 c.Assert(err, jc.ErrorIsNil) 649 // Zero out the updated timestamps so we can easily check the results. 650 for i, statusResult := range result.Results { 651 r := statusResult 652 if r.Status != "" { 653 c.Assert(r.Since, gc.NotNil) 654 } 655 r.Since = nil 656 result.Results[i] = r 657 } 658 c.Assert(result, gc.DeepEquals, params.StatusResults{ 659 Results: []params.StatusResult{ 660 {Status: status.Started.String(), Info: "blah", Data: map[string]interface{}{}}, 661 {Status: status.Stopped.String(), Info: "foo", Data: map[string]interface{}{}}, 662 {Status: status.Error.String(), Info: "not really", Data: map[string]interface{}{"foo": "bar"}}, 663 {Error: apiservertesting.NotFoundError("machine 42")}, 664 {Error: apiservertesting.ErrUnauthorized}, 665 {Error: apiservertesting.ErrUnauthorized}, 666 }, 667 }) 668 } 669 670 func (s *withoutControllerSuite) TestSeries(c *gc.C) { 671 // Add a machine with different series. 672 foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits) 673 c.Assert(err, jc.ErrorIsNil) 674 675 args := params.Entities{Entities: []params.Entity{ 676 {Tag: s.machines[0].Tag().String()}, 677 {Tag: foobarMachine.Tag().String()}, 678 {Tag: s.machines[2].Tag().String()}, 679 {Tag: "machine-42"}, 680 {Tag: "unit-foo-0"}, 681 {Tag: "application-bar"}, 682 }} 683 result, err := s.provisioner.Series(args) 684 c.Assert(err, jc.ErrorIsNil) 685 c.Assert(result, gc.DeepEquals, params.StringResults{ 686 Results: []params.StringResult{ 687 {Result: s.machines[0].Series()}, 688 {Result: foobarMachine.Series()}, 689 {Result: s.machines[2].Series()}, 690 {Error: apiservertesting.NotFoundError("machine 42")}, 691 {Error: apiservertesting.ErrUnauthorized}, 692 {Error: apiservertesting.ErrUnauthorized}, 693 }, 694 }) 695 } 696 697 func (s *withoutControllerSuite) TestDistributionGroup(c *gc.C) { 698 addUnits := func(name string, machines ...*state.Machine) (units []*state.Unit) { 699 svc := s.AddTestingService(c, name, s.AddTestingCharm(c, name)) 700 for _, m := range machines { 701 unit, err := svc.AddUnit() 702 c.Assert(err, jc.ErrorIsNil) 703 err = unit.AssignToMachine(m) 704 c.Assert(err, jc.ErrorIsNil) 705 units = append(units, unit) 706 } 707 return units 708 } 709 setProvisioned := func(id string) { 710 m, err := s.State.Machine(id) 711 c.Assert(err, jc.ErrorIsNil) 712 err = m.SetProvisioned(instance.Id("machine-"+id+"-inst"), "nonce", nil) 713 c.Assert(err, jc.ErrorIsNil) 714 } 715 716 mysqlUnit := addUnits("mysql", s.machines[0], s.machines[3])[0] 717 wordpressUnits := addUnits("wordpress", s.machines[0], s.machines[1], s.machines[2]) 718 719 // Unassign wordpress/1 from machine-1. 720 // The unit should not show up in the results. 721 err := wordpressUnits[1].UnassignFromMachine() 722 c.Assert(err, jc.ErrorIsNil) 723 724 // Provision machines 1, 2 and 3. Machine-0 remains 725 // unprovisioned, and machine-1 has no units, and so 726 // neither will show up in the results. 727 setProvisioned("1") 728 setProvisioned("2") 729 setProvisioned("3") 730 731 // Add a few controllers, provision two of them. 732 _, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 733 c.Assert(err, jc.ErrorIsNil) 734 setProvisioned("5") 735 setProvisioned("7") 736 737 // Create a logging service, subordinate to mysql. 738 s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 739 eps, err := s.State.InferEndpoints("mysql", "logging") 740 c.Assert(err, jc.ErrorIsNil) 741 rel, err := s.State.AddRelation(eps...) 742 c.Assert(err, jc.ErrorIsNil) 743 ru, err := rel.Unit(mysqlUnit) 744 c.Assert(err, jc.ErrorIsNil) 745 err = ru.EnterScope(nil) 746 c.Assert(err, jc.ErrorIsNil) 747 748 args := params.Entities{Entities: []params.Entity{ 749 {Tag: s.machines[0].Tag().String()}, 750 {Tag: s.machines[1].Tag().String()}, 751 {Tag: s.machines[2].Tag().String()}, 752 {Tag: s.machines[3].Tag().String()}, 753 {Tag: "machine-5"}, 754 }} 755 result, err := s.provisioner.DistributionGroup(args) 756 c.Assert(err, jc.ErrorIsNil) 757 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 758 Results: []params.DistributionGroupResult{ 759 {Result: []instance.Id{"machine-2-inst", "machine-3-inst"}}, 760 {Result: []instance.Id{}}, 761 {Result: []instance.Id{"machine-2-inst"}}, 762 {Result: []instance.Id{"machine-3-inst"}}, 763 {Result: []instance.Id{"machine-5-inst", "machine-7-inst"}}, 764 }, 765 }) 766 } 767 768 func (s *withoutControllerSuite) TestDistributionGroupEnvironManagerAuth(c *gc.C) { 769 args := params.Entities{Entities: []params.Entity{ 770 {Tag: "machine-0"}, 771 {Tag: "machine-42"}, 772 {Tag: "machine-0-lxd-99"}, 773 {Tag: "unit-foo-0"}, 774 {Tag: "application-bar"}, 775 }} 776 result, err := s.provisioner.DistributionGroup(args) 777 c.Assert(err, jc.ErrorIsNil) 778 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 779 Results: []params.DistributionGroupResult{ 780 // environ manager may access any top-level machines. 781 {Result: []instance.Id{}}, 782 {Error: apiservertesting.NotFoundError("machine 42")}, 783 // only a machine agent for the container or its 784 // parent may access it. 785 {Error: apiservertesting.ErrUnauthorized}, 786 // non-machines always unauthorized 787 {Error: apiservertesting.ErrUnauthorized}, 788 {Error: apiservertesting.ErrUnauthorized}, 789 }, 790 }) 791 } 792 793 func (s *withoutControllerSuite) TestDistributionGroupMachineAgentAuth(c *gc.C) { 794 anAuthorizer := s.authorizer 795 anAuthorizer.Tag = names.NewMachineTag("1") 796 anAuthorizer.EnvironManager = false 797 provisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 798 c.Check(err, jc.ErrorIsNil) 799 args := params.Entities{Entities: []params.Entity{ 800 {Tag: "machine-0"}, 801 {Tag: "machine-1"}, 802 {Tag: "machine-42"}, 803 {Tag: "machine-0-lxd-99"}, 804 {Tag: "machine-1-lxd-99"}, 805 {Tag: "machine-1-lxd-99-lxd-100"}, 806 }} 807 result, err := provisioner.DistributionGroup(args) 808 c.Assert(err, jc.ErrorIsNil) 809 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 810 Results: []params.DistributionGroupResult{ 811 {Error: apiservertesting.ErrUnauthorized}, 812 {Result: []instance.Id{}}, 813 {Error: apiservertesting.ErrUnauthorized}, 814 // only a machine agent for the container or its 815 // parent may access it. 816 {Error: apiservertesting.ErrUnauthorized}, 817 {Error: apiservertesting.NotFoundError("machine 1/lxd/99")}, 818 {Error: apiservertesting.ErrUnauthorized}, 819 }, 820 }) 821 } 822 823 func (s *withoutControllerSuite) TestConstraints(c *gc.C) { 824 // Add a machine with some constraints. 825 cons := constraints.MustParse("cores=123", "mem=8G") 826 template := state.MachineTemplate{ 827 Series: "quantal", 828 Jobs: []state.MachineJob{state.JobHostUnits}, 829 Constraints: cons, 830 } 831 consMachine, err := s.State.AddOneMachine(template) 832 c.Assert(err, jc.ErrorIsNil) 833 834 machine0Constraints, err := s.machines[0].Constraints() 835 c.Assert(err, jc.ErrorIsNil) 836 837 args := params.Entities{Entities: []params.Entity{ 838 {Tag: s.machines[0].Tag().String()}, 839 {Tag: consMachine.Tag().String()}, 840 {Tag: "machine-42"}, 841 {Tag: "unit-foo-0"}, 842 {Tag: "application-bar"}, 843 }} 844 result, err := s.provisioner.Constraints(args) 845 c.Assert(err, jc.ErrorIsNil) 846 c.Assert(result, gc.DeepEquals, params.ConstraintsResults{ 847 Results: []params.ConstraintsResult{ 848 {Constraints: machine0Constraints}, 849 {Constraints: template.Constraints}, 850 {Error: apiservertesting.NotFoundError("machine 42")}, 851 {Error: apiservertesting.ErrUnauthorized}, 852 {Error: apiservertesting.ErrUnauthorized}, 853 }, 854 }) 855 } 856 857 func (s *withoutControllerSuite) TestSetInstanceInfo(c *gc.C) { 858 pm := poolmanager.New(state.NewStateSettings(s.State), dummy.StorageProviders()) 859 _, err := pm.Create("static-pool", "static", map[string]interface{}{"foo": "bar"}) 860 c.Assert(err, jc.ErrorIsNil) 861 err = s.State.UpdateModelConfig(map[string]interface{}{ 862 "storage-default-block-source": "static-pool", 863 }, nil, nil) 864 c.Assert(err, jc.ErrorIsNil) 865 866 // Provision machine 0 first. 867 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 868 err = s.machines[0].SetInstanceInfo("i-am", "fake_nonce", &hwChars, nil, nil, nil, nil) 869 c.Assert(err, jc.ErrorIsNil) 870 871 volumesMachine, err := s.State.AddOneMachine(state.MachineTemplate{ 872 Series: "quantal", 873 Jobs: []state.MachineJob{state.JobHostUnits}, 874 Volumes: []state.MachineVolumeParams{{ 875 Volume: state.VolumeParams{Size: 1000}, 876 }}, 877 }) 878 c.Assert(err, jc.ErrorIsNil) 879 880 args := params.InstancesInfo{Machines: []params.InstanceInfo{{ 881 Tag: s.machines[0].Tag().String(), 882 InstanceId: "i-was", 883 Nonce: "fake_nonce", 884 }, { 885 Tag: s.machines[1].Tag().String(), 886 InstanceId: "i-will", 887 Nonce: "fake_nonce", 888 Characteristics: &hwChars, 889 }, { 890 Tag: s.machines[2].Tag().String(), 891 InstanceId: "i-am-too", 892 Nonce: "fake", 893 Characteristics: nil, 894 }, { 895 Tag: volumesMachine.Tag().String(), 896 InstanceId: "i-am-also", 897 Nonce: "fake", 898 Volumes: []params.Volume{{ 899 VolumeTag: "volume-0", 900 Info: params.VolumeInfo{ 901 VolumeId: "vol-0", 902 Size: 1234, 903 }, 904 }}, 905 VolumeAttachments: map[string]params.VolumeAttachmentInfo{ 906 "volume-0": { 907 DeviceName: "sda", 908 }, 909 }, 910 }, 911 {Tag: "machine-42"}, 912 {Tag: "unit-foo-0"}, 913 {Tag: "application-bar"}, 914 }} 915 result, err := s.provisioner.SetInstanceInfo(args) 916 c.Assert(err, jc.ErrorIsNil) 917 c.Assert(result, jc.DeepEquals, params.ErrorResults{ 918 Results: []params.ErrorResult{ 919 {¶ms.Error{ 920 Message: `cannot record provisioning info for "i-was": cannot set instance data for machine "0": already set`, 921 }}, 922 {nil}, 923 {nil}, 924 {nil}, 925 {apiservertesting.NotFoundError("machine 42")}, 926 {apiservertesting.ErrUnauthorized}, 927 {apiservertesting.ErrUnauthorized}, 928 }, 929 }) 930 931 // Verify machine 1 and 2 were provisioned. 932 c.Assert(s.machines[1].Refresh(), gc.IsNil) 933 c.Assert(s.machines[2].Refresh(), gc.IsNil) 934 935 instanceId, err := s.machines[1].InstanceId() 936 c.Assert(err, jc.ErrorIsNil) 937 c.Check(instanceId, gc.Equals, instance.Id("i-will")) 938 instanceId, err = s.machines[2].InstanceId() 939 c.Assert(err, jc.ErrorIsNil) 940 c.Check(instanceId, gc.Equals, instance.Id("i-am-too")) 941 c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue) 942 c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue) 943 gotHardware, err := s.machines[1].HardwareCharacteristics() 944 c.Assert(err, jc.ErrorIsNil) 945 c.Check(gotHardware, gc.DeepEquals, &hwChars) 946 947 // Verify the machine with requested volumes was provisioned, and the 948 // volume information recorded in state. 949 volumeAttachments, err := s.State.MachineVolumeAttachments(volumesMachine.MachineTag()) 950 c.Assert(err, jc.ErrorIsNil) 951 c.Assert(volumeAttachments, gc.HasLen, 1) 952 volumeAttachmentInfo, err := volumeAttachments[0].Info() 953 c.Assert(err, jc.ErrorIsNil) 954 c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{DeviceName: "sda"}) 955 volume, err := s.State.Volume(volumeAttachments[0].Volume()) 956 c.Assert(err, jc.ErrorIsNil) 957 volumeInfo, err := volume.Info() 958 c.Assert(err, jc.ErrorIsNil) 959 c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{VolumeId: "vol-0", Pool: "static-pool", Size: 1234}) 960 961 // Verify the machine without requested volumes still has no volume 962 // attachments recorded in state. 963 volumeAttachments, err = s.State.MachineVolumeAttachments(s.machines[1].MachineTag()) 964 c.Assert(err, jc.ErrorIsNil) 965 c.Assert(volumeAttachments, gc.HasLen, 0) 966 } 967 968 func (s *withoutControllerSuite) TestInstanceId(c *gc.C) { 969 // Provision 2 machines first. 970 err := s.machines[0].SetProvisioned("i-am", "fake_nonce", nil) 971 c.Assert(err, jc.ErrorIsNil) 972 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 973 err = s.machines[1].SetProvisioned("i-am-not", "fake_nonce", &hwChars) 974 c.Assert(err, jc.ErrorIsNil) 975 976 args := params.Entities{Entities: []params.Entity{ 977 {Tag: s.machines[0].Tag().String()}, 978 {Tag: s.machines[1].Tag().String()}, 979 {Tag: s.machines[2].Tag().String()}, 980 {Tag: "machine-42"}, 981 {Tag: "unit-foo-0"}, 982 {Tag: "application-bar"}, 983 }} 984 result, err := s.provisioner.InstanceId(args) 985 c.Assert(err, jc.ErrorIsNil) 986 c.Assert(result, gc.DeepEquals, params.StringResults{ 987 Results: []params.StringResult{ 988 {Result: "i-am"}, 989 {Result: "i-am-not"}, 990 {Error: apiservertesting.NotProvisionedError("2")}, 991 {Error: apiservertesting.NotFoundError("machine 42")}, 992 {Error: apiservertesting.ErrUnauthorized}, 993 {Error: apiservertesting.ErrUnauthorized}, 994 }, 995 }) 996 } 997 998 func (s *withoutControllerSuite) TestWatchModelMachines(c *gc.C) { 999 c.Assert(s.resources.Count(), gc.Equals, 0) 1000 1001 got, err := s.provisioner.WatchModelMachines() 1002 c.Assert(err, jc.ErrorIsNil) 1003 want := params.StringsWatchResult{ 1004 StringsWatcherId: "1", 1005 Changes: []string{"0", "1", "2", "3", "4"}, 1006 } 1007 c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId) 1008 c.Assert(got.Changes, jc.SameContents, want.Changes) 1009 1010 // Verify the resources were registered and stop them when done. 1011 c.Assert(s.resources.Count(), gc.Equals, 1) 1012 resource := s.resources.Get("1") 1013 defer statetesting.AssertStop(c, resource) 1014 1015 // Check that the Watch has consumed the initial event ("returned" 1016 // in the Watch call) 1017 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 1018 wc.AssertNoChange() 1019 1020 // Make sure WatchModelMachines fails with a machine agent login. 1021 anAuthorizer := s.authorizer 1022 anAuthorizer.Tag = names.NewMachineTag("1") 1023 anAuthorizer.EnvironManager = false 1024 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1025 c.Assert(err, jc.ErrorIsNil) 1026 1027 result, err := aProvisioner.WatchModelMachines() 1028 c.Assert(err, gc.ErrorMatches, "permission denied") 1029 c.Assert(result, gc.DeepEquals, params.StringsWatchResult{}) 1030 } 1031 1032 func (s *provisionerSuite) getManagerConfig(c *gc.C, typ instance.ContainerType) map[string]string { 1033 args := params.ContainerManagerConfigParams{Type: typ} 1034 results, err := s.provisioner.ContainerManagerConfig(args) 1035 c.Assert(err, jc.ErrorIsNil) 1036 return results.ManagerConfig 1037 } 1038 1039 func (s *withoutControllerSuite) TestContainerManagerConfig(c *gc.C) { 1040 cfg := s.getManagerConfig(c, instance.KVM) 1041 c.Assert(cfg, jc.DeepEquals, map[string]string{ 1042 container.ConfigModelUUID: coretesting.ModelTag.Id(), 1043 }) 1044 } 1045 1046 func (s *withoutControllerSuite) TestContainerConfig(c *gc.C) { 1047 attrs := map[string]interface{}{ 1048 "http-proxy": "http://proxy.example.com:9000", 1049 "allow-lxd-loop-mounts": true, 1050 "apt-mirror": "http://example.mirror.com", 1051 } 1052 err := s.State.UpdateModelConfig(attrs, nil, nil) 1053 c.Assert(err, jc.ErrorIsNil) 1054 expectedProxy := proxy.Settings{ 1055 Http: "http://proxy.example.com:9000", 1056 } 1057 1058 results, err := s.provisioner.ContainerConfig() 1059 c.Check(err, jc.ErrorIsNil) 1060 c.Check(results.UpdateBehavior, gc.Not(gc.IsNil)) 1061 c.Check(results.ProviderType, gc.Equals, "dummy") 1062 c.Check(results.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 1063 c.Check(results.SSLHostnameVerification, jc.IsTrue) 1064 c.Check(results.Proxy, gc.DeepEquals, expectedProxy) 1065 c.Check(results.AptProxy, gc.DeepEquals, expectedProxy) 1066 c.Check(results.AptMirror, gc.DeepEquals, "http://example.mirror.com") 1067 } 1068 1069 func (s *withoutControllerSuite) TestSetSupportedContainers(c *gc.C) { 1070 args := params.MachineContainersParams{Params: []params.MachineContainers{{ 1071 MachineTag: "machine-0", 1072 ContainerTypes: []instance.ContainerType{instance.LXD}, 1073 }, { 1074 MachineTag: "machine-1", 1075 ContainerTypes: []instance.ContainerType{instance.LXD, instance.KVM}, 1076 }}} 1077 results, err := s.provisioner.SetSupportedContainers(args) 1078 c.Assert(err, jc.ErrorIsNil) 1079 c.Assert(results.Results, gc.HasLen, 2) 1080 for _, result := range results.Results { 1081 c.Assert(result.Error, gc.IsNil) 1082 } 1083 m0, err := s.State.Machine("0") 1084 c.Assert(err, jc.ErrorIsNil) 1085 containers, ok := m0.SupportedContainers() 1086 c.Assert(ok, jc.IsTrue) 1087 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXD}) 1088 m1, err := s.State.Machine("1") 1089 c.Assert(err, jc.ErrorIsNil) 1090 containers, ok = m1.SupportedContainers() 1091 c.Assert(ok, jc.IsTrue) 1092 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXD, instance.KVM}) 1093 } 1094 1095 func (s *withoutControllerSuite) TestSetSupportedContainersPermissions(c *gc.C) { 1096 // Login as a machine agent for machine 0. 1097 anAuthorizer := s.authorizer 1098 anAuthorizer.EnvironManager = false 1099 anAuthorizer.Tag = s.machines[0].Tag() 1100 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1101 c.Assert(err, jc.ErrorIsNil) 1102 c.Assert(aProvisioner, gc.NotNil) 1103 1104 args := params.MachineContainersParams{ 1105 Params: []params.MachineContainers{{ 1106 MachineTag: "machine-0", 1107 ContainerTypes: []instance.ContainerType{instance.LXD}, 1108 }, { 1109 MachineTag: "machine-1", 1110 ContainerTypes: []instance.ContainerType{instance.LXD}, 1111 }, { 1112 MachineTag: "machine-42", 1113 ContainerTypes: []instance.ContainerType{instance.LXD}, 1114 }, 1115 }, 1116 } 1117 // Only machine 0 can have it's containers updated. 1118 results, err := aProvisioner.SetSupportedContainers(args) 1119 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 1120 Results: []params.ErrorResult{ 1121 {Error: nil}, 1122 {Error: apiservertesting.ErrUnauthorized}, 1123 {Error: apiservertesting.ErrUnauthorized}, 1124 }, 1125 }) 1126 } 1127 1128 func (s *withoutControllerSuite) TestSupportsNoContainers(c *gc.C) { 1129 args := params.MachineContainersParams{ 1130 Params: []params.MachineContainers{ 1131 { 1132 MachineTag: "machine-0", 1133 }, 1134 }, 1135 } 1136 results, err := s.provisioner.SetSupportedContainers(args) 1137 c.Assert(err, jc.ErrorIsNil) 1138 c.Assert(results.Results, gc.HasLen, 1) 1139 c.Assert(results.Results[0].Error, gc.IsNil) 1140 m0, err := s.State.Machine("0") 1141 c.Assert(err, jc.ErrorIsNil) 1142 containers, ok := m0.SupportedContainers() 1143 c.Assert(ok, jc.IsTrue) 1144 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{}) 1145 } 1146 1147 var _ = gc.Suite(&withControllerSuite{}) 1148 1149 type withControllerSuite struct { 1150 provisionerSuite 1151 } 1152 1153 func (s *withControllerSuite) SetUpTest(c *gc.C) { 1154 s.provisionerSuite.setUpTest(c, true) 1155 } 1156 1157 func (s *withControllerSuite) TestAPIAddresses(c *gc.C) { 1158 hostPorts := [][]network.HostPort{ 1159 network.NewHostPorts(1234, "0.1.2.3"), 1160 } 1161 err := s.State.SetAPIHostPorts(hostPorts) 1162 c.Assert(err, jc.ErrorIsNil) 1163 1164 result, err := s.provisioner.APIAddresses() 1165 c.Assert(err, jc.ErrorIsNil) 1166 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1167 Result: []string{"0.1.2.3:1234"}, 1168 }) 1169 } 1170 1171 func (s *withControllerSuite) TestStateAddresses(c *gc.C) { 1172 addresses, err := s.State.Addresses() 1173 c.Assert(err, jc.ErrorIsNil) 1174 1175 result, err := s.provisioner.StateAddresses() 1176 c.Assert(err, jc.ErrorIsNil) 1177 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1178 Result: addresses, 1179 }) 1180 } 1181 1182 func (s *withControllerSuite) TestCACert(c *gc.C) { 1183 result := s.provisioner.CACert() 1184 c.Assert(result, gc.DeepEquals, params.BytesResult{ 1185 Result: []byte(s.State.CACert()), 1186 }) 1187 } 1188 1189 func (s *withoutControllerSuite) TestWatchMachineErrorRetry(c *gc.C) { 1190 coretesting.SkipIfI386(c, "lp:1425569") 1191 1192 s.PatchValue(&provisioner.ErrorRetryWaitDelay, 2*coretesting.ShortWait) 1193 c.Assert(s.resources.Count(), gc.Equals, 0) 1194 1195 _, err := s.provisioner.WatchMachineErrorRetry() 1196 c.Assert(err, jc.ErrorIsNil) 1197 1198 // Verify the resources were registered and stop them when done. 1199 c.Assert(s.resources.Count(), gc.Equals, 1) 1200 resource := s.resources.Get("1") 1201 defer statetesting.AssertStop(c, resource) 1202 1203 // Check that the Watch has consumed the initial event ("returned" 1204 // in the Watch call) 1205 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 1206 wc.AssertNoChange() 1207 1208 // We should now get a time triggered change. 1209 wc.AssertOneChange() 1210 1211 // Make sure WatchMachineErrorRetry fails with a machine agent login. 1212 anAuthorizer := s.authorizer 1213 anAuthorizer.Tag = names.NewMachineTag("1") 1214 anAuthorizer.EnvironManager = false 1215 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1216 c.Assert(err, jc.ErrorIsNil) 1217 1218 result, err := aProvisioner.WatchMachineErrorRetry() 1219 c.Assert(err, gc.ErrorMatches, "permission denied") 1220 c.Assert(result, gc.DeepEquals, params.NotifyWatchResult{}) 1221 } 1222 1223 func (s *withoutControllerSuite) TestFindTools(c *gc.C) { 1224 args := params.FindToolsParams{ 1225 MajorVersion: -1, 1226 MinorVersion: -1, 1227 } 1228 result, err := s.provisioner.FindTools(args) 1229 c.Assert(err, jc.ErrorIsNil) 1230 c.Assert(result.Error, gc.IsNil) 1231 c.Assert(result.List, gc.Not(gc.HasLen), 0) 1232 for _, tools := range result.List { 1233 url := fmt.Sprintf("https://%s/model/%s/tools/%s", 1234 s.APIState.Addr(), coretesting.ModelTag.Id(), tools.Version) 1235 c.Assert(tools.URL, gc.Equals, url) 1236 } 1237 } 1238 1239 func (s *withoutControllerSuite) TestMarkMachinesForRemoval(c *gc.C) { 1240 err := s.machines[0].EnsureDead() 1241 c.Assert(err, jc.ErrorIsNil) 1242 err = s.machines[2].EnsureDead() 1243 c.Assert(err, jc.ErrorIsNil) 1244 1245 res, err := s.provisioner.MarkMachinesForRemoval(params.Entities{ 1246 Entities: []params.Entity{ 1247 {Tag: "machine-2"}, // ok 1248 {Tag: "machine-100"}, // not found 1249 {Tag: "machine-0"}, // ok 1250 {Tag: "machine-1"}, // not dead 1251 {Tag: "machine-0-lxd-5"}, // unauthorised 1252 {Tag: "application-thing"}, // only machines allowed 1253 }, 1254 }) 1255 c.Assert(err, jc.ErrorIsNil) 1256 results := res.Results 1257 c.Assert(results, gc.HasLen, 6) 1258 c.Check(results[0].Error, gc.IsNil) 1259 c.Check(*results[1].Error, gc.Equals, 1260 *common.ServerError(errors.NotFoundf("machine 100"))) 1261 c.Check(*results[1].Error, jc.Satisfies, params.IsCodeNotFound) 1262 c.Check(results[2].Error, gc.IsNil) 1263 c.Check(*results[3].Error, gc.Equals, 1264 *common.ServerError(errors.New("cannot remove machine 1: machine is not dead"))) 1265 c.Check(*results[4].Error, gc.Equals, *apiservertesting.ErrUnauthorized) 1266 c.Check(*results[5].Error, gc.Equals, 1267 *common.ServerError(errors.New(`"application-thing" is not a valid machine tag`))) 1268 1269 removals, err := s.State.AllMachineRemovals() 1270 c.Assert(err, jc.ErrorIsNil) 1271 c.Check(removals, jc.SameContents, []string{"0", "2"}) 1272 }