| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- // 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 options
- import (
- "fmt"
- "reflect"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/gotypes"
- "yunion.io/x/pkg/util/reflectutils"
- dbapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/util/tagutils"
- )
- // Int returns a pointer to int type with the same value as the argument. This
- // is intended to be used for literal initialization of options
- func Int(v int) *int {
- return &v
- }
- // Bool returns a pointer to bool type with the same value as the argument.
- // This is intended to be used for literal initialization of options
- func Bool(v bool) *bool {
- return &v
- }
- func String(v string) *string {
- return &v
- }
- // IntV returns the integer value as pointed to by the argument if it's
- // non-nil, return 0 otherwise
- func IntV(p *int) int {
- if p != nil {
- return *p
- }
- return 0
- }
- // BoolV returns the bool value as pointed to by the argument if it's non-nil,
- // return false otherwise
- func BoolV(p *bool) bool {
- if p != nil {
- return *p
- }
- return false
- }
- func StringV(p *string) string {
- if p != nil {
- return *p
- }
- return ""
- }
- type IParamsOptions interface {
- Params() (*jsonutils.JSONDict, error)
- }
- var BaseListOptionsType = reflect.TypeOf((*BaseListOptions)(nil)).Elem()
- func optionsStructRvToParams(rv reflect.Value) (*jsonutils.JSONDict, error) {
- p := jsonutils.NewDict()
- rvType := rv.Type()
- for i := 0; i < rvType.NumField(); i++ {
- ft := rvType.Field(i)
- jsonInfo := reflectutils.ParseStructFieldJsonInfo(ft)
- name := jsonInfo.MarshalName()
- if name == "" {
- continue
- }
- if jsonInfo.Ignore {
- continue
- }
- f := rv.Field(i)
- begin:
- switch f.Kind() {
- case reflect.Ptr:
- if f.IsNil() {
- continue
- }
- f = f.Elem()
- goto begin
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- rv64 := f.Convert(gotypes.Int64Type)
- i64 := rv64.Interface().(int64)
- if i64 != 0 || !jsonInfo.OmitZero {
- p.Set(name, jsonutils.NewInt(i64))
- }
- case reflect.Bool:
- b := f.Interface().(bool)
- if b || !jsonInfo.OmitFalse {
- p.Set(name, jsonutils.NewBool(b))
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- // NOTE uint64 converted to int64
- rv64 := f.Convert(gotypes.Uint64Type)
- i64 := rv64.Interface().(uint64)
- if i64 != 0 || !jsonInfo.OmitZero {
- p.Set(name, jsonutils.NewInt(int64(i64)))
- }
- case reflect.Float32, reflect.Float64:
- rv64 := f.Convert(gotypes.Float64Type)
- f64 := rv64.Interface().(float64)
- if f64 != 0 || !jsonInfo.OmitZero {
- p.Set(name, jsonutils.NewFloat64(f64))
- }
- case reflect.String:
- s := f.Interface().(string)
- if len(s) > 0 || !jsonInfo.OmitEmpty {
- p.Set(name, jsonutils.NewString(s))
- }
- case reflect.Struct:
- if ft.Anonymous {
- continue
- }
- if f.Type() == gotypes.TimeType {
- t := f.Interface().(time.Time)
- p.Set(name, jsonutils.NewTimeString(t))
- continue
- }
- // TODO
- msg := fmt.Sprintf("do not know what to do with non-anonymous struct field: %s", ft.Name)
- panic(msg)
- case reflect.Map:
- p.Set(name, jsonutils.Marshal(f.Interface()))
- case reflect.Slice, reflect.Array:
- l := f.Len()
- for i := 0; i < l; i++ {
- namei := fmt.Sprintf("%s.%d", name, i)
- vali := jsonutils.Marshal(f.Index(i).Interface())
- p.Set(namei, vali)
- }
- default:
- msg := fmt.Sprintf("unsupported field type %s: %s", ft.Name, ft.Type)
- panic(msg)
- }
- }
- return p, nil
- }
- func optionsStructToParams(v interface{}) (*jsonutils.JSONDict, error) {
- rv := reflect.Indirect(reflect.ValueOf(v))
- return optionsStructRvToParams(rv)
- }
- // StructToParams converts the struct as pointed to by the argument to JSON
- // dict params, ignoring any embedded in struct
- func StructToParams(v interface{}) (*jsonutils.JSONDict, error) {
- return optionsStructToParams(v)
- }
- // ListStructToParams converts the struct as pointed to by the argument to JSON
- // dict params, taking into account .BaseListOptions.Params() if it exists
- func ListStructToParams(v interface{}) (*jsonutils.JSONDict, error) {
- rv := reflect.Indirect(reflect.ValueOf(v))
- params, err := optionsStructRvToParams(rv)
- if err != nil {
- return nil, err
- }
- {
- for _, oName := range []string{"BaseListOptions", "MultiArchListOptions"} {
- f := rv.FieldByName(oName)
- if f.IsValid() {
- listOpts, ok := f.Addr().Interface().(IParamsOptions)
- if ok {
- listParams, err := listOpts.Params()
- if err != nil {
- return nil, err
- }
- params.Update(listParams)
- }
- }
- }
- }
- return params, nil
- }
- const (
- ListOrderAsc = "asc"
- ListOrderDesc = "desc"
- )
- type BaseListOptions struct {
- Limit *int `default:"20" help:"Page limit"`
- Offset *int `default:"0" help:"Page offset"`
- OrderBy []string `help:"Name of the field to be ordered by"`
- Order string `help:"List order" choices:"desc|asc"`
- Details *bool `help:"Show more details" default:"false"`
- ShowFailReason *bool `help:"show fail reason fields"`
- Search string `help:"Filter results by a simple keyword search"`
- Meta *bool `help:"Piggyback metadata information" json:"with_meta" token:"meta"`
- Filter []string `help:"Filters"`
- JointFilter []string `help:"Filters with joint table col; joint_tbl.related_key(origin_key).filter_col.filter_cond(filters)"`
- FilterAny *bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"`
- Admin *bool `help:"Is an admin call?"`
- Tenant string `help:"Tenant ID or Name" alias:"project"`
- ProjectDomain string `help:"Project domain filter"`
- User string `help:"User ID or Name"`
- Field []string `help:"Show only specified fields"`
- Scope string `help:"resource scope" choices:"system|domain|project|user"`
- System *bool `help:"Show system resource"`
- PendingDelete *bool `help:"Show only pending deleted resources"`
- PendingDeleteAll *bool `help:"Show also pending-deleted resources" json:"-"`
- DeleteAll *bool `help:"Show also deleted resources" json:"-"`
- ShowEmulated *bool `help:"Show all resources including the emulated resources"`
- ExportKeys string `help:"Export field keys"`
- ExtraListOptions
- Tags []string `help:"filter by Tags, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: \"hypervisor=aliyun;os_type=Linux;os_version\"" json:"-"`
- NoTags []string `help:"List resources without this tags, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: os_type=Linux, os_version" json:"-"`
- UserTags []string `help:"UserTags info, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: group=rd" json:"-"`
- CloudTags []string `help:"CloudTags info, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: price_key=cn-beijing" json:"-"`
- NoUserTags []string `help:"filter by without these UserTags, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: group=rd" json:"-"`
- NoCloudTags []string `help:"filter by no these CloudTags, key and value separated by \"=\", keyvalue pairs separated by \";\", eg: price_key=cn-beijing" json:"-"`
- ProjectTags []string `help:"filter by project tags, key and value separated by \"=\", keyvalue pairs separated by \";\"" json:"-"`
- NoProjectTags []string `help:"filter by no these project tags, key and value separated by \"=\", keyvalue pairs separated by \";\"" json:"-"`
- DomainTags []string `help:"filter by domain project tags, key and value separated by \"=\", keyvalue pairs separated by \";\"" json:"-"`
- NoDomainTags []string `help:"filter by no these domain tags, key and value separated by \"=\", keyvalue pairs separated by \";\"" json:"-"`
- ProjectOrganizations []string `help:"filter by projects of specified organizations"`
- DomainOrganizations []string `help:"filter by domains of specified organizations"`
- 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"`
- Provider []string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Apsara|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|VolcEngine|ZStack|Google|Ctyun|Cloudpods|Nutanix|BingoCloud|IncloudSphere|JDcloud|Proxmox|Ceph|CephFS|Ecloud|HCSO|HCS|HCSOP|H3C|S3|RemoteFile|Ksyun|Baidu|QingCloud|OracleCloud|SangFor|ZettaKit|UIS|CNWare" json:"provider,omitempty"`
- Brand []string `help:"List objects belonging to a special brand"`
- CloudEnv string `help:"Cloud environment" choices:"public|private|onpremise|private_or_onpremise" json:"cloud_env,omitempty"`
- PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"`
- PrivateCloud *bool `help:"List objects belonging to private cloud" json:"private_cloud"`
- IsOnPremise *bool `help:"List objects belonging to on premise infrastructures" token:"on-premise" json:"is_on_premise"`
- IsManaged *bool `help:"List objects managed by external providers" token:"managed" json:"is_managed"`
- PagingMarker string `help:"Marker for pagination" json:"paging_marker"`
- PagingOrder string `help:"paging order" choices:"DESC|ASC"`
- OrderByTag string `help:"Order results by tag values, composed by a tag key and order, e.g user:部门:ASC"`
- Delete string `help:"show deleted records"`
- Id []string `help:"filter by id"`
- // Name []string `help:"fitler by name"`
- Status []string `help:"filter by status"`
- SummaryStats bool `help:"show summary stats" json:"summary_stats"`
- }
- func (opts *BaseListOptions) addTag(keyPrefix, tagstr string, idx int, params *jsonutils.JSONDict) error {
- return opts.addTagInternal(keyPrefix, "obj_tags", tagstr, idx, params)
- }
- func (opts *BaseListOptions) addNoTag(keyPrefix, tagstr string, idx int, params *jsonutils.JSONDict) error {
- return opts.addTagInternal(keyPrefix, "no_obj_tags", tagstr, idx, params)
- }
- func (opts *BaseListOptions) addTagInternal(keyPrefix, tagName, tagstr string, idx int, params *jsonutils.JSONDict) error {
- tags := SplitTag(tagstr)
- if len(tags) == 0 {
- return fmt.Errorf("empty tags")
- }
- for i, tag := range tags {
- params.Add(jsonutils.NewString(keyPrefix+tag.Key), fmt.Sprintf("%s.%d.%d.key", tagName, idx, i))
- params.Add(jsonutils.NewString(tag.Value), fmt.Sprintf("%s.%d.%d.value", tagName, idx, i))
- }
- return nil
- }
- func SplitTag(tag string) tagutils.TTagSet {
- tags := make(tagutils.TTagSet, 0)
- tagInfoList := strings.Split(tag, ";")
- for _, tagInfo := range tagInfoList {
- if len(tagInfo) == 0 {
- continue
- }
- tagInfo := strings.Split(tagInfo, "=")
- tag := tagutils.STag{Key: tagInfo[0]}
- if len(tagInfo) > 1 {
- tag.Value = tagInfo[1]
- }
- tags = append(tags, tag)
- }
- return tags
- }
- func (opts *BaseListOptions) Params() (*jsonutils.JSONDict, error) {
- params, err := optionsStructToParams(opts)
- if err != nil {
- return nil, err
- }
- if len(opts.Filter) == 0 {
- params.Remove("filter_any")
- }
- if BoolV(opts.DeleteAll) {
- params.Set("delete", jsonutils.NewString("all"))
- }
- if BoolV(opts.PendingDeleteAll) {
- params.Set("pending_delete", jsonutils.NewString("all"))
- }
- /*if opts.Admin == nil {
- requiresSystem := len(opts.Tenant) > 0 ||
- len(opts.ProjectDomain) > 0 ||
- BoolV(opts.System) ||
- BoolV(opts.PendingDelete) ||
- BoolV(opts.PendingDeleteAll)
- if requiresSystem {
- params.Set("admin", jsonutils.JSONTrue)
- }
- }*/
- tagIdx, noTagIdx := 0, 0
- for _, tag := range opts.Tags {
- err = opts.addTag("", tag, tagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "Tags")
- }
- tagIdx++
- }
- for _, tag := range opts.NoTags {
- err = opts.addNoTag("", tag, noTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "NoTags")
- }
- noTagIdx++
- }
- for _, tag := range opts.UserTags {
- err = opts.addTag(dbapi.USER_TAG_PREFIX, tag, tagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "UserTags")
- }
- tagIdx++
- }
- for _, tag := range opts.NoUserTags {
- err = opts.addNoTag(dbapi.USER_TAG_PREFIX, tag, noTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "NoUserTags")
- }
- noTagIdx++
- }
- for _, tag := range opts.CloudTags {
- err = opts.addTag(dbapi.CLOUD_TAG_PREFIX, tag, tagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "CloudTags")
- }
- tagIdx++
- }
- for _, tag := range opts.NoCloudTags {
- err = opts.addNoTag(dbapi.CLOUD_TAG_PREFIX, tag, noTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "NoCloudTags")
- }
- noTagIdx++
- }
- projTagIdx := 0
- for _, tag := range opts.ProjectTags {
- err := opts.addTagInternal("", "project_tags", tag, projTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "ProjectTags")
- }
- projTagIdx++
- }
- noProjTagIdx := 0
- for _, tag := range opts.NoProjectTags {
- err := opts.addTagInternal("", "no_project_tags", tag, noProjTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "NoProjectTags")
- }
- noProjTagIdx++
- }
- for i, orgId := range opts.ProjectOrganizations {
- params.Add(jsonutils.NewString(orgId), fmt.Sprintf("project_organizations.%d", i))
- }
- domainTagIdx := 0
- for _, tag := range opts.DomainTags {
- err := opts.addTagInternal("", "domain_tags", tag, domainTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "DomainTags")
- }
- domainTagIdx++
- }
- noDomainTagIdx := 0
- for _, tag := range opts.NoDomainTags {
- err := opts.addTagInternal("", "no_domain_tags", tag, noDomainTagIdx, params)
- if err != nil {
- return nil, errors.Wrap(err, "NoDomainTags")
- }
- noDomainTagIdx++
- }
- for i, orgId := range opts.DomainOrganizations {
- params.Add(jsonutils.NewString(orgId), fmt.Sprintf("domain_organizations.%d", i))
- }
- return params, nil
- }
- func (o *BaseListOptions) GetExportKeys() string {
- return o.ExportKeys
- }
- type ExtraListOptions struct {
- ExportFile string `help:"Export to file" metavar:"<EXPORT_FILE_PATH>" json:"-"`
- ExportTexts string `help:"Export field displayname texts" json:"-"`
- }
- func (o ExtraListOptions) GetExportFile() string {
- return o.ExportFile
- }
- func (o ExtraListOptions) GetExportTexts() string {
- return o.ExportTexts
- }
- func (o ExtraListOptions) GetContextId() string {
- return ""
- }
- type ScopedResourceListOptions struct {
- BelongScope string `help:"Filter by resource belong scope" choices:"system|domain|project"`
- }
- func (o *ScopedResourceListOptions) Params() (*jsonutils.JSONDict, error) {
- return optionsStructToParams(o)
- }
- type MultiArchListOptions struct {
- OsArch string `help:"Filter resource by arch" choices:"i386|x86|x86_32|x86_64|arm|aarch32|aarch64|riscv|riscv32|riscv64"`
- }
- func (o *MultiArchListOptions) Params() (*jsonutils.JSONDict, error) {
- return optionsStructToParams(o)
- }
- type BaseUpdateOptions struct {
- ID string `help:"ID or Name of resource to update" json:"-"`
- Name string `help:"Name of resource to update" json:"name"`
- Desc string `metavar:"<DESCRIPTION>" help:"Description" json:"description"`
- }
- func (opts *BaseUpdateOptions) GetId() string {
- return opts.ID
- }
- func (opts *BaseUpdateOptions) Params() (jsonutils.JSONObject, error) {
- params := jsonutils.NewDict()
- if len(opts.Name) > 0 {
- params.Add(jsonutils.NewString(opts.Name), "name")
- }
- if len(opts.Desc) > 0 {
- params.Add(jsonutils.NewString(opts.Desc), "description")
- }
- return params, nil
- }
- type BasePublicOptions struct {
- ID string `help:"ID or name of resource" json:"-"`
- Scope string `help:"sharing scope" choices:"system|domain|project"`
- SharedDomains []string `help:"share to domains"`
- SharedProjects []string `help:"share to projects"`
- }
- func (opts *BasePublicOptions) GetId() string {
- return opts.ID
- }
- func (opts *BasePublicOptions) Params() (jsonutils.JSONObject, error) {
- params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
- params.Remove("id")
- return params, nil
- }
- type BaseCreateOptions struct {
- NAME string `json:"name" help:"Resource Name"`
- Desc string `metavar:"<DESCRIPTION>" help:"Description" json:"description"`
- }
- func (opts *BaseCreateOptions) Params() (jsonutils.JSONObject, error) {
- return jsonutils.Marshal(opts), nil
- }
- type EnabledStatusCreateOptions struct {
- BaseCreateOptions
- Status string
- Enabled *bool `help:"turn on enabled flag"`
- }
- type BaseIdOptions struct {
- ID string `json:"-"`
- }
- func (o *BaseIdOptions) GetId() string {
- return o.ID
- }
- func (o *BaseIdOptions) Params() (jsonutils.JSONObject, error) {
- return nil, nil
- }
- type BaseIdsOptions struct {
- ID []string `json:"-"`
- }
- func (o *BaseIdsOptions) GetIds() []string {
- return o.ID
- }
- func (o *BaseIdsOptions) Params() (jsonutils.JSONObject, error) {
- return nil, nil
- }
- type BaseShowOptions struct {
- BaseIdOptions
- WithMeta *bool `help:"With meta data"`
- ShowFailReason *bool `help:"show fail reason fields"`
- }
- func (o BaseShowOptions) Params() (jsonutils.JSONObject, error) {
- return StructToParams(o)
- }
- type ChangeOwnerOptions struct {
- BaseIdOptions
- ProjectDomain string `json:"project_domain" help:"target domain"`
- }
- func (o ChangeOwnerOptions) Params() (jsonutils.JSONObject, error) {
- if len(o.ProjectDomain) == 0 {
- return nil, fmt.Errorf("empty project_domain")
- }
- return jsonutils.Marshal(map[string]string{"project_domain": o.ProjectDomain}), nil
- }
- type StatusStatisticsOptions struct {
- }
- func (o StatusStatisticsOptions) Property() string {
- return "statistics"
- }
- type ProjectStatisticsOptions struct {
- }
- func (o ProjectStatisticsOptions) Property() string {
- return "project-statistics"
- }
- type DomainStatisticsOptions struct {
- }
- func (o DomainStatisticsOptions) Property() string {
- return "domain-statistics"
- }
|