From dc8086ed90f3e80bde2299fe6fd05ca7cd1d40ae Mon Sep 17 00:00:00 2001 From: TangBin Date: Wed, 26 Dec 2018 14:42:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=9D=E6=AC=A1=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E4=BA=91=E8=B4=A6=E5=8F=B7=E5=86=85=E5=AD=98=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/skus.go | 10 +- pkg/compute/models/skus.go | 133 +++++++++++++----- pkg/compute/skus/skus.go | 33 +++-- pkg/compute/tasks/cloud_account_sync_task.go | 15 -- .../tasks/cloud_provider_sync_info_task.go | 21 +++ pkg/mcclient/modules/mod_skus.go | 3 +- 6 files changed, 148 insertions(+), 67 deletions(-) diff --git a/cmd/climc/shell/skus.go b/cmd/climc/shell/skus.go index 7d1f3e79e6..104a0c550f 100644 --- a/cmd/climc/shell/skus.go +++ b/cmd/climc/shell/skus.go @@ -11,8 +11,8 @@ func init() { 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"` + 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 { @@ -83,8 +83,10 @@ func init() { type ServerSkusUpdateOptions struct { ID string `help:"Name or ID of SKU" json:"-"` - CpuCoreCount *int `help:"Cpu Count"` - MemorySizeMB *int `help:"Memory MB"` + PostpaidStatus *string `help:"skus available status for postpaid instance" choices:"available|soldout"` + PrepaidStatus *string `help:"skus available status for prepaid instance" choices:"available|soldout"` + CpuCoreCount *int `help:"Cpu Count"` + MemorySizeMB *int `help:"Memory MB"` InstanceTypeCategory *string `help:"instance type category" choices:"general_purpose|compute_optimized|memory_optimized|storage_optimized|hardware_accelerated|high_memory|high_storage"` diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index fa26fe3d1d..b25b7b61d6 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -26,6 +26,11 @@ const ( SkuCategoryHighMemory = "high_memory" // 高内存型 ) +const ( + SkuStatusAvailable = "available" + SkuStatusSoldout = "soldout" +) + var InstanceFamilies = map[string]string{ SkuCategoryGeneralPurpose: "g1", SkuCategoryBurstable: "t1", @@ -63,6 +68,9 @@ type SServerSku struct { InstanceTypeFamily string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // x2 InstanceTypeCategory string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 通用型 + PrepaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 预付费资源状态 available|soldout + PostpaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 按需付费资源状态 available|soldout + CpuCoreCount int `nullable:"false" list:"user" create:"admin_required" update:"admin"` MemorySizeMB int `nullable:"false" list:"user" create:"admin_required" update:"admin"` @@ -351,50 +359,70 @@ func (self *SServerSku) ValidateUpdateData( data.Add(jsonutils.NewString(zoneObj.GetId()), "zone_id") } - // name 由服务器端生成 - cpu, err := data.Int("cpu_core_count") - if err != nil { - cpu = int64(self.CpuCoreCount) - } - data.Set("cpu_core_count", jsonutils.NewInt(cpu)) - - mem, err := data.Int("memory_size_mb") - if err != nil { - mem = int64(self.MemorySizeMB) - } - data.Set("memory_size_mb", jsonutils.NewInt(mem)) - - category, err := data.GetString("instance_type_category") - family := "" - if err != nil { - family = self.InstanceTypeFamily - } else { - f, exists := InstanceFamilies[category] - if !exists { - return nil, httperrors.NewInputParameterError("instance_type_category %s is invalid", category) + // 可用资源状态 + if postpaid, err := data.GetString("postpaid_status"); err != nil { + if postpaid == SkuStatusSoldout { + data.Set("postpaid_status", jsonutils.NewString(SkuStatusSoldout)) + } else { + data.Set("postpaid_status", jsonutils.NewString(SkuStatusAvailable)) } - - family = f } - data.Set("instance_type_family", jsonutils.NewString(family)) - // 格式 ecs.g1.c1m1 - name, err := genInstanceType(family, cpu, mem) - if err != nil { - return nil, httperrors.NewInputParameterError(err.Error()) + prepaid, _ := data.GetString("prepaid_status") + if prepaid == SkuStatusSoldout { + data.Set("prepaid_status", jsonutils.NewString(SkuStatusSoldout)) + } else { + data.Set("prepaid_status", jsonutils.NewString(SkuStatusAvailable)) } - data.Set("name", jsonutils.NewString(name)) - - q := self.GetModelManager().Query() - q = q.Equals("name", name).Filter(sqlchemy.OR( - sqlchemy.IsNull(q.Field("provider")), - sqlchemy.IsEmpty(q.Field("provider")), - )) - - if q.Count() > 0 { - return nil, httperrors.NewDuplicateResourceError("sku cpu %d mem %d(Mb) already exists", cpu, mem) - } + // name 由服务器端生成 + // cpu, err := data.Int("cpu_core_count") + // if err != nil { + // cpu = int64(self.CpuCoreCount) + // } + // data.Set("cpu_core_count", jsonutils.NewInt(cpu)) + // + // mem, err := data.Int("memory_size_mb") + // if err != nil { + // mem = int64(self.MemorySizeMB) + // } + // data.Set("memory_size_mb", jsonutils.NewInt(mem)) + // + // category, err := data.GetString("instance_type_category") + // family := "" + // if err != nil { + // family = self.InstanceTypeFamily + // } else { + // f, exists := InstanceFamilies[category] + // if !exists { + // return nil, httperrors.NewInputParameterError("instance_type_category %s is invalid", category) + // } + // + // family = f + // } + // + // data.Set("instance_type_family", jsonutils.NewString(family)) + // // 格式 ecs.g1.c1m1 + // name, err := genInstanceType(family, cpu, mem) + // if err != nil { + // return nil, httperrors.NewInputParameterError(err.Error()) + // } + // + // data.Set("name", jsonutils.NewString(name)) + // 暂时不允许修改CPU、MEM值 + data.Remove("cpu_core_count") + data.Remove("memory_size_mb") + data.Remove("name") + // 暂时不允许修改CPU、MEM值 + // q := self.GetModelManager().Query() + // q = q.Equals("name", name).Filter(sqlchemy.OR( + // sqlchemy.IsNull(q.Field("provider")), + // sqlchemy.IsEmpty(q.Field("provider")), + // )) + // + // if q.Count() > 0 { + // return nil, httperrors.NewDuplicateResourceError("sku cpu %d mem %d(Mb) already exists", cpu, mem) + // } return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) } @@ -404,6 +432,11 @@ func (self *SServerSku) AllowDeleteItem(ctx context.Context, userCred mcclient.T } func (self *SServerSku) ValidateDeleteCondition(ctx context.Context) error { + serverCount := GuestManager.Query().Equals("instance_type", self.Id).Limit(1).Count() + if serverCount > 0 { + return httperrors.NewForbiddenError("now allow to delete inuse instance_type.please remove related server: %s", self.Name) + } + if !inWhiteList(self.Provider) { return httperrors.NewForbiddenError("not allow to delete public cloud instance_type: %s", self.Name) } @@ -456,6 +489,17 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("cloudregion_id", regionObj.GetId()) } + // 可用资源状态 + postpaid, _ := query.GetString("postpaid_status") + if len(postpaid) > 0 { + q.Equals("postpaid_status", postpaid) + } + + prepaid, _ := query.GetString("prepaid_status") + if len(prepaid) > 0 { + q.Equals("prepaid_status", postpaid) + } + // 当查询私有云时,需要忽略zone参数 zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) if !inWhiteList(provider) && len(zoneStr) > 0 { @@ -530,6 +574,17 @@ func (manager *SServerSkuManager) GetSkuCountByProvider(provider string) int { return q.Count() } +func (manager *SServerSkuManager) GetSkuCountByRegion(regionId string) int { + q := manager.Query() + if len(regionId) == 0 { + q = q.IsNotEmpty("cloudregion_id") + } else { + q = q.Equals("cloudregion_id", regionId) + } + + return q.Count() +} + // 删除表中zone not found的记录 func (manager *SServerSkuManager) PendingDeleteInvalidSku() error { sq := ZoneManager.Query("id").Distinct().SubQuery() diff --git a/pkg/compute/skus/skus.go b/pkg/compute/skus/skus.go index fe5557c8b1..76d4deefb7 100644 --- a/pkg/compute/skus/skus.go +++ b/pkg/compute/skus/skus.go @@ -74,11 +74,7 @@ func processSkuData(ndata jsonutils.JSONObject) jsonutils.JSONObject { } // 处理os name - os_name, err := ndata.GetString("os_name") - if err != nil { - log.Debugf("no os name %s", ndata) - } - + os_name, _ := ndata.GetString("os_name") os_name = strings.ToLower(os_name) if strings.Contains(os_name, "any") || strings.Contains(os_name, "na") || os_name == "" { data.Set("os_name", jsonutils.NewString("Any")) @@ -186,13 +182,11 @@ func (self *SkusZone) SyncToLocalDB() error { log.Debugf("SyncToLocalDB zone %s name %s : %s", self.ZoneId, name, err.Error()) return err } - data := models.SServerSku{} if e := sku.Unmarshal(&data); e != nil { log.Debugf("sku Unmarshal failed: %s, %s", sku, e.Error()) return e } - if err := self.doCreate(data); err != nil { return err } @@ -273,10 +267,14 @@ func (self *SkusZoneList) Refresh(providerIds *[]string) error { } } + self.refresh() + return nil +} + +func (self *SkusZoneList) refresh() { self.total = len(self.Data) self.scuccesed = 0 self.failed = 0 - return nil } func (self *SkusZoneList) SyncToLocalDB() error { @@ -341,3 +339,22 @@ func SyncSkusByProviderIds(providerIds []string) error { return nil } + +// 同步指定zone sku列表 +func SyncSkusByRegion(region *models.SCloudregion) error { + skus := SkusZoneList{} + zones, err := models.ZoneManager.GetZonesByRegion(region) + if err != nil { + return err + } + + log.Debugf("SyncSkusByRegion %s", region.GetName()) + skus.initData(region.Provider, *region, zones) + skus.refresh() + + if e := skus.SyncToLocalDB(); e != nil { + return fmt.Errorf("SyncSkus sync to local db failed, %s", e.Error()) + } + + return nil +} diff --git a/pkg/compute/tasks/cloud_account_sync_task.go b/pkg/compute/tasks/cloud_account_sync_task.go index 0ffcf2ef83..6806cf5508 100644 --- a/pkg/compute/tasks/cloud_account_sync_task.go +++ b/pkg/compute/tasks/cloud_account_sync_task.go @@ -7,7 +7,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/compute/skus" ) type CloudAccountSyncInfoTask struct { @@ -83,20 +82,6 @@ func (self *CloudAccountSyncInfoTask) OnCloudaccountSyncComplete(ctx context.Con if account != nil { account.SetStatus(self.UserCred, models.CLOUD_PROVIDER_CONNECTED, "") } - - if models.ServerSkuManager.GetSkuCountByProvider(cloudprovider.Provider) == 0 { - // sync skus - self.SetStage("OnSyncServerSkuComplete", nil) - taskman.LocalTaskRun(self, func() (jsonutils.JSONObject, error) { - err := skus.SyncSkusByProviderIds([]string{cloudprovider.Provider}) - return nil, err - }) - return - } } self.SetStageComplete(ctx, nil) } - -func (self *CloudAccountSyncInfoTask) OnSyncServerSkuComplete(ctx context.Context, items []db.IStandaloneModel, data jsonutils.JSONObject) { - self.SetStageComplete(ctx, nil) -} diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index 4ae4161630..6170d14d7f 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/compute/skus" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/pkg/utils" ) @@ -124,6 +125,7 @@ func syncPublicCloudProviderInfo(ctx context.Context, provider *models.SCloudpro localZones, remoteZones := syncRegionZones(ctx, provider, task, &localRegions[i], remoteRegions[i]) + syncRegionSkus(ctx, provider, task, &localRegions[i]) syncRegionVPCs(ctx, provider, task, &localRegions[i], remoteRegions[i], syncRange) if localZones != nil && remoteZones != nil { @@ -140,6 +142,25 @@ func syncPublicCloudProviderInfo(ctx context.Context, provider *models.SCloudpro } } +func syncRegionSkus(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localRegion *models.SCloudregion) { + if localRegion == nil { + log.Debugf("local region is nil skipped.") + return + } + + regionId := localRegion.GetId() + if len(regionId) > 0 && models.ServerSkuManager.GetSkuCountByRegion(regionId) == 0 { + // 提前同步instance type.如果同步失败可能导致vm 内存显示为0 + if err := skus.SyncSkusByRegion(localRegion); err != nil { + msg := fmt.Sprintf("Get Skus for region %s failed %s", localRegion.GetName(), err) + log.Errorf(msg) + // 暂时不终止同步 + // logSyncFailed(provider, task, msg) + return + } + } +} + func syncRegionSnapshots(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localRegion *models.SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *models.SSyncRange) { snapshots, err := remoteRegion.GetISnapshots() if err != nil { diff --git a/pkg/mcclient/modules/mod_skus.go b/pkg/mcclient/modules/mod_skus.go index 4e4c5e9b7e..9a21846592 100644 --- a/pkg/mcclient/modules/mod_skus.go +++ b/pkg/mcclient/modules/mod_skus.go @@ -30,7 +30,8 @@ func init() { "Memory_size_mb", "Os_name", "Sys_disk_resizable", "Sys_disk_type", "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"}, + "Data_disk_max_count", "Nic_max_count", "Cloudregion_id", "Zone_id", + "Provider", "Postpaid_status", "Prepaid_status"}, []string{})} register(&CloudmetaSkus)