From 9f3266d1eb773b26f82ee58fe817c7b9d4375a7f Mon Sep 17 00:00:00 2001 From: TangBin Date: Sat, 20 Apr 2019 13:52:08 +0800 Subject: [PATCH] fix skus & zone-list & cloud-region-list query with params manager&account --- cmd/climc/shell/skus.go | 21 ++++++ pkg/compute/models/cloudaccounts.go | 16 +++-- pkg/compute/models/cloudproviderregions.go | 29 ++++++-- pkg/compute/models/cloudregions.go | 20 ++---- pkg/compute/models/skus.go | 82 +++++++++++++++------- pkg/compute/models/zones.go | 22 +----- 6 files changed, 117 insertions(+), 73 deletions(-) diff --git a/cmd/climc/shell/skus.go b/cmd/climc/shell/skus.go index c4da6db59b..a0a13bae66 100644 --- a/cmd/climc/shell/skus.go +++ b/cmd/climc/shell/skus.go @@ -148,4 +148,25 @@ func init() { printObject(result) return nil }) + + type ServerSkuSpecsListOptions struct { + Provider string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud" json:"provider"` + PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"` + Zone string `help:"zone Id or name"` + PostpaidStatus *string `help:"skus available status for postpaid instance" choices:"available|soldout"` + PrepaidStatus *string `help:"skus available status for prepaid instance" choices:"available|soldout"` + IngoreCache bool `help:"query without cache"` + } + R(&ServerSkuSpecsListOptions{}, "server-sku-specs-list", "List all avaiable Server SKU specifications", func(s *mcclient.ClientSession, args *ServerSkuSpecsListOptions) error { + params, err := options.ListStructToParams(args) + if err != nil { + return err + } + result, err := modules.ServerSkus.Get(s, "instance-specs", params) + if err != nil { + return err + } + printObject(result) + return nil + }) } diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index 984944790a..7caef3709b 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -929,12 +929,16 @@ func (manager *SCloudaccountManager) ListItemFilter(ctx context.Context, q *sqlc } managerStr, _ := query.GetString("manager") if len(managerStr) > 0 { - cpr := CloudproviderRegionManager.Query().SubQuery() - sq := cpr.Query(cpr.Field("cloudregion_id")) - sq = sq.Filter(sqlchemy.Equals(cpr.Field("cloudprovider_id"), managerStr)) - sq = sq.Filter(sqlchemy.IsTrue(cpr.Field("enabled"))) - - q = q.In("id", sq.SubQuery()) + providerObj, err := CloudproviderManager.FetchByIdOrName(userCred, managerStr) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(CloudproviderManager.Keyword(), managerStr) + } else { + return nil, httperrors.NewGeneralError(err) + } + } + provider := providerObj.(*SCloudprovider) + q = q.Equals("id", provider.CloudaccountId) } cloudEnvStr, _ := query.GetString("cloud_env") diff --git a/pkg/compute/models/cloudproviderregions.go b/pkg/compute/models/cloudproviderregions.go index cceb45dedf..568659fbdc 100644 --- a/pkg/compute/models/cloudproviderregions.go +++ b/pkg/compute/models/cloudproviderregions.go @@ -19,16 +19,15 @@ import ( "database/sql" "math/rand" "time" - "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/pkg/util/compare" - "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/pkg/util/compare" + "yunion.io/x/pkg/util/timeutils" + "yunion.io/x/sqlchemy" ) type SCloudproviderregionManager struct { @@ -155,6 +154,28 @@ func (self *SCloudproviderregion) Detach(ctx context.Context, userCred mcclient. return db.DetachJoint(ctx, userCred, self) } +/* +过滤出指定cloudAccountId || providerIds || cloudAccountId+providerIds关联的region id +*/ +func (manager *SCloudproviderregionManager) QueryRelatedRegionIds(cloudAccountId string, providerIds ...string) *sqlchemy.SSubQuery { + q := manager.Query("cloudregion_id") + accounts := CloudaccountManager.Query().SubQuery() + providers := CloudproviderManager.Query().SubQuery() + + q = q.Join(providers, sqlchemy.Equals(providers.Field("id"), q.Field("cloudprovider_id"))) + q = q.Join(accounts, sqlchemy.Equals(accounts.Field("id"), providers.Field("cloudaccount_id"))) + + if len(providerIds) > 0 { + q = q.Filter(sqlchemy.In(providers.Field("id"), providerIds)) + } + + if len(cloudAccountId) > 0 { + q.Filter(sqlchemy.Equals(accounts.Field("id"), cloudAccountId)) + } + + return q.Distinct().SubQuery() +} + func (manager *SCloudproviderregionManager) FetchByIds(providerId string, regionId string) *SCloudproviderregion { q := manager.Query().Equals("cloudprovider_id", providerId).Equals("cloudregion_id", regionId) obj, err := db.NewModelObject(manager) diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index c4bfce6a4d..19effd33bc 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -443,25 +443,13 @@ func (manager *SCloudregionManager) ListItemFilter(ctx context.Context, q *sqlch managerStr, _ := query.GetString("manager") if len(managerStr) > 0 { - cpr := CloudproviderRegionManager.Query().SubQuery() - sq := cpr.Query(cpr.Field("cloudregion_id")) - sq = sq.Filter(sqlchemy.Equals(cpr.Field("cloudprovider_id"), managerStr)) - sq = sq.Filter(sqlchemy.IsTrue(cpr.Field("enabled"))) - - q = q.In("id", sq.SubQuery()) + subq := CloudproviderRegionManager.QueryRelatedRegionIds("", managerStr) + q = q.In("id", subq) } accountStr, _ := query.GetString("account") if len(accountStr) > 0 { - accountObj, err := CloudaccountManager.FetchByIdOrName(userCred, accountStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(CloudaccountManager.Keyword(), accountStr) - } else { - return nil, httperrors.NewGeneralError(err) - } - } - account := accountObj.(*SCloudaccount) - q = q.In("provider", account.Provider) + subq := CloudproviderRegionManager.QueryRelatedRegionIds(accountStr) + q = q.In("id", subq) } if jsonutils.QueryBoolean(query, "usable", false) || jsonutils.QueryBoolean(query, "usable_vpc", false) { diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index f9dd5b31b7..60d4fd1321 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -24,6 +24,7 @@ import ( "strconv" "strings" "time" + "yunion.io/x/pkg/utils" "yunion.io/x/jsonutils" @@ -104,6 +105,44 @@ type SServerSku struct { Provider string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"admin_optional" update:"admin"` } +type SInstanceSpecQueryParams struct { + Provider string + PublicCloud bool + ZoneId string + PostpaidStatus string + PrepaidStatus string + IngoreCache bool +} + +func (self *SInstanceSpecQueryParams) GetCacheKey() string { + hashStr := fmt.Sprintf("%s:%t:%s:%s:%s", self.Provider, self.PublicCloud, self.ZoneId, self.PostpaidStatus, self.PrepaidStatus) + _md5 := md5.Sum([]byte(hashStr)) + return "InstanceSpecs_" + fmt.Sprintf("%x", _md5) +} + +func NewInstanceSpecQueryParams(query jsonutils.JSONObject) *SInstanceSpecQueryParams { + zone := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) + postpaid, _ := query.GetString("postpaid_status") + prepaid, _ := query.GetString("prepaid_status") + ingore_cache, _ := query.Bool("ingore_cache") + provider := normalizeProvider(jsonutils.GetAnyString(query, []string{"provider"})) + public_cloud, _ := query.Bool("public_cloud") + if utils.IsInStringArray(provider, cloudprovider.GetPublicProviders()) { + public_cloud = true + } + + params := &SInstanceSpecQueryParams{ + Provider: provider, + PublicCloud: public_cloud, + ZoneId: zone, + PostpaidStatus: postpaid, + PrepaidStatus: prepaid, + IngoreCache: ingore_cache, + } + + return params +} + func sliceToJsonObject(items []int) jsonutils.JSONObject { sort.Slice(items, func(i, j int) bool { if items[i] < items[j] { @@ -490,37 +529,28 @@ func providerFilter(q *sqlchemy.SQuery, provider string, public_cloud bool) *sql return q } -func queryCacheKey(prefix string, query jsonutils.JSONObject) string { - _ret := md5.Sum([]byte(query.QueryString())) - return prefix + fmt.Sprintf("%x", _ret) -} - func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - specsKey := queryCacheKey("InstanceSpecs", query) - v := Cache.Get(specsKey) - if v != nil { - if cacheRet, ok := v.(*jsonutils.JSONDict); ok { - return cacheRet, nil + params := NewInstanceSpecQueryParams(query) + if !params.IngoreCache { + v := Cache.Get(params.GetCacheKey()) + if v != nil { + if cacheRet, ok := v.(*jsonutils.JSONDict); ok { + return cacheRet, nil + } } } q := self.Query() // 未明确指定provider或者public_cloud时,默认查询私有云 - provider := normalizeProvider(jsonutils.GetAnyString(query, []string{"provider"})) - public_cloud, _ := query.Bool("public_cloud") - if utils.IsInStringArray(provider, cloudprovider.GetPublicProviders()) { - public_cloud = true - } - q = providerFilter(q, provider, public_cloud) + q = providerFilter(q, params.Provider, params.PublicCloud) q = excludeSkus(q) // 如果是查询私有云需要忽略zone参数 - zone := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) - if public_cloud && len(zone) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zone) + if params.PublicCloud && len(params.ZoneId) > 0 { + zoneObj, err := ZoneManager.FetchByIdOrName(userCred, params.ZoneId) if err != nil { if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zone) + return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), params.ZoneId) } return nil, httperrors.NewGeneralError(err) } @@ -529,14 +559,12 @@ func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, use } skus := make([]SServerSku, 0) - postpaid, _ := query.GetString("postpaid_status") - if len(postpaid) > 0 { - q.Equals("postpaid_status", postpaid) + if len(params.PostpaidStatus) > 0 { + q.Equals("postpaid_status", params.PostpaidStatus) } - prepaid, _ := query.GetString("prepaid_status") - if len(prepaid) > 0 { - q.Equals("prepaid_status", prepaid) + if len(params.PrepaidStatus) > 0 { + q.Equals("prepaid_status", params.PrepaidStatus) } q = q.GroupBy(q.Field("cpu_core_count"), q.Field("memory_size_mb")) q = q.Asc(q.Field("cpu_core_count"), q.Field("memory_size_mb")) @@ -584,7 +612,7 @@ func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, use r_obj := jsonutils.Marshal(&cpu_mems_mb) ret.Add(r_obj, "cpu_mems_mb") // cache 1min - Cache.Set(specsKey, ret, time.Now().Add(60*time.Second)) + Cache.Set(params.GetCacheKey(), ret, time.Now().Add(60*time.Second)) return ret, nil } diff --git a/pkg/compute/models/zones.go b/pkg/compute/models/zones.go index 3bee111d88..af7b19ae89 100644 --- a/pkg/compute/models/zones.go +++ b/pkg/compute/models/zones.go @@ -604,30 +604,12 @@ func (manager *SZoneManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu managerStr, _ := query.GetString("manager") if len(managerStr) > 0 { - providerObj, err := CloudproviderManager.FetchByIdOrName(userCred, managerStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(CloudproviderManager.Keyword(), managerStr) - } else { - return nil, httperrors.NewGeneralError(err) - } - } - provider := providerObj.(*SCloudprovider) - subq := CloudregionManager.Query("id").Equals("provider", provider.Provider).SubQuery() + subq := CloudproviderRegionManager.QueryRelatedRegionIds("", managerStr) q = q.In("cloudregion_id", subq) } accountStr, _ := query.GetString("account") if len(accountStr) > 0 { - accountObj, err := CloudaccountManager.FetchByIdOrName(userCred, accountStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(CloudaccountManager.Keyword(), accountStr) - } else { - return nil, httperrors.NewGeneralError(err) - } - } - account := accountObj.(*SCloudaccount) - subq := CloudregionManager.Query("id").Equals("provider", account.Provider).SubQuery() + subq := CloudproviderRegionManager.QueryRelatedRegionIds(accountStr) q = q.In("cloudregion_id", subq) } providerStr, _ := query.GetString("provider")