mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
585 lines
17 KiB
Go
585 lines
17 KiB
Go
package guestdrivers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/compare"
|
|
"yunion.io/x/pkg/util/secrules"
|
|
|
|
"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/models"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/util/billing"
|
|
)
|
|
|
|
type SManagedVirtualizedGuestDriver struct {
|
|
SVirtualizedGuestDriver
|
|
}
|
|
|
|
type SManagedVMCreateConfig struct {
|
|
Name string
|
|
ExternalImageId string
|
|
OsDistribution string
|
|
OsVersion string
|
|
InstanceType string // InstanceType 不为空时,直接采用InstanceType创建机器。
|
|
Cpu int
|
|
Memory int
|
|
ExternalNetworkId string
|
|
IpAddr string
|
|
Description string
|
|
StorageType string
|
|
SysDiskSize int
|
|
DataDisks []int
|
|
PublicKey string
|
|
SecGroupId string
|
|
SecGroupName string
|
|
SecRules []secrules.SecurityRule
|
|
|
|
BillingCycle billing.SBillingCycle
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject {
|
|
config := SManagedVMCreateConfig{}
|
|
config.Name = guest.Name
|
|
config.Cpu = int(guest.VcpuCount)
|
|
config.Memory = guest.VmemSize
|
|
config.Description = guest.Description
|
|
|
|
config.InstanceType = guest.InstanceType
|
|
|
|
if len(guest.KeypairId) > 0 {
|
|
config.PublicKey = guest.GetKeypairPublicKey()
|
|
}
|
|
|
|
nics := guest.GetNetworks()
|
|
net := nics[0].GetNetwork()
|
|
config.ExternalNetworkId = net.ExternalId
|
|
config.IpAddr = nics[0].IpAddr
|
|
|
|
config.SecGroupId = guest.SecgrpId
|
|
config.SecGroupName = guest.GetSecgroupName()
|
|
config.SecRules = guest.GetSecRules()
|
|
|
|
disks := guest.GetDisks()
|
|
config.DataDisks = make([]int, len(disks)-1)
|
|
|
|
for i := 0; i < len(disks); i += 1 {
|
|
disk := disks[i].GetDisk()
|
|
if i == 0 {
|
|
storage := disk.GetStorage()
|
|
config.StorageType = storage.StorageType
|
|
cache := storage.GetStoragecache()
|
|
imageId := disk.GetTemplateId()
|
|
//避免因同步过来的instance没有对应的imagecache信息,重置密码时引发空指针访问
|
|
if scimg := models.StoragecachedimageManager.GetStoragecachedimage(cache.Id, imageId); scimg != nil {
|
|
config.ExternalImageId = scimg.ExternalId
|
|
img := scimg.GetCachedimage()
|
|
config.OsDistribution, _ = img.Info.GetString("properties", "os_distribution")
|
|
config.OsVersion, _ = img.Info.GetString("properties", "os_version")
|
|
}
|
|
config.SysDiskSize = disk.DiskSize / 1024 // MB => GB
|
|
} else {
|
|
config.DataDisks[i-1] = disk.DiskSize / 1024 // MB => GB
|
|
}
|
|
}
|
|
|
|
if guest.BillingType == models.BILLING_TYPE_PREPAID {
|
|
bc, err := billing.ParseBillingCycle(guest.BillingCycle)
|
|
if err != nil {
|
|
log.Errorf("fail to parse billing cycle %s: %s", guest.BillingCycle, err)
|
|
}
|
|
config.BillingCycle = bc
|
|
}
|
|
|
|
return jsonutils.Marshal(&config)
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
|
diskCat := guest.CategorizeDisks()
|
|
var imageId string
|
|
if diskCat.Root != nil {
|
|
imageId = diskCat.Root.GetTemplateId()
|
|
}
|
|
if len(imageId) == 0 {
|
|
task.ScheduleRun(nil)
|
|
return nil
|
|
}
|
|
storage := diskCat.Root.GetStorage()
|
|
if storage == nil {
|
|
return fmt.Errorf("no valid storage")
|
|
}
|
|
storageCache := storage.GetStoragecache()
|
|
if storageCache == nil {
|
|
return fmt.Errorf("no valid storage cache")
|
|
}
|
|
return storageCache.StartImageCacheTask(ctx, task.GetUserCred(), imageId, false, task.GetTaskId())
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
|
return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId())
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestAttachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
|
return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId())
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestStartOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) (jsonutils.JSONObject, error) {
|
|
ihost, e := host.GetIHost()
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
|
|
ivm, e := ihost.GetIVMById(guest.GetExternalId())
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
|
|
result := jsonutils.NewDict()
|
|
if ivm.GetStatus() != models.VM_RUNNING {
|
|
if err := ivm.StartVM(ctx); err != nil {
|
|
return nil, e
|
|
} else {
|
|
task.ScheduleRun(result)
|
|
}
|
|
} else {
|
|
result.Add(jsonutils.NewBool(true), "is_running")
|
|
}
|
|
|
|
return result, e
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
|
|
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
|
ihost, err := host.GetIHost()
|
|
if err != nil {
|
|
log.Errorf("host.GetIHost fail %s", err)
|
|
return nil, err
|
|
}
|
|
ivm, err := ihost.GetIVMById(guest.ExternalId)
|
|
if err != nil {
|
|
if err == cloudprovider.ErrNotFound {
|
|
return nil, nil
|
|
}
|
|
log.Errorf("ihost.GetIVMById fail %s", err)
|
|
return nil, err
|
|
}
|
|
err = ivm.DeleteVM(ctx)
|
|
if err != nil {
|
|
log.Errorf("ivm.DeleteVM fail %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
for _, guestdisk := range guest.GetDisks() {
|
|
if disk := guestdisk.GetDisk(); disk != nil && disk.AutoDelete {
|
|
idisk, err := disk.GetIDisk()
|
|
if err != nil {
|
|
if err == cloudprovider.ErrNotFound {
|
|
continue
|
|
}
|
|
log.Errorf("disk.GetIDisk fail %s", err)
|
|
return nil, err
|
|
}
|
|
err = idisk.Delete(ctx)
|
|
if err != nil {
|
|
log.Errorf("idisk.Delete fail %s", err)
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return nil, nil
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestStopOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
|
|
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
|
ihost, err := host.GetIHost()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ivm, err := ihost.GetIVMById(guest.ExternalId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = ivm.StopVM(ctx, true)
|
|
return nil, err
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestSyncstatusOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential) (jsonutils.JSONObject, error) {
|
|
ihost, err := host.GetIHost()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ivm, err := ihost.GetIVMById(guest.ExternalId)
|
|
if err != nil {
|
|
log.Errorf("fail to find ivm by id %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
status := ivm.GetStatus()
|
|
switch status {
|
|
case models.VM_RUNNING:
|
|
status = cloudprovider.CloudVMStatusRunning
|
|
case models.VM_READY:
|
|
status = cloudprovider.CloudVMStatusStopped
|
|
case models.VM_STARTING:
|
|
status = cloudprovider.CloudVMStatusStopped
|
|
case models.VM_STOPPING:
|
|
status = cloudprovider.CloudVMStatusRunning
|
|
default:
|
|
status = cloudprovider.CloudVMStatusOther
|
|
}
|
|
|
|
body := jsonutils.NewDict()
|
|
body.Add(jsonutils.NewString(status), "status")
|
|
return body, nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) GetGuestVncInfo(userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost) (*jsonutils.JSONDict, error) {
|
|
ihost, err := host.GetIHost()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
iVM, err := ihost.GetIVMById(guest.ExternalId)
|
|
if err != nil {
|
|
log.Errorf("cannot find vm %s %s", iVM, err)
|
|
return nil, err
|
|
}
|
|
|
|
data, err := iVM.GetVNCInfo()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dataDict := data.(*jsonutils.JSONDict)
|
|
|
|
return dataDict, nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestRebuildRootDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
|
subtask, err := taskman.TaskManager.NewTask(ctx, "ManagedGuestRebuildRootTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
subtask.ScheduleRun(nil)
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
|
subtask, err := taskman.TaskManager.NewTask(ctx, "ManagedGuestCreateDiskTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
subtask.ScheduleRun(nil)
|
|
return nil
|
|
}
|
|
|
|
type SManagedVMChangeConfig struct {
|
|
InstanceId string
|
|
InstanceType string // InstanceType 不为空时,直接采用InstanceType更新主机。
|
|
Cpu int
|
|
Memory int
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
|
|
config := SManagedVMChangeConfig{}
|
|
config.InstanceId = guest.GetExternalId()
|
|
if instanceType, err := task.GetParams().GetString("instance_type"); err == nil {
|
|
config.InstanceType = instanceType
|
|
}
|
|
|
|
config.Cpu = int(vcpuCount)
|
|
config.Memory = int(vmemSize)
|
|
ihost, err := guest.GetHost().GetIHost()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
iVM, err := ihost.GetIVMById(config.InstanceId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if int(guest.VcpuCount) != config.Cpu || guest.VmemSize != config.Memory {
|
|
if len(config.InstanceType) > 0 {
|
|
err = iVM.ChangeConfig2(ctx, config.InstanceType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
err = iVM.ChangeConfig(ctx, config.Cpu, config.Memory)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
|
|
iDisk, _ := models.DiskManager.FetchById(diskId)
|
|
disk := iDisk.(*models.SDisk)
|
|
providerDisk, err := disk.GetIDisk()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
|
|
snapshot := iSnapshot.(*models.SSnapshot)
|
|
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
|
cloudSnapshot, err := providerDisk.CreateISnapshot(ctx, snapshot.Name, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := jsonutils.NewDict()
|
|
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
|
|
return res, nil
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
|
|
|
|
recycle := false
|
|
if guest.IsPrepaidRecycle() {
|
|
recycle = true
|
|
}
|
|
|
|
if data.Contains("disks") {
|
|
diskInfo := make([]SDiskInfo, 0)
|
|
err := data.Unmarshal(&diskInfo, "disks")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
disks := guest.GetDisks()
|
|
if len(disks) != len(diskInfo) {
|
|
msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo))
|
|
log.Errorf(msg)
|
|
return fmt.Errorf(msg)
|
|
}
|
|
for i := 0; i < len(diskInfo); i += 1 {
|
|
disk := disks[i].GetDisk()
|
|
_, err = disk.GetModelManager().TableSpec().Update(disk, func() error {
|
|
disk.DiskSize = diskInfo[i].Size
|
|
disk.ExternalId = diskInfo[i].Uuid
|
|
disk.DiskType = diskInfo[i].DiskType
|
|
disk.Status = models.DISK_READY
|
|
|
|
disk.FsFormat = diskInfo[i].FsFromat
|
|
if diskInfo[i].AutoDelete {
|
|
disk.AutoDelete = true
|
|
}
|
|
// disk.TemplateId = diskInfo[i].TemplateId
|
|
disk.AccessPath = diskInfo[i].Path
|
|
|
|
if !recycle {
|
|
disk.BillingType = diskInfo[i].BillingType
|
|
disk.ExpiredAt = diskInfo[i].ExpiredAt
|
|
}
|
|
|
|
if len(diskInfo[i].Metadata) > 0 {
|
|
for key, value := range diskInfo[i].Metadata {
|
|
if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
|
|
log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
msg := fmt.Sprintf("save disk info failed %s", err)
|
|
log.Errorf(msg)
|
|
break
|
|
}
|
|
db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(ctx), task.GetUserCred())
|
|
guestdisk := guest.GetGuestDisk(disk.Id)
|
|
_, err = guestdisk.GetModelManager().TableSpec().Update(guestdisk, func() error {
|
|
guestdisk.Driver = diskInfo[i].Driver
|
|
guestdisk.CacheMode = diskInfo[i].CacheMode
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
msg := fmt.Sprintf("save disk info failed %s", err)
|
|
log.Errorf(msg)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
uuid, _ := data.GetString("uuid")
|
|
if len(uuid) > 0 {
|
|
guest.SetExternalId(uuid)
|
|
}
|
|
|
|
if metaData, _ := data.Get("metadata"); metaData != nil {
|
|
meta := make(map[string]string, 0)
|
|
if err := metaData.Unmarshal(meta); err != nil {
|
|
log.Errorf("Get guest %s metadata error: %v", guest.Name, err)
|
|
} else {
|
|
for key, value := range meta {
|
|
if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
|
|
log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exp, err := data.GetTime("expired_at")
|
|
if err == nil && !guest.IsPrepaidRecycle() {
|
|
guest.SaveRenewInfo(ctx, task.GetUserCred(), nil, &exp)
|
|
}
|
|
|
|
guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
|
|
return nil
|
|
}
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
|
|
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
|
ihost, err := host.GetIHost()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iVM, err := ihost.GetIVMById(guest.ExternalId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if fwOnly, _ := task.GetParams().Bool("fw_only"); fwOnly {
|
|
vpcId := ""
|
|
for _, network := range guest.GetNetworks() {
|
|
if vpc := network.GetNetwork().GetVpc(); vpc != nil {
|
|
vpcId = vpc.ExternalId
|
|
break
|
|
}
|
|
}
|
|
iregion, err := host.GetIRegion()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
secgroups := guest.GetSecgroups()
|
|
externalIds := []string{}
|
|
for _, secgroup := range secgroups {
|
|
lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId))
|
|
defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId))
|
|
|
|
secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), secgroup.Id, vpcId, host.GetRegion().Id, host.ManagerId)
|
|
if secgroupCache == nil {
|
|
return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s", secgroup.Id, vpcId)
|
|
}
|
|
extID, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpcId, secgroup.Name, secgroup.Description, secgroup.GetSecRules(""))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = secgroupCache.SetExternalId(extID); err != nil {
|
|
return nil, err
|
|
}
|
|
externalIds = append(externalIds, extID)
|
|
}
|
|
return nil, iVM.AssignSecurityGroups(externalIds)
|
|
}
|
|
|
|
iDisks, err := iVM.GetIDisks()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
disks := make([]models.SDisk, 0)
|
|
for _, guestdisk := range guest.GetDisks() {
|
|
disk := guestdisk.GetDisk()
|
|
disks = append(disks, *disk)
|
|
}
|
|
|
|
added := make([]models.SDisk, 0)
|
|
commondb := make([]models.SDisk, 0)
|
|
commonext := make([]cloudprovider.ICloudDisk, 0)
|
|
removed := make([]cloudprovider.ICloudDisk, 0)
|
|
|
|
if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil {
|
|
return nil, err
|
|
}
|
|
for _, disk := range removed {
|
|
if err := iVM.DetachDisk(ctx, disk.GetId()); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, disk := range added {
|
|
if err := iVM.AttachDisk(ctx, disk.ExternalId); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return nil, nil
|
|
})
|
|
return nil
|
|
}
|
|
|
|
/*func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
|
|
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
|
if ihost, err := host.GetIHost(); err != nil {
|
|
return nil, err
|
|
} else if iVM, err := ihost.GetIVMById(guest.ExternalId); err != nil {
|
|
return nil, err
|
|
} else {
|
|
if fw_only, _ := task.GetParams().Bool("fw_only"); fw_only {
|
|
if err := iVM.SyncSecurityGroup(guest.SecgrpId, guest.GetSecgroupName(), guest.GetSecRules()); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
if iDisks, err := iVM.GetIDisks(); err != nil {
|
|
return nil, err
|
|
} else {
|
|
disks := make([]models.SDisk, 0)
|
|
for _, guestdisk := range guest.GetDisks() {
|
|
disk := guestdisk.GetDisk()
|
|
disks = append(disks, *disk)
|
|
}
|
|
|
|
added := make([]models.SDisk, 0)
|
|
commondb := make([]models.SDisk, 0)
|
|
commonext := make([]cloudprovider.ICloudDisk, 0)
|
|
removed := make([]cloudprovider.ICloudDisk, 0)
|
|
|
|
if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil {
|
|
return nil, err
|
|
}
|
|
for _, disk := range removed {
|
|
if err := iVM.DetachDisk(ctx, disk.GetId()); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, disk := range added {
|
|
if err := iVM.AttachDisk(ctx, disk.ExternalId); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil, nil
|
|
})
|
|
return nil
|
|
}*/
|
|
|
|
func (self *SManagedVirtualizedGuestDriver) RequestRenewInstance(guest *models.SGuest, bc billing.SBillingCycle) (time.Time, error) {
|
|
iVM, err := guest.GetIVM()
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
err = iVM.Renew(bc)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
return iVM.GetExpiredAt(), nil
|
|
}
|