mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 06:09:39 +08:00
Merge pull request #4428 from tb365/feature/tb-ctyun-operations
ctyun operations
This commit is contained in:
@@ -50,7 +50,7 @@ type ImageOptionalOptions struct {
|
||||
OsLang string `help:"OS Language" choices:"zh_CN|en_US"`
|
||||
Preference int64 `help:"Disk preferences"`
|
||||
Notes string `help:"Notes about the image"`
|
||||
Hypervisor []string `help:"Prefer hypervisor type" choices:"kvm|esxi|baremetal|container|openstack"`
|
||||
Hypervisor []string `help:"Prefer hypervisor type" choices:"kvm|esxi|baremetal|container|openstack|ctyun"`
|
||||
DiskDriver string `help:"Perfer disk driver" choices:"virtio|scsi|pvscsi|ide|sata"`
|
||||
NetDriver string `help:"Preferred network driver" choices:"virtio|e1000|vmxnet3"`
|
||||
}
|
||||
|
||||
@@ -679,8 +679,6 @@ yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa h1:+7zYi8MhaOW/53/7FOERnhQqAU
|
||||
yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20191226074733-6eb73845bfb7 h1:nK047S9fIjIBkB9Yyo2e6itUA7TpmFsd7/a6mGKjNU0=
|
||||
yunion.io/x/sqlchemy v0.0.0-20191226074733-6eb73845bfb7/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/sqlchemy v0.0.0-20200114051901-dfdc01cac3c3 h1:4OA/7udM060GPhj1hqX80Tu+lC2ziAcMrKpo+EG5LZA=
|
||||
yunion.io/x/sqlchemy v0.0.0-20200114051901-dfdc01cac3c3/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3 h1:bfC8EhXYvyGYldRWlzxiCM39Zfj3s3+zham9mW2h2LE=
|
||||
|
||||
@@ -634,6 +634,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestUndeployGuestOnHost(ctx conte
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
log.Errorf("ihost.GetIVMById fail %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+214
-20
@@ -16,10 +16,13 @@ package ctyun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -257,13 +260,44 @@ func (self *SDisk) GetAccessPath() string {
|
||||
}
|
||||
|
||||
func (self *SDisk) Delete(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
_, err := self.storage.zone.region.DeleteDisk(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SDisk.Delete")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
jobId, err := self.storage.zone.region.CreateSnapshot(name, self.GetId(), desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Disk.CreateISnapshot.CreateSnapshot")
|
||||
}
|
||||
|
||||
snapshotId := ""
|
||||
err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.storage.zone.region.GetVbsJob(jobId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
snapshotId, _ = statusJson.GetString("entities", "snapshot_id")
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("CreateSnapshot job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Disk.CreateISnapshot.Wait")
|
||||
}
|
||||
|
||||
return self.storage.zone.region.GetSnapshot(self.GetId(), snapshotId)
|
||||
}
|
||||
|
||||
// POST http://ctyun-api-url/apiproxy/v3/ondemand/createVBS
|
||||
func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) {
|
||||
return self.storage.zone.region.GetSnapshot(self.GetId(), idStr)
|
||||
}
|
||||
@@ -289,15 +323,61 @@ func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) {
|
||||
}
|
||||
|
||||
func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
jobId, err := self.storage.zone.region.ResizeDisk(self.GetId(), strconv.Itoa(int(newSizeMB/1024)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Disk.Resize")
|
||||
}
|
||||
|
||||
err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.storage.zone.region.GetVbsJob(jobId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("Resize job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Disk.Resize.Wait")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
jobId, err := self.storage.zone.region.RestoreDisk(self.GetId(), snapshotId)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Disk.Reset")
|
||||
}
|
||||
|
||||
err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.storage.zone.region.GetVbsJob(jobId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("Reset job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Disk.Reset.Wait")
|
||||
}
|
||||
|
||||
return self.GetId(), nil
|
||||
}
|
||||
|
||||
func (self *SDisk) Rebuild(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDiskDetails() (*DiskDetails, error) {
|
||||
@@ -414,26 +494,140 @@ func (self *SRegion) CreateDisk(zoneId, name, diskType, size string) (*SDisk, er
|
||||
"createVolumeInfo": diskParams,
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVolume", params)
|
||||
disks, err := self.GetDisks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateDisk.GetDisks")
|
||||
}
|
||||
|
||||
diskIds := []string{}
|
||||
for i := range disks {
|
||||
diskIds = append(diskIds, disks[i].GetId())
|
||||
}
|
||||
|
||||
_, err = self.client.DoPost("/apiproxy/v3/ondemand/createVolume", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Region.CreateDisk.DoPost")
|
||||
}
|
||||
|
||||
disk := &SDisk{}
|
||||
err = resp.Unmarshal(disk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Region.CreateDisk.Unmarshal")
|
||||
}
|
||||
// 查询job结果一直报错,目前先用替代办法查找新硬盘ID,可能不准确。后续需要替换其它方法
|
||||
diskId := ""
|
||||
cloudprovider.Wait(3*time.Second, 300*time.Second, func() (b bool, err error) {
|
||||
disks, err := self.GetDisks()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
izone, err := self.GetIZoneById(disk.AvailabilityZone)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateDisk.GetIZoneById")
|
||||
}
|
||||
for i := range disks {
|
||||
if !utils.IsInStringArray(disks[i].GetId(), diskIds) {
|
||||
diskId = disks[i].GetId()
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
disk.storage = &SStorage{
|
||||
zone: izone.(*SZone),
|
||||
storageType: disk.VolumeType,
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
|
||||
return disk, nil
|
||||
return self.GetDisk(diskId)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateSnapshot(name, volumeId, desc string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"volumeId": jsonutils.NewString(volumeId),
|
||||
"name": jsonutils.NewString(name),
|
||||
"description": jsonutils.NewString(desc),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVBS", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Region.CreateSnapshot.DoPost")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Region.CreateSnapshot.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteDisk(volumeId string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"volumeId": jsonutils.NewString(volumeId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVolume", params)
|
||||
if err != nil {
|
||||
msg, _ := resp.GetString("message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteDisk.DoPost")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.DeleteDisk.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) ResizeDisk(volumeId string, newSizeGB string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"volumeId": jsonutils.NewString(volumeId),
|
||||
"newSize": jsonutils.NewString(newSizeGB),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/expandVolumeSize", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.ResizeDisk.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ResizeDisk.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.ResizeDisk.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) RestoreDisk(volumeId, backupId string) (string, error) {
|
||||
diskBackupParams := jsonutils.NewDict()
|
||||
diskBackupParams.Set("regionId", jsonutils.NewString(self.GetId()))
|
||||
diskBackupParams.Set("backupId", jsonutils.NewString(backupId))
|
||||
diskBackupParams.Set("volumeId", jsonutils.NewString(volumeId))
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"diskBackup": diskBackupParams,
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/restoreDiskBackup", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.RestoreDisk.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RestoreDisk.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.RestoreDisk.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
+118
-10
@@ -15,6 +15,8 @@
|
||||
package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -185,19 +187,34 @@ func (self *SEip) GetInternetChargeType() string {
|
||||
}
|
||||
|
||||
func (self *SEip) Delete() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.region.DeleteEip(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SEip) Associate(instanceId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
nics, err := self.region.GetNics(instanceId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Eip.Associate.GetNics")
|
||||
}
|
||||
|
||||
if len(nics) == 0 {
|
||||
return errors.Wrap(fmt.Errorf("no network card found"), "Eip.Associate.GetINics")
|
||||
}
|
||||
|
||||
return self.region.AssociateEip(self.GetId(), nics[0].PortID)
|
||||
}
|
||||
|
||||
func (self *SEip) Dissociate() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
err := self.region.DissociateEip(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SEip) ChangeBandwidth(bw int) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.region.ChangeBandwidthEip(self.GetName(), self.GetId(), strconv.Itoa(bw))
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
@@ -257,7 +274,7 @@ func (self *SRegion) GetEip(eipId string) (*SEip, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateEip(zoneId, name, size, shareType string) (*SEip, error) {
|
||||
func (self *SRegion) CreateEip(zoneId, name, size, shareType, chargeType string) (*SEip, error) {
|
||||
eipParams := jsonutils.NewDict()
|
||||
eipParams.Set("regionId", jsonutils.NewString(self.GetId()))
|
||||
eipParams.Set("zoneId", jsonutils.NewString(zoneId))
|
||||
@@ -265,22 +282,113 @@ func (self *SRegion) CreateEip(zoneId, name, size, shareType string) (*SEip, err
|
||||
eipParams.Set("type", jsonutils.NewString("5_telcom"))
|
||||
eipParams.Set("size", jsonutils.NewString(size))
|
||||
eipParams.Set("shareType", jsonutils.NewString(shareType))
|
||||
eipParams.Set("chargeMode", jsonutils.NewString(chargeType))
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"createIpInfo": eipParams,
|
||||
}
|
||||
|
||||
eip := &SEip{}
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createIp", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateEip.DoPost")
|
||||
}
|
||||
|
||||
err = resp.Unmarshal(eip, "returnObj")
|
||||
eipId, err := resp.GetString("returnObj", "id")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateEip.Unmarshal")
|
||||
return nil, errors.Wrap(err, "SRegion.CreateEip.GetEipId")
|
||||
}
|
||||
|
||||
eip.region = self
|
||||
return eip, nil
|
||||
return self.GetEip(eipId)
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteEip(publicIpId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"publicIpId": jsonutils.NewString(publicIpId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteIp", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteEip.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("message")
|
||||
return errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteEip.JobFailed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 这里networkCardId 实际指的是port id
|
||||
func (self *SRegion) AssociateEip(publicIpId, networkCardId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"publicIpId": jsonutils.NewString(publicIpId),
|
||||
"networkCardId": jsonutils.NewString(networkCardId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/bindIp", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.AssociateEip.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DissociateEip(publicIpId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"publicIpId": jsonutils.NewString(publicIpId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/unbindIp", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DissociateEip.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type SBandwidth struct {
|
||||
PublicipInfo []PublicipInfo `json:"publicip_info"`
|
||||
EnterpriseProjectID string `json:"enterprise_project_id"`
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
ShareType string `json:"share_type"`
|
||||
Size int64 `json:"size"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
ChargeMode string `json:"charge_mode"`
|
||||
BandwidthType string `json:"bandwidth_type"`
|
||||
}
|
||||
|
||||
type PublicipInfo struct {
|
||||
PublicipType string `json:"publicip_type"`
|
||||
PublicipAddress string `json:"publicip_address"`
|
||||
IPVersion int64 `json:"ip_version"`
|
||||
PublicipID string `json:"publicip_id"`
|
||||
}
|
||||
|
||||
func (self *SRegion) ChangeBandwidthEip(name, publicIpId, sizeMb string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"publicIpId": jsonutils.NewString(publicIpId),
|
||||
"name": jsonutils.NewString(name),
|
||||
"size": jsonutils.NewString(sizeMb),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeNetwork", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.ChangeBandwidthEip.DoPost")
|
||||
}
|
||||
|
||||
bandwidth := SBandwidth{}
|
||||
err = resp.Unmarshal(&bandwidth, "returnObj")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.ChangeBandwidthEip.Unmarshal")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -160,7 +162,53 @@ func (self *SHost) GetVersion() string {
|
||||
}
|
||||
|
||||
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
network, err := self.zone.region.GetNetwork(desc.ExternalNetworkId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Host.CreateVM.GetNetwork")
|
||||
}
|
||||
|
||||
jobId, err := self.zone.region.CreateInstance(self.zone.GetId(), desc.Name, desc.ExternalImageId, desc.OsType, desc.SysDisk.StorageType, desc.InstanceType, network.VpcID, desc.ExternalNetworkId, desc.ExternalSecgroupId, desc.Password)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Host.CreateVM.CreateInstance")
|
||||
}
|
||||
|
||||
vmId := ""
|
||||
err = cloudprovider.Wait(10*time.Second, 600*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.zone.region.GetJob(jobId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "job fail") {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
jobs, err := statusJson.GetArray("entities", "sub_jobs")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(jobs) > 0 {
|
||||
vmId, err = jobs[0].GetString("entities", "server_id")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
return false, fmt.Errorf("CreateVM empty sub jobs")
|
||||
}
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("CreateVM job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Disk.CreateISnapshot.Wait")
|
||||
}
|
||||
|
||||
return self.zone.region.GetVMById(vmId)
|
||||
}
|
||||
|
||||
func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
|
||||
|
||||
@@ -98,7 +98,7 @@ func (self *SImage) GetMetadata() *jsonutils.JSONDict {
|
||||
}
|
||||
|
||||
func (self *SImage) Delete(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
|
||||
|
||||
@@ -17,6 +17,7 @@ package ctyun
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -402,11 +403,18 @@ func (self *SInstance) getSecurityGroupIdsByMasterOrderId(orderId string) ([]str
|
||||
}
|
||||
|
||||
func (self *SInstance) AssignSecurityGroup(secgroupId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.host.zone.region.AssignSecurityGroup(self.GetId(), secgroupId)
|
||||
}
|
||||
|
||||
func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
for i := 0; i < len(secgroupIds); i++ {
|
||||
err := self.host.zone.region.AssignSecurityGroup(self.GetId(), secgroupIds[i])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.SetSecurityGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetHypervisor() string {
|
||||
@@ -414,35 +422,144 @@ func (self *SInstance) GetHypervisor() string {
|
||||
}
|
||||
|
||||
func (self *SInstance) StartVM(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
err := self.host.zone.region.StartVM(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.StartVM")
|
||||
}
|
||||
|
||||
return cloudprovider.WaitStatus(self, api.VM_RUNNING, 5*time.Second, 300*time.Second)
|
||||
}
|
||||
|
||||
func (self *SInstance) StopVM(ctx context.Context, isForce bool) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
err := self.host.zone.region.StopVM(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.StopVM")
|
||||
}
|
||||
|
||||
return cloudprovider.WaitStatus(self, api.VM_READY, 5*time.Second, 300*time.Second)
|
||||
}
|
||||
|
||||
func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
err := self.host.zone.region.DeleteVM(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SInstance.DeleteVM")
|
||||
}
|
||||
|
||||
return cloudprovider.WaitDeleted(self, 10*time.Second, 180*time.Second)
|
||||
}
|
||||
|
||||
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SInstance) UpdateUserData(userData string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
|
||||
currentImage, err := self.GetImage()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Instance.RebuildRoot")
|
||||
}
|
||||
|
||||
publicKeyName := ""
|
||||
if len(config.PublicKey) > 0 {
|
||||
publicKeyName, err = self.host.zone.region.syncKeypair(config.PublicKey)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Instance.RebuildRoot.syncKeypair")
|
||||
}
|
||||
}
|
||||
|
||||
jobId := ""
|
||||
if currentImage.GetId() != config.ImageId {
|
||||
jobId, err = self.host.zone.region.SwitchVMOs(self.GetId(), config.Password, publicKeyName, config.ImageId)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SInstance.RebuildRoot.SwitchVMOs")
|
||||
}
|
||||
} else {
|
||||
jobId, err = self.host.zone.region.RebuildVM(self.GetId(), config.Password, publicKeyName)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SInstance.RebuildRoot.RebuildVM")
|
||||
}
|
||||
}
|
||||
|
||||
err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.host.zone.region.GetJob(jobId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "job fail") {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("RebuildRoot job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Instance.RebuildRoot.Wait")
|
||||
}
|
||||
|
||||
err = self.Refresh()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
idisks, err := self.GetIDisks()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(idisks) == 0 {
|
||||
return "", fmt.Errorf("server %s has no volume attached.", self.GetId())
|
||||
}
|
||||
|
||||
return idisks[0].GetId(), nil
|
||||
}
|
||||
|
||||
func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
if len(password) == 0 {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// 只支持重置密码
|
||||
return self.host.zone.region.ResetVMPassword(self.GetId(), password)
|
||||
}
|
||||
|
||||
func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
jobId, err := self.host.zone.region.ChangeVMConfig(self.GetId(), config.InstanceType)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.ChangeConfig")
|
||||
}
|
||||
|
||||
err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) {
|
||||
statusJson, err := self.host.zone.region.GetJob(jobId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "job fail") {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if status, _ := statusJson.GetString("status"); status == "SUCCESS" {
|
||||
return true, nil
|
||||
} else if status == "FAILED" {
|
||||
return false, fmt.Errorf("ChangeConfig job %s failed", jobId)
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.ChangeConfig.Wait")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// http://ctyun-api-url/apiproxy/v3/queryVncUrl
|
||||
@@ -458,20 +575,113 @@ func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SInstance) NextDeviceName() (string, error) {
|
||||
details, err := self.GetDetails()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDetails")
|
||||
}
|
||||
|
||||
disks := []*SDisk{}
|
||||
for i := range details.Volumes {
|
||||
disk, err := self.host.zone.region.GetDisk(details.Volumes[i].ID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDisk")
|
||||
}
|
||||
|
||||
disks = append(disks, disk)
|
||||
}
|
||||
|
||||
prefix := "s"
|
||||
if len(disks) > 0 && strings.Contains(disks[0].GetMountpoint(), "/vd") {
|
||||
prefix = "v"
|
||||
}
|
||||
|
||||
currents := []string{}
|
||||
for _, disk := range disks {
|
||||
currents = append(currents, strings.ToLower(disk.GetMountpoint()))
|
||||
}
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
device := fmt.Sprintf("/dev/%sd%s", prefix, string(98+i))
|
||||
if ok, _ := utils.InStringArray(device, currents); !ok {
|
||||
return device, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents)
|
||||
}
|
||||
|
||||
func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
device, err := self.NextDeviceName()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName")
|
||||
}
|
||||
|
||||
_, err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.AttachDisk")
|
||||
}
|
||||
|
||||
disk, err := self.host.zone.region.GetDisk(diskId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "AttachDisk.GetDisk")
|
||||
}
|
||||
|
||||
err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay")
|
||||
}
|
||||
|
||||
if disk.Status != "in-use" {
|
||||
return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
disk, err := self.host.zone.region.GetDisk(diskId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "DetachDisk.Wait")
|
||||
}
|
||||
|
||||
if len(disk.Attachments) == 0 {
|
||||
return errors.Wrap(err, "Instance.DetachDisk")
|
||||
}
|
||||
|
||||
_, err = self.host.zone.region.DetachDisk(self.GetId(), diskId, disk.Attachments[0].Device)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.DetachDisk")
|
||||
}
|
||||
|
||||
err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay")
|
||||
}
|
||||
|
||||
if disk.Status != "available" {
|
||||
return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
_, err := self.host.zone.region.CreateDisk(self.host.zone.GetId(), uuid, driver, strconv.Itoa(sizeMb))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.CreateDisk")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SInstance) Renew(bc billing.SBillingCycle) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
_, err := self.host.zone.region.RenewVM(self.GetId(), &bc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Instance.Renew.RenewVM")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetError() error {
|
||||
@@ -549,7 +759,11 @@ func (self *SRegion) GetInstanceVNCUrl(vmId string) (string, error) {
|
||||
return ret.URL, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateInstance(zoneId, name, imageId, volumetype, flavorRef, vpcid, subnetId, secGroupId, adminPass string) error {
|
||||
/*
|
||||
创建主机接口目前没有绑定密钥的参数选项,不支持绑定密码。
|
||||
但是重装系统接口支持绑定密钥
|
||||
*/
|
||||
func (self *SRegion) CreateInstance(zoneId, name, imageId, osType, volumetype, flavorRef, vpcid, subnetId, secGroupId, adminPass string) (string, error) {
|
||||
rootParams := jsonutils.NewDict()
|
||||
rootParams.Set("volumetype", jsonutils.NewString(volumetype))
|
||||
|
||||
@@ -572,8 +786,7 @@ func (self *SRegion) CreateInstance(zoneId, name, imageId, volumetype, flavorRef
|
||||
serverParams.Set("imageRef", jsonutils.NewString(imageId))
|
||||
serverParams.Set("root_volume", rootParams)
|
||||
serverParams.Set("flavorRef", jsonutils.NewString(flavorRef))
|
||||
// todo: fix me
|
||||
serverParams.Set("osType", jsonutils.NewString("Linux"))
|
||||
serverParams.Set("osType", jsonutils.NewString(osType))
|
||||
serverParams.Set("vpcid", jsonutils.NewString(vpcid))
|
||||
serverParams.Set("security_groups", secgroupParams)
|
||||
serverParams.Set("nics", nicParams)
|
||||
@@ -588,12 +801,25 @@ func (self *SRegion) CreateInstance(zoneId, name, imageId, volumetype, flavorRef
|
||||
"createVMInfo": vmParams,
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/createVM", params)
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVM", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.CreateInstance.DoPost")
|
||||
return "", errors.Wrap(err, "SRegion.CreateInstance.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.CreateInstance.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.CreateInstance.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
// vm & nic job
|
||||
@@ -637,3 +863,337 @@ func (self *SRegion) GetVbsJob(jobId string) (jsonutils.JSONObject, error) {
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// POST http://ctyun-api-url/apiproxy/v3/addSecurityGroup 绑定安全组
|
||||
func (self *SRegion) AssignSecurityGroup(vmId, securityGroupRuleId string) error {
|
||||
securityParams := jsonutils.NewDict()
|
||||
securityParams.Set("regionId", jsonutils.NewString(self.GetId()))
|
||||
securityParams.Set("vmId", jsonutils.NewString(vmId))
|
||||
securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId))
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"securityGroup": securityParams,
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/addSecurityGroup", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.AssignSecurityGroup.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// POST http://ctyun-api-url/apiproxy/v3/removeSecurityGroup 解绑安全组
|
||||
func (self *SRegion) UnsignSecurityGroup(vmId, securityGroupRuleId string) error {
|
||||
securityParams := jsonutils.NewDict()
|
||||
securityParams.Set("regionId", jsonutils.NewString(self.GetId()))
|
||||
securityParams.Set("vmId", jsonutils.NewString(vmId))
|
||||
securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId))
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"securityGroup": securityParams,
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/removeSecurityGroup", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.UnsignSecurityGroup.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) StartVM(vmId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/startVM", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.StartVm.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) StopVM(vmId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/stopVM", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.StopVM.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteVM(vmId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVM", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteVM.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) RestartVM(vmId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"type": jsonutils.NewString("SOFT"),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/ondemand/restartVM", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.RestartVM.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) SwitchVMOs(vmId, adminPass, keyName, imageRef string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"imageRef": jsonutils.NewString(imageRef),
|
||||
}
|
||||
|
||||
if len(keyName) > 0 {
|
||||
params["keyName"] = jsonutils.NewString(keyName)
|
||||
} else if len(adminPass) > 0 {
|
||||
params["adminPass"] = jsonutils.NewString(adminPass)
|
||||
} else {
|
||||
return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.SwitchVMOs")
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/switchSys", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.SwitchVMOs.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.SwitchVMOs.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.SwitchVMOs.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) RebuildVM(vmId, adminPass, keyName string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
}
|
||||
|
||||
if len(keyName) > 0 {
|
||||
params["keyName"] = jsonutils.NewString(keyName)
|
||||
} else if len(adminPass) > 0 {
|
||||
params["adminPass"] = jsonutils.NewString(adminPass)
|
||||
} else {
|
||||
return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.RebuildVM")
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/reInstallSys", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.RebuildVM.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RebuildVM.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.RebuildVM.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) AttachDisk(vmId, volumeId, device string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"volumeId": jsonutils.NewString(volumeId),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"device": jsonutils.NewString(device),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/attachVolume", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.AttachDisk.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.AttachDisk.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.AttachDisk.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DetachDisk(vmId, volumeId, device string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"volumeId": jsonutils.NewString(volumeId),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"device": jsonutils.NewString(device),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/uninstallVolume", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.DetachDisk.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DetachDisk.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.DetachDisk.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) ChangeVMConfig(vmId, flavorId string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"flavorId": jsonutils.NewString(flavorId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeVM", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.ChangeVMConfig.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ChangeVMConfig.JobFailed")
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.ChangeVMConfig.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
// POST http://ctyun-api-url/apiproxy/v3/order/placeRenewOrder 续订
|
||||
func (self *SRegion) RenewVM(vmId string, bc *billing.SBillingCycle) ([]string, error) {
|
||||
if bc == nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("SBillingCycle is nil"), "Region.RenewVM")
|
||||
}
|
||||
|
||||
resourcePackage := jsonutils.NewDict()
|
||||
month := bc.GetMonths()
|
||||
switch {
|
||||
case month <= 11:
|
||||
resourcePackage.Set("cycleCount", jsonutils.NewString(strconv.Itoa(month)))
|
||||
resourcePackage.Set("cycleType", jsonutils.NewString("3"))
|
||||
case month == 12:
|
||||
resourcePackage.Set("cycleCount", jsonutils.NewString("1"))
|
||||
resourcePackage.Set("cycleType", jsonutils.NewString("5"))
|
||||
case month == 24:
|
||||
resourcePackage.Set("cycleCount", jsonutils.NewString("1"))
|
||||
resourcePackage.Set("cycleType", jsonutils.NewString("6"))
|
||||
case month == 36:
|
||||
resourcePackage.Set("cycleCount", jsonutils.NewString("1"))
|
||||
resourcePackage.Set("cycleType", jsonutils.NewString("7"))
|
||||
default:
|
||||
return nil, errors.Wrap(fmt.Errorf("unsupported month duration %d. expected 1~11, 12, 24, 36", month), "Region.RenewVM")
|
||||
}
|
||||
|
||||
vmIds := jsonutils.NewArray()
|
||||
vmIds.Add(jsonutils.NewString(vmId))
|
||||
resourcePackage.Set("resourceIds", vmIds)
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"resourceDetailJson": resourcePackage,
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/order/placeRenewOrder", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.RenewVM.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "submitted")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("returnObj", "message")
|
||||
return nil, errors.Wrap(fmt.Errorf(msg), "SRegion.RenewVM.JobFailed")
|
||||
}
|
||||
|
||||
type OrderPlacedEventsElement struct {
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Submitted bool `json:"submitted"`
|
||||
NewOrderID string `json:"newOrderId"`
|
||||
NewOrderNo string `json:"newOrderNo"`
|
||||
TotalPrice int64 `json:"totalPrice"`
|
||||
}
|
||||
|
||||
orders := []OrderPlacedEventsElement{}
|
||||
err = resp.Unmarshal(&orders, "returnObj", "orderPlacedEvents")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.RenewVM.Unmarshal")
|
||||
}
|
||||
|
||||
orderIds := []string{}
|
||||
for i := range orders {
|
||||
orderIds = append(orderIds, orders[i].NewOrderID)
|
||||
}
|
||||
|
||||
return orderIds, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) ResetVMPassword(vmId, password string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vmId": jsonutils.NewString(vmId),
|
||||
"password": jsonutils.NewString(password),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/resetVmPassword", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.ResetVMPassword.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,140 @@
|
||||
|
||||
package ctyun
|
||||
|
||||
// http://ctyun-api-url/apiproxy/v3/order/getZoneConfig
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aokoli/goutils"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
// GET http://ctyun-api-url/apiproxy/v3/querySSH
|
||||
// POST http://ctyun-api-url/apiproxy/v3/deleteSSH
|
||||
type SKeypair struct {
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
Name string `json:"name"`
|
||||
PublicKey string `json:"public_key"`
|
||||
}
|
||||
|
||||
func (self *SRegion) getFingerprint(publicKey string) (string, error) {
|
||||
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("publicKey error %s", err)
|
||||
}
|
||||
|
||||
return ssh.FingerprintSHA256(pk), nil
|
||||
}
|
||||
|
||||
// GET http://ctyun-api-url/apiproxy/v3/querySSH
|
||||
func (self *SRegion) GetKeypairs() ([]SKeypair, int, error) {
|
||||
params := map[string]string{
|
||||
"regionId": self.GetId(),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoGet("/apiproxy/v3/querySSH", params)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.DoGet")
|
||||
}
|
||||
|
||||
keypairs := []jsonutils.JSONObject{}
|
||||
err = resp.Unmarshal(&keypairs, "returnObj", "keypairs")
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.Unmarshal")
|
||||
}
|
||||
|
||||
ret := []SKeypair{}
|
||||
for i := range keypairs {
|
||||
k, err := keypairs[i].Get("keypair")
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs")
|
||||
}
|
||||
|
||||
keypair := SKeypair{}
|
||||
err = k.Unmarshal(&keypair)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.Unmarshal")
|
||||
}
|
||||
|
||||
ret = append(ret, keypair)
|
||||
}
|
||||
|
||||
return ret, len(ret), nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetKeypair(name string) (*SKeypair, error) {
|
||||
keypairs, _, err := self.GetKeypairs()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.GetKeypair.GetKeypairs")
|
||||
}
|
||||
|
||||
for i := range keypairs {
|
||||
if keypairs[i].Name == name {
|
||||
return &keypairs[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.Wrap(errors.ErrNotFound, "SRegion.GetKeypair")
|
||||
}
|
||||
|
||||
func (self *SRegion) lookUpKeypair(publicKey string) (string, error) {
|
||||
keypairs, _, err := self.GetKeypairs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fingerprint, err := self.getFingerprint(publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, keypair := range keypairs {
|
||||
if keypair.Fingerprint == fingerprint {
|
||||
return keypair.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("keypair not found %s", err)
|
||||
}
|
||||
|
||||
// POST http://ctyun-api-url/apiproxy/v3/createSSH
|
||||
func (self *SRegion) ImportKeypair(name, publicKey string) (*SKeypair, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"name": jsonutils.NewString(name),
|
||||
"publicKey": jsonutils.NewString(publicKey),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/createSSH", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.ImportKeypair.DoPost")
|
||||
}
|
||||
|
||||
return self.GetKeypair(name)
|
||||
}
|
||||
|
||||
func (self *SRegion) importKeypair(publicKey string) (string, error) {
|
||||
prefix, e := goutils.RandomAlphabetic(6)
|
||||
if e != nil {
|
||||
return "", fmt.Errorf("publicKey error %s", e)
|
||||
}
|
||||
|
||||
name := prefix + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
if k, e := self.ImportKeypair(name, publicKey); e != nil {
|
||||
return "", fmt.Errorf("keypair import error %s", e)
|
||||
} else {
|
||||
return k.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) syncKeypair(publicKey string) (string, error) {
|
||||
name, e := self.lookUpKeypair(publicKey)
|
||||
if e == nil {
|
||||
return name, nil
|
||||
}
|
||||
return self.importKeypair(publicKey)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -133,7 +137,7 @@ func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope {
|
||||
}
|
||||
|
||||
func (self *SNetwork) Delete() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.vpc.region.DeleteNetwork(self.vpc.GetId(), self.GetId())
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetAllocTimeoutSeconds() int {
|
||||
@@ -218,13 +222,18 @@ func (self *SRegion) GetNetwork(subnetId string) (*SNetwork, error) {
|
||||
return network, err
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateNetwork(vpcId, zoneId, name, cidr, gatewayIp, dhcpEnable string) (*SNetwork, error) {
|
||||
func (self *SRegion) CreateNetwork(vpcId, zoneId, name, cidr, dhcpEnable string) (*SNetwork, error) {
|
||||
gateway, err := getDefaultGateWay(cidr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
networkParams := jsonutils.NewDict()
|
||||
networkParams.Set("regionId", jsonutils.NewString(self.GetId()))
|
||||
networkParams.Set("zoneId", jsonutils.NewString(zoneId))
|
||||
networkParams.Set("name", jsonutils.NewString(name))
|
||||
networkParams.Set("cidr", jsonutils.NewString(cidr))
|
||||
networkParams.Set("gatewayIp", jsonutils.NewString(gatewayIp))
|
||||
networkParams.Set("gatewayIp", jsonutils.NewString(gateway))
|
||||
networkParams.Set("dhcpEnable", jsonutils.NewString(dhcpEnable))
|
||||
networkParams.Set("vpcId", jsonutils.NewString(vpcId))
|
||||
// DNS地址,如果主机需要访问公网就需要填写该值,不填写就不能使用DNS解析
|
||||
@@ -235,16 +244,53 @@ func (self *SRegion) CreateNetwork(vpcId, zoneId, name, cidr, gatewayIp, dhcpEna
|
||||
"jsonStr": networkParams,
|
||||
}
|
||||
|
||||
network := &SNetwork{}
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/createSubnet", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateNetwork.DoPost")
|
||||
}
|
||||
|
||||
err = resp.Unmarshal(network, "returnObj")
|
||||
netId, err := resp.GetString("returnObj", "id")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateNetwork.Unmarshal")
|
||||
return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetString")
|
||||
}
|
||||
|
||||
return network, err
|
||||
err = cloudprovider.WaitCreated(10*time.Second, 180*time.Second, func() bool {
|
||||
network, err := self.getNetwork(netId)
|
||||
if err != nil {
|
||||
log.Debugf("SRegion.CreateNetwork.getNetwork")
|
||||
return false
|
||||
}
|
||||
|
||||
if len(network.VpcID) == 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetVpc")
|
||||
}
|
||||
|
||||
return self.GetNetwork(netId)
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteNetwork(vpcId, subnetId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vpcId": jsonutils.NewString(vpcId),
|
||||
"subnetId": jsonutils.NewString(subnetId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/deleteSubnet", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteNetwork.DoPost")
|
||||
}
|
||||
|
||||
var statusCode int
|
||||
err = resp.Unmarshal(&statusCode, "statusCode")
|
||||
if statusCode != 800 {
|
||||
return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteNetwork.Failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -142,7 +143,17 @@ func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudpr
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
secgroup, err := self.CreateSecurityGroup(conf.VpcId, conf.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Region.CreateISecurityGroup")
|
||||
}
|
||||
|
||||
err = self.syncSecgroupRules(secgroup.GetId(), conf.Rules)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Region.CreateISecurityGroup.syncSecgroupRules")
|
||||
}
|
||||
|
||||
return secgroup, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetId() string {
|
||||
@@ -257,20 +268,63 @@ func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
|
||||
return self.GetDisk(id)
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
func (self *SRegion) DeleteSecurityGroup(securityGroupId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"securityGroupId": jsonutils.NewString(securityGroupId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("statusCode", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteSecurityGroup.DoPost")
|
||||
}
|
||||
|
||||
var statusCode int
|
||||
err = resp.Unmarshal(&statusCode, "statusCode")
|
||||
if statusCode != 800 {
|
||||
return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteSecurityGroup.JobFailed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
if len(secgroupId) > 0 {
|
||||
_, err := self.GetSecurityGroupDetails(secgroupId)
|
||||
if err == cloudprovider.ErrNotFound {
|
||||
secgroupId = ""
|
||||
} else if err != nil {
|
||||
return "", errors.Wrapf(err, "self.GetSecurityGroupDetails(%s)", secgroupId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(secgroupId) == 0 {
|
||||
secgroup, err := self.CreateSecurityGroup(vpcId, name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "self.CreateSecurityGroup")
|
||||
}
|
||||
secgroupId = secgroup.GetId()
|
||||
}
|
||||
|
||||
rules = SecurityRuleSetToAllowSet(rules)
|
||||
return secgroupId, self.syncSecgroupRules(secgroupId, rules)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
return self.CreateVpc(name, cidr)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
zones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateEIP.GetIZones")
|
||||
}
|
||||
|
||||
if len(zones) == 0 {
|
||||
return nil, errors.Wrap(errors.ErrNotFound, "SRegion.CreateEIP.GetIZones")
|
||||
}
|
||||
|
||||
return self.CreateEip(zones[0].GetId(), eip.Name, strconv.Itoa(eip.BandwidthMbps), "PER", eip.ChargeType)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
@@ -310,7 +364,7 @@ func (self *SRegion) UpdateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput, st
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteSnapshotPolicy(string) error {
|
||||
func (self *SRegion) DeleteSnapshotPolicy(policyId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
|
||||
@@ -15,20 +15,21 @@
|
||||
package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SSecurityGroup struct {
|
||||
region *SRegion
|
||||
vpc *SVpc
|
||||
|
||||
ID string `json:"id"`
|
||||
ResSecurityGroupID string `json:"resSecurityGroupId"`
|
||||
Name string `json:"name"`
|
||||
AccountID string `json:"accountId"`
|
||||
@@ -40,12 +41,179 @@ type SSecurityGroup struct {
|
||||
Status int64 `json:"status"`
|
||||
}
|
||||
|
||||
// 将安全组规则全部转换为等价的allow规则
|
||||
func SecurityRuleSetToAllowSet(srs secrules.SecurityRuleSet) secrules.SecurityRuleSet {
|
||||
inRuleSet := secrules.SecurityRuleSet{}
|
||||
outRuleSet := secrules.SecurityRuleSet{}
|
||||
|
||||
for _, rule := range srs {
|
||||
if rule.Direction == secrules.SecurityRuleIngress {
|
||||
inRuleSet = append(inRuleSet, rule)
|
||||
}
|
||||
|
||||
if rule.Direction == secrules.SecurityRuleEgress {
|
||||
outRuleSet = append(outRuleSet, rule)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(inRuleSet)
|
||||
sort.Sort(outRuleSet)
|
||||
|
||||
inRuleSet = inRuleSet.AllowList()
|
||||
// out方向空规则默认全部放行
|
||||
if outRuleSet.Len() == 0 {
|
||||
_, ipNet, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
outRuleSet = append(outRuleSet, secrules.SecurityRule{
|
||||
Priority: 0,
|
||||
Action: secrules.SecurityRuleAllow,
|
||||
IPNet: ipNet,
|
||||
Protocol: secrules.PROTO_ANY,
|
||||
Direction: secrules.SecurityRuleEgress,
|
||||
PortStart: -1,
|
||||
PortEnd: -1,
|
||||
})
|
||||
}
|
||||
outRuleSet = outRuleSet.AllowList()
|
||||
|
||||
ret := secrules.SecurityRuleSet{}
|
||||
ret = append(ret, inRuleSet...)
|
||||
ret = append(ret, outRuleSet...)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetRulesWithExtId() ([]secrules.SecurityRule, error) {
|
||||
_rules, err := self.region.GetSecurityGroupRules(self.GetId())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SSecurityGroup.GetRulesWithExtId.GetSecurityGroupRules")
|
||||
}
|
||||
|
||||
rules := make([]secrules.SecurityRule, 0)
|
||||
for _, r := range _rules {
|
||||
if !compatibleSecurityGroupRule(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
rule, err := self.GetSecurityRule(r, true)
|
||||
if err != nil {
|
||||
return rules, err
|
||||
}
|
||||
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
|
||||
var DeleteRules []secrules.SecurityRule
|
||||
var AddRules []secrules.SecurityRule
|
||||
|
||||
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
|
||||
return errors.Wrapf(err, "syncSecgroupRules.GetSecurityGroupDetails(%s)", secgroupId)
|
||||
} else {
|
||||
remoteRules, err := secgroup.GetRulesWithExtId()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "secgroup.GetRulesWithExtId")
|
||||
}
|
||||
|
||||
sort.Sort(secrules.SecurityRuleSet(rules))
|
||||
sort.Sort(secrules.SecurityRuleSet(remoteRules))
|
||||
|
||||
i, j := 0, 0
|
||||
for i < len(rules) || j < len(remoteRules) {
|
||||
if i < len(rules) && j < len(remoteRules) {
|
||||
permissionStr := remoteRules[j].String()
|
||||
ruleStr := rules[i].String()
|
||||
cmp := strings.Compare(permissionStr, ruleStr)
|
||||
if cmp == 0 {
|
||||
// DeleteRules = append(DeleteRules, remoteRules[j])
|
||||
// AddRules = append(AddRules, rules[i])
|
||||
i += 1
|
||||
j += 1
|
||||
} else if cmp > 0 {
|
||||
DeleteRules = append(DeleteRules, remoteRules[j])
|
||||
j += 1
|
||||
} else {
|
||||
AddRules = append(AddRules, rules[i])
|
||||
i += 1
|
||||
}
|
||||
} else if i >= len(rules) {
|
||||
DeleteRules = append(DeleteRules, remoteRules[j])
|
||||
j += 1
|
||||
} else if j >= len(remoteRules) {
|
||||
AddRules = append(AddRules, rules[i])
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range DeleteRules {
|
||||
// r.Description 实际存储的是ruleId
|
||||
if err := self.delSecurityGroupRule(r.Description); err != nil {
|
||||
log.Errorf("delSecurityGroupRule %v error: %s", r, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range AddRules {
|
||||
if err := self.addSecurityGroupRules(secgroupId, &r); err != nil {
|
||||
log.Errorf("addSecurityGroupRule %v error: %s", r, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
|
||||
return self.DeleteSecurityGroupRule(secGrpRuleId)
|
||||
}
|
||||
|
||||
func (self *SRegion) addSecurityGroupRules(secGrpId string, rule *secrules.SecurityRule) error {
|
||||
direction := ""
|
||||
if rule.Direction == secrules.SecurityRuleIngress {
|
||||
direction = "ingress"
|
||||
} else {
|
||||
direction = "egress"
|
||||
}
|
||||
|
||||
protocal := rule.Protocol
|
||||
if rule.Protocol == secrules.PROTO_ANY {
|
||||
protocal = ""
|
||||
}
|
||||
|
||||
// imcp协议默认为any
|
||||
if rule.Protocol == secrules.PROTO_ICMP {
|
||||
return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String())
|
||||
}
|
||||
|
||||
if len(rule.Ports) > 0 {
|
||||
for _, port := range rule.Ports {
|
||||
portStr := fmt.Sprintf("%d", port)
|
||||
err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
portStart := fmt.Sprintf("%d", rule.PortStart)
|
||||
portEnd := fmt.Sprintf("%d", rule.PortEnd)
|
||||
err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
rules = SecurityRuleSetToAllowSet(rules)
|
||||
return self.region.syncSecgroupRules(self.ResSecurityGroupID, rules)
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) Delete() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.region.DeleteSecurityGroup(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetId() string {
|
||||
@@ -252,10 +420,14 @@ func (self *SRegion) CreateSecurityGroup(vpcId, name string) (*SSecurityGroup, e
|
||||
return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.DoPost")
|
||||
}
|
||||
|
||||
ret := &SSecurityGroup{}
|
||||
err = resp.Unmarshal(ret, "returnObj")
|
||||
secgroupId, err := resp.GetString("returnObj", "id")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.Unmarshal")
|
||||
return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetSecgroupId")
|
||||
}
|
||||
|
||||
secgroup, err := self.GetSecurityGroupDetails(secgroupId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetISecurityGroupById")
|
||||
}
|
||||
|
||||
vpc, err := self.GetVpc(vpcId)
|
||||
@@ -263,7 +435,57 @@ func (self *SRegion) CreateSecurityGroup(vpcId, name string) (*SSecurityGroup, e
|
||||
return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetVpc")
|
||||
}
|
||||
|
||||
ret.vpc = vpc
|
||||
ret.region = self
|
||||
return ret, nil
|
||||
secgroup.vpc = vpc
|
||||
secgroup.region = self
|
||||
return secgroup, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteSecurityGroupRule(securityGroupRuleId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"securityGroupRuleId": jsonutils.NewString(securityGroupRuleId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroupRule", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteSecurityGroupRule.DoPost")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error {
|
||||
secgroupObj := jsonutils.NewDict()
|
||||
secgroupObj.Add(jsonutils.NewString(self.GetId()), "regionId")
|
||||
secgroupObj.Add(jsonutils.NewString(secGrpId), "securityGroupId")
|
||||
secgroupObj.Add(jsonutils.NewString(direction), "direction")
|
||||
secgroupObj.Add(jsonutils.NewString(ipNet), "remoteIpPrefix")
|
||||
secgroupObj.Add(jsonutils.NewString("IPv4"), "ethertype")
|
||||
// 端口为空或者1-65535
|
||||
if len(portStart) > 0 && portStart != "0" && portStart != "-1" {
|
||||
secgroupObj.Add(jsonutils.NewString(portStart), "portRangeMin")
|
||||
}
|
||||
if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" {
|
||||
secgroupObj.Add(jsonutils.NewString(portEnd), "portRangeMax")
|
||||
}
|
||||
if len(protocol) > 0 {
|
||||
secgroupObj.Add(jsonutils.NewString(protocol), "protocol")
|
||||
}
|
||||
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"jsonStr": secgroupObj,
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroupRule", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DoPost")
|
||||
}
|
||||
|
||||
rule := SSecurityGroupRule{}
|
||||
err = resp.Unmarshal(&rule, "returnObj")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.Unmarshal")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -32,13 +32,14 @@ func init() {
|
||||
})
|
||||
|
||||
type EipCreateOptions struct {
|
||||
ZoneId string `help:"zone id"`
|
||||
Name string `help:"eip name"`
|
||||
Size string `help:"size"`
|
||||
ShareType string `help:"share type" choice:"PER|WHOLE"`
|
||||
ZoneId string `help:"zone id"`
|
||||
Name string `help:"eip name"`
|
||||
Size string `help:"size"`
|
||||
ShareType string `help:"share type" choice:"PER|WHOLE"`
|
||||
ChargeMode string `help:"charge mode" choice:"bandwidth|traffic"`
|
||||
}
|
||||
shellutils.R(&EipCreateOptions{}, "eip-create", "Create eip", func(cli *ctyun.SRegion, args *EipCreateOptions) error {
|
||||
eip, e := cli.CreateEip(args.ZoneId, args.Name, args.Size, args.ShareType)
|
||||
eip, e := cli.CreateEip(args.ZoneId, args.Name, args.Size, args.ShareType, args.ChargeMode)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ func init() {
|
||||
NAME string `help:"name of instance"`
|
||||
ADMINPASS string `help:"admin password of instance"`
|
||||
ImageId string `help:"image Id of instance"`
|
||||
OsType string `help:"Os type of image"`
|
||||
VolumeType string `help:"volume type of instance"`
|
||||
Flavor string `help:"Flavor of instance"`
|
||||
VpcId string `help:"Vpc of instance"`
|
||||
@@ -45,7 +46,7 @@ func init() {
|
||||
}
|
||||
|
||||
shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create intance", func(cli *ctyun.SRegion, args *InstanceCreateOptions) error {
|
||||
e := cli.CreateInstance(args.ZoneId, args.NAME, args.ImageId, args.VolumeType, args.Flavor, args.VpcId, args.SubnetId, args.SecGroupId, args.ADMINPASS)
|
||||
_, e := cli.CreateInstance(args.ZoneId, args.NAME, args.ImageId, args.OsType, args.VolumeType, args.Flavor, args.VpcId, args.SubnetId, args.SecGroupId, args.ADMINPASS)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func init() {
|
||||
DhcpEnable string `help:"gateway ip" choice:"true|false"`
|
||||
}
|
||||
shellutils.R(&NetworkCreateOptions{}, "subnet-create", "Create subnet", func(cli *ctyun.SRegion, args *NetworkCreateOptions) error {
|
||||
vpc, e := cli.CreateNetwork(args.VpcId, args.ZoneId, args.Name, args.Cidr, args.GatewayIp, args.DhcpEnable)
|
||||
vpc, e := cli.CreateNetwork(args.VpcId, args.ZoneId, args.Name, args.Cidr, args.DhcpEnable)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SSnapshot struct {
|
||||
@@ -111,7 +112,12 @@ func (self *SSnapshot) GetDiskType() string {
|
||||
}
|
||||
|
||||
func (self *SSnapshot) Delete() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
_, err := self.region.DeleteSnapshot(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Snapshot.Delete.DeleteSnapshot")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSnapshot(diskId string, snapshotId string) (*SSnapshot, error) {
|
||||
@@ -157,3 +163,30 @@ func (self *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) {
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteSnapshot(vbsId string) (string, error) {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vbsId": jsonutils.NewString(vbsId),
|
||||
}
|
||||
|
||||
resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVBS", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.DeleteSnapshot.DoPost")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
err = resp.Unmarshal(&ok, "returnObj", "status")
|
||||
if !ok {
|
||||
msg, _ := resp.GetString("message")
|
||||
return "", fmt.Errorf("SRegion.DeleteSnapshot.JobFailed %s", msg)
|
||||
}
|
||||
|
||||
var jobId string
|
||||
err = resp.Unmarshal(&jobId, "returnObj", "data")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SRegion.DeleteSnapshot.Unmarshal")
|
||||
}
|
||||
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ package ctyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -121,7 +123,12 @@ func (self *SStorage) GetEnabled() bool {
|
||||
}
|
||||
|
||||
func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
disk, err := self.zone.region.CreateDisk(self.zone.GetId(), self.GetName(), self.GetStorageType(), strconv.Itoa(sizeGb))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Storage.CreateIDisk.CreateDisk")
|
||||
}
|
||||
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
|
||||
|
||||
@@ -33,15 +33,15 @@ type SStoragecache struct {
|
||||
}
|
||||
|
||||
func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, isForce bool) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
return "", cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func GetBucketName(regionId string, imageId string) string {
|
||||
|
||||
@@ -123,7 +123,7 @@ func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
|
||||
}
|
||||
|
||||
func (self *SVpc) Delete() error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
return self.region.DeleteVpc(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) {
|
||||
@@ -212,3 +212,17 @@ func (self *SRegion) GetVpc(vpcId string) (*SVpc, error) {
|
||||
vpc.region = self
|
||||
return vpc, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteVpc(vpcId string) error {
|
||||
params := map[string]jsonutils.JSONObject{
|
||||
"regionId": jsonutils.NewString(self.GetId()),
|
||||
"vpcId": jsonutils.NewString(vpcId),
|
||||
}
|
||||
|
||||
_, err := self.client.DoPost("/apiproxy/v3/deleteVPC", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SRegion.DeleteVpc.DoPost")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -107,7 +107,12 @@ func getDefaultGateWay(cidr string) (string, error) {
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
network, err := self.region.CreateNetwork(self.vpc.GetId(), self.inetworks[0].(*SNetwork).ZoneID, name, cidr, "true")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SWire.CreateINetwork.CreateNetwork")
|
||||
}
|
||||
|
||||
return network, nil
|
||||
}
|
||||
|
||||
func (self *SWire) addNetwork(network *SNetwork) {
|
||||
|
||||
@@ -203,7 +203,7 @@ func handleServerRemoteConsole(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
return
|
||||
}
|
||||
switch info.Protocol {
|
||||
case session.ALIYUN, session.QCLOUD, session.OPENSTACK, session.VMRC, session.ZSTACK:
|
||||
case session.ALIYUN, session.QCLOUD, session.OPENSTACK, session.VMRC, session.ZSTACK, session.CTYUN:
|
||||
responsePublicCloudConsole(info, w)
|
||||
case session.VNC, session.SPICE, session.WMKS:
|
||||
handleDataSession(info, w, url.Values{"password": {info.GetPassword()}})
|
||||
|
||||
@@ -32,6 +32,7 @@ const (
|
||||
WMKS = "wmks"
|
||||
VMRC = "vmrc"
|
||||
ZSTACK = "zstack"
|
||||
CTYUN = "ctyun"
|
||||
)
|
||||
|
||||
type RemoteConsoleInfo struct {
|
||||
@@ -109,7 +110,7 @@ func (info *RemoteConsoleInfo) GetConnectParams() (string, error) {
|
||||
return info.getAliyunURL()
|
||||
case QCLOUD:
|
||||
return info.getQcloudURL()
|
||||
case OPENSTACK, VMRC, ZSTACK:
|
||||
case OPENSTACK, VMRC, ZSTACK, CTYUN:
|
||||
return info.Url, nil
|
||||
default:
|
||||
return "", fmt.Errorf("Can't convert protocol %s to connect params", info.Protocol)
|
||||
|
||||
Reference in New Issue
Block a user