mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-24 23:41:52 +08:00
Merge pull request #13371 from rainzm/secret/resource
Classification of resources
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -274,6 +275,70 @@ func (model *SStandaloneAnonResourceBase) SetCloudMetadataAll(ctx context.Contex
|
||||
return Metadata.SetAll(ctx, model, userTags, userCred, USER_TAG_PREFIX)
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) SetClassMetadataValues(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
err := Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValuesWithLog")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) SetClassMetadataAll(ctx context.Context, dictstore map[string]string, 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()
|
||||
return sonModel.SetClassMetadataAll(ctx, metadata, userCred)
|
||||
}
|
||||
|
||||
type IClassMetadataOwner interface {
|
||||
GetAllClassMetadata() (map[string]string, error)
|
||||
}
|
||||
|
||||
func IsInSameClass(ctx context.Context, cmo1, cmo2 IClassMetadataOwner) (bool, error) {
|
||||
pureTags, err := cmo1.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "GetAllPureMetadata")
|
||||
}
|
||||
pureTagsP, err := cmo2.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) IsInSameClass(ctx context.Context, pModel *SStandaloneAnonResourceBase) (bool, error) {
|
||||
return IsInSameClass(ctx, model, pModel)
|
||||
}
|
||||
|
||||
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 +391,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 +470,42 @@ func (model *SStandaloneAnonResourceBase) PerformSetUserMetadata(ctx context.Con
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 更新资源的 class 标签
|
||||
func (model *SStandaloneAnonResourceBase) PerformClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
dictStore := make(map[string]interface{})
|
||||
for k, v := range input {
|
||||
dictStore[CLASS_TAG_PREFIX+k] = v
|
||||
}
|
||||
err := model.SetUserMetadataValues(ctx, dictStore, userCred)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SetUserMetadataValues")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 全量替换资源的所有 class 标签
|
||||
func (model *SStandaloneAnonResourceBase) PerformSetClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformSetClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
dictStore := make(map[string]string)
|
||||
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"`
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -520,3 +521,26 @@ func (tenant *STenant) IsDomain() bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (tenant *STenant) objType() string {
|
||||
if tenant.IsDomain() {
|
||||
return "domain"
|
||||
} else {
|
||||
return "project"
|
||||
}
|
||||
}
|
||||
|
||||
func (tenant *STenant) GetAllClassMetadata() (map[string]string, error) {
|
||||
meta, err := Metadata.rawGetAll(tenant.objType(), tenant.GetId(), nil, CLASS_TAG_PREFIX)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rawGetAll")
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
for k, v := range meta {
|
||||
if strings.HasPrefix(k, SYSTEM_ADMIN_PREFIX) {
|
||||
continue
|
||||
}
|
||||
ret[k[len(CLASS_TAG_PREFIX):]] = v
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -282,6 +282,18 @@ func (model *SVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred
|
||||
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 = project.Inherit(ctx, &model.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
log.Errorf("unable to inherit class metadata from poject %s: %s", project.GetId(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
@@ -416,6 +428,27 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
|
||||
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
|
||||
@@ -461,6 +494,13 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user