diff --git a/pkg/cloudcommon/db/standalone.go b/pkg/cloudcommon/db/standalone.go index 45bbfd5716..88702015c3 100644 --- a/pkg/cloudcommon/db/standalone.go +++ b/pkg/cloudcommon/db/standalone.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "strings" + "unicode" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -279,8 +280,10 @@ func (model *SStandaloneResourceBase) PerformMetadata(ctx context.Context, userC } func (model *SStandaloneResourceBase) ValidateMetadataKey(key string) error { - if strings.HasPrefix(key, CLOUD_TAG_PREFIX) || strings.ContainsAny(key, `:=#&?$/\`) { - return httperrors.NewInputParameterError(`key cannot start with %s and not contain :=#&?$/\`, CLOUD_TAG_PREFIX) + for _, k := range []rune(key) { + if k != rune('_') && !unicode.IsLetter(k) && !unicode.IsDigit(k) { + return httperrors.NewInputParameterError(`Not support tag key with %s`, string(k)) + } } return nil } diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go index af622c7347..f6fdb6cabd 100644 --- a/pkg/mcclient/options/base.go +++ b/pkg/mcclient/options/base.go @@ -3,7 +3,9 @@ package options import ( "fmt" "reflect" + "strings" "time" + "unicode" "yunion.io/x/jsonutils" "yunion.io/x/pkg/gotypes" @@ -186,8 +188,7 @@ type BaseListOptions struct { ExportFile string `help:"Export to file" metavar:"" json:"-"` ExportKeys string `help:"Export field keys"` ExportTexts string `help:"Export field displayname texts" json:"-"` - TagsKey []string `help:"Tag key" json:"-"` - TagsValue []string `help:"Tag key" json:"-"` + Tags []string `help:"Tags info, eg: hypervisor=aliyun、os_type=Linux、os_version"` Manager string `help:"List objects belonging to the cloud provider" json:"manager,omitempty"` Account string `help:"List objects belonging to the cloud account" json:"account,omitempty"` @@ -219,13 +220,23 @@ func (opts *BaseListOptions) Params() (*jsonutils.JSONDict, error) { params.Set("admin", jsonutils.JSONTrue) } } - if len(opts.TagsKey) > 0 { - for i := 0; i < len(opts.TagsKey); i++ { - params.Add(jsonutils.NewString(opts.TagsKey[i]), fmt.Sprintf("tags.%d.key", i)) - if len(opts.TagsValue) > i { - params.Add(jsonutils.NewString(opts.TagsValue[i]), fmt.Sprintf("tags.%d.value", i)) + for idx, tag := range opts.Tags { + tagInfo := strings.Split(tag, "=") + if len(tagInfo) > 2 { + return nil, fmt.Errorf("failed parse tags info %s", tag) + } + if len(tagInfo[0]) == 0 { + return nil, fmt.Errorf("Not support empty key") + } + for _, k := range tagInfo[0] { + if k != rune('_') && !unicode.IsLetter(k) && !unicode.IsDigit(k) { + return nil, fmt.Errorf("Not support tag key with %s", string(k)) } } + params.Add(jsonutils.NewString(tagInfo[0]), fmt.Sprintf("tags.%d.key", idx)) + if len(tagInfo) == 2 { + params.Add(jsonutils.NewString(tagInfo[1]), fmt.Sprintf("tags.%d.value", idx)) + } } return params, nil }