mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-23 14:04:09 +08:00
595 lines
22 KiB
Go
595 lines
22 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"
|
||
"strings"
|
||
|
||
"yunion.io/x/jsonutils"
|
||
"yunion.io/x/log"
|
||
"yunion.io/x/pkg/errors"
|
||
"yunion.io/x/pkg/util/regutils"
|
||
"yunion.io/x/pkg/util/stringutils"
|
||
"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/rbacutils"
|
||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||
)
|
||
|
||
type UUIDGenerator func() string
|
||
|
||
var (
|
||
DefaultUUIDGenerator = stringutils.UUID4
|
||
)
|
||
|
||
type SStandaloneResourceBase struct {
|
||
SResourceBase
|
||
|
||
// 资源UUID
|
||
Id string `width:"128" charset:"ascii" primary:"true" list:"user" json:"id"`
|
||
// 资源名称
|
||
Name string `width:"128" charset:"utf8" nullable:"false" index:"true" list:"user" update:"user" create:"required" json:"name"`
|
||
|
||
// 资源描述信息
|
||
Description string `width:"256" charset:"utf8" get:"user" list:"user" update:"user" create:"optional" json:"description"`
|
||
|
||
// 是否是模拟资源, 部分从公有云上同步的资源并不真实存在, 例如宿主机
|
||
// list 接口默认不会返回这类资源,除非显示指定 is_emulate=true 过滤参数
|
||
IsEmulated bool `nullable:"false" default:"false" list:"admin" create:"admin_optional" json:"is_emulated"`
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) BeforeInsert() {
|
||
if len(model.Id) == 0 {
|
||
model.Id = DefaultUUIDGenerator()
|
||
}
|
||
}
|
||
|
||
type SStandaloneResourceBaseManager struct {
|
||
SResourceBaseManager
|
||
NameRequireAscii bool
|
||
NameLength int
|
||
}
|
||
|
||
func NewStandaloneResourceBaseManager(
|
||
dt interface{},
|
||
tableName string,
|
||
keyword string,
|
||
keywordPlural string,
|
||
) SStandaloneResourceBaseManager {
|
||
return SStandaloneResourceBaseManager{
|
||
SResourceBaseManager: NewResourceBaseManager(dt, tableName, keyword, keywordPlural),
|
||
}
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) IsStandaloneManager() bool {
|
||
return true
|
||
}
|
||
|
||
func (self *SStandaloneResourceBaseManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||
return IsAdminAllowList(userCred, self)
|
||
}
|
||
|
||
func (self *SStandaloneResourceBaseManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||
return IsAdminAllowCreate(userCred, self)
|
||
}
|
||
|
||
func (self *SStandaloneResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||
return IsAdminAllowGet(userCred, self)
|
||
}
|
||
|
||
func (self *SStandaloneResourceBase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
|
||
return IsAdminAllowUpdate(userCred, self)
|
||
}
|
||
|
||
func (self *SStandaloneResourceBase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||
return IsAdminAllowDelete(userCred, self)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) GetIStandaloneModelManager() IStandaloneModelManager {
|
||
return manager.GetVirtualObject().(IStandaloneModelManager)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
|
||
return q.Equals("id", idStr)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FilterByNotId(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
|
||
return q.NotEquals("id", idStr)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FilterByName(q *sqlchemy.SQuery, name string) *sqlchemy.SQuery {
|
||
return q.Equals("name", name)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
|
||
q = manager.SResourceBaseManager.FilterByHiddenSystemAttributes(q, userCred, query, scope)
|
||
showEmulated := jsonutils.QueryBoolean(query, "show_emulated", false)
|
||
if showEmulated {
|
||
var isAllow bool
|
||
if consts.IsRbacEnabled() {
|
||
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList, "show_emulated")
|
||
if !scope.HigherThan(allowScope) {
|
||
isAllow = true
|
||
}
|
||
} else {
|
||
if userCred.HasSystemAdminPrivilege() {
|
||
isAllow = true
|
||
}
|
||
}
|
||
if !isAllow {
|
||
showEmulated = false
|
||
}
|
||
}
|
||
if !showEmulated {
|
||
q = q.IsFalse("is_emulated")
|
||
}
|
||
return q
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) ValidateName(name string) error {
|
||
if manager.NameRequireAscii && !regutils.MatchName(name) {
|
||
return httperrors.NewInputParameterError("name starts with letter, and contains letter, number and ._@- only")
|
||
}
|
||
if manager.NameLength > 0 && len(name) > manager.NameLength {
|
||
return httperrors.NewInputParameterError("name longer than %d", manager.NameLength)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FetchById(idStr string) (IModel, error) {
|
||
return FetchById(manager.GetIStandaloneModelManager(), idStr)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) {
|
||
return FetchByName(manager.GetIStandaloneModelManager(), userCred, idStr)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) {
|
||
return FetchByIdOrName(manager.GetIStandaloneModelManager(), userCred, idStr)
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) ListItemFilter(
|
||
ctx context.Context,
|
||
q *sqlchemy.SQuery,
|
||
userCred mcclient.TokenCredential,
|
||
input apis.StandaloneResourceListInput,
|
||
) (*sqlchemy.SQuery, error) {
|
||
q, err := manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ResourceBaseListInput)
|
||
if err != nil {
|
||
return q, errors.Wrap(err, "SResourceBaseManager.ListItemFilte")
|
||
}
|
||
|
||
// show_emulated is handled by FilterByHiddenSystemAttributes
|
||
|
||
if len(input.Names) > 0 {
|
||
q = q.In("name", input.Names)
|
||
}
|
||
|
||
if len(input.Ids) > 0 {
|
||
q = q.In("id", input.Ids)
|
||
}
|
||
|
||
tags := map[string][]string{}
|
||
for _, tag := range input.Tags {
|
||
if _, ok := tags[tag.Key]; !ok {
|
||
tags[tag.Key] = []string{}
|
||
}
|
||
if len(tag.Value) > 0 && !utils.IsInStringArray(tag.Value, tags[tag.Key]) {
|
||
tags[tag.Key] = append(tags[tag.Key], tag.Value)
|
||
}
|
||
}
|
||
|
||
if len(tags) > 0 {
|
||
metadataResQ := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
||
metadataView := metadataResQ.Query()
|
||
idx := 0
|
||
for key, values := range tags {
|
||
if idx == 0 {
|
||
metadataView = metadataView.Equals("key", key)
|
||
if len(values) > 0 {
|
||
metadataView = metadataView.In("value", values)
|
||
}
|
||
} else {
|
||
subMetataView := metadataResQ.Query().Equals("key", key)
|
||
if len(values) > 0 {
|
||
subMetataView = subMetataView.In("value", values)
|
||
}
|
||
sq := subMetataView.SubQuery()
|
||
metadataView.Join(sq, sqlchemy.Equals(metadataView.Field("id"), sq.Field("id")))
|
||
}
|
||
idx++
|
||
}
|
||
metadatas := metadataView.SubQuery()
|
||
sq := metadatas.Query(metadatas.Field("obj_id")).Distinct().SubQuery()
|
||
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
||
}
|
||
|
||
if input.WithoutUserMeta {
|
||
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
||
sq := metadatas.Query(metadatas.Field("obj_id")).Startswith("key", USER_TAG_PREFIX).Distinct().SubQuery()
|
||
q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
||
}
|
||
|
||
return q, nil
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
||
if strings.HasPrefix(field, "tag:") {
|
||
tagKey := field[4:]
|
||
metaQ := Metadata.Query("obj_id", "value").Equals("obj_type", manager.Keyword()).Equals("key", tagKey).SubQuery()
|
||
q = q.AppendField(metaQ.Field("value", field)).Distinct()
|
||
q = q.LeftJoin(metaQ, sqlchemy.Equals(q.Field("id"), metaQ.Field("obj_id")))
|
||
q = q.Asc(metaQ.Field("value"))
|
||
return q, nil
|
||
}
|
||
q, err := manager.SResourceBaseManager.QueryDistinctExtraField(q, field)
|
||
if err == nil {
|
||
return q, nil
|
||
}
|
||
return q, httperrors.ErrNotFound
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) OrderByExtraFields(
|
||
ctx context.Context,
|
||
q *sqlchemy.SQuery,
|
||
userCred mcclient.TokenCredential,
|
||
input apis.StandaloneResourceListInput,
|
||
) (*sqlchemy.SQuery, error) {
|
||
q, err := manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ResourceBaseListInput)
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFields")
|
||
}
|
||
|
||
if len(input.OrderByTag) > 0 {
|
||
order := sqlchemy.SQL_ORDER_ASC
|
||
tagKey := input.OrderByTag
|
||
if stringutils2.HasSuffixIgnoreCase(input.OrderByTag, string(sqlchemy.SQL_ORDER_ASC)) {
|
||
tagKey = tagKey[0 : len(tagKey)-len(sqlchemy.SQL_ORDER_ASC)-1]
|
||
} else if stringutils2.HasSuffixIgnoreCase(input.OrderByTag, string(sqlchemy.SQL_ORDER_DESC)) {
|
||
tagKey = tagKey[0 : len(tagKey)-len(sqlchemy.SQL_ORDER_DESC)-1]
|
||
order = sqlchemy.SQL_ORDER_DESC
|
||
}
|
||
metaQ := Metadata.Query("obj_id", "value").Equals("obj_type", manager.Keyword()).Equals("key", tagKey).SubQuery()
|
||
q = q.LeftJoin(metaQ, sqlchemy.Equals(q.Field("id"), metaQ.Field("obj_id")))
|
||
if order == sqlchemy.SQL_ORDER_ASC {
|
||
q = q.Asc(metaQ.Field("value"))
|
||
} else {
|
||
q = q.Desc(metaQ.Field("value"))
|
||
}
|
||
}
|
||
|
||
return q, nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) StandaloneModelManager() IStandaloneModelManager {
|
||
return model.GetModelManager().(IStandaloneModelManager)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetId() string {
|
||
return model.Id
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetName() string {
|
||
return model.Name
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetIStandaloneModel() IStandaloneModel {
|
||
return model.GetVirtualObject().(IStandaloneModel)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
|
||
desc := model.SResourceBase.GetShortDesc(ctx)
|
||
desc.Add(jsonutils.NewString(model.GetName()), "name")
|
||
desc.Add(jsonutils.NewString(model.GetId()), "id")
|
||
/*if len(model.ExternalId) > 0 {
|
||
desc.Add(jsonutils.NewString(model.ExternalId), "external_id")
|
||
}*/
|
||
return desc
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetShortDescV2(ctx context.Context) *apis.StandaloneResourceShortDescDetail {
|
||
desc := &apis.StandaloneResourceShortDescDetail{}
|
||
desc.ModelBaseShortDescDetail = *model.SResourceBase.GetShortDescV2(ctx)
|
||
desc.Name = model.GetName()
|
||
desc.Id = model.GetId()
|
||
return desc
|
||
}
|
||
|
||
/*
|
||
* userCred: optional
|
||
*/
|
||
func (model *SStandaloneResourceBase) GetMetadata(key string, userCred mcclient.TokenCredential) string {
|
||
return Metadata.GetStringValue(model, key, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetMetadataJson(key string, userCred mcclient.TokenCredential) jsonutils.JSONObject {
|
||
return Metadata.GetJsonValue(model, key, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) SetMetadata(ctx context.Context, key string, value interface{}, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetValue(ctx, model, key, value, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) SetAllMetadata(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) SetUserMetadataValues(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) SetUserMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetAll(ctx, model, dictstore, userCred, USER_TAG_PREFIX)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) SetCloudMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetAll(ctx, model, dictstore, userCred, CLOUD_TAG_PREFIX)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) RemoveMetadata(ctx context.Context, key string, userCred mcclient.TokenCredential) error {
|
||
return Metadata.SetValue(ctx, model, key, "", userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) RemoveAllMetadata(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||
return Metadata.RemoveAll(ctx, model, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) {
|
||
return Metadata.GetAll(model, nil, userCred)
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) AllowGetDetailsMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||
return IsAllowGetSpec(rbacutils.ScopeSystem, userCred, model, "metadata")
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetDetailsMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||
fields := jsonutils.GetQueryStringArray(query, "field")
|
||
val, err := Metadata.GetAll(model, fields, userCred)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return jsonutils.Marshal(val), nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) AllowPerformMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "metadata")
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PerformMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||
dict, ok := data.(*jsonutils.JSONDict)
|
||
if !ok {
|
||
return nil, httperrors.NewInputParameterError("input data not key value dict")
|
||
}
|
||
dictMap, err := dict.GetMap()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
dictStore := make(map[string]interface{})
|
||
for k, v := range dictMap {
|
||
// 已双下滑线开头的metadata是系统内置,普通用户不可添加,只能查看
|
||
if strings.HasPrefix(k, SYS_TAG_PREFIX) && (userCred == nil || !IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "metadata")) {
|
||
return nil, httperrors.NewForbiddenError("not allow to set system key, please remove the underscore at the beginning")
|
||
}
|
||
dictStore[k], _ = v.GetString()
|
||
}
|
||
err = model.SetAllMetadata(ctx, dictStore, userCred)
|
||
return nil, err
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) AllowPerformUserMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "user-metadata")
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PerformUserMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||
dict, ok := data.(*jsonutils.JSONDict)
|
||
if !ok {
|
||
return nil, httperrors.NewInputParameterError("input data not key value dict")
|
||
}
|
||
dictMap, err := dict.GetMap()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
dictStore := make(map[string]interface{})
|
||
for k, v := range dictMap {
|
||
dictStore[USER_TAG_PREFIX+k], _ = v.GetString()
|
||
}
|
||
err = model.SetUserMetadataValues(ctx, dictStore, userCred)
|
||
return nil, err
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) AllowPerformSetUserMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||
return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "set-user-metadata")
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PerformSetUserMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||
dict, ok := data.(*jsonutils.JSONDict)
|
||
if !ok {
|
||
return nil, httperrors.NewInputParameterError("input data not key value dict")
|
||
}
|
||
dictMap, err := dict.GetMap()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
dictStore := make(map[string]interface{})
|
||
for k, v := range dictMap {
|
||
dictStore[USER_TAG_PREFIX+k], _ = v.GetString()
|
||
}
|
||
err = model.SetUserMetadataAll(ctx, dictStore, userCred)
|
||
return nil, err
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||
model.SResourceBase.PostUpdate(ctx, userCred, query, data)
|
||
|
||
jsonMeta, _ := data.Get("__meta__")
|
||
if jsonMeta != nil {
|
||
model.PerformMetadata(ctx, userCred, nil, jsonMeta)
|
||
}
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||
model.SResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
|
||
|
||
jsonMeta, _ := data.Get("__meta__")
|
||
if jsonMeta != nil {
|
||
model.PerformMetadata(ctx, userCred, nil, jsonMeta)
|
||
}
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
|
||
if model.Deleted {
|
||
model.RemoveAllMetadata(ctx, userCred)
|
||
}
|
||
model.SResourceBase.PostDelete(ctx, userCred)
|
||
}
|
||
|
||
// func (model *SStandaloneResourceBase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||
// return DeleteModel(ctx, userCred, model)
|
||
// }
|
||
|
||
func (model *SStandaloneResourceBase) ClearSchedDescCache() error {
|
||
return nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) AppendDescription(userCred mcclient.TokenCredential, msg string) error {
|
||
_, err := Update(model.GetIStandaloneModel(), func() error {
|
||
if len(model.Description) > 0 {
|
||
model.Description += ";"
|
||
}
|
||
model.Description += msg
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
return errors.Wrap(err, "db.Update")
|
||
}
|
||
OpsLog.LogEvent(model, "append_desc", msg, userCred)
|
||
return nil
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.StandaloneResourceCreateInput) (apis.StandaloneResourceCreateInput, error) {
|
||
var err error
|
||
input.ResourceBaseCreateInput, err = manager.SResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.ResourceBaseCreateInput)
|
||
if err != nil {
|
||
return input, errors.Wrap(err, "SResourceBaseManager.ValidateCreateData")
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.StandaloneResourceDetails, error) {
|
||
return apis.StandaloneResourceDetails{}, nil
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) FetchCustomizeColumns(
|
||
ctx context.Context,
|
||
userCred mcclient.TokenCredential,
|
||
query jsonutils.JSONObject,
|
||
objs []interface{},
|
||
fields stringutils2.SSortedStrings,
|
||
isList bool,
|
||
) []apis.StandaloneResourceDetails {
|
||
ret := make([]apis.StandaloneResourceDetails, len(objs))
|
||
resIds := make([]string, len(objs))
|
||
upperRet := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||
for i := range objs {
|
||
ret[i] = apis.StandaloneResourceDetails{
|
||
ResourceBaseDetails: upperRet[i],
|
||
}
|
||
resIds[i] = GetObjectIdstr(objs[i].(IModel))
|
||
}
|
||
|
||
if fields == nil || fields.Contains("__meta__") {
|
||
q := Metadata.Query("id", "key", "value")
|
||
metaKeyValues := make(map[string][]SMetadata)
|
||
err := FetchQueryObjectsByIds(q, "id", resIds, &metaKeyValues)
|
||
if err != nil {
|
||
log.Errorf("FetchQueryObjectsByIds metadata fail %s", err)
|
||
return ret
|
||
}
|
||
|
||
for i := range objs {
|
||
if metaList, ok := metaKeyValues[resIds[i]]; ok {
|
||
ret[i].Metadata = metaList2Map(manager.GetIStandaloneModelManager(), userCred, metaList)
|
||
}
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) GetMetadataHiddenKeys() []string {
|
||
return nil
|
||
}
|
||
|
||
const (
|
||
TAG_EXPORT_KEY_PREFIX = "tag:"
|
||
)
|
||
|
||
func (manager *SStandaloneResourceBaseManager) GetExportExtraKeys(ctx context.Context, keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict {
|
||
res := manager.SResourceBaseManager.GetExportExtraKeys(ctx, keys, rowMap)
|
||
|
||
for _, key := range keys {
|
||
if strings.HasPrefix(key, TAG_EXPORT_KEY_PREFIX) {
|
||
res.Add(jsonutils.NewString(rowMap[key]), key)
|
||
}
|
||
}
|
||
|
||
return res
|
||
}
|
||
|
||
func (manager *SStandaloneResourceBaseManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
|
||
var err error
|
||
q, err = manager.SResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "SResourceBaseManager.ListItemExportKeys")
|
||
}
|
||
|
||
for _, key := range keys {
|
||
if strings.HasPrefix(key, TAG_EXPORT_KEY_PREFIX) {
|
||
tagKey := key[len(TAG_EXPORT_KEY_PREFIX):]
|
||
metaQ := Metadata.Query("obj_id", "value").Equals("obj_type", manager.Keyword()).Equals("key", tagKey).SubQuery()
|
||
q = q.LeftJoin(metaQ, sqlchemy.Equals(q.Field("id"), metaQ.Field("obj_id")))
|
||
q = q.AppendField(metaQ.Field("value", key))
|
||
}
|
||
}
|
||
|
||
return q, nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.StandaloneResourceBaseUpdateInput) (apis.StandaloneResourceBaseUpdateInput, error) {
|
||
var err error
|
||
input.ResourceBaseUpdateInput, err = model.SResourceBase.ValidateUpdateData(ctx, userCred, query, input.ResourceBaseUpdateInput)
|
||
if err != nil {
|
||
return input, errors.Wrap(err, "SModelBase.ValidateUpdateData")
|
||
}
|
||
|
||
if len(input.Name) > 0 {
|
||
err = alterNameValidator(model.GetIStandaloneModel(), input.Name)
|
||
if err != nil {
|
||
return input, errors.Wrap(err, "alterNameValidator")
|
||
}
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (model *SStandaloneResourceBase) IsShared() bool {
|
||
return false
|
||
}
|