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() }