github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/modelmanager"
    16  	"github.com/juju/juju/apiserver/params"
    17  	apiservertesting "github.com/juju/juju/apiserver/testing"
    18  	"github.com/juju/juju/environs"
    19  	"github.com/juju/juju/environs/config"
    20  	jujutesting "github.com/juju/juju/juju/testing"
    21  	jujuversion "github.com/juju/juju/version"
    22  	// Register the providers for the field check test
    23  	_ "github.com/juju/juju/provider/azure"
    24  	_ "github.com/juju/juju/provider/ec2"
    25  	_ "github.com/juju/juju/provider/joyent"
    26  	_ "github.com/juju/juju/provider/maas"
    27  	_ "github.com/juju/juju/provider/openstack"
    28  	"github.com/juju/juju/state"
    29  	coretesting "github.com/juju/juju/testing"
    30  	"github.com/juju/juju/testing/factory"
    31  )
    32  
    33  type modelManagerBaseSuite struct {
    34  	jujutesting.JujuConnSuite
    35  
    36  	modelmanager *modelmanager.ModelManagerAPI
    37  	authoriser   apiservertesting.FakeAuthorizer
    38  }
    39  
    40  func (s *modelManagerBaseSuite) SetUpTest(c *gc.C) {
    41  	s.JujuConnSuite.SetUpTest(c)
    42  	s.authoriser = apiservertesting.FakeAuthorizer{
    43  		Tag: s.AdminUserTag(c),
    44  	}
    45  	loggo.GetLogger("juju.apiserver.modelmanager").SetLogLevel(loggo.TRACE)
    46  }
    47  
    48  func (s *modelManagerBaseSuite) setAPIUser(c *gc.C, user names.UserTag) {
    49  	s.authoriser.Tag = user
    50  	modelmanager, err := modelmanager.NewModelManagerAPI(
    51  		modelmanager.NewStateBackend(s.State), s.authoriser,
    52  	)
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	s.modelmanager = modelmanager
    55  }
    56  
    57  type modelManagerSuite struct {
    58  	modelManagerBaseSuite
    59  }
    60  
    61  var _ = gc.Suite(&modelManagerSuite{})
    62  
    63  func (s *modelManagerSuite) TestNewAPIAcceptsClient(c *gc.C) {
    64  	anAuthoriser := s.authoriser
    65  	anAuthoriser.Tag = names.NewUserTag("external@remote")
    66  	endPoint, err := modelmanager.NewModelManagerAPI(
    67  		modelmanager.NewStateBackend(s.State), anAuthoriser,
    68  	)
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(endPoint, gc.NotNil)
    71  }
    72  
    73  func (s *modelManagerSuite) TestNewAPIRefusesNonClient(c *gc.C) {
    74  	anAuthoriser := s.authoriser
    75  	anAuthoriser.Tag = names.NewUnitTag("mysql/0")
    76  	endPoint, err := modelmanager.NewModelManagerAPI(
    77  		modelmanager.NewStateBackend(s.State), anAuthoriser,
    78  	)
    79  	c.Assert(endPoint, gc.IsNil)
    80  	c.Assert(err, gc.ErrorMatches, "permission denied")
    81  }
    82  
    83  func (s *modelManagerSuite) createArgs(c *gc.C, owner names.UserTag) params.ModelCreateArgs {
    84  	return params.ModelCreateArgs{
    85  		OwnerTag: owner.String(),
    86  		Account:  make(map[string]interface{}),
    87  		Config: map[string]interface{}{
    88  			"name":            "test-model",
    89  			"authorized-keys": "ssh-key",
    90  			// And to make it a valid dummy config
    91  			"controller": false,
    92  		},
    93  	}
    94  }
    95  
    96  func (s *modelManagerSuite) createArgsForVersion(c *gc.C, owner names.UserTag, ver interface{}) params.ModelCreateArgs {
    97  	params := s.createArgs(c, owner)
    98  	params.Config["agent-version"] = ver
    99  	return params
   100  }
   101  
   102  func (s *modelManagerSuite) TestUserCanCreateModel(c *gc.C) {
   103  	owner := names.NewUserTag("external@remote")
   104  	s.setAPIUser(c, owner)
   105  	model, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   108  	c.Assert(model.Name, gc.Equals, "test-model")
   109  }
   110  
   111  func (s *modelManagerSuite) TestAdminCanCreateModelForSomeoneElse(c *gc.C) {
   112  	s.setAPIUser(c, s.AdminUserTag(c))
   113  	owner := names.NewUserTag("external@remote")
   114  	model, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   115  	c.Assert(err, jc.ErrorIsNil)
   116  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   117  	c.Assert(model.Name, gc.Equals, "test-model")
   118  	// Make sure that the environment created does actually have the correct
   119  	// owner, and that owner is actually allowed to use the environment.
   120  	newState, err := s.State.ForModel(names.NewModelTag(model.UUID))
   121  	c.Assert(err, jc.ErrorIsNil)
   122  	defer newState.Close()
   123  
   124  	newModel, err := newState.Model()
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	c.Assert(newModel.Owner(), gc.Equals, owner)
   127  	_, err = newState.ModelUser(owner)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  }
   130  
   131  func (s *modelManagerSuite) TestNonAdminCannotCreateModelForSomeoneElse(c *gc.C) {
   132  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   133  	owner := names.NewUserTag("external@remote")
   134  	_, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   135  	c.Assert(err, gc.ErrorMatches, "permission denied")
   136  }
   137  
   138  func (s *modelManagerSuite) TestConfigSkeleton(c *gc.C) {
   139  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   140  
   141  	_, err := s.modelmanager.ConfigSkeleton(
   142  		params.ModelSkeletonConfigArgs{Provider: "ec2"})
   143  	c.Check(err, gc.ErrorMatches, `cannot create new model with credentials for provider type "ec2" on controller with provider type "dummy"`)
   144  	_, err = s.modelmanager.ConfigSkeleton(
   145  		params.ModelSkeletonConfigArgs{Region: "the sun"})
   146  	c.Check(err, gc.ErrorMatches, `region value "the sun" not valid`)
   147  
   148  	skeleton, err := s.modelmanager.ConfigSkeleton(params.ModelSkeletonConfigArgs{})
   149  	c.Assert(err, jc.ErrorIsNil)
   150  
   151  	// The apiPort changes every test run as the dummy provider
   152  	// looks for a random open port.
   153  	apiPort := s.Environ.Config().APIPort()
   154  
   155  	c.Assert(skeleton.Config, jc.DeepEquals, params.ModelConfig{
   156  		"type":            "dummy",
   157  		"controller-uuid": coretesting.ModelTag.Id(),
   158  		"ca-cert":         coretesting.CACert,
   159  		"state-port":      1234,
   160  		"api-port":        apiPort,
   161  	})
   162  }
   163  
   164  func (s *modelManagerSuite) TestCreateModelValidatesConfig(c *gc.C) {
   165  	admin := s.AdminUserTag(c)
   166  	s.setAPIUser(c, admin)
   167  	args := s.createArgs(c, admin)
   168  	args.Config["controller"] = "maybe"
   169  	_, err := s.modelmanager.CreateModel(args)
   170  	c.Assert(err, gc.ErrorMatches,
   171  		"failed to create config: provider validation failed: controller: expected bool, got string\\(\"maybe\"\\)",
   172  	)
   173  }
   174  
   175  func (s *modelManagerSuite) TestCreateModelBadConfig(c *gc.C) {
   176  	owner := names.NewUserTag("external@remote")
   177  	s.setAPIUser(c, owner)
   178  	for i, test := range []struct {
   179  		key      string
   180  		value    interface{}
   181  		errMatch string
   182  	}{
   183  		{
   184  			key:      "uuid",
   185  			value:    "anything",
   186  			errMatch: `failed to create config: uuid is generated, you cannot specify one`,
   187  		}, {
   188  			key:      "type",
   189  			value:    "fake",
   190  			errMatch: `failed to create config: specified type "fake" does not match controller "dummy"`,
   191  		}, {
   192  			key:      "ca-cert",
   193  			value:    coretesting.OtherCACert,
   194  			errMatch: `failed to create config: (?s)specified ca-cert ".*" does not match controller ".*"`,
   195  		}, {
   196  			key:      "state-port",
   197  			value:    9876,
   198  			errMatch: `failed to create config: specified state-port "9876" does not match controller "1234"`,
   199  		}, {
   200  			// The api-port is dynamic, but always in user-space, so > 1024.
   201  			key:      "api-port",
   202  			value:    123,
   203  			errMatch: `failed to create config: specified api-port "123" does not match controller ".*"`,
   204  		},
   205  	} {
   206  		c.Logf("%d: %s", i, test.key)
   207  		args := s.createArgs(c, owner)
   208  		args.Config[test.key] = test.value
   209  		_, err := s.modelmanager.CreateModel(args)
   210  		c.Assert(err, gc.ErrorMatches, test.errMatch)
   211  
   212  	}
   213  }
   214  
   215  func (s *modelManagerSuite) TestCreateModelSameAgentVersion(c *gc.C) {
   216  	admin := s.AdminUserTag(c)
   217  	s.setAPIUser(c, admin)
   218  	args := s.createArgsForVersion(c, admin, jujuversion.Current.String())
   219  	_, err := s.modelmanager.CreateModel(args)
   220  	c.Assert(err, jc.ErrorIsNil)
   221  }
   222  
   223  func (s *modelManagerSuite) TestCreateModelBadAgentVersion(c *gc.C) {
   224  	err := s.BackingState.SetModelAgentVersion(coretesting.FakeVersionNumber)
   225  	c.Assert(err, jc.ErrorIsNil)
   226  
   227  	admin := s.AdminUserTag(c)
   228  	s.setAPIUser(c, admin)
   229  
   230  	bigger := coretesting.FakeVersionNumber
   231  	bigger.Minor += 1
   232  
   233  	smaller := coretesting.FakeVersionNumber
   234  	smaller.Minor -= 1
   235  
   236  	for i, test := range []struct {
   237  		value    interface{}
   238  		errMatch string
   239  	}{
   240  		{
   241  			value:    42,
   242  			errMatch: `failed to create config: agent-version must be a string but has type 'int'`,
   243  		}, {
   244  			value:    "not a number",
   245  			errMatch: `failed to create config: invalid version \"not a number\"`,
   246  		}, {
   247  			value:    bigger.String(),
   248  			errMatch: "failed to create config: agent-version .* cannot be greater than the controller .*",
   249  		}, {
   250  			value:    smaller.String(),
   251  			errMatch: "failed to create config: no tools found for version .*",
   252  		},
   253  	} {
   254  		c.Logf("test %d", i)
   255  		args := s.createArgsForVersion(c, admin, test.value)
   256  		_, err := s.modelmanager.CreateModel(args)
   257  		c.Check(err, gc.ErrorMatches, test.errMatch)
   258  	}
   259  }
   260  
   261  func (s *modelManagerSuite) TestListModelsForSelf(c *gc.C) {
   262  	user := names.NewUserTag("external@remote")
   263  	s.setAPIUser(c, user)
   264  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   265  	c.Assert(err, jc.ErrorIsNil)
   266  	c.Assert(result.UserModels, gc.HasLen, 0)
   267  }
   268  
   269  func (s *modelManagerSuite) TestListModelsForSelfLocalUser(c *gc.C) {
   270  	// When the user's credentials cache stores the simple name, but the
   271  	// api server converts it to a fully qualified name.
   272  	user := names.NewUserTag("local-user")
   273  	s.setAPIUser(c, names.NewUserTag("local-user@local"))
   274  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   275  	c.Assert(err, jc.ErrorIsNil)
   276  	c.Assert(result.UserModels, gc.HasLen, 0)
   277  }
   278  
   279  func (s *modelManagerSuite) checkModelMatches(c *gc.C, env params.Model, expected *state.Model) {
   280  	c.Check(env.Name, gc.Equals, expected.Name())
   281  	c.Check(env.UUID, gc.Equals, expected.UUID())
   282  	c.Check(env.OwnerTag, gc.Equals, expected.Owner().String())
   283  }
   284  
   285  func (s *modelManagerSuite) TestListModelsAdminSelf(c *gc.C) {
   286  	user := s.AdminUserTag(c)
   287  	s.setAPIUser(c, user)
   288  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   289  	c.Assert(err, jc.ErrorIsNil)
   290  	c.Assert(result.UserModels, gc.HasLen, 1)
   291  	expected, err := s.State.Model()
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	s.checkModelMatches(c, result.UserModels[0].Model, expected)
   294  }
   295  
   296  func (s *modelManagerSuite) TestListModelsAdminListsOther(c *gc.C) {
   297  	user := s.AdminUserTag(c)
   298  	s.setAPIUser(c, user)
   299  	other := names.NewUserTag("external@remote")
   300  	result, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
   301  	c.Assert(err, jc.ErrorIsNil)
   302  	c.Assert(result.UserModels, gc.HasLen, 0)
   303  }
   304  
   305  func (s *modelManagerSuite) TestListModelsDenied(c *gc.C) {
   306  	user := names.NewUserTag("external@remote")
   307  	s.setAPIUser(c, user)
   308  	other := names.NewUserTag("other@remote")
   309  	_, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
   310  	c.Assert(err, gc.ErrorMatches, "permission denied")
   311  }
   312  
   313  func (s *modelManagerSuite) TestAdminModelManager(c *gc.C) {
   314  	user := s.AdminUserTag(c)
   315  	s.setAPIUser(c, user)
   316  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsTrue)
   317  }
   318  
   319  func (s *modelManagerSuite) TestNonAdminModelManager(c *gc.C) {
   320  	user := names.NewUserTag("external@remote")
   321  	s.setAPIUser(c, user)
   322  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsFalse)
   323  }
   324  
   325  func (s *modelManagerSuite) modifyAccess(c *gc.C, user names.UserTag, action params.ModelAction, access params.ModelAccessPermission, model names.ModelTag) error {
   326  	args := params.ModifyModelAccessRequest{
   327  		Changes: []params.ModifyModelAccess{{
   328  			UserTag:  user.String(),
   329  			Action:   action,
   330  			Access:   access,
   331  			ModelTag: model.String(),
   332  		}}}
   333  	result, err := s.modelmanager.ModifyModelAccess(args)
   334  	c.Assert(err, jc.ErrorIsNil)
   335  	return result.OneError()
   336  }
   337  
   338  func (s *modelManagerSuite) grant(c *gc.C, user names.UserTag, access params.ModelAccessPermission, model names.ModelTag) error {
   339  	return s.modifyAccess(c, user, params.GrantModelAccess, access, model)
   340  }
   341  
   342  func (s *modelManagerSuite) revoke(c *gc.C, user names.UserTag, access params.ModelAccessPermission, model names.ModelTag) error {
   343  	return s.modifyAccess(c, user, params.RevokeModelAccess, access, model)
   344  }
   345  
   346  func (s *modelManagerSuite) TestGrantMissingUserFails(c *gc.C) {
   347  	s.setAPIUser(c, s.AdminUserTag(c))
   348  	st := s.Factory.MakeModel(c, nil)
   349  	defer st.Close()
   350  
   351  	user := names.NewLocalUserTag("foobar")
   352  	err := s.grant(c, user, params.ModelReadAccess, st.ModelTag())
   353  	expectedErr := `could not grant model access: user "foobar" does not exist locally: user "foobar" not found`
   354  	c.Assert(err, gc.ErrorMatches, expectedErr)
   355  }
   356  
   357  func (s *modelManagerSuite) TestGrantMissingModelFails(c *gc.C) {
   358  	s.setAPIUser(c, s.AdminUserTag(c))
   359  	user := s.Factory.MakeModelUser(c, nil)
   360  	model := names.NewModelTag("17e4bd2d-3e08-4f3d-b945-087be7ebdce4")
   361  	err := s.grant(c, user.UserTag(), params.ModelReadAccess, model)
   362  	expectedErr := `model not found`
   363  	c.Assert(err, gc.ErrorMatches, expectedErr)
   364  }
   365  
   366  func (s *modelManagerSuite) TestRevokeAdminLeavesReadAccess(c *gc.C) {
   367  	s.setAPIUser(c, s.AdminUserTag(c))
   368  	user := s.Factory.MakeModelUser(c, &factory.ModelUserParams{Access: state.ModelAdminAccess})
   369  
   370  	err := s.revoke(c, user.UserTag(), params.ModelWriteAccess, user.ModelTag())
   371  	c.Assert(err, gc.IsNil)
   372  
   373  	modelUser, err := s.State.ModelUser(user.UserTag())
   374  	c.Assert(err, jc.ErrorIsNil)
   375  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
   376  }
   377  
   378  func (s *modelManagerSuite) TestRevokeReadRemovesModelUser(c *gc.C) {
   379  	s.setAPIUser(c, s.AdminUserTag(c))
   380  	user := s.Factory.MakeModelUser(c, nil)
   381  
   382  	err := s.revoke(c, user.UserTag(), params.ModelReadAccess, user.ModelTag())
   383  	c.Assert(err, gc.IsNil)
   384  
   385  	_, err = s.State.ModelUser(user.UserTag())
   386  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
   387  }
   388  
   389  func (s *modelManagerSuite) TestRevokeModelMissingUser(c *gc.C) {
   390  	s.setAPIUser(c, s.AdminUserTag(c))
   391  	st := s.Factory.MakeModel(c, nil)
   392  	defer st.Close()
   393  
   394  	user := names.NewUserTag("bob")
   395  	err := s.revoke(c, user, params.ModelReadAccess, st.ModelTag())
   396  	c.Assert(err, gc.ErrorMatches, `could not revoke model access: model user "bob@local" does not exist`)
   397  
   398  	_, err = st.ModelUser(user)
   399  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
   400  }
   401  
   402  func (s *modelManagerSuite) TestGrantOnlyGreaterAccess(c *gc.C) {
   403  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
   404  	s.setAPIUser(c, s.AdminUserTag(c))
   405  	st := s.Factory.MakeModel(c, nil)
   406  	defer st.Close()
   407  
   408  	err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
   409  	c.Assert(err, jc.ErrorIsNil)
   410  
   411  	err = s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
   412  	c.Assert(err, gc.ErrorMatches, `user already has "read" access`)
   413  }
   414  
   415  func (s *modelManagerSuite) assertNewUser(c *gc.C, modelUser *state.ModelUser, userTag, creatorTag names.UserTag) {
   416  	c.Assert(modelUser.UserTag(), gc.Equals, userTag)
   417  	c.Assert(modelUser.CreatedBy(), gc.Equals, creatorTag.Canonical())
   418  	_, err := modelUser.LastConnection()
   419  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
   420  }
   421  
   422  func (s *modelManagerSuite) TestGrantModelAddLocalUser(c *gc.C) {
   423  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
   424  	apiUser := s.AdminUserTag(c)
   425  	s.setAPIUser(c, apiUser)
   426  	st := s.Factory.MakeModel(c, nil)
   427  	defer st.Close()
   428  
   429  	err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
   430  	c.Assert(err, jc.ErrorIsNil)
   431  
   432  	modelUser, err := st.ModelUser(user.UserTag())
   433  	c.Assert(err, jc.ErrorIsNil)
   434  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
   435  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
   436  }
   437  
   438  func (s *modelManagerSuite) TestGrantModelAddRemoteUser(c *gc.C) {
   439  	userTag := names.NewUserTag("foobar@ubuntuone")
   440  	apiUser := s.AdminUserTag(c)
   441  	s.setAPIUser(c, apiUser)
   442  	st := s.Factory.MakeModel(c, nil)
   443  	defer st.Close()
   444  
   445  	err := s.grant(c, userTag, params.ModelReadAccess, st.ModelTag())
   446  	c.Assert(err, jc.ErrorIsNil)
   447  
   448  	modelUser, err := st.ModelUser(userTag)
   449  	c.Assert(err, jc.ErrorIsNil)
   450  
   451  	s.assertNewUser(c, modelUser, userTag, apiUser)
   452  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
   453  }
   454  
   455  func (s *modelManagerSuite) TestGrantModelAddAdminUser(c *gc.C) {
   456  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
   457  	apiUser := s.AdminUserTag(c)
   458  	s.setAPIUser(c, apiUser)
   459  	st := s.Factory.MakeModel(c, nil)
   460  	defer st.Close()
   461  
   462  	err := s.grant(c, user.UserTag(), params.ModelWriteAccess, st.ModelTag())
   463  
   464  	modelUser, err := st.ModelUser(user.UserTag())
   465  	c.Assert(err, jc.ErrorIsNil)
   466  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
   467  	c.Assert(modelUser.ReadOnly(), jc.IsFalse)
   468  }
   469  
   470  func (s *modelManagerSuite) TestGrantModelIncreaseAccess(c *gc.C) {
   471  	s.setAPIUser(c, s.AdminUserTag(c))
   472  	st := s.Factory.MakeModel(c, nil)
   473  	defer st.Close()
   474  	stFactory := factory.NewFactory(st)
   475  	user := stFactory.MakeModelUser(c, &factory.ModelUserParams{Access: state.ModelReadAccess})
   476  
   477  	err := s.grant(c, user.UserTag(), params.ModelWriteAccess, st.ModelTag())
   478  	c.Assert(err, jc.ErrorIsNil)
   479  
   480  	modelUser, err := st.ModelUser(user.UserTag())
   481  	c.Assert(err, jc.ErrorIsNil)
   482  	c.Assert(modelUser.Access(), gc.Equals, state.ModelAdminAccess)
   483  }
   484  
   485  func (s *modelManagerSuite) TestGrantToModelNoAccess(c *gc.C) {
   486  	apiUser := names.NewUserTag("bob@remote")
   487  	s.setAPIUser(c, apiUser)
   488  
   489  	st := s.Factory.MakeModel(c, nil)
   490  	defer st.Close()
   491  
   492  	other := names.NewUserTag("other@remote")
   493  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
   494  	c.Assert(err, gc.ErrorMatches, "permission denied")
   495  }
   496  
   497  func (s *modelManagerSuite) TestGrantToModelReadAccess(c *gc.C) {
   498  	apiUser := names.NewUserTag("bob@remote")
   499  	s.setAPIUser(c, apiUser)
   500  
   501  	st := s.Factory.MakeModel(c, nil)
   502  	defer st.Close()
   503  	stFactory := factory.NewFactory(st)
   504  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
   505  		User: apiUser.Canonical(), Access: state.ModelReadAccess})
   506  
   507  	other := names.NewUserTag("other@remote")
   508  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
   509  	c.Assert(err, gc.ErrorMatches, "permission denied")
   510  }
   511  
   512  func (s *modelManagerSuite) TestGrantToModelWriteAccess(c *gc.C) {
   513  	apiUser := names.NewUserTag("bob@remote")
   514  	s.setAPIUser(c, apiUser)
   515  
   516  	st := s.Factory.MakeModel(c, nil)
   517  	defer st.Close()
   518  	stFactory := factory.NewFactory(st)
   519  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
   520  		User: apiUser.Canonical(), Access: state.ModelAdminAccess})
   521  
   522  	other := names.NewUserTag("other@remote")
   523  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
   524  	c.Assert(err, jc.ErrorIsNil)
   525  
   526  	modelUser, err := st.ModelUser(other)
   527  	c.Assert(err, jc.ErrorIsNil)
   528  	s.assertNewUser(c, modelUser, other, apiUser)
   529  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
   530  }
   531  
   532  func (s *modelManagerSuite) TestGrantModelInvalidUserTag(c *gc.C) {
   533  	s.setAPIUser(c, s.AdminUserTag(c))
   534  	for _, testParam := range []struct {
   535  		tag      string
   536  		validTag bool
   537  	}{{
   538  		tag:      "unit-foo/0",
   539  		validTag: true,
   540  	}, {
   541  		tag:      "service-foo",
   542  		validTag: true,
   543  	}, {
   544  		tag:      "relation-wordpress:db mysql:db",
   545  		validTag: true,
   546  	}, {
   547  		tag:      "machine-0",
   548  		validTag: true,
   549  	}, {
   550  		tag:      "user@local",
   551  		validTag: false,
   552  	}, {
   553  		tag:      "user-Mua^h^h^h^arh",
   554  		validTag: true,
   555  	}, {
   556  		tag:      "user@",
   557  		validTag: false,
   558  	}, {
   559  		tag:      "user@ubuntuone",
   560  		validTag: false,
   561  	}, {
   562  		tag:      "user@ubuntuone",
   563  		validTag: false,
   564  	}, {
   565  		tag:      "@ubuntuone",
   566  		validTag: false,
   567  	}, {
   568  		tag:      "in^valid.",
   569  		validTag: false,
   570  	}, {
   571  		tag:      "",
   572  		validTag: false,
   573  	},
   574  	} {
   575  		var expectedErr string
   576  		errPart := `could not modify model access: "` + regexp.QuoteMeta(testParam.tag) + `" is not a valid `
   577  
   578  		if testParam.validTag {
   579  			// The string is a valid tag, but not a user tag.
   580  			expectedErr = errPart + `user tag`
   581  		} else {
   582  			// The string is not a valid tag of any kind.
   583  			expectedErr = errPart + `tag`
   584  		}
   585  
   586  		args := params.ModifyModelAccessRequest{
   587  			Changes: []params.ModifyModelAccess{{
   588  				UserTag: testParam.tag,
   589  				Action:  params.GrantModelAccess,
   590  				Access:  params.ModelReadAccess,
   591  			}}}
   592  
   593  		result, err := s.modelmanager.ModifyModelAccess(args)
   594  		c.Assert(err, jc.ErrorIsNil)
   595  		c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
   596  	}
   597  }
   598  
   599  func (s *modelManagerSuite) TestModifyModelAccessEmptyArgs(c *gc.C) {
   600  	s.setAPIUser(c, s.AdminUserTag(c))
   601  	args := params.ModifyModelAccessRequest{Changes: []params.ModifyModelAccess{{}}}
   602  
   603  	result, err := s.modelmanager.ModifyModelAccess(args)
   604  	c.Assert(err, jc.ErrorIsNil)
   605  	expectedErr := `could not modify model access: invalid model access permission ""`
   606  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
   607  }
   608  
   609  func (s *modelManagerSuite) TestModifyModelAccessInvalidAction(c *gc.C) {
   610  	s.setAPIUser(c, s.AdminUserTag(c))
   611  	var dance params.ModelAction = "dance"
   612  	args := params.ModifyModelAccessRequest{
   613  		Changes: []params.ModifyModelAccess{{
   614  			UserTag:  "user-user@local",
   615  			Action:   dance,
   616  			Access:   params.ModelReadAccess,
   617  			ModelTag: s.State.ModelTag().String(),
   618  		}}}
   619  
   620  	result, err := s.modelmanager.ModifyModelAccess(args)
   621  	c.Assert(err, jc.ErrorIsNil)
   622  	expectedErr := `unknown action "dance"`
   623  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
   624  }
   625  
   626  type fakeProvider struct {
   627  	environs.EnvironProvider
   628  }
   629  
   630  func (*fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
   631  	return cfg, nil
   632  }
   633  
   634  func (*fakeProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
   635  	return cfg, nil
   636  }
   637  
   638  func init() {
   639  	environs.RegisterProvider("fake", &fakeProvider{})
   640  }