mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-08 22:49:22 +08:00
265 lines
8.6 KiB
Go
265 lines
8.6 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 (
|
|
"strings"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/rbacscope"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
"yunion.io/x/onecloud/pkg/apis"
|
|
"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"
|
|
"yunion.io/x/onecloud/pkg/util/tagutils"
|
|
)
|
|
|
|
type SMetadataResourceBaseModelManager struct{}
|
|
|
|
func ObjectIdQueryWithPolicyResult(q *sqlchemy.SQuery, manager IModelManager, result rbacutils.SPolicyResult) *sqlchemy.SQuery {
|
|
scope := manager.ResourceScope()
|
|
if scope == rbacscope.ScopeDomain || scope == rbacscope.ScopeProject {
|
|
if !result.DomainTags.IsEmpty() {
|
|
tagFilters := tagutils.STagFilters{}
|
|
tagFilters.AddFilters(result.DomainTags)
|
|
q = ObjectIdQueryWithTagFilters(q, "domain_id", "domain", tagFilters)
|
|
}
|
|
}
|
|
if scope == rbacscope.ScopeProject {
|
|
if !result.ProjectTags.IsEmpty() {
|
|
tagFilters := tagutils.STagFilters{}
|
|
tagFilters.AddFilters(result.ProjectTags)
|
|
q = ObjectIdQueryWithTagFilters(q, "tenant_id", "project", tagFilters)
|
|
}
|
|
}
|
|
if !result.ObjectTags.IsEmpty() {
|
|
tagFilters := tagutils.STagFilters{}
|
|
tagFilters.AddFilters(result.ObjectTags)
|
|
q = ObjectIdQueryWithTagFilters(q, "id", manager.Keyword(), tagFilters)
|
|
}
|
|
return q
|
|
}
|
|
|
|
func ObjectIdQueryWithTagFilters(q *sqlchemy.SQuery, idField string, modelName string, filters tagutils.STagFilters) *sqlchemy.SQuery {
|
|
if len(filters.Filters) > 0 {
|
|
sq := objIdQueryWithTags(modelName, filters.Filters)
|
|
if sq != nil {
|
|
sqq := sq.SubQuery()
|
|
q = q.Join(sqq, sqlchemy.Equals(q.Field(idField), sqq.Field("obj_id")))
|
|
}
|
|
}
|
|
if len(filters.NoFilters) > 0 {
|
|
sq := objIdQueryWithTags(modelName, filters.NoFilters)
|
|
if sq != nil {
|
|
q = q.Filter(sqlchemy.NotIn(q.Field(idField), sq.SubQuery()))
|
|
}
|
|
}
|
|
return q
|
|
}
|
|
|
|
func objIdQueryWithTags(modelName string, tagsList []map[string][]string) *sqlchemy.SQuery {
|
|
metadataResQ := Metadata.Query().Equals("obj_type", modelName).SubQuery()
|
|
|
|
queries := make([]sqlchemy.IQuery, 0)
|
|
for _, tags := range tagsList {
|
|
if len(tags) == 0 {
|
|
continue
|
|
}
|
|
metadataView := metadataResQ.Query(metadataResQ.Field("obj_id"))
|
|
for key, val := range tags {
|
|
q := metadataResQ.Query().Equals("key", key)
|
|
if len(val) > 0 {
|
|
q = q.Equals("key", key).In("value", val)
|
|
}
|
|
sq := q.SubQuery()
|
|
metadataView = metadataView.Join(sq, sqlchemy.Equals(metadataView.Field("id"), sq.Field("id")))
|
|
}
|
|
queries = append(queries, metadataView.Distinct())
|
|
}
|
|
if len(queries) == 0 {
|
|
return nil
|
|
}
|
|
var query sqlchemy.IQuery
|
|
if len(queries) == 1 {
|
|
query = queries[0]
|
|
} else {
|
|
uq, _ := sqlchemy.UnionWithError(queries...)
|
|
query = uq.Query()
|
|
}
|
|
return query.SubQuery().Query()
|
|
}
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) ListItemFilter(
|
|
manager IModelManager,
|
|
q *sqlchemy.SQuery,
|
|
input apis.MetadataResourceListInput,
|
|
) *sqlchemy.SQuery {
|
|
|
|
inputTagFilters := tagutils.STagFilters{}
|
|
if len(input.Tags) > 0 {
|
|
inputTagFilters.AddFilter(input.Tags)
|
|
}
|
|
if !input.ObjTags.IsEmpty() {
|
|
inputTagFilters.AddFilters(input.ObjTags)
|
|
}
|
|
if len(input.NoTags) > 0 {
|
|
inputTagFilters.AddNoFilter(input.NoTags)
|
|
}
|
|
if !input.NoObjTags.IsEmpty() {
|
|
inputTagFilters.AddNoFilters(input.NoObjTags)
|
|
}
|
|
q = ObjectIdQueryWithTagFilters(q, "id", manager.Keyword(), inputTagFilters)
|
|
|
|
//if !input.PolicyObjectTags.IsEmpty() {
|
|
// projTagFilters := tagutils.STagFilters{}
|
|
// projTagFilters.AddFilters(input.PolicyObjectTags)
|
|
// q = ObjectIdQueryWithTagFilters(q, "id", manager.Keyword(), projTagFilters)
|
|
//}
|
|
|
|
if input.WithoutUserMeta != nil || input.WithUserMeta != nil {
|
|
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
|
sq := metadatas.Query(metadatas.Field("obj_id")).Startswith("key", USER_TAG_PREFIX).Distinct().SubQuery()
|
|
if (input.WithoutUserMeta != nil && *input.WithoutUserMeta) || (input.WithUserMeta != nil && !*input.WithUserMeta) {
|
|
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
|
} else {
|
|
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
|
}
|
|
}
|
|
|
|
if input.WithCloudMeta != nil {
|
|
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
|
sq := metadatas.Query(metadatas.Field("obj_id")).Startswith("key", CLOUD_TAG_PREFIX).Distinct().SubQuery()
|
|
if *input.WithCloudMeta {
|
|
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
|
} else {
|
|
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
|
}
|
|
}
|
|
|
|
if input.WithAnyMeta != nil {
|
|
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
|
sq := metadatas.Query(metadatas.Field("obj_id")).Distinct().SubQuery()
|
|
if *input.WithAnyMeta {
|
|
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
|
} else {
|
|
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
|
}
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) QueryDistinctExtraField(manager IModelManager, 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
|
|
}
|
|
return q, httperrors.ErrNotFound
|
|
}
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) OrderByExtraFields(
|
|
manager IModelManager,
|
|
q *sqlchemy.SQuery,
|
|
input apis.MetadataResourceListInput,
|
|
) *sqlchemy.SQuery {
|
|
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
|
|
}
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) FetchCustomizeColumns(
|
|
manager IModelManager,
|
|
userCred mcclient.TokenCredential,
|
|
objs []interface{},
|
|
fields stringutils2.SSortedStrings,
|
|
) []apis.MetadataResourceInfo {
|
|
ret := make([]apis.MetadataResourceInfo, len(objs))
|
|
resIds := make([]string, len(objs))
|
|
for i := range objs {
|
|
resIds[i] = GetModelIdstr(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.(IMetadataBaseModelManager), userCred, metaList)
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
const (
|
|
TAG_EXPORT_KEY_PREFIX = "tag:"
|
|
)
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) GetExportExtraKeys(keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict {
|
|
res := jsonutils.NewDict()
|
|
for _, key := range keys {
|
|
if strings.HasPrefix(key, TAG_EXPORT_KEY_PREFIX) {
|
|
res.Add(jsonutils.NewString(rowMap[key]), key)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (meta *SMetadataResourceBaseModelManager) ListItemExportKeys(manager IModelManager, q *sqlchemy.SQuery, keys stringutils2.SSortedStrings) *sqlchemy.SQuery {
|
|
keyMaps := map[string]bool{}
|
|
for _, key := range keys {
|
|
if strings.HasPrefix(key, TAG_EXPORT_KEY_PREFIX) {
|
|
tagKey := key[len(TAG_EXPORT_KEY_PREFIX):]
|
|
if _, ok := keyMaps[strings.ToLower(tagKey)]; !ok {
|
|
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))
|
|
keyMaps[strings.ToLower(tagKey)] = true
|
|
}
|
|
}
|
|
}
|
|
return q
|
|
}
|