阿里云调整配置等API

This commit is contained in:
TangBin
2018-08-20 11:02:37 +08:00
parent 6054ed4727
commit 8feaa3538b
17 changed files with 683 additions and 134 deletions
-1
View File
@@ -980,7 +980,6 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre
return nil, httperrors.NewGeneralError(err)
}
item.PreUpdate(ctx, userCred, query, dataDict)
diff, err := manager.TableSpec().Update(item, func() error {
filterData := dataDict.CopyIncludes(updateFields(manager, userCred)...)
err = filterData.Unmarshal(item)
+7 -1
View File
@@ -153,7 +153,12 @@ type ICloudVM interface {
StopVM(isForce bool) error
DeleteVM() error
UpdateVM(name string) error
RebuildRoot(imageId string) error
DeployVM(name string, password string, publicKey string, resetPassword bool, deleteKeypair bool, description string) error
ChangeConfig(instanceId string,ncpu int, vmem int) error
GetVNCInfo() (jsonutils.JSONObject, error)
AttachDisk(diskId string) error
}
type ICloudNic interface {
@@ -193,7 +198,8 @@ type ICloudDisk interface {
GetCacheMode() string
GetMountpoint() string
Delete() error
Resize(int64) error
Resize(newSize int64) error
}
type ICloudVpc interface {
+226 -72
View File
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -103,7 +102,6 @@ func (self *SAliyunGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *mo
imageId := disk.GetTemplateId()
scimg := models.StoragecachedimageManager.GetStoragecachedimage(cache.Id, imageId)
config.ExternalImageId = scimg.ExternalId
img := scimg.GetCachedimage()
config.OsDistribution, _ = img.Info.GetString("properties", "os_distribution")
config.OsVersion, _ = img.Info.GetString("properties", "os_version")
@@ -134,92 +132,134 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
return err
}
if action != "create" {
return fmt.Errorf("Action %s not supported", action)
}
ihost, err := host.GetIHost()
if err != nil {
return err
}
desc := SAliyunVMCreateConfig{}
err = config.Unmarshal(&desc, "desc")
if err != nil {
return err
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
passwd := seclib2.RandomPassword2(12)
iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, desc.PublicKey)
if action == "create" {
desc := SAliyunVMCreateConfig{}
err = config.Unmarshal(&desc, "desc")
if err != nil {
return nil, err
}
log.Debugf("VMcreated %s, wait status ready ...", iVM.GetGlobalId())
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*1800)
if err != nil {
return nil, err
}
log.Debugf("VMcreated %s, and status is ready", iVM.GetGlobalId())
iVM, err = ihost.GetIVMById(iVM.GetGlobalId())
if err != nil {
log.Errorf("cannot find vm %s", err)
return nil, err
return err
}
if len(guest.SecgrpId) > 0 {
if err := iVM.SyncSecurityGroup(guest.SecgrpId, guest.GetSecgroupName(), guest.GetSecRules()); err != nil {
log.Errorf("SyncSecurityGroup error: %v", err)
return nil, err
}
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
passwd := seclib2.RandomPassword2(12)
if onfinish == "none" {
err = iVM.StartVM()
iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, desc.PublicKey)
if err != nil {
return nil, err
}
}
encpasswd, err := utils.EncryptAESBase64(guest.Id, passwd)
if err != nil {
log.Errorf("encrypt password failed %s", err)
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(iVM.GetOSType()), "os")
data.Add(jsonutils.NewString("root"), "account")
data.Add(jsonutils.NewString(encpasswd), "key")
if len(desc.OsDistribution) > 0 {
data.Add(jsonutils.NewString(desc.OsDistribution), "distro")
}
if len(desc.OsVersion) > 0 {
data.Add(jsonutils.NewString(desc.OsVersion), "version")
}
idisks, err := iVM.GetIDisks()
if err != nil {
log.Errorf("GetiDisks error %s", err)
} else {
diskInfo := make([]SDiskInfo, len(idisks))
for i := 0; i < len(idisks); i += 1 {
dinfo := SDiskInfo{}
dinfo.Uuid = idisks[i].GetGlobalId()
dinfo.Size = idisks[i].GetDiskSizeMB()
diskInfo[i] = dinfo
log.Debugf("VMcreated %s, wait status ready ...", iVM.GetGlobalId())
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*1800)
if err != nil {
return nil, err
}
data.Add(jsonutils.Marshal(&diskInfo), "disks")
log.Debugf("VMcreated %s, and status is ready", iVM.GetGlobalId())
iVM, err = ihost.GetIVMById(iVM.GetGlobalId())
if err != nil {
log.Errorf("cannot find vm %s", err)
return nil, err
}
if len(guest.SecgrpId) > 0 {
if err := iVM.SyncSecurityGroup(guest.SecgrpId, guest.GetSecgroupName(), guest.GetSecRules()); err != nil {
log.Errorf("SyncSecurityGroup error: %v", err)
return nil, err
}
}
if onfinish == "none" {
err = iVM.StartVM()
if err != nil {
return nil, err
}
}
encpasswd, err := utils.EncryptAESBase64(guest.Id, passwd)
if err != nil {
log.Errorf("encrypt password failed %s", err)
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(iVM.GetOSType()), "os")
data.Add(jsonutils.NewString("root"), "account")
data.Add(jsonutils.NewString(encpasswd), "key")
if len(desc.OsDistribution) > 0 {
data.Add(jsonutils.NewString(desc.OsDistribution), "distro")
}
if len(desc.OsVersion) > 0 {
data.Add(jsonutils.NewString(desc.OsVersion), "version")
}
idisks, err := iVM.GetIDisks()
if err != nil {
log.Errorf("GetiDisks error %s", err)
} else {
diskInfo := make([]SDiskInfo, len(idisks))
for i := 0; i < len(idisks); i += 1 {
dinfo := SDiskInfo{}
dinfo.Uuid = idisks[i].GetGlobalId()
dinfo.Size = idisks[i].GetDiskSizeMB()
diskInfo[i] = dinfo
}
data.Add(jsonutils.Marshal(&diskInfo), "disks")
}
data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid")
return data, nil
})
} else if action == "deploy" {
iVM, err := ihost.GetIVMById(guest.GetExternalId())
if err != nil || iVM == nil {
log.Errorf("cannot find vm %s", err)
return fmt.Errorf("cannot find vm")
}
data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid")
params := task.GetParams()
log.Debugf("Deploy VM params %s", params.String())
var name string
if v, e := params.GetString("name"); e != nil {
name = v
}
var description string
if v, e := params.GetString("description"); e != nil {
description = v
}
resetPassword := jsonutils.QueryBoolean(params, "reset_password", false)
deleteKeypair := jsonutils.QueryBoolean(params, "__delete_keypair__", false)
password, _ := params.GetString("password")
if resetPassword && len(password) == 0{
password = seclib2.RandomPassword2(12)
}
publicKey := ""
if k, e := config.GetString("public_key"); e != nil {
publicKey = k
}
taskman.LocalTaskRun(task, func () (jsonutils.JSONObject, error) {
encpasswd, err := utils.EncryptAESBase64(guest.Id, password)
if err != nil {
log.Errorf("encrypt password failed %s", err)
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewString("root"), "account") // 用户名
data.Add(jsonutils.NewString(encpasswd), "key") // 密码
e := iVM.DeployVM(name, password, publicKey, resetPassword, deleteKeypair, description)
return data, e
})
} else {
return fmt.Errorf("Action %s not supported", action)
}
return data, nil
})
return nil
}
@@ -277,3 +317,117 @@ func (self *SAliyunGuestDriver) RequestSyncConfigOnHost(ctx context.Context, gue
})
return nil
}
type SAliyunVMChangeConfig struct {
InstanceId string
Cpu int
Memory int
}
func (self *SAliyunGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
subtask, err := taskman.TaskManager.NewTask(ctx, "AliyunGuestCreateDiskTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
if err != nil {
return err
}
subtask.ScheduleRun(nil)
return nil
}
func (self *SAliyunGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SAliyunGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
config := SAliyunVMChangeConfig{}
config.InstanceId = guest.GetExternalId()
config.Cpu = int(vcpuCount)
config.Memory = int(vmemSize)
// taskman localTaskRun
ihost, err := guest.GetHost().GetIHost()
if err != nil {
return err
}
iVM, err := ihost.GetIVMById(config.InstanceId)
if err != nil {
return err
}
err = iVM.ChangeConfig(config.InstanceId, config.Cpu, config.Memory)
// todo: wait status ready & check disk
if err != nil {
return err
}
log.Debugf("VMchangeConfig %s, wait status ready ...", iVM.GetGlobalId())
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*300)
if err != nil {
return err
}
log.Debugf("VMchangeConfig %s, and status is ready", iVM.GetGlobalId())
return nil
}
func (self *SAliyunGuestDriver) 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
}
err := ivm.StartVM()
if err != nil {
return nil, e
}
result := jsonutils.NewDict()
result.Add(jsonutils.NewBool(true), "is_running")
return result, e
}
func (self *SAliyunGuestDriver) RequestRebuildRootDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
ihost, e := guest.GetHost().GetIHost()
if e != nil {
return e
}
externalId := guest.GetExternalId()
if len(externalId) <= 0 {
return fmt.Errorf("external id not found")
}
disks := guest.GetDisks()
if len(disks) <= 0 {
return fmt.Errorf("guest has no disk")
}
imageId := guest.CategorizeDisks().Root.TemplateId
cacheId := disks[0].GetDisk().GetStorage().GetStoragecache().Id
externalImageId := models.StoragecachedimageManager.GetStoragecachedimage(cacheId, imageId).ExternalId
if len(externalImageId) <= 0 {
return fmt.Errorf("external image (%s) id is not found", imageId)
}
iVM, err := ihost.GetIVMById(externalId)
if err != nil {
return err
}
err = iVM.RebuildRoot(externalImageId)
if err != nil {
return err
}
log.Debugf("VMrebuildRoot %s, wait status ready ...", iVM.GetGlobalId())
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*1800)
if err != nil {
return err
}
log.Debugf("VMrebuildRoot %s, and status is ready", iVM.GetGlobalId())
task.ScheduleRun(nil)
return nil
}
+32 -16
View File
@@ -472,9 +472,11 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To
return nil, err
}
// if data.Contains("name") {
// return nil, httperrors.NewInputParameterError("cannot update server name")
// }
if data.Contains("name") {
if name, _ := data.GetString("name"); len(name) < 2 {
return nil, httperrors.NewInputParameterError("name is to short")
}
}
/* if self.GetHypervisor() == HYPERVISOR_BAREMETAL {
return nil, httperrors.NewInputParameterError("Cannot modify memory for baremetal")
}
@@ -1507,7 +1509,11 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
if !ok {
return nil, fmt.Errorf("Parse query body error")
}
// 变更密码/密钥时需要Restart才能生效。更新普通字段不需要Restart
doRestart := false
if kwargs.Contains("__delete_keypair__") || kwargs.Contains("keypair") {
doRestart = true
var kpId string
if !jsonutils.QueryBoolean(kwargs, "__delete_keypair__", false) {
keypair, _ := kwargs.GetString("keypair")
@@ -1529,8 +1535,9 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
kwargs.Set("reset_password", jsonutils.JSONTrue)
}
}
if utils.IsInStringArray(self.Status, []string{VM_RUNNING, VM_READY, VM_ADMIN}) {
if self.Status == VM_RUNNING {
if doRestart && self.Status == VM_RUNNING {
kwargs.Set("restart", jsonutils.JSONTrue)
}
err := self.StartGuestDeployTask(ctx, userCred, kwargs, "deploy", "")
@@ -1874,12 +1881,10 @@ func (self *SGuest) createDiskOnHost(ctx context.Context, userCred mcclient.Toke
if storage == nil {
return nil, fmt.Errorf("No storage to create disk")
}
disk, err := self.createDiskOnStorage(ctx, userCred, storage, diskConfig, pendingUsage)
if err != nil {
return nil, err
}
err = self.attach2Disk(disk, userCred, diskConfig.Driver, diskConfig.Cache, diskConfig.Mountpoint)
return disk, err
}
@@ -2412,16 +2417,27 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
diskIdx += 1
}
for storageId, needSize := range diskSizes {
iStorage, err := StorageManager.FetchById(storageId)
if err != nil {
return nil, httperrors.NewBadRequestError("Fetch storage error: %s", err)
}
storage := iStorage.(*SStorage)
if storage.GetFreeCapacity() < needSize {
return nil, httperrors.NewInsufficientResourceError("Not enough free space")
}
provider, e := self.GetHost().GetDriver()
if e != nil {
log.Errorf("Get Provider Error: %s", e)
return nil, httperrors.NewInsufficientResourceError("Provider Not Found")
}
if !provider.IsPublicCloud() {
for storageId, needSize := range diskSizes {
iStorage, err := StorageManager.FetchById(storageId)
if err != nil {
return nil, httperrors.NewBadRequestError("Fetch storage error: %s", err)
}
storage := iStorage.(*SStorage)
if storage.GetFreeCapacity() < needSize {
return nil, httperrors.NewInsufficientResourceError("Not enough free space")
}
}
} else {
log.Debugf("Skip storage free capacity validating for public cloud: %s", provider.GetName())
}
if newDisks.Length() > 0 {
confs.Add(newDisks, "create")
}
@@ -3293,4 +3309,4 @@ func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, use
for i := 0; i < len(guests); i += 1 {
guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true)
}
}
}
+109
View File
@@ -9,6 +9,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/log"
)
type GuestCreateDiskTask struct {
@@ -118,7 +119,115 @@ func (self *KVMGuestCreateDiskTask) OnConfigSyncComplete(ctx context.Context, ob
self.SetStageComplete(ctx, nil)
}
type AliyunGuestCreateDiskTask struct {
SGuestBaseTask
}
func (self *AliyunGuestCreateDiskTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
self.SetStage("on_aliyun_disk_prepared", nil)
self.OnAliyunDiskPrepared(ctx, obj, data)
}
func (self *AliyunGuestCreateDiskTask) OnAliyunDiskPrepared(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
var diskIndex = 0
var diskReady = true
for {
diskId, err := self.Params.GetString(fmt.Sprintf("disk.%d.id", diskIndex))
if !diskReady || err != nil {
break
}
iDisk, err := models.DiskManager.FetchById(diskId)
if err != nil {
self.SetStageFailed(ctx, err.Error())
return
}
if iDisk == nil {
self.SetStageFailed(ctx, "Disk not found")
return
}
disk := iDisk.(*models.SDisk)
if disk.Status == models.DISK_INIT {
snapInfo, err := self.Params.GetString(fmt.Sprintf("disk.%d.snapshot", diskIndex))
if err != nil {
snapInfo = ""
}
err = disk.StartDiskCreateTask(ctx, self.UserCred, false, snapInfo, self.GetTaskId())
if err != nil {
self.SetStageFailed(ctx, err.Error())
return
}
diskReady = false
break
}
diskIndex += 1
}
diskIndex = 0
guest := obj.(*models.SGuest)
for {
diskId, err := self.Params.GetString(fmt.Sprintf("disk.%d.id", diskIndex))
if !diskReady || err != nil {
break
}
iDisk, err := models.DiskManager.FetchById(diskId)
if err != nil {
self.SetStageFailed(ctx, err.Error())
return
}
if iDisk == nil {
self.SetStageFailed(ctx, "Disk not found")
return
}
disk := iDisk.(*models.SDisk)
if disk.Status != models.DISK_READY {
diskReady = false
break
}
ihost, err := guest.GetHost().GetIHost()
if err != nil {
self.SetStageFailed(ctx, "Host not found")
return
}
iVM, e := ihost.GetIVMById(guest.GetExternalId())
if e != nil {
self.SetStageFailed(ctx, "Aliyun VM not found")
return
}
err = iVM.AttachDisk(disk.GetExternalId())
if err != nil {
log.Debugf("Attach Disk %s to guest fail: %s", diskId, err)
self.SetStageFailed(ctx, "Attach Disk to guest fail")
return
}
diskIndex += 1
}
if diskReady {
if guest.Status == models.VM_RUNNING {
self.SetStage("on_config_sync_complete", nil)
err := guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
if err != nil {
self.SetStageFailed(ctx, err.Error())
}
} else {
self.SetStageComplete(ctx, nil)
}
}
}
func (self *AliyunGuestCreateDiskTask) OnConfigSyncComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *AliyunGuestCreateDiskTask) AttachAliyunDisks(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func init() {
taskman.RegisterTask(GuestCreateDiskTask{})
taskman.RegisterTask(KVMGuestCreateDiskTask{})
taskman.RegisterTask(AliyunGuestCreateDiskTask{})
}
+1 -5
View File
@@ -54,14 +54,10 @@ func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest *
log.Errorf("request_deploy_guest_on_host %s", err)
self.OnDeployGuestFail(ctx, guest, err)
} else {
self.OnDeployGuestSucc(guest)
guest.SetStatus(self.UserCred, models.VM_DEPLOYING, "")
}
}
func (self *GuestDeployTask) OnDeployGuestSucc(guest *models.SGuest) {
guest.SetStatus(self.UserCred, models.VM_DEPLOYING, "")
}
func (self *GuestDeployTask) OnDeployGuestFail(ctx context.Context, guest *models.SGuest, err error) {
guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
+1 -1
View File
@@ -141,4 +141,4 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context
func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
}
+21 -2
View File
@@ -138,6 +138,12 @@ func (self *SDisk) Refresh() error {
return jsonutils.Update(self, new)
}
func (self *SDisk) ResizeDisk(newSize int64) error {
// newSize 单位为 GB. 范围在20 ~2000. 只能往大调。不能调小
// https://help.aliyun.com/document_detail/25522.html?spm=a2c4g.11174283.6.897.aHwqkS
return self.storage.zone.region.resizeDisk(self.DiskId, newSize)
}
func (self *SDisk) GetDiskFormat() string {
return "vhd"
}
@@ -185,7 +191,7 @@ func (self *SDisk) GetMountpoint() string {
return ""
}
func (self *SRegion) createDisk(zoneId string, category string, name string, sizeGb int, desc string) (string, error) {
func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string) (string, error) {
params := make(map[string]string)
params["ZoneId"] = zoneId
params["DiskName"] = name
@@ -223,11 +229,24 @@ func (self *SRegion) deleteDisk(diskId string) error {
return err
}
func (self *SRegion) DeleteDisk(diskId string) error {
params := make(map[string]string)
params["DiskId"] = diskId
_, err := self.ecsRequest("DeleteDisk", params)
return err
}
func (self *SRegion) resizeDisk(diskId string, size int64) error {
params := make(map[string]string)
params["DiskId"] = diskId
params["NewSize"] = fmt.Sprintf("%d", size)
_, err := self.ecsRequest("ResizeDisk", params)
return err
if err != nil {
log.Errorf("ResizeDisk %s to %s GiB fail %s", diskId, size, err)
return err
}
return nil
}
+2 -2
View File
@@ -157,7 +157,7 @@ func (self *SHost) GetManagerId() string {
return self.zone.region.client.providerId
}
func (self *SHost) getInstanceById(instanceId string) (*SInstance, error) {
func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
inst, err := self.zone.region.GetInstance(instanceId)
if err != nil {
return nil, err
@@ -171,7 +171,7 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int,
if err != nil {
return nil, err
}
vm, err := self.getInstanceById(vmId)
vm, err := self.GetInstanceById(vmId)
if err != nil {
return nil, err
}
+162 -32
View File
@@ -3,6 +3,7 @@ package aliyun
import (
"fmt"
"time"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -110,6 +111,7 @@ type SInstance struct {
InternetMaxBandwidthIn int
InternetMaxBandwidthOut int
IoOptimized bool
KeyPairName string
Memory int
NetworkInterfaces SNetworkInterfaces
OSName string
@@ -322,6 +324,81 @@ func (self *SInstance) GetHypervisor() string {
return models.HYPERVISOR_ALIYUN
}
func (self *SInstance) StartVM() error {
err := self.host.zone.region.StartVM(self.InstanceId)
if err != nil {
return err
}
return cloudprovider.WaitStatus(self, models.VM_RUNNING, 5*time.Second, 180*time.Second) // 3minutes
}
func (self *SInstance) StopVM(isForce bool) error {
err := self.host.zone.region.StopVM(self.InstanceId, isForce)
if err != nil {
return err
}
return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) // 5mintues
}
func (self *SInstance) DeleteVM() error {
err := self.host.zone.region.DeleteVM(self.InstanceId)
if err != nil {
return err
}
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
}
func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId)
if err != nil {
return nil, err
}
passwd := seclib.RandomPassword(6)
err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd)
if err != nil {
return nil, err
}
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewString(url), "url")
ret.Add(jsonutils.NewString(passwd), "password")
ret.Add(jsonutils.NewString("aliyun"), "protocol")
ret.Add(jsonutils.NewString(self.InstanceId), "instance_id")
return ret, nil
}
func (self *SInstance) UpdateVM(name string) error {
return self.host.zone.region.UpdateVM(self.InstanceId, name)
}
func (self *SInstance) DeployVM(name string, password string, publicKey string, resetPassword bool, deleteKeypair bool, description string) error {
var keypairName string
if len(publicKey) > 0 {
key, e := self.host.lookUpAliyunKeypair(publicKey)
if e != nil {
key, e = self.host.importAliyunKeypair(publicKey)
if e != nil {
return e
}
}
keypairName = key
}
return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, resetPassword, deleteKeypair, description)
}
func (self *SInstance) RebuildRoot(imageId string) error {
return self.host.zone.region.ReplaceSystemDisk(self.InstanceId, imageId)
}
func (self *SInstance) ChangeConfig(instanceId string, ncpu int, vmem int) error {
return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, ncpu, vmem, nil)
}
func (self *SInstance) AttachDisk(diskId string) error {
return self.host.zone.region.AttachDisk(self.InstanceId, diskId)
}
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1)
if err != nil {
@@ -472,46 +549,99 @@ func (self *SRegion) DeleteVM(instanceId string) error {
// }
}
func (self *SInstance) StartVM() error {
err := self.host.zone.region.StartVM(self.InstanceId)
func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, resetPassword bool, deleteKeypair bool, description string) error {
instance, err := self.GetInstance(instanceId)
if err != nil {
return err
}
return cloudprovider.WaitStatus(self, models.VM_RUNNING, 5*time.Second, 180*time.Second) // 3minutes
// 修改密钥时直接返回
if deleteKeypair {
return self.DetachKeyPair(instanceId, instance.KeyPairName)
}
if len(keypairName) > 0 {
return self.AttachKeypair(instanceId, keypairName)
}
params := make(map[string]string)
if resetPassword {
params["Password"] = seclib2.RandomPassword2(12)
}
// 指定密码的情况下,使用指定的密码
if len(password) > 0 {
params["Password"] = password
}
if len(name) > 0 && instance.InstanceName != name {
params["InstanceName"] = name
params["HostName"] = name
}
if len(description) > 0 && instance.Description != description {
params["Description"] = description
}
if len(params) > 0 {
log.Debugf("DeployVM with params %s", params)
return self.modifyInstanceAttribute(instanceId, params)
} else {
return nil
}
}
func (self *SInstance) StopVM(isForce bool) error {
err := self.host.zone.region.StopVM(self.InstanceId, isForce)
func (self *SRegion) UpdateVM(instanceId string, hostname string) error {
/*
api: ModifyInstanceAttribute
https://help.aliyun.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW
*/
params := make(map[string]string)
params["HostName"] = hostname
return self.modifyInstanceAttribute(instanceId, params)
}
func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error {
return self.instanceOperation(instanceId, "ModifyInstanceAttribute", params)
}
func (self *SRegion) ReplaceSystemDisk(instanceId string, image string) error {
params := make(map[string]string)
params["ImageId"] = image
return self.instanceOperation(instanceId, "ReplaceSystemDisk", params)
}
func (self *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error {
// todo: support change disk config?
params := make(map[string]string)
instanceTypes, e := self.GetMatchInstanceTypes(ncpu, vmem, 0, zoneId)
if e != nil {
return e
}
for _, instancetype := range instanceTypes {
params["InstanceType"] = instancetype.InstanceTypeId
params["ClientToken"] = utils.GenRequestId(20)
if err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params); err != nil {
log.Errorf("Failed for %s: %s", instancetype.InstanceTypeId, err)
} else {
return nil
}
}
return fmt.Errorf("Failed to change vm config, specification not supported")
}
func (self *SRegion) AttachDisk(instanceId string, diskId string) error {
params := make(map[string]string)
params["InstanceId"] = instanceId
params["DiskId"] = diskId
_, err := self.ecsRequest("AttachDisk", params)
if err != nil {
log.Errorf("AttachDisk %s to %s fail %s", diskId, instanceId, err)
return err
}
return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) // 5mintues
}
func (self *SInstance) DeleteVM() error {
err := self.host.zone.region.DeleteVM(self.InstanceId)
if err != nil {
return err
}
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
}
func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId)
if err != nil {
return nil, err
}
passwd := seclib.RandomPassword(6)
err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd)
if err != nil {
return nil, err
}
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewString(url), "url")
ret.Add(jsonutils.NewString(passwd), "password")
ret.Add(jsonutils.NewString("aliyun"), "protocol")
ret.Add(jsonutils.NewString(self.InstanceId), "instance_id")
return ret, nil
return nil
}
func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error {
@@ -538,4 +668,4 @@ func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules [
self.SecurityGroupIds.SecurityGroupId = []string{secgrpId}
}
return nil
}
}
+31
View File
@@ -1,6 +1,7 @@
package aliyun
import (
"encoding/json"
"fmt"
"yunion.io/x/log"
)
@@ -62,3 +63,33 @@ func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error
}
return &keypair, nil
}
func (self *SRegion) AttachKeypair(instanceId string, name string) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["KeyPairName"] = name
instances, _ := json.Marshal(&[...]string{instanceId})
params["InstanceIds"] = string(instances)
_, err := self.ecsRequest("AttachKeyPair", params)
if err != nil {
log.Errorf("AttachKeyPair fail %s", err)
return err
}
return nil
}
func (self *SRegion) DetachKeyPair(instanceId string, name string) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["KeyPairName"] = name
instances, _ := json.Marshal(&[...]string{instanceId})
params["InstanceIds"] = string(instances)
_, err := self.ecsRequest("DetachKeyPair", params)
if err != nil {
log.Errorf("DetachKeyPair fail %s", err)
return err
}
return nil
}
+11
View File
@@ -21,4 +21,15 @@ func init() {
printList(disks, total, args.Offset, args.Limit, []string{})
return nil
})
type DiskDeleteOptions struct {
Instance string `help:"Instance ID"`
}
shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *aliyun.SRegion, args *DiskDeleteOptions) error {
e := cli.DeleteDisk(args.Instance)
if e != nil {
return e
}
return nil
})
}
+57
View File
@@ -82,6 +82,63 @@ func init() {
return nil
})
/*
server-change-config 更改系统配置
server-reset
*/
type InstanceDeployOptions struct {
ID string `help:"instance ID"`
Name string `help:"new instance name"`
Hostname string `help:"new hostname"`
Keypair string `help:"Keypair Name"`
DeleteKeypair bool `help:"Remove SSH keypair"`
Password string `help:"new password"`
ResetPassword bool `help:"Force reset password"`
Description string `help:"new instances description"`
}
shellutils.R(&InstanceDeployOptions{}, "instance-deploy", "Deploy keypair/password to a stopped virtual server", func(cli *aliyun.SRegion, args *InstanceDeployOptions) error {
err := cli.DeployVM(args.ID, args.Name, args.Password, args.Keypair, args.ResetPassword, args.DeleteKeypair, args.Description)
if err != nil {
return err
}
return nil
})
type InstanceRebuildRootOptions struct {
ID string `help:"instance ID"`
Image string `help:"Image ID"`
}
shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *aliyun.SRegion, args *InstanceRebuildRootOptions) error {
err := cli.ReplaceSystemDisk(args.ID, args.Image)
if err != nil {
return err
}
return nil
})
type InstanceChangeConfigOptions struct {
ID string `help:"instance ID"`
Ncpu int `help:"number of CPU"`
Vmem int `help:"MiB of memory"`
Disk []int `help:"Data disk sizes int GB"`
}
shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *aliyun.SRegion, args *InstanceChangeConfigOptions) error {
instance, e := cli.GetInstance(args.ID)
if e != nil {
return e
}
// todo : add create disks
err := cli.ChangeVMConfig(instance.ZoneId, args.ID, args.Ncpu, args.Vmem, nil)
if err != nil {
return err
}
return nil
})
type InstanceUpdatePasswordOptions struct {
ID string `help:"Instance ID"`
PASSWD string `help:"new password"`
+1 -1
View File
@@ -100,7 +100,7 @@ func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
}
func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
diskId, err := self.zone.region.createDisk(self.zone.ZoneId, self.storageType, name, sizeGb, desc)
diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, name, sizeGb, desc)
if err != nil {
log.Errorf("createDisk fail %s", err)
return nil, err
+1
View File
@@ -76,3 +76,4 @@ func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
}
return dc.istorages, nil
}
+1 -1
View File
@@ -89,4 +89,4 @@ func (self *SDatastore) GetManagerId() string {
func (self *SDatastore) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
return nil, cloudprovider.ErrNotImplemented
}
}
+20
View File
@@ -65,6 +65,22 @@ func (self *SVirtualMachine) IsEmulated() bool {
return false
}
func (self *SVirtualMachine) DeployVM(name string, password string, publicKey string, resetPassword bool, deleteKeypair bool, description string) error {
return cloudprovider.ErrNotImplemented
}
func (self *SVirtualMachine) RebuildRoot(imageId string) error {
return cloudprovider.ErrNotImplemented
}
func (self *SVirtualMachine) UpdateVM(name string) error {
return cloudprovider.ErrNotImplemented
}
func (self *SVirtualMachine) AttachDisk(diskId string) error {
return cloudprovider.ErrNotImplemented
}
func (self *SVirtualMachine) getUuid() string {
return self.getVirtualMachine().Summary.Config.Uuid
}
@@ -209,3 +225,7 @@ func (self *SVirtualMachine) acquireVmrcUrl() (jsonutils.JSONObject, error) {
ret.Add(jsonutils.NewString(url), "url")
return ret, nil
}
func (dc *SVirtualMachine) ChangeConfig(instanceId string,ncpu int, vmem int) error {
return cloudprovider.ErrNotImplemented
}