github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/modeluser_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/testing"
    18  	"github.com/juju/juju/testing/factory"
    19  )
    20  
    21  type ModelUserSuite struct {
    22  	ConnSuite
    23  }
    24  
    25  var _ = gc.Suite(&ModelUserSuite{})
    26  
    27  func (s *ModelUserSuite) TestAddModelUser(c *gc.C) {
    28  	now := state.NowToTheSecond()
    29  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", NoModelUser: true})
    30  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
    31  	modelUser, err := s.State.AddModelUser(state.ModelUserSpec{
    32  		User: user.UserTag(), CreatedBy: createdBy.UserTag()})
    33  	c.Assert(err, jc.ErrorIsNil)
    34  
    35  	c.Assert(modelUser.ID(), gc.Equals, fmt.Sprintf("%s:validusername@local", s.modelTag.Id()))
    36  	c.Assert(modelUser.ModelTag(), gc.Equals, s.modelTag)
    37  	c.Assert(modelUser.UserName(), gc.Equals, "validusername@local")
    38  	c.Assert(modelUser.DisplayName(), gc.Equals, user.DisplayName())
    39  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
    40  	c.Assert(modelUser.CreatedBy(), gc.Equals, "createdby@local")
    41  	c.Assert(modelUser.DateCreated().Equal(now) || modelUser.DateCreated().After(now), jc.IsTrue)
    42  	when, err := modelUser.LastConnection()
    43  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
    44  	c.Assert(when.IsZero(), jc.IsTrue)
    45  
    46  	modelUser, err = s.State.ModelUser(user.UserTag())
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	c.Assert(modelUser.ID(), gc.Equals, fmt.Sprintf("%s:validusername@local", s.modelTag.Id()))
    49  	c.Assert(modelUser.ModelTag(), gc.Equals, s.modelTag)
    50  	c.Assert(modelUser.UserName(), gc.Equals, "validusername@local")
    51  	c.Assert(modelUser.DisplayName(), gc.Equals, user.DisplayName())
    52  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
    53  	c.Assert(modelUser.CreatedBy(), gc.Equals, "createdby@local")
    54  	c.Assert(modelUser.DateCreated().Equal(now) || modelUser.DateCreated().After(now), jc.IsTrue)
    55  	when, err = modelUser.LastConnection()
    56  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
    57  	c.Assert(when.IsZero(), jc.IsTrue)
    58  }
    59  
    60  func (s *ModelUserSuite) TestAddReadOnlyModelUser(c *gc.C) {
    61  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", NoModelUser: true})
    62  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
    63  	modelUser, err := s.State.AddModelUser(state.ModelUserSpec{
    64  		User: user.UserTag(), CreatedBy: createdBy.UserTag(), Access: state.ModelReadAccess})
    65  	c.Assert(err, jc.ErrorIsNil)
    66  
    67  	c.Assert(modelUser.UserName(), gc.Equals, "validusername@local")
    68  	c.Assert(modelUser.DisplayName(), gc.Equals, user.DisplayName())
    69  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
    70  
    71  	// Make sure that it is set when we read the user out.
    72  	modelUser, err = s.State.ModelUser(user.UserTag())
    73  	c.Assert(err, jc.ErrorIsNil)
    74  	c.Assert(modelUser.UserName(), gc.Equals, "validusername@local")
    75  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
    76  }
    77  
    78  func (s *ModelUserSuite) TestDefaultAccessModelUser(c *gc.C) {
    79  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", NoModelUser: true})
    80  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
    81  	modelUser, err := s.State.AddModelUser(state.ModelUserSpec{
    82  		User: user.UserTag(), CreatedBy: createdBy.UserTag()})
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
    85  	c.Assert(modelUser.Access(), gc.Equals, state.ModelReadAccess)
    86  }
    87  
    88  func (s *ModelUserSuite) TestSetAccessModelUser(c *gc.C) {
    89  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", NoModelUser: true})
    90  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
    91  	modelUser, err := s.State.AddModelUser(state.ModelUserSpec{
    92  		User: user.UserTag(), CreatedBy: createdBy.UserTag(), Access: state.ModelAdminAccess})
    93  	c.Assert(err, jc.ErrorIsNil)
    94  	c.Assert(modelUser.ReadOnly(), jc.IsFalse)
    95  	c.Assert(modelUser.Access(), gc.Equals, state.ModelAdminAccess)
    96  
    97  	modelUser.SetAccess(state.ModelReadAccess)
    98  
    99  	modelUser, err = s.State.ModelUser(user.UserTag())
   100  	c.Assert(err, jc.ErrorIsNil)
   101  	c.Assert(modelUser.ReadOnly(), jc.IsTrue)
   102  	c.Assert(modelUser.Access(), gc.Equals, state.ModelReadAccess)
   103  }
   104  
   105  func (s *ModelUserSuite) TestCaseUserNameVsId(c *gc.C) {
   106  	model, err := s.State.Model()
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	user, err := s.State.AddModelUser(state.ModelUserSpec{
   110  		User:      names.NewUserTag("Bob@RandomProvider"),
   111  		CreatedBy: model.Owner()})
   112  	c.Assert(err, gc.IsNil)
   113  	c.Assert(user.UserName(), gc.Equals, "Bob@RandomProvider")
   114  	c.Assert(user.ID(), gc.Equals, state.DocID(s.State, "bob@randomprovider"))
   115  }
   116  
   117  func (s *ModelUserSuite) TestCaseSensitiveModelUserErrors(c *gc.C) {
   118  	model, err := s.State.Model()
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	s.Factory.MakeModelUser(c, &factory.ModelUserParams{User: "Bob@ubuntuone"})
   121  
   122  	_, err = s.State.AddModelUser(state.ModelUserSpec{
   123  		User:      names.NewUserTag("boB@ubuntuone"),
   124  		CreatedBy: model.Owner()})
   125  	c.Assert(err, gc.ErrorMatches, `model user "boB@ubuntuone" already exists`)
   126  	c.Assert(errors.IsAlreadyExists(err), jc.IsTrue)
   127  }
   128  
   129  func (s *ModelUserSuite) TestCaseInsensitiveLookupInMultiEnvirons(c *gc.C) {
   130  	assertIsolated := func(st1, st2 *state.State, usernames ...string) {
   131  		f := factory.NewFactory(st1)
   132  		expectedUser := f.MakeModelUser(c, &factory.ModelUserParams{User: usernames[0]})
   133  
   134  		// assert case insensitive lookup for each username
   135  		for _, username := range usernames {
   136  			userTag := names.NewUserTag(username)
   137  			obtainedUser, err := st1.ModelUser(userTag)
   138  			c.Assert(err, jc.ErrorIsNil)
   139  			c.Assert(obtainedUser, gc.DeepEquals, expectedUser)
   140  
   141  			_, err = st2.ModelUser(userTag)
   142  			c.Assert(errors.IsNotFound(err), jc.IsTrue)
   143  		}
   144  	}
   145  
   146  	otherSt := s.Factory.MakeModel(c, nil)
   147  	defer otherSt.Close()
   148  	assertIsolated(s.State, otherSt,
   149  		"Bob@UbuntuOne",
   150  		"bob@ubuntuone",
   151  		"BOB@UBUNTUONE",
   152  	)
   153  	assertIsolated(otherSt, s.State,
   154  		"Sam@UbuntuOne",
   155  		"sam@ubuntuone",
   156  		"SAM@UBUNTUONE",
   157  	)
   158  }
   159  
   160  func (s *ModelUserSuite) TestAddModelDisplayName(c *gc.C) {
   161  	modelUserDefault := s.Factory.MakeModelUser(c, nil)
   162  	c.Assert(modelUserDefault.DisplayName(), gc.Matches, "display name-[0-9]*")
   163  
   164  	modelUser := s.Factory.MakeModelUser(c, &factory.ModelUserParams{DisplayName: "Override user display name"})
   165  	c.Assert(modelUser.DisplayName(), gc.Equals, "Override user display name")
   166  }
   167  
   168  func (s *ModelUserSuite) TestAddModelNoUserFails(c *gc.C) {
   169  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
   170  	_, err := s.State.AddModelUser(state.ModelUserSpec{
   171  		User:      names.NewLocalUserTag("validusername"),
   172  		CreatedBy: createdBy.UserTag()})
   173  	c.Assert(err, gc.ErrorMatches, `user "validusername" does not exist locally: user "validusername" not found`)
   174  }
   175  
   176  func (s *ModelUserSuite) TestAddModelNoCreatedByUserFails(c *gc.C) {
   177  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername"})
   178  	_, err := s.State.AddModelUser(state.ModelUserSpec{
   179  		User:      user.UserTag(),
   180  		CreatedBy: names.NewLocalUserTag("createdby")})
   181  	c.Assert(err, gc.ErrorMatches, `createdBy user "createdby" does not exist locally: user "createdby" not found`)
   182  }
   183  
   184  func (s *ModelUserSuite) TestRemoveModelUser(c *gc.C) {
   185  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validUsername"})
   186  	_, err := s.State.ModelUser(user.UserTag())
   187  	c.Assert(err, jc.ErrorIsNil)
   188  
   189  	err = s.State.RemoveModelUser(user.UserTag())
   190  	c.Assert(err, jc.ErrorIsNil)
   191  
   192  	_, err = s.State.ModelUser(user.UserTag())
   193  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   194  }
   195  
   196  func (s *ModelUserSuite) TestRemoveModelUserFails(c *gc.C) {
   197  	user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true})
   198  	err := s.State.RemoveModelUser(user.UserTag())
   199  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   200  }
   201  
   202  func (s *ModelUserSuite) TestUpdateLastConnection(c *gc.C) {
   203  	now := state.NowToTheSecond()
   204  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
   205  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", Creator: createdBy.Tag()})
   206  	modelUser, err := s.State.ModelUser(user.UserTag())
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	err = modelUser.UpdateLastConnection()
   209  	c.Assert(err, jc.ErrorIsNil)
   210  	when, err := modelUser.LastConnection()
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	// It is possible that the update is done over a second boundary, so we need
   213  	// to check for after now as well as equal.
   214  	c.Assert(when.After(now) || when.Equal(now), jc.IsTrue)
   215  }
   216  
   217  func (s *ModelUserSuite) TestUpdateLastConnectionTwoModelUsers(c *gc.C) {
   218  	now := state.NowToTheSecond()
   219  
   220  	// Create a user and add them to the inital model.
   221  	createdBy := s.Factory.MakeUser(c, &factory.UserParams{Name: "createdby"})
   222  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "validusername", Creator: createdBy.Tag()})
   223  	modelUser, err := s.State.ModelUser(user.UserTag())
   224  	c.Assert(err, jc.ErrorIsNil)
   225  
   226  	// Create a second model and add the same user to this.
   227  	st2 := s.Factory.MakeModel(c, nil)
   228  	defer st2.Close()
   229  	modelUser2, err := st2.AddModelUser(state.ModelUserSpec{
   230  		User:      user.UserTag(),
   231  		CreatedBy: createdBy.UserTag()})
   232  	c.Assert(err, jc.ErrorIsNil)
   233  
   234  	// Now we have two model users with the same username. Ensure we get
   235  	// separate last connections.
   236  
   237  	// Connect modelUser and get last connection.
   238  	err = modelUser.UpdateLastConnection()
   239  	c.Assert(err, jc.ErrorIsNil)
   240  	when, err := modelUser.LastConnection()
   241  	c.Assert(err, jc.ErrorIsNil)
   242  	c.Assert(when.After(now) || when.Equal(now), jc.IsTrue)
   243  
   244  	// Try to get last connection for modelUser2. As they have never connected,
   245  	// we expect to get an error.
   246  	_, err = modelUser2.LastConnection()
   247  	c.Assert(err, gc.ErrorMatches, `never connected: "validusername@local"`)
   248  
   249  	// Connect modelUser2 and get last connection.
   250  	err = modelUser2.UpdateLastConnection()
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	when, err = modelUser2.LastConnection()
   253  	c.Assert(err, jc.ErrorIsNil)
   254  	c.Assert(when.After(now) || when.Equal(now), jc.IsTrue)
   255  }
   256  
   257  func (s *ModelUserSuite) TestModelsForUserNone(c *gc.C) {
   258  	tag := names.NewUserTag("non-existent@remote")
   259  	models, err := s.State.ModelsForUser(tag)
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	c.Assert(models, gc.HasLen, 0)
   262  }
   263  
   264  func (s *ModelUserSuite) TestModelsForUserNewLocalUser(c *gc.C) {
   265  	user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true})
   266  	models, err := s.State.ModelsForUser(user.UserTag())
   267  	c.Assert(err, jc.ErrorIsNil)
   268  	c.Assert(models, gc.HasLen, 0)
   269  }
   270  
   271  func (s *ModelUserSuite) TestModelsForUser(c *gc.C) {
   272  	user := s.Factory.MakeUser(c, nil)
   273  	models, err := s.State.ModelsForUser(user.UserTag())
   274  	c.Assert(err, jc.ErrorIsNil)
   275  	c.Assert(models, gc.HasLen, 1)
   276  	c.Assert(models[0].UUID(), gc.Equals, s.State.ModelUUID())
   277  	when, err := models[0].LastConnection()
   278  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
   279  	c.Assert(when.IsZero(), jc.IsTrue)
   280  }
   281  
   282  func (s *ModelUserSuite) newEnvWithOwner(c *gc.C, name string, owner names.UserTag) *state.Model {
   283  	// Don't use the factory to call MakeModel because it may at some
   284  	// time in the future be modified to do additional things.  Instead call
   285  	// the state method directly to create an model to make sure that
   286  	// the owner is able to access the model.
   287  	uuid, err := utils.NewUUID()
   288  	c.Assert(err, jc.ErrorIsNil)
   289  	cfg := testing.CustomModelConfig(c, testing.Attrs{
   290  		"name": name,
   291  		"uuid": uuid.String(),
   292  	})
   293  	model, st, err := s.State.NewModel(state.ModelArgs{Config: cfg, Owner: owner})
   294  	c.Assert(err, jc.ErrorIsNil)
   295  	defer st.Close()
   296  	return model
   297  }
   298  
   299  func (s *ModelUserSuite) TestModelsForUserEnvOwner(c *gc.C) {
   300  	owner := names.NewUserTag("external@remote")
   301  	model := s.newEnvWithOwner(c, "test-model", owner)
   302  
   303  	models, err := s.State.ModelsForUser(owner)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  	c.Assert(models, gc.HasLen, 1)
   306  	s.checkSameModel(c, models[0].Model, model)
   307  }
   308  
   309  func (s *ModelUserSuite) checkSameModel(c *gc.C, env1, env2 *state.Model) {
   310  	c.Check(env1.Name(), gc.Equals, env2.Name())
   311  	c.Check(env1.UUID(), gc.Equals, env2.UUID())
   312  }
   313  
   314  func (s *ModelUserSuite) newEnvWithUser(c *gc.C, name string, user names.UserTag) *state.Model {
   315  	envState := s.Factory.MakeModel(c, &factory.ModelParams{Name: name})
   316  	defer envState.Close()
   317  	newEnv, err := envState.Model()
   318  	c.Assert(err, jc.ErrorIsNil)
   319  
   320  	_, err = envState.AddModelUser(state.ModelUserSpec{
   321  		User: user, CreatedBy: newEnv.Owner()})
   322  	c.Assert(err, jc.ErrorIsNil)
   323  	return newEnv
   324  }
   325  
   326  func (s *ModelUserSuite) TestModelsForUserOfNewEnv(c *gc.C) {
   327  	userTag := names.NewUserTag("external@remote")
   328  	model := s.newEnvWithUser(c, "test-model", userTag)
   329  
   330  	models, err := s.State.ModelsForUser(userTag)
   331  	c.Assert(err, jc.ErrorIsNil)
   332  	c.Assert(models, gc.HasLen, 1)
   333  	s.checkSameModel(c, models[0].Model, model)
   334  }
   335  
   336  func (s *ModelUserSuite) TestModelsForUserMultiple(c *gc.C) {
   337  	userTag := names.NewUserTag("external@remote")
   338  	expected := []*state.Model{
   339  		s.newEnvWithUser(c, "user1", userTag),
   340  		s.newEnvWithUser(c, "user2", userTag),
   341  		s.newEnvWithUser(c, "user3", userTag),
   342  		s.newEnvWithOwner(c, "owner1", userTag),
   343  		s.newEnvWithOwner(c, "owner2", userTag),
   344  	}
   345  	sort.Sort(UUIDOrder(expected))
   346  
   347  	models, err := s.State.ModelsForUser(userTag)
   348  	c.Assert(err, jc.ErrorIsNil)
   349  	c.Assert(models, gc.HasLen, len(expected))
   350  	sort.Sort(userUUIDOrder(models))
   351  	for i := range expected {
   352  		s.checkSameModel(c, models[i].Model, expected[i])
   353  	}
   354  }
   355  
   356  func (s *ModelUserSuite) TestIsControllerAdministrator(c *gc.C) {
   357  	isAdmin, err := s.State.IsControllerAdministrator(s.Owner)
   358  	c.Assert(err, jc.ErrorIsNil)
   359  	c.Assert(isAdmin, jc.IsTrue)
   360  
   361  	user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true})
   362  	isAdmin, err = s.State.IsControllerAdministrator(user.UserTag())
   363  	c.Assert(err, jc.ErrorIsNil)
   364  	c.Assert(isAdmin, jc.IsFalse)
   365  
   366  	s.Factory.MakeModelUser(c, &factory.ModelUserParams{User: user.UserTag().Canonical()})
   367  	isAdmin, err = s.State.IsControllerAdministrator(user.UserTag())
   368  	c.Assert(err, jc.ErrorIsNil)
   369  	c.Assert(isAdmin, jc.IsTrue)
   370  
   371  	readonly := s.Factory.MakeModelUser(c, &factory.ModelUserParams{Access: state.ModelReadAccess})
   372  	isAdmin, err = s.State.IsControllerAdministrator(readonly.UserTag())
   373  	c.Assert(err, jc.ErrorIsNil)
   374  	c.Assert(isAdmin, jc.IsFalse)
   375  }
   376  
   377  func (s *ModelUserSuite) TestIsControllerAdministratorFromOtherState(c *gc.C) {
   378  	user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true})
   379  
   380  	otherState := s.Factory.MakeModel(c, &factory.ModelParams{Owner: user.UserTag()})
   381  	defer otherState.Close()
   382  
   383  	isAdmin, err := otherState.IsControllerAdministrator(user.UserTag())
   384  	c.Assert(err, jc.ErrorIsNil)
   385  	c.Assert(isAdmin, jc.IsFalse)
   386  
   387  	isAdmin, err = otherState.IsControllerAdministrator(s.Owner)
   388  	c.Assert(err, jc.ErrorIsNil)
   389  	c.Assert(isAdmin, jc.IsTrue)
   390  }
   391  
   392  // UUIDOrder is used to sort the models into a stable order
   393  type UUIDOrder []*state.Model
   394  
   395  func (a UUIDOrder) Len() int           { return len(a) }
   396  func (a UUIDOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   397  func (a UUIDOrder) Less(i, j int) bool { return a[i].UUID() < a[j].UUID() }
   398  
   399  // userUUIDOrder is used to sort the UserModels into a stable order
   400  type userUUIDOrder []*state.UserModel
   401  
   402  func (a userUUIDOrder) Len() int           { return len(a) }
   403  func (a userUUIDOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   404  func (a userUUIDOrder) Less(i, j int) bool { return a[i].UUID() < a[j].UUID() }