github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils/proxy" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/apiserver/common" 17 commontesting "github.com/juju/juju/apiserver/common/testing" 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/apiserver/provisioner" 20 apiservertesting "github.com/juju/juju/apiserver/testing" 21 "github.com/juju/juju/constraints" 22 "github.com/juju/juju/container" 23 "github.com/juju/juju/environs/tags" 24 "github.com/juju/juju/feature" 25 "github.com/juju/juju/instance" 26 "github.com/juju/juju/juju/testing" 27 "github.com/juju/juju/network" 28 "github.com/juju/juju/provider/dummy" 29 "github.com/juju/juju/state" 30 "github.com/juju/juju/state/multiwatcher" 31 statetesting "github.com/juju/juju/state/testing" 32 "github.com/juju/juju/storage/poolmanager" 33 storagedummy "github.com/juju/juju/storage/provider/dummy" 34 "github.com/juju/juju/storage/provider/registry" 35 coretesting "github.com/juju/juju/testing" 36 ) 37 38 func Test(t *stdtesting.T) { 39 coretesting.MgoTestPackage(t) 40 } 41 42 type provisionerSuite struct { 43 testing.JujuConnSuite 44 45 machines []*state.Machine 46 47 authorizer apiservertesting.FakeAuthorizer 48 resources *common.Resources 49 provisioner *provisioner.ProvisionerAPI 50 } 51 52 var _ = gc.Suite(&provisionerSuite{}) 53 54 func (s *provisionerSuite) SetUpTest(c *gc.C) { 55 s.setUpTest(c, false) 56 } 57 58 func (s *provisionerSuite) setUpTest(c *gc.C, withStateServer bool) { 59 s.JujuConnSuite.SetUpTest(c) 60 // We're testing with address allocation on by default. There are 61 // separate tests to check the behavior when the flag is not 62 // enabled. 63 s.SetFeatureFlags(feature.AddressAllocation) 64 65 // Reset previous machines (if any) and create 3 machines 66 // for the tests, plus an optional state server machine. 67 s.machines = nil 68 // Note that the specific machine ids allocated are assumed 69 // to be numerically consecutive from zero. 70 if withStateServer { 71 s.machines = append(s.machines, testing.AddStateServerMachine(c, s.State)) 72 } 73 for i := 0; i < 5; i++ { 74 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 75 c.Check(err, jc.ErrorIsNil) 76 s.machines = append(s.machines, machine) 77 } 78 79 // Create a FakeAuthorizer so we can check permissions, 80 // set up assuming we logged in as the environment manager. 81 s.authorizer = apiservertesting.FakeAuthorizer{ 82 EnvironManager: true, 83 } 84 85 // Create the resource registry separately to track invocations to 86 // Register, and to register the root for tools URLs. 87 s.resources = common.NewResources() 88 89 // Create a provisioner API for the machine. 90 provisionerAPI, err := provisioner.NewProvisionerAPI( 91 s.State, 92 s.resources, 93 s.authorizer, 94 ) 95 c.Assert(err, jc.ErrorIsNil) 96 s.provisioner = provisionerAPI 97 } 98 99 type withoutStateServerSuite struct { 100 provisionerSuite 101 *commontesting.EnvironWatcherTest 102 } 103 104 var _ = gc.Suite(&withoutStateServerSuite{}) 105 106 func (s *withoutStateServerSuite) SetUpTest(c *gc.C) { 107 s.setUpTest(c, false) 108 s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.provisioner, s.State, s.resources, commontesting.HasSecrets) 109 } 110 111 func (s *withoutStateServerSuite) TestProvisionerFailsWithNonMachineAgentNonManagerUser(c *gc.C) { 112 anAuthorizer := s.authorizer 113 anAuthorizer.EnvironManager = true 114 // Works with an environment manager, which is not a machine agent. 115 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 116 c.Assert(err, jc.ErrorIsNil) 117 c.Assert(aProvisioner, gc.NotNil) 118 119 // But fails with neither a machine agent or an environment manager. 120 anAuthorizer.EnvironManager = false 121 aProvisioner, err = provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 122 c.Assert(err, gc.NotNil) 123 c.Assert(aProvisioner, gc.IsNil) 124 c.Assert(err, gc.ErrorMatches, "permission denied") 125 } 126 127 func (s *withoutStateServerSuite) TestSetPasswords(c *gc.C) { 128 args := params.EntityPasswords{ 129 Changes: []params.EntityPassword{ 130 {Tag: s.machines[0].Tag().String(), Password: "xxx0-1234567890123457890"}, 131 {Tag: s.machines[1].Tag().String(), Password: "xxx1-1234567890123457890"}, 132 {Tag: s.machines[2].Tag().String(), Password: "xxx2-1234567890123457890"}, 133 {Tag: s.machines[3].Tag().String(), Password: "xxx3-1234567890123457890"}, 134 {Tag: s.machines[4].Tag().String(), Password: "xxx4-1234567890123457890"}, 135 {Tag: "machine-42", Password: "foo"}, 136 {Tag: "unit-foo-0", Password: "zzz"}, 137 {Tag: "service-bar", Password: "abc"}, 138 }, 139 } 140 results, err := s.provisioner.SetPasswords(args) 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 143 Results: []params.ErrorResult{ 144 {nil}, 145 {nil}, 146 {nil}, 147 {nil}, 148 {nil}, 149 {apiservertesting.NotFoundError("machine 42")}, 150 {apiservertesting.ErrUnauthorized}, 151 {apiservertesting.ErrUnauthorized}, 152 }, 153 }) 154 155 // Verify the changes to both machines succeeded. 156 for i, machine := range s.machines { 157 c.Logf("trying %q password", machine.Tag()) 158 err = machine.Refresh() 159 c.Assert(err, jc.ErrorIsNil) 160 changed := machine.PasswordValid(fmt.Sprintf("xxx%d-1234567890123457890", i)) 161 c.Assert(changed, jc.IsTrue) 162 } 163 } 164 165 func (s *withoutStateServerSuite) TestShortSetPasswords(c *gc.C) { 166 args := params.EntityPasswords{ 167 Changes: []params.EntityPassword{ 168 {Tag: s.machines[1].Tag().String(), Password: "xxx1"}, 169 }, 170 } 171 results, err := s.provisioner.SetPasswords(args) 172 c.Assert(err, jc.ErrorIsNil) 173 c.Assert(results.Results, gc.HasLen, 1) 174 c.Assert(results.Results[0].Error, gc.ErrorMatches, 175 "password is only 4 bytes long, and is not a valid Agent password") 176 } 177 178 func (s *withoutStateServerSuite) TestLifeAsMachineAgent(c *gc.C) { 179 // NOTE: This and the next call serve to test the two 180 // different authorization schemes: 181 // 1. Machine agents can access their own machine and 182 // any container that has their own machine as parent; 183 // 2. Environment managers can access any machine without 184 // a parent. 185 // There's no need to repeat this test for each method, 186 // because the authorization logic is common. 187 188 // Login as a machine agent for machine 0. 189 anAuthorizer := s.authorizer 190 anAuthorizer.EnvironManager = false 191 anAuthorizer.Tag = s.machines[0].Tag() 192 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 193 c.Assert(err, jc.ErrorIsNil) 194 c.Assert(aProvisioner, gc.NotNil) 195 196 // Make the machine dead before trying to add containers. 197 err = s.machines[0].EnsureDead() 198 c.Assert(err, jc.ErrorIsNil) 199 200 // Create some containers to work on. 201 template := state.MachineTemplate{ 202 Series: "quantal", 203 Jobs: []state.MachineJob{state.JobHostUnits}, 204 } 205 var containers []*state.Machine 206 for i := 0; i < 3; i++ { 207 container, err := s.State.AddMachineInsideMachine(template, s.machines[0].Id(), instance.LXC) 208 c.Check(err, jc.ErrorIsNil) 209 containers = append(containers, container) 210 } 211 // Make one container dead. 212 err = containers[1].EnsureDead() 213 c.Assert(err, jc.ErrorIsNil) 214 215 args := params.Entities{Entities: []params.Entity{ 216 {Tag: s.machines[0].Tag().String()}, 217 {Tag: s.machines[1].Tag().String()}, 218 {Tag: containers[0].Tag().String()}, 219 {Tag: containers[1].Tag().String()}, 220 {Tag: containers[2].Tag().String()}, 221 {Tag: "machine-42"}, 222 {Tag: "unit-foo-0"}, 223 {Tag: "service-bar"}, 224 }} 225 result, err := aProvisioner.Life(args) 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(result, gc.DeepEquals, params.LifeResults{ 228 Results: []params.LifeResult{ 229 {Life: "dead"}, 230 {Error: apiservertesting.ErrUnauthorized}, 231 {Life: "alive"}, 232 {Life: "dead"}, 233 {Life: "alive"}, 234 {Error: apiservertesting.ErrUnauthorized}, 235 {Error: apiservertesting.ErrUnauthorized}, 236 {Error: apiservertesting.ErrUnauthorized}, 237 }, 238 }) 239 } 240 241 func (s *withoutStateServerSuite) TestLifeAsEnvironManager(c *gc.C) { 242 err := s.machines[1].EnsureDead() 243 c.Assert(err, jc.ErrorIsNil) 244 err = s.machines[1].Refresh() 245 c.Assert(err, jc.ErrorIsNil) 246 c.Assert(s.machines[0].Life(), gc.Equals, state.Alive) 247 c.Assert(s.machines[1].Life(), gc.Equals, state.Dead) 248 c.Assert(s.machines[2].Life(), gc.Equals, state.Alive) 249 250 args := params.Entities{Entities: []params.Entity{ 251 {Tag: s.machines[0].Tag().String()}, 252 {Tag: s.machines[1].Tag().String()}, 253 {Tag: s.machines[2].Tag().String()}, 254 {Tag: "machine-42"}, 255 {Tag: "unit-foo-0"}, 256 {Tag: "service-bar"}, 257 }} 258 result, err := s.provisioner.Life(args) 259 c.Assert(err, jc.ErrorIsNil) 260 c.Assert(result, gc.DeepEquals, params.LifeResults{ 261 Results: []params.LifeResult{ 262 {Life: "alive"}, 263 {Life: "dead"}, 264 {Life: "alive"}, 265 {Error: apiservertesting.NotFoundError("machine 42")}, 266 {Error: apiservertesting.ErrUnauthorized}, 267 {Error: apiservertesting.ErrUnauthorized}, 268 }, 269 }) 270 271 // Remove the subordinate and make sure it's detected. 272 err = s.machines[1].Remove() 273 c.Assert(err, jc.ErrorIsNil) 274 err = s.machines[1].Refresh() 275 c.Assert(err, jc.Satisfies, errors.IsNotFound) 276 277 result, err = s.provisioner.Life(params.Entities{ 278 Entities: []params.Entity{ 279 {Tag: s.machines[1].Tag().String()}, 280 }, 281 }) 282 c.Assert(err, jc.ErrorIsNil) 283 c.Assert(result, gc.DeepEquals, params.LifeResults{ 284 Results: []params.LifeResult{ 285 {Error: apiservertesting.NotFoundError("machine 1")}, 286 }, 287 }) 288 } 289 290 func (s *withoutStateServerSuite) TestRemove(c *gc.C) { 291 err := s.machines[1].EnsureDead() 292 c.Assert(err, jc.ErrorIsNil) 293 s.assertLife(c, 0, state.Alive) 294 s.assertLife(c, 1, state.Dead) 295 s.assertLife(c, 2, state.Alive) 296 297 args := params.Entities{Entities: []params.Entity{ 298 {Tag: s.machines[0].Tag().String()}, 299 {Tag: s.machines[1].Tag().String()}, 300 {Tag: s.machines[2].Tag().String()}, 301 {Tag: "machine-42"}, 302 {Tag: "unit-foo-0"}, 303 {Tag: "service-bar"}, 304 }} 305 result, err := s.provisioner.Remove(args) 306 c.Assert(err, jc.ErrorIsNil) 307 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 308 Results: []params.ErrorResult{ 309 {¶ms.Error{Message: `cannot remove entity "machine-0": still alive`}}, 310 {nil}, 311 {¶ms.Error{Message: `cannot remove entity "machine-2": still alive`}}, 312 {apiservertesting.NotFoundError("machine 42")}, 313 {apiservertesting.ErrUnauthorized}, 314 {apiservertesting.ErrUnauthorized}, 315 }, 316 }) 317 318 // Verify the changes. 319 s.assertLife(c, 0, state.Alive) 320 err = s.machines[2].Refresh() 321 c.Assert(err, jc.ErrorIsNil) 322 s.assertLife(c, 2, state.Alive) 323 } 324 325 func (s *withoutStateServerSuite) TestSetStatus(c *gc.C) { 326 err := s.machines[0].SetStatus(state.StatusStarted, "blah", nil) 327 c.Assert(err, jc.ErrorIsNil) 328 err = s.machines[1].SetStatus(state.StatusStopped, "foo", nil) 329 c.Assert(err, jc.ErrorIsNil) 330 err = s.machines[2].SetStatus(state.StatusError, "not really", nil) 331 c.Assert(err, jc.ErrorIsNil) 332 333 args := params.SetStatus{ 334 Entities: []params.EntityStatus{ 335 {Tag: s.machines[0].Tag().String(), Status: params.StatusError, Info: "not really", 336 Data: map[string]interface{}{"foo": "bar"}}, 337 {Tag: s.machines[1].Tag().String(), Status: params.StatusStopped, Info: "foobar"}, 338 {Tag: s.machines[2].Tag().String(), Status: params.StatusStarted, Info: "again"}, 339 {Tag: "machine-42", Status: params.StatusStarted, Info: "blah"}, 340 {Tag: "unit-foo-0", Status: params.StatusStopped, Info: "foobar"}, 341 {Tag: "service-bar", Status: params.StatusStopped, Info: "foobar"}, 342 }} 343 result, err := s.provisioner.SetStatus(args) 344 c.Assert(err, jc.ErrorIsNil) 345 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 346 Results: []params.ErrorResult{ 347 {nil}, 348 {nil}, 349 {nil}, 350 {apiservertesting.NotFoundError("machine 42")}, 351 {apiservertesting.ErrUnauthorized}, 352 {apiservertesting.ErrUnauthorized}, 353 }, 354 }) 355 356 // Verify the changes. 357 s.assertStatus(c, 0, state.StatusError, "not really", map[string]interface{}{"foo": "bar"}) 358 s.assertStatus(c, 1, state.StatusStopped, "foobar", map[string]interface{}{}) 359 s.assertStatus(c, 2, state.StatusStarted, "again", map[string]interface{}{}) 360 } 361 362 func (s *withoutStateServerSuite) TestMachinesWithTransientErrors(c *gc.C) { 363 err := s.machines[0].SetStatus(state.StatusStarted, "blah", nil) 364 c.Assert(err, jc.ErrorIsNil) 365 err = s.machines[1].SetStatus(state.StatusError, "transient error", 366 map[string]interface{}{"transient": true, "foo": "bar"}) 367 c.Assert(err, jc.ErrorIsNil) 368 err = s.machines[2].SetStatus(state.StatusError, "error", map[string]interface{}{"transient": false}) 369 c.Assert(err, jc.ErrorIsNil) 370 err = s.machines[3].SetStatus(state.StatusError, "error", nil) 371 c.Assert(err, jc.ErrorIsNil) 372 // Machine 4 is provisioned but error not reset yet. 373 err = s.machines[4].SetStatus(state.StatusError, "transient error", 374 map[string]interface{}{"transient": true, "foo": "bar"}) 375 c.Assert(err, jc.ErrorIsNil) 376 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 377 err = s.machines[4].SetProvisioned("i-am", "fake_nonce", &hwChars) 378 c.Assert(err, jc.ErrorIsNil) 379 380 result, err := s.provisioner.MachinesWithTransientErrors() 381 c.Assert(err, jc.ErrorIsNil) 382 c.Assert(result, gc.DeepEquals, params.StatusResults{ 383 Results: []params.StatusResult{ 384 {Id: "1", Life: "alive", Status: "error", Info: "transient error", 385 Data: map[string]interface{}{"transient": true, "foo": "bar"}}, 386 }, 387 }) 388 } 389 390 func (s *withoutStateServerSuite) TestMachinesWithTransientErrorsPermission(c *gc.C) { 391 // Machines where there's permission issues are omitted. 392 anAuthorizer := s.authorizer 393 anAuthorizer.EnvironManager = false 394 anAuthorizer.Tag = names.NewMachineTag("1") 395 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, 396 anAuthorizer) 397 err = s.machines[0].SetStatus(state.StatusStarted, "blah", nil) 398 c.Assert(err, jc.ErrorIsNil) 399 err = s.machines[1].SetStatus(state.StatusError, "transient error", 400 map[string]interface{}{"transient": true, "foo": "bar"}) 401 c.Assert(err, jc.ErrorIsNil) 402 err = s.machines[2].SetStatus(state.StatusError, "error", map[string]interface{}{"transient": false}) 403 c.Assert(err, jc.ErrorIsNil) 404 err = s.machines[3].SetStatus(state.StatusError, "error", nil) 405 c.Assert(err, jc.ErrorIsNil) 406 407 result, err := aProvisioner.MachinesWithTransientErrors() 408 c.Assert(err, jc.ErrorIsNil) 409 c.Assert(result, gc.DeepEquals, params.StatusResults{ 410 Results: []params.StatusResult{ 411 {Id: "1", Life: "alive", Status: "error", Info: "transient error", 412 Data: map[string]interface{}{"transient": true, "foo": "bar"}}, 413 }, 414 }) 415 } 416 417 func (s *withoutStateServerSuite) TestEnsureDead(c *gc.C) { 418 err := s.machines[1].EnsureDead() 419 c.Assert(err, jc.ErrorIsNil) 420 s.assertLife(c, 0, state.Alive) 421 s.assertLife(c, 1, state.Dead) 422 s.assertLife(c, 2, state.Alive) 423 424 args := params.Entities{Entities: []params.Entity{ 425 {Tag: s.machines[0].Tag().String()}, 426 {Tag: s.machines[1].Tag().String()}, 427 {Tag: s.machines[2].Tag().String()}, 428 {Tag: "machine-42"}, 429 {Tag: "unit-foo-0"}, 430 {Tag: "service-bar"}, 431 }} 432 result, err := s.provisioner.EnsureDead(args) 433 c.Assert(err, jc.ErrorIsNil) 434 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 435 Results: []params.ErrorResult{ 436 {nil}, 437 {nil}, 438 {nil}, 439 {apiservertesting.NotFoundError("machine 42")}, 440 {apiservertesting.ErrUnauthorized}, 441 {apiservertesting.ErrUnauthorized}, 442 }, 443 }) 444 445 // Verify the changes. 446 s.assertLife(c, 0, state.Dead) 447 s.assertLife(c, 1, state.Dead) 448 s.assertLife(c, 2, state.Dead) 449 } 450 451 func (s *withoutStateServerSuite) assertLife(c *gc.C, index int, expectLife state.Life) { 452 err := s.machines[index].Refresh() 453 c.Assert(err, jc.ErrorIsNil) 454 c.Assert(s.machines[index].Life(), gc.Equals, expectLife) 455 } 456 457 func (s *withoutStateServerSuite) assertStatus(c *gc.C, index int, expectStatus state.Status, expectInfo string, 458 expectData map[string]interface{}) { 459 460 statusInfo, err := s.machines[index].Status() 461 c.Assert(err, jc.ErrorIsNil) 462 c.Assert(statusInfo.Status, gc.Equals, expectStatus) 463 c.Assert(statusInfo.Message, gc.Equals, expectInfo) 464 c.Assert(statusInfo.Data, gc.DeepEquals, expectData) 465 } 466 467 func (s *withoutStateServerSuite) TestWatchContainers(c *gc.C) { 468 c.Assert(s.resources.Count(), gc.Equals, 0) 469 470 args := params.WatchContainers{Params: []params.WatchContainer{ 471 {MachineTag: s.machines[0].Tag().String(), ContainerType: string(instance.LXC)}, 472 {MachineTag: s.machines[1].Tag().String(), ContainerType: string(instance.KVM)}, 473 {MachineTag: "machine-42", ContainerType: ""}, 474 {MachineTag: "unit-foo-0", ContainerType: ""}, 475 {MachineTag: "service-bar", ContainerType: ""}, 476 }} 477 result, err := s.provisioner.WatchContainers(args) 478 c.Assert(err, jc.ErrorIsNil) 479 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 480 Results: []params.StringsWatchResult{ 481 {StringsWatcherId: "1", Changes: []string{}}, 482 {StringsWatcherId: "2", Changes: []string{}}, 483 {Error: apiservertesting.NotFoundError("machine 42")}, 484 {Error: apiservertesting.ErrUnauthorized}, 485 {Error: apiservertesting.ErrUnauthorized}, 486 }, 487 }) 488 489 // Verify the resources were registered and stop them when done. 490 c.Assert(s.resources.Count(), gc.Equals, 2) 491 m0Watcher := s.resources.Get("1") 492 defer statetesting.AssertStop(c, m0Watcher) 493 m1Watcher := s.resources.Get("2") 494 defer statetesting.AssertStop(c, m1Watcher) 495 496 // Check that the Watch has consumed the initial event ("returned" 497 // in the Watch call) 498 wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher)) 499 wc0.AssertNoChange() 500 wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher)) 501 wc1.AssertNoChange() 502 } 503 504 func (s *withoutStateServerSuite) TestWatchAllContainers(c *gc.C) { 505 c.Assert(s.resources.Count(), gc.Equals, 0) 506 507 args := params.WatchContainers{Params: []params.WatchContainer{ 508 {MachineTag: s.machines[0].Tag().String()}, 509 {MachineTag: s.machines[1].Tag().String()}, 510 {MachineTag: "machine-42"}, 511 {MachineTag: "unit-foo-0"}, 512 {MachineTag: "service-bar"}, 513 }} 514 result, err := s.provisioner.WatchAllContainers(args) 515 c.Assert(err, jc.ErrorIsNil) 516 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 517 Results: []params.StringsWatchResult{ 518 {StringsWatcherId: "1", Changes: []string{}}, 519 {StringsWatcherId: "2", Changes: []string{}}, 520 {Error: apiservertesting.NotFoundError("machine 42")}, 521 {Error: apiservertesting.ErrUnauthorized}, 522 {Error: apiservertesting.ErrUnauthorized}, 523 }, 524 }) 525 526 // Verify the resources were registered and stop them when done. 527 c.Assert(s.resources.Count(), gc.Equals, 2) 528 m0Watcher := s.resources.Get("1") 529 defer statetesting.AssertStop(c, m0Watcher) 530 m1Watcher := s.resources.Get("2") 531 defer statetesting.AssertStop(c, m1Watcher) 532 533 // Check that the Watch has consumed the initial event ("returned" 534 // in the Watch call) 535 wc0 := statetesting.NewStringsWatcherC(c, s.State, m0Watcher.(state.StringsWatcher)) 536 wc0.AssertNoChange() 537 wc1 := statetesting.NewStringsWatcherC(c, s.State, m1Watcher.(state.StringsWatcher)) 538 wc1.AssertNoChange() 539 } 540 541 func (s *withoutStateServerSuite) TestEnvironConfigNonManager(c *gc.C) { 542 // Now test it with a non-environment manager and make sure 543 // the secret attributes are masked. 544 anAuthorizer := s.authorizer 545 anAuthorizer.Tag = names.NewMachineTag("1") 546 anAuthorizer.EnvironManager = false 547 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, 548 anAuthorizer) 549 c.Assert(err, jc.ErrorIsNil) 550 s.AssertEnvironConfig(c, aProvisioner, commontesting.NoSecrets) 551 } 552 553 func (s *withoutStateServerSuite) TestStatus(c *gc.C) { 554 err := s.machines[0].SetStatus(state.StatusStarted, "blah", nil) 555 c.Assert(err, jc.ErrorIsNil) 556 err = s.machines[1].SetStatus(state.StatusStopped, "foo", nil) 557 c.Assert(err, jc.ErrorIsNil) 558 err = s.machines[2].SetStatus(state.StatusError, "not really", map[string]interface{}{"foo": "bar"}) 559 c.Assert(err, jc.ErrorIsNil) 560 561 args := params.Entities{Entities: []params.Entity{ 562 {Tag: s.machines[0].Tag().String()}, 563 {Tag: s.machines[1].Tag().String()}, 564 {Tag: s.machines[2].Tag().String()}, 565 {Tag: "machine-42"}, 566 {Tag: "unit-foo-0"}, 567 {Tag: "service-bar"}, 568 }} 569 result, err := s.provisioner.Status(args) 570 c.Assert(err, jc.ErrorIsNil) 571 // Zero out the updated timestamps so we can easily check the results. 572 for i, statusResult := range result.Results { 573 r := statusResult 574 if r.Status != "" { 575 c.Assert(r.Since, gc.NotNil) 576 } 577 r.Since = nil 578 result.Results[i] = r 579 } 580 c.Assert(result, gc.DeepEquals, params.StatusResults{ 581 Results: []params.StatusResult{ 582 {Status: params.StatusStarted, Info: "blah", Data: map[string]interface{}{}}, 583 {Status: params.StatusStopped, Info: "foo", Data: map[string]interface{}{}}, 584 {Status: params.StatusError, Info: "not really", Data: map[string]interface{}{"foo": "bar"}}, 585 {Error: apiservertesting.NotFoundError("machine 42")}, 586 {Error: apiservertesting.ErrUnauthorized}, 587 {Error: apiservertesting.ErrUnauthorized}, 588 }, 589 }) 590 } 591 592 func (s *withoutStateServerSuite) TestSeries(c *gc.C) { 593 // Add a machine with different series. 594 foobarMachine, err := s.State.AddMachine("foobar", state.JobHostUnits) 595 c.Assert(err, jc.ErrorIsNil) 596 597 args := params.Entities{Entities: []params.Entity{ 598 {Tag: s.machines[0].Tag().String()}, 599 {Tag: foobarMachine.Tag().String()}, 600 {Tag: s.machines[2].Tag().String()}, 601 {Tag: "machine-42"}, 602 {Tag: "unit-foo-0"}, 603 {Tag: "service-bar"}, 604 }} 605 result, err := s.provisioner.Series(args) 606 c.Assert(err, jc.ErrorIsNil) 607 c.Assert(result, gc.DeepEquals, params.StringResults{ 608 Results: []params.StringResult{ 609 {Result: s.machines[0].Series()}, 610 {Result: foobarMachine.Series()}, 611 {Result: s.machines[2].Series()}, 612 {Error: apiservertesting.NotFoundError("machine 42")}, 613 {Error: apiservertesting.ErrUnauthorized}, 614 {Error: apiservertesting.ErrUnauthorized}, 615 }, 616 }) 617 } 618 619 func (s *withoutStateServerSuite) TestDistributionGroup(c *gc.C) { 620 addUnits := func(name string, machines ...*state.Machine) (units []*state.Unit) { 621 svc := s.AddTestingService(c, name, s.AddTestingCharm(c, name)) 622 for _, m := range machines { 623 unit, err := svc.AddUnit() 624 c.Assert(err, jc.ErrorIsNil) 625 err = unit.AssignToMachine(m) 626 c.Assert(err, jc.ErrorIsNil) 627 units = append(units, unit) 628 } 629 return units 630 } 631 setProvisioned := func(id string) { 632 m, err := s.State.Machine(id) 633 c.Assert(err, jc.ErrorIsNil) 634 err = m.SetProvisioned(instance.Id("machine-"+id+"-inst"), "nonce", nil) 635 c.Assert(err, jc.ErrorIsNil) 636 } 637 638 mysqlUnit := addUnits("mysql", s.machines[0], s.machines[3])[0] 639 wordpressUnits := addUnits("wordpress", s.machines[0], s.machines[1], s.machines[2]) 640 641 // Unassign wordpress/1 from machine-1. 642 // The unit should not show up in the results. 643 err := wordpressUnits[1].UnassignFromMachine() 644 c.Assert(err, jc.ErrorIsNil) 645 646 // Provision machines 1, 2 and 3. Machine-0 remains 647 // unprovisioned, and machine-1 has no units, and so 648 // neither will show up in the results. 649 setProvisioned("1") 650 setProvisioned("2") 651 setProvisioned("3") 652 653 // Add a few state servers, provision two of them. 654 _, err = s.State.EnsureAvailability(3, constraints.Value{}, "quantal", nil) 655 c.Assert(err, jc.ErrorIsNil) 656 setProvisioned("5") 657 setProvisioned("7") 658 659 // Create a logging service, subordinate to mysql. 660 s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 661 eps, err := s.State.InferEndpoints("mysql", "logging") 662 c.Assert(err, jc.ErrorIsNil) 663 rel, err := s.State.AddRelation(eps...) 664 c.Assert(err, jc.ErrorIsNil) 665 ru, err := rel.Unit(mysqlUnit) 666 c.Assert(err, jc.ErrorIsNil) 667 err = ru.EnterScope(nil) 668 c.Assert(err, jc.ErrorIsNil) 669 670 args := params.Entities{Entities: []params.Entity{ 671 {Tag: s.machines[0].Tag().String()}, 672 {Tag: s.machines[1].Tag().String()}, 673 {Tag: s.machines[2].Tag().String()}, 674 {Tag: s.machines[3].Tag().String()}, 675 {Tag: "machine-5"}, 676 }} 677 result, err := s.provisioner.DistributionGroup(args) 678 c.Assert(err, jc.ErrorIsNil) 679 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 680 Results: []params.DistributionGroupResult{ 681 {Result: []instance.Id{"machine-2-inst", "machine-3-inst"}}, 682 {Result: []instance.Id{}}, 683 {Result: []instance.Id{"machine-2-inst"}}, 684 {Result: []instance.Id{"machine-3-inst"}}, 685 {Result: []instance.Id{"machine-5-inst", "machine-7-inst"}}, 686 }, 687 }) 688 } 689 690 func (s *withoutStateServerSuite) TestDistributionGroupEnvironManagerAuth(c *gc.C) { 691 args := params.Entities{Entities: []params.Entity{ 692 {Tag: "machine-0"}, 693 {Tag: "machine-42"}, 694 {Tag: "machine-0-lxc-99"}, 695 {Tag: "unit-foo-0"}, 696 {Tag: "service-bar"}, 697 }} 698 result, err := s.provisioner.DistributionGroup(args) 699 c.Assert(err, jc.ErrorIsNil) 700 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 701 Results: []params.DistributionGroupResult{ 702 // environ manager may access any top-level machines. 703 {Result: []instance.Id{}}, 704 {Error: apiservertesting.NotFoundError("machine 42")}, 705 // only a machine agent for the container or its 706 // parent may access it. 707 {Error: apiservertesting.ErrUnauthorized}, 708 // non-machines always unauthorized 709 {Error: apiservertesting.ErrUnauthorized}, 710 {Error: apiservertesting.ErrUnauthorized}, 711 }, 712 }) 713 } 714 715 func (s *withoutStateServerSuite) TestDistributionGroupMachineAgentAuth(c *gc.C) { 716 anAuthorizer := s.authorizer 717 anAuthorizer.Tag = names.NewMachineTag("1") 718 anAuthorizer.EnvironManager = false 719 provisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 720 c.Check(err, jc.ErrorIsNil) 721 args := params.Entities{Entities: []params.Entity{ 722 {Tag: "machine-0"}, 723 {Tag: "machine-1"}, 724 {Tag: "machine-42"}, 725 {Tag: "machine-0-lxc-99"}, 726 {Tag: "machine-1-lxc-99"}, 727 {Tag: "machine-1-lxc-99-lxc-100"}, 728 }} 729 result, err := provisioner.DistributionGroup(args) 730 c.Assert(err, jc.ErrorIsNil) 731 c.Assert(result, gc.DeepEquals, params.DistributionGroupResults{ 732 Results: []params.DistributionGroupResult{ 733 {Error: apiservertesting.ErrUnauthorized}, 734 {Result: []instance.Id{}}, 735 {Error: apiservertesting.ErrUnauthorized}, 736 // only a machine agent for the container or its 737 // parent may access it. 738 {Error: apiservertesting.ErrUnauthorized}, 739 {Error: apiservertesting.NotFoundError("machine 1/lxc/99")}, 740 {Error: apiservertesting.ErrUnauthorized}, 741 }, 742 }) 743 } 744 745 func (s *withoutStateServerSuite) TestProvisioningInfo(c *gc.C) { 746 registry.RegisterProvider("static", &storagedummy.StorageProvider{IsDynamic: false}) 747 defer registry.RegisterProvider("static", nil) 748 registry.RegisterEnvironStorageProviders("dummy", "static") 749 750 pm := poolmanager.New(state.NewStateSettings(s.State)) 751 _, err := pm.Create("static-pool", "static", map[string]interface{}{"foo": "bar"}) 752 c.Assert(err, jc.ErrorIsNil) 753 754 cons := constraints.MustParse("cpu-cores=123 mem=8G networks=^net3,^net4") 755 template := state.MachineTemplate{ 756 Series: "quantal", 757 Jobs: []state.MachineJob{state.JobHostUnits}, 758 Constraints: cons, 759 Placement: "valid", 760 RequestedNetworks: []string{"net1", "net2"}, 761 Volumes: []state.MachineVolumeParams{ 762 {Volume: state.VolumeParams{Size: 1000, Pool: "static-pool"}}, 763 {Volume: state.VolumeParams{Size: 2000, Pool: "static-pool"}}, 764 }, 765 } 766 placementMachine, err := s.State.AddOneMachine(template) 767 c.Assert(err, jc.ErrorIsNil) 768 769 args := params.Entities{Entities: []params.Entity{ 770 {Tag: s.machines[0].Tag().String()}, 771 {Tag: placementMachine.Tag().String()}, 772 {Tag: "machine-42"}, 773 {Tag: "unit-foo-0"}, 774 {Tag: "service-bar"}, 775 }} 776 result, err := s.provisioner.ProvisioningInfo(args) 777 c.Assert(err, jc.ErrorIsNil) 778 779 expected := params.ProvisioningInfoResults{ 780 Results: []params.ProvisioningInfoResult{ 781 {Result: ¶ms.ProvisioningInfo{ 782 Series: "quantal", 783 Networks: []string{}, 784 Jobs: []multiwatcher.MachineJob{multiwatcher.JobHostUnits}, 785 Tags: map[string]string{ 786 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 787 }, 788 }}, 789 {Result: ¶ms.ProvisioningInfo{ 790 Series: "quantal", 791 Constraints: template.Constraints, 792 Placement: template.Placement, 793 Networks: template.RequestedNetworks, 794 Jobs: []multiwatcher.MachineJob{multiwatcher.JobHostUnits}, 795 Tags: map[string]string{ 796 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 797 }, 798 Volumes: []params.VolumeParams{{ 799 VolumeTag: "volume-0", 800 Size: 1000, 801 Provider: "static", 802 Attributes: map[string]interface{}{"foo": "bar"}, 803 Tags: map[string]string{ 804 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 805 }, 806 Attachment: ¶ms.VolumeAttachmentParams{ 807 MachineTag: placementMachine.Tag().String(), 808 VolumeTag: "volume-0", 809 Provider: "static", 810 }, 811 }, { 812 VolumeTag: "volume-1", 813 Size: 2000, 814 Provider: "static", 815 Attributes: map[string]interface{}{"foo": "bar"}, 816 Tags: map[string]string{ 817 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 818 }, 819 Attachment: ¶ms.VolumeAttachmentParams{ 820 MachineTag: placementMachine.Tag().String(), 821 VolumeTag: "volume-1", 822 Provider: "static", 823 }, 824 }}, 825 }}, 826 {Error: apiservertesting.NotFoundError("machine 42")}, 827 {Error: apiservertesting.ErrUnauthorized}, 828 {Error: apiservertesting.ErrUnauthorized}, 829 }, 830 } 831 // The order of volumes is not predictable, so we make sure we compare the right ones. This only 832 // applies to Results[1] since it is the only result to contain volumes. 833 if expected.Results[1].Result.Volumes[0].VolumeTag != result.Results[1].Result.Volumes[0].VolumeTag { 834 vols := expected.Results[1].Result.Volumes 835 vols[0], vols[1] = vols[1], vols[0] 836 } 837 c.Assert(result, jc.DeepEquals, expected) 838 } 839 840 func (s *withoutStateServerSuite) TestStorageProviderFallbackToType(c *gc.C) { 841 registry.RegisterProvider("dynamic", &storagedummy.StorageProvider{IsDynamic: true}) 842 defer registry.RegisterProvider("dynamic", nil) 843 registry.RegisterProvider("static", &storagedummy.StorageProvider{IsDynamic: false}) 844 defer registry.RegisterProvider("static", nil) 845 registry.RegisterEnvironStorageProviders("dummy", "dynamic", "static") 846 847 template := state.MachineTemplate{ 848 Series: "quantal", 849 Jobs: []state.MachineJob{state.JobHostUnits}, 850 Placement: "valid", 851 RequestedNetworks: []string{"net1", "net2"}, 852 Volumes: []state.MachineVolumeParams{ 853 {Volume: state.VolumeParams{Size: 1000, Pool: "dynamic"}}, 854 {Volume: state.VolumeParams{Size: 1000, Pool: "static"}}, 855 }, 856 } 857 placementMachine, err := s.State.AddOneMachine(template) 858 c.Assert(err, jc.ErrorIsNil) 859 860 args := params.Entities{Entities: []params.Entity{ 861 {Tag: placementMachine.Tag().String()}, 862 }} 863 result, err := s.provisioner.ProvisioningInfo(args) 864 c.Assert(err, jc.ErrorIsNil) 865 866 c.Assert(result, jc.DeepEquals, params.ProvisioningInfoResults{ 867 Results: []params.ProvisioningInfoResult{ 868 {Result: ¶ms.ProvisioningInfo{ 869 Series: "quantal", 870 Constraints: template.Constraints, 871 Placement: template.Placement, 872 Networks: template.RequestedNetworks, 873 Jobs: []multiwatcher.MachineJob{multiwatcher.JobHostUnits}, 874 Tags: map[string]string{ 875 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 876 }, 877 Volumes: []params.VolumeParams{{ 878 VolumeTag: "volume-1", 879 Size: 1000, 880 Provider: "static", 881 Attributes: nil, 882 Tags: map[string]string{ 883 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 884 }, 885 Attachment: ¶ms.VolumeAttachmentParams{ 886 MachineTag: placementMachine.Tag().String(), 887 VolumeTag: "volume-1", 888 Provider: "static", 889 }, 890 }}, 891 }}, 892 }, 893 }) 894 } 895 896 func (s *withoutStateServerSuite) TestProvisioningInfoPermissions(c *gc.C) { 897 // Login as a machine agent for machine 0. 898 anAuthorizer := s.authorizer 899 anAuthorizer.EnvironManager = false 900 anAuthorizer.Tag = s.machines[0].Tag() 901 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 902 c.Assert(err, jc.ErrorIsNil) 903 c.Assert(aProvisioner, gc.NotNil) 904 905 args := params.Entities{Entities: []params.Entity{ 906 {Tag: s.machines[0].Tag().String()}, 907 {Tag: s.machines[0].Tag().String() + "-lxc-0"}, 908 {Tag: "machine-42"}, 909 {Tag: s.machines[1].Tag().String()}, 910 {Tag: "service-bar"}, 911 }} 912 913 // Only machine 0 and containers therein can be accessed. 914 results, err := aProvisioner.ProvisioningInfo(args) 915 c.Assert(results, jc.DeepEquals, params.ProvisioningInfoResults{ 916 Results: []params.ProvisioningInfoResult{ 917 {Result: ¶ms.ProvisioningInfo{ 918 Series: "quantal", 919 Networks: []string{}, 920 Jobs: []multiwatcher.MachineJob{multiwatcher.JobHostUnits}, 921 Tags: map[string]string{ 922 tags.JujuEnv: coretesting.EnvironmentTag.Id(), 923 }, 924 }}, 925 {Error: apiservertesting.NotFoundError("machine 0/lxc/0")}, 926 {Error: apiservertesting.ErrUnauthorized}, 927 {Error: apiservertesting.ErrUnauthorized}, 928 {Error: apiservertesting.ErrUnauthorized}, 929 }, 930 }) 931 } 932 933 func (s *withoutStateServerSuite) TestConstraints(c *gc.C) { 934 // Add a machine with some constraints. 935 cons := constraints.MustParse("cpu-cores=123", "mem=8G", "networks=net3,^net4") 936 template := state.MachineTemplate{ 937 Series: "quantal", 938 Jobs: []state.MachineJob{state.JobHostUnits}, 939 Constraints: cons, 940 } 941 consMachine, err := s.State.AddOneMachine(template) 942 c.Assert(err, jc.ErrorIsNil) 943 944 machine0Constraints, err := s.machines[0].Constraints() 945 c.Assert(err, jc.ErrorIsNil) 946 947 args := params.Entities{Entities: []params.Entity{ 948 {Tag: s.machines[0].Tag().String()}, 949 {Tag: consMachine.Tag().String()}, 950 {Tag: "machine-42"}, 951 {Tag: "unit-foo-0"}, 952 {Tag: "service-bar"}, 953 }} 954 result, err := s.provisioner.Constraints(args) 955 c.Assert(err, jc.ErrorIsNil) 956 c.Assert(result, gc.DeepEquals, params.ConstraintsResults{ 957 Results: []params.ConstraintsResult{ 958 {Constraints: machine0Constraints}, 959 {Constraints: template.Constraints}, 960 {Error: apiservertesting.NotFoundError("machine 42")}, 961 {Error: apiservertesting.ErrUnauthorized}, 962 {Error: apiservertesting.ErrUnauthorized}, 963 }, 964 }) 965 } 966 967 func (s *withoutStateServerSuite) TestRequestedNetworks(c *gc.C) { 968 // Add a machine with some requested networks. 969 template := state.MachineTemplate{ 970 Series: "quantal", 971 Jobs: []state.MachineJob{state.JobHostUnits}, 972 RequestedNetworks: []string{"net1", "net2"}, 973 } 974 netsMachine, err := s.State.AddOneMachine(template) 975 c.Assert(err, jc.ErrorIsNil) 976 977 networksMachine0, err := s.machines[0].RequestedNetworks() 978 c.Assert(err, jc.ErrorIsNil) 979 980 args := params.Entities{Entities: []params.Entity{ 981 {Tag: s.machines[0].Tag().String()}, 982 {Tag: netsMachine.Tag().String()}, 983 {Tag: "machine-42"}, 984 {Tag: "unit-foo-0"}, 985 {Tag: "service-bar"}, 986 }} 987 result, err := s.provisioner.RequestedNetworks(args) 988 c.Assert(err, jc.ErrorIsNil) 989 c.Assert(result, gc.DeepEquals, params.RequestedNetworksResults{ 990 Results: []params.RequestedNetworkResult{ 991 { 992 Networks: networksMachine0, 993 }, 994 { 995 Networks: template.RequestedNetworks, 996 }, 997 {Error: apiservertesting.NotFoundError("machine 42")}, 998 {Error: apiservertesting.ErrUnauthorized}, 999 {Error: apiservertesting.ErrUnauthorized}, 1000 }, 1001 }) 1002 } 1003 1004 func (s *withoutStateServerSuite) TestSetProvisioned(c *gc.C) { 1005 // Provision machine 0 first. 1006 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 1007 err := s.machines[0].SetProvisioned("i-am", "fake_nonce", &hwChars) 1008 c.Assert(err, jc.ErrorIsNil) 1009 1010 args := params.SetProvisioned{Machines: []params.MachineSetProvisioned{ 1011 {Tag: s.machines[0].Tag().String(), InstanceId: "i-was", Nonce: "fake_nonce", Characteristics: nil}, 1012 {Tag: s.machines[1].Tag().String(), InstanceId: "i-will", Nonce: "fake_nonce", Characteristics: &hwChars}, 1013 {Tag: s.machines[2].Tag().String(), InstanceId: "i-am-too", Nonce: "fake", Characteristics: nil}, 1014 {Tag: "machine-42", InstanceId: "", Nonce: "", Characteristics: nil}, 1015 {Tag: "unit-foo-0", InstanceId: "", Nonce: "", Characteristics: nil}, 1016 {Tag: "service-bar", InstanceId: "", Nonce: "", Characteristics: nil}, 1017 }} 1018 result, err := s.provisioner.SetProvisioned(args) 1019 c.Assert(err, jc.ErrorIsNil) 1020 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1021 Results: []params.ErrorResult{ 1022 {¶ms.Error{ 1023 Message: `cannot set instance data for machine "0": already set`, 1024 }}, 1025 {nil}, 1026 {nil}, 1027 {apiservertesting.NotFoundError("machine 42")}, 1028 {apiservertesting.ErrUnauthorized}, 1029 {apiservertesting.ErrUnauthorized}, 1030 }, 1031 }) 1032 1033 // Verify machine 1 and 2 were provisioned. 1034 c.Assert(s.machines[1].Refresh(), gc.IsNil) 1035 c.Assert(s.machines[2].Refresh(), gc.IsNil) 1036 1037 instanceId, err := s.machines[1].InstanceId() 1038 c.Assert(err, jc.ErrorIsNil) 1039 c.Check(instanceId, gc.Equals, instance.Id("i-will")) 1040 instanceId, err = s.machines[2].InstanceId() 1041 c.Assert(err, jc.ErrorIsNil) 1042 c.Check(instanceId, gc.Equals, instance.Id("i-am-too")) 1043 c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue) 1044 c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue) 1045 gotHardware, err := s.machines[1].HardwareCharacteristics() 1046 c.Assert(err, jc.ErrorIsNil) 1047 c.Check(gotHardware, gc.DeepEquals, &hwChars) 1048 } 1049 1050 func (s *withoutStateServerSuite) TestSetInstanceInfo(c *gc.C) { 1051 registry.RegisterProvider("static", &storagedummy.StorageProvider{IsDynamic: false}) 1052 defer registry.RegisterProvider("static", nil) 1053 registry.RegisterEnvironStorageProviders("dummy", "static") 1054 1055 pm := poolmanager.New(state.NewStateSettings(s.State)) 1056 _, err := pm.Create("static-pool", "static", map[string]interface{}{"foo": "bar"}) 1057 c.Assert(err, jc.ErrorIsNil) 1058 err = s.State.UpdateEnvironConfig(map[string]interface{}{ 1059 "storage-default-block-source": "static-pool", 1060 }, nil, nil) 1061 c.Assert(err, jc.ErrorIsNil) 1062 1063 // Provision machine 0 first. 1064 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 1065 err = s.machines[0].SetInstanceInfo("i-am", "fake_nonce", &hwChars, nil, nil, nil, nil) 1066 c.Assert(err, jc.ErrorIsNil) 1067 1068 volumesMachine, err := s.State.AddOneMachine(state.MachineTemplate{ 1069 Series: "quantal", 1070 Jobs: []state.MachineJob{state.JobHostUnits}, 1071 Volumes: []state.MachineVolumeParams{{ 1072 Volume: state.VolumeParams{Size: 1000}, 1073 }}, 1074 }) 1075 c.Assert(err, jc.ErrorIsNil) 1076 1077 networks := []params.Network{{ 1078 Tag: "network-net1", 1079 ProviderId: "net1", 1080 CIDR: "0.1.2.0/24", 1081 VLANTag: 0, 1082 }, { 1083 Tag: "network-vlan42", 1084 ProviderId: "vlan42", 1085 CIDR: "0.2.2.0/24", 1086 VLANTag: 42, 1087 }, { 1088 Tag: "network-vlan69", 1089 ProviderId: "vlan69", 1090 CIDR: "0.3.2.0/24", 1091 VLANTag: 69, 1092 }, { 1093 Tag: "network-vlan42", // duplicated; ignored 1094 ProviderId: "vlan42", 1095 CIDR: "0.2.2.0/24", 1096 VLANTag: 42, 1097 }} 1098 ifaces := []params.NetworkInterface{{ 1099 MACAddress: "aa:bb:cc:dd:ee:f0", 1100 NetworkTag: "network-net1", 1101 InterfaceName: "eth0", 1102 IsVirtual: false, 1103 }, { 1104 MACAddress: "aa:bb:cc:dd:ee:f1", 1105 NetworkTag: "network-net1", 1106 InterfaceName: "eth1", 1107 IsVirtual: false, 1108 }, { 1109 MACAddress: "aa:bb:cc:dd:ee:f1", 1110 NetworkTag: "network-vlan42", 1111 InterfaceName: "eth1.42", 1112 IsVirtual: true, 1113 }, { 1114 MACAddress: "aa:bb:cc:dd:ee:f0", 1115 NetworkTag: "network-vlan69", 1116 InterfaceName: "eth0.69", 1117 IsVirtual: true, 1118 Disabled: true, 1119 }, { 1120 MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored 1121 NetworkTag: "network-vlan42", 1122 InterfaceName: "eth2", 1123 IsVirtual: true, 1124 }, { 1125 MACAddress: "aa:bb:cc:dd:ee:f2", 1126 NetworkTag: "network-net1", 1127 InterfaceName: "eth1", // duplicated name+machine id; ignored for machine 1. 1128 IsVirtual: false, 1129 }} 1130 args := params.InstancesInfo{Machines: []params.InstanceInfo{{ 1131 Tag: s.machines[0].Tag().String(), 1132 InstanceId: "i-was", 1133 Nonce: "fake_nonce", 1134 }, { 1135 Tag: s.machines[1].Tag().String(), 1136 InstanceId: "i-will", 1137 Nonce: "fake_nonce", 1138 Characteristics: &hwChars, 1139 Networks: networks, 1140 Interfaces: ifaces, 1141 }, { 1142 Tag: s.machines[2].Tag().String(), 1143 InstanceId: "i-am-too", 1144 Nonce: "fake", 1145 Characteristics: nil, 1146 Networks: networks, 1147 Interfaces: ifaces, 1148 }, { 1149 Tag: volumesMachine.Tag().String(), 1150 InstanceId: "i-am-also", 1151 Nonce: "fake", 1152 Volumes: []params.Volume{{ 1153 VolumeTag: "volume-0", 1154 Info: params.VolumeInfo{ 1155 VolumeId: "vol-0", 1156 Size: 1234, 1157 }, 1158 }}, 1159 VolumeAttachments: map[string]params.VolumeAttachmentInfo{ 1160 "volume-0": { 1161 DeviceName: "sda", 1162 }, 1163 }, 1164 }, 1165 {Tag: "machine-42"}, 1166 {Tag: "unit-foo-0"}, 1167 {Tag: "service-bar"}, 1168 }} 1169 result, err := s.provisioner.SetInstanceInfo(args) 1170 c.Assert(err, jc.ErrorIsNil) 1171 c.Assert(result, jc.DeepEquals, params.ErrorResults{ 1172 Results: []params.ErrorResult{ 1173 {¶ms.Error{ 1174 Message: `cannot record provisioning info for "i-was": cannot set instance data for machine "0": already set`, 1175 }}, 1176 {nil}, 1177 {nil}, 1178 {nil}, 1179 {apiservertesting.NotFoundError("machine 42")}, 1180 {apiservertesting.ErrUnauthorized}, 1181 {apiservertesting.ErrUnauthorized}, 1182 }, 1183 }) 1184 1185 // Verify machine 1 and 2 were provisioned. 1186 c.Assert(s.machines[1].Refresh(), gc.IsNil) 1187 c.Assert(s.machines[2].Refresh(), gc.IsNil) 1188 1189 instanceId, err := s.machines[1].InstanceId() 1190 c.Assert(err, jc.ErrorIsNil) 1191 c.Check(instanceId, gc.Equals, instance.Id("i-will")) 1192 instanceId, err = s.machines[2].InstanceId() 1193 c.Assert(err, jc.ErrorIsNil) 1194 c.Check(instanceId, gc.Equals, instance.Id("i-am-too")) 1195 c.Check(s.machines[1].CheckProvisioned("fake_nonce"), jc.IsTrue) 1196 c.Check(s.machines[2].CheckProvisioned("fake"), jc.IsTrue) 1197 gotHardware, err := s.machines[1].HardwareCharacteristics() 1198 c.Assert(err, jc.ErrorIsNil) 1199 c.Check(gotHardware, gc.DeepEquals, &hwChars) 1200 ifacesMachine1, err := s.machines[1].NetworkInterfaces() 1201 c.Assert(err, jc.ErrorIsNil) 1202 c.Assert(ifacesMachine1, gc.HasLen, 4) 1203 actual := make([]params.NetworkInterface, len(ifacesMachine1)) 1204 for i, iface := range ifacesMachine1 { 1205 actual[i].InterfaceName = iface.InterfaceName() 1206 actual[i].NetworkTag = iface.NetworkTag().String() 1207 actual[i].MACAddress = iface.MACAddress() 1208 actual[i].IsVirtual = iface.IsVirtual() 1209 actual[i].Disabled = iface.IsDisabled() 1210 c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id()) 1211 c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag()) 1212 } 1213 c.Assert(actual, jc.SameContents, ifaces[:4]) 1214 ifacesMachine2, err := s.machines[2].NetworkInterfaces() 1215 c.Assert(err, jc.ErrorIsNil) 1216 c.Assert(ifacesMachine2, gc.HasLen, 1) 1217 c.Assert(ifacesMachine2[0].InterfaceName(), gc.Equals, ifaces[5].InterfaceName) 1218 c.Assert(ifacesMachine2[0].MACAddress(), gc.Equals, ifaces[5].MACAddress) 1219 c.Assert(ifacesMachine2[0].NetworkTag().String(), gc.Equals, ifaces[5].NetworkTag) 1220 c.Assert(ifacesMachine2[0].MachineId(), gc.Equals, s.machines[2].Id()) 1221 for i := range networks { 1222 if i == 3 { 1223 // Last one was ignored, so don't check. 1224 break 1225 } 1226 tag, err := names.ParseNetworkTag(networks[i].Tag) 1227 c.Assert(err, jc.ErrorIsNil) 1228 networkName := tag.Id() 1229 nw, err := s.State.Network(networkName) 1230 c.Assert(err, jc.ErrorIsNil) 1231 c.Check(nw.Name(), gc.Equals, networkName) 1232 c.Check(nw.ProviderId(), gc.Equals, network.Id(networks[i].ProviderId)) 1233 c.Check(nw.Tag().String(), gc.Equals, networks[i].Tag) 1234 c.Check(nw.VLANTag(), gc.Equals, networks[i].VLANTag) 1235 c.Check(nw.CIDR(), gc.Equals, networks[i].CIDR) 1236 } 1237 1238 // Verify the machine with requested volumes was provisioned, and the 1239 // volume information recorded in state. 1240 volumeAttachments, err := s.State.MachineVolumeAttachments(volumesMachine.MachineTag()) 1241 c.Assert(err, jc.ErrorIsNil) 1242 c.Assert(volumeAttachments, gc.HasLen, 1) 1243 volumeAttachmentInfo, err := volumeAttachments[0].Info() 1244 c.Assert(err, jc.ErrorIsNil) 1245 c.Assert(volumeAttachmentInfo, gc.Equals, state.VolumeAttachmentInfo{DeviceName: "sda"}) 1246 volume, err := s.State.Volume(volumeAttachments[0].Volume()) 1247 c.Assert(err, jc.ErrorIsNil) 1248 volumeInfo, err := volume.Info() 1249 c.Assert(err, jc.ErrorIsNil) 1250 c.Assert(volumeInfo, gc.Equals, state.VolumeInfo{VolumeId: "vol-0", Pool: "static-pool", Size: 1234}) 1251 1252 // Verify the machine without requested volumes still has no volume 1253 // attachments recorded in state. 1254 volumeAttachments, err = s.State.MachineVolumeAttachments(s.machines[1].MachineTag()) 1255 c.Assert(err, jc.ErrorIsNil) 1256 c.Assert(volumeAttachments, gc.HasLen, 0) 1257 } 1258 1259 func (s *withoutStateServerSuite) TestInstanceId(c *gc.C) { 1260 // Provision 2 machines first. 1261 err := s.machines[0].SetProvisioned("i-am", "fake_nonce", nil) 1262 c.Assert(err, jc.ErrorIsNil) 1263 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 1264 err = s.machines[1].SetProvisioned("i-am-not", "fake_nonce", &hwChars) 1265 c.Assert(err, jc.ErrorIsNil) 1266 1267 args := params.Entities{Entities: []params.Entity{ 1268 {Tag: s.machines[0].Tag().String()}, 1269 {Tag: s.machines[1].Tag().String()}, 1270 {Tag: s.machines[2].Tag().String()}, 1271 {Tag: "machine-42"}, 1272 {Tag: "unit-foo-0"}, 1273 {Tag: "service-bar"}, 1274 }} 1275 result, err := s.provisioner.InstanceId(args) 1276 c.Assert(err, jc.ErrorIsNil) 1277 c.Assert(result, gc.DeepEquals, params.StringResults{ 1278 Results: []params.StringResult{ 1279 {Result: "i-am"}, 1280 {Result: "i-am-not"}, 1281 {Error: apiservertesting.NotProvisionedError("2")}, 1282 {Error: apiservertesting.NotFoundError("machine 42")}, 1283 {Error: apiservertesting.ErrUnauthorized}, 1284 {Error: apiservertesting.ErrUnauthorized}, 1285 }, 1286 }) 1287 } 1288 1289 func (s *withoutStateServerSuite) TestWatchEnvironMachines(c *gc.C) { 1290 c.Assert(s.resources.Count(), gc.Equals, 0) 1291 1292 got, err := s.provisioner.WatchEnvironMachines() 1293 c.Assert(err, jc.ErrorIsNil) 1294 want := params.StringsWatchResult{ 1295 StringsWatcherId: "1", 1296 Changes: []string{"0", "1", "2", "3", "4"}, 1297 } 1298 c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId) 1299 c.Assert(got.Changes, jc.SameContents, want.Changes) 1300 1301 // Verify the resources were registered and stop them when done. 1302 c.Assert(s.resources.Count(), gc.Equals, 1) 1303 resource := s.resources.Get("1") 1304 defer statetesting.AssertStop(c, resource) 1305 1306 // Check that the Watch has consumed the initial event ("returned" 1307 // in the Watch call) 1308 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 1309 wc.AssertNoChange() 1310 1311 // Make sure WatchEnvironMachines fails with a machine agent login. 1312 anAuthorizer := s.authorizer 1313 anAuthorizer.Tag = names.NewMachineTag("1") 1314 anAuthorizer.EnvironManager = false 1315 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1316 c.Assert(err, jc.ErrorIsNil) 1317 1318 result, err := aProvisioner.WatchEnvironMachines() 1319 c.Assert(err, gc.ErrorMatches, "permission denied") 1320 c.Assert(result, gc.DeepEquals, params.StringsWatchResult{}) 1321 } 1322 1323 func (s *provisionerSuite) getManagerConfig(c *gc.C, typ instance.ContainerType) map[string]string { 1324 args := params.ContainerManagerConfigParams{Type: typ} 1325 results, err := s.provisioner.ContainerManagerConfig(args) 1326 c.Assert(err, jc.ErrorIsNil) 1327 return results.ManagerConfig 1328 } 1329 1330 func (s *withoutStateServerSuite) TestContainerManagerConfig(c *gc.C) { 1331 cfg := s.getManagerConfig(c, instance.KVM) 1332 c.Assert(cfg, jc.DeepEquals, map[string]string{ 1333 container.ConfigName: "juju", 1334 1335 // dummy provider supports both networking and address 1336 // allocation by default, so IP forwarding should be enabled. 1337 container.ConfigIPForwarding: "true", 1338 }) 1339 } 1340 1341 func (s *withoutStateServerSuite) TestContainerManagerConfigNoFeatureFlagNoIPForwarding(c *gc.C) { 1342 s.SetFeatureFlags() // clear the flags. 1343 1344 cfg := s.getManagerConfig(c, instance.KVM) 1345 c.Assert(cfg, jc.DeepEquals, map[string]string{ 1346 container.ConfigName: "juju", 1347 // ConfigIPForwarding should be missing. 1348 }) 1349 } 1350 1351 func (s *withoutStateServerSuite) TestContainerManagerConfigNoIPForwarding(c *gc.C) { 1352 // Break dummy provider's SupportsAddressAllocation method to 1353 // ensure ConfigIPForwarding is not set below. 1354 s.AssertConfigParameterUpdated(c, "broken", "SupportsAddressAllocation") 1355 1356 cfg := s.getManagerConfig(c, instance.KVM) 1357 c.Assert(cfg, jc.DeepEquals, map[string]string{ 1358 container.ConfigName: "juju", 1359 }) 1360 } 1361 1362 func (s *withoutStateServerSuite) TestContainerConfig(c *gc.C) { 1363 attrs := map[string]interface{}{ 1364 "http-proxy": "http://proxy.example.com:9000", 1365 "allow-lxc-loop-mounts": true, 1366 } 1367 err := s.State.UpdateEnvironConfig(attrs, nil, nil) 1368 c.Assert(err, jc.ErrorIsNil) 1369 expectedProxy := proxy.Settings{ 1370 Http: "http://proxy.example.com:9000", 1371 } 1372 1373 results, err := s.provisioner.ContainerConfig() 1374 c.Check(err, jc.ErrorIsNil) 1375 c.Check(results.UpdateBehavior, gc.Not(gc.IsNil)) 1376 c.Check(results.ProviderType, gc.Equals, "dummy") 1377 c.Check(results.AuthorizedKeys, gc.Equals, s.Environ.Config().AuthorizedKeys()) 1378 c.Check(results.SSLHostnameVerification, jc.IsTrue) 1379 c.Check(results.Proxy, gc.DeepEquals, expectedProxy) 1380 c.Check(results.AptProxy, gc.DeepEquals, expectedProxy) 1381 c.Check(results.PreferIPv6, jc.IsTrue) 1382 c.Check(results.AllowLXCLoopMounts, jc.IsTrue) 1383 } 1384 1385 func (s *withoutStateServerSuite) TestSetSupportedContainers(c *gc.C) { 1386 args := params.MachineContainersParams{Params: []params.MachineContainers{{ 1387 MachineTag: "machine-0", 1388 ContainerTypes: []instance.ContainerType{instance.LXC}, 1389 }, { 1390 MachineTag: "machine-1", 1391 ContainerTypes: []instance.ContainerType{instance.LXC, instance.KVM}, 1392 }}} 1393 results, err := s.provisioner.SetSupportedContainers(args) 1394 c.Assert(err, jc.ErrorIsNil) 1395 c.Assert(results.Results, gc.HasLen, 2) 1396 for _, result := range results.Results { 1397 c.Assert(result.Error, gc.IsNil) 1398 } 1399 m0, err := s.State.Machine("0") 1400 c.Assert(err, jc.ErrorIsNil) 1401 containers, ok := m0.SupportedContainers() 1402 c.Assert(ok, jc.IsTrue) 1403 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC}) 1404 m1, err := s.State.Machine("1") 1405 c.Assert(err, jc.ErrorIsNil) 1406 containers, ok = m1.SupportedContainers() 1407 c.Assert(ok, jc.IsTrue) 1408 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{instance.LXC, instance.KVM}) 1409 } 1410 1411 func (s *withoutStateServerSuite) TestSetSupportedContainersPermissions(c *gc.C) { 1412 // Login as a machine agent for machine 0. 1413 anAuthorizer := s.authorizer 1414 anAuthorizer.EnvironManager = false 1415 anAuthorizer.Tag = s.machines[0].Tag() 1416 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1417 c.Assert(err, jc.ErrorIsNil) 1418 c.Assert(aProvisioner, gc.NotNil) 1419 1420 args := params.MachineContainersParams{ 1421 Params: []params.MachineContainers{{ 1422 MachineTag: "machine-0", 1423 ContainerTypes: []instance.ContainerType{instance.LXC}, 1424 }, { 1425 MachineTag: "machine-1", 1426 ContainerTypes: []instance.ContainerType{instance.LXC}, 1427 }, { 1428 MachineTag: "machine-42", 1429 ContainerTypes: []instance.ContainerType{instance.LXC}, 1430 }, 1431 }, 1432 } 1433 // Only machine 0 can have it's containers updated. 1434 results, err := aProvisioner.SetSupportedContainers(args) 1435 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 1436 Results: []params.ErrorResult{ 1437 {Error: nil}, 1438 {Error: apiservertesting.ErrUnauthorized}, 1439 {Error: apiservertesting.ErrUnauthorized}, 1440 }, 1441 }) 1442 } 1443 1444 func (s *withoutStateServerSuite) TestSupportsNoContainers(c *gc.C) { 1445 args := params.MachineContainersParams{ 1446 Params: []params.MachineContainers{ 1447 { 1448 MachineTag: "machine-0", 1449 }, 1450 }, 1451 } 1452 results, err := s.provisioner.SetSupportedContainers(args) 1453 c.Assert(err, jc.ErrorIsNil) 1454 c.Assert(results.Results, gc.HasLen, 1) 1455 c.Assert(results.Results[0].Error, gc.IsNil) 1456 m0, err := s.State.Machine("0") 1457 c.Assert(err, jc.ErrorIsNil) 1458 containers, ok := m0.SupportedContainers() 1459 c.Assert(ok, jc.IsTrue) 1460 c.Assert(containers, gc.DeepEquals, []instance.ContainerType{}) 1461 } 1462 1463 var _ = gc.Suite(&withStateServerSuite{}) 1464 1465 type withStateServerSuite struct { 1466 provisionerSuite 1467 } 1468 1469 func (s *withStateServerSuite) SetUpTest(c *gc.C) { 1470 s.provisionerSuite.setUpTest(c, true) 1471 } 1472 1473 func (s *withStateServerSuite) TestAPIAddresses(c *gc.C) { 1474 hostPorts := [][]network.HostPort{ 1475 network.NewHostPorts(1234, "0.1.2.3"), 1476 } 1477 err := s.State.SetAPIHostPorts(hostPorts) 1478 c.Assert(err, jc.ErrorIsNil) 1479 1480 result, err := s.provisioner.APIAddresses() 1481 c.Assert(err, jc.ErrorIsNil) 1482 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1483 Result: []string{"0.1.2.3:1234"}, 1484 }) 1485 } 1486 1487 func (s *withStateServerSuite) TestStateAddresses(c *gc.C) { 1488 addresses, err := s.State.Addresses() 1489 c.Assert(err, jc.ErrorIsNil) 1490 1491 result, err := s.provisioner.StateAddresses() 1492 c.Assert(err, jc.ErrorIsNil) 1493 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1494 Result: addresses, 1495 }) 1496 } 1497 1498 func (s *withStateServerSuite) TestCACert(c *gc.C) { 1499 result := s.provisioner.CACert() 1500 c.Assert(result, gc.DeepEquals, params.BytesResult{ 1501 Result: []byte(s.State.CACert()), 1502 }) 1503 } 1504 1505 func (s *withoutStateServerSuite) TestWatchMachineErrorRetry(c *gc.C) { 1506 coretesting.SkipIfI386(c, "lp:1425569") 1507 1508 s.PatchValue(&provisioner.ErrorRetryWaitDelay, 2*coretesting.ShortWait) 1509 c.Assert(s.resources.Count(), gc.Equals, 0) 1510 1511 _, err := s.provisioner.WatchMachineErrorRetry() 1512 c.Assert(err, jc.ErrorIsNil) 1513 1514 // Verify the resources were registered and stop them when done. 1515 c.Assert(s.resources.Count(), gc.Equals, 1) 1516 resource := s.resources.Get("1") 1517 defer statetesting.AssertStop(c, resource) 1518 1519 // Check that the Watch has consumed the initial event ("returned" 1520 // in the Watch call) 1521 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 1522 wc.AssertNoChange() 1523 1524 // We should now get a time triggered change. 1525 wc.AssertOneChange() 1526 1527 // Make sure WatchMachineErrorRetry fails with a machine agent login. 1528 anAuthorizer := s.authorizer 1529 anAuthorizer.Tag = names.NewMachineTag("1") 1530 anAuthorizer.EnvironManager = false 1531 aProvisioner, err := provisioner.NewProvisionerAPI(s.State, s.resources, anAuthorizer) 1532 c.Assert(err, jc.ErrorIsNil) 1533 1534 result, err := aProvisioner.WatchMachineErrorRetry() 1535 c.Assert(err, gc.ErrorMatches, "permission denied") 1536 c.Assert(result, gc.DeepEquals, params.NotifyWatchResult{}) 1537 } 1538 1539 func (s *withoutStateServerSuite) TestFindTools(c *gc.C) { 1540 args := params.FindToolsParams{ 1541 MajorVersion: -1, 1542 MinorVersion: -1, 1543 } 1544 result, err := s.provisioner.FindTools(args) 1545 c.Assert(err, jc.ErrorIsNil) 1546 c.Assert(result.Error, gc.IsNil) 1547 c.Assert(result.List, gc.Not(gc.HasLen), 0) 1548 for _, tools := range result.List { 1549 url := fmt.Sprintf("https://%s/environment/%s/tools/%s", 1550 s.APIState.Addr(), coretesting.EnvironmentTag.Id(), tools.Version) 1551 c.Assert(tools.URL, gc.Equals, url) 1552 } 1553 } 1554 1555 type lxcDefaultMTUSuite struct { 1556 provisionerSuite 1557 } 1558 1559 var _ = gc.Suite(&lxcDefaultMTUSuite{}) 1560 1561 func (s *lxcDefaultMTUSuite) SetUpTest(c *gc.C) { 1562 // Because lxc-default-mtu is an immutable setting, we need to set 1563 // it in the default config JujuConnSuite uses, before the 1564 // environment is "created". 1565 s.DummyConfig = dummy.SampleConfig() 1566 s.DummyConfig["lxc-default-mtu"] = 9000 1567 s.provisionerSuite.SetUpTest(c) 1568 1569 stateConfig, err := s.State.EnvironConfig() 1570 c.Assert(err, jc.ErrorIsNil) 1571 value, ok := stateConfig.LXCDefaultMTU() 1572 c.Assert(ok, jc.IsTrue) 1573 c.Assert(value, gc.Equals, 9000) 1574 c.Logf("environ config lxc-default-mtu set to %v", value) 1575 } 1576 1577 func (s *lxcDefaultMTUSuite) TestContainerManagerConfigLXCDefaultMTU(c *gc.C) { 1578 managerConfig := s.getManagerConfig(c, instance.LXC) 1579 c.Assert(managerConfig, jc.DeepEquals, map[string]string{ 1580 container.ConfigName: "juju", 1581 container.ConfigLXCDefaultMTU: "9000", 1582 1583 "use-aufs": "false", 1584 container.ConfigIPForwarding: "true", 1585 }) 1586 1587 // KVM instances are not affected. 1588 managerConfig = s.getManagerConfig(c, instance.KVM) 1589 c.Assert(managerConfig, jc.DeepEquals, map[string]string{ 1590 container.ConfigName: "juju", 1591 container.ConfigIPForwarding: "true", 1592 }) 1593 }