mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-11 08:11:33 +08:00
1. Query 'scope=system' and 'system=true' is neccessary when fetching all users or groups from Keystone. Without these, users and groups in other domains (non-caller domains), as well as system-level users, cannot be detected. 2. Query 'scope=system' is neccessary when fetching all project from Keystone.
189 lines
4.5 KiB
Go
189 lines
4.5 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package cache
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/util/compare"
|
|
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
|
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
|
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
|
)
|
|
|
|
type SUserGroupCacheManager struct {
|
|
db.SResourceBaseManager
|
|
}
|
|
|
|
type SUserGroup struct {
|
|
db.SResourceBase
|
|
UserId string
|
|
GroupId string
|
|
LastCheck time.Time `nullable:"false"`
|
|
}
|
|
|
|
func (ug *SUserGroup) GetModelManager() db.IModelManager {
|
|
return UserGroupCacheManager
|
|
}
|
|
|
|
var UserGroupCacheManager *SUserGroupCacheManager
|
|
|
|
func init() {
|
|
UserGroupCacheManager = &SUserGroupCacheManager{db.NewResourceBaseManager(
|
|
SUserGroup{},
|
|
"user_group_cache_tbl",
|
|
"usergroup",
|
|
"usergroups",
|
|
)}
|
|
}
|
|
|
|
func (ug *SUserGroup) IsExpired() bool {
|
|
if ug.LastCheck.IsZero() {
|
|
return true
|
|
}
|
|
now := time.Now().UTC()
|
|
if ug.LastCheck.Add(consts.GetTenantCacheExpireSeconds()).Before(now) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (manager *SUserGroupCacheManager) FetchByGroupId(ctx context.Context, groupId string) ([]SUserGroup, error) {
|
|
q := manager.Query().Equals("gourp_id", groupId)
|
|
ugs := make([]SUserGroup, 0)
|
|
err := db.FetchModelObjects(manager, q, &ugs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var needSync bool
|
|
if len(ugs) == 0 {
|
|
needSync = true
|
|
}
|
|
now := time.Now().UTC()
|
|
expireTime := now.Add(-consts.GetTenantCacheExpireSeconds())
|
|
for i := range ugs {
|
|
if ugs[i].LastCheck.Before(expireTime) {
|
|
needSync = true
|
|
break
|
|
}
|
|
}
|
|
if !needSync {
|
|
return ugs, nil
|
|
}
|
|
ugs, syncResult, err := manager.Sync(ctx, ugs, groupId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if syncResult.IsError() {
|
|
log.Errorf(syncResult.Result())
|
|
}
|
|
return ugs, nil
|
|
}
|
|
|
|
func (manager *SUserGroupCacheManager) Sync(ctx context.Context, ugCache []SUserGroup, groupId string) ([]SUserGroup,
|
|
compare.SyncResult, error) {
|
|
lockman.LockRawObject(ctx, manager.KeywordPlural(), groupId)
|
|
defer lockman.ReleaseRawObject(ctx, manager.KeywordPlural(), groupId)
|
|
|
|
syncResult := compare.SyncResult{}
|
|
|
|
// It's to query all groups and their users.
|
|
query := jsonutils.NewDict()
|
|
query.Set("scope", jsonutils.NewString("system"))
|
|
query.Set("system", jsonutils.JSONTrue)
|
|
|
|
s := auth.GetAdminSession(ctx, consts.GetRegion(), "v3")
|
|
users, err := modules.Groups.GetUsers(s, groupId, query)
|
|
if err != nil {
|
|
return nil, syncResult, errors.Wrap(err, "fetch users by group id from keystone failed")
|
|
}
|
|
newUgCache := make([]SUserGroup, len(users.Data))
|
|
for i := range users.Data {
|
|
userId, _ := users.Data[i].GetString("id")
|
|
newUgCache[i] = SUserGroup{
|
|
UserId: userId,
|
|
GroupId: groupId,
|
|
}
|
|
}
|
|
added := make([]SUserGroup, 0)
|
|
removed := make([]SUserGroup, 0)
|
|
commondb := make([]SUserGroup, 0)
|
|
compareSets(ugCache, newUgCache, &added, &removed, &commondb)
|
|
now := time.Now().UTC()
|
|
for i := range added {
|
|
added[i].LastCheck = now
|
|
err := manager.TableSpec().Insert(&added[i])
|
|
if err != nil {
|
|
syncResult.AddError(err)
|
|
} else {
|
|
syncResult.Add()
|
|
}
|
|
}
|
|
|
|
for i := range commondb {
|
|
ug := &commondb[i]
|
|
_, err := db.Update(ug, func() error {
|
|
ug.LastCheck = now
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
syncResult.UpdateError(err)
|
|
} else {
|
|
syncResult.Update()
|
|
}
|
|
}
|
|
|
|
for i := range removed {
|
|
ug := &removed[i]
|
|
_, err := db.Update(ug, func() error {
|
|
return ug.MarkDelete()
|
|
})
|
|
if err != nil {
|
|
syncResult.DeleteError(err)
|
|
} else {
|
|
syncResult.Delete()
|
|
}
|
|
}
|
|
|
|
return newUgCache, syncResult, nil
|
|
}
|
|
|
|
func compareSets(dbs, remotes []SUserGroup, added, removed, commondb *[]SUserGroup) {
|
|
dbmap := make(map[string]SUserGroup)
|
|
for i := range dbs {
|
|
dbmap[dbs[i].UserId] = dbs[i]
|
|
}
|
|
|
|
for i := range remotes {
|
|
userId := remotes[i].UserId
|
|
if _, ok := dbmap[userId]; ok {
|
|
*commondb = append(*commondb, remotes[i])
|
|
} else {
|
|
*added = append(*added, remotes[i])
|
|
}
|
|
delete(dbmap, userId)
|
|
}
|
|
for _, v := range dbmap {
|
|
*removed = append(*removed, v)
|
|
}
|
|
}
|