diff --git a/pkg/apis/cloudcommon/db/metadata.go b/pkg/apis/cloudcommon/db/metadata.go index 26294fe172..33ea11211c 100644 --- a/pkg/apis/cloudcommon/db/metadata.go +++ b/pkg/apis/cloudcommon/db/metadata.go @@ -20,4 +20,5 @@ const ( CLOUD_TAG_PREFIX = apis.CLOUD_TAG_PREFIX USER_TAG_PREFIX = apis.USER_TAG_PREFIX SYS_CLOUD_TAG_PREFIX = apis.SYS_CLOUD_TAG_PREFIX + CLASS_TAT_PREFIX = apis.CLASS_TAT_PREFIX ) diff --git a/pkg/apis/const.go b/pkg/apis/const.go index 55b8eb4a78..0beca5fb00 100644 --- a/pkg/apis/const.go +++ b/pkg/apis/const.go @@ -51,6 +51,8 @@ const ( CLOUD_TAG_PREFIX = "ext:" USER_TAG_PREFIX = "user:" SYS_CLOUD_TAG_PREFIX = "sys:" + // Such tags have inherited and isolated properties + CLASS_TAT_PREFIX = "cls:" ) var ( diff --git a/pkg/apis/input.go b/pkg/apis/input.go index a4155cabfc..323d273eb5 100644 --- a/pkg/apis/input.go +++ b/pkg/apis/input.go @@ -344,6 +344,10 @@ type PerformUserMetadataInput map[string]string // 全量替换资源的用户标签(元数据)输入 type PerformSetUserMetadataInput map[string]string +type PerformSetClassMetadataInput map[string]string + +type GetClassMetadataOutput map[string]string + // 获取资源的元数据输入 type GetMetadataInput struct { // 指定需要获取的所有标签的KEY列表,如果列表为空,则获取全部标签 diff --git a/pkg/cloudcommon/db/metadata.go b/pkg/cloudcommon/db/metadata.go index 630106a643..1882a3f713 100644 --- a/pkg/cloudcommon/db/metadata.go +++ b/pkg/cloudcommon/db/metadata.go @@ -45,6 +45,7 @@ const ( CLOUD_TAG_PREFIX = dbapi.CLOUD_TAG_PREFIX USER_TAG_PREFIX = dbapi.USER_TAG_PREFIX SYS_CLOUD_TAG_PREFIX = dbapi.SYS_CLOUD_TAG_PREFIX + CLASS_TAG_PREFIX = dbapi.CLASS_TAT_PREFIX // TAG_DELETE_RANGE_USER = "user" // TAG_DELETE_RANGE_CLOUD = CLOUD_TAG_PREFIX // "cloud" @@ -602,14 +603,15 @@ func (manager *SMetadataManager) rawSetValues(ctx context.Context, objType strin if replace { records := []SMetadata{} q := manager.Query().Equals("id", idStr).NotLike("key", `\_\_%`) //避免删除系统内置的metadata, _ 在mysql里面有特殊含义,需要转义 - switch replaceRange { - case USER_TAG_PREFIX: - q = q.Startswith("key", USER_TAG_PREFIX) - case CLOUD_TAG_PREFIX: - q = q.Startswith("key", CLOUD_TAG_PREFIX) - case SYS_CLOUD_TAG_PREFIX: - q = q.Startswith("key", SYS_CLOUD_TAG_PREFIX) - } + // switch replaceRange { + // case USER_TAG_PREFIX: + // q = q.Startswith("key", USER_TAG_PREFIX) + // case CLOUD_TAG_PREFIX: + // q = q.Startswith("key", CLOUD_TAG_PREFIX) + // case SYS_CLOUD_TAG_PREFIX: + // q = q.Startswith("key", SYS_CLOUD_TAG_PREFIX) + // } + q = q.Startswith("key", replaceRange) q = q.Filter(sqlchemy.NOT(sqlchemy.In(q.Field("key"), keys))) if err := FetchModelObjects(manager, q, &records); err != nil { log.Errorf("failed to fetch metadata error: %v", err) diff --git a/pkg/cloudcommon/db/standalone_anon.go b/pkg/cloudcommon/db/standalone_anon.go index 6911a9f209..68f2272991 100644 --- a/pkg/cloudcommon/db/standalone_anon.go +++ b/pkg/cloudcommon/db/standalone_anon.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/stringutils2" "yunion.io/x/onecloud/pkg/util/tagutils" @@ -63,6 +64,7 @@ func (model *SStandaloneAnonResourceBase) BeforeInsert() { type SStandaloneAnonResourceBaseManager struct { SResourceBaseManager SMetadataResourceBaseModelManager + SSecretResourceBaseModelManager } func NewStandaloneAnonResourceBaseManager( @@ -139,6 +141,8 @@ func (manager *SStandaloneAnonResourceBaseManager) ListItemFilter( q = manager.SMetadataResourceBaseModelManager.ListItemFilter(manager.GetIModelManager(), q, input.MetadataResourceListInput) + q = manager.SSecretResourceBaseModelManager.ListItemFilter(manager.GetIModelManager(), q, input.SecretResourceListInput) + return q, nil } @@ -274,6 +278,58 @@ func (model *SStandaloneAnonResourceBase) SetCloudMetadataAll(ctx context.Contex return Metadata.SetAll(ctx, model, userTags, userCred, USER_TAG_PREFIX) } +func (model *SStandaloneAnonResourceBase) SetClassMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error { + afterCheck := make(map[string]interface{}, len(dictstore)) + for k, v := range dictstore { + if !strings.HasPrefix(k, CLASS_TAG_PREFIX) { + afterCheck[CLASS_TAG_PREFIX+k] = v + } else { + afterCheck[k] = v + } + } + err := Metadata.SetAll(ctx, model, afterCheck, userCred, CLASS_TAG_PREFIX) + if err != nil { + return errors.Wrap(err, "SetAll") + } + return nil +} + +func (model *SStandaloneAnonResourceBase) Inherit(ctx context.Context, sonModel *SStandaloneAnonResourceBase) error { + metadata, err := model.GetAllClassMetadata() + if err != nil { + return errors.Wrap(err, "GetAllPureMetadata") + } + if len(metadata) == 0 { + return nil + } + userCred := auth.AdminCredential() + dictstore := make(map[string]interface{}, 0) + for k, v := range metadata { + dictstore[k] = v + } + return sonModel.SetClassMetadataAll(ctx, dictstore, userCred) +} + +func (model *SStandaloneAnonResourceBase) IsInSameClass(ctx context.Context, pModel *SStandaloneAnonResourceBase) (bool, error) { + pureTags, err := model.GetAllClassMetadata() + if err != nil { + return false, errors.Wrap(err, "GetAllPureMetadata") + } + pureTagsP, err := pModel.GetAllClassMetadata() + if err != nil { + return false, errors.Wrap(err, "GetAllPureMetadata") + } + if len(pureTags) != len(pureTagsP) { + return false, nil + } + for k, v := range pureTags { + if vp, ok := pureTagsP[k]; !ok || vp != v { + return false, nil + } + } + return true, nil +} + func (model *SStandaloneAnonResourceBase) SetSysCloudMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error { err := Metadata.SetAll(ctx, model, dictstore, userCred, SYS_CLOUD_TAG_PREFIX) if err != nil { @@ -326,6 +382,18 @@ func (model *SStandaloneAnonResourceBase) GetAllCloudMetadata() (map[string]stri return ret, nil } +func (model *SStandaloneAnonResourceBase) GetAllClassMetadata() (map[string]string, error) { + meta, err := Metadata.GetAll(nil, model, nil, CLASS_TAG_PREFIX, nil) + if err != nil { + return nil, errors.Wrap(err, "Metadata.GetAll") + } + ret := make(map[string]string) + for k, v := range meta { + ret[k[len(CLASS_TAG_PREFIX):]] = v + } + return ret, nil +} + // 获取资源标签(元数据) func (model *SStandaloneAnonResourceBase) GetDetailsMetadata(ctx context.Context, userCred mcclient.TokenCredential, input apis.GetMetadataInput) (apis.GetMetadataOutput, error) { val, err := Metadata.GetAll(ctx, model, input.Field, input.Prefix, userCred) @@ -393,6 +461,28 @@ func (model *SStandaloneAnonResourceBase) PerformSetUserMetadata(ctx context.Con return nil, nil } +func (model *SStandaloneAnonResourceBase) PerformSetClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformSetClassMetadataInput) (jsonutils.JSONObject, error) { + dictStore := make(map[string]interface{}) + for k, v := range input { + if len(k) > 64-len(CLASS_TAG_PREFIX) { + return nil, httperrors.NewInputParameterError("input key too long > %d", 64-len(CLASS_TAG_PREFIX)) + } + if len(v) > 65535 { + return nil, httperrors.NewInputParameterError("input value too long > %d", 65535) + } + dictStore[k] = v + } + err := model.SetClassMetadataAll(ctx, dictStore, userCred) + if err != nil { + return nil, errors.Wrap(err, "SetUserMetadataAll") + } + return nil, nil +} + +func (model *SStandaloneAnonResourceBase) GetDetailsClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, input apis.GetClassMetadataOutput) (apis.GetClassMetadataOutput, error) { + return model.GetAllClassMetadata() +} + type sPolicyTags struct { PolicyObjectTags tagutils.TTagSetList `json:"policy_object_tags"` PolicyProjectTags tagutils.TTagSetList `json:"policy_project_tags"` @@ -487,10 +577,12 @@ func (manager *SStandaloneAnonResourceBaseManager) FetchCustomizeColumns( ret := make([]apis.StandaloneAnonResourceDetails, len(objs)) upperRet := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) metaRet := manager.SMetadataResourceBaseModelManager.FetchCustomizeColumns(manager.GetIModelManager(), userCred, objs, fields) + secretRet := manager.SSecretResourceBaseModelManager.FetchCustomizeColumns(manager.GetIModelManager(), userCred, objs, fields) for i := range objs { ret[i] = apis.StandaloneAnonResourceDetails{ ResourceBaseDetails: upperRet[i], MetadataResourceInfo: metaRet[i], + SecretResourceInfo: secretRet[i], } } return ret