From 66634a4dfaa42d873961e4eac1a3083c122eee32 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 23 Feb 2019 18:45:04 +0800 Subject: [PATCH 1/4] fix: eip support prepaid charge type --- cmd/climc/shell/cloudregions.go | 1 + cmd/climc/shell/events.go | 10 ++++ pkg/cloudprovider/resources.go | 2 + pkg/compute/models/elasticips.go | 21 ++++++-- pkg/compute/models/guests.go | 4 +- .../tasks/cloud_provider_sync_info_task.go | 3 +- pkg/compute/tasks/eip_allocate_task.go | 2 +- pkg/compute/tasks/eip_syncstatus_task.go | 2 +- pkg/util/aliyun/aliyun.go | 13 ++++- pkg/util/aliyun/business.go | 8 +-- pkg/util/aliyun/charge.go | 28 +++++++++++ pkg/util/aliyun/disk.go | 13 ++--- pkg/util/aliyun/eip.go | 36 +++++++++++-- pkg/util/aliyun/instance.go | 21 ++------ pkg/util/aliyun/ram.go | 8 +-- pkg/util/aliyun/region.go | 8 +-- pkg/util/aliyun/zone.go | 8 +-- pkg/util/aws/eip.go | 8 +++ pkg/util/azure/classic_eip.go | 9 ++++ pkg/util/azure/eip.go | 14 +++--- pkg/util/httputils/httputils.go | 3 +- .../huawei/client/modules/manager_base.go | 2 +- pkg/util/huawei/eip.go | 44 ++++++++++------ pkg/util/huawei/instance.go | 50 +++++++++---------- pkg/util/huawei/shell/eip.go | 4 +- pkg/util/qcloud/eip.go | 8 +++ 26 files changed, 213 insertions(+), 117 deletions(-) create mode 100644 pkg/util/aliyun/charge.go diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go index ccea6932ce..034ba9d8c0 100644 --- a/cmd/climc/shell/cloudregions.go +++ b/cmd/climc/shell/cloudregions.go @@ -34,6 +34,7 @@ func init() { Manager string `help:"List objects belonging to the cloud provider"` Account string `help:"List objects belonging to the cloud account"` Provider string `help:"List objects from the provider" choices:"VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack"` + City string `help:"List regions in the specified city"` PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"` PrivateCloud *bool `help:"List objects belonging to private cloud" json:"private_cloud"` diff --git a/cmd/climc/shell/events.go b/cmd/climc/shell/events.go index 974f33b3ca..ad442d8b49 100644 --- a/cmd/climc/shell/events.go +++ b/cmd/climc/shell/events.go @@ -85,6 +85,16 @@ func init() { return doComputeEventList(s, &nargs) }) + R(&TypeEventListOptions{}, "disk-event", "Show operation event logs of disk", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"disk"}} + return doComputeEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "eip-event", "Show operation event logs of elastic IP", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"eip"}} + return doComputeEventList(s, &nargs) + }) + R(&TypeEventListOptions{}, "host-event", "Show operation event logs of host", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"host"}} return doComputeEventList(s, &nargs) diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index eaa76d6a24..9c2e7fadae 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -252,6 +252,7 @@ type ICloudNic interface { type ICloudEIP interface { ICloudResource + IBillingResource GetIpAddr() string GetMode() string @@ -274,6 +275,7 @@ type ICloudEIP interface { type ICloudSecurityGroup interface { ICloudResource + GetDescription() string GetRules() ([]secrules.SecurityRule, error) GetVpcId() string diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index efcdf1b517..dd90cf12a0 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -66,6 +66,7 @@ type SElasticip struct { db.SVirtualResourceBase SManagedResourceBase + SBillingResourceBase Mode string `width:"32" charset:"ascii" list:"user"` @@ -76,7 +77,7 @@ type SElasticip struct { Bandwidth int `list:"user" create:"required"` - ChargeType string `list:"user" create:"required"` + ChargeType string `name:"charge_type" list:"user" create:"required"` BgpType string `list:"user" create:"optional"` // 目前只有华为云此字段是必需填写的。 AutoDellocate tristate.TriState `default:"false" get:"user" create:"optional" update:"user"` @@ -173,7 +174,7 @@ func (self *SElasticip) GetRegion() *SCloudregion { func (self *SElasticip) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc := self.SVirtualResourceBase.GetShortDesc(ctx) - desc.Add(jsonutils.NewString(self.ChargeType), "charge_type") + // desc.Add(jsonutils.NewString(self.ChargeType), "charge_type") desc.Add(jsonutils.NewInt(int64(self.Bandwidth)), "bandwidth") desc.Add(jsonutils.NewString(self.Mode), "mode") @@ -191,8 +192,14 @@ func (self *SElasticip) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { billingInfo.SCloudProviderInfo = self.getCloudProviderInfo() + billingInfo.SBillingBaseInfo = self.getBillingBaseInfo() + billingInfo.InternetChargeType = self.ChargeType + if priceKey := self.GetMetadata("price_key", nil); len(priceKey) > 0 { + billingInfo.PriceKey = priceKey + } + desc.Update(jsonutils.Marshal(billingInfo)) return desc @@ -229,7 +236,7 @@ func (manager *SElasticipManager) SyncEips(ctx context.Context, userCred mcclien } } for i := 0; i < len(commondb); i += 1 { - err = commondb[i].SyncWithCloudEip(userCred, commonext[i], projectId, projectSync) + err = commondb[i].SyncWithCloudEip(userCred, provider, commonext[i], projectId, projectSync) if err != nil { syncResult.UpdateError(err) } else { @@ -283,7 +290,7 @@ func (self *SElasticip) SyncInstanceWithCloudEip(ctx context.Context, userCred m return nil } -func (self *SElasticip) SyncWithCloudEip(userCred mcclient.TokenCredential, ext cloudprovider.ICloudEIP, projectId string, projectSync bool) error { +func (self *SElasticip) SyncWithCloudEip(userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudEIP, projectId string, projectSync bool) error { _, err := self.GetModelManager().TableSpec().Update(self, func() error { // self.Name = ext.GetName() @@ -300,6 +307,12 @@ func (self *SElasticip) SyncWithCloudEip(userCred mcclient.TokenCredential, ext } self.ChargeType = ext.GetInternetChargeType() + factory, _ := provider.GetProviderFactory() + if factory != nil && factory.IsSupportPrepaidResources() { + self.BillingType = ext.GetBillingType() + self.ExpiredAt = ext.GetExpiredAt() + } + return nil }) if err != nil { diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 5f857654ec..780c8a129b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3686,7 +3686,7 @@ func (self *SGuest) GetRealIps() []string { return self.getRealIPs() } -func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCredential, extEip cloudprovider.ICloudEIP, projectId string) compare.SyncResult { +func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extEip cloudprovider.ICloudEIP, projectId string) compare.SyncResult { result := compare.SyncResult{} eip, err := self.GetEip() @@ -3744,7 +3744,7 @@ func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCreden } } else { // do nothing - err := eip.SyncWithCloudEip(userCred, extEip, projectId, false) + err := eip.SyncWithCloudEip(userCred, provider, extEip, projectId, false) if err != nil { result.UpdateError(err) } else { diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index 406f32a875..852d01468f 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -3,7 +3,6 @@ package tasks import ( "context" "fmt" - "strings" "yunion.io/x/jsonutils" @@ -767,7 +766,7 @@ func syncVMEip(ctx context.Context, provider *models.SCloudprovider, task *Cloud logSyncFailed(provider, task, msg) return } - result := localVM.SyncVMEip(ctx, task.UserCred, eip, provider.ProjectId) + result := localVM.SyncVMEip(ctx, task.UserCred, provider, eip, provider.ProjectId) msg := result.Result() log.Infof("syncVMEip for VM %s result: %s", localVM.Name, msg) if result.IsError() { diff --git a/pkg/compute/tasks/eip_allocate_task.go b/pkg/compute/tasks/eip_allocate_task.go index 7ec5713f7e..c3299ecfe8 100644 --- a/pkg/compute/tasks/eip_allocate_task.go +++ b/pkg/compute/tasks/eip_allocate_task.go @@ -53,7 +53,7 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel return } - err = eip.SyncWithCloudEip(self.UserCred, extEip, "", false) + err = eip.SyncWithCloudEip(self.UserCred, eip.GetCloudprovider(), extEip, "", false) if err != nil { msg := fmt.Sprintf("sync eip fail %s", err) diff --git a/pkg/compute/tasks/eip_syncstatus_task.go b/pkg/compute/tasks/eip_syncstatus_task.go index 799d316bed..369a5b4d07 100644 --- a/pkg/compute/tasks/eip_syncstatus_task.go +++ b/pkg/compute/tasks/eip_syncstatus_task.go @@ -38,7 +38,7 @@ func (self *EipSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneMod return } - err = eip.SyncWithCloudEip(self.UserCred, extEip, "", false) + err = eip.SyncWithCloudEip(self.UserCred, eip.GetCloudprovider(), extEip, "", false) if err != nil { msg := fmt.Sprintf("fail to sync eip status %s", err) eip.SetStatus(self.UserCred, models.EIP_STATUS_UNKNOWN, msg) diff --git a/pkg/util/aliyun/aliyun.go b/pkg/util/aliyun/aliyun.go index 830422825c..0eb3d7bd11 100644 --- a/pkg/util/aliyun/aliyun.go +++ b/pkg/util/aliyun/aliyun.go @@ -50,7 +50,10 @@ func NewAliyunClient(providerId string, providerName string, accessKey string, s return &client, nil } -func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { + if debug { + log.Debugf("request %s %s %s %s", domain, apiVersion, apiName, params) + } for i := 1; i < 4; i++ { resp, err := _jsonRequest(client, domain, apiVersion, apiName, params) retry := false @@ -68,9 +71,15 @@ func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params } } if retry { + if debug { + log.Debugf("Retry %d...", i) + } time.Sleep(time.Second * time.Duration(i*10)) continue } + if debug { + log.Debugf("Response: %s", resp) + } return resp, err } return nil, fmt.Errorf("timeout for request %s params: %s", apiName, params) @@ -128,7 +137,7 @@ func (self *SAliyunClient) ecsRequest(apiName string, params map[string]string) if err != nil { return nil, err } - return jsonRequest(cli, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params) + return jsonRequest(cli, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params, self.Debug) } func (self *SAliyunClient) fetchRegions() error { diff --git a/pkg/util/aliyun/business.go b/pkg/util/aliyun/business.go index 3c521ab340..c5a479d634 100644 --- a/pkg/util/aliyun/business.go +++ b/pkg/util/aliyun/business.go @@ -3,22 +3,16 @@ package aliyun import ( "time" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk" - "yunion.io/x/jsonutils" "yunion.io/x/log" ) -func businessRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return jsonRequest(client, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params) -} - func (self *SAliyunClient) businessRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { cli, err := self.getDefaultClient() if err != nil { return nil, err } - return businessRequest(cli, apiName, params) + return jsonRequest(cli, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params, self.Debug) } type SAccountBalance struct { diff --git a/pkg/util/aliyun/charge.go b/pkg/util/aliyun/charge.go new file mode 100644 index 0000000000..7511212e54 --- /dev/null +++ b/pkg/util/aliyun/charge.go @@ -0,0 +1,28 @@ +package aliyun + +import ( + "time" + + "yunion.io/x/onecloud/pkg/compute/models" +) + +func convertChargeType(ct TChargeType) string { + switch ct { + case PrePaidInstanceChargeType: + return models.BILLING_TYPE_PREPAID + case PostPaidInstanceChargeType: + return models.BILLING_TYPE_POSTPAID + default: + return models.BILLING_TYPE_PREPAID + } +} + +func convertExpiredAt(expired time.Time) time.Time { + if !expired.IsZero() { + now := time.Now() + if expired.Sub(now) < time.Hour*24*365*6 { + return expired + } + } + return time.Time{} +} diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index 390900c1c0..2f52be2bf1 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -33,7 +33,7 @@ type SDisk struct { Description string DetachedTime time.Time Device string - DiskChargeType InstanceChargeType + DiskChargeType TChargeType DiskId string DiskName string EnableAutoSnapshot bool @@ -373,18 +373,11 @@ func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) } func (self *SDisk) GetBillingType() string { - switch self.DiskChargeType { - case PrePaidInstanceChargeType: - return models.BILLING_TYPE_PREPAID - case PostPaidInstanceChargeType: - return models.BILLING_TYPE_POSTPAID - default: - return models.BILLING_TYPE_PREPAID - } + return convertChargeType(self.DiskChargeType) } func (self *SDisk) GetExpiredAt() time.Time { - return self.ExpiredTime + return convertExpiredAt(self.ExpiredTime) } func (self *SDisk) GetAccessPath() string { diff --git a/pkg/util/aliyun/eip.go b/pkg/util/aliyun/eip.go index 3f32e82b4f..af609a9f3a 100644 --- a/pkg/util/aliyun/eip.go +++ b/pkg/util/aliyun/eip.go @@ -34,12 +34,29 @@ const ( EIP_INSTANCE_TYPE_HAVIP = "HaVip" // :HAVIP ) +/* +{ + "AllocationId":"eip-2zeddtan63ou44dtyt9s3", + "AllocationTime":"2019-02-23T06:48:36Z", + "Bandwidth":"100", + "ChargeType":"PostPaid", + "ExpiredTime":"", + "InstanceId":"", + "InstanceType":"", + "InternetChargeType":"PayByTraffic", + "IpAddress":"39.105.131.32", + "OperationLocks":{"LockReason":[]}, + "RegionId":"cn-beijing", + "Status":"Available" +} +*/ + type SEipAddress struct { region *SRegion AllocationId string - InternetChargeType string + InternetChargeType TInternetChargeType IpAddress string Status string @@ -51,6 +68,9 @@ type SEipAddress struct { AllocationTime time.Time OperationLocks string + + ChargeType TChargeType + ExpiredTime time.Time } func (self *SEipAddress) GetId() string { @@ -132,6 +152,14 @@ func (self *SEipAddress) GetManagerId() string { return self.region.client.providerId } +func (self *SEipAddress) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + func (self *SEipAddress) Delete() error { return self.region.DeallocateEIP(self.AllocationId) } @@ -142,9 +170,9 @@ func (self *SEipAddress) GetBandwidth() int { func (self *SEipAddress) GetInternetChargeType() string { switch self.InternetChargeType { - case string(InternetChargeByTraffic): + case InternetChargeByTraffic: return models.EIP_CHARGE_TYPE_BY_TRAFFIC - case string(InternetChargeByBandwidth): + case InternetChargeByBandwidth: return models.EIP_CHARGE_TYPE_BY_BANDWIDTH default: return models.EIP_CHARGE_TYPE_BY_TRAFFIC @@ -193,8 +221,6 @@ func (region *SRegion) GetEips(eipId string, offset int, limit int) ([]SEipAddre return nil, 0, err } - // log.Errorf("%s", body) - eips := make([]SEipAddress, 0) err = body.Unmarshal(&eips, "EipAddresses", "EipAddress") if err != nil { diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index 5e0f44448a..c42365e4a6 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -84,13 +84,13 @@ type SInstance struct { HostName string ImageId string InnerIpAddress SIpAddress - InstanceChargeType InstanceChargeType + InstanceChargeType TChargeType InstanceId string InstanceName string InstanceNetworkType string InstanceType string InstanceTypeFamily string - InternetChargeType string + InternetChargeType TInternetChargeType InternetMaxBandwidthIn int InternetMaxBandwidthOut int IoOptimized bool @@ -901,24 +901,11 @@ func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { } func (self *SInstance) GetBillingType() string { - switch self.InstanceChargeType { - case PrePaidInstanceChargeType: - return models.BILLING_TYPE_PREPAID - case PostPaidInstanceChargeType: - return models.BILLING_TYPE_POSTPAID - default: - return models.BILLING_TYPE_PREPAID - } + return convertChargeType(self.InstanceChargeType) } func (self *SInstance) GetExpiredAt() time.Time { - if !self.ExpiredTime.IsZero() { - now := time.Now() - if self.ExpiredTime.Sub(now) < time.Hour*24*365*6 { - return self.ExpiredTime - } - } - return time.Time{} + return convertExpiredAt(self.ExpiredTime) } func (self *SInstance) UpdateUserData(userData string) error { diff --git a/pkg/util/aliyun/ram.go b/pkg/util/aliyun/ram.go index f31862a035..b45743aa52 100644 --- a/pkg/util/aliyun/ram.go +++ b/pkg/util/aliyun/ram.go @@ -3,24 +3,18 @@ package aliyun import ( "time" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" ) -func ramRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return jsonRequest(client, "ram.aliyuncs.com", ALIYUN_RAM_API_VERSION, apiName, params) -} - func (self *SAliyunClient) ramRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { cli, err := self.getDefaultClient() if err != nil { return nil, err } - return ramRequest(cli, apiName, params) + return jsonRequest(cli, "ram.aliyuncs.com", ALIYUN_RAM_API_VERSION, apiName, params, self.Debug) } type SRole struct { diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index ab3032d655..6e0630aaed 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -90,7 +90,7 @@ func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonu if err != nil { return nil, err } - return jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params) + return jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params, self.client.Debug) } func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { @@ -98,7 +98,7 @@ func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonut if err != nil { return nil, err } - return jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params) + return jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params, self.Debug) } type LBRegion struct { @@ -148,7 +148,7 @@ func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonut } func (self *SRegion) _lbRequest(client *sdk.Client, apiName string, domain string, params map[string]string) (jsonutils.JSONObject, error) { - return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params) + return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.Debug) } ///////////////////////////////////////////////////////////////////////////// @@ -219,7 +219,7 @@ func (self *SRegion) getStoragecache() *SStoragecache { return self.storageCache } -func (self *SRegion) _fetchZones(chargeType InstanceChargeType, spotStrategy SpotStrategyType) error { +func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { params := make(map[string]string) params["RegionId"] = self.RegionId if len(chargeType) > 0 { diff --git a/pkg/util/aliyun/zone.go b/pkg/util/aliyun/zone.go index 00ae518797..27a43a8855 100644 --- a/pkg/util/aliyun/zone.go +++ b/pkg/util/aliyun/zone.go @@ -11,12 +11,12 @@ import ( "yunion.io/x/onecloud/pkg/compute/models" ) -type InstanceChargeType string +type TChargeType string const ( - PrePaidInstanceChargeType InstanceChargeType = "PrePaid" - PostPaidInstanceChargeType InstanceChargeType = "PostPaid" - DefaultInstanceChargeType = PostPaidInstanceChargeType + PrePaidInstanceChargeType TChargeType = "PrePaid" + PostPaidInstanceChargeType TChargeType = "PostPaid" + DefaultInstanceChargeType = PostPaidInstanceChargeType ) type SpotStrategyType string diff --git a/pkg/util/aws/eip.go b/pkg/util/aws/eip.go index 1e76df40fd..8ac7d7e1ee 100644 --- a/pkg/util/aws/eip.go +++ b/pkg/util/aws/eip.go @@ -296,3 +296,11 @@ func (self *SRegion) DissociateEip(eipId string, instanceId string) error { func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error { return cloudprovider.ErrNotSupported } + +func (self *SEipAddress) GetBillingType() string { + return models.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} diff --git a/pkg/util/azure/classic_eip.go b/pkg/util/azure/classic_eip.go index 901dd900b6..71415c7b93 100644 --- a/pkg/util/azure/classic_eip.go +++ b/pkg/util/azure/classic_eip.go @@ -2,6 +2,7 @@ package azure import ( "strings" + "time" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -142,3 +143,11 @@ func (region *SRegion) GetClassicEips() ([]SClassicEipAddress, error) { } return result, nil } + +func (self *SClassicEipAddress) GetBillingType() string { + return models.BILLING_TYPE_POSTPAID +} + +func (self *SClassicEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} diff --git a/pkg/util/azure/eip.go b/pkg/util/azure/eip.go index 4b5db78ad4..68ddbe06c3 100644 --- a/pkg/util/azure/eip.go +++ b/pkg/util/azure/eip.go @@ -12,12 +12,6 @@ import ( "yunion.io/x/onecloud/pkg/compute/models" ) -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("PayByTraffic") -) - type PublicIPAddressSku struct { Name string } @@ -240,3 +234,11 @@ func (self *SEipAddress) Refresh() error { } return jsonutils.Update(self, eip) } + +func (self *SEipAddress) GetBillingType() string { + return models.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} diff --git a/pkg/util/httputils/httputils.go b/pkg/util/httputils/httputils.go index b13e1a8f76..b2be6b61e0 100644 --- a/pkg/util/httputils/httputils.go +++ b/pkg/util/httputils/httputils.go @@ -17,9 +17,10 @@ import ( "github.com/moul/http2curl" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/appctx" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/trace" + + "yunion.io/x/onecloud/pkg/appctx" ) type THttpMethod string diff --git a/pkg/util/huawei/client/modules/manager_base.go b/pkg/util/huawei/client/modules/manager_base.go index d740681d71..4590b80262 100644 --- a/pkg/util/huawei/client/modules/manager_base.go +++ b/pkg/util/huawei/client/modules/manager_base.go @@ -143,7 +143,7 @@ func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, j h, b, e := httputils.JSONRequest(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, jsonBody, self.debug) if e == nil { if self.debug { - log.Debugf("response: %s body: %s", h, b.String()) + log.Debugf("response: %s body: %s", h, b) } return h, b, e } diff --git a/pkg/util/huawei/eip.go b/pkg/util/huawei/eip.go index 7238fc2e77..b0aa932fc3 100644 --- a/pkg/util/huawei/eip.go +++ b/pkg/util/huawei/eip.go @@ -50,7 +50,7 @@ type PublicipInfo struct { IPVersion int64 `json:"ip_version"` } -type Profile struct { +type SProfile struct { UserID string `json:"user_id"` ProductID string `json:"product_id"` RegionID string `json:"region_id"` @@ -61,21 +61,21 @@ type Profile struct { type SEipAddress struct { region *SRegion - ID string `json:"id"` - Status string `json:"status"` - Profile Profile `json:"profile"` - Type string `json:"type"` - PublicIPAddress string `json:"public_ip_address"` - PrivateIPAddress string `json:"private_ip_address"` - TenantID string `json:"tenant_id"` - CreateTime string `json:"create_time"` - BandwidthID string `json:"bandwidth_id"` - BandwidthShareType string `json:"bandwidth_share_type"` - BandwidthSize int64 `json:"bandwidth_size"` - BandwidthName string `json:"bandwidth_name"` - EnterpriseProjectID string `json:"enterprise_project_id"` - IPVersion int64 `json:"ip_version"` - PortId string `json:"port_id"` + ID string `json:"id"` + Status string `json:"status"` + Profile *SProfile `json:"profile,omitempty"` + Type string `json:"type"` + PublicIPAddress string `json:"public_ip_address"` + PrivateIPAddress string `json:"private_ip_address"` + TenantID string `json:"tenant_id"` + CreateTime string `json:"create_time"` + BandwidthID string `json:"bandwidth_id"` + BandwidthShareType string `json:"bandwidth_share_type"` + BandwidthSize int64 `json:"bandwidth_size"` + BandwidthName string `json:"bandwidth_name"` + EnterpriseProjectID string `json:"enterprise_project_id"` + IPVersion int64 `json:"ip_version"` + PortId string `json:"port_id"` } func (self *SEipAddress) GetId() string { @@ -180,6 +180,18 @@ func (self *SEipAddress) GetManagerId() string { return self.region.client.providerId } +func (self *SEipAddress) GetBillingType() string { + if self.Profile == nil { + return models.BILLING_TYPE_POSTPAID + } else { + return models.BILLING_TYPE_PREPAID + } +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + func (self *SEipAddress) Delete() error { return self.region.DeallocateEIP(self.ID) } diff --git a/pkg/util/huawei/instance.go b/pkg/util/huawei/instance.go index 685b5ec456..30846abeda 100644 --- a/pkg/util/huawei/instance.go +++ b/pkg/util/huawei/instance.go @@ -3,21 +3,20 @@ package huawei import ( "context" "fmt" + "sort" + "strconv" "strings" "time" - "strconv" - - "sort" - "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/huawei/client/modules" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" ) const ( @@ -83,25 +82,26 @@ type SysTag struct { type SInstance struct { host *SHost - ID string `json:"id"` - Name string `json:"name"` - Addresses map[string][]IpAddress `json:"addresses"` - Flavor Flavor `json:"flavor"` - AccessIPv4 string `json:"accessIPv4"` - AccessIPv6 string `json:"accessIPv6"` - Status string `json:"status"` - Progress string `json:"progress"` - HostID string `json:"hostId"` - Updated string `json:"updated"` - Created time.Time `json:"created"` - Metadata VMMetadata `json:"metadata"` - Tags []string `json:"tags"` - Description string `json:"description"` - Locked bool `json:"locked"` - ConfigDrive string `json:"config_drive"` - TenantID string `json:"tenant_id"` - UserID string `json:"user_id"` - KeyName string `json:"key_name"` + ID string `json:"id"` + Name string `json:"name"` + Addresses map[string][]IpAddress `json:"addresses"` + Flavor Flavor `json:"flavor"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Status string `json:"status"` + Progress string `json:"progress"` + HostID string `json:"hostId"` + Updated string `json:"updated"` + Created time.Time `json:"created"` + Metadata VMMetadata `json:"metadata"` + Tags []string `json:"tags"` + Description string `json:"description"` + Locked bool `json:"locked"` + ConfigDrive string `json:"config_drive"` + TenantID string `json:"tenant_id"` + UserID string `json:"user_id"` + KeyName string `json:"key_name"` + OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` diff --git a/pkg/util/huawei/shell/eip.go b/pkg/util/huawei/shell/eip.go index 34b45ab7d4..efbea7bc3a 100644 --- a/pkg/util/huawei/shell/eip.go +++ b/pkg/util/huawei/shell/eip.go @@ -18,12 +18,12 @@ func init() { }) type EipAllocateOptions struct { - Name string `help:"eip name"` + NAME string `help:"eip name"` BW int `help:"Bandwidth limit in Mbps"` BGP string `help:"bgp type" choices:"5_telcom|5_union|5_bgp|5_sbgp"` } shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *huawei.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.Name, args.BW, huawei.InternetChargeByTraffic, args.BGP) + eip, err := cli.AllocateEIP(args.NAME, args.BW, huawei.InternetChargeByTraffic, args.BGP) if err != nil { return err } diff --git a/pkg/util/qcloud/eip.go b/pkg/util/qcloud/eip.go index 7293ec9581..afd6dc666d 100644 --- a/pkg/util/qcloud/eip.go +++ b/pkg/util/qcloud/eip.go @@ -150,6 +150,14 @@ func (self *SEipAddress) GetBandwidth() int { return 0 } +func (self *SEipAddress) GetBillingType() string { + return models.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + func (self *SEipAddress) GetInternetChargeType() string { if len(self.InstanceId) > 0 { if instance, err := self.region.GetInstance(self.InstanceId); err == nil { From 67540f32b478d153017619136618ccfc15d1205e Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 23 Feb 2019 18:45:33 +0800 Subject: [PATCH 2/4] fix: cannot undo recycle of expired prepaid vm --- pkg/compute/models/host_recycle.go | 62 +++++++++++------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/pkg/compute/models/host_recycle.go b/pkg/compute/models/host_recycle.go index 7937d27afc..ad44d1a900 100644 --- a/pkg/compute/models/host_recycle.go +++ b/pkg/compute/models/host_recycle.go @@ -419,27 +419,23 @@ func doUndoPrepaidRecycleNoLock(ctx context.Context, userCred mcclient.TokenCred return errors.New(msg) } - iHost, err := oHost.GetIHost() - if err != nil { - msg := fmt.Sprint("fail to find ihost %s", err) - log.Errorf(msg) - return errors.New(msg) - } + guestdisks := server.GetDisks() - iVM, err := iHost.GetIVMById(server.ExternalId) - if err != nil { - msg := fmt.Sprintf("fail to GetIVMById %s", err) - log.Errorf(msg) - return errors.New(msg) - } - - idisks, err := iVM.GetIDisks() - if err != nil { - msg := fmt.Sprintf("iVM.GetIDisks fail %s", err) - log.Errorf(msg) - return errors.New(msg) + // check disk data integrity + for i := 0; i < len(guestdisks); i += 1 { + disk := guestdisks[i].GetDisk() + storage := disk.GetStorage() + if storage.StorageType == STORAGE_LOCAL { + oHostStorage := oHost.GetHoststorageByExternalId(storage.ExternalId) + if oHostStorage == nil { + msg := fmt.Sprintf("oHost.GetHoststorageByExternalId not found %s", storage.ExternalId) + log.Errorf(msg) + return errors.New(msg) + } + } } + // check passed, do convert _, err = server.GetModelManager().TableSpec().Update(server, func() error { // recover billing information server.BillingType = BILLING_TYPE_PREPAID @@ -454,38 +450,24 @@ func doUndoPrepaidRecycleNoLock(ctx context.Context, userCred mcclient.TokenCred return err } - guestdisks := server.GetDisks() - for i := 0; i < len(guestdisks); i += 1 { disk := guestdisks[i].GetDisk() storage := disk.GetStorage() - idisk := findIdiskById(idisks, disk.ExternalId) - if idisk == nil { - msg := fmt.Sprintf("fail to find idisk by ID %s: %s", disk.ExternalId, err) - log.Errorf(msg) - return errors.New(msg) - } - istorage, err := idisk.GetIStorage() - if err != nil { - log.Errorf("idisk.GetIStorage fail %s", err) - return err - } - - oHostStorage := oHost.GetHoststorageByExternalId(istorage.GetGlobalId()) - if oHostStorage == nil { - msg := fmt.Sprintf("oHost.GetHoststorageByExternalId not found %s", istorage.GetGlobalId()) - log.Errorf(msg) - return errors.New(msg) - } - - oStorage := oHostStorage.GetStorage() if storage.StorageType == STORAGE_LOCAL { + oHostStorage := oHost.GetHoststorageByExternalId(storage.ExternalId) + if oHostStorage == nil { + msg := fmt.Sprintf("oHost.GetHoststorageByExternalId not found %s", storage.ExternalId) + log.Errorf(msg) + return errors.New(msg) + } + oStorage := oHostStorage.GetStorage() _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { disk.BillingType = BILLING_TYPE_PREPAID disk.BillingCycle = host.BillingCycle disk.ExpiredAt = host.ExpiredAt disk.StorageId = oStorage.Id + disk.AutoDelete = true return nil }) if err != nil { From 85b1e5732428b4bff1aedb43081406dea6558993 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 23 Feb 2019 21:00:40 +0800 Subject: [PATCH 3/4] fix: action log always success --- pkg/logger/models/actionlog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/logger/models/actionlog.go b/pkg/logger/models/actionlog.go index e75aed9b34..e0534d4b0a 100644 --- a/pkg/logger/models/actionlog.go +++ b/pkg/logger/models/actionlog.go @@ -18,7 +18,7 @@ type SActionlog struct { db.SOpsLog StartTime time.Time `nullable:"false" list:"user" create:"optional"` // = Column(DateTime, nullable=False) - Success bool `default:"true" list:"user" create:"required"` // = Column(Boolean, default=True) + Success bool `list:"user" create:"required"` // = Column(Boolean, default=True) Service string `width:"32" charset:"utf8" nullable:"true" list:"user" create:"optional"` //= Column(VARCHAR(32, charset='utf8'), nullable=False) } From 4c2e9996c13ce2e75095b4cfa423faaf2b2ff326 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 23 Feb 2019 21:01:05 +0800 Subject: [PATCH 4/4] fix: schedule fail should post actionlog --- pkg/compute/models/disks.go | 2 +- pkg/compute/models/guests.go | 1 + pkg/compute/tasks/disk_batch_create_task.go | 4 +- pkg/compute/tasks/guest_backup_tasks.go | 2 +- pkg/compute/tasks/guest_batch_create_task.go | 65 +++++++++----------- pkg/compute/tasks/guest_live_migrate_task.go | 2 +- pkg/compute/tasks/schedule.go | 8 ++- pkg/util/aliyun/shell/image.go | 12 ++++ pkg/util/aliyun/storagecache.go | 9 +-- 9 files changed, 55 insertions(+), 50 deletions(-) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index c4db8bd36c..98376eaefc 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1274,7 +1274,7 @@ func fillDiskConfigByImage(ctx context.Context, userCred mcclient.TokenCredentia // diskConfig.ImageDiskFormat = image.DiskFormat CachedimageManager.ImageAddRefCount(image.Id) if diskConfig.SizeMb == 0 { - diskConfig.SizeMb = image.MinDisk // MB + diskConfig.SizeMb = image.MinDisk * 1024 // MB } } return nil diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 780c8a129b..7542b30e19 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -920,6 +920,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m if rootDiskConfig.SizeMb == 0 { rootDiskConfig.SizeMb = GetDriver(hypervisor).GetMinimalSysDiskSizeGb() * 1024 } + log.Debugf("ROOT DISK: %#v", rootDiskConfig) data.Set("disk.0", jsonutils.Marshal(rootDiskConfig)) for i := 0; i < len(dataDiskDefs); i += 1 { diff --git a/pkg/compute/tasks/disk_batch_create_task.go b/pkg/compute/tasks/disk_batch_create_task.go index d7cbd8e9c4..7948067510 100644 --- a/pkg/compute/tasks/disk_batch_create_task.go +++ b/pkg/compute/tasks/disk_batch_create_task.go @@ -44,8 +44,8 @@ func (self *DiskBatchCreateTask) OnInit(ctx context.Context, objs []db.IStandalo StartScheduleObjects(ctx, self, toSchedDisks) } -func (self *DiskBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) { - self.SSchedTask.OnScheduleFailCallback(obj, reason) +func (self *DiskBatchCreateTask) OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) { + self.SSchedTask.OnScheduleFailCallback(ctx, obj, reason) disk := obj.(*models.SDisk) log.Errorf("Schedule disk %s failed", disk.Name) } diff --git a/pkg/compute/tasks/guest_backup_tasks.go b/pkg/compute/tasks/guest_backup_tasks.go index c993192bb0..0e41cda0e9 100644 --- a/pkg/compute/tasks/guest_backup_tasks.go +++ b/pkg/compute/tasks/guest_backup_tasks.go @@ -172,7 +172,7 @@ func (self *GuestCreateBackupTask) GetSchedParams() *jsonutils.JSONDict { return schedDesc } -func (self *GuestCreateBackupTask) OnScheduleFailCallback(obj IScheduleModel, reason string) { +func (self *GuestCreateBackupTask) OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) { // do nothing } diff --git a/pkg/compute/tasks/guest_batch_create_task.go b/pkg/compute/tasks/guest_batch_create_task.go index b67e9f7456..891d0ae4b3 100644 --- a/pkg/compute/tasks/guest_batch_create_task.go +++ b/pkg/compute/tasks/guest_batch_create_task.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestBatchCreateTask struct { @@ -24,8 +25,8 @@ func (self *GuestBatchCreateTask) OnInit(ctx context.Context, objs []db.IStandal StartScheduleObjects(ctx, self, objs) } -func (self *GuestBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) { - self.SSchedTask.OnScheduleFailCallback(obj, reason) +func (self *GuestBatchCreateTask) OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) { + self.SSchedTask.OnScheduleFailCallback(ctx, obj, reason) guest := obj.(*models.SGuest) if guest.DisableDelete.IsTrue() { guest.SetDisableDelete(false) @@ -38,18 +39,12 @@ func (self *GuestBatchCreateTask) SaveScheduleResultWithBackup(ctx context.Conte self.SaveScheduleResult(ctx, obj, master) } -func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string) { - var err error - guest := obj.(*models.SGuest) +func (self *GuestBatchCreateTask) allocateGuestOnHost(ctx context.Context, guest *models.SGuest) error { pendingUsage := models.SQuota{} - err = self.GetPendingUsage(&pendingUsage) + err := self.GetPendingUsage(&pendingUsage) if err != nil { log.Errorf("GetPendingUsage fail %s", err) } - if len(guest.HostId) == 0 { - guest.OnScheduleToHost(ctx, self.UserCred, hostId) - } - quotaCpuMem := models.SQuota{Cpu: int(guest.VcpuCount), Memory: guest.VmemSize} err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, "aCpuMem) self.SetPendingUsage(&pendingUsage) @@ -61,10 +56,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("host.SetGuestCreateNetworkAndDiskParams fail %s", err) guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error()) - return + return err } self.Params = params self.SaveParams(params) @@ -76,10 +68,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("Network failed: %s", err) guest.SetStatus(self.UserCred, models.VM_NETWORK_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_NETWORK_FAILED, err.Error()) - return + return err } guest.GetDriver().PrepareDiskRaidConfig(host, self.Params) @@ -89,10 +78,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("Disk create failed: %s", err) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, err.Error()) - return + return err } err = guest.CreateIsolatedDeviceOnHost(ctx, self.UserCred, host, self.Params, &pendingUsage) @@ -101,10 +87,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("IsolatedDevices create failed: %s", err) guest.SetStatus(self.UserCred, models.VM_DEVICE_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEVICE_FAILED, err.Error()) - return + return err } guest.JoinGroups(self.UserCred, self.Params) @@ -114,10 +97,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("start guest create task fail %s", err) guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error()) - return + return err } autoStart := jsonutils.QueryBoolean(self.Params, "auto_start", false) @@ -127,20 +107,33 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS if err != nil { log.Errorf("start guest create task fail %s", err) guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) - db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) - notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error()) - return + return err } - return + return nil } + err = guest.StartGuestCreateTask(ctx, self.UserCred, self.Params, nil, self.GetId()) if err != nil { log.Errorf("start guest create task fail %s", err) guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error()) - self.SetStageFailed(ctx, err.Error()) + return err + } + return nil +} + +func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string) { + var err error + guest := obj.(*models.SGuest) + if len(guest.HostId) == 0 { + guest.OnScheduleToHost(ctx, self.UserCred, hostId) + } + + err = self.allocateGuestOnHost(ctx, guest) + if err != nil { db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred) + logclient.AddActionLogWithStartable(self, obj, logclient.ACT_ALLOCATE, err.Error(), self.GetUserCred(), false) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error()) + self.SetStageFailed(ctx, err.Error()) } } diff --git a/pkg/compute/tasks/guest_live_migrate_task.go b/pkg/compute/tasks/guest_live_migrate_task.go index ad970302dc..2d2b88d2e5 100644 --- a/pkg/compute/tasks/guest_live_migrate_task.go +++ b/pkg/compute/tasks/guest_live_migrate_task.go @@ -48,7 +48,7 @@ func (self *GuestMigrateTask) OnStartSchedule(obj IScheduleModel) { db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, "", self.UserCred) } -func (self *GuestMigrateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) { +func (self *GuestMigrateTask) OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) { // do nothing } diff --git a/pkg/compute/tasks/schedule.go b/pkg/compute/tasks/schedule.go index 48c5588ae2..fc275ab941 100644 --- a/pkg/compute/tasks/schedule.go +++ b/pkg/compute/tasks/schedule.go @@ -17,6 +17,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/util/logclient" ) const ( @@ -38,7 +39,7 @@ type IScheduleTask interface { SetStageFailed(ctx context.Context, reason string) OnStartSchedule(obj IScheduleModel) - OnScheduleFailCallback(obj IScheduleModel, reason string) + OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) OnScheduleComplete(ctx context.Context, items []db.IStandaloneModel, data *jsonutils.JSONDict) SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string) SaveScheduleResultWithBackup(ctx context.Context, obj IScheduleModel, master, slave string) @@ -58,9 +59,10 @@ func (self *SSchedTask) OnStartSchedule(obj IScheduleModel) { obj.SetStatus(self.GetUserCred(), SCHEDULE, "") } -func (self *SSchedTask) OnScheduleFailCallback(obj IScheduleModel, reason string) { +func (self *SSchedTask) OnScheduleFailCallback(ctx context.Context, obj IScheduleModel, reason string) { obj.SetStatus(self.GetUserCred(), SCHEDULE_FAILED, reason) db.OpsLog.LogEvent(obj, db.ACT_ALLOCATE_FAIL, reason, self.GetUserCred()) + logclient.AddActionLogWithStartable(self, obj, logclient.ACT_ALLOCATE, reason, self.GetUserCred(), false) notifyclient.NotifySystemError(obj.GetId(), obj.GetName(), SCHEDULE_FAILED, reason) } @@ -153,7 +155,7 @@ func onObjScheduleFail( if len(msg) > 0 { reason = fmt.Sprintf("%s: %s", reason, msg) } - task.OnScheduleFailCallback(obj, reason) + task.OnScheduleFailCallback(ctx, obj, reason) } func onSchedulerResults( diff --git a/pkg/util/aliyun/shell/image.go b/pkg/util/aliyun/shell/image.go index b02ff69774..0c379dcb30 100644 --- a/pkg/util/aliyun/shell/image.go +++ b/pkg/util/aliyun/shell/image.go @@ -25,6 +25,18 @@ func init() { return nil }) + type ImageShowOptions struct { + ID string `help:"image ID"` + } + shellutils.R(&ImageShowOptions{}, "image-show", "Show image", func(cli *aliyun.SRegion, args *ImageShowOptions) error { + img, err := cli.GetImage(args.ID) + if err != nil { + return err + } + printObject(img) + return nil + }) + type ImageDeleteOptions struct { ID string `help:"ID or Name to delete"` } diff --git a/pkg/util/aliyun/storagecache.go b/pkg/util/aliyun/storagecache.go index 84ce8dc1c4..4be1250805 100644 --- a/pkg/util/aliyun/storagecache.go +++ b/pkg/util/aliyun/storagecache.go @@ -90,15 +90,12 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { } func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - parts, _, err := self.region.GetImages(ImageStatusType(""), "", []string{extId}, "", 0, 1) + img, err := self.region.GetImage(extId) if err != nil { return nil, err } - if len(parts) == 0 { - return nil, cloudprovider.ErrNotFound - } - parts[0].storageCache = self - return &parts[0], nil + img.storageCache = self + return img, nil } func (self *SStoragecache) GetPath() string {