From da559be138201df0ecf2629287f3dc69179bf09c Mon Sep 17 00:00:00 2001 From: TangBin Date: Tue, 11 Dec 2018 17:52:28 +0800 Subject: [PATCH] update sku create & update & list method --- cmd/climc/shell/skus.go | 8 +- pkg/appsrv/handlerinfo.go | 2 +- pkg/compute/models/hosts.go | 2 +- pkg/compute/models/skus.go | 156 ++++++++++++++++++++++++++++++++---- 4 files changed, 145 insertions(+), 23 deletions(-) diff --git a/cmd/climc/shell/skus.go b/cmd/climc/shell/skus.go index 3fae33b88c..794f052e49 100644 --- a/cmd/climc/shell/skus.go +++ b/cmd/climc/shell/skus.go @@ -50,10 +50,9 @@ func init() { }) type ServerSkusCreateOptions struct { - Name string `help:"Name ID of SKU" required:"true" positional:"true"` CpuCoreCount int `help:"Cpu Count" required:"true" positional:"true"` MemorySizeMB int `help:"Memory MB" required:"true" positional:"true"` - Provider string `help:"Provider name" choices:"kvm|esxi"` + Provider string `help:"Provider name" choices:"all|kvm|esxi"` OsName *string `help:"OS name/type" choices:"Linux|Windows|Any" default:"Any"` SkuFamily *string `help:"sku family"` @@ -95,9 +94,8 @@ func init() { type ServerSkusUpdateOptions struct { ID string `help:"Name or ID of SKU" json:"-"` - Name *string `help:"new name of SKU"` - CpuCoreCount *int `help:"Cpu Count"` - MemorySizeMB *int `help:"Memory MB"` + CpuCoreCount *int `help:"Cpu Count"` + MemorySizeMB *int `help:"Memory MB"` SkuFamily *string `help:"sku family"` SkuCategory *string `help:"sku category" choices:"general_purpose|compute_optimized|memory_optimized|storage_optimized|hardware_accelerated|high_memory|high_storage"` diff --git a/pkg/appsrv/handlerinfo.go b/pkg/appsrv/handlerinfo.go index 6a7234ca65..048a4124cd 100644 --- a/pkg/appsrv/handlerinfo.go +++ b/pkg/appsrv/handlerinfo.go @@ -110,4 +110,4 @@ func (hi *SHandlerInfo) GetAppParams(params map[string]string, path []string) *S appParams.Params = params appParams.Path = path return &appParams -} \ No newline at end of file +} diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 9fa926df40..d9107bdbfe 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -23,6 +23,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/appsrv" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -35,7 +36,6 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" - "yunion.io/x/onecloud/pkg/appsrv" ) const ( diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index 7b953b445b..7606c156da 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -25,6 +26,17 @@ const ( SkuCategoryHighMemory = "high_memory" // 高内存型 ) +var InstanceFamilies map[string]string = map[string]string{ + SkuCategoryGeneralPurpose: "g1", + SkuCategoryBurstable: "t1", + SkuCategoryComputeOptimized: "c1", + SkuCategoryMemoryOptimized: "r1", + SkuCategoryStorageIOOptimized: "i1", + SkuCategoryHardwareAccelerated: "", + SkuCategoryHighStorage: "hc1", + SkuCategoryHighMemory: "hr1", +} + type SServerSkuManager struct { db.SStandaloneResourceBaseManager } @@ -87,13 +99,25 @@ func inWhiteList(provider string) bool { return true } switch provider { - case HYPERVISOR_ESXI, HYPERVISOR_KVM: + case HYPERVISOR_ESXI, HYPERVISOR_KVM, "all": // 空或者all时。表示`通用`私用云instance type列表 return true default: return false } } +func genInstanceType(family string, cpu, mem_mb int64) (string, error) { + if cpu < 0 { + return "", fmt.Errorf("cpu_core_count should great than zero") + } + + if mem_mb < 0 || mem_mb%1024 != 0 { + return "", fmt.Errorf("memory_size_mb should great than zero. and should be integral multiple of 1024") + } + + return fmt.Sprintf("ecs.%s.c%dm%d", family, cpu, mem_mb/1024), nil +} + func (self *SServerSkuManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } @@ -143,6 +167,50 @@ func (self *SServerSkuManager) ValidateCreateData(ctx context.Context, } data.Add(jsonutils.NewString(zoneObj.GetId()), "zone_id") } + + // name 由服务器端生成 + _, err := data.GetString("name") + if err != nil { + data.Remove("name") + } + + cpu, err := data.Int("cpu_core_count") + if err != nil { + return nil, httperrors.NewInputParameterError("cpu_core_count should not be empty") + } + + mem, err := data.Int("memory_size_mb") + if err != nil { + return nil, httperrors.NewInputParameterError("memory_size_mb should not be empty") + } + + category, _ := data.GetString("instance_type_category") + family, exists := InstanceFamilies[category] + if !exists { + return nil, httperrors.NewInputParameterError("instance_type_category %s is invalid", category) + } + // 格式 ecs.g1.c1m1 + name, err := genInstanceType(family, cpu, mem) + if err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + + data.Set("name", jsonutils.NewString(name)) + + q := self.Query().Equals("name", name) + if len(provider) > 0 { + q = q.Equals("provider", provider) + } else { + q = q.Filter(sqlchemy.OR( + sqlchemy.IsNull(q.Field("provider")), + sqlchemy.IsEmpty(q.Field("provider")), + )) + } + + if q.Count() > 0 { + return nil, httperrors.NewDuplicateResourceError("Duplicate sku") + } + return self.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data) } @@ -184,7 +252,15 @@ func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, use q := self.Query() zone, err := query.GetString("zone") if err == nil && len(zone) > 0 { - q = q.Equals("zone_id", zone) + 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) + } + + q = q.Equals("zone_id", zoneObj.GetId()) } else { return nil, httperrors.NewMissingParameterError("zone") } @@ -255,12 +331,12 @@ func (self *SServerSku) ValidateUpdateData( data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { if !inWhiteList(self.Provider) { - return nil, httperrors.NewForbiddenError("can not create instance_type for public cloud %s", self.Provider) + return nil, httperrors.NewForbiddenError("can not update instance_type for public cloud %s", self.Provider) } provider, err := data.GetString("provider") if err == nil && !inWhiteList(provider) { - return nil, httperrors.NewForbiddenError("can not create instance_type for public cloud %s", provider) + return nil, httperrors.NewForbiddenError("can not update instance_type for public cloud %s", provider) } zoneStr := jsonutils.GetAnyString(data, []string{"zone", "zone_id"}) @@ -274,6 +350,50 @@ func (self *SServerSku) ValidateUpdateData( } data.Add(jsonutils.NewString(zoneObj.GetId()), "zone_id") } + + // name 由服务器端生成 + _, err = data.GetString("name") + if err != nil { + data.Remove("name") + } + + cpu, err := data.Int("cpu_core_count") + if err != nil { + cpu = int64(self.CpuCoreCount) + } + + mem, err := data.Int("memory_size_mb") + if err != nil { + mem = int64(self.MemorySizeMB) + } + + category, _ := data.GetString("instance_type_category") + family, exists := InstanceFamilies[category] + if !exists { + return nil, httperrors.NewInputParameterError("instance_type_category %s is invalid", category) + } + // 格式 ecs.g1.c1m1 + name, err := genInstanceType(family, cpu, mem) + if err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + + data.Set("name", jsonutils.NewString(name)) + + q := self.GetModelManager().Query().Equals("name", name) + if len(provider) > 0 { + q = q.Equals("provider", provider) + } else { + q = q.Filter(sqlchemy.OR( + sqlchemy.IsNull(q.Field("provider")), + sqlchemy.IsEmpty(q.Field("provider")), + )) + } + + if q.Count() > 0 { + return nil, httperrors.NewDuplicateResourceError("sku cpu %s mem %s(Mb) already exists", cpu, mem) + } + return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) } @@ -303,20 +423,23 @@ 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) { - queryDict := query.(*jsonutils.JSONDict) - provider := jsonutils.GetAnyString(query, []string{"provider"}) - if len(provider) > 0 { - if provider != "all" { - q = q.Equals("provider", provider) + if inWhiteList(provider) { + // provider 参数为空或者all时。表示查询`通用`私用云instance type列表 + if provider == "" || provider == "all" { + q = q.Filter(sqlchemy.OR( + sqlchemy.IsNull(q.Field("provider")), + sqlchemy.IsEmpty(q.Field("provider")), + )) + } else { + q = q.Filter(sqlchemy.OR( + sqlchemy.IsNull(q.Field("provider")), + sqlchemy.IsEmpty(q.Field("provider")), + sqlchemy.Equals(q.Field("provider"), provider), + )) } - - queryDict.Remove("provider") } else { - q = q.Filter(sqlchemy.OR( - sqlchemy.IsNull(q.Field("provider")), - sqlchemy.IsEmpty(q.Field("provider")), - )) + q = q.Equals("provider", provider) } q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query) @@ -336,8 +459,9 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("cloudregion_id", regionObj.GetId()) } + // 当查询私有云时,需要忽略zone参数 zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) - if len(zoneStr) > 0 { + if !inWhiteList(provider) && len(zoneStr) > 0 { zoneObj, err := ZoneManager.FetchByIdOrName(nil, zoneStr) if err != nil { if err == sql.ErrNoRows {