From ebd7298d0d0d9d4da7cb61ca4e7059b3a0651ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Thu, 10 Jul 2025 19:37:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(region):=20=E4=BF=AE=E5=A4=8D=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=88=B0=E6=9C=9F=E9=87=8A=E6=94=BE=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=92=8C=E8=B5=84=E6=BA=90=E5=90=8C=E6=AD=A5=E5=86=B2=E7=AA=81?= =?UTF-8?q?=20(#22860)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/apis/compute/api.go | 4 + pkg/apis/compute/dbinstance.go | 4 +- pkg/apis/compute/elasticcache.go | 6 +- pkg/apis/compute/filesystem.go | 4 +- pkg/apis/compute/natgateway.go | 4 +- pkg/apis/input.go | 29 ++++- pkg/cloudcommon/db/opslog_const.go | 2 + pkg/compute/guestdrivers/base.go | 7 +- pkg/compute/guestdrivers/managedvirtual.go | 3 +- pkg/compute/models/billingresource.go | 119 ++++++++++++------ pkg/compute/models/dbinstances.go | 100 ++++----------- pkg/compute/models/disks.go | 50 +------- pkg/compute/models/elastic_search.go | 12 +- pkg/compute/models/elasticcache_instances.go | 109 ++++------------ pkg/compute/models/elasticips.go | 20 ++- pkg/compute/models/filesystem.go | 5 +- pkg/compute/models/guest_actions.go | 70 +++-------- pkg/compute/models/guestdrivers.go | 1 - pkg/compute/models/guests.go | 50 +++----- pkg/compute/models/kafka.go | 12 +- pkg/compute/models/modelarts_pools.go | 6 +- pkg/compute/models/mongodb.go | 68 +++------- pkg/compute/models/natgateways.go | 78 +++--------- pkg/compute/models/regiondrivers.go | 3 +- pkg/compute/regiondrivers/base.go | 5 +- pkg/compute/regiondrivers/managedvirtual.go | 16 ++- .../disk/disk_change_billing_type_task.go | 1 + .../elasticcache/elasticcache_renew_task.go | 24 ++-- pkg/compute/tasks/guest/guest_create_task.go | 2 +- pkg/compute/tasks/guest/guest_renew_task.go | 2 +- pkg/util/logclient/consts.go | 2 +- pkg/util/logclient/consts_i18n.go | 4 +- 32 files changed, 298 insertions(+), 524 deletions(-) diff --git a/pkg/apis/compute/api.go b/pkg/apis/compute/api.go index a2559815a0..c5b5396115 100644 --- a/pkg/apis/compute/api.go +++ b/pkg/apis/compute/api.go @@ -15,6 +15,8 @@ package compute import ( + "time" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/apis" @@ -648,6 +650,8 @@ type ServerCreateInput struct { BillingType string `json:"billing_type"` // swagger:ignore BillingCycle string `json:"billing_cycle"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` // swagger:ignore // Deprecated diff --git a/pkg/apis/compute/dbinstance.go b/pkg/apis/compute/dbinstance.go index 976a2820b7..a97f8fb1d7 100644 --- a/pkg/apis/compute/dbinstance.go +++ b/pkg/apis/compute/dbinstance.go @@ -82,8 +82,8 @@ type DBInstanceCreateInput struct { // default: false AutoRenew bool `json:"auto_renew"` - // swagger:ignore - ExpiredAt time.Time `json:"expired_at"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` // 计费方式 // enum: ["postpaid", "prepaid"] diff --git a/pkg/apis/compute/elasticcache.go b/pkg/apis/compute/elasticcache.go index 5c8f5d406d..234f5b4d4a 100644 --- a/pkg/apis/compute/elasticcache.go +++ b/pkg/apis/compute/elasticcache.go @@ -246,13 +246,13 @@ type ElasticcacheCreateInput struct { // 包年包月时间周期 Duration string `json:"duration"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` + // 是否自动续费(仅包年包月时生效) // default: false AutoRenew bool `json:"auto_renew"` - // swagger:ignore - ExpiredAt time.Time `json:"expired_at"` - // 计费方式 // enum: ["postpaid", "prepaid"] BillingType string diff --git a/pkg/apis/compute/filesystem.go b/pkg/apis/compute/filesystem.go index 7cb29f98ab..cb51bf02bb 100644 --- a/pkg/apis/compute/filesystem.go +++ b/pkg/apis/compute/filesystem.go @@ -87,8 +87,8 @@ type FileSystemCreateInput struct { // default: false AutoRenew bool `json:"auto_renew"` - // 到期释放时间,仅后付费支持 - ExpiredAt time.Time `json:"expired_at"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` // 计费方式 // enum: ["postpaid", "prepaid"] diff --git a/pkg/apis/compute/natgateway.go b/pkg/apis/compute/natgateway.go index f402e06f5a..a39f1efc9d 100644 --- a/pkg/apis/compute/natgateway.go +++ b/pkg/apis/compute/natgateway.go @@ -117,8 +117,8 @@ type NatgatewayCreateInput struct { // default: false AutoRenew bool `json:"auto_renew"` - // 到期释放时间,仅后付费支持 - ExpiredAt time.Time `json:"expired_at"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` // 计费方式 // enum: ["postpaid", "prepaid"] diff --git a/pkg/apis/input.go b/pkg/apis/input.go index 1901a486f6..d26fa535e5 100644 --- a/pkg/apis/input.go +++ b/pkg/apis/input.go @@ -14,7 +14,13 @@ package apis -import "time" +import ( + "time" + + "yunion.io/x/pkg/util/billing" + + "yunion.io/x/onecloud/pkg/httperrors" +) type DomainizedResourceInput struct { // 指定项目归属域名称或ID @@ -390,8 +396,25 @@ type DistinctFieldsInput struct { } type PostpaidExpireInput struct { - Duration string `json:"duration"` - ExpireTime time.Time `json:"expire_time"` + Duration string `json:"duration"` + // swagger:ignore + ExpireTime time.Time `json:"expire_time" yunion-deprecated-by:"release_at"` + // 到期释放时间 + ReleaseAt time.Time `json:"release_at"` +} + +func (input *PostpaidExpireInput) GetReleaseAt() (time.Time, error) { + if !input.ReleaseAt.IsZero() { + return input.ReleaseAt, nil + } + if len(input.Duration) == 0 { + return time.Time{}, httperrors.NewInputParameterError("missing duration/expire_time") + } + bc, err := billing.ParseBillingCycle(input.Duration) + if err != nil { + return time.Time{}, httperrors.NewInputParameterError("invalid duration: %s", input.Duration) + } + return bc.EndAt(time.Now()), nil } type AutoRenewInput struct { diff --git a/pkg/cloudcommon/db/opslog_const.go b/pkg/cloudcommon/db/opslog_const.go index 11d2ad0141..4d762bcff1 100644 --- a/pkg/cloudcommon/db/opslog_const.go +++ b/pkg/cloudcommon/db/opslog_const.go @@ -51,6 +51,8 @@ const ( ACT_BACKUP_START = "backup_start" ACT_BACKUP_START_FAILED = "backup_start_fail" + ACT_SET_RELEASE_TIME = "set_release_time" + ACT_FREEZE = "freeze" ACT_FREEZE_FAIL = "freeze_fail" ACT_UNFREEZE = "unfreeze" diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 6b5b2f257a..0fc7b4c5ea 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -78,7 +78,7 @@ func (drv *SBaseGuestDriver) OnGuestCreateTaskComplete(ctx context.Context, gues if len(duration) > 0 { bc, err := billing.ParseBillingCycle(duration) if err == nil && guest.ExpiredAt.IsZero() { - guest.SaveRenewInfo(ctx, task.GetUserCred(), &bc, nil, "") + models.SaveRenewInfo(ctx, task.GetUserCred(), guest, &bc, nil, "") } if jsonutils.QueryBoolean(task.GetParams(), "auto_prepaid_recycle", false) { err := guest.CanPerformPrepaidRecycle() @@ -395,11 +395,6 @@ func (drv *SBaseGuestDriver) RequestSyncSecgroupsOnHost(ctx context.Context, gue return nil // do nothing } -func (drv *SBaseGuestDriver) CancelExpireTime( - ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest) error { - return guest.CancelExpireTime(ctx, userCred) -} - func (drv *SBaseGuestDriver) IsSupportPublicipToEip() bool { return false } diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 3dea9e1d82..e5684d31f5 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -1040,6 +1040,7 @@ func (drv *SManagedVirtualizedGuestDriver) RequestChangeBillingType(ctx context. guest.BillingType = ivm.GetBillingType() guest.Status = ivm.GetStatus() guest.ExpiredAt = time.Time{} + guest.AutoRenew = false if guest.BillingType == billing_api.BILLING_TYPE_PREPAID { guest.AutoRenew = ivm.IsAutoRenew() guest.ExpiredAt = ivm.GetExpiredAt() @@ -1293,7 +1294,7 @@ func (drv *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx con exp, err := data.GetTime("expired_at") if err == nil && !guest.IsPrepaidRecycle() { - guest.SaveRenewInfo(ctx, task.GetUserCred(), nil, &exp, "") + models.SaveRenewInfo(ctx, task.GetUserCred(), guest, nil, &exp, "") } driver, _ := guest.GetDriver() diff --git a/pkg/compute/models/billingresource.go b/pkg/compute/models/billingresource.go index f8565b1645..88ed7233c0 100644 --- a/pkg/compute/models/billingresource.go +++ b/pkg/compute/models/billingresource.go @@ -26,17 +26,16 @@ import ( "yunion.io/x/pkg/util/billing" "yunion.io/x/sqlchemy" - "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/billing" billing_api "yunion.io/x/onecloud/pkg/apis/billing" notifyapi "yunion.io/x/onecloud/pkg/apis/notify" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules/notify" + "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) @@ -44,8 +43,10 @@ type SBillingResourceBase struct { // 计费类型, 按量、包年包月 // example: postpaid BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional" json:"billing_type"` - // 过期时间 - ExpiredAt time.Time `nullable:"true" list:"user" create:"optional" json:"expired_at"` + // 包年包月到期时间 + ExpiredAt time.Time `nullable:"true" list:"user" json:"expired_at"` + // 到期释放时间 + ReleaseAt time.Time `nullable:"true" list:"user" create:"optional" json:"release_at"` // 计费周期 BillingCycle string `width:"10" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"billing_cycle"` // 是否自动续费 @@ -62,10 +63,35 @@ func (self *SBillingResourceBase) GetChargeType() string { } } +func (self *SBillingResourceBase) SetReleaseAt(releaseAt time.Time) { + self.ReleaseAt = releaseAt +} + +func (self *SBillingResourceBase) GetExpiredAt() time.Time { + return self.ExpiredAt +} + +func (self *SBillingResourceBase) SetExpiredAt(expireAt time.Time) { + self.ExpiredAt = expireAt +} + +func (self *SBillingResourceBase) SetBillingCycle(billingCycle string) { + self.BillingCycle = billingCycle +} + +func (self *SBillingResourceBase) SetBillingType(billingType string) { + self.BillingType = billingType +} + +func (self *SBillingResourceBase) GetBillingType() string { + return self.BillingType +} + func (self *SBillingResourceBase) getBillingBaseInfo() SBillingBaseInfo { info := SBillingBaseInfo{} info.ChargeType = self.GetChargeType() info.ExpiredAt = self.ExpiredAt + info.ReleaseAt = self.ReleaseAt if self.GetChargeType() == api.BILLING_TYPE_PREPAID { info.BillingCycle = self.BillingCycle } @@ -93,7 +119,7 @@ func (self *SBillingResourceBase) IsValidPrePaid() bool { func (self *SBillingResourceBase) IsValidPostPaid() bool { if self.BillingType == api.BILLING_TYPE_POSTPAID { now := time.Now().UTC() - if self.ExpiredAt.After(now) { + if self.ReleaseAt.After(now) { return true } } @@ -103,6 +129,7 @@ func (self *SBillingResourceBase) IsValidPostPaid() bool { type SBillingBaseInfo struct { ChargeType string `json:",omitempty"` ExpiredAt time.Time `json:",omitempty"` + ReleaseAt time.Time `json:",omitempty"` BillingCycle string `json:",omitempty"` } @@ -170,43 +197,14 @@ func (manager *SBillingResourceBaseManager) OrderByExtraFields( func ListExpiredPostpaidResources( q *sqlchemy.SQuery, limit int) *sqlchemy.SQuery { q = q.Equals("billing_type", api.BILLING_TYPE_POSTPAID) - q = q.IsNotNull("expired_at") - q = q.LT("expired_at", time.Now()) + q = q.IsNotNull("release_at") + q = q.LT("release_at", time.Now()) if limit > 0 { q = q.Limit(limit) } return q } -func ParseBillingCycleInput(billingBase *SBillingResourceBase, input apis.PostpaidExpireInput) (*billing.SBillingCycle, error) { - var ( - bc billing.SBillingCycle - err error - durationStr string - ) - if len(input.Duration) == 0 { - if input.ExpireTime.IsZero() { - return nil, httperrors.NewInputParameterError("missing duration/expire_time") - } - timeC := billingBase.ExpiredAt - if timeC.IsZero() { - timeC = time.Now() - } - dur := input.ExpireTime.Sub(timeC) - if dur <= 0 { - return nil, httperrors.NewInputParameterError("expire time is before current expire at") - } - bc = billing.DurationToBillingCycle(dur) - } else { - bc, err = billing.ParseBillingCycle(durationStr) - if err != nil { - return nil, httperrors.NewInputParameterError("invalid duration %s: %s", durationStr, err) - } - } - - return &bc, nil -} - type SBillingResourceCheckManager struct { db.SResourceBaseManager } @@ -242,6 +240,55 @@ type IBillingModelManager interface { type IBillingModel interface { db.IModel GetExpiredAt() time.Time + SetReleaseAt(releaseAt time.Time) + SetExpiredAt(expireAt time.Time) + SetBillingCycle(billingCycle string) + SetBillingType(billingType string) + GetBillingType() string +} + +func SaveReleaseAt(ctx context.Context, model IBillingModel, userCred mcclient.TokenCredential, releaseAt time.Time) error { + diff, err := db.Update(model, func() error { + model.SetReleaseAt(releaseAt) + return nil + }) + if err != nil { + return errors.Wrap(err, "Update") + } + if len(diff) > 0 { + db.OpsLog.LogEvent(model, db.ACT_SET_RELEASE_TIME, fmt.Sprintf("release at: %s", releaseAt), userCred) + } + if len(diff) > 0 && userCred != nil { + logclient.AddActionLogWithContext(ctx, model, logclient.ACT_SET_RELEASE_TIME, diff, userCred, true) + } + return nil +} + +func SaveRenewInfo( + ctx context.Context, userCred mcclient.TokenCredential, + model IBillingModel, bc *billing.SBillingCycle, expireAt *time.Time, billingType string, +) error { + _, err := db.Update(model, func() error { + if billingType == "" { + billingType = billing_api.BILLING_TYPE_PREPAID + } + if model.GetBillingType() == "" { + model.SetBillingType(billingType) + } + if expireAt != nil && !expireAt.IsZero() { + model.SetExpiredAt(*expireAt) + } else if bc != nil { + model.SetBillingCycle(bc.String()) + model.SetExpiredAt(bc.EndAt(model.GetExpiredAt())) + } + return nil + }) + if err != nil { + log.Errorf("UpdateItem error %s", err) + return err + } + db.OpsLog.LogEvent(model, db.ACT_RENEW, model.GetShortDesc(ctx), userCred) + return nil } func fetchExpiredModels(manager db.IModelManager, advanceDay int) ([]IBillingModel, error) { diff --git a/pkg/compute/models/dbinstances.go b/pkg/compute/models/dbinstances.go index 6a4bff57be..e8a30a1ccd 100644 --- a/pkg/compute/models/dbinstances.go +++ b/pkg/compute/models/dbinstances.go @@ -405,9 +405,10 @@ func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred } } - tm := time.Time{} input.BillingCycle = billingCycle.String() - input.ExpiredAt = billingCycle.EndAt(tm) + if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { + input.ReleaseAt = billingCycle.EndAt(time.Now()) + } } for k, v := range map[string]string{ @@ -1133,33 +1134,6 @@ func (self *SDBInstance) StartDBInstanceRenewTask(ctx context.Context, userCred return nil } -func (self *SDBInstance) SaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bc *billing.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(self, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if self.BillingType == "" { - self.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - self.ExpiredAt = *expireAt - } else { - self.BillingCycle = bc.String() - self.ExpiredAt = bc.EndAt(self.ExpiredAt) - } - return nil - }) - if err != nil { - log.Errorf("Update error %s", err) - return err - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) - return nil -} - func (self *SDBInstance) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc := self.SVirtualResourceBase.GetShortDesc(ctx) region, _ := self.GetRegion() @@ -1722,10 +1696,6 @@ func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred m self.CreatedAt = createdAt } - if expiredAt := ext.GetExpiredAt(); !expiredAt.IsZero() { - self.ExpiredAt = expiredAt - } - if len(self.VpcId) == 0 { if vpcId := ext.GetIVpcId(); len(vpcId) > 0 { vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery { @@ -1751,19 +1721,13 @@ func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred m } } - factory, err := provider.GetProviderFactory() - if err != nil { - return errors.Wrap(err, "SyncWithCloudDBInstance.GetProviderFactory") - } - - if factory.IsSupportPrepaidResources() && !ext.GetExpiredAt().IsZero() { - self.BillingType = ext.GetBillingType() - if expired := ext.GetExpiredAt(); !expired.IsZero() { - self.ExpiredAt = expired - } + self.BillingType = ext.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false + if self.BillingType == billing_api.BILLING_TYPE_PREPAID { self.AutoRenew = ext.IsAutoRenew() + self.ExpiredAt = ext.GetExpiredAt() } - return nil }) if err != nil { @@ -1841,23 +1805,19 @@ func (manager *SDBInstanceManager) newFromCloudDBInstance(ctx context.Context, u instance.CreatedAt = createdAt } - factory, err := provider.GetProviderFactory() - if err != nil { - return nil, errors.Wrap(err, "newFromCloudDBInstance.GetProviderFactory") - } - - if factory.IsSupportPrepaidResources() { - instance.BillingType = extInstance.GetBillingType() - if expired := extInstance.GetExpiredAt(); !expired.IsZero() { - instance.ExpiredAt = expired - } + instance.BillingType = extInstance.GetBillingType() + instance.AutoRenew = false + instance.ExpiredAt = time.Time{} + if instance.BillingType == billing_api.BILLING_TYPE_PREPAID { instance.AutoRenew = extInstance.IsAutoRenew() + instance.ExpiredAt = extInstance.GetExpiredAt() } - err = func() error { + err := func() error { lockman.LockRawObject(ctx, manager.Keyword(), "name") defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name") + var err error instance.Name, err = db.GenerateName(ctx, manager, ownerId, extInstance.GetName()) if err != nil { return errors.Wrapf(err, "db.GenerateName") @@ -2063,41 +2023,27 @@ func (self *SDBInstance) PerformPostpaidExpire(ctx context.Context, userCred mcc return nil, httperrors.NewBadRequestError("dbinstance billing type is %s", self.BillingType) } - bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input) + releaseAt, err := input.GetReleaseAt() + if err != nil { + return nil, err + } + + err = SaveReleaseAt(ctx, self, userCred, releaseAt) if err != nil { return nil, err } - err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID) return nil, err } func (self *SDBInstance) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if err := self.CancelExpireTime(ctx, userCred); err != nil { + err := SaveReleaseAt(ctx, self, userCred, time.Time{}) + if err != nil { return nil, err } - return nil, nil } -func (self *SDBInstance) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return httperrors.NewBadRequestError("dbinstance billing type %s not support cancel expire", self.BillingType) - } - - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - DBInstanceManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "dbinstance cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "dbinstance cancel expire time", userCred) - return nil -} - func (self *SDBInstance) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DBInstanceRemoteUpdateInput) (jsonutils.JSONObject, error) { err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "") if err != nil { diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 170a3cd71e..f358e50434 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -28,7 +28,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" - "yunion.io/x/pkg/util/billing" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/fileutils" "yunion.io/x/pkg/util/pinyinutils" @@ -1852,13 +1851,13 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke if provider.GetFactory().IsSupportPrepaidResources() && !recycle { if billintType := extDisk.GetBillingType(); len(billintType) > 0 { self.BillingType = extDisk.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false if self.BillingType == billing_api.BILLING_TYPE_PREPAID { + self.ExpiredAt = extDisk.GetExpiredAt() self.AutoRenew = extDisk.IsAutoRenew() } } - if expiredAt := extDisk.GetExpiredAt(); !expiredAt.IsZero() { - self.ExpiredAt = extDisk.GetExpiredAt() - } } if createdAt := extDisk.GetCreatedAt(); !createdAt.IsZero() { @@ -3021,49 +3020,6 @@ func (self *SDisk) DeleteSnapshots(ctx context.Context, userCred mcclient.TokenC return nil } -func (self *SDisk) SaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bc *billing.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(self, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if self.BillingType == "" { - self.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - self.ExpiredAt = *expireAt - } else if bc != nil { - self.BillingCycle = bc.String() - self.ExpiredAt = bc.EndAt(self.ExpiredAt) - } - return nil - }) - if err != nil { - return errors.Wrapf(err, "SaveRenewInfo.Update") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) - return nil -} - -func (self *SDisk) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return fmt.Errorf("billing type %s not support cancel expire", self.BillingType) - } - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - DiskManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "disk cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "disk cancel expire time", userCred) - return nil -} - func (self *SDisk) IsDetachable() bool { storage, _ := self.GetStorage() if storage == nil { diff --git a/pkg/compute/models/elastic_search.go b/pkg/compute/models/elastic_search.go index ef166fb5d7..70c722a795 100644 --- a/pkg/compute/models/elastic_search.go +++ b/pkg/compute/models/elastic_search.go @@ -440,10 +440,10 @@ func (self *SElasticSearch) SyncWithCloudElasticSearch(ctx context.Context, user self.IsMultiAz = ext.IsMultiAz() self.BillingType = ext.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false if self.BillingType == billing_api.BILLING_TYPE_PREPAID { - if expiredAt := ext.GetExpiredAt(); !expiredAt.IsZero() { - self.ExpiredAt = expiredAt - } + self.ExpiredAt = ext.GetExpiredAt() self.AutoRenew = ext.IsAutoRenew() } @@ -586,10 +586,10 @@ func (self *SCloudregion) newFromCloudElasticSearch(ctx context.Context, userCre } es.BillingType = ext.GetBillingType() + es.ExpiredAt = time.Time{} + es.AutoRenew = false if es.BillingType == billing_api.BILLING_TYPE_PREPAID { - if expired := ext.GetExpiredAt(); !expired.IsZero() { - es.ExpiredAt = expired - } + es.ExpiredAt = ext.GetExpiredAt() es.AutoRenew = ext.IsAutoRenew() } diff --git a/pkg/compute/models/elasticcache_instances.go b/pkg/compute/models/elasticcache_instances.go index 1ac3f56a91..67fd780885 100644 --- a/pkg/compute/models/elasticcache_instances.go +++ b/pkg/compute/models/elasticcache_instances.go @@ -27,7 +27,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" - "yunion.io/x/pkg/util/billing" bc "yunion.io/x/pkg/util/billing" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/netutils" @@ -641,16 +640,11 @@ func (self *SElasticcache) SyncWithCloudElasticcache(ctx context.Context, userCr self.Connections = cnns } - factory, err := provider.GetProviderFactory() - if err != nil { - return errors.Wrap(err, "SyncWithCloudElasticcache.GetProviderFactory") - } - - if factory.IsSupportPrepaidResources() { - self.BillingType = extInstance.GetBillingType() - if expired := extInstance.GetExpiredAt(); !expired.IsZero() { - self.ExpiredAt = expired - } + self.BillingType = extInstance.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false + if self.BillingType == billing_api.BILLING_TYPE_PREPAID { + self.ExpiredAt = extInstance.GetExpiredAt() self.AutoRenew = extInstance.IsAutoRenew() } @@ -760,23 +754,19 @@ func (self *SCloudregion) newFromCloudElasticcache(ctx context.Context, userCred instance.CreatedAt = createdAt } - factory, err := provider.GetProviderFactory() - if err != nil { - return nil, errors.Wrap(err, "newFromCloudElasticcache.GetProviderFactory") - } - - if factory.IsSupportPrepaidResources() { - instance.BillingType = extInstance.GetBillingType() - if expired := extInstance.GetExpiredAt(); !expired.IsZero() { - instance.ExpiredAt = expired - } + instance.BillingType = extInstance.GetBillingType() + instance.ExpiredAt = time.Time{} + instance.AutoRenew = false + if instance.BillingType == billing_api.BILLING_TYPE_PREPAID { + instance.ExpiredAt = extInstance.GetExpiredAt() instance.AutoRenew = extInstance.IsAutoRenew() } - err = func() error { + err := func() error { lockman.LockRawObject(ctx, ElasticcacheManager.Keyword(), "name") defer lockman.ReleaseRawObject(ctx, ElasticcacheManager.Keyword(), "name") + var err error instance.Name, err = db.GenerateName(ctx, ElasticcacheManager, ownerId, extInstance.GetName()) if err != nil { return err @@ -883,25 +873,15 @@ func (manager *SElasticcacheManager) validateCreateData(ctx context.Context, use } } - // postpiad billing cycle - if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { - if len(input.Duration) > 0 { - cycle, err := bc.ParseBillingCycle(input.Duration) - if err != nil { - return nil, httperrors.NewInputParameterError("invalid duration %s", input.Duration) - } - - tm := time.Time{} - input.BillingCycle = cycle.String() - // .Format("2006-01-02 15:04:05") - input.ExpiredAt = cycle.EndAt(tm) - } - } else if input.BillingType == billing_api.BILLING_TYPE_PREPAID { - cycle, err := billing.ParseBillingCycle(input.BillingCycle) + if len(input.Duration) > 0 { + cycle, err := bc.ParseBillingCycle(input.Duration) if err != nil { - return nil, httperrors.NewInputParameterError("invalid billing_cycle %s", input.BillingCycle) + return nil, httperrors.NewInputParameterError("invalid duration %s", input.Duration) } input.BillingCycle = cycle.String() + if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { + input.ReleaseAt = cycle.EndAt(time.Now()) + } } // validate password @@ -1569,33 +1549,6 @@ func (manager *SElasticcacheManager) getExpiredPostpaids() []SElasticcache { return ecs } -func (cache *SElasticcache) SaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bcycle *bc.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(cache, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if cache.BillingType == "" { - cache.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - cache.ExpiredAt = *expireAt - } else if bcycle != nil { - cache.BillingCycle = bcycle.String() - cache.ExpiredAt = bcycle.EndAt(cache.ExpiredAt) - } - return nil - }) - if err != nil { - log.Errorf("Update error %s", err) - return err - } - db.OpsLog.LogEvent(cache, db.ACT_RENEW, cache.GetShortDesc(ctx), userCred) - return nil -} - func (cache *SElasticcache) SetDisableDelete(userCred mcclient.TokenCredential, val bool) error { diff, err := db.Update(cache, func() error { if val { @@ -1677,41 +1630,23 @@ func (self *SElasticcache) PerformPostpaidExpire(ctx context.Context, userCred m return nil, httperrors.NewBadRequestError("elasticcache billing type is %s", self.BillingType) } - bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input) + releaseAt, err := input.GetReleaseAt() if err != nil { return nil, err } - err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID) + err = SaveReleaseAt(ctx, self, userCred, releaseAt) return nil, err } func (self *SElasticcache) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if err := self.CancelExpireTime(ctx, userCred); err != nil { + err := SaveReleaseAt(ctx, self, userCred, time.Time{}) + if err != nil { return nil, err } - return nil, nil } -func (self *SElasticcache) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return httperrors.NewBadRequestError("elasticcache billing type %s not support cancel expire", self.BillingType) - } - - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - ElasticcacheManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "elasticcache cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "elasticcache cancel expire time", userCred) - return nil -} - func (self *SElasticcache) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheRemoteUpdateInput) (jsonutils.JSONObject, error) { err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "") if err != nil { diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index e6120f6e97..e2ef910f4b 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" "sort" + "time" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" @@ -33,6 +34,7 @@ import ( "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" + billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -599,12 +601,11 @@ func (self *SElasticip) SyncWithCloudEip(ctx context.Context, userCred mcclient. self.ChargeType = chargeType } - factory, _ := provider.GetProviderFactory() - if factory != nil && factory.IsSupportPrepaidResources() { - self.BillingType = ext.GetBillingType() - if expired := ext.GetExpiredAt(); !expired.IsZero() { - self.ExpiredAt = expired - } + self.BillingType = ext.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false + if self.BillingType == billing_api.BILLING_TYPE_PREPAID { + self.ExpiredAt = ext.GetExpiredAt() self.AutoRenew = ext.IsAutoRenew() } @@ -660,6 +661,13 @@ func (manager *SElasticipManager) newFromCloudEip(ctx context.Context, userCred if !extEip.GetCreatedAt().IsZero() { eip.CreatedAt = extEip.GetCreatedAt() } + eip.BillingType = extEip.GetBillingType() + eip.ExpiredAt = time.Time{} + eip.AutoRenew = false + if eip.BillingType == billing_api.BILLING_TYPE_PREPAID { + eip.ExpiredAt = extEip.GetExpiredAt() + eip.AutoRenew = extEip.IsAutoRenew() + } if len(eip.ChargeType) == 0 { eip.ChargeType = api.EIP_CHARGE_TYPE_BY_TRAFFIC } diff --git a/pkg/compute/models/filesystem.go b/pkg/compute/models/filesystem.go index 96f3bf0f3e..ae5668f5f1 100644 --- a/pkg/compute/models/filesystem.go +++ b/pkg/compute/models/filesystem.go @@ -187,9 +187,10 @@ func (man *SFileSystemManager) ValidateCreateData(ctx context.Context, userCred return input, httperrors.NewInputParameterError("unsupported duration %s", input.Duration) } } - tm := time.Time{} input.BillingCycle = billingCycle.String() - input.ExpiredAt = billingCycle.EndAt(tm) + if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { + input.ReleaseAt = billingCycle.EndAt(time.Now()) + } } input.SharableVirtualResourceCreateInput, err = man.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput) diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index f9f041bf2c..2d2c7d6e48 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -3349,7 +3349,8 @@ func (self *SGuest) DoCancelPendingDelete(ctx context.Context, userCred mcclient } if self.BillingType == billing_api.BILLING_TYPE_POSTPAID && !self.ExpiredAt.IsZero() { - if err := self.CancelExpireTime(ctx, userCred); err != nil { + err := SaveReleaseAt(ctx, self, userCred, time.Time{}) + if err != nil { return err } } @@ -4482,20 +4483,22 @@ func (self *SGuest) PerformCancelExpire(ctx context.Context, userCred mcclient.T if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { return nil, httperrors.NewBadRequestError("guest billing type %s not support cancel expire", self.BillingType) } - driver, err := self.GetDriver() + + err := SaveReleaseAt(ctx, self, userCred, time.Time{}) if err != nil { return nil, err } - if err := driver.CancelExpireTime(ctx, userCred, self); err != nil { - return nil, err - } + disks, err := self.GetDisks() if err != nil { return nil, err } for i := 0; i < len(disks); i += 1 { - if err := disks[i].CancelExpireTime(ctx, userCred); err != nil { - return nil, err + if disks[i].BillingType == billing_api.BILLING_TYPE_POSTPAID { + err := SaveReleaseAt(ctx, &disks[i], userCred, time.Time{}) + if err != nil { + return nil, err + } } } return nil, nil @@ -4516,16 +4519,15 @@ func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient return nil, httperrors.NewBadRequestError("guest %s unsupport postpaid expire", self.Hypervisor) } - bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input) + releaseAt, err := input.GetReleaseAt() if err != nil { return nil, err } - err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID) + err = SaveReleaseAt(ctx, self, userCred, releaseAt) if err != nil { return nil, err } - logclient.AddActionLogWithContext(ctx, self, logclient.ACT_SET_EXPIRED_TIME, input, userCred, true) return nil, nil } @@ -4589,7 +4591,7 @@ func (self *SGuest) SaveRenewInfo( ctx context.Context, userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time, billingType string, ) error { - err := self.doSaveRenewInfo(ctx, userCred, bc, expireAt, billingType) + err := SaveRenewInfo(ctx, userCred, self, bc, expireAt, billingType) if err != nil { return err } @@ -4599,7 +4601,7 @@ func (self *SGuest) SaveRenewInfo( } for i := 0; i < len(disks); i += 1 { if disks[i].AutoDelete { - err = disks[i].SaveRenewInfo(ctx, userCred, bc, expireAt, billingType) + err = SaveRenewInfo(ctx, userCred, &disks[i], bc, expireAt, billingType) if err != nil { return err } @@ -4608,50 +4610,6 @@ func (self *SGuest) SaveRenewInfo( return nil } -func (self *SGuest) doSaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bc *billing.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(self, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if self.BillingType == "" { - self.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - self.ExpiredAt = *expireAt - } else if bc != nil { - self.BillingCycle = bc.String() - self.ExpiredAt = bc.EndAt(self.ExpiredAt) - } - return nil - }) - if err != nil { - log.Errorf("UpdateItem error %s", err) - return err - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) - return nil -} - -func (self *SGuest) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return fmt.Errorf("billing type %s not support cancel expire", self.BillingType) - } - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - GuestManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "guest cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "guest cancel expire time", userCred) - return nil -} - func (self *SGuest) PerformStreamDisksComplete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { disks, err := self.GetDisks() if err != nil { diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 303c1f1fbc..79773a96fa 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -202,7 +202,6 @@ type IGuestDriver interface { GetUserDataType() string GetWindowsUserDataType() string IsWindowsUserDataTypeNeedEncode() bool - CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error IsSupportCdrom(guest *SGuest) (bool, error) IsSupportFloppy(guest *SGuest) (bool, error) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 027324e411..f285fd81f9 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1983,10 +1983,6 @@ func (manager *SGuestManager) validateCreateData( } if len(input.Duration) > 0 { - /*if !userCred.IsAllow(rbacutils.ScopeSystem, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionPerform, "renew") { - return nil, httperrors.NewForbiddenError("only admin can create prepaid resource") - }*/ - if input.ResourceType == api.HostResourceTypePrepaidRecycle { return nil, httperrors.NewConflictError("cannot create prepaid server on prepaid resource type") } @@ -2010,10 +2006,10 @@ func (manager *SGuestManager) validateCreateData( input.BillingType = billing_api.BILLING_TYPE_PREPAID } input.BillingCycle = billingCycle.String() - // expired_at will be set later by callback - // data.Add(jsonutils.NewTimeString(billingCycle.EndAt(time.Time{})), "expired_at") - input.Duration = billingCycle.String() + if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { + input.ReleaseAt = billingCycle.EndAt(time.Now()) + } } } @@ -3263,16 +3259,15 @@ func (g *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.TokenCre if len(extVM.GetDescription()) > 0 { g.Description = extVM.GetDescription() } - g.IsEmulated = extVM.IsEmulated() - if provider.GetFactory().IsSupportPrepaidResources() && !recycle { - g.BillingType = extVM.GetBillingType() + g.BillingType = extVM.GetBillingType() + g.ExpiredAt = time.Time{} + g.AutoRenew = false + if g.BillingType == billing_api.BILLING_TYPE_PREPAID { g.ExpiredAt = extVM.GetExpiredAt() - drv, _ := g.GetDriver() - if drv != nil && drv.IsSupportSetAutoRenew() { - g.AutoRenew = extVM.IsAutoRenew() - } + g.AutoRenew = extVM.IsAutoRenew() } + return nil }) if err != nil { @@ -3339,15 +3334,12 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient. guest.IsEmulated = extVM.IsEmulated() - if provider.GetFactory().IsSupportPrepaidResources() { - guest.BillingType = extVM.GetBillingType() - if expired := extVM.GetExpiredAt(); !expired.IsZero() { - guest.ExpiredAt = expired - } - drv, _ := guest.GetDriver() - if drv != nil && drv.IsSupportSetAutoRenew() { - guest.AutoRenew = extVM.IsAutoRenew() - } + guest.BillingType = extVM.GetBillingType() + guest.ExpiredAt = time.Time{} + guest.AutoRenew = false + if guest.BillingType == billing_api.BILLING_TYPE_PREPAID { + guest.ExpiredAt = extVM.GetExpiredAt() + guest.AutoRenew = extVM.IsAutoRenew() } if createdAt := extVM.GetCreatedAt(); !createdAt.IsZero() { @@ -3358,18 +3350,6 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient. instanceType := extVM.GetInstanceType() - /*zoneExtId, err := metaData.GetString("zone_ext_id") - if err != nil { - log.Errorf("get zone external id fail %s", err) - } - - isku, err := ServerSkuManager.FetchByZoneExtId(zoneExtId, instanceType) - if err != nil { - log.Errorf("get sku zone %s instance type %s fail %s", zoneExtId, instanceType, err) - } else { - guest.SkuId = isku.GetId() - }*/ - if len(instanceType) > 0 { guest.InstanceType = instanceType } diff --git a/pkg/compute/models/kafka.go b/pkg/compute/models/kafka.go index 4fba13269a..ac5ad71f52 100644 --- a/pkg/compute/models/kafka.go +++ b/pkg/compute/models/kafka.go @@ -437,10 +437,10 @@ func (self *SKafka) SyncWithCloudKafka(ctx context.Context, userCred mcclient.To self.IsMultiAz = ext.IsMultiAz() self.BillingType = ext.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false if self.BillingType == billing_api.BILLING_TYPE_PREPAID { - if expiredAt := ext.GetExpiredAt(); !expiredAt.IsZero() { - self.ExpiredAt = expiredAt - } + self.ExpiredAt = ext.GetExpiredAt() self.AutoRenew = ext.IsAutoRenew() } @@ -538,10 +538,10 @@ func (self *SCloudregion) newFromCloudKafka(ctx context.Context, userCred mcclie } kafka.BillingType = ext.GetBillingType() + kafka.ExpiredAt = time.Time{} + kafka.AutoRenew = false if kafka.BillingType == billing_api.BILLING_TYPE_PREPAID { - if expired := ext.GetExpiredAt(); !expired.IsZero() { - kafka.ExpiredAt = expired - } + kafka.ExpiredAt = ext.GetExpiredAt() kafka.AutoRenew = ext.IsAutoRenew() } diff --git a/pkg/compute/models/modelarts_pools.go b/pkg/compute/models/modelarts_pools.go index 492909eee1..c4e4ded19a 100644 --- a/pkg/compute/models/modelarts_pools.go +++ b/pkg/compute/models/modelarts_pools.go @@ -491,10 +491,10 @@ func (self *SCloudregion) newFromCloudModelartsPool(ctx context.Context, userCre pool.CpuArch = sku.CpuArch pool.BillingType = ext.GetBillingType() + pool.ExpiredAt = time.Time{} + pool.AutoRenew = false if pool.BillingType == billing_api.BILLING_TYPE_PREPAID { - if expired := ext.GetExpiredAt(); !expired.IsZero() { - pool.ExpiredAt = expired - } + pool.ExpiredAt = ext.GetExpiredAt() pool.AutoRenew = ext.IsAutoRenew() } diff --git a/pkg/compute/models/mongodb.go b/pkg/compute/models/mongodb.go index b16ea6c43b..3ac4c738b9 100644 --- a/pkg/compute/models/mongodb.go +++ b/pkg/compute/models/mongodb.go @@ -23,7 +23,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/billing" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/rbacscope" "yunion.io/x/sqlchemy" @@ -340,32 +339,6 @@ func (self *SMongoDB) SetAutoRenew(autoRenew bool) error { return err } -func (self *SMongoDB) SaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bc *billing.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(self, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if self.BillingType == "" { - self.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - self.ExpiredAt = *expireAt - } else { - self.BillingCycle = bc.String() - self.ExpiredAt = bc.EndAt(self.ExpiredAt) - } - return nil - }) - if err != nil { - return errors.Wrapf(err, "db.Update") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) - return nil -} - func (self *SMongoDB) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { log.Infof("mongodb delete do nothing") return nil @@ -526,6 +499,14 @@ func (self *SMongoDB) SyncWithCloudMongoDB(ctx context.Context, userCred mcclien self.MaxConnections = ext.GetMaxConnections() self.NetworkAddress = ext.GetNetworkAddress() + self.BillingType = ext.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false + if self.BillingType == billing_api.BILLING_TYPE_PREPAID { + self.ExpiredAt = ext.GetExpiredAt() + self.AutoRenew = ext.IsAutoRenew() + } + if vpcId := ext.GetVpcId(); len(vpcId) > 0 { vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery { return q.Equals("manager_id", self.ManagerId) @@ -616,11 +597,10 @@ func (self *SCloudregion) newFromCloudMongoDB(ctx context.Context, userCred mccl } ins.BillingType = ext.GetBillingType() + ins.ExpiredAt = time.Time{} + ins.AutoRenew = false if ins.BillingType == billing_api.BILLING_TYPE_PREPAID { - expiredAt := ext.GetExpiredAt() - if !expiredAt.IsZero() { - ins.ExpiredAt = expiredAt - } + ins.ExpiredAt = ext.GetExpiredAt() ins.AutoRenew = ext.IsAutoRenew() } @@ -782,41 +762,23 @@ func (self *SMongoDB) PerformPostpaidExpire(ctx context.Context, userCred mcclie return nil, httperrors.NewBadRequestError("self billing type is %s", self.BillingType) } - bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input) + releaseAt, err := input.GetReleaseAt() if err != nil { return nil, err } - err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID) + err = SaveReleaseAt(ctx, self, userCred, releaseAt) return nil, err } func (self *SMongoDB) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if err := self.CancelExpireTime(ctx, userCred); err != nil { + err := SaveReleaseAt(ctx, self, userCred, time.Time{}) + if err != nil { return nil, err } - return nil, nil } -func (self *SMongoDB) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return httperrors.NewBadRequestError("self billing type %s not support cancel expire", self.BillingType) - } - - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - MongoDBManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "self cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "self cancel expire time", userCred) - return nil -} - func (self *SMongoDB) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MongoDBRemoteUpdateInput) (jsonutils.JSONObject, error) { err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "") if err != nil { diff --git a/pkg/compute/models/natgateways.go b/pkg/compute/models/natgateways.go index a58aed8f8f..2abca8f077 100644 --- a/pkg/compute/models/natgateways.go +++ b/pkg/compute/models/natgateways.go @@ -186,9 +186,10 @@ func (man *SNatGatewayManager) ValidateCreateData( return input, httperrors.NewInputParameterError("unsupported duration %s", input.Duration) } } - tm := time.Time{} input.BillingCycle = billingCycle.String() - input.ExpiredAt = billingCycle.EndAt(tm) + if input.BillingType == billing_api.BILLING_TYPE_POSTPAID { + input.ReleaseAt = billingCycle.EndAt(time.Now()) + } } if len(input.Eip) > 0 || input.EipBw > 0 { if len(input.Eip) > 0 { @@ -521,12 +522,11 @@ func (self *SNatGateway) SyncWithCloudNatGateway(ctx context.Context, userCred m } } - factory, _ := provider.GetProviderFactory() - if factory.IsSupportPrepaidResources() { - self.BillingType = extNat.GetBillingType() - if expired := extNat.GetExpiredAt(); !expired.IsZero() { - self.ExpiredAt = expired - } + self.BillingType = extNat.GetBillingType() + self.ExpiredAt = time.Time{} + self.AutoRenew = false + if self.BillingType == billing_api.BILLING_TYPE_PREPAID { + self.ExpiredAt = extNat.GetExpiredAt() self.AutoRenew = extNat.IsAutoRenew() } @@ -566,14 +566,14 @@ func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, u nat.ExternalId = extNat.GetGlobalId() nat.IsEmulated = extNat.IsEmulated() - factory, _ := provider.GetProviderFactory() - if factory.IsSupportPrepaidResources() { - nat.BillingType = extNat.GetBillingType() - if expired := extNat.GetExpiredAt(); !expired.IsZero() { - nat.ExpiredAt = expired - } + nat.BillingType = extNat.GetBillingType() + nat.ExpiredAt = time.Time{} + nat.AutoRenew = false + if nat.BillingType == billing_api.BILLING_TYPE_PREPAID { + nat.ExpiredAt = extNat.GetExpiredAt() nat.AutoRenew = extNat.IsAutoRenew() } + if networId := extNat.GetINetworkId(); len(networId) > 0 { _network, err := db.FetchByExternalIdAndManagerId(NetworkManager, networId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery { sq := WireManager.Query("id").Equals("vpc_id", vpc.Id).SubQuery() @@ -892,25 +892,7 @@ func (manager *SNatEntryManager) FetchCustomizeColumns( } func (self *SNatGateway) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return nil, self.CancelExpireTime(ctx, userCred) -} - -func (self *SNatGateway) CancelExpireTime(ctx context.Context, userCred mcclient.TokenCredential) error { - if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { - return httperrors.NewBadRequestError("nat billing type %s not support cancel expire", self.BillingType) - } - - _, err := sqlchemy.GetDB().Exec( - fmt.Sprintf( - "update %s set expired_at = NULL and billing_cycle = NULL where id = ?", - NatGatewayManager.TableSpec().Name(), - ), self.Id, - ) - if err != nil { - return errors.Wrap(err, "nat cancel expire time") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, "nat cancel expire time", userCred) - return nil + return nil, SaveReleaseAt(ctx, self, userCred, time.Time{}) } func (self *SNatGateway) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) { @@ -918,41 +900,15 @@ func (self *SNatGateway) PerformPostpaidExpire(ctx context.Context, userCred mcc return nil, httperrors.NewBadRequestError("nat gateway billing type is %s", self.BillingType) } - bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input) + releaseAt, err := input.GetReleaseAt() if err != nil { return nil, err } - err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID) + err = SaveReleaseAt(ctx, self, userCred, releaseAt) return nil, err } -func (self *SNatGateway) SaveRenewInfo( - ctx context.Context, userCred mcclient.TokenCredential, - bc *billing.SBillingCycle, expireAt *time.Time, billingType string, -) error { - _, err := db.Update(self, func() error { - if billingType == "" { - billingType = billing_api.BILLING_TYPE_PREPAID - } - if self.BillingType == "" { - self.BillingType = billingType - } - if expireAt != nil && !expireAt.IsZero() { - self.ExpiredAt = *expireAt - } else { - self.BillingCycle = bc.String() - self.ExpiredAt = bc.EndAt(self.ExpiredAt) - } - return nil - }) - if err != nil { - return errors.Wrapf(err, "db.Update") - } - db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) - return nil -} - func (self *SNatGateway) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.RenewInput) (jsonutils.JSONObject, error) { if !utils.IsInStringArray(self.Status, []string{api.NAT_STAUTS_AVAILABLE}) { return nil, httperrors.NewInvalidStatusError("Cannot do renew nat gateway in status %s required status %s", self.Status, api.NAT_SKU_AVAILABLE) diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 5ef67fc48a..c03318939c 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -16,7 +16,6 @@ package models import ( "context" - "time" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" @@ -237,7 +236,7 @@ type IElasticcacheDriver interface { RequestCreateElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAccount *SElasticcacheAccount, task taskman.ITask) error RequestCreateElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAcl *SElasticcacheAcl, task taskman.ITask) error RequestCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheBackup *SElasticcacheBackup, task taskman.ITask) error - RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, bc billing.SBillingCycle) (time.Time, error) + RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, bc billing.SBillingCycle) error RequestElasticcacheSetAutoRenew(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, autoRenew bool, task taskman.ITask) error RequestRestartElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error RequestSyncElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index 574e3ab257..2af516e50b 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -17,7 +17,6 @@ package regiondrivers import ( "context" "fmt" - "time" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" @@ -358,8 +357,8 @@ func (self *SBaseRegionDriver) GetRdsSupportSecgroupCount() int { return 0 } -func (self *SBaseRegionDriver) RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SElasticcache, bc billing.SBillingCycle) (time.Time, error) { - return time.Time{}, fmt.Errorf("Not Implement RequestRenewElasticcache") +func (self *SBaseRegionDriver) RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SElasticcache, bc billing.SBillingCycle) error { + return errors.Wrapf(cloudprovider.ErrNotImplemented, "RequestRenewElasticcache") } func (self *SBaseRegionDriver) IsSupportedElasticcacheAutoRenew() bool { diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 15b4075367..2c6f0b3d26 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -2843,25 +2843,25 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecgroupsForElasticca return nil } -func (self *SManagedVirtualizationRegionDriver) RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, bc billing.SBillingCycle) (time.Time, error) { +func (self *SManagedVirtualizationRegionDriver) RequestRenewElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, bc billing.SBillingCycle) error { iregion, err := ec.GetIRegion(ctx) if err != nil { - return time.Time{}, errors.Wrap(err, "GetIRegion") + return errors.Wrap(err, "GetIRegion") } if len(ec.GetExternalId()) == 0 { - return time.Time{}, errors.Wrap(err, "ExternalId is empty") + return errors.Wrap(err, "ExternalId is empty") } iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) if err != nil { - return time.Time{}, errors.Wrap(err, "GetIElasticcacheById") + return errors.Wrap(err, "GetIElasticcacheById") } oldExpired := iec.GetExpiredAt() err = iec.Renew(bc) if err != nil { - return time.Time{}, err + return err } //避免有些云续费后过期时间刷新比较慢问题 cloudprovider.WaitCreated(15*time.Second, 5*time.Minute, func() bool { @@ -2875,7 +2875,11 @@ func (self *SManagedVirtualizationRegionDriver) RequestRenewElasticcache(ctx con } return false }) - return iec.GetExpiredAt(), nil + db.Update(ec, func() error { + ec.ExpiredAt = iec.GetExpiredAt() + return nil + }) + return nil } func (self *SManagedVirtualizationRegionDriver) IsSupportedElasticcacheAutoRenew() bool { diff --git a/pkg/compute/tasks/disk/disk_change_billing_type_task.go b/pkg/compute/tasks/disk/disk_change_billing_type_task.go index 9ff88b9344..619c9262f2 100644 --- a/pkg/compute/tasks/disk/disk_change_billing_type_task.go +++ b/pkg/compute/tasks/disk/disk_change_billing_type_task.go @@ -72,6 +72,7 @@ func (self *DiskChangeBillingTypeTask) OnInit(ctx context.Context, obj db.IStand db.Update(disk, func() error { disk.BillingType = billType disk.ExpiredAt = time.Time{} + disk.AutoRenew = false if disk.BillingType == billing_api.BILLING_TYPE_PREPAID { disk.AutoRenew = idisk.IsAutoRenew() disk.ExpiredAt = idisk.GetExpiredAt() diff --git a/pkg/compute/tasks/elasticcache/elasticcache_renew_task.go b/pkg/compute/tasks/elasticcache/elasticcache_renew_task.go index 3e111dfad1..116a8fc843 100644 --- a/pkg/compute/tasks/elasticcache/elasticcache_renew_task.go +++ b/pkg/compute/tasks/elasticcache/elasticcache_renew_task.go @@ -16,10 +16,8 @@ package elasticcache import ( "context" - "fmt" "yunion.io/x/jsonutils" - "yunion.io/x/log" "yunion.io/x/pkg/util/billing" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -37,27 +35,27 @@ func init() { taskman.RegisterTask(ElasticcacheRenewTask{}) } +func (self *ElasticcacheRenewTask) taskFail(ctx context.Context, cache *models.SElasticcache, err error) { + db.OpsLog.LogEvent(cache, db.ACT_REW_FAIL, err, self.UserCred) + logclient.AddActionLogWithStartable(self, cache, logclient.ACT_RENEW, err, self.UserCred, false) + cache.SetStatus(ctx, self.GetUserCred(), api.ELASTIC_CACHE_RENEW_FAILED, err.Error()) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + func (self *ElasticcacheRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { instance := obj.(*models.SElasticcache) durationStr, _ := self.GetParams().GetString("duration") bc, _ := billing.ParseBillingCycle(durationStr) - region, _ := instance.GetRegion() - exp, err := region.GetDriver().RequestRenewElasticcache(ctx, self.UserCred, instance, bc) + region, err := instance.GetRegion() if err != nil { - db.OpsLog.LogEvent(instance, db.ACT_REW_FAIL, err, self.UserCred) - logclient.AddActionLogWithStartable(self, instance, logclient.ACT_RENEW, err, self.UserCred, false) - instance.SetStatus(ctx, self.GetUserCred(), api.ELASTIC_CACHE_RENEW_FAILED, err.Error()) - self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) + self.taskFail(ctx, instance, err) return } - - err = instance.SaveRenewInfo(ctx, self.UserCred, &bc, &exp, "") + err = region.GetDriver().RequestRenewElasticcache(ctx, self.UserCred, instance, bc) if err != nil { - msg := fmt.Sprintf("SaveRenewInfo fail %s", err) - log.Errorf(msg) - self.SetStageFailed(ctx, jsonutils.NewString(msg)) + self.taskFail(ctx, instance, err) return } diff --git a/pkg/compute/tasks/guest/guest_create_task.go b/pkg/compute/tasks/guest/guest_create_task.go index 7665bd92db..c2df841342 100644 --- a/pkg/compute/tasks/guest/guest_create_task.go +++ b/pkg/compute/tasks/guest/guest_create_task.go @@ -266,7 +266,7 @@ func (self *GuestCreateTask) OnDeployEipComplete(ctx context.Context, obj db.ISt if len(duration) > 0 { bc, err := billing.ParseBillingCycle(duration) if err == nil && guest.ExpiredAt.IsZero() { - guest.SaveRenewInfo(ctx, self.GetUserCred(), &bc, nil, "") + models.SaveRenewInfo(ctx, self.GetUserCred(), guest, &bc, nil, "") } if jsonutils.QueryBoolean(self.GetParams(), "auto_prepaid_recycle", false) { err := guest.CanPerformPrepaidRecycle() diff --git a/pkg/compute/tasks/guest/guest_renew_task.go b/pkg/compute/tasks/guest/guest_renew_task.go index 9e04db41a4..94b3565ac9 100644 --- a/pkg/compute/tasks/guest/guest_renew_task.go +++ b/pkg/compute/tasks/guest/guest_renew_task.go @@ -65,7 +65,7 @@ func (self *GuestRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, return } - err = guest.SaveRenewInfo(ctx, self.UserCred, &bc, &exp, "") + err = models.SaveRenewInfo(ctx, self.UserCred, guest, &bc, &exp, "") if err != nil { msg := fmt.Sprintf("SaveRenewInfo fail %s", err) log.Errorf(msg) diff --git a/pkg/util/logclient/consts.go b/pkg/util/logclient/consts.go index 11772762f6..6d1b5019b5 100644 --- a/pkg/util/logclient/consts.go +++ b/pkg/util/logclient/consts.go @@ -113,7 +113,7 @@ const ( ACT_UNFREEZE = "unfreeze" ACT_CHANGE_BILLING_TYPE = "change_billing_type" // 到期释放 - ACT_SET_EXPIRED_TIME = "set_expired_time" + ACT_SET_RELEASE_TIME = "set_release_time" ACT_VM_SYNC_ISOLATED_DEVICE = "vm_sync_isolated_device" ACT_CACHED_IMAGE = "cached_image" diff --git a/pkg/util/logclient/consts_i18n.go b/pkg/util/logclient/consts_i18n.go index 37ba442d31..937c17d582 100644 --- a/pkg/util/logclient/consts_i18n.go +++ b/pkg/util/logclient/consts_i18n.go @@ -104,8 +104,8 @@ func init() { EN("Guest Detach Isolated Device"). CN("卸载透传设备"), ) - t.Set(ACT_SET_EXPIRED_TIME, i18n.NewTableEntry(). - EN("Set Resource Expire Time"). + t.Set(ACT_SET_RELEASE_TIME, i18n.NewTableEntry(). + EN("Set Resource Release Time"). CN("到期释放"), ) t.Set(ACT_VM_SYNC_ISOLATED_DEVICE, i18n.NewTableEntry().