mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
784 lines
23 KiB
Go
784 lines
23 KiB
Go
package aliyun
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/osprofile"
|
|
"yunion.io/x/pkg/util/seclib"
|
|
"yunion.io/x/pkg/util/secrules"
|
|
"yunion.io/x/pkg/utils"
|
|
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/compute/models"
|
|
)
|
|
|
|
const (
|
|
// Running:运行中
|
|
//Starting:启动中
|
|
//Stopping:停止中
|
|
//Stopped:已停止
|
|
|
|
InstanceStatusStopped = "Stopped"
|
|
InstanceStatusRunning = "Running"
|
|
InstanceStatusStopping = "Stopping"
|
|
InstanceStatusStarting = "Starting"
|
|
)
|
|
|
|
type SDedicatedHostAttribute struct {
|
|
DedicatedHostId string
|
|
DedicatedHostName string
|
|
}
|
|
|
|
type SIpAddress struct {
|
|
IpAddress []string
|
|
}
|
|
|
|
type SNetworkInterfaces struct {
|
|
NetworkInterface []SNetworkInterface
|
|
}
|
|
|
|
type SNetworkInterface struct {
|
|
MacAddress string
|
|
NetworkInterfaceId string
|
|
PrimaryIpAddress string
|
|
}
|
|
|
|
type SOperationLocks struct {
|
|
LockReason []string
|
|
}
|
|
|
|
type SSecurityGroupIds struct {
|
|
SecurityGroupId []string
|
|
}
|
|
|
|
// {"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"}
|
|
|
|
type SVpcAttributes struct {
|
|
NatIpAddress string
|
|
PrivateIpAddress SIpAddress
|
|
VSwitchId string
|
|
VpcId string
|
|
}
|
|
|
|
type SInstance struct {
|
|
host *SHost
|
|
|
|
// idisks []cloudprovider.ICloudDisk
|
|
|
|
AutoReleaseTime string
|
|
ClusterId string
|
|
Cpu int8
|
|
CreationTime time.Time
|
|
DedicatedHostAttribute SDedicatedHostAttribute
|
|
Description string
|
|
DeviceAvailable bool
|
|
EipAddress SEipAddress
|
|
ExpiredTime time.Time
|
|
GPUAmount int
|
|
GPUSpec string
|
|
HostName string
|
|
ImageId string
|
|
InnerIpAddress SIpAddress
|
|
InstanceChargeType InstanceChargeType
|
|
InstanceId string
|
|
InstanceName string
|
|
InstanceNetworkType string
|
|
InstanceType string
|
|
InstanceTypeFamily string
|
|
InternetChargeType string
|
|
InternetMaxBandwidthIn int
|
|
InternetMaxBandwidthOut int
|
|
IoOptimized bool
|
|
KeyPairName string
|
|
Memory int
|
|
NetworkInterfaces SNetworkInterfaces
|
|
OSName string
|
|
OSType string
|
|
OperationLocks SOperationLocks
|
|
PublicIpAddress SIpAddress
|
|
Recyclable bool
|
|
RegionId string
|
|
ResourceGroupId string
|
|
SaleCycle string
|
|
SecurityGroupIds SSecurityGroupIds
|
|
SerialNumber string
|
|
SpotPriceLimit string
|
|
SpotStrategy string
|
|
StartTime time.Time
|
|
Status string
|
|
StoppedMode string
|
|
VlanId string
|
|
VpcAttributes SVpcAttributes
|
|
ZoneId string
|
|
}
|
|
|
|
// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"}
|
|
|
|
func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) {
|
|
params := make(map[string]string)
|
|
params["RegionId"] = self.RegionId
|
|
|
|
if len(zoneId) > 0 {
|
|
params["ZoneId"] = zoneId
|
|
}
|
|
|
|
if ids != nil && len(ids) > 0 {
|
|
params["InstanceIds"] = jsonutils.Marshal(ids).String()
|
|
}
|
|
|
|
body, err := self.ecsRequest("DescribeInstances", params)
|
|
if err != nil {
|
|
log.Errorf("GetInstances fail %s", err)
|
|
return nil, 0, err
|
|
}
|
|
|
|
instances := make([]SInstance, 0)
|
|
err = body.Unmarshal(&instances, "Instances", "Instance")
|
|
if err != nil {
|
|
log.Errorf("Unmarshal security group details fail %s", err)
|
|
return nil, 0, err
|
|
}
|
|
total, _ := body.Int("TotalCount")
|
|
return instances, int(total), nil
|
|
}
|
|
|
|
func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
|
|
data := jsonutils.NewDict()
|
|
|
|
// The pricingInfo key structure is 'RegionId::InstanceType::NetworkType::OSType::IoOptimized'
|
|
optimized := "optimized"
|
|
if !self.IoOptimized {
|
|
optimized = "none"
|
|
}
|
|
priceKey := fmt.Sprintf("%s::%s::%s::%s::%s", self.RegionId, self.InstanceType, self.InstanceNetworkType, self.OSType, optimized)
|
|
data.Add(jsonutils.NewString(priceKey), "price_key")
|
|
|
|
if len(self.ImageId) > 0 {
|
|
if image, err := self.host.zone.region.GetImage(self.ImageId); err != nil {
|
|
log.Errorf("Failed to find image %s for instance %s", self.ImageId, self.GetName())
|
|
} else if meta := image.GetMetadata(); meta != nil {
|
|
data.Update(meta)
|
|
}
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
func (self *SInstance) GetCreateTime() time.Time {
|
|
return self.CreationTime
|
|
}
|
|
|
|
func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
|
|
return self.host
|
|
}
|
|
|
|
func (self *SInstance) GetId() string {
|
|
return self.InstanceId
|
|
}
|
|
|
|
func (self *SInstance) GetName() string {
|
|
return self.HostName
|
|
}
|
|
|
|
func (self *SInstance) GetGlobalId() string {
|
|
return self.InstanceId
|
|
}
|
|
|
|
func (self *SInstance) IsEmulated() bool {
|
|
return false
|
|
}
|
|
|
|
func (self *SInstance) getVpc() (*SVpc, error) {
|
|
return self.host.zone.region.getVpc(self.VpcAttributes.VpcId)
|
|
}
|
|
|
|
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
|
disks, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, 50)
|
|
if err != nil {
|
|
log.Errorf("fetchDisks fail %s", err)
|
|
return nil, err
|
|
}
|
|
if total > len(disks) {
|
|
disks, _, err = self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, total)
|
|
}
|
|
idisks := make([]cloudprovider.ICloudDisk, len(disks))
|
|
for i := 0; i < len(disks); i += 1 {
|
|
store, err := self.host.zone.getStorageByCategory(disks[i].Category)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
disks[i].storage = store
|
|
idisks[i] = &disks[i]
|
|
}
|
|
return idisks, nil
|
|
}
|
|
|
|
func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
|
nics := make([]cloudprovider.ICloudNic, 0)
|
|
for _, ip := range self.VpcAttributes.PrivateIpAddress.IpAddress {
|
|
nic := SInstanceNic{instance: self, ipAddr: ip}
|
|
nics = append(nics, &nic)
|
|
}
|
|
return nics, nil
|
|
}
|
|
|
|
func (self *SInstance) GetVcpuCount() int8 {
|
|
return self.Cpu
|
|
}
|
|
|
|
func (self *SInstance) GetVmemSizeMB() int {
|
|
return self.Memory
|
|
}
|
|
|
|
func (self *SInstance) GetBootOrder() string {
|
|
return "dcn"
|
|
}
|
|
|
|
func (self *SInstance) GetVga() string {
|
|
return "std"
|
|
}
|
|
|
|
func (self *SInstance) GetVdi() string {
|
|
return "vnc"
|
|
}
|
|
|
|
func (self *SInstance) GetOSType() string {
|
|
return osprofile.NormalizeOSType(self.OSType)
|
|
}
|
|
|
|
func (self *SInstance) GetOSName() string {
|
|
return self.OSName
|
|
}
|
|
|
|
func (self *SInstance) GetBios() string {
|
|
return "BIOS"
|
|
}
|
|
|
|
func (self *SInstance) GetMachine() string {
|
|
return "pc"
|
|
}
|
|
|
|
func (self *SInstance) GetStatus() string {
|
|
// Running:运行中
|
|
//Starting:启动中
|
|
//Stopping:停止中
|
|
//Stopped:已停止
|
|
switch self.Status {
|
|
case InstanceStatusRunning:
|
|
return models.VM_RUNNING
|
|
case InstanceStatusStarting:
|
|
return models.VM_STARTING
|
|
case InstanceStatusStopping:
|
|
return models.VM_STOPPING
|
|
case InstanceStatusStopped:
|
|
return models.VM_READY
|
|
default:
|
|
return models.VM_UNKNOWN
|
|
}
|
|
}
|
|
|
|
func (self *SInstance) Refresh() error {
|
|
new, err := self.host.zone.region.GetInstance(self.InstanceId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return jsonutils.Update(self, new)
|
|
}
|
|
|
|
/*
|
|
func (self *SInstance) GetRemoteStatus() string {
|
|
// Running:运行中
|
|
//Starting:启动中
|
|
//Stopping:停止中
|
|
//Stopped:已停止
|
|
switch self.Status {
|
|
case InstanceStatusRunning:
|
|
return cloudprovider.CloudVMStatusRunning
|
|
case InstanceStatusStarting:
|
|
return cloudprovider.CloudVMStatusStopped
|
|
case InstanceStatusStopping:
|
|
return cloudprovider.CloudVMStatusRunning
|
|
case InstanceStatusStopped:
|
|
return cloudprovider.CloudVMStatusStopped
|
|
default:
|
|
return cloudprovider.CloudVMStatusOther
|
|
}
|
|
}
|
|
*/
|
|
|
|
func (self *SInstance) GetHypervisor() string {
|
|
return models.HYPERVISOR_ALIYUN
|
|
}
|
|
|
|
func (self *SInstance) StartVM() error {
|
|
timeout := 300*time.Second
|
|
interval := 15*time.Second
|
|
|
|
startTime := time.Now()
|
|
for time.Now().Sub(startTime) < timeout {
|
|
err := self.Refresh()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Debugf("status %s expect %s", self.GetStatus(), models.VM_RUNNING)
|
|
if self.GetStatus() == models.VM_RUNNING {
|
|
return nil
|
|
} else if self.GetStatus() == models.VM_READY {
|
|
err := self.host.zone.region.StartVM(self.InstanceId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
time.Sleep(interval)
|
|
}
|
|
return cloudprovider.ErrTimeout
|
|
}
|
|
|
|
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, deleteKeypair bool, description string) error {
|
|
var keypairName string
|
|
if len(publicKey) > 0 {
|
|
var err error
|
|
keypairName, err = self.host.zone.region.syncKeypair(publicKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description)
|
|
}
|
|
|
|
func (self *SInstance) RebuildRoot(imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
|
|
keypair := ""
|
|
if len(publicKey) > 0 {
|
|
var err error
|
|
keypair, err = self.host.zone.region.syncKeypair(publicKey)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, imageId, passwd, keypair, sysSizeGB)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return diskId, nil
|
|
}
|
|
|
|
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 *SInstance) DetachDisk(diskId string) error {
|
|
return self.host.zone.region.DetachDisk(self.InstanceId, diskId)
|
|
}
|
|
|
|
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
|
|
instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(instances) == 0 {
|
|
return nil, cloudprovider.ErrNotFound
|
|
}
|
|
return &instances[0], nil
|
|
}
|
|
|
|
func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, securityGroupId string,
|
|
zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string,
|
|
keypair string) (string, error) {
|
|
params := make(map[string]string)
|
|
params["RegionId"] = self.RegionId
|
|
params["ImageId"] = imageId
|
|
params["InstanceType"] = instanceType
|
|
params["SecurityGroupId"] = securityGroupId
|
|
params["ZoneId"] = zoneId
|
|
params["InstanceName"] = name
|
|
params["Description"] = desc
|
|
params["InternetChargeType"] = "PayByTraffic"
|
|
params["InternetMaxBandwidthIn"] = "200"
|
|
params["InternetMaxBandwidthOut"] = "100"
|
|
params["HostName"] = name
|
|
if len(passwd) > 0 {
|
|
params["Password"] = passwd
|
|
} else {
|
|
params["PasswordInherit"] = "True"
|
|
}
|
|
params["IoOptimized"] = "optimized"
|
|
for i, d := range disks {
|
|
if i == 0 {
|
|
params["SystemDisk.Category"] = d.Category
|
|
params["SystemDisk.Size"] = fmt.Sprintf("%d", d.Size)
|
|
params["SystemDisk.DiskName"] = d.GetName()
|
|
params["SystemDisk.Description"] = d.Description
|
|
} else {
|
|
params[fmt.Sprintf("DataDisk.%d.Size", i)] = fmt.Sprintf("%d", d.Size)
|
|
params[fmt.Sprintf("DataDisk.%d.Category", i)] = d.Category
|
|
params[fmt.Sprintf("DataDisk.%d.DiskName", i)] = d.GetName()
|
|
params[fmt.Sprintf("DataDisk.%d.Description", i)] = d.Description
|
|
params[fmt.Sprintf("DataDisk.%d.Encrypted", i)] = "false"
|
|
}
|
|
}
|
|
params["VSwitchId"] = vSwitchId
|
|
params["PrivateIpAddress"] = ipAddr
|
|
params["InstanceChargeType"] = "PostPaid"
|
|
params["SpotStrategy"] = "NoSpot"
|
|
if len(keypair) > 0 {
|
|
params["KeyPairName"] = keypair
|
|
}
|
|
params["ClientToken"] = utils.GenRequestId(20)
|
|
|
|
body, err := self.ecsRequest("CreateInstance", params)
|
|
if err != nil {
|
|
log.Errorf("CreateInstance fail %s", err)
|
|
return "", err
|
|
}
|
|
instanceId, _ := body.GetString("InstanceId")
|
|
return instanceId, nil
|
|
}
|
|
|
|
func (self *SRegion) doStartVM(instanceId string) error {
|
|
return self.instanceOperation(instanceId, "StartInstance", nil)
|
|
}
|
|
|
|
func (self *SRegion) doStopVM(instanceId string, isForce bool) error {
|
|
params := make(map[string]string)
|
|
if isForce {
|
|
params["ForceStop"] = "true"
|
|
} else {
|
|
params["ForceStop"] = "false"
|
|
}
|
|
params["StoppedMode"] = "KeepCharging"
|
|
return self.instanceOperation(instanceId, "StopInstance", params)
|
|
}
|
|
|
|
func (self *SRegion) doDeleteVM(instanceId string) error {
|
|
params := make(map[string]string)
|
|
params["TerminateSubscription"] = "false"
|
|
params["Force"] = "true"
|
|
return self.instanceOperation(instanceId, "DeleteInstance", params)
|
|
}
|
|
|
|
/*func (self *SRegion) waitInstanceStatus(instanceId string, target string, interval time.Duration, timeout time.Duration) error {
|
|
startTime := time.Now()
|
|
for time.Now().Sub(startTime) < timeout {
|
|
status, err := self.GetInstanceStatus(instanceId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if status == target {
|
|
return nil
|
|
}
|
|
time.Sleep(interval)
|
|
}
|
|
return cloudprovider.ErrTimeout
|
|
}
|
|
|
|
func (self *SInstance) waitStatus(target string, interval time.Duration, timeout time.Duration) error {
|
|
return self.host.zone.region.waitInstanceStatus(self.InstanceId, target, interval, timeout)
|
|
}*/
|
|
|
|
func (self *SRegion) StartVM(instanceId string) error {
|
|
status, err := self.GetInstanceStatus(instanceId)
|
|
if err != nil {
|
|
log.Errorf("Fail to get instance status on StartVM: %s", err)
|
|
return err
|
|
}
|
|
if status != InstanceStatusStopped {
|
|
log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped)
|
|
return cloudprovider.ErrInvalidStatus
|
|
}
|
|
return self.doStartVM(instanceId)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// return self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*5, time.Second*180) // 3 minutes to timeout
|
|
}
|
|
|
|
func (self *SRegion) StopVM(instanceId string, isForce bool) error {
|
|
status, err := self.GetInstanceStatus(instanceId)
|
|
if err != nil {
|
|
log.Errorf("Fail to get instance status on StopVM: %s", err)
|
|
return err
|
|
}
|
|
if status != InstanceStatusRunning {
|
|
log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning)
|
|
return cloudprovider.ErrInvalidStatus
|
|
}
|
|
return self.doStopVM(instanceId, isForce)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// return self.waitInstanceStatus(instanceId, InstanceStatusStopped, time.Second*10, time.Second*300) // 5 minutes to timeout
|
|
}
|
|
|
|
func (self *SRegion) DeleteVM(instanceId string) error {
|
|
status, err := self.GetInstanceStatus(instanceId)
|
|
if err != nil {
|
|
log.Errorf("Fail to get instance status on DeleteVM: %s", err)
|
|
return err
|
|
}
|
|
log.Debugf("Instance status on delete is %s", status)
|
|
if status != InstanceStatusStopped {
|
|
log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped)
|
|
}
|
|
return self.doDeleteVM(instanceId)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// err = self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*10, time.Second*300) // 5 minutes to timeout
|
|
// if err == cloudprovider.ErrNotFound {
|
|
// return nil
|
|
// } else if err == nil {
|
|
// return cloudprovider.ErrTimeout
|
|
// } else {
|
|
// return err
|
|
// }
|
|
}
|
|
|
|
func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error {
|
|
instance, err := self.GetInstance(instanceId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 修改密钥时直接返回
|
|
if deleteKeypair {
|
|
err = self.DetachKeyPair(instanceId, instance.KeyPairName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if len(keypairName) > 0 {
|
|
err = self.AttachKeypair(instanceId, keypairName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
func (self *SInstance) DeleteVM() error {
|
|
for {
|
|
err := self.host.zone.region.DeleteVM(self.InstanceId)
|
|
if err != nil {
|
|
if isError(err, "IncorrectInstanceStatus.Initializing") {
|
|
log.Infof("The instance is initializing, try later ...")
|
|
time.Sleep(10 * time.Second)
|
|
} else {
|
|
return err
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
|
|
}
|
|
|
|
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, imageId string, passwd string, keypairName string, sysDiskSizeGB int) (string, error) {
|
|
params := make(map[string]string)
|
|
params["RegionId"] = self.RegionId
|
|
params["InstanceId"] = instanceId
|
|
params["ImageId"] = imageId
|
|
if len(passwd) > 0 {
|
|
params["Password"] = passwd
|
|
} else {
|
|
params["PasswordInherit"] = "True"
|
|
}
|
|
if len(keypairName) > 0 {
|
|
params["KeyPairName"] = keypairName
|
|
}
|
|
if sysDiskSizeGB > 0 {
|
|
params["SystemDisk.Size"] = fmt.Sprintf("%d", sysDiskSizeGB)
|
|
}
|
|
body, err := self.ecsRequest("ReplaceSystemDisk", params)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// log.Debugf("%s", body.String())
|
|
return body.GetString("DiskId")
|
|
}
|
|
|
|
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) DetachDisk(instanceId string, diskId string) error {
|
|
params := make(map[string]string)
|
|
params["InstanceId"] = instanceId
|
|
params["DiskId"] = diskId
|
|
log.Infof("Detach instance %s disk %s", instanceId, diskId)
|
|
_, err := self.ecsRequest("DetachDisk", params)
|
|
if err != nil {
|
|
log.Errorf("DetachDisk %s to %s fail %s", diskId, instanceId, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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 {
|
|
if vpc, err := self.getVpc(); err != nil {
|
|
return err
|
|
} else if len(secgroupId) == 0 {
|
|
for index, secgrpId := range self.SecurityGroupIds.SecurityGroupId {
|
|
if err := vpc.revokeSecurityGroup(secgrpId, self.InstanceId, index == 0); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else if secgrpId, err := vpc.SyncSecurityGroup(secgroupId, name, rules); err != nil {
|
|
return err
|
|
} else if err := vpc.assignSecurityGroup(secgrpId, self.InstanceId); err != nil {
|
|
return err
|
|
} else {
|
|
for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId {
|
|
if secgroupId != secgrpId {
|
|
if err := vpc.revokeSecurityGroup(secgroupId, self.InstanceId, false); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
self.SecurityGroupIds.SecurityGroupId = []string{secgrpId}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
|
|
if len(self.PublicIpAddress.IpAddress) > 0 {
|
|
eip := SEipAddress{}
|
|
eip.region = self.host.zone.region
|
|
eip.IpAddress = self.PublicIpAddress.IpAddress[0]
|
|
eip.InstanceId = self.InstanceId
|
|
eip.InstanceType = EIP_INSTANCE_TYPE_ECS
|
|
eip.Status = EIP_STATUS_INUSE
|
|
eip.AllocationId = self.InstanceId // fixed
|
|
eip.AllocationTime = self.CreationTime
|
|
eip.Bandwidth = self.InternetMaxBandwidthOut
|
|
eip.InternetChargeType = self.InternetChargeType
|
|
return &eip, nil
|
|
} else if len(self.EipAddress.IpAddress) > 0 {
|
|
return self.host.zone.region.GetEip(self.EipAddress.AllocationId)
|
|
} else {
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
func (self *SInstance) GetBillingType() string {
|
|
switch self.InstanceChargeType {
|
|
case PrePaidInstanceChargeType:
|
|
return models.BILLING_TYPE_PREPAID
|
|
case PostPaidInstanceChargeType:
|
|
return models.BILLING_TYPE_POSTPAID
|
|
default:
|
|
return models.BILLING_TYPE_PREPAID
|
|
}
|
|
}
|
|
|
|
func (self *SInstance) GetExpiredAt() time.Time {
|
|
return self.ExpiredTime
|
|
} |