github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/modelmanager/modelmanager_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelmanager_test 5 6 import ( 7 "regexp" 8 "runtime" 9 "time" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 gitjujutesting "github.com/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/juju/names.v2" 17 18 "github.com/juju/juju/apiserver/modelmanager" 19 "github.com/juju/juju/apiserver/params" 20 apiservertesting "github.com/juju/juju/apiserver/testing" 21 "github.com/juju/juju/cloud" 22 "github.com/juju/juju/environs" 23 "github.com/juju/juju/environs/config" 24 jujutesting "github.com/juju/juju/juju/testing" 25 "github.com/juju/juju/permission" 26 "github.com/juju/juju/state/stateenvirons" 27 "github.com/juju/juju/status" 28 jujuversion "github.com/juju/juju/version" 29 // Register the providers for the field check test 30 "github.com/juju/juju/apiserver/common" 31 _ "github.com/juju/juju/provider/azure" 32 "github.com/juju/juju/provider/dummy" 33 _ "github.com/juju/juju/provider/ec2" 34 _ "github.com/juju/juju/provider/joyent" 35 _ "github.com/juju/juju/provider/maas" 36 _ "github.com/juju/juju/provider/openstack" 37 "github.com/juju/juju/state" 38 coretesting "github.com/juju/juju/testing" 39 "github.com/juju/juju/testing/factory" 40 ) 41 42 type modelManagerBaseSuite struct { 43 } 44 45 type modelManagerSuite struct { 46 gitjujutesting.IsolationSuite 47 st *mockState 48 authoriser apiservertesting.FakeAuthorizer 49 api *modelmanager.ModelManagerAPI 50 } 51 52 var _ = gc.Suite(&modelManagerSuite{}) 53 54 func (s *modelManagerSuite) SetUpTest(c *gc.C) { 55 s.IsolationSuite.SetUpTest(c) 56 57 attrs := dummy.SampleConfig() 58 attrs["agent-version"] = jujuversion.Current.String() 59 cfg, err := config.New(config.UseDefaults, attrs) 60 c.Assert(err, jc.ErrorIsNil) 61 62 dummyCloud := cloud.Cloud{ 63 Type: "dummy", 64 AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, 65 Regions: []cloud.Region{ 66 {Name: "some-region"}, 67 {Name: "qux"}, 68 }, 69 } 70 71 s.st = &mockState{ 72 modelUUID: coretesting.ModelTag.Id(), 73 cloud: dummyCloud, 74 clouds: map[names.CloudTag]cloud.Cloud{ 75 names.NewCloudTag("some-cloud"): dummyCloud, 76 }, 77 controllerModel: &mockModel{ 78 owner: names.NewUserTag("admin@local"), 79 life: state.Alive, 80 cfg: cfg, 81 status: status.StatusInfo{ 82 Status: status.Available, 83 Since: &time.Time{}, 84 }, 85 users: []*mockModelUser{{ 86 userName: "admin", 87 access: permission.AdminAccess, 88 }, { 89 userName: "otheruser", 90 access: permission.WriteAccess, 91 }}, 92 }, 93 model: &mockModel{ 94 owner: names.NewUserTag("admin@local"), 95 life: state.Alive, 96 tag: coretesting.ModelTag, 97 cfg: cfg, 98 status: status.StatusInfo{ 99 Status: status.Available, 100 Since: &time.Time{}, 101 }, 102 users: []*mockModelUser{{ 103 userName: "admin", 104 access: permission.AdminAccess, 105 }, { 106 userName: "otheruser", 107 access: permission.WriteAccess, 108 }}, 109 }, 110 cred: cloud.NewEmptyCredential(), 111 cfgDefaults: config.ModelDefaultAttributes{ 112 "attr": config.AttributeDefaultValues{ 113 Default: "", 114 Controller: "val", 115 Regions: []config.RegionDefaultValue{{ 116 Name: "dummy", 117 Value: "val++"}}}, 118 "attr2": config.AttributeDefaultValues{ 119 Controller: "val3", 120 Default: "val2", 121 Regions: []config.RegionDefaultValue{{ 122 Name: "left", 123 Value: "spam"}}}, 124 }, 125 } 126 s.authoriser = apiservertesting.FakeAuthorizer{ 127 Tag: names.NewUserTag("admin@local"), 128 } 129 api, err := modelmanager.NewModelManagerAPI(s.st, nil, s.authoriser) 130 c.Assert(err, jc.ErrorIsNil) 131 s.api = api 132 } 133 134 func (s *modelManagerSuite) setAPIUser(c *gc.C, user names.UserTag) { 135 s.authoriser.Tag = user 136 mm, err := modelmanager.NewModelManagerAPI(s.st, nil, s.authoriser) 137 c.Assert(err, jc.ErrorIsNil) 138 s.api = mm 139 } 140 141 func (s *modelManagerSuite) getModelArgs(c *gc.C) state.ModelArgs { 142 for _, v := range s.st.Calls() { 143 if v.Args == nil { 144 continue 145 } 146 if newModelArgs, ok := v.Args[0].(state.ModelArgs); ok { 147 return newModelArgs 148 } 149 } 150 c.Fatal("failed to find state.ModelArgs") 151 panic("unreachable") 152 } 153 154 func (s *modelManagerSuite) TestCreateModelArgs(c *gc.C) { 155 args := params.ModelCreateArgs{ 156 Name: "foo", 157 OwnerTag: "user-admin@local", 158 Config: map[string]interface{}{ 159 "bar": "baz", 160 }, 161 CloudRegion: "qux", 162 CloudCredentialTag: "cloudcred-some-cloud_admin@local_some-credential", 163 } 164 _, err := s.api.CreateModel(args) 165 c.Assert(err, jc.ErrorIsNil) 166 s.st.CheckCallNames(c, 167 "ControllerTag", 168 "ModelUUID", 169 "ControllerTag", 170 "ControllerModel", 171 "Cloud", 172 "CloudCredential", 173 "ControllerConfig", 174 "ComposeNewModelConfig", 175 "NewModel", 176 "ForModel", 177 "Model", 178 "ControllerConfig", 179 "LastModelConnection", 180 "LastModelConnection", 181 "AllMachines", 182 "Close", 183 "Close", 184 ) 185 186 // We cannot predict the UUID, because it's generated, 187 // so we just extract it and ensure that it's not the 188 // same as the controller UUID. 189 newModelArgs := s.getModelArgs(c) 190 uuid := newModelArgs.Config.UUID() 191 c.Assert(uuid, gc.Not(gc.Equals), s.st.controllerModel.cfg.UUID()) 192 193 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 194 "name": "foo", 195 "type": "dummy", 196 "uuid": uuid, 197 "agent-version": jujuversion.Current.String(), 198 "bar": "baz", 199 "controller": false, 200 "broken": "", 201 "secret": "pork", 202 "something": "value", 203 }) 204 c.Assert(err, jc.ErrorIsNil) 205 206 c.Assert(newModelArgs.StorageProviderRegistry, gc.NotNil) 207 newModelArgs.StorageProviderRegistry = nil 208 209 c.Assert(newModelArgs, jc.DeepEquals, state.ModelArgs{ 210 Owner: names.NewUserTag("admin@local"), 211 CloudName: "some-cloud", 212 CloudRegion: "qux", 213 CloudCredential: names.NewCloudCredentialTag( 214 "some-cloud/admin@local/some-credential", 215 ), 216 Config: cfg, 217 }) 218 } 219 220 func (s *modelManagerSuite) TestCreateModelArgsWithCloud(c *gc.C) { 221 args := params.ModelCreateArgs{ 222 Name: "foo", 223 OwnerTag: "user-admin@local", 224 Config: map[string]interface{}{ 225 "bar": "baz", 226 }, 227 CloudTag: "cloud-some-cloud", 228 CloudRegion: "qux", 229 CloudCredentialTag: "cloudcred-some-cloud_admin@local_some-credential", 230 } 231 _, err := s.api.CreateModel(args) 232 c.Assert(err, jc.ErrorIsNil) 233 234 newModelArgs := s.getModelArgs(c) 235 c.Assert(newModelArgs.CloudName, gc.Equals, "some-cloud") 236 } 237 238 func (s *modelManagerSuite) TestCreateModelArgsWithCloudNotFound(c *gc.C) { 239 s.st.SetErrors(nil, errors.NotFoundf("cloud")) 240 args := params.ModelCreateArgs{ 241 Name: "foo", 242 OwnerTag: "user-admin@local", 243 CloudTag: "cloud-some-unknown-cloud", 244 } 245 _, err := s.api.CreateModel(args) 246 c.Assert(err, gc.ErrorMatches, `cloud "some-unknown-cloud" not found, expected one of \["some-cloud"\]`) 247 } 248 249 func (s *modelManagerSuite) TestCreateModelDefaultRegion(c *gc.C) { 250 args := params.ModelCreateArgs{ 251 Name: "foo", 252 OwnerTag: "user-admin@local", 253 } 254 _, err := s.api.CreateModel(args) 255 c.Assert(err, jc.ErrorIsNil) 256 257 newModelArgs := s.getModelArgs(c) 258 c.Assert(newModelArgs.CloudRegion, gc.Equals, "some-region") 259 } 260 261 func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdmin(c *gc.C) { 262 s.testCreateModelDefaultCredentialAdmin(c, "user-admin@local") 263 } 264 265 func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdminNoDomain(c *gc.C) { 266 s.testCreateModelDefaultCredentialAdmin(c, "user-admin") 267 } 268 269 func (s *modelManagerSuite) testCreateModelDefaultCredentialAdmin(c *gc.C, ownerTag string) { 270 s.st.cloud.AuthTypes = []cloud.AuthType{"userpass"} 271 args := params.ModelCreateArgs{ 272 Name: "foo", 273 OwnerTag: ownerTag, 274 } 275 _, err := s.api.CreateModel(args) 276 c.Assert(err, jc.ErrorIsNil) 277 278 newModelArgs := s.getModelArgs(c) 279 c.Assert(newModelArgs.CloudCredential, gc.Equals, names.NewCloudCredentialTag( 280 "some-cloud/bob@local/some-credential", 281 )) 282 } 283 284 func (s *modelManagerSuite) TestCreateModelEmptyCredentialNonAdmin(c *gc.C) { 285 args := params.ModelCreateArgs{ 286 Name: "foo", 287 OwnerTag: "user-bob@local", 288 } 289 _, err := s.api.CreateModel(args) 290 c.Assert(err, jc.ErrorIsNil) 291 292 newModelArgs := s.getModelArgs(c) 293 c.Assert(newModelArgs.CloudCredential, gc.Equals, names.CloudCredentialTag{}) 294 } 295 296 func (s *modelManagerSuite) TestCreateModelNoDefaultCredentialNonAdmin(c *gc.C) { 297 s.st.cloud.AuthTypes = nil 298 args := params.ModelCreateArgs{ 299 Name: "foo", 300 OwnerTag: "user-bob@local", 301 } 302 _, err := s.api.CreateModel(args) 303 c.Assert(err, gc.ErrorMatches, "no credential specified") 304 } 305 306 func (s *modelManagerSuite) TestCreateModelUnknownCredential(c *gc.C) { 307 s.st.SetErrors(nil, nil, errors.NotFoundf("credential")) 308 args := params.ModelCreateArgs{ 309 Name: "foo", 310 OwnerTag: "user-admin@local", 311 CloudCredentialTag: "cloudcred-some-cloud_admin@local_bar", 312 } 313 _, err := s.api.CreateModel(args) 314 c.Assert(err, gc.ErrorMatches, `getting credential: credential not found`) 315 } 316 317 func (s *modelManagerSuite) TestModelDefaults(c *gc.C) { 318 result, err := s.api.ModelDefaults() 319 c.Assert(err, jc.ErrorIsNil) 320 expectedValues := map[string]params.ModelDefaults{ 321 "attr": { 322 Controller: "val", 323 Default: "", 324 Regions: []params.RegionDefaults{{ 325 RegionName: "dummy", 326 Value: "val++"}}}, 327 "attr2": { 328 Controller: "val3", 329 Default: "val2", 330 Regions: []params.RegionDefaults{{ 331 RegionName: "left", 332 Value: "spam"}}}, 333 } 334 c.Assert(result.Config, jc.DeepEquals, expectedValues) 335 } 336 337 func (s *modelManagerSuite) TestSetModelDefaults(c *gc.C) { 338 params := params.SetModelDefaults{ 339 Config: []params.ModelDefaultValues{{ 340 Config: map[string]interface{}{ 341 "attr3": "val3", 342 "attr4": "val4"}, 343 }}} 344 result, err := s.api.SetModelDefaults(params) 345 c.Assert(err, jc.ErrorIsNil) 346 c.Assert(result.OneError(), jc.ErrorIsNil) 347 c.Assert(s.st.cfgDefaults, jc.DeepEquals, config.ModelDefaultAttributes{ 348 "attr": { 349 Controller: "val", 350 Default: "", 351 Regions: []config.RegionDefaultValue{{ 352 Name: "dummy", 353 Value: "val++"}}}, 354 "attr2": { 355 Controller: "val3", 356 Default: "val2", 357 Regions: []config.RegionDefaultValue{{ 358 Name: "left", 359 Value: "spam"}}}, 360 "attr3": {Controller: "val3"}, 361 "attr4": {Controller: "val4"}, 362 }) 363 } 364 365 func (s *modelManagerSuite) blockAllChanges(c *gc.C, msg string) { 366 s.st.blockMsg = msg 367 s.st.block = state.ChangeBlock 368 } 369 370 func (s *modelManagerSuite) assertBlocked(c *gc.C, err error, msg string) { 371 c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err)) 372 c.Assert(errors.Cause(err), jc.DeepEquals, ¶ms.Error{ 373 Message: msg, 374 Code: "operation is blocked", 375 }) 376 } 377 378 func (s *modelManagerSuite) TestBlockChangesSetModelDefaults(c *gc.C) { 379 s.blockAllChanges(c, "TestBlockChangesSetModelDefaults") 380 _, err := s.api.SetModelDefaults(params.SetModelDefaults{}) 381 s.assertBlocked(c, err, "TestBlockChangesSetModelDefaults") 382 } 383 384 func (s *modelManagerSuite) TestUnsetModelDefaults(c *gc.C) { 385 args := params.UnsetModelDefaults{ 386 Keys: []params.ModelUnsetKeys{{ 387 Keys: []string{"attr"}, 388 }}} 389 result, err := s.api.UnsetModelDefaults(args) 390 c.Assert(err, jc.ErrorIsNil) 391 c.Assert(result.OneError(), jc.ErrorIsNil) 392 want := config.ModelDefaultAttributes{ 393 "attr": config.AttributeDefaultValues{ 394 Regions: []config.RegionDefaultValue{ 395 config.RegionDefaultValue{ 396 Name: "dummy", 397 Value: "val++"}, 398 }}, 399 "attr2": config.AttributeDefaultValues{ 400 Default: "val2", 401 Controller: "val3", 402 Regions: []config.RegionDefaultValue{ 403 config.RegionDefaultValue{ 404 Name: "left", 405 Value: "spam"}}}} 406 c.Assert(s.st.cfgDefaults, jc.DeepEquals, want) 407 } 408 409 func (s *modelManagerSuite) TestBlockUnsetModelDefaults(c *gc.C) { 410 s.blockAllChanges(c, "TestBlockUnsetModelDefaults") 411 args := params.UnsetModelDefaults{ 412 Keys: []params.ModelUnsetKeys{{ 413 Keys: []string{"abc"}, 414 }}} 415 _, err := s.api.UnsetModelDefaults(args) 416 s.assertBlocked(c, err, "TestBlockUnsetModelDefaults") 417 } 418 419 func (s *modelManagerSuite) TestUnsetModelDefaultsMissing(c *gc.C) { 420 // It's okay to unset a non-existent attribute. 421 args := params.UnsetModelDefaults{ 422 Keys: []params.ModelUnsetKeys{{ 423 Keys: []string{"not there"}, 424 }}} 425 result, err := s.api.UnsetModelDefaults(args) 426 c.Assert(err, jc.ErrorIsNil) 427 c.Assert(result.OneError(), jc.ErrorIsNil) 428 } 429 430 func (s *modelManagerSuite) TestModelDefaultsAsNormalUser(c *gc.C) { 431 s.setAPIUser(c, names.NewUserTag("charlie@local")) 432 got, err := s.api.ModelDefaults() 433 c.Assert(err, gc.ErrorMatches, "permission denied") 434 c.Assert(got, gc.DeepEquals, params.ModelDefaultsResult{}) 435 } 436 437 func (s *modelManagerSuite) TestSetModelDefaultsAsNormalUser(c *gc.C) { 438 s.setAPIUser(c, names.NewUserTag("charlie@local")) 439 got, err := s.api.SetModelDefaults(params.SetModelDefaults{ 440 Config: []params.ModelDefaultValues{{ 441 Config: map[string]interface{}{ 442 "ftp-proxy": "http://charlie", 443 }}}}) 444 c.Assert(err, jc.ErrorIsNil) 445 c.Assert(got, jc.DeepEquals, params.ErrorResults{ 446 Results: []params.ErrorResult{ 447 params.ErrorResult{ 448 Error: ¶ms.Error{ 449 Message: "permission denied", 450 Code: "unauthorized access"}}}}) 451 452 // Make sure it didn't change. 453 s.setAPIUser(c, names.NewUserTag("admin@local")) 454 cfg, err := s.api.ModelDefaults() 455 c.Assert(err, jc.ErrorIsNil) 456 c.Assert(cfg.Config["ftp-proxy"].Controller, gc.IsNil) 457 } 458 459 func (s *modelManagerSuite) TestUnsetModelDefaultsAsNormalUser(c *gc.C) { 460 s.setAPIUser(c, names.NewUserTag("charlie@local")) 461 got, err := s.api.UnsetModelDefaults(params.UnsetModelDefaults{ 462 Keys: []params.ModelUnsetKeys{{ 463 Keys: []string{"attr2"}}}}) 464 c.Assert(err, gc.ErrorMatches, "permission denied") 465 c.Assert(got, gc.DeepEquals, params.ErrorResults{ 466 Results: []params.ErrorResult{ 467 params.ErrorResult{ 468 Error: nil}}}) 469 470 // Make sure it didn't change. 471 s.setAPIUser(c, names.NewUserTag("admin@local")) 472 cfg, err := s.api.ModelDefaults() 473 c.Assert(err, jc.ErrorIsNil) 474 c.Assert(cfg.Config["attr2"].Controller.(string), gc.Equals, "val3") 475 } 476 477 func (s *modelManagerSuite) TestDumpModel(c *gc.C) { 478 results := s.api.DumpModels(params.Entities{[]params.Entity{{ 479 Tag: "bad-tag", 480 }, { 481 Tag: "application-foo", 482 }, { 483 Tag: s.st.ModelTag().String(), 484 }}}) 485 486 c.Assert(results.Results, gc.HasLen, 3) 487 bad, notApp, good := results.Results[0], results.Results[1], results.Results[2] 488 c.Check(bad.Result, gc.IsNil) 489 c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`) 490 491 c.Check(notApp.Result, gc.IsNil) 492 c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`) 493 494 c.Check(good.Error, gc.IsNil) 495 c.Check(good.Result, jc.DeepEquals, map[string]interface{}{ 496 "model-uuid": "deadbeef-0bad-400d-8000-4b1d0d06f00d", 497 }) 498 } 499 500 func (s *modelManagerSuite) TestDumpModelMissingModel(c *gc.C) { 501 s.st.SetErrors(errors.NotFoundf("boom")) 502 tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000") 503 models := params.Entities{[]params.Entity{{Tag: tag.String()}}} 504 results := s.api.DumpModels(models) 505 506 calls := s.st.Calls() 507 c.Logf("%#v", calls) 508 lastCall := calls[len(calls)-1] 509 c.Check(lastCall.FuncName, gc.Equals, "ForModel") 510 511 c.Assert(results.Results, gc.HasLen, 1) 512 result := results.Results[0] 513 c.Assert(result.Result, gc.IsNil) 514 c.Assert(result.Error, gc.NotNil) 515 c.Check(result.Error.Code, gc.Equals, `not found`) 516 c.Check(result.Error.Message, gc.Equals, `id not found`) 517 } 518 519 func (s *modelManagerSuite) TestDumpModelUsers(c *gc.C) { 520 models := params.Entities{[]params.Entity{{Tag: s.st.ModelTag().String()}}} 521 for _, user := range []names.UserTag{ 522 names.NewUserTag("otheruser"), 523 names.NewUserTag("unknown"), 524 } { 525 s.setAPIUser(c, user) 526 results := s.api.DumpModels(models) 527 c.Assert(results.Results, gc.HasLen, 1) 528 result := results.Results[0] 529 c.Assert(result.Result, gc.IsNil) 530 c.Assert(result.Error, gc.NotNil) 531 c.Check(result.Error.Message, gc.Equals, `permission denied`) 532 } 533 } 534 535 func (s *modelManagerSuite) TestDumpModelsDB(c *gc.C) { 536 results := s.api.DumpModelsDB(params.Entities{[]params.Entity{{ 537 Tag: "bad-tag", 538 }, { 539 Tag: "application-foo", 540 }, { 541 Tag: s.st.ModelTag().String(), 542 }}}) 543 544 c.Assert(results.Results, gc.HasLen, 3) 545 bad, notApp, good := results.Results[0], results.Results[1], results.Results[2] 546 c.Check(bad.Result, gc.IsNil) 547 c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`) 548 549 c.Check(notApp.Result, gc.IsNil) 550 c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`) 551 552 c.Check(good.Error, gc.IsNil) 553 c.Check(good.Result, jc.DeepEquals, map[string]interface{}{ 554 "models": "lots of data", 555 }) 556 } 557 558 func (s *modelManagerSuite) TestDumpModelsDBMissingModel(c *gc.C) { 559 s.st.SetErrors(errors.NotFoundf("boom")) 560 tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000") 561 models := params.Entities{[]params.Entity{{Tag: tag.String()}}} 562 results := s.api.DumpModelsDB(models) 563 564 calls := s.st.Calls() 565 c.Logf("%#v", calls) 566 lastCall := calls[len(calls)-1] 567 c.Check(lastCall.FuncName, gc.Equals, "ForModel") 568 569 c.Assert(results.Results, gc.HasLen, 1) 570 result := results.Results[0] 571 c.Assert(result.Result, gc.IsNil) 572 c.Assert(result.Error, gc.NotNil) 573 c.Check(result.Error.Code, gc.Equals, `not found`) 574 c.Check(result.Error.Message, gc.Equals, `id not found`) 575 } 576 577 func (s *modelManagerSuite) TestDumpModelsDBUsers(c *gc.C) { 578 models := params.Entities{[]params.Entity{{Tag: s.st.ModelTag().String()}}} 579 for _, user := range []names.UserTag{ 580 names.NewUserTag("otheruser"), 581 names.NewUserTag("unknown"), 582 } { 583 s.setAPIUser(c, user) 584 results := s.api.DumpModelsDB(models) 585 c.Assert(results.Results, gc.HasLen, 1) 586 result := results.Results[0] 587 c.Assert(result.Result, gc.IsNil) 588 c.Assert(result.Error, gc.NotNil) 589 c.Check(result.Error.Message, gc.Equals, `permission denied`) 590 } 591 } 592 593 // modelManagerStateSuite contains end-to-end tests. 594 // Prefer adding tests to modelManagerSuite above. 595 type modelManagerStateSuite struct { 596 jujutesting.JujuConnSuite 597 modelmanager *modelmanager.ModelManagerAPI 598 authoriser apiservertesting.FakeAuthorizer 599 } 600 601 var _ = gc.Suite(&modelManagerStateSuite{}) 602 603 func (s *modelManagerStateSuite) SetUpSuite(c *gc.C) { 604 // TODO(anastasiamac 2016-07-19): Fix this on windows 605 if runtime.GOOS != "linux" { 606 c.Skip("bug 1603585: Skipping this on windows for now") 607 } 608 s.JujuConnSuite.SetUpSuite(c) 609 } 610 611 func (s *modelManagerStateSuite) SetUpTest(c *gc.C) { 612 s.JujuConnSuite.SetUpTest(c) 613 s.authoriser = apiservertesting.FakeAuthorizer{ 614 Tag: s.AdminUserTag(c), 615 } 616 loggo.GetLogger("juju.apiserver.modelmanager").SetLogLevel(loggo.TRACE) 617 } 618 619 func (s *modelManagerStateSuite) setAPIUser(c *gc.C, user names.UserTag) { 620 s.authoriser.Tag = user 621 modelmanager, err := modelmanager.NewModelManagerAPI( 622 common.NewModelManagerBackend(s.State), 623 stateenvirons.EnvironConfigGetter{s.State}, 624 s.authoriser, 625 ) 626 c.Assert(err, jc.ErrorIsNil) 627 s.modelmanager = modelmanager 628 } 629 630 func (s *modelManagerStateSuite) TestNewAPIAcceptsClient(c *gc.C) { 631 anAuthoriser := s.authoriser 632 anAuthoriser.Tag = names.NewUserTag("external@remote") 633 endPoint, err := modelmanager.NewModelManagerAPI( 634 common.NewModelManagerBackend(s.State), nil, anAuthoriser, 635 ) 636 c.Assert(err, jc.ErrorIsNil) 637 c.Assert(endPoint, gc.NotNil) 638 } 639 640 func (s *modelManagerStateSuite) TestNewAPIRefusesNonClient(c *gc.C) { 641 anAuthoriser := s.authoriser 642 anAuthoriser.Tag = names.NewUnitTag("mysql/0") 643 endPoint, err := modelmanager.NewModelManagerAPI( 644 common.NewModelManagerBackend(s.State), nil, anAuthoriser, 645 ) 646 c.Assert(endPoint, gc.IsNil) 647 c.Assert(err, gc.ErrorMatches, "permission denied") 648 } 649 650 func (s *modelManagerStateSuite) createArgs(c *gc.C, owner names.UserTag) params.ModelCreateArgs { 651 return params.ModelCreateArgs{ 652 Name: "test-model", 653 OwnerTag: owner.String(), 654 Config: map[string]interface{}{ 655 "authorized-keys": "ssh-key", 656 // And to make it a valid dummy config 657 "controller": false, 658 }, 659 } 660 } 661 662 func (s *modelManagerStateSuite) createArgsForVersion(c *gc.C, owner names.UserTag, ver interface{}) params.ModelCreateArgs { 663 params := s.createArgs(c, owner) 664 params.Config["agent-version"] = ver 665 return params 666 } 667 668 func (s *modelManagerStateSuite) TestUserCanCreateModel(c *gc.C) { 669 owner := names.NewUserTag("admin@local") 670 s.setAPIUser(c, owner) 671 model, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 672 c.Assert(err, jc.ErrorIsNil) 673 c.Assert(model.OwnerTag, gc.Equals, owner.String()) 674 c.Assert(model.Name, gc.Equals, "test-model") 675 } 676 677 func (s *modelManagerStateSuite) TestAdminCanCreateModelForSomeoneElse(c *gc.C) { 678 s.setAPIUser(c, s.AdminUserTag(c)) 679 owner := names.NewUserTag("external@remote") 680 model, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 681 c.Assert(err, jc.ErrorIsNil) 682 c.Assert(model.OwnerTag, gc.Equals, owner.String()) 683 c.Assert(model.Name, gc.Equals, "test-model") 684 // Make sure that the environment created does actually have the correct 685 // owner, and that owner is actually allowed to use the environment. 686 newState, err := s.State.ForModel(names.NewModelTag(model.UUID)) 687 c.Assert(err, jc.ErrorIsNil) 688 defer newState.Close() 689 690 newModel, err := newState.Model() 691 c.Assert(err, jc.ErrorIsNil) 692 c.Assert(newModel.Owner(), gc.Equals, owner) 693 _, err = newState.UserAccess(owner, newState.ModelTag()) 694 c.Assert(err, jc.ErrorIsNil) 695 } 696 697 func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSomeoneElse(c *gc.C) { 698 s.setAPIUser(c, names.NewUserTag("non-admin@remote")) 699 owner := names.NewUserTag("external@remote") 700 _, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 701 c.Assert(err, gc.ErrorMatches, "permission denied") 702 } 703 704 func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSelf(c *gc.C) { 705 owner := names.NewUserTag("non-admin@remote") 706 s.setAPIUser(c, owner) 707 _, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 708 c.Assert(err, gc.ErrorMatches, "permission denied") 709 } 710 711 func (s *modelManagerStateSuite) TestCreateModelValidatesConfig(c *gc.C) { 712 admin := s.AdminUserTag(c) 713 s.setAPIUser(c, admin) 714 args := s.createArgs(c, admin) 715 args.Config["controller"] = "maybe" 716 _, err := s.modelmanager.CreateModel(args) 717 c.Assert(err, gc.ErrorMatches, 718 "failed to create config: provider config preparation failed: controller: expected bool, got string\\(\"maybe\"\\)", 719 ) 720 } 721 722 func (s *modelManagerStateSuite) TestCreateModelBadConfig(c *gc.C) { 723 owner := names.NewUserTag("admin@local") 724 s.setAPIUser(c, owner) 725 for i, test := range []struct { 726 key string 727 value interface{} 728 errMatch string 729 }{ 730 { 731 key: "uuid", 732 value: "anything", 733 errMatch: `failed to create config: uuid is generated, you cannot specify one`, 734 }, { 735 key: "type", 736 value: "fake", 737 errMatch: `failed to create config: specified type "fake" does not match controller "dummy"`, 738 }, 739 } { 740 c.Logf("%d: %s", i, test.key) 741 args := s.createArgs(c, owner) 742 args.Config[test.key] = test.value 743 _, err := s.modelmanager.CreateModel(args) 744 c.Assert(err, gc.ErrorMatches, test.errMatch) 745 746 } 747 } 748 749 func (s *modelManagerStateSuite) TestCreateModelSameAgentVersion(c *gc.C) { 750 admin := s.AdminUserTag(c) 751 s.setAPIUser(c, admin) 752 args := s.createArgsForVersion(c, admin, jujuversion.Current.String()) 753 _, err := s.modelmanager.CreateModel(args) 754 c.Assert(err, jc.ErrorIsNil) 755 } 756 757 func (s *modelManagerStateSuite) TestCreateModelBadAgentVersion(c *gc.C) { 758 err := s.BackingState.SetModelAgentVersion(coretesting.FakeVersionNumber) 759 c.Assert(err, jc.ErrorIsNil) 760 761 admin := s.AdminUserTag(c) 762 s.setAPIUser(c, admin) 763 764 bigger := coretesting.FakeVersionNumber 765 bigger.Minor += 1 766 767 smaller := coretesting.FakeVersionNumber 768 smaller.Minor -= 1 769 770 for i, test := range []struct { 771 value interface{} 772 errMatch string 773 }{ 774 { 775 value: 42, 776 errMatch: `failed to create config: agent-version must be a string but has type 'int'`, 777 }, { 778 value: "not a number", 779 errMatch: `failed to create config: invalid version \"not a number\"`, 780 }, { 781 value: bigger.String(), 782 errMatch: "failed to create config: agent-version .* cannot be greater than the controller .*", 783 }, { 784 value: smaller.String(), 785 errMatch: "failed to create config: no tools found for version .*", 786 }, 787 } { 788 c.Logf("test %d", i) 789 args := s.createArgsForVersion(c, admin, test.value) 790 _, err := s.modelmanager.CreateModel(args) 791 c.Check(err, gc.ErrorMatches, test.errMatch) 792 } 793 } 794 795 func (s *modelManagerStateSuite) TestListModelsForSelf(c *gc.C) { 796 user := names.NewUserTag("external@remote") 797 s.setAPIUser(c, user) 798 result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()}) 799 c.Assert(err, jc.ErrorIsNil) 800 c.Assert(result.UserModels, gc.HasLen, 0) 801 } 802 803 func (s *modelManagerStateSuite) TestListModelsForSelfLocalUser(c *gc.C) { 804 // When the user's credentials cache stores the simple name, but the 805 // api server converts it to a fully qualified name. 806 user := names.NewUserTag("local-user") 807 s.setAPIUser(c, names.NewUserTag("local-user@local")) 808 result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()}) 809 c.Assert(err, jc.ErrorIsNil) 810 c.Assert(result.UserModels, gc.HasLen, 0) 811 } 812 813 func (s *modelManagerStateSuite) checkModelMatches(c *gc.C, model params.Model, expected *state.Model) { 814 c.Check(model.Name, gc.Equals, expected.Name()) 815 c.Check(model.UUID, gc.Equals, expected.UUID()) 816 c.Check(model.OwnerTag, gc.Equals, expected.Owner().String()) 817 } 818 819 func (s *modelManagerStateSuite) TestListModelsAdminSelf(c *gc.C) { 820 user := s.AdminUserTag(c) 821 s.setAPIUser(c, user) 822 result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()}) 823 c.Assert(err, jc.ErrorIsNil) 824 c.Assert(result.UserModels, gc.HasLen, 1) 825 expected, err := s.State.Model() 826 c.Assert(err, jc.ErrorIsNil) 827 s.checkModelMatches(c, result.UserModels[0].Model, expected) 828 } 829 830 func (s *modelManagerStateSuite) TestListModelsAdminListsOther(c *gc.C) { 831 user := s.AdminUserTag(c) 832 s.setAPIUser(c, user) 833 other := names.NewUserTag("external@remote") 834 result, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()}) 835 c.Assert(err, jc.ErrorIsNil) 836 c.Assert(result.UserModels, gc.HasLen, 0) 837 } 838 839 func (s *modelManagerStateSuite) TestListModelsDenied(c *gc.C) { 840 user := names.NewUserTag("external@remote") 841 s.setAPIUser(c, user) 842 other := names.NewUserTag("other@remote") 843 _, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()}) 844 c.Assert(err, gc.ErrorMatches, "permission denied") 845 } 846 847 func (s *modelManagerStateSuite) TestAdminModelManager(c *gc.C) { 848 user := s.AdminUserTag(c) 849 s.setAPIUser(c, user) 850 c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsTrue) 851 } 852 853 func (s *modelManagerStateSuite) TestNonAdminModelManager(c *gc.C) { 854 user := names.NewUserTag("external@remote") 855 s.setAPIUser(c, user) 856 c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsFalse) 857 } 858 859 func (s *modelManagerStateSuite) TestDestroyOwnModel(c *gc.C) { 860 // TODO(perrito666) this test is not valid until we have 861 // proper controller permission since the only users that 862 // can create models are controller admins. 863 owner := names.NewUserTag("admin@local") 864 s.setAPIUser(c, owner) 865 m, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 866 c.Assert(err, jc.ErrorIsNil) 867 st, err := s.State.ForModel(names.NewModelTag(m.UUID)) 868 c.Assert(err, jc.ErrorIsNil) 869 defer st.Close() 870 871 s.modelmanager, err = modelmanager.NewModelManagerAPI( 872 common.NewModelManagerBackend(st), nil, s.authoriser, 873 ) 874 c.Assert(err, jc.ErrorIsNil) 875 876 results, err := s.modelmanager.DestroyModels(params.Entities{ 877 Entities: []params.Entity{{"model-" + m.UUID}}, 878 }) 879 c.Assert(err, jc.ErrorIsNil) 880 c.Assert(results.Results, gc.HasLen, 1) 881 c.Assert(results.Results[0].Error, gc.IsNil) 882 883 model, err := st.Model() 884 c.Assert(err, jc.ErrorIsNil) 885 c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive) 886 } 887 888 func (s *modelManagerStateSuite) TestAdminDestroysOtherModel(c *gc.C) { 889 // TODO(perrito666) Both users are admins in this case, this tesst is of dubious 890 // usefulness until proper controller permissions are in place. 891 owner := names.NewUserTag("admin@local") 892 s.setAPIUser(c, owner) 893 m, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 894 c.Assert(err, jc.ErrorIsNil) 895 st, err := s.State.ForModel(names.NewModelTag(m.UUID)) 896 c.Assert(err, jc.ErrorIsNil) 897 defer st.Close() 898 899 s.modelmanager, err = modelmanager.NewModelManagerAPI( 900 common.NewModelManagerBackend(st), nil, s.authoriser, 901 ) 902 c.Assert(err, jc.ErrorIsNil) 903 904 other := s.AdminUserTag(c) 905 s.setAPIUser(c, other) 906 907 results, err := s.modelmanager.DestroyModels(params.Entities{ 908 Entities: []params.Entity{{"model-" + m.UUID}}, 909 }) 910 c.Assert(err, jc.ErrorIsNil) 911 c.Assert(results.Results, gc.HasLen, 1) 912 c.Assert(results.Results[0].Error, gc.IsNil) 913 914 s.setAPIUser(c, owner) 915 model, err := st.Model() 916 c.Assert(err, jc.ErrorIsNil) 917 c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive) 918 } 919 920 func (s *modelManagerStateSuite) TestDestroyModelErrors(c *gc.C) { 921 owner := names.NewUserTag("admin@local") 922 s.setAPIUser(c, owner) 923 m, err := s.modelmanager.CreateModel(s.createArgs(c, owner)) 924 c.Assert(err, jc.ErrorIsNil) 925 st, err := s.State.ForModel(names.NewModelTag(m.UUID)) 926 c.Assert(err, jc.ErrorIsNil) 927 defer st.Close() 928 929 s.modelmanager, err = modelmanager.NewModelManagerAPI( 930 common.NewModelManagerBackend(st), nil, s.authoriser, 931 ) 932 c.Assert(err, jc.ErrorIsNil) 933 934 user := names.NewUserTag("other@remote") 935 s.setAPIUser(c, user) 936 937 results, err := s.modelmanager.DestroyModels(params.Entities{ 938 Entities: []params.Entity{ 939 {"model-" + m.UUID}, 940 {"model-9f484882-2f18-4fd2-967d-db9663db7bea"}, 941 {"machine-42"}, 942 }, 943 }) 944 c.Assert(err, jc.ErrorIsNil) 945 c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{{ 946 // we don't have admin access to the model 947 ¶ms.Error{ 948 Message: "permission denied", 949 Code: params.CodeUnauthorized, 950 }, 951 }, { 952 ¶ms.Error{ 953 Message: "model not found", 954 Code: params.CodeNotFound, 955 }, 956 }, { 957 ¶ms.Error{ 958 Message: `"machine-42" is not a valid model tag`, 959 }, 960 }}) 961 962 s.setAPIUser(c, owner) 963 model, err := st.Model() 964 c.Assert(err, jc.ErrorIsNil) 965 c.Assert(model.Life(), gc.Equals, state.Alive) 966 } 967 968 func (s *modelManagerStateSuite) modifyAccess(c *gc.C, user names.UserTag, action params.ModelAction, access params.UserAccessPermission, model names.ModelTag) error { 969 args := params.ModifyModelAccessRequest{ 970 Changes: []params.ModifyModelAccess{{ 971 UserTag: user.String(), 972 Action: action, 973 Access: access, 974 ModelTag: model.String(), 975 }}} 976 977 result, err := s.modelmanager.ModifyModelAccess(args) 978 if err != nil { 979 return err 980 } 981 return result.OneError() 982 } 983 984 func (s *modelManagerStateSuite) grant(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error { 985 return s.modifyAccess(c, user, params.GrantModelAccess, access, model) 986 } 987 988 func (s *modelManagerStateSuite) revoke(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error { 989 return s.modifyAccess(c, user, params.RevokeModelAccess, access, model) 990 } 991 992 func (s *modelManagerStateSuite) TestGrantMissingUserFails(c *gc.C) { 993 s.setAPIUser(c, s.AdminUserTag(c)) 994 st := s.Factory.MakeModel(c, nil) 995 defer st.Close() 996 997 user := names.NewLocalUserTag("foobar") 998 err := s.grant(c, user, params.ModelReadAccess, st.ModelTag()) 999 expectedErr := `could not grant model access: user "foobar" does not exist locally: user "foobar" not found` 1000 c.Assert(err, gc.ErrorMatches, expectedErr) 1001 } 1002 1003 func (s *modelManagerStateSuite) TestGrantMissingModelFails(c *gc.C) { 1004 s.setAPIUser(c, s.AdminUserTag(c)) 1005 user := s.Factory.MakeModelUser(c, nil) 1006 model := names.NewModelTag("17e4bd2d-3e08-4f3d-b945-087be7ebdce4") 1007 err := s.grant(c, user.UserTag, params.ModelReadAccess, model) 1008 expectedErr := `.*model not found` 1009 c.Assert(err, gc.ErrorMatches, expectedErr) 1010 } 1011 1012 func (s *modelManagerStateSuite) TestRevokeAdminLeavesReadAccess(c *gc.C) { 1013 s.setAPIUser(c, s.AdminUserTag(c)) 1014 user := s.Factory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.WriteAccess}) 1015 1016 err := s.revoke(c, user.UserTag, params.ModelWriteAccess, user.Object.(names.ModelTag)) 1017 c.Assert(err, gc.IsNil) 1018 1019 modelUser, err := s.State.UserAccess(user.UserTag, user.Object) 1020 c.Assert(err, jc.ErrorIsNil) 1021 c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess) 1022 } 1023 1024 func (s *modelManagerStateSuite) TestRevokeReadRemovesModelUser(c *gc.C) { 1025 s.setAPIUser(c, s.AdminUserTag(c)) 1026 user := s.Factory.MakeModelUser(c, nil) 1027 1028 err := s.revoke(c, user.UserTag, params.ModelReadAccess, user.Object.(names.ModelTag)) 1029 c.Assert(err, gc.IsNil) 1030 1031 _, err = s.State.UserAccess(user.UserTag, user.Object) 1032 c.Assert(errors.IsNotFound(err), jc.IsTrue) 1033 } 1034 1035 func (s *modelManagerStateSuite) TestRevokeModelMissingUser(c *gc.C) { 1036 s.setAPIUser(c, s.AdminUserTag(c)) 1037 st := s.Factory.MakeModel(c, nil) 1038 defer st.Close() 1039 1040 user := names.NewUserTag("bob") 1041 err := s.revoke(c, user, params.ModelReadAccess, st.ModelTag()) 1042 c.Assert(err, gc.ErrorMatches, `could not revoke model access: model user "bob@local" does not exist`) 1043 1044 _, err = st.UserAccess(user, st.ModelTag()) 1045 c.Assert(errors.IsNotFound(err), jc.IsTrue) 1046 } 1047 1048 func (s *modelManagerStateSuite) TestGrantOnlyGreaterAccess(c *gc.C) { 1049 user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true}) 1050 s.setAPIUser(c, s.AdminUserTag(c)) 1051 st := s.Factory.MakeModel(c, nil) 1052 defer st.Close() 1053 1054 err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag()) 1055 c.Assert(err, jc.ErrorIsNil) 1056 1057 err = s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag()) 1058 c.Assert(err, gc.ErrorMatches, `user already has "read" access or greater`) 1059 } 1060 1061 func (s *modelManagerStateSuite) assertNewUser(c *gc.C, modelUser permission.UserAccess, userTag, creatorTag names.UserTag) { 1062 c.Assert(modelUser.UserTag, gc.Equals, userTag) 1063 c.Assert(modelUser.CreatedBy, gc.Equals, creatorTag) 1064 _, err := s.State.LastModelConnection(modelUser.UserTag) 1065 c.Assert(err, jc.Satisfies, state.IsNeverConnectedError) 1066 } 1067 1068 func (s *modelManagerStateSuite) assertModelAccess(c *gc.C, st *state.State) { 1069 result, err := s.modelmanager.ModelInfo(params.Entities{Entities: []params.Entity{{Tag: st.ModelTag().String()}}}) 1070 c.Assert(err, jc.ErrorIsNil) 1071 c.Assert(result.Results, gc.HasLen, 1) 1072 c.Assert(result.Results[0].Error, gc.IsNil) 1073 } 1074 1075 func (s *modelManagerStateSuite) TestGrantModelAddLocalUser(c *gc.C) { 1076 user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true}) 1077 apiUser := s.AdminUserTag(c) 1078 s.setAPIUser(c, apiUser) 1079 st := s.Factory.MakeModel(c, nil) 1080 defer st.Close() 1081 1082 err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag()) 1083 c.Assert(err, jc.ErrorIsNil) 1084 1085 modelUser, err := st.UserAccess(user.UserTag(), st.ModelTag()) 1086 c.Assert(err, jc.ErrorIsNil) 1087 s.assertNewUser(c, modelUser, user.UserTag(), apiUser) 1088 c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess) 1089 s.setAPIUser(c, user.UserTag()) 1090 s.assertModelAccess(c, st) 1091 } 1092 1093 func (s *modelManagerStateSuite) TestGrantModelAddRemoteUser(c *gc.C) { 1094 userTag := names.NewUserTag("foobar@ubuntuone") 1095 apiUser := s.AdminUserTag(c) 1096 s.setAPIUser(c, apiUser) 1097 st := s.Factory.MakeModel(c, nil) 1098 defer st.Close() 1099 1100 err := s.grant(c, userTag, params.ModelReadAccess, st.ModelTag()) 1101 c.Assert(err, jc.ErrorIsNil) 1102 1103 modelUser, err := st.UserAccess(userTag, st.ModelTag()) 1104 c.Assert(err, jc.ErrorIsNil) 1105 1106 s.assertNewUser(c, modelUser, userTag, apiUser) 1107 c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess) 1108 s.setAPIUser(c, userTag) 1109 s.assertModelAccess(c, st) 1110 } 1111 1112 func (s *modelManagerStateSuite) TestGrantModelAddAdminUser(c *gc.C) { 1113 user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true}) 1114 apiUser := s.AdminUserTag(c) 1115 s.setAPIUser(c, apiUser) 1116 st := s.Factory.MakeModel(c, nil) 1117 defer st.Close() 1118 1119 err := s.grant(c, user.UserTag(), params.ModelWriteAccess, st.ModelTag()) 1120 1121 modelUser, err := st.UserAccess(user.UserTag(), st.ModelTag()) 1122 c.Assert(err, jc.ErrorIsNil) 1123 s.assertNewUser(c, modelUser, user.UserTag(), apiUser) 1124 c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess) 1125 s.setAPIUser(c, user.UserTag()) 1126 s.assertModelAccess(c, st) 1127 } 1128 1129 func (s *modelManagerStateSuite) TestGrantModelIncreaseAccess(c *gc.C) { 1130 s.setAPIUser(c, s.AdminUserTag(c)) 1131 st := s.Factory.MakeModel(c, nil) 1132 defer st.Close() 1133 stFactory := factory.NewFactory(st) 1134 user := stFactory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.ReadAccess}) 1135 1136 err := s.grant(c, user.UserTag, params.ModelWriteAccess, st.ModelTag()) 1137 c.Assert(err, jc.ErrorIsNil) 1138 1139 modelUser, err := st.UserAccess(user.UserTag, st.ModelTag()) 1140 c.Assert(err, jc.ErrorIsNil) 1141 c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess) 1142 } 1143 1144 func (s *modelManagerStateSuite) TestGrantToModelNoAccess(c *gc.C) { 1145 s.setAPIUser(c, s.AdminUserTag(c)) 1146 st := s.Factory.MakeModel(c, nil) 1147 defer st.Close() 1148 1149 apiUser := names.NewUserTag("bob@remote") 1150 s.setAPIUser(c, apiUser) 1151 1152 other := names.NewUserTag("other@remote") 1153 err := s.grant(c, other, params.ModelReadAccess, st.ModelTag()) 1154 c.Assert(err, gc.ErrorMatches, "permission denied") 1155 } 1156 1157 func (s *modelManagerStateSuite) TestGrantToModelReadAccess(c *gc.C) { 1158 s.setAPIUser(c, s.AdminUserTag(c)) 1159 st := s.Factory.MakeModel(c, nil) 1160 defer st.Close() 1161 1162 apiUser := names.NewUserTag("bob@remote") 1163 s.setAPIUser(c, apiUser) 1164 1165 stFactory := factory.NewFactory(st) 1166 stFactory.MakeModelUser(c, &factory.ModelUserParams{ 1167 User: apiUser.Canonical(), Access: permission.ReadAccess}) 1168 1169 other := names.NewUserTag("other@remote") 1170 err := s.grant(c, other, params.ModelReadAccess, st.ModelTag()) 1171 c.Assert(err, gc.ErrorMatches, "permission denied") 1172 } 1173 1174 func (s *modelManagerStateSuite) TestGrantToModelWriteAccess(c *gc.C) { 1175 s.setAPIUser(c, s.AdminUserTag(c)) 1176 st := s.Factory.MakeModel(c, nil) 1177 defer st.Close() 1178 1179 apiUser := names.NewUserTag("admin@remote") 1180 s.setAPIUser(c, apiUser) 1181 stFactory := factory.NewFactory(st) 1182 stFactory.MakeModelUser(c, &factory.ModelUserParams{ 1183 User: apiUser.Canonical(), Access: permission.AdminAccess}) 1184 1185 other := names.NewUserTag("other@remote") 1186 err := s.grant(c, other, params.ModelReadAccess, st.ModelTag()) 1187 c.Assert(err, jc.ErrorIsNil) 1188 1189 modelUser, err := st.UserAccess(other, st.ModelTag()) 1190 c.Assert(err, jc.ErrorIsNil) 1191 s.assertNewUser(c, modelUser, other, apiUser) 1192 c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess) 1193 } 1194 1195 func (s *modelManagerStateSuite) TestGrantModelInvalidUserTag(c *gc.C) { 1196 s.setAPIUser(c, s.AdminUserTag(c)) 1197 for _, testParam := range []struct { 1198 tag string 1199 validTag bool 1200 }{{ 1201 tag: "unit-foo/0", 1202 validTag: true, 1203 }, { 1204 tag: "application-foo", 1205 validTag: true, 1206 }, { 1207 tag: "relation-wordpress:db mysql:db", 1208 validTag: true, 1209 }, { 1210 tag: "machine-0", 1211 validTag: true, 1212 }, { 1213 tag: "user@local", 1214 validTag: false, 1215 }, { 1216 tag: "user-Mua^h^h^h^arh", 1217 validTag: true, 1218 }, { 1219 tag: "user@", 1220 validTag: false, 1221 }, { 1222 tag: "user@ubuntuone", 1223 validTag: false, 1224 }, { 1225 tag: "user@ubuntuone", 1226 validTag: false, 1227 }, { 1228 tag: "@ubuntuone", 1229 validTag: false, 1230 }, { 1231 tag: "in^valid.", 1232 validTag: false, 1233 }, { 1234 tag: "", 1235 validTag: false, 1236 }, 1237 } { 1238 var expectedErr string 1239 errPart := `could not modify model access: "` + regexp.QuoteMeta(testParam.tag) + `" is not a valid ` 1240 1241 if testParam.validTag { 1242 // The string is a valid tag, but not a user tag. 1243 expectedErr = errPart + `user tag` 1244 } else { 1245 // The string is not a valid tag of any kind. 1246 expectedErr = errPart + `tag` 1247 } 1248 1249 args := params.ModifyModelAccessRequest{ 1250 Changes: []params.ModifyModelAccess{{ 1251 ModelTag: "model-deadbeef-0bad-400d-8000-4b1d0d06f00d", 1252 UserTag: testParam.tag, 1253 Action: params.GrantModelAccess, 1254 Access: params.ModelReadAccess, 1255 }}} 1256 1257 result, err := s.modelmanager.ModifyModelAccess(args) 1258 c.Assert(err, jc.ErrorIsNil) 1259 c.Assert(result.OneError(), gc.ErrorMatches, expectedErr) 1260 } 1261 } 1262 1263 func (s *modelManagerStateSuite) TestModifyModelAccessEmptyArgs(c *gc.C) { 1264 s.setAPIUser(c, s.AdminUserTag(c)) 1265 args := params.ModifyModelAccessRequest{Changes: []params.ModifyModelAccess{{}}} 1266 1267 result, err := s.modelmanager.ModifyModelAccess(args) 1268 c.Assert(err, jc.ErrorIsNil) 1269 expectedErr := `could not modify model access: "" model access not valid` 1270 c.Assert(result.OneError(), gc.ErrorMatches, expectedErr) 1271 } 1272 1273 func (s *modelManagerStateSuite) TestModifyModelAccessInvalidAction(c *gc.C) { 1274 s.setAPIUser(c, s.AdminUserTag(c)) 1275 var dance params.ModelAction = "dance" 1276 args := params.ModifyModelAccessRequest{ 1277 Changes: []params.ModifyModelAccess{{ 1278 UserTag: "user-user@local", 1279 Action: dance, 1280 Access: params.ModelReadAccess, 1281 ModelTag: s.State.ModelTag().String(), 1282 }}} 1283 1284 result, err := s.modelmanager.ModifyModelAccess(args) 1285 c.Assert(err, jc.ErrorIsNil) 1286 expectedErr := `unknown action "dance"` 1287 c.Assert(result.OneError(), gc.ErrorMatches, expectedErr) 1288 } 1289 1290 type fakeProvider struct { 1291 environs.EnvironProvider 1292 } 1293 1294 func (*fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) { 1295 return cfg, nil 1296 } 1297 1298 func (*fakeProvider) PrepareForCreateEnvironment(controllerUUID string, cfg *config.Config) (*config.Config, error) { 1299 return cfg, nil 1300 } 1301 1302 func init() { 1303 environs.RegisterProvider("fake", &fakeProvider{}) 1304 }