Merge pull request #76 in YUNIONIO/onecloud from ~TANGBIN/onecloud:feature/tb-aliyun-apis to release/2.1.0

* commit '8167aa0c85c388b3286b675bdd0705417d684854':
  增加CPU、内存变更判断
  阿里云调整配置等API
This commit is contained in:
邱剑
2018-08-25 18:17:41 +08:00
17 changed files with 668 additions and 165 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)
+1 -1
View File
@@ -155,7 +155,7 @@ type ICloudVM interface {
UpdateVM(name string) error
RebuildRoot(imageId string) error
DeployVM(resetPassword bool, keypair string, deleteKeypair bool) 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
+227 -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")
@@ -135,92 +133,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
}
@@ -278,3 +318,118 @@ 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)
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 {
err = iVM.ChangeConfig(config.InstanceId, config.Cpu, config.Memory)
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
@@ -493,9 +493,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")
}
@@ -1552,7 +1554,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")
@@ -1574,8 +1580,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", "")
@@ -1919,12 +1926,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
}
@@ -2457,16 +2462,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")
}
@@ -3438,4 +3454,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
}
+154 -45
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,73 @@ 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) 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 {
@@ -485,20 +554,44 @@ 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
}
func (self *SInstance) StopVM(isForce bool) error {
err := self.host.zone.region.StopVM(self.InstanceId, isForce)
if err != nil {
return err
// 修改密钥时直接返回
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 {
return self.modifyInstanceAttribute(instanceId, params)
} else {
return nil
}
return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) // 5mintues
}
func (self *SInstance) DeleteVM() error {
@@ -507,33 +600,69 @@ func (self *SInstance) DeleteVM() error {
if err != nil {
if isError(err, "IncorrectInstanceStatus.Initializing") {
log.Infof("The instance is initializing, try later ...")
time.Sleep(10*time.Second)
time.Sleep(10 * time.Second)
} else {
return err
}
}else {
} else {
break
}
}
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
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
}
passwd := seclib.RandomPassword(6)
err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd)
if err != nil {
return nil, err
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
}
}
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 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 nil
}
func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error {
@@ -561,23 +690,3 @@ func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules [
}
return nil
}
func (self *SInstance) UpdateVM(name string) error {
return fmt.Errorf("not implement")
}
func (self *SInstance) RebuildRoot(imageId string) error {
return fmt.Errorf("not implement")
}
func (self *SInstance) DeployVM(resetPassword bool, keypair string, deleteKeypair bool) error {
return fmt.Errorf("not implement")
}
func (self *SInstance) ChangeConfig(instanceId string,ncpu int, vmem int) error {
return fmt.Errorf("not implement")
}
func (self *SInstance) AttachDisk(diskId string) error {
return fmt.Errorf("not implement")
}
+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
}
}
+18 -18
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
}
@@ -210,22 +226,6 @@ func (self *SVirtualMachine) acquireVmrcUrl() (jsonutils.JSONObject, error) {
return ret, nil
}
func (self *SVirtualMachine) UpdateVM(name string) error {
return fmt.Errorf("not implement")
}
func (self *SVirtualMachine) RebuildRoot(imageId string) error {
return fmt.Errorf("not implement")
}
func (self *SVirtualMachine) DeployVM(resetPassword bool, keypair string, deleteKeypair bool) error {
return fmt.Errorf("not implement")
}
func (self *SVirtualMachine) ChangeConfig(instanceId string,ncpu int, vmem int) error {
return fmt.Errorf("not implement")
}
func (self *SVirtualMachine) AttachDisk(diskId string) error {
return fmt.Errorf("not implement")
func (dc *SVirtualMachine) ChangeConfig(instanceId string,ncpu int, vmem int) error {
return cloudprovider.ErrNotImplemented
}