mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-06 21:52:54 +08:00
341 lines
13 KiB
Go
341 lines
13 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 db
|
|
|
|
import (
|
|
"context"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/utils"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
"yunion.io/x/onecloud/pkg/apis"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
|
"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 SDomainLevelResourceBaseManager struct {
|
|
SStandaloneResourceBaseManager
|
|
SDomainizedResourceBaseManager
|
|
}
|
|
|
|
func NewDomainLevelResourceBaseManager(
|
|
dt interface{},
|
|
tableName string,
|
|
keyword string,
|
|
keywordPlural string,
|
|
) SDomainLevelResourceBaseManager {
|
|
return SDomainLevelResourceBaseManager{
|
|
SStandaloneResourceBaseManager: NewStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural),
|
|
}
|
|
}
|
|
|
|
type SDomainLevelResourceBase struct {
|
|
SStandaloneResourceBase
|
|
SDomainizedResourceBase
|
|
|
|
// 归属Domain信息的来源, local: 本地设置, cloud: 从云上同步过来
|
|
// example: local
|
|
DomainSrc string `width:"10" charset:"ascii" nullable:"true" list:"user" default:"" json:"domain_src"`
|
|
}
|
|
|
|
func (self *SDomainLevelResourceBaseManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
|
return IsDomainAllowList(userCred, self)
|
|
}
|
|
|
|
func (self *SDomainLevelResourceBaseManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
|
return IsDomainAllowCreate(userCred, self)
|
|
}
|
|
|
|
func (self *SDomainLevelResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
|
return IsDomainAllowGet(userCred, self)
|
|
}
|
|
|
|
func (self *SDomainLevelResourceBase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
|
|
return IsDomainAllowUpdate(userCred, self)
|
|
}
|
|
|
|
func (self *SDomainLevelResourceBase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
|
return IsDomainAllowDelete(userCred, self)
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) ListItemFilter(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query apis.DomainLevelResourceListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
|
|
}
|
|
q, err = manager.SDomainizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainizedResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.ListItemFilter")
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
|
q, err := manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
q, err = manager.SDomainizedResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
return q, httperrors.ErrNotFound
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) OrderByExtraFields(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query apis.DomainLevelResourceListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
q, err = manager.SDomainizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DomainizedResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
|
model.DomainId = ownerId.GetProjectDomainId()
|
|
model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL)
|
|
return model.SStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) AllowPerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) bool {
|
|
return IsAdminAllowPerform(userCred, model, "change-owner")
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
|
|
if !consts.GetNonDefaultDomainProjects() {
|
|
return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to change owner of domain resource if non_default_domain_projects is turned off")
|
|
}
|
|
if model.GetIStandaloneModel().IsShared() {
|
|
return nil, errors.Wrap(httperrors.ErrForbidden, "cannot change owner of shared resource")
|
|
}
|
|
|
|
manager := model.GetModelManager()
|
|
|
|
data := jsonutils.Marshal(input)
|
|
log.Debugf("SDomainLevelResourceBase change_owner %s %s %#v", query, data, manager)
|
|
ownerId, err := manager.FetchOwnerId(ctx, data)
|
|
if err != nil {
|
|
return nil, httperrors.NewGeneralError(err)
|
|
}
|
|
if len(ownerId.GetProjectDomainId()) == 0 {
|
|
return nil, httperrors.NewInputParameterError("missing new domain")
|
|
}
|
|
if ownerId.GetProjectDomainId() == model.DomainId {
|
|
// do nothing
|
|
Update(model, func() error {
|
|
model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL)
|
|
return nil
|
|
})
|
|
return nil, nil
|
|
}
|
|
|
|
// change domain, do check
|
|
candidates := model.GetIDomainLevelModel().GetChangeOwnerCandidateDomainIds()
|
|
if len(candidates) > 0 && !utils.IsInStringArray(ownerId.GetProjectDomainId(), candidates) {
|
|
return nil, errors.Wrap(httperrors.ErrForbidden, "target domain not in change owner candidate list")
|
|
}
|
|
requires := model.GetIDomainLevelModel().GetChangeOwnerRequiredDomainIds()
|
|
log.Debugf("%s required domains: %s", model.Keyword(), requires)
|
|
if len(requires) > 0 && !utils.IsInStringArray(ownerId.GetProjectDomainId(), requires) {
|
|
return nil, errors.Wrap(httperrors.ErrForbidden, "target domain not in change owner required list")
|
|
}
|
|
|
|
if !IsAdminAllowPerform(userCred, model, "change-owner") {
|
|
return nil, errors.Wrap(httperrors.ErrNotSufficientPrivilege, "require system privileges")
|
|
}
|
|
|
|
q := manager.Query().Equals("name", model.GetName())
|
|
q = manager.FilterByOwner(q, ownerId, manager.NamespaceScope())
|
|
q = manager.FilterBySystemAttributes(q, nil, nil, manager.ResourceScope())
|
|
q = q.NotEquals("id", model.GetId())
|
|
cnt, err := q.CountWithError()
|
|
if err != nil {
|
|
return nil, httperrors.NewInternalServerError("check name duplication error: %s", err)
|
|
}
|
|
if cnt > 0 {
|
|
return nil, httperrors.NewDuplicateNameError("name", model.GetName())
|
|
}
|
|
former, _ := TenantCacheManager.FetchDomainById(ctx, model.DomainId)
|
|
if former == nil {
|
|
log.Warningf("domain_id %s not found", model.DomainId)
|
|
formerObj := NewDomain(model.DomainId, "unknown")
|
|
former = &formerObj
|
|
}
|
|
|
|
// clean shared projects before update domain id
|
|
if sharedModel, ok := model.GetIDomainLevelModel().(ISharableBaseModel); ok {
|
|
if err := SharedResourceManager.CleanModelShares(ctx, userCred, sharedModel); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// cancel usage
|
|
model.cleanModelUsages(ctx, userCred)
|
|
|
|
_, err = Update(model, func() error {
|
|
model.DomainId = ownerId.GetProjectDomainId()
|
|
model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Update")
|
|
}
|
|
|
|
// add usage
|
|
model.RecoverUsages(ctx, userCred)
|
|
|
|
OpsLog.SyncOwner(model, former, userCred)
|
|
notes := struct {
|
|
OldDomainId string
|
|
OldDomain string
|
|
NewDomainId string
|
|
NewDomain string
|
|
}{
|
|
OldDomainId: former.DomainId,
|
|
OldDomain: former.Domain,
|
|
NewDomainId: ownerId.GetProjectDomainId(),
|
|
NewDomain: ownerId.GetProjectDomain(),
|
|
}
|
|
logclient.AddActionLogWithContext(ctx, model, logclient.ACT_CHANGE_OWNER, notes, userCred, true)
|
|
return nil, nil
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) FetchCustomizeColumns(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
objs []interface{},
|
|
fields stringutils2.SSortedStrings,
|
|
isList bool,
|
|
) []apis.DomainLevelResourceDetails {
|
|
rows := make([]apis.DomainLevelResourceDetails, len(objs))
|
|
stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
domainRows := manager.SDomainizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
for i := range rows {
|
|
rows[i] = apis.DomainLevelResourceDetails{
|
|
StandaloneResourceDetails: stdRows[i],
|
|
DomainizedResourceInfo: domainRows[i],
|
|
}
|
|
}
|
|
return rows
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) GetExtraDetails(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
isList bool,
|
|
) (apis.DomainLevelResourceDetails, error) {
|
|
return apis.DomainLevelResourceDetails{}, nil
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) GetIDomainLevelModelManager() IDomainLevelModelManager {
|
|
return manager.GetVirtualObject().(IDomainLevelModelManager)
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) ValidateCreateData(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
ownerId mcclient.IIdentityProvider,
|
|
query jsonutils.JSONObject,
|
|
input apis.DomainLevelResourceCreateInput,
|
|
) (apis.DomainLevelResourceCreateInput, error) {
|
|
var err error
|
|
input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput)
|
|
if err != nil {
|
|
return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData")
|
|
}
|
|
return input, nil
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) DomainLevelModelManager() IDomainLevelModelManager {
|
|
return model.GetModelManager().(IDomainLevelModelManager)
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) IsOwner(userCred mcclient.TokenCredential) bool {
|
|
return model.DomainId == userCred.GetProjectDomainId()
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) SyncCloudDomainId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) {
|
|
if model.DomainSrc != string(apis.OWNER_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectDomainId()) > 0 {
|
|
diff, _ := Update(model, func() error {
|
|
model.DomainSrc = string(apis.OWNER_SOURCE_CLOUD)
|
|
model.DomainId = ownerId.GetProjectDomainId()
|
|
return nil
|
|
})
|
|
if len(diff) > 0 {
|
|
OpsLog.LogEvent(model, ACT_SYNC_OWNER, diff, userCred)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) GetIDomainLevelModel() IDomainLevelModel {
|
|
return model.GetVirtualObject().(IDomainLevelModel)
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) ValidateUpdateData(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
input apis.DomainLevelResourceBaseUpdateInput,
|
|
) (apis.DomainLevelResourceBaseUpdateInput, error) {
|
|
var err error
|
|
input.StandaloneResourceBaseUpdateInput, err = model.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
|
|
if err != nil {
|
|
return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
|
|
}
|
|
return input, nil
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) AllowGetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
|
return model.IsOwner(userCred) || IsAdminAllowGetSpec(userCred, model, "change-owner-candidate-domains")
|
|
}
|
|
|
|
func (model *SDomainLevelResourceBase) GetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.ChangeOwnerCandidateDomainsOutput, error) {
|
|
return IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(model.GetIDomainLevelModel())
|
|
}
|
|
|
|
func (manager *SDomainLevelResourceBaseManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
|
|
q, err := manager.SStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemExportKeys")
|
|
}
|
|
q, err = manager.SDomainizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.ListItemExportKeys")
|
|
}
|
|
return q, nil
|
|
}
|