// 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" "database/sql" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/rbacscope" "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/cloudcommon/policy" "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 SVirtualResourceBaseManager struct { SStatusStandaloneResourceBaseManager SProjectizedResourceBaseManager SPendingDeletedBaseManager } func NewVirtualResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SVirtualResourceBaseManager { return SVirtualResourceBaseManager{ SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural), } } type SVirtualResourceBase struct { SStatusStandaloneResourceBase SProjectizedResourceBase SPendingDeletedBase // 云上同步资源是否在本地被更改过配置, local: 更改过, cloud: 未更改过 // example: local ProjectSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"" json:"project_src"` // 是否是系统资源 IsSystem bool `nullable:"true" default:"false" list:"admin" create:"optional" json:"is_system"` // 资源是否被冻结 Freezed bool `nullable:"false" default:"false" get:"user" list:"user" json:"freezed"` } func (model *SVirtualResourceBase) IsOwner(userCred mcclient.TokenCredential) bool { return userCred.GetProjectId() == model.ProjectId } func (manager *SVirtualResourceBaseManager) GetIVirtualModelManager() IVirtualModelManager { return manager.GetVirtualObject().(IVirtualModelManager) } // +onecloud:swagger-gen-ignore func (manager *SVirtualResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*apis.StatusStatistic, error) { im, ok := manager.GetVirtualObject().(IModelManager) if !ok { im = manager } var err error q := manager.Query() q, err = ListItemQueryFilters(im, ctx, q, userCred, query, policy.PolicyActionList) if err != nil { return nil, err } sq := q.SubQuery() statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")), sqlchemy.SUM("pending_deleted_count", sq.Field("pending_deleted"))) statQ = statQ.GroupBy(sq.Field("status")) ret := []struct { Status string TotalCount int64 PendingDeletedCount int64 }{} err = statQ.All(&ret) if err != nil { return nil, errors.Wrapf(err, "q.All") } type sStatistic struct { TotalCount int64 PendingDeletedCount int64 } result := &apis.StatusStatistic{ StatusInfo: []apis.StatusStatisticStatusInfo{}, } for _, s := range ret { result.StatusInfo = append(result.StatusInfo, apis.StatusStatisticStatusInfo{ Status: s.Status, TotalCount: s.TotalCount, PendingDeletedCount: s.PendingDeletedCount, }) } return result, nil } func (manager *SVirtualResourceBaseManager) CustomizedTotalCount(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, totalQ *sqlchemy.SQuery) (int, jsonutils.JSONObject, error) { results := struct { apis.TotalCountBase StatusInfo []apis.StatusStatisticStatusInfo }{} err := totalQ.First(&results.TotalCountBase) if err != nil && errors.Cause(err) != sql.ErrNoRows { return -1, nil, errors.Wrapf(err, "First") } totalSQ := totalQ.ResetFields().SubQuery() statQ := totalSQ.Query(totalSQ.Field("status"), sqlchemy.COUNT("total_count", totalSQ.Field("id")), sqlchemy.SUM("pending_deleted_count", totalSQ.Field("pending_deleted"))) statQ = statQ.GroupBy(totalSQ.Field("status")) err = statQ.All(&results.StatusInfo) if err != nil { return -1, nil, errors.Wrapf(err, "status query") } return results.Count, jsonutils.Marshal(results), nil } // +onecloud:swagger-gen-ignore func (manager *SVirtualResourceBaseManager) GetPropertyProjectStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) ([]apis.ProjectStatistic, error) { im, ok := manager.GetVirtualObject().(IModelManager) if !ok { im = manager } tenants := TenantCacheManager.GetTenantQuery().Equals("domain_id", userCred.GetProjectDomainId()).SubQuery() _q, err := ListItemQueryFilters(im, ctx, im.Query(), userCred, query, policy.PolicyActionList) if err != nil { return nil, err } sq := _q.SubQuery() q := sq.Query( sq.Field("tenant_id"), sqlchemy.COUNT("count"), ).GroupBy(sq.Field("tenant_id")) q.Join(tenants, sqlchemy.Equals(q.Field("tenant_id"), tenants.Field("id"))) q.AppendField(tenants.Field("id")) q.AppendField(tenants.Field("name")) result := []apis.ProjectStatistic{} return result, q.All(&result) } // +onecloud:swagger-gen-ignore func (manager *SVirtualResourceBaseManager) GetPropertyDomainStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) ([]apis.ProjectStatistic, error) { im, ok := manager.GetVirtualObject().(IModelManager) if !ok { im = manager } domains := TenantCacheManager.GetDomainQuery().SubQuery() _q, err := ListItemQueryFilters(im, ctx, im.Query(), userCred, query, policy.PolicyActionList) if err != nil { return nil, err } sq := _q.SubQuery() q := sq.Query( sq.Field("domain_id"), sqlchemy.COUNT("count"), ).GroupBy(sq.Field("domain_id")) q.Join(domains, sqlchemy.Equals(q.Field("domain_id"), domains.Field("id"))) q.AppendField(domains.Field("id")) q.AppendField(domains.Field("name")) result := []apis.ProjectStatistic{} return result, q.All(&result) } func (manager *SVirtualResourceBaseManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacscope.TRbacScope) *sqlchemy.SQuery { q = manager.SStatusStandaloneResourceBaseManager.FilterByHiddenSystemAttributes(q, userCred, query, scope) isSystem := jsonutils.QueryBoolean(query, "system", false) if isSystem { var isAllow bool allowScope, result := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList, "system") if result.Result.IsAllow() && !scope.HigherThan(allowScope) { isAllow = true } if !isAllow { isSystem = false } } if !isSystem { q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("is_system")), sqlchemy.IsFalse(q.Field("is_system")))) } return q } func (model *SVirtualResourceBase) SetSystemInfo(isSystem bool) error { _, err := Update(model, func() error { model.IsSystem = isSystem return nil }) return err } func (model *SVirtualResourceBase) SetProjectInfo(ctx context.Context, userCred mcclient.TokenCredential, projectId, domainId string) error { _, err := Update(model, func() error { model.ProjectId = projectId model.DomainId = domainId return nil }) return err } func (manager *SVirtualResourceBaseManager) FilterBySystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacscope.TRbacScope) *sqlchemy.SQuery { q = manager.SStatusStandaloneResourceBaseManager.FilterBySystemAttributes(q, userCred, query, scope) q = manager.SPendingDeletedBaseManager.FilterBySystemAttributes(manager.GetIStandaloneModelManager(), q, userCred, query, scope) return q } func (manager *SVirtualResourceBaseManager) FetchByName(ctx context.Context, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { return FetchByName(ctx, manager, userCred, idStr) } func (manager *SVirtualResourceBaseManager) FetchByIdOrName(ctx context.Context, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { return FetchByIdOrName(ctx, manager, userCred, idStr) } func (manager *SVirtualResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.VirtualResourceCreateInput) (apis.VirtualResourceCreateInput, error) { var err error if input.IsSystem != nil && *input.IsSystem && IsAdminAllowCreate(userCred, manager).Result.IsDeny() { return input, httperrors.NewNotSufficientPrivilegeError("non-admin user not allowed to create system object") } input.StatusStandaloneResourceCreateInput, err = manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput) if err != nil { return input, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ValidateCreateData") } return input, nil } func (model *SVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { model.DomainId = ownerId.GetProjectDomainId() model.ProjectId = ownerId.GetProjectId() isSystem, err := data.Bool("is_system") if err == nil && isSystem { model.IsSystem = true } else { model.IsSystem = false } model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) return model.SStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) } func (model *SVirtualResourceBase) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { project, err := model.GetTenantCache(ctx) if err != nil { log.Errorf("unable to GetTenantCache: %s", err.Error()) return } err = InheritFromTo(ctx, userCred, project, model) if err != nil { log.Errorf("unable to inherit class metadata from poject %s: %s", project.GetId(), err.Error()) } model.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) } func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool, ) []apis.VirtualResourceDetails { ret := make([]apis.VirtualResourceDetails, len(objs)) stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) for i := range objs { ret[i] = apis.VirtualResourceDetails{ StatusStandaloneResourceDetails: stdRows[i], ProjectizedResourceInfo: projRows[i], } } return ret } func (model *SVirtualResourceBase) PreCheckPerformAction( ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject, ) error { if err := model.SStandaloneResourceBase.PreCheckPerformAction(ctx, userCred, action, query, data); err != nil { return err } if model.Freezed && action != "unfreeze" { return httperrors.NewBadRequestError("Virtual resource freezed, can't do %s", action) } return nil } func (model *SVirtualResourceBase) GetTenantCache(ctx context.Context) (*STenant, error) { // log.Debugf("Get tenant by Id %s", model.ProjectId) return TenantCacheManager.FetchTenantById(ctx, model.ProjectId) } // +onecloud:swagger-gen-ignore // freezed update and perform action operation except for unfreeze func (model *SVirtualResourceBase) PerformFreeze(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformFreezeInput) (jsonutils.JSONObject, error) { if model.Freezed { return nil, httperrors.NewBadRequestError("virtual resource already freezed") } _, err := Update(model, func() error { model.Freezed = true return nil }) if err != nil { return nil, err } vm := model.GetIVirtualModel() OpsLog.LogEvent(model, ACT_FREEZE, vm.GetShortDesc(ctx), userCred) logclient.AddActionLogWithContext(ctx, model, logclient.ACT_FREEZE, "perform freeze", userCred, true) return nil, nil } // +onecloud:swagger-gen-ignore func (model *SVirtualResourceBase) PerformUnfreeze(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformUnfreezeInput) (jsonutils.JSONObject, error) { if !model.Freezed { return nil, httperrors.NewBadRequestError("virtual resource not freezed") } _, err := Update(model, func() error { model.Freezed = false return nil }) if err != nil { return nil, err } vm := model.GetIVirtualModel() OpsLog.LogEvent(model, ACT_UNFREEZE, vm.GetShortDesc(ctx), userCred) logclient.AddActionLogWithContext(ctx, model, logclient.ACT_UNFREEZE, "perform unfreeze", userCred, true) return nil, nil } // 更改项目 func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { 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("SVirtualResourceBase 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.GetProjectId()) == 0 { return nil, httperrors.NewInputParameterError("missing new project/tenant") } if ownerId.GetProjectId() == model.ProjectId { // do nothing Update(model, func() error { model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) return nil }) return nil, nil } var requireScope rbacscope.TRbacScope if ownerId.GetProjectDomainId() != model.DomainId { // change domain, do check candidates := model.GetIVirtualModel().GetChangeOwnerCandidateDomainIds() if len(candidates) > 0 && !utils.IsInStringArray(ownerId.GetProjectDomainId(), candidates) { return nil, errors.Wrap(httperrors.ErrForbidden, "target domain not in change owner candidate list") } requireScope = rbacscope.ScopeSystem } else { requireScope = rbacscope.ScopeDomain } allowScope, policyTags := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.KeywordPlural(), policy.PolicyActionPerform, "change-owner") if requireScope.HigherThan(allowScope) { return nil, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope) } err = objectConfirmPolicyTags(ctx, model, policyTags) if err != nil { return nil, errors.Wrap(err, "objectConfirmPolicyTags") } if !consts.GetChangeOwnerAutoRename() { q := manager.Query().Equals("name", model.GetName()) q = manager.FilterByOwner(ctx, q, manager, userCred, 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.FetchTenantById(ctx, model.ProjectId) if former == nil { log.Warningf("tenant_id %s not found", model.ProjectId) formerObj := NewTenant(model.ProjectId, "unknown", model.DomainId, "unknown") former = &formerObj } else { // check fromer's class metadata cm, err := former.GetAllClassMetadata() if err != nil { return nil, errors.Wrap(err, "unable to GetAllClassMetadata") } if len(cm) > 0 { return nil, httperrors.NewForbiddenError("can't change owner for resource in project with class metadata") } } toer, err := TenantCacheManager.FetchTenantById(ctx, ownerId.GetProjectId()) if err != nil { return nil, errors.Wrapf(err, "unable to get project %s", ownerId.GetProjectId()) } toCm, err := toer.GetAllClassMetadata() if err != nil { return nil, errors.Wrap(err, "unable to GetAllClassMetadata") } if model.Keyword() != "image" && len(toCm) > 0 { return nil, httperrors.NewForbiddenError("can't change resource's owner as that in project with class metadata") } // clean shared projects before update project id if sharedModel, ok := model.GetIVirtualModel().(ISharableBaseModel); ok { if err := SharedResourceManager.CleanModelShares(ctx, userCred, sharedModel); err != nil { return nil, err } } // cancel usage model.cleanModelUsages(ctx, userCred) oldName := model.Name newName, err := GenerateName2(ctx, manager, ownerId, oldName, model, 1) if err != nil { return nil, errors.Wrap(err, "GenerateName2") } _, err = Update(model, func() error { if newName != oldName { model.Name = newName } model.DomainId = ownerId.GetProjectDomainId() model.ProjectId = ownerId.GetProjectId() model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) return nil }) if err != nil { return nil, errors.Wrap(err, "Update") } if oldName != model.Name { model.SetMetadata(ctx, "old_name", oldName, userCred) } // add usage model.RecoverUsages(ctx, userCred) OpsLog.SyncOwner(model, former, userCred) notes := struct { OldProjectId string OldProject string NewProjectId string NewProject string OldDomainId string OldDomain string NewDomainId string NewDomain string }{ OldProjectId: former.Id, OldProject: former.Name, NewProjectId: ownerId.GetProjectId(), NewProject: ownerId.GetProjectName(), OldDomainId: former.DomainId, OldDomain: former.Domain, NewDomainId: ownerId.GetProjectDomainId(), NewDomain: ownerId.GetProjectDomain(), } // set class metadata err = model.SetClassMetadataAll(ctx, toCm, userCred) if err != nil { return nil, errors.Wrap(err, "unable to SetClassMetadataAll") } logclient.AddActionLogWithContext(ctx, model, logclient.ACT_CHANGE_OWNER, notes, userCred, true) return nil, nil } func (model *SVirtualResourceBase) DoPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error { if !model.PendingDeleted { return model.SPendingDeletedBase.MarkPendingDelete(model.GetIStandaloneModel(), ctx, userCred, "") } return nil } func (model *SVirtualResourceBase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { err := model.DoPendingDelete(ctx, userCred) if err != nil { return errors.Wrap(err, "DoPendingDelete") } return DeleteModel(ctx, userCred, model.GetIVirtualModel()) } // +onecloud:swagger-gen-ignore func (model *SVirtualResourceBase) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { if model.PendingDeleted && !model.Deleted { err := model.DoCancelPendingDelete(ctx, userCred) if err != nil { return nil, errors.Wrap(err, "model.DoCancelPendingDelete") } model.RecoverUsages(ctx, userCred) } return nil, nil } func (model *SVirtualResourceBase) DoCancelPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error { if model.PendingDeleted && !model.Deleted { err := model.SPendingDeletedBase.MarkCancelPendingDelete(model.GetIStandaloneModel(), ctx, userCred) if err != nil { return errors.Wrap(err, "MarkCancelPendingDelete") } } return nil } func (model *SVirtualResourceBase) VirtualModelManager() IVirtualModelManager { return model.GetModelManager().(IVirtualModelManager) } func (model *SVirtualResourceBase) GetIVirtualModel() IVirtualModel { return model.GetVirtualObject().(IVirtualModel) } func (model *SVirtualResourceBase) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc := model.SStatusStandaloneResourceBase.GetShortDesc(ctx) desc.Add(jsonutils.NewString(model.ProjectId), "owner_tenant_id") tc, _ := TenantCacheManager.FetchTenantById(ctx, model.ProjectId) if tc != nil { desc.Add(jsonutils.NewString(tc.GetName()), "owner_tenant") metadata, _ := GetVisibleMetadata(ctx, tc, nil) desc.Set("project_tags", jsonutils.Marshal(metadata)) } return desc } func (model *SVirtualResourceBase) SetProjectSrc(src apis.TOwnerSource) { if model.ProjectSrc != string(src) { Update(model, func() error { model.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD) return nil }) } } func (model *SVirtualResourceBase) SyncCloudProjectId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) { if model.ProjectSrc != string(apis.OWNER_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectId()) > 0 { diff, _ := Update(model, func() error { model.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD) model.ProjectId = ownerId.GetProjectId() model.DomainId = ownerId.GetProjectDomainId() return nil }) if len(diff) > 0 { OpsLog.LogEvent(model, ACT_SYNC_OWNER, diff, userCred) } } } func (manager *SVirtualResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.VirtualResourceListInput) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, err } q, err = manager.SProjectizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ProjectizedResourceListInput) if err != nil { return nil, err } return q, nil } func (manager *SVirtualResourceBaseManager) ListItemFilter( ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.VirtualResourceListInput, ) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput) if err != nil { return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemFilter") } return q, nil } func (manager *SVirtualResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { return q, nil } q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { return q, nil } return q, httperrors.ErrNotFound } func (model *SVirtualResourceBase) ValidateUpdateData( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.VirtualResourceBaseUpdateInput, ) (apis.VirtualResourceBaseUpdateInput, error) { var err error input.StatusStandaloneResourceBaseUpdateInput, err = model.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput) if err != nil { return input, errors.Wrap(err, "SStatusStandaloneResourceBase.ValidateUpdateData") } return input, nil } // +onecloud:swagger-gen-ignore func (model *SVirtualResourceBase) GetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.ChangeOwnerCandidateDomainsOutput, error) { return IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(model.GetIVirtualModel()) } func (manager *SVirtualResourceBaseManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys") } q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) if err != nil { return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemExportKeys") } return q, nil } func (manager *SVirtualResourceBaseManager) GetExportExtraKeys(ctx context.Context, keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict { res := manager.SStatusStandaloneResourceBaseManager.GetExportExtraKeys(ctx, keys, rowMap) if userTags, ok := rowMap["user_tags"]; ok && len(userTags) > 0 { res.Set("user_tags", jsonutils.NewString(userTags)) } return res } // +onecloud:swagger-gen-ignore func (manager *SVirtualResourceBaseManager) GetPropertyProjectTagValuePairs( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, ) (jsonutils.JSONObject, error) { return GetPropertyTagValuePairs( manager.GetIVirtualModelManager(), "project", "tenant_id", ctx, userCred, query, ) } // +onecloud:swagger-gen-ignore func (manager *SVirtualResourceBaseManager) GetPropertyProjectTagValueTree( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, ) (jsonutils.JSONObject, error) { return GetPropertyTagValueTree( manager.GetIVirtualModelManager(), "project", "tenant_id", "", ctx, userCred, query, ) }