usercache.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package db
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "runtime/debug"
  20. "time"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/util/httputils"
  25. "yunion.io/x/sqlchemy"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/mcclient/auth"
  30. modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  31. "yunion.io/x/onecloud/pkg/util/stringutils2"
  32. )
  33. var (
  34. DefaultUserFetcher func(ctx context.Context, id string) (*SUser, error)
  35. )
  36. type SUserCacheManager struct {
  37. SKeystoneCacheObjectManager
  38. }
  39. type SUser struct {
  40. SKeystoneCacheObject
  41. }
  42. func (user *SUser) GetModelManager() IModelManager {
  43. return UserCacheManager
  44. }
  45. var UserCacheManager *SUserCacheManager
  46. func init() {
  47. UserCacheManager = &SUserCacheManager{
  48. NewKeystoneCacheObjectManager(SUser{}, "users_cache_tbl", "user_cache", "user_caches")}
  49. // log.Debugf("initialize user cache manager %s", UserCacheManager.KeywordPlural())
  50. UserCacheManager.SetVirtualObject(UserCacheManager)
  51. DefaultUserFetcher = UserCacheManager.FetchUserByIdOrName
  52. }
  53. func (manager *SUserCacheManager) updateUserCache(ctx context.Context, userCred mcclient.TokenCredential) {
  54. manager.Save(ctx, userCred.GetUserId(), userCred.GetUserName(),
  55. userCred.GetDomainId(), userCred.GetDomainName(), "")
  56. }
  57. func (manager *SUserCacheManager) FetchUserByIdOrName(ctx context.Context, idStr string) (*SUser, error) {
  58. return manager.fetchUser(ctx, idStr, false, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  59. if stringutils2.IsUtf8(idStr) {
  60. return q.Equals("name", idStr)
  61. } else {
  62. return q.Filter(sqlchemy.OR(
  63. sqlchemy.Equals(q.Field("id"), idStr),
  64. sqlchemy.Equals(q.Field("name"), idStr),
  65. ))
  66. }
  67. })
  68. }
  69. func (manager *SUserCacheManager) FetchUserById(ctx context.Context, idStr string) (*SUser, error) {
  70. return manager.fetchUser(ctx, idStr, false, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  71. return q.Filter(sqlchemy.Equals(q.Field("id"), idStr))
  72. })
  73. }
  74. func (manager *SUserCacheManager) FetchUserByName(ctx context.Context, idStr string) (*SUser, error) {
  75. return manager.fetchUser(ctx, idStr, false, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  76. return q.Filter(sqlchemy.Equals(q.Field("name"), idStr))
  77. })
  78. }
  79. func (manager *SUserCacheManager) fetchUser(
  80. ctx context.Context, idStr string, noExpireCheck bool,
  81. filter func(*sqlchemy.SQuery) *sqlchemy.SQuery,
  82. ) (*SUser, error) {
  83. q := manager.Query()
  84. q = filter(q)
  85. tobj, err := NewModelObject(manager)
  86. if err != nil {
  87. return nil, errors.Wrap(err, "NewModelObject")
  88. }
  89. err = q.First(tobj)
  90. if err != nil && err != sql.ErrNoRows {
  91. return nil, errors.Wrap(err, "query")
  92. } else if tobj != nil {
  93. user := tobj.(*SUser)
  94. if noExpireCheck || !user.IsExpired() {
  95. return user, nil
  96. }
  97. }
  98. return manager.FetchUserFromKeystone(ctx, idStr)
  99. }
  100. func (manager *SUserCacheManager) FetchUserFromKeystone(ctx context.Context, idStr string) (*SUser, error) {
  101. if len(idStr) == 0 {
  102. log.Debugf("fetch empty user!!!!\n%s", debug.Stack())
  103. return nil, fmt.Errorf("Empty idStr")
  104. }
  105. // It's to query the full list of users(contains other domain's ones and system ones)
  106. query := jsonutils.NewDict()
  107. query.Set("scope", jsonutils.NewString("system"))
  108. query.Set("system", jsonutils.JSONTrue)
  109. query.Set("pending_delete", jsonutils.NewString("all"))
  110. s := auth.GetAdminSession(ctx, consts.GetRegion())
  111. user, err := modules.UsersV3.GetById(s, idStr, query)
  112. if err != nil {
  113. if je, ok := err.(*httputils.JSONClientError); ok && je.Code == 404 {
  114. user, err = modules.UsersV3.GetByName(s, idStr, query)
  115. if je, ok := err.(*httputils.JSONClientError); ok && je.Code == 404 {
  116. return nil, sql.ErrNoRows
  117. }
  118. }
  119. if err != nil {
  120. log.Errorf("fetch user %s fail %s", idStr, err)
  121. return nil, errors.Wrap(err, "modules.UsersV3.Get")
  122. }
  123. }
  124. id, _ := user.GetString("id")
  125. name, _ := user.GetString("name")
  126. domainId, _ := user.GetString("domain_id")
  127. domainNmae, _ := user.GetString("project_domain")
  128. lang, _ := user.GetString("lang")
  129. return manager.Save(ctx, id, name, domainId, domainNmae, lang)
  130. }
  131. func (manager *SUserCacheManager) Save(ctx context.Context, idStr string, name string, domainId string, domain, lang string) (*SUser, error) {
  132. lockman.LockRawObject(ctx, manager.KeywordPlural(), idStr)
  133. defer lockman.ReleaseRawObject(ctx, manager.KeywordPlural(), idStr)
  134. objo, err := manager.FetchById(idStr)
  135. if err != nil && err != sql.ErrNoRows {
  136. log.Errorf("FetchUserbyId fail %s", err)
  137. return nil, err
  138. }
  139. if err == nil {
  140. obj := objo.(*SUser)
  141. _, err = Update(obj, func() error {
  142. obj.Id = idStr
  143. obj.Name = name
  144. obj.Domain = domain
  145. obj.DomainId = domainId
  146. obj.LastCheck = time.Now().UTC()
  147. if len(lang) > 0 {
  148. obj.Lang = lang
  149. }
  150. return nil
  151. })
  152. if err != nil {
  153. return nil, err
  154. } else {
  155. return obj, nil
  156. }
  157. } else {
  158. objm, err := NewModelObject(manager)
  159. obj := objm.(*SUser)
  160. obj.Id = idStr
  161. obj.Name = name
  162. obj.Domain = domain
  163. obj.DomainId = domainId
  164. obj.LastCheck = time.Now().UTC()
  165. obj.Lang = lang
  166. err = manager.TableSpec().InsertOrUpdate(ctx, obj)
  167. if err != nil {
  168. return nil, err
  169. } else {
  170. return obj, nil
  171. }
  172. }
  173. }