diff --git a/cmd/climc/shell/skus.go b/cmd/climc/shell/skus.go index 104a0c550f..59cf7a883a 100644 --- a/cmd/climc/shell/skus.go +++ b/cmd/climc/shell/skus.go @@ -9,11 +9,12 @@ import ( func init() { type ServerSkusListOptions struct { options.BaseListOptions - Region string `help:"region Id or name"` - Zone string `help:"zone Id or name"` - Cpu *int `help:"Cpu core count" json:"cpu_core_count"` - Mem *int `help:"Memory size in MB" json:"memory_size_mb"` - Name string `help:"Name of Sku"` + Region string `help:"region Id or name"` + Zone string `help:"zone Id or name"` + City *string `help:"city name,eg. BeiJing"` + Cpu *int `help:"Cpu core count" json:"cpu_core_count"` + Mem *int `help:"Memory size in MB" json:"memory_size_mb"` + Name string `help:"Name of Sku"` } R(&ServerSkusListOptions{}, "server-sku-list", "List all avaiable Server SKU", func(s *mcclient.ClientSession, args *ServerSkusListOptions) error { params, err := options.ListStructToParams(args) diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index 5d8554bfe3..3ebc1cdc54 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -6,9 +6,11 @@ import ( "fmt" "sort" "strconv" + "time" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/util/hashcache" "yunion.io/x/pkg/util/compare" "yunion.io/x/sqlchemy" @@ -45,6 +47,8 @@ var InstanceFamilies = map[string]string{ SkuCategoryHighMemory: "hr1", } +var Cache *hashcache.Cache + type SServerSkuManager struct { db.SStandaloneResourceBaseManager } @@ -61,6 +65,8 @@ func init() { ), } ServerSkuManager.NameRequireAscii = false + + Cache = hashcache.NewCache(2048, time.Second*300) } // SServerSku 实际对应的是instance type清单. 这里的Sku实际指的是instance type。 @@ -167,8 +173,50 @@ func (self *SServerSku) AllowGetDetails(ctx context.Context, userCred mcclient.T func (self *SServerSku) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { extra := self.SStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) - count := skuRelatedGuestCount(self) + // count + var count int + countKey := self.GetId() + ".total_guest_count" + v := Cache.Get(countKey) + if v == nil { + count = skuRelatedGuestCount(self) + Cache.Set(countKey, count) + } else { + count = v.(int) + } + extra.Add(jsonutils.NewInt(int64(count)), "total_guest_count") + + // zone + if len(self.ZoneId) > 0 { + var zoneName string + v := Cache.Get(self.ZoneId) + if v == nil { + zone, err := ZoneManager.FetchById(self.ZoneId) + if err == nil { + zoneName = zone.GetName() + Cache.Set(zone.GetId(), zoneName) + } + } else { + zoneName = v.(string) + } + + extra.Add(jsonutils.NewString(zoneName), "zone_name") + } + + // region + var regionName string + v = Cache.Get(self.CloudregionId) + if v == nil { + region, err := CloudregionManager.FetchById(self.CloudregionId) + if err == nil { + regionName = region.GetName() + Cache.Set(region.GetId(), regionName) + } + } else { + regionName = v.(string) + } + + extra.Add(jsonutils.NewString(regionName), "region_name") return extra } @@ -305,32 +353,32 @@ func (self *SServerSkuManager) AllowGetPropertyInstanceSpecs(ctx context.Context func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { q := self.Query() + // 未明确指定provider或者public_cloud时,默认查询私有云 provider, _ := query.GetString("provider") - if inWhiteList(provider) { + public_cloud, _ := query.Bool("public_cloud") + if len(provider) > 0 { + q = q.Equals("provider", provider) + } else if public_cloud { + q = q.IsNotEmpty("provider") + } else { q = q.Filter(sqlchemy.OR( sqlchemy.IsNull(q.Field("provider")), sqlchemy.IsEmpty(q.Field("provider")), )) - } else { - q = q.Equals("provider", provider) } // 如果是查询私有云需要忽略zone参数 zone := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) - if !inWhiteList(provider) { - if len(zone) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zone) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zone) - } - return nil, httperrors.NewGeneralError(err) + if public_cloud && len(zone) > 0 { + zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zone) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zone) } - - q = q.Equals("zone_id", zoneObj.GetId()) - } else { - return nil, httperrors.NewMissingParameterError("zone") + return nil, httperrors.NewGeneralError(err) } + + q = q.Equals("zone_id", zoneObj.GetId()) } skus := make([]SServerSku, 0) @@ -520,17 +568,20 @@ func (self *SServerSku) GetZoneExternalId() (string, error) { func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { provider := jsonutils.GetAnyString(query, []string{"provider"}) + public_cloud, _ := query.Bool("public_cloud") queryDict := query.(*jsonutils.JSONDict) - if provider == "" { + if provider == "all" { + // provider 参数为all时。表示查询所有instance type. + queryDict.Remove("provider") + } else if len(provider) > 0 { + q = q.Equals("provider", provider) + } else if public_cloud { + q = q.IsNotEmpty("provider") + } else { q = q.Filter(sqlchemy.OR( sqlchemy.IsNull(q.Field("provider")), sqlchemy.IsEmpty(q.Field("provider")), )) - } else if provider == "all" { - // provider 参数为all时。表示查询所有instance type. - queryDict.Remove("provider") - } else { - q = q.Equals("provider", provider) } q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query) @@ -538,6 +589,12 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem return nil, err } + regionTable := CloudregionManager.Query().SubQuery() + zoneTable := ZoneManager.Query().SubQuery() + q = q.Join(regionTable, sqlchemy.Equals(regionTable.Field("id"), q.Field("cloudregion_id"))) + q = q.Join(zoneTable, sqlchemy.Equals(zoneTable.Field("id"), q.Field("zone_id"))) + + // region filter regionStr := jsonutils.GetAnyString(query, []string{"region", "cloudregion", "region_id", "cloudregion_id"}) if len(regionStr) > 0 { regionObj, err := CloudregionManager.FetchByIdOrName(nil, regionStr) @@ -550,6 +607,32 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("cloudregion_id", regionObj.GetId()) } + zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) + var zoneObj db.IModel + if len(zoneStr) > 0 { + zoneObj, err = ZoneManager.FetchByIdOrName(nil, zoneStr) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zoneStr) + } + return nil, httperrors.NewGeneralError(err) + } + + // 当查询私有云时,需要忽略zone参数 + if len(zoneObj.(*SZone).ExternalId) > 0 { + q = q.Equals("zone_id", zoneObj.GetId()) + } + } + + queryDict.Remove("zone") + queryDict.Remove("zone_id") + + // city filter + city, _ := query.GetString("city") + if len(city) > 0 { + q = q.Filter(sqlchemy.Equals(regionTable.Field("city"), city)) + } + // 可用资源状态 postpaid, _ := query.GetString("postpaid_status") if len(postpaid) > 0 { @@ -561,22 +644,6 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem q.Equals("prepaid_status", prepaid) } - // 当查询私有云时,需要忽略zone参数 - zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) - if !inWhiteList(provider) && len(zoneStr) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(nil, zoneStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zoneStr) - } - return nil, httperrors.NewGeneralError(err) - } - q = q.Equals("zone_id", zoneObj.GetId()) - } else { - queryDict.Remove("zone") - queryDict.Remove("zone_id") - } - q = q.Asc(q.Field("cpu_core_count"), q.Field("memory_size_mb")) return q, err } diff --git a/pkg/mcclient/modules/mod_skus.go b/pkg/mcclient/modules/mod_skus.go index 38446597af..7e6bbd7163 100644 --- a/pkg/mcclient/modules/mod_skus.go +++ b/pkg/mcclient/modules/mod_skus.go @@ -31,7 +31,7 @@ func init() { "Sys_disk_min_size_mb", "Sys_disk_max_size_mb", "Attached_disk_type", "Attached_disk_size_gb", "Attached_disk_count", "Data_disk_types", "Data_disk_max_count", "Nic_max_count", "Cloudregion_id", "Zone_id", - "Provider", "Postpaid_status", "Prepaid_status"}, + "Provider", "Postpaid_status", "Prepaid_status", "region_name", "Zone_name"}, []string{"Total_guest_count"})} register(&CloudmetaSkus)