diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 4cad079cb4..9357b970f7 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -60,7 +60,7 @@ func (self *SBaseGuestDriver) OnGuestCreateTaskComplete(ctx context.Context, gue if len(duration) > 0 { bc, err := billing.ParseBillingCycle(duration) if err == nil && guest.ExpiredAt.IsZero() { - guest.SaveRenewInfo(ctx, task.GetUserCred(), &bc, nil) + guest.SaveRenewInfo(ctx, task.GetUserCred(), &bc, nil, "") } if jsonutils.QueryBoolean(task.GetParams(), "auto_prepaid_recycle", false) { err := guest.CanPerformPrepaidRecycle() diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 62e614fffd..7f99dcf8f0 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -918,7 +918,7 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co exp, err := data.GetTime("expired_at") if err == nil && !guest.IsPrepaidRecycle() { - guest.SaveRenewInfo(ctx, task.GetUserCred(), nil, &exp) + guest.SaveRenewInfo(ctx, task.GetUserCred(), nil, &exp, "") } guest.SaveDeployInfo(ctx, task.GetUserCred(), data) diff --git a/pkg/compute/models/dbinstances.go b/pkg/compute/models/dbinstances.go index 95346f190d..e2aa9b01ce 100644 --- a/pkg/compute/models/dbinstances.go +++ b/pkg/compute/models/dbinstances.go @@ -770,11 +770,15 @@ 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) error { +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 self.BillingType != billing_api.BILLING_TYPE_PREPAID { - self.BillingType = billing_api.BILLING_TYPE_PREPAID + if billingType == "" { + billingType = billing_api.BILLING_TYPE_PREPAID } + self.BillingType = billingType if expireAt != nil && !expireAt.IsZero() { self.ExpiredAt = *expireAt } else { diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 055a7bad70..25c5e89971 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -2170,11 +2170,15 @@ 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) error { +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 self.BillingType != billing_api.BILLING_TYPE_PREPAID { - self.BillingType = billing_api.BILLING_TYPE_PREPAID + if billingType == "" { + billingType = billing_api.BILLING_TYPE_PREPAID } + self.BillingType = billingType if expireAt != nil && !expireAt.IsZero() { self.ExpiredAt = *expireAt } else if bc != nil { @@ -2191,6 +2195,23 @@ func (self *SDisk) SaveRenewInfo(ctx context.Context, userCred mcclient.TokenCre 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/guest_actions.go b/pkg/compute/models/guest_actions.go index 4983c35b85..34c17dfcfb 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -3413,8 +3413,17 @@ 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) } - err := self.GetDriver().CancelExpireTime(ctx, userCred, self) - return nil, err + if err := self.GetDriver().CancelExpireTime(ctx, userCred, self); err != nil { + return nil, err + } + guestdisks := self.GetDisks() + for i := 0; i < len(guestdisks); i += 1 { + disk := guestdisks[i].GetDisk() + if err := disk.CancelExpireTime(ctx, userCred); err != nil { + return nil, err + } + } + return nil, nil } func (self *SGuest) AllowPerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -3422,6 +3431,10 @@ func (self *SGuest) AllowPerformPostpaidExpire(ctx context.Context, userCred mcc } func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.BillingType != billing_api.BILLING_TYPE_POSTPAID { + return nil, httperrors.NewBadRequestError("guest billing type is %s", self.BillingType) + } + durationStr := jsonutils.GetAnyString(data, []string{"duration"}) if len(durationStr) == 0 { return nil, httperrors.NewInputParameterError("missong duration") @@ -3436,7 +3449,7 @@ func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient return nil, httperrors.NewBadRequestError("guest %s unsupport postpaid expire", self.Hypervisor) } - err = self.SaveRenewInfo(ctx, userCred, &bc, nil) + err = self.SaveRenewInfo(ctx, userCred, &bc, nil, billing_api.BILLING_TYPE_POSTPAID) return nil, err } @@ -3480,15 +3493,18 @@ func (self *SGuest) startGuestRenewTask(ctx context.Context, userCred mcclient.T return nil } -func (self *SGuest) SaveRenewInfo(ctx context.Context, userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error { - err := self.doSaveRenewInfo(ctx, userCred, bc, expireAt) +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) if err != nil { return err } guestdisks := self.GetDisks() for i := 0; i < len(guestdisks); i += 1 { disk := guestdisks[i].GetDisk() - err = disk.SaveRenewInfo(ctx, userCred, bc, expireAt) + err = disk.SaveRenewInfo(ctx, userCred, bc, expireAt, billingType) if err != nil { return err } @@ -3496,11 +3512,15 @@ func (self *SGuest) SaveRenewInfo(ctx context.Context, userCred mcclient.TokenCr return nil } -func (self *SGuest) doSaveRenewInfo(ctx context.Context, userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error { +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 len(self.BillingType) == 0 { - self.BillingType = billing_api.BILLING_TYPE_PREPAID + if billingType == "" { + billingType = billing_api.BILLING_TYPE_PREPAID } + self.BillingType = billingType if expireAt != nil && !expireAt.IsZero() { self.ExpiredAt = *expireAt } else { diff --git a/pkg/compute/tasks/dbinstance_renew_task.go b/pkg/compute/tasks/dbinstance_renew_task.go index 7a830d9927..8b7f626686 100644 --- a/pkg/compute/tasks/dbinstance_renew_task.go +++ b/pkg/compute/tasks/dbinstance_renew_task.go @@ -54,7 +54,7 @@ func (self *DBInstanceRenewTask) OnInit(ctx context.Context, obj db.IStandaloneM return } - err = instance.SaveRenewInfo(ctx, self.UserCred, &bc, &exp) + err = instance.SaveRenewInfo(ctx, self.UserCred, &bc, &exp, "") if err != nil { msg := fmt.Sprintf("SaveRenewInfo fail %s", err) log.Errorf(msg) diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index 21941b4390..fff6bfc3ea 100644 --- a/pkg/compute/tasks/guest_create_task.go +++ b/pkg/compute/tasks/guest_create_task.go @@ -168,7 +168,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) + guest.SaveRenewInfo(ctx, self.GetUserCred(), &bc, nil, "") } if jsonutils.QueryBoolean(self.GetParams(), "auto_prepaid_recycle", false) { err := guest.CanPerformPrepaidRecycle() diff --git a/pkg/compute/tasks/guest_renew_task.go b/pkg/compute/tasks/guest_renew_task.go index eadce8892f..4fd3b1d07b 100644 --- a/pkg/compute/tasks/guest_renew_task.go +++ b/pkg/compute/tasks/guest_renew_task.go @@ -55,7 +55,7 @@ func (self *GuestRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, return } - err = guest.SaveRenewInfo(ctx, self.UserCred, &bc, &exp) + err = guest.SaveRenewInfo(ctx, self.UserCred, &bc, &exp, "") if err != nil { msg := fmt.Sprintf("SaveRenewInfo fail %s", err) log.Errorf(msg)