增加:1.

包年包月主机加入资源池后,如果auto_delete=true,则自动删除该主机 2.
包年包月资源池的宿主机支持续费操作Perform(host.id,
"renew-prepaid-recycle", {"duration": "1m"})
This commit is contained in:
Qiu Jian
2019-01-05 09:51:58 +08:00
parent 16a7306746
commit c477a05f39
11 changed files with 154 additions and 12 deletions

View File

@@ -497,4 +497,19 @@ func init() {
printObject(result)
return nil
})
type PrepaidRecycleHostRenewOptions struct {
ID string `help:"ID or name of server to renew"`
DURATION string `help:"Duration of renew, ADMIN only command"`
}
R(&PrepaidRecycleHostRenewOptions{}, "host-renew-prepaid-recycle", "Renew a prepaid recycle host", func(s *mcclient.ClientSession, args *PrepaidRecycleHostRenewOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.DURATION), "duration")
result, err := modules.Hosts.PerformAction(s, args.ID, "renew-prepaid-recycle", params)
if err != nil {
return err
}
printObject(result)
return nil
})
}

View File

@@ -634,10 +634,14 @@ func init() {
})
type ServerPrepaidRecycleOptions struct {
ID string `help:"ID or name of server to recycle"`
ID string `help:"ID or name of server to recycle"`
AutoDelete bool `help:"after joining the pool, remove the server automatically"`
}
R(&ServerPrepaidRecycleOptions{}, "server-enable-recycle", "Put a prepaid server into recycle pool, so that it can be shared", func(s *mcclient.ClientSession, args *ServerPrepaidRecycleOptions) error {
params := jsonutils.NewDict()
if args.AutoDelete {
params.Add(jsonutils.JSONTrue, "auto_delete")
}
result, err := modules.Servers.PerformAction(s, args.ID, "prepaid-recycle", params)
if err != nil {
return err

View File

@@ -3429,7 +3429,8 @@ func (manager *SGuestManager) DeleteExpiredPrepaidServers(ctx context.Context, u
return
}
for i := 0; i < len(guests); i += 1 {
guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true)
// fake delete expired prepaid servers
guests[i].StartDeleteGuestTask(ctx, userCred, "", false, false)
}
}

View File

@@ -15,10 +15,12 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -65,6 +67,10 @@ func (self *SGuest) PerformPrepaidRecycle(ctx context.Context, userCred mcclient
db.OpsLog.LogEvent(self, db.ACT_RECYCLE_PREPAID, self.GetShortDesc(ctx), userCred)
logclient.AddActionLog(self, logclient.ACT_RECYCLE_PREPAID, self.GetShortDesc(ctx), userCred, true)
autoDelete := jsonutils.QueryBoolean(data, "auto_delete", false)
if autoDelete {
self.StartDeleteGuestTask(ctx, userCred, "", false, true)
}
return nil, nil
}
@@ -656,3 +662,63 @@ func (manager *SHostManager) GetHostByRealExternalId(eid string) *SHost {
return &host
}
func (self *SHost) AllowPerformRenewPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "renew-prepaid-recycle")
}
func (self *SHost) PerformRenewPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
durationStr := jsonutils.GetAnyString(data, []string{"duration"})
if len(durationStr) == 0 {
return nil, httperrors.NewInputParameterError("missing duration")
}
bc, err := billing.ParseBillingCycle(durationStr)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid duration %s: %s", durationStr, err)
}
if !GetDriver(HOSTTYPE_HYPERVISOR[self.HostType]).IsSupportedBillingCycle(bc) {
return nil, httperrors.NewInputParameterError("unsupported duration %s", durationStr)
}
err = self.startPrepaidRecycleHostRenewTask(ctx, userCred, durationStr, "")
if err != nil {
return nil, err
}
return nil, nil
}
func (self *SHost) startPrepaidRecycleHostRenewTask(ctx context.Context, userCred mcclient.TokenCredential, duration string, parentTaskId string) error {
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(duration), "duration")
task, err := taskman.TaskManager.NewTask(ctx, "PrepaidRecycleHostRenewTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
log.Errorf("fail to crate GuestRenewTask %s", err)
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SHost) DoSaveRenewInfo(ctx context.Context, userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
if self.BillingType != BILLING_TYPE_PREPAID {
self.BillingType = BILLING_TYPE_PREPAID
}
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
}

View File

@@ -138,11 +138,11 @@ type SHost struct {
CpuMhz int `nullable:"true" get:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # cpu MHz
CpuCache int `nullable:"true" get:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # cpu Cache in KB
CpuReserved int8 `nullable:"true" default:"0" list:"admin" update:"admin" create:"admin_optional"` // Column(TINYINT, nullable=True, default=0)
CpuCmtbound float32 `nullable:"true" default:"8.0" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True)
CpuCmtbound float32 `nullable:"true" default:"8" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True)
MemSize int `nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # memory size in MB
MemReserved int `nullable:"true" default:"0" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True, default=0) # memory reserved in MB
MemCmtbound float32 `nullable:"true" default:"1.0" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True)
MemCmtbound float32 `nullable:"true" default:"1" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True)
StorageSize int `nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # storage size in MB
StorageType string `width:"20" charset:"ascii" nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(VARCHAR(20, charset='ascii'), nullable=True)

View File

@@ -120,7 +120,7 @@ type SStorage struct {
Reserved int `nullable:"true" default:"0" list:"admin" update:"admin"` // Column(Integer, nullable=True, default=0)
StorageType string `width:"32" charset:"ascii" nullable:"false" list:"user" update:"admin" create:"admin_required"` // Column(VARCHAR(32, charset='ascii'), nullable=False)
MediumType string `width:"32" charset:"ascii" nullable:"false" list:"user" update:"admin" create:"admin_required"` // Column(VARCHAR(32, charset='ascii'), nullable=False)
Cmtbound float32 `nullable:"true" default:"1.0" list:"admin" update:"admin"` // Column(Float, nullable=True)
Cmtbound float32 `nullable:"true" default:"1" list:"admin" update:"admin"` // Column(Float, nullable=True)
StorageConf jsonutils.JSONObject `nullable:"true" get:"admin" update:"admin"` // = Column(JSONEncodedDict, nullable=True)
ZoneId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"admin_required"`

View File

@@ -153,8 +153,9 @@ func (self *GuestDeleteTask) OnSyncConfigComplete(ctx context.Context, obj db.IS
}
func (self *GuestDeleteTask) OnSyncConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
self.OnFailed(ctx, guest, err)
// guest := obj.(*models.SGuest)
// self.OnFailed(ctx, guest, err)
self.OnSyncConfigComplete(ctx, obj, err) // ignore sync config failed error
}
func (self *GuestDeleteTask) OnGuestDeleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {

View File

@@ -19,6 +19,7 @@ type GuestRenewTask struct {
func init() {
taskman.RegisterTask(GuestRenewTask{})
taskman.RegisterTask(PrepaidRecycleHostRenewTask{})
}
func (self *GuestRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
@@ -45,3 +46,50 @@ func (self *GuestRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel,
self.SetStageComplete(ctx, nil)
}
type PrepaidRecycleHostRenewTask struct {
taskman.STask
}
func (self *PrepaidRecycleHostRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
host := obj.(*models.SHost)
durationStr, _ := self.GetParams().GetString("duration")
bc, _ := billing.ParseBillingCycle(durationStr)
ihost, err := host.GetIHost()
if err != nil {
msg := fmt.Sprintf("host.GetIHost fail %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
iVM, err := ihost.GetIVMById(host.RealExternalId)
if err != nil {
msg := fmt.Sprintf("ihost.GetIVMById fail %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
err = iVM.Renew(bc)
if err != nil {
msg := fmt.Sprintf("iVM.Renew fail %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
exp := iVM.GetExpiredAt()
err = host.DoSaveRenewInfo(ctx, self.UserCred, &bc, &exp)
if err != nil {
msg := fmt.Sprintf("SaveRenewInfo fail %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
self.SetStageComplete(ctx, nil)
}

View File

@@ -83,7 +83,7 @@ func _jsonRequest(client *sdk.Client, domain string, version string, apiName str
resp, err := processCommonRequest(client, req)
if err != nil {
log.Errorf("request error %s", err)
log.Errorf("request error %s parameters %s", err, params)
return nil, err
}
body, err := jsonutils.Parse(resp.GetHttpContentBytes())

View File

@@ -905,7 +905,13 @@ func (self *SInstance) GetBillingType() string {
}
func (self *SInstance) GetExpiredAt() time.Time {
return self.ExpiredTime
if !self.ExpiredTime.IsZero() {
now := time.Now()
if self.ExpiredTime.Sub(now) < time.Hour*24*365*6 {
return self.ExpiredTime
}
}
return time.Time{}
}
func (self *SInstance) UpdateUserData(userData string) error {
@@ -925,10 +931,10 @@ func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle
params["InstanceId"] = instanceId
if bc.GetWeeks() <= 4 {
params["PeriodUnit"] = "Week"
params["Period"] = fmt.Sprintf("%s", bc.GetWeeks())
params["Period"] = fmt.Sprintf("%d", bc.GetWeeks())
} else {
params["PeriodUnit"] = "Month"
params["Period"] = fmt.Sprintf("%s", bc.GetMonths())
params["Period"] = fmt.Sprintf("%d", bc.GetMonths())
}
params["ClientToken"] = utils.GenRequestId(20)
_, err := region.ecsRequest("RenewInstance", params)

View File

@@ -5,6 +5,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
@@ -134,7 +135,7 @@ func (self *SZone) IsEmulated() bool {
}
func (self *SZone) GetStatus() string {
if len(self.AvailableResourceCreation.ResourceTypes) == 0 {
if len(self.AvailableResourceCreation.ResourceTypes) == 0 || !utils.IsInStringArray("Instance", self.AvailableResourceCreation.ResourceTypes) {
return models.ZONE_SOLDOUT
} else {
return models.ZONE_ENABLE