Files
cloudpods/pkg/cloudid/models/cloudgroupcaches.go
2022-12-27 01:21:26 +08:00

533 lines
17 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 models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/rand"
"yunion.io/x/pkg/util/rbacscope"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SCloudgroupcacheManager struct {
db.SStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudaccountResourceBaseManager
}
var CloudgroupcacheManager *SCloudgroupcacheManager
func init() {
CloudgroupcacheManager = &SCloudgroupcacheManager{
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SCloudgroupcache{},
"cloudgroupcaches_tbl",
"cloudgroupcache",
"cloudgroupcaches",
),
}
CloudgroupcacheManager.SetVirtualObject(CloudgroupcacheManager)
}
type SCloudgroupcache struct {
db.SStatusStandaloneResourceBase
db.SExternalizedResourceBase
SCloudaccountResourceBase
// 用户组Id
CloudgroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" index:"true" json:"cloudgroup_id"`
}
// 公有云权限组缓存
func (manager *SCloudgroupcacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudgroupcacheListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, err
}
q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
if err != nil {
return nil, err
}
if len(query.CloudgroupId) > 0 {
_, err = CloudgroupManager.FetchById(query.CloudgroupId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("cloudgroup", query.CloudgroupId)
}
return q, httperrors.NewGeneralError(errors.Wrap(err, "CloudgroupManager.FetchById"))
}
q = q.Equals("cloudgroup_id", query.CloudgroupId)
}
return q, nil
}
// +onecloud:swagger-gen-ignore
func (self *SCloudgroupcache) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupUpdateInput) (api.CloudgroupUpdateInput, error) {
return input, httperrors.NewNotSupportedError("Not support")
}
// +onecloud:swagger-gen-ignore
func (manager *SCloudgroupcacheManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudgroupcacheCreateInput) (api.CloudgroupcacheCreateInput, error) {
return input, httperrors.NewNotSupportedError("Not support")
}
// 删除权限组缓存
func (self *SCloudgroupcache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartCloudgroupcacheDeleteTask(ctx, userCred, "")
}
func (manager *SCloudgroupcacheManager) ResourceScope() rbacscope.TRbacScope {
return rbacscope.ScopeDomain
}
func (self *SCloudgroupcache) GetOwnerId() mcclient.IIdentityProvider {
group, err := self.GetCloudgroup()
if err != nil {
return nil
}
return group.GetOwnerId()
}
func (self *SCloudgroupcache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SCloudgroupcache) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
}
func (manager *SCloudgroupcacheManager) newFromCloudgroup(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup, group *SCloudgroup, cloudaccountId string) (*SCloudgroupcache, error) {
cache := &SCloudgroupcache{}
cache.SetModelManager(manager, cache)
cache.CloudgroupId = group.Id
cache.Name = iGroup.GetName()
cache.Description = iGroup.GetDescription()
cache.Status = api.CLOUD_GROUP_CACHE_STATUS_AVAILABLE
cache.ExternalId = iGroup.GetGlobalId()
cache.CloudaccountId = cloudaccountId
return cache, manager.TableSpec().Insert(ctx, cache)
}
func (self *SCloudgroupcache) syncWithCloudgroupcache(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup) error {
_, err := db.Update(self, func() error {
self.Name = iGroup.GetName()
self.Description = iGroup.GetDescription()
self.Status = api.CLOUD_GROUP_CACHE_STATUS_AVAILABLE
return nil
})
return err
}
func (manager *SCloudgroupcacheManager) Register(group *SCloudgroup, account *SCloudaccount) (*SCloudgroupcache, error) {
q := manager.Query().Equals("cloudgroup_id", group.Id).Equals("cloudaccount_id", account.Id)
caches := []SCloudgroupcache{}
err := db.FetchModelObjects(manager, q, &caches)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
if len(caches) == 0 {
cache := &SCloudgroupcache{}
cache.SetModelManager(manager, cache)
cache.Name = group.Name
cache.Description = group.Description
cache.Status = api.CLOUD_GROUP_CACHE_STATUS_CREATING
cache.CloudgroupId = group.Id
cache.CloudaccountId = account.Id
return cache, manager.TableSpec().Insert(context.Background(), cache)
}
for i := range caches {
if len(caches[i].ExternalId) > 0 {
return &caches[i], nil
}
}
return &caches[0], nil
}
// 获取权限组缓存详情
func (manager *SCloudgroupcacheManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.CloudgroupcacheDetails {
rows := make([]api.CloudgroupcacheDetails, len(objs))
statusRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.CloudgroupcacheDetails{
StatusStandaloneResourceDetails: statusRows[i],
CloudaccountResourceDetails: acRows[i],
}
}
return rows
}
// 同步权限组缓存状态
func (self *SCloudgroupcache) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupSyncstatusInput) (jsonutils.JSONObject, error) {
return nil, self.StartCloudgroupcacheSyncstatusTask(ctx, userCred, "")
}
func (self *SCloudgroupcache) StartCloudgroupcacheSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupcacheSyncstatusTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.CLOUD_GROUP_CACHE_STATUS_SYNC_STATUS, "")
task.ScheduleRun(nil)
return nil
}
func (self *SCloudgroupcache) StartCloudgroupcacheDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupcacheDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.CLOUD_GROUP_STATUS_DELETING, "")
task.ScheduleRun(nil)
return nil
}
func (self *SCloudgroupcache) GetOrCreateICloudgroup(ctx context.Context, userCred mcclient.TokenCredential) (cloudprovider.ICloudgroup, error) {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
if len(self.ExternalId) > 0 {
iGroup, err := self.GetICloudgroup()
if err == nil {
return iGroup, nil
}
if errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, errors.Wrap(err, "GetICloudgroup")
}
}
account, err := self.GetCloudaccount()
if err != nil {
return nil, errors.Wrap(err, "GetCloudaccount")
}
provider, err := account.GetProvider()
if err != nil {
return nil, errors.Wrap(err, "account.GetProvider")
}
randomString := func(prefix string, length int) string {
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
}
groupName := self.Name
for i := 2; i < 30; i++ {
_, err := provider.GetICloudgroupByName(groupName)
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
break
}
return nil, errors.Wrapf(err, "GetICloudgroupByName(%s)", groupName)
}
groupName = randomString(self.Name, i)
}
iGroup, err := provider.CreateICloudgroup(groupName, self.Description)
if err != nil {
logclient.AddSimpleActionLog(self, logclient.ACT_CREATE, err, userCred, false)
return nil, errors.Wrap(err, "CreateICloudgroup")
}
_, err = db.Update(self, func() error {
self.Name = groupName
self.ExternalId = iGroup.GetGlobalId()
self.Status = api.CLOUD_GROUP_CACHE_STATUS_AVAILABLE
return nil
})
if err != nil {
return nil, errors.Wrapf(err, "db.Update")
}
err = self.SyncSystemCloudpoliciesForCloud(ctx, userCred)
if err != nil {
return nil, errors.Wrapf(err, "SyncSystemCloudpoliciesForCloud")
}
err = self.SyncCustomCloudpoliciesForCloud(ctx, userCred)
if err != nil {
return nil, errors.Wrapf(err, "SyncCustomCloudpoliciesForCloud")
}
err = self.SyncCloudusersForCloud(ctx, userCred)
if err != nil {
return nil, errors.Wrapf(err, "SyncCloudusersForCloud")
}
return iGroup, nil
}
func (self *SCloudgroupcache) GetCloudgroup() (*SCloudgroup, error) {
group, err := CloudgroupManager.FetchById(self.CloudgroupId)
if err != nil {
return nil, errors.Wrapf(err, "FetchById(%s)", self.CloudgroupId)
}
return group.(*SCloudgroup), nil
}
func (self *SCloudgroupcache) GetICloudgroup() (cloudprovider.ICloudgroup, error) {
account, err := self.GetCloudaccount()
if err != nil {
return nil, errors.Wrap(err, "self.GetCloudaccount")
}
provider, err := account.GetProvider()
if err != nil {
return nil, errors.Wrap(err, "account.GetProvider")
}
return provider.GetICloudgroupByName(self.Name)
}
func (self *SCloudgroupcache) SyncCustomCloudpoliciesForCloud(ctx context.Context, userCred mcclient.TokenCredential) error {
group, err := self.GetCloudgroup()
if err != nil {
return errors.Wrap(err, "GetCloudgroup")
}
policies, err := group.GetCustomCloudpolicies()
if err != nil {
return errors.Wrap(err, "GetCustomCloudpolicies")
}
account, err := self.GetCloudaccount()
if err != nil {
return errors.Wrap(err, "GetCloudaccount")
}
policyIds := []string{}
for i := range policies {
err = account.getOrCacheCustomCloudpolicy(ctx, "", policies[i].Id)
if err != nil {
return errors.Wrapf(err, "getOrCacheCloudpolicy %s(%s) for account %s", policies[i].Name, policies[i].Provider, self.Name)
}
policyIds = append(policyIds, policies[i].Id)
}
dbCaches := []SCloudpolicycache{}
if len(policyIds) > 0 {
dbCaches, err = account.GetCloudpolicycaches(policyIds, "")
if err != nil {
return errors.Wrapf(err, "GetCloudpolicycaches")
}
}
iGroup, err := self.GetICloudgroup()
if err != nil {
return errors.Wrapf(err, "GetICloudgroup")
}
iPolicies, err := iGroup.GetICustomCloudpolicies()
if err != nil {
return errors.Wrap(err, "iGroup.GetICustomCloudpolicies")
}
added := make([]SCloudpolicycache, 0)
commondb := make([]SCloudpolicycache, 0)
commonext := make([]cloudprovider.ICloudpolicy, 0)
removed := make([]cloudprovider.ICloudpolicy, 0)
err = compare.CompareSets(dbCaches, iPolicies, &added, &commondb, &commonext, &removed)
if err != nil {
return errors.Wrap(err, "compare.CompareSets")
}
result := compare.SyncResult{}
for i := 0; i < len(removed); i++ {
err = iGroup.DetachCustomPolicy(removed[i].GetGlobalId())
if err != nil {
result.DeleteError(err)
logclient.AddSimpleActionLog(self, logclient.ACT_DETACH_POLICY, err, userCred, false)
continue
}
logclient.AddSimpleActionLog(self, logclient.ACT_DETACH_POLICY, jsonutils.Marshal(removed[i]), userCred, true)
result.Delete()
}
result.UpdateCnt = len(commondb)
for i := 0; i < len(added); i++ {
err = iGroup.AttachCustomPolicy(added[i].ExternalId)
if err != nil {
result.AddError(err)
logclient.AddSimpleActionLog(self, logclient.ACT_ATTACH_POLICY, err, userCred, false)
continue
}
logclient.AddSimpleActionLog(self, logclient.ACT_ATTACH_POLICY, added[i], userCred, true)
result.Add()
}
if result.IsError() {
return result.AllError()
}
log.Infof("Sync %s(%s) custom policies for cloudgroupcache %s result: %s", account.Name, account.Provider, self.Name, result.Result())
return nil
}
// 将本地的权限推送到云上(覆盖云上设置)
func (self *SCloudgroupcache) SyncSystemCloudpoliciesForCloud(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
account, err := self.GetCloudaccount()
if err != nil {
return errors.Wrap(err, "GetCloudaccount")
}
iGroup, err := self.GetICloudgroup()
if err != nil {
return errors.Wrap(err, "GetICloudgroup")
}
iPolicies, err := iGroup.GetISystemCloudpolicies()
if err != nil {
return errors.Wrap(err, "GetISystemCloudpolicies")
}
group, err := self.GetCloudgroup()
if err != nil {
return errors.Wrap(err, "GetCloudgroup")
}
dbPolicies, err := group.GetSystemCloudpolicies()
if err != nil {
return errors.Wrap(err, "GetCloudpolicies")
}
added := make([]SCloudpolicy, 0)
commondb := make([]SCloudpolicy, 0)
commonext := make([]cloudprovider.ICloudpolicy, 0)
removed := make([]cloudprovider.ICloudpolicy, 0)
err = compare.CompareSets(dbPolicies, iPolicies, &added, &commondb, &commonext, &removed)
if err != nil {
return errors.Wrap(err, "compare.CompareSets")
}
result := compare.SyncResult{}
for i := 0; i < len(removed); i++ {
err = iGroup.DetachSystemPolicy(removed[i].GetGlobalId())
if err != nil {
logclient.AddSimpleActionLog(self, logclient.ACT_DETACH_POLICY, err, userCred, false)
result.DeleteError(err)
continue
}
result.Delete()
}
result.UpdateCnt = len(commondb)
for i := 0; i < len(added); i++ {
err = iGroup.AttachSystemPolicy(added[i].ExternalId)
if err != nil {
logclient.AddSimpleActionLog(self, logclient.ACT_ATTACH_POLICY, err, userCred, false)
result.AddError(err)
continue
}
result.Add()
}
if result.IsError() {
return result.AllError()
}
log.Infof("Sync %s(%s) system policies for cloudgroupcache %s result: %s", account.Name, account.Provider, self.Name, result.Result())
return nil
}
func (self *SCloudgroupcache) GetCloudusers() ([]SClouduser, error) {
sq := CloudgroupUserManager.Query("clouduser_id").Equals("cloudgroup_id", self.CloudgroupId)
q := ClouduserManager.Query().Equals("cloudaccount_id", self.CloudaccountId).In("id", sq.SubQuery())
users := []SClouduser{}
err := db.FetchModelObjects(ClouduserManager, q, &users)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return users, nil
}
// 将本地的用户推送到云上(覆盖云上设置)
func (self *SCloudgroupcache) SyncCloudusersForCloud(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
iGroup, err := self.GetICloudgroup()
if err != nil {
return errors.Wrap(err, "GetICloudgroup")
}
iUsers, err := iGroup.GetICloudusers()
if err != nil {
return errors.Wrap(err, "GetICloudusers")
}
dbUsers, err := self.GetCloudusers()
if err != nil {
return errors.Wrap(err, "GetCloudusers")
}
added := make([]SClouduser, 0)
commondb := make([]SClouduser, 0)
commonext := make([]cloudprovider.IClouduser, 0)
removed := make([]cloudprovider.IClouduser, 0)
err = compare.CompareSets(dbUsers, iUsers, &added, &commondb, &commonext, &removed)
if err != nil {
return errors.Wrap(err, "compare.CompareSets")
}
result := compare.SyncResult{}
for i := 0; i < len(removed); i++ {
err = iGroup.RemoveUser(removed[i].GetName())
if err != nil {
result.DeleteError(err)
logclient.AddSimpleActionLog(self, logclient.ACT_REMOVE_USER, err, userCred, false)
continue
}
logclient.AddSimpleActionLog(self, logclient.ACT_REMOVE_USER, jsonutils.Marshal(removed[i]), userCred, true)
result.Delete()
}
result.UpdateCnt = len(commondb)
for i := 0; i < len(added); i++ {
err = iGroup.AddUser(added[i].GetName())
if err != nil {
result.AddError(err)
logclient.AddSimpleActionLog(self, logclient.ACT_ADD_USER, err, userCred, false)
continue
}
logclient.AddSimpleActionLog(self, logclient.ACT_ADD_USER, jsonutils.Marshal(added[i]), userCred, true)
result.Add()
}
if result.IsError() {
return result.AllError()
}
log.Infof("sync cloudusers for cloudgroupcache %s(%s) result: %s", self.Name, self.Id, result.Result())
return nil
}