fix(region): vendor update (#24998)

This commit is contained in:
屈轩
2026-06-09 14:16:49 +08:00
committed by GitHub
parent ac31682e01
commit b876405c97
24 changed files with 402 additions and 470 deletions
+1 -1
View File
@@ -108,7 +108,7 @@ require (
k8s.io/cri-api v0.28.15
k8s.io/klog/v2 v2.90.1
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260608093459-7789fd47ef2b
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260609055727-275f3963d64c
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005
yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
+2 -2
View File
@@ -1785,8 +1785,8 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260608093459-7789fd47ef2b h1:/ksenqUkmchwkBsE80p7RMzvsNyPNtPHQHHHJjUoumA=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260608093459-7789fd47ef2b/go.mod h1:TbMuTWxcTdyL2Usn+WQdIw0jdlBYO66SzPRY8LZ3Wj0=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260609055727-275f3963d64c h1:XucESU4LflBCCvfiW89YcdG58a0KQ9KPJK/ucFsQcww=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260609055727-275f3963d64c/go.mod h1:TbMuTWxcTdyL2Usn+WQdIw0jdlBYO66SzPRY8LZ3Wj0=
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005 h1:3sWwcjGXGjG9mLBWa7AyLq+QSi0udTAx21pfVQRFMBE=
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
+1 -1
View File
@@ -2603,7 +2603,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.3.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260608093459-7789fd47ef2b
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260609055727-275f3963d64c
## explicit; go 1.24
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
+5
View File
@@ -207,6 +207,11 @@ var UCLOUD_STORAGES = []string{
STORAGE_UCLOUD_CLOUD_RSSD,
}
var UCLOUD_LOCAL_STORAGES = []string{
STORAGE_UCLOUD_LOCAL_SSD,
STORAGE_UCLOUD_LOCAL_NORMAL,
}
var KSYUN_STORAGES = []string{
STORAGE_KSYUN_ESSD_AUTO_PL,
STORAGE_KSYUN_ESSD_PL1,
+19 -28
View File
@@ -23,8 +23,6 @@ import (
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
api "yunion.io/x/cloudmux/pkg/apis/compute"
@@ -163,11 +161,10 @@ func (self *SDisk) GetIsAutoDelete() bool {
func (self *SDisk) GetTemplateId() string {
if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 {
ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID)
ins, err := self.storage.zone.region.GetInstance(self.UHostID)
if err != nil {
log.Errorln(err)
return ""
}
return ins.ImageID
}
@@ -303,27 +300,23 @@ func (self *SDisk) Rebuild(ctx context.Context) error {
}
func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
if len(diskId) == 0 {
return nil, fmt.Errorf("GetDisk id should not empty")
}
disks, err := self.GetDisks("", "", []string{diskId})
disks, err := self.GetDisks("", "", "", diskId)
if err != nil {
return nil, err
}
if len(disks) == 1 {
return &disks[0], nil
} else if len(disks) == 0 {
return nil, cloudprovider.ErrNotFound
} else {
return nil, fmt.Errorf("GetDisk %s %d found", diskId, len(disks))
for i := range disks {
if disks[i].UDiskID == diskId {
return &disks[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetDisk %s", diskId)
}
// https://docs.ucloud.cn/api/udisk-api/describe_udisk
// diskType DataDisk|SystemDisk (DataDisk表示数据盘,SystemDisk表示系统盘)
func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string) ([]SDisk, error) {
func (self *SRegion) GetDisks(zoneId string, diskType string, isBoot string, diskId string) ([]SDisk, error) {
disks := make([]SDisk, 0)
params := NewRockbaseParams()
if len(zoneId) > 0 {
@@ -331,25 +324,23 @@ func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string)
}
if len(diskType) > 0 {
params.Set("ProtocolVersion", "1")
params.Set("DiskType", diskType)
}
if len(diskId) > 0 {
params.Set("UDiskId", diskId)
}
if len(isBoot) > 0 {
params.Set("IsBoot", isBoot)
}
err := self.DoListAll("DescribeUDisk", params, &disks)
if err != nil {
return nil, err
}
if len(diskIds) > 0 {
filtedDisks := make([]SDisk, 0)
for i := range disks {
if utils.IsInStringArray(disks[i].UDiskID, diskIds) {
filtedDisks = append(filtedDisks, disks[i])
}
}
return filtedDisks, nil
}
return disks, nil
}
+11 -11
View File
@@ -15,12 +15,12 @@
package rockbase
import (
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
api "yunion.io/x/cloudmux/pkg/apis/compute"
@@ -99,7 +99,7 @@ func (self *SEip) GetGlobalId() string {
func (self *SEip) GetStatus() string {
switch self.Status {
case "used":
return api.EIP_STATUS_ASSOCIATE // ?
return api.EIP_STATUS_READY
case "free":
return api.EIP_STATUS_READY
case "freeze":
@@ -113,9 +113,9 @@ func (self *SEip) Refresh() error {
if self.IsEmulated() {
return nil
}
new, err := self.region.GetEipById(self.GetId())
new, err := self.region.GetEip(self.GetId())
if err != nil {
return err
return errors.Wrapf(err, "Refresh")
}
return jsonutils.Update(self, new)
}
@@ -225,12 +225,15 @@ func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP
params.Set("OperatorName", eip.BGPType)
params.Set("Bandwidth", eip.BandwidthMbps)
params.Set("Name", eip.Name)
params.Set("Region", self.GetId())
var payMode string
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
payMode = "Traffic"
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
payMode = "Bandwidth"
default:
payMode = "Bandwidth"
}
params.Set("PayMode", payMode)
params.Set("ChargeType", "Dynamic") // 按需付费
@@ -241,14 +244,11 @@ func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP
return nil, err
}
if len(eips) == 1 {
eip := eips[0]
eip.region = self
eip.Refresh()
return &eip, nil
} else {
return nil, fmt.Errorf("CreateEIP %d eip created", len(eips))
for i := range eips {
eips[i].region = self
return &eips[i], nil
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "CreateEIP %d eip created", len(eips))
}
// https://docs.ucloud.cn/api/unet-api/release_eip
+59 -68
View File
@@ -17,11 +17,10 @@ package rockbase
import (
"encoding/base64"
"fmt"
"regexp"
"strconv"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/billing"
@@ -77,13 +76,13 @@ func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
}
func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
vm, err := self.zone.region.GetInstanceByID(id)
vm, err := self.zone.region.GetInstance(id)
if err != nil {
return nil, err
}
vm.host = self
return &vm, nil
return vm, nil
}
func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
@@ -162,19 +161,19 @@ func (self *SHost) GetVersion() string {
// 不支持user data
// 不支持指定keypair
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.ExternalSecgroupIds, desc.BillingCycle)
func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(opts)
if err != nil {
return nil, err
}
vm, err := self.zone.region.GetInstanceByID(vmId)
vm, err := self.zone.region.GetInstance(vmId)
if err != nil {
return nil, err
}
vm.host = self
return &vm, err
return vm, err
}
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
@@ -187,103 +186,92 @@ func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error
type SInstanceType struct {
UHostType string
GpuType string
CPU int
MemoryMB int
GPU int
}
// 格式: {机型}.c{cpu}.m{memGB}[.g{gpu}],机型支持 UCloud GpuType 如 T4S、2080Ti-4C、T4/4
var instanceTypeRe = regexp.MustCompile(`^([A-Za-z0-9][A-Za-z0-9/_-]*)\.c(\d+)\.m(\d+)(?:\.g(\d+))?$`)
func ParseInstanceType(instanceType string) (SInstanceType, error) {
i := SInstanceType{}
segs := strings.Split(instanceType, ".")
if len(segs) < 3 {
matches := instanceTypeRe.FindStringSubmatch(instanceType)
if matches == nil {
return i, fmt.Errorf("invalid instance type %s", instanceType)
} else if len(segs) >= 4 {
gpu, err := strconv.Atoi(strings.TrimLeft(segs[3], "g"))
}
hostType := matches[1]
cpu, err := strconv.Atoi(matches[2])
if err != nil {
return i, err
}
memGB, err := strconv.Atoi(matches[3])
if err != nil {
return i, err
}
i.CPU = cpu
i.MemoryMB = memGB * 1024
if len(matches[4]) > 0 {
gpu, err := strconv.Atoi(matches[4])
if err != nil {
return i, err
}
i.GPU = gpu
i.GpuType = hostType
i.UHostType = "G"
} else {
i.UHostType = hostType
}
cpu, err := strconv.Atoi(strings.TrimLeft(segs[1], "c"))
if err != nil {
return i, err
}
mem, err := strconv.Atoi(strings.TrimLeft(segs[2], "m"))
if err != nil {
return i, err
}
i.UHostType = segs[0]
i.CPU = cpu
i.MemoryMB = mem * 1024
return i, nil
}
func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, cpu, memMB int, instanceType string,
networkId, ipAddr, desc, passwd string,
dataDisks []cloudprovider.SDiskInfo, secgroupIds []string, bc *billing.SBillingCycle) (string, error) {
// 网络配置及安全组绑定
net, _ := self.zone.region.getNetwork(networkId)
if net == nil {
return "", fmt.Errorf("invalid network ID %s", networkId)
func (self *SHost) _createVM(opts *cloudprovider.SManagedVMCreateConfig) (string, error) {
net, err := self.zone.region.getNetwork(opts.ExternalNetworkId)
if err != nil {
return "", errors.Wrapf(err, "getNetwork %s", opts.ExternalNetworkId)
}
if net.wire == nil {
log.Errorf("network's wire is empty")
return "", fmt.Errorf("network's wire is empty")
}
if net.wire.vpc == nil {
log.Errorf("wire's vpc is empty")
return "", fmt.Errorf("wire's vpc is empty")
}
if len(passwd) == 0 {
if len(opts.Password) == 0 {
return "", fmt.Errorf("CreateVM password should not be emtpty")
}
// 镜像及硬盘配置
img, err := self.zone.region.GetImage(imgId)
img, err := self.zone.region.GetImage(opts.ExternalImageId)
if err != nil {
log.Errorf("GetImage %s fail %s", imgId, err)
return "", err
return "", errors.Wrapf(err, "GetImage %s", opts.ExternalImageId)
}
if img.GetStatus() != api.CACHED_IMAGE_STATUS_ACTIVE {
log.Errorf("image %s status %s, expect %s", imgId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE)
return "", fmt.Errorf("image not ready")
return "", errors.Wrapf(cloudprovider.ErrInvalidStatus, "image %s status %s, expect %s", opts.ExternalImageId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE)
}
disks := make([]SDisk, len(dataDisks)+1)
disks := make([]SDisk, len(opts.DataDisks)+1)
disks[0].SizeGB = int(img.ImageSizeGB)
if sysDisk.SizeGB > 0 && sysDisk.SizeGB > int(img.ImageSizeGB) {
disks[0].SizeGB = sysDisk.SizeGB
if opts.SysDisk.SizeGB > 0 && opts.SysDisk.SizeGB > int(img.ImageSizeGB) {
disks[0].SizeGB = opts.SysDisk.SizeGB
}
disks[0].DiskType = sysDisk.StorageType
disks[0].DiskType = opts.SysDisk.StorageType
for i, dataDisk := range dataDisks {
for i, dataDisk := range opts.DataDisks {
disks[i+1].SizeGB = dataDisk.SizeGB
disks[i+1].DiskType = dataDisk.StorageType
}
// 创建实例
// https://docs.ucloud.cn/api/uhost-api/uhost_type
// https://docs.ucloud.cn/compute/uhost/introduction/uhost/type
var vmId string
i, err := ParseInstanceType(instanceType)
i, err := ParseInstanceType(opts.InstanceType)
if err != nil {
if cpu <= 0 || memMB <= 0 {
if opts.Cpu <= 0 || opts.MemoryMB <= 0 {
return "", err
} else {
i.UHostType = "N2"
i.CPU = cpu
i.MemoryMB = memMB
i.UHostType = "O"
i.CPU = opts.Cpu
i.MemoryMB = opts.MemoryMB
}
}
vmId, err = self.zone.region.CreateInstance(name, imgId, i.UHostType, passwd, net.wire.vpc.GetId(), networkId, secgroupIds, self.zone.ZoneId, desc, ipAddr, i.CPU, i.MemoryMB, i.GPU, disks, bc)
vmId, err = self.zone.region.CreateInstance(opts.Name, opts.ExternalImageId, i.UHostType, opts.Password, net.wire.vpc.GetId(), opts.ExternalNetworkId, opts.ExternalSecgroupIds, self.zone.ZoneId, opts.Description, opts.IpAddr, i.CPU, i.MemoryMB, i.GPU, i.GpuType, disks, opts.BillingCycle)
if err != nil {
return "", fmt.Errorf("Failed to create: %v", err)
}
@@ -295,14 +283,14 @@ func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo
// https://docs.ucloud.cn/api/uhost-api/specification
// 支持8-30位字符, 不能包含[A-Z],[a-z],[0-9]和[()`~!@#$%^&*-+=_|{}[]:;'<>,.?/]之外的非法字符
func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, SubnetId string, securityGroupId []string,
zoneId, desc, ipAddr string, cpu, memMB, gpu int, disks []SDisk, bc *billing.SBillingCycle) (string, error) {
zoneId, desc, ipAddr string, cpu, memMB, gpu int, gpuType string, disks []SDisk, bc *billing.SBillingCycle) (string, error) {
params := NewRockbaseParams()
params.Set("Zone", zoneId)
params.Set("ImageId", imageId)
params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password)))
params.Set("LoginMode", "Password")
params.Set("Name", name)
params.Set("UHostType", hostType)
params.Set("MachineType", hostType)
params.Set("CPU", cpu)
params.Set("Memory", memMB)
params.Set("VPCId", vpcId)
@@ -312,6 +300,9 @@ func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, Su
}
if gpu > 0 {
params.Set("GPU", gpu)
if len(gpuType) > 0 {
params.Set("GpuType", gpuType)
}
}
if bc != nil && bc.GetMonths() >= 1 && bc.GetMonths() < 10 {
@@ -347,7 +338,7 @@ func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, Su
ret := Ret{}
err := self.DoAction("CreateUHostInstance", params, &ret)
if err != nil {
return "", err
return "", errors.Wrapf(err, "CreateUHostInstance")
}
if len(ret.UHostIds) == 1 {
+31 -51
View File
@@ -55,6 +55,8 @@ type SInstance struct {
State string `json:"State"`
NetworkState string `json:"NetworkState"`
HostType string `json:"HostType"`
MachineType string `json:"MachineType"`
GpuType string `json:"GpuType"`
StorageType string `json:"StorageType"`
TotalDiskSpace int `json:"TotalDiskSpace"`
DiskSet []DiskSet `json:"DiskSet"`
@@ -175,7 +177,7 @@ func (self *SInstance) GetStatus() string {
}
func (self *SInstance) Refresh() error {
new, err := self.host.zone.region.GetInstanceByID(self.GetId())
new, err := self.host.zone.region.GetInstance(self.GetId())
if err != nil {
return err
}
@@ -235,22 +237,17 @@ func (self *SInstance) GetLocalDisk(diskId, storageType string, sizeGB int, isBo
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
localDisks := make([]SDisk, 0)
diskIds := make([]string, 0)
disks := []SDisk{}
for _, disk := range self.DiskSet {
if utils.IsInStringArray(disk.DiskType, []string{api.STORAGE_ROCKBASE_LOCAL_NORMAL, api.STORAGE_ROCKBASE_LOCAL_SSD}) {
localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot))
} else {
diskIds = append(diskIds, disk.DiskID)
continue
}
}
disks := []SDisk{}
var err error
if len(diskIds) > 0 {
disks, err = self.host.zone.region.GetDisks("", "", diskIds)
disk, err := self.host.zone.region.GetDisk(disk.DiskID)
if err != nil {
return nil, err
}
disks = append(disks, *disk)
}
disks = append(disks, localDisks...)
@@ -302,12 +299,12 @@ func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
for _, ip := range self.IPSet {
if len(ip.IPId) > 0 {
eip, err := self.host.zone.region.GetEipById(ip.IPId)
eip, err := self.host.zone.region.GetEip(ip.IPId)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "GetEip %s", ip.IPId)
}
return &eip, nil
return eip, nil
}
}
@@ -374,13 +371,22 @@ func (self *SInstance) GetMachine() string {
return "pc"
}
func (self *SInstance) GetInstanceType() string {
// C1.c8.m24
if strings.HasPrefix(self.HostType, "G") {
return fmt.Sprintf("%s.c%d.m%d.g%d", self.HostType, self.CPU, self.MemoryMB/1014, self.GPU)
} else {
return fmt.Sprintf("%s.c%d.m%d", self.HostType, self.CPU, self.MemoryMB/1014)
func (self *SInstance) instanceTypeHostPrefix() string {
if self.GPU > 0 && len(self.GpuType) > 0 {
return self.GpuType
}
if len(self.UHostType) > 0 {
return self.UHostType
}
if len(self.MachineType) > 0 {
return self.MachineType
}
return self.HostType
}
func (self *SInstance) GetInstanceType() string {
memGB := self.MemoryMB / 1024
return formatInstanceSpec(self.instanceTypeHostPrefix(), self.CPU, memGB, self.GPU)
}
// https://docs.ucloud.cn/api/unet-api/grant_firewall
@@ -437,34 +443,7 @@ func (self *SInstance) UpdateUserData(userData string) error {
}
// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance
// 1.请确认在重新安装之前,该实例已被关闭;
// 2.请确认该实例未挂载UDisk;
// todo:// 3.将原系统重装为不同类型的系统时(Linux-&gt;Windows),不可选择保留数据盘;
// 4.重装不同版本的系统时(CentOS6-&gt;CentOS7),若选择保留数据盘,请注意数据盘的文件系统格式;
// 5.若主机CPU低于2核,不可重装为Windows系统。
func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
if len(desc.PublicKey) > 0 {
return "", fmt.Errorf("DeployVM not support assign ssh keypair")
}
if self.GetStatus() != api.VM_READY {
return "", fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY)
}
if len(self.DiskSet) > 1 {
for _, disk := range self.DiskSet {
if disk.Type == "Data" {
err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID)
if err != nil {
return "", fmt.Errorf("RebuildRoot detach disk %s", err)
}
defer self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID)
}
}
}
err := self.host.zone.region.RebuildRoot(self.GetId(), desc.ImageId, desc.Password)
if err != nil {
return "", err
@@ -475,12 +454,12 @@ func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SMan
return "", errors.Wrap(err, "RebuildRoot")
}
disks, err := self.GetIDisks()
if len(disks) > 0 {
return disks[0].GetId(), nil
} else {
return "", fmt.Errorf("RebuildRoot %s", err)
for _, disk := range self.DiskSet {
if disk.Type == "SystemDisk" {
return disk.DiskID, nil
}
}
return "", errors.Wrapf(cloudprovider.ErrNotFound, "SystemDisk not found")
}
func (self *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
@@ -614,6 +593,7 @@ func (self *SRegion) DeleteVM(instanceId string) error {
params := NewRockbaseParams()
params.Set("UHostId", instanceId)
params.Set("Destroy", 1) // 跳过回收站,直接删除
params.Set("ReleaseUDisk", true)
return self.DoAction("TerminateUHostInstance", params, nil)
}
+1 -5
View File
@@ -326,11 +326,7 @@ func (self *SRegion) GetZoneStorageTypes(zoneId string) ([]string, error) {
if err != nil {
return nil, err
}
storageTypes := collectStorageTypesFromInstanceTypes(types, zoneId)
if len(storageTypes) == 0 {
return nil, fmt.Errorf("no storage types found for zone %s", zoneId)
}
return storageTypes, nil
return collectStorageTypesFromInstanceTypes(types, zoneId), nil
}
// GetAvailableInstanceTypes 获取地域/可用区下可售机型信息。
+10 -14
View File
@@ -19,6 +19,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/rbacscope"
@@ -142,9 +143,6 @@ func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) {
}
func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
if len(networkId) == 0 {
return nil, fmt.Errorf("getNetwork network id should not be empty")
}
networks := make([]SNetwork, 0)
params := NewRockbaseParams()
@@ -154,19 +152,17 @@ func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
return nil, err
}
if len(networks) == 1 {
network := networks[0]
vpc, err := self.GetVpc(network.VpcId)
if err != nil {
return nil, err
for i := range networks {
if networks[i].SubnetID == networkId {
vpc, err := self.GetVpc(networks[i].VpcId)
if err != nil {
return nil, err
}
networks[i].wire = &SWire{vpc: vpc}
return &networks[i], nil
}
network.wire = &SWire{vpc: vpc}
return &network, nil
} else if len(networks) == 0 {
return nil, cloudprovider.ErrNotFound
} else {
return nil, fmt.Errorf("getNetwork %s %d found", networkId, len(networks))
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "getNetwork %s", networkId)
}
// https://docs.ucloud.cn/api/vpc2.0-api/delete_subnet
+23 -22
View File
@@ -71,11 +71,11 @@ func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
}
func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
instance, err := self.GetInstanceByID(id)
instance, err := self.GetInstance(id)
if err != nil {
return nil, err
}
return &instance, nil
return instance, nil
}
func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
@@ -144,29 +144,30 @@ func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetEipById(eipId string) (SEip, error) {
func (self *SRegion) GetEip(eipId string) (*SEip, error) {
params := NewRockbaseParams()
params.Set("EIPIds.0", eipId)
eips := make([]SEip, 0)
err := self.DoListAll("DescribeEIP", params, &eips)
if err != nil {
return SEip{}, err
return nil, err
}
if len(eips) == 1 {
eip := eips[0]
eip.region = self
return eip, nil
} else if len(eips) == 0 {
return SEip{}, cloudprovider.ErrNotFound
} else {
return SEip{}, fmt.Errorf("GetEipById %d eip found", len(eips))
for i := range eips {
if eips[i].EIPID == eipId {
eips[i].region = self
return &eips[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetEip %s", eipId)
}
func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) {
eip, err := self.GetEipById(id)
return &eip, err
eip, err := self.GetEip(id)
if err != nil {
return nil, err
}
return eip, nil
}
// https://docs.ucloud.cn/api/unet-api/delete_firewall
@@ -386,22 +387,22 @@ func (self *SRegion) GetZones() ([]SZone, error) {
return zones, err
}
func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) {
// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
params := NewRockbaseParams()
params.Set("UHostIds.0", instanceId)
instances := make([]SInstance, 0)
err := self.DoAction("DescribeUHostInstance", params, &instances)
if err != nil {
return SInstance{}, err
return nil, errors.Wrapf(err, "DescribeUHostInstance")
}
if len(instances) == 1 {
return instances[0], nil
} else if len(instances) == 0 {
return SInstance{}, cloudprovider.ErrNotFound
} else {
return SInstance{}, fmt.Errorf("GetInstanceByID %s %d found.", instanceId, len(instances))
for i := range instances {
if instances[i].UHostID == instanceId {
return &instances[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetInstance %s", instanceId)
}
func (self *SRegion) GetClient() *SRockbaseClient {
+25 -25
View File
@@ -23,6 +23,7 @@ import (
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
"yunion.io/x/pkg/utils"
)
type SStorage struct {
@@ -65,30 +66,18 @@ func (self *SStorage) GetIZone() cloudprovider.ICloudZone {
}
func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := self.zone.region.GetDisks(self.zone.GetId(), "", nil)
if err != nil {
return nil, err
}
filtedDisks := make([]SDisk, 0)
for _, disk := range disks {
// ssd 盘
if self.storageType == api.STORAGE_ROCKBASE_CLOUD_SSD && strings.Contains(disk.DiskType, "SSD") {
filtedDisks = append(filtedDisks, disk)
ret := []cloudprovider.ICloudDisk{}
for _, isBoot := range []string{"True", "False"} {
disks, err := self.zone.region.GetDisks(self.zone.GetId(), self.storageType, isBoot, "")
if err != nil {
return nil, err
}
// 普通盘
if self.storageType == api.STORAGE_ROCKBASE_CLOUD_NORMAL && !strings.Contains(disk.DiskType, "SSD") {
filtedDisks = append(filtedDisks, disk)
for _, disk := range disks {
disk.storage = self
ret = append(ret, &disk)
}
}
idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks))
for i := 0; i < len(filtedDisks); i += 1 {
filtedDisks[i].storage = self
idisks[i] = &filtedDisks[i]
}
return idisks, nil
return ret, nil
}
func (self *SStorage) GetStorageType() string {
@@ -124,6 +113,10 @@ func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudpr
switch self.storageType {
case api.STORAGE_ROCKBASE_CLOUD_SSD:
diskType = "SSDDataDisk"
case api.STORAGE_ROCKBASE_CLOUD_ESSD:
diskType = "ESSDDataDisk"
case api.STORAGE_ROCKBASE_CLOUD_RSSD:
diskType = "RSSDDataDisk"
}
diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), diskType, opts)
if err != nil {
@@ -140,12 +133,12 @@ func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudpr
}
func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
if disk, err := self.zone.region.GetDisk(idStr); err != nil {
disk, err := self.zone.region.GetDisk(idStr)
if err != nil {
return nil, err
} else {
disk.storage = self
return disk, nil
}
disk.storage = self
return disk, nil
}
func (self *SStorage) GetMountPoint() string {
@@ -155,3 +148,10 @@ func (self *SStorage) GetMountPoint() string {
func (self *SStorage) IsSysDiskStore() bool {
return true
}
func (self *SStorage) DisableSync() bool {
return utils.IsInStringArray(self.storageType, []string{
api.STORAGE_ROCKBASE_LOCAL_SSD,
api.STORAGE_ROCKBASE_LOCAL_NORMAL,
})
}
+12 -10
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
)
var responseMetaKeys = map[string]bool{
@@ -99,24 +100,21 @@ func detectArrayResultKey(resp jsonutils.JSONObject) string {
return candidates[0]
}
func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}) error {
if respErr != nil {
return respErr
}
func unmarshalResult(resp jsonutils.JSONObject, result interface{}) error {
if result == nil {
return nil
}
var err error
resultKey := detectResultKey(resp, result)
if len(resultKey) > 0 {
respErr = resp.Unmarshal(result, resultKey)
err = resp.Unmarshal(result, resultKey)
} else {
respErr = resp.Unmarshal(result)
err = resp.Unmarshal(result)
}
if respErr != nil {
log.Errorf("unmarshal json error %s", respErr)
if err != nil {
return errors.Wrapf(err, "unmarshalResult")
}
return nil
@@ -154,7 +152,11 @@ func doListPart(client *SRockbaseClient, action string, params SParams, result i
func DoAction(client *SRockbaseClient, action string, params SParams, result interface{}) error {
params.SetAction(action)
resp, err := jsonRequest(client, params)
return unmarshalResult(resp, err, result)
if err != nil {
log.Debugf("DoAction %s %s error %s", action, params.PrettyString(), err)
return err
}
return unmarshalResult(resp, result)
}
// 遍历所有结果
+6
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
@@ -52,6 +53,11 @@ func (self *SZone) fetchStorages() error {
if err != nil {
return err
}
for _, storageType := range []string{api.STORAGE_ROCKBASE_LOCAL_SSD, api.STORAGE_ROCKBASE_LOCAL_NORMAL} {
if !utils.IsInStringArray(storageType, storageTypes) {
storageTypes = append(storageTypes, storageType)
}
}
self.storageTypes = storageTypes
self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes))
for i, sc := range self.storageTypes {
+19 -28
View File
@@ -23,8 +23,6 @@ import (
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
api "yunion.io/x/cloudmux/pkg/apis/compute"
@@ -163,11 +161,10 @@ func (self *SDisk) GetIsAutoDelete() bool {
func (self *SDisk) GetTemplateId() string {
if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 {
ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID)
ins, err := self.storage.zone.region.GetInstance(self.UHostID)
if err != nil {
log.Errorln(err)
return ""
}
return ins.ImageID
}
@@ -303,27 +300,23 @@ func (self *SDisk) Rebuild(ctx context.Context) error {
}
func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
if len(diskId) == 0 {
return nil, fmt.Errorf("GetDisk id should not empty")
}
disks, err := self.GetDisks("", "", []string{diskId})
disks, err := self.GetDisks("", "", "", diskId)
if err != nil {
return nil, err
}
if len(disks) == 1 {
return &disks[0], nil
} else if len(disks) == 0 {
return nil, cloudprovider.ErrNotFound
} else {
return nil, fmt.Errorf("GetDisk %s %d found", diskId, len(disks))
for i := range disks {
if disks[i].UDiskID == diskId {
return &disks[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetDisk %s", diskId)
}
// https://docs.ucloud.cn/api/udisk-api/describe_udisk
// diskType DataDisk|SystemDisk (DataDisk表示数据盘,SystemDisk表示系统盘)
func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string) ([]SDisk, error) {
func (self *SRegion) GetDisks(zoneId string, diskType string, isBoot string, diskId string) ([]SDisk, error) {
disks := make([]SDisk, 0)
params := NewUcloudParams()
if len(zoneId) > 0 {
@@ -331,25 +324,23 @@ func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string)
}
if len(diskType) > 0 {
params.Set("ProtocolVersion", "1")
params.Set("DiskType", diskType)
}
if len(diskId) > 0 {
params.Set("UDiskId", diskId)
}
if len(isBoot) > 0 {
params.Set("IsBoot", isBoot)
}
err := self.DoListAll("DescribeUDisk", params, &disks)
if err != nil {
return nil, err
}
if len(diskIds) > 0 {
filtedDisks := make([]SDisk, 0)
for i := range disks {
if utils.IsInStringArray(disks[i].UDiskID, diskIds) {
filtedDisks = append(filtedDisks, disks[i])
}
}
return filtedDisks, nil
}
return disks, nil
}
+11 -11
View File
@@ -15,12 +15,12 @@
package ucloud
import (
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
api "yunion.io/x/cloudmux/pkg/apis/compute"
@@ -99,7 +99,7 @@ func (self *SEip) GetGlobalId() string {
func (self *SEip) GetStatus() string {
switch self.Status {
case "used":
return api.EIP_STATUS_ASSOCIATE // ?
return api.EIP_STATUS_READY
case "free":
return api.EIP_STATUS_READY
case "freeze":
@@ -113,9 +113,9 @@ func (self *SEip) Refresh() error {
if self.IsEmulated() {
return nil
}
new, err := self.region.GetEipById(self.GetId())
new, err := self.region.GetEip(self.GetId())
if err != nil {
return err
return errors.Wrapf(err, "Refresh")
}
return jsonutils.Update(self, new)
}
@@ -225,12 +225,15 @@ func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP
params.Set("OperatorName", eip.BGPType)
params.Set("Bandwidth", eip.BandwidthMbps)
params.Set("Name", eip.Name)
params.Set("Region", self.GetId())
var payMode string
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
payMode = "Traffic"
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
payMode = "Bandwidth"
default:
payMode = "Bandwidth"
}
params.Set("PayMode", payMode)
params.Set("ChargeType", "Dynamic") // 按需付费
@@ -241,14 +244,11 @@ func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP
return nil, err
}
if len(eips) == 1 {
eip := eips[0]
eip.region = self
eip.Refresh()
return &eip, nil
} else {
return nil, fmt.Errorf("CreateEIP %d eip created", len(eips))
for i := range eips {
eips[i].region = self
return &eips[i], nil
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "CreateEIP %d eip created", len(eips))
}
// https://docs.ucloud.cn/api/unet-api/release_eip
+59 -63
View File
@@ -17,11 +17,10 @@ package ucloud
import (
"encoding/base64"
"fmt"
"regexp"
"strconv"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/billing"
@@ -77,13 +76,13 @@ func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
}
func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
vm, err := self.zone.region.GetInstanceByID(id)
vm, err := self.zone.region.GetInstance(id)
if err != nil {
return nil, err
}
vm.host = self
return &vm, nil
return vm, nil
}
func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
@@ -162,19 +161,19 @@ func (self *SHost) GetVersion() string {
// 不支持user data
// 不支持指定keypair
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.ExternalSecgroupIds, desc.BillingCycle)
func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(opts)
if err != nil {
return nil, err
}
vm, err := self.zone.region.GetInstanceByID(vmId)
vm, err := self.zone.region.GetInstance(vmId)
if err != nil {
return nil, err
}
vm.host = self
return &vm, err
return vm, err
}
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
@@ -187,83 +186,77 @@ func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error
type SInstanceType struct {
UHostType string
GpuType string
CPU int
MemoryMB int
GPU int
}
// 格式: {机型}.c{cpu}.m{memGB}[.g{gpu}],机型支持 UCloud GpuType 如 T4S、2080Ti-4C、T4/4
var instanceTypeRe = regexp.MustCompile(`^([A-Za-z0-9][A-Za-z0-9/_-]*)\.c(\d+)\.m(\d+)(?:\.g(\d+))?$`)
func ParseInstanceType(instanceType string) (SInstanceType, error) {
i := SInstanceType{}
segs := strings.Split(instanceType, ".")
if len(segs) < 3 {
matches := instanceTypeRe.FindStringSubmatch(instanceType)
if matches == nil {
return i, fmt.Errorf("invalid instance type %s", instanceType)
} else if len(segs) >= 4 {
gpu, err := strconv.Atoi(strings.TrimLeft(segs[3], "g"))
}
hostType := matches[1]
cpu, err := strconv.Atoi(matches[2])
if err != nil {
return i, err
}
memGB, err := strconv.Atoi(matches[3])
if err != nil {
return i, err
}
i.CPU = cpu
i.MemoryMB = memGB * 1024
if len(matches[4]) > 0 {
gpu, err := strconv.Atoi(matches[4])
if err != nil {
return i, err
}
i.GPU = gpu
i.GpuType = hostType
i.UHostType = "G"
} else {
i.UHostType = hostType
}
cpu, err := strconv.Atoi(strings.TrimLeft(segs[1], "c"))
if err != nil {
return i, err
}
mem, err := strconv.Atoi(strings.TrimLeft(segs[2], "m"))
if err != nil {
return i, err
}
i.UHostType = segs[0]
i.CPU = cpu
i.MemoryMB = mem * 1024
return i, nil
}
func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, cpu, memMB int, instanceType string,
networkId, ipAddr, desc, passwd string,
dataDisks []cloudprovider.SDiskInfo, secgroupIds []string, bc *billing.SBillingCycle) (string, error) {
func (self *SHost) _createVM(opts *cloudprovider.SManagedVMCreateConfig) (string, error) {
// 网络配置及安全组绑定
net, _ := self.zone.region.getNetwork(networkId)
if net == nil {
return "", fmt.Errorf("invalid network ID %s", networkId)
net, err := self.zone.region.getNetwork(opts.ExternalNetworkId)
if err != nil {
return "", errors.Wrapf(err, "getNetwork %s", opts.ExternalNetworkId)
}
if net.wire == nil {
log.Errorf("network's wire is empty")
return "", fmt.Errorf("network's wire is empty")
}
if net.wire.vpc == nil {
log.Errorf("wire's vpc is empty")
return "", fmt.Errorf("wire's vpc is empty")
}
if len(passwd) == 0 {
if len(opts.Password) == 0 {
return "", fmt.Errorf("CreateVM password should not be emtpty")
}
// 镜像及硬盘配置
img, err := self.zone.region.GetImage(imgId)
img, err := self.zone.region.GetImage(opts.ExternalImageId)
if err != nil {
log.Errorf("GetImage %s fail %s", imgId, err)
return "", err
return "", errors.Wrapf(err, "GetImage %s", opts.ExternalImageId)
}
if img.GetStatus() != api.CACHED_IMAGE_STATUS_ACTIVE {
log.Errorf("image %s status %s, expect %s", imgId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE)
return "", fmt.Errorf("image not ready")
return "", errors.Wrapf(cloudprovider.ErrInvalidStatus, "image %s status %s, expect %s", opts.ExternalImageId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE)
}
disks := make([]SDisk, len(dataDisks)+1)
disks := make([]SDisk, len(opts.DataDisks)+1)
disks[0].SizeGB = int(img.ImageSizeGB)
if sysDisk.SizeGB > 0 && sysDisk.SizeGB > int(img.ImageSizeGB) {
disks[0].SizeGB = sysDisk.SizeGB
if opts.SysDisk.SizeGB > 0 && opts.SysDisk.SizeGB > int(img.ImageSizeGB) {
disks[0].SizeGB = opts.SysDisk.SizeGB
}
disks[0].DiskType = sysDisk.StorageType
disks[0].DiskType = opts.SysDisk.StorageType
for i, dataDisk := range dataDisks {
for i, dataDisk := range opts.DataDisks {
disks[i+1].SizeGB = dataDisk.SizeGB
disks[i+1].DiskType = dataDisk.StorageType
}
@@ -272,18 +265,18 @@ func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo
// https://docs.ucloud.cn/api/uhost-api/uhost_type
// https://docs.ucloud.cn/compute/uhost/introduction/uhost/type
var vmId string
i, err := ParseInstanceType(instanceType)
i, err := ParseInstanceType(opts.InstanceType)
if err != nil {
if cpu <= 0 || memMB <= 0 {
if opts.Cpu <= 0 || opts.MemoryMB <= 0 {
return "", err
} else {
i.UHostType = "N2"
i.CPU = cpu
i.MemoryMB = memMB
i.UHostType = "O"
i.CPU = opts.Cpu
i.MemoryMB = opts.MemoryMB
}
}
vmId, err = self.zone.region.CreateInstance(name, imgId, i.UHostType, passwd, net.wire.vpc.GetId(), networkId, secgroupIds, self.zone.ZoneId, desc, ipAddr, i.CPU, i.MemoryMB, i.GPU, disks, bc)
vmId, err = self.zone.region.CreateInstance(opts.Name, opts.ExternalImageId, i.UHostType, opts.Password, net.wire.vpc.GetId(), opts.ExternalNetworkId, opts.ExternalSecgroupIds, self.zone.ZoneId, opts.Description, opts.IpAddr, i.CPU, i.MemoryMB, i.GPU, i.GpuType, disks, opts.BillingCycle)
if err != nil {
return "", fmt.Errorf("Failed to create: %v", err)
}
@@ -295,14 +288,14 @@ func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo
// https://docs.ucloud.cn/api/uhost-api/specification
// 支持8-30位字符, 不能包含[A-Z],[a-z],[0-9]和[()`~!@#$%^&*-+=_|{}[]:;'<>,.?/]之外的非法字符
func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, SubnetId string, securityGroupId []string,
zoneId, desc, ipAddr string, cpu, memMB, gpu int, disks []SDisk, bc *billing.SBillingCycle) (string, error) {
zoneId, desc, ipAddr string, cpu, memMB, gpu int, gpuType string, disks []SDisk, bc *billing.SBillingCycle) (string, error) {
params := NewUcloudParams()
params.Set("Zone", zoneId)
params.Set("ImageId", imageId)
params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password)))
params.Set("LoginMode", "Password")
params.Set("Name", name)
params.Set("UHostType", hostType)
params.Set("MachineType", hostType)
params.Set("CPU", cpu)
params.Set("Memory", memMB)
params.Set("VPCId", vpcId)
@@ -312,6 +305,9 @@ func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, Su
}
if gpu > 0 {
params.Set("GPU", gpu)
if len(gpuType) > 0 {
params.Set("GpuType", gpuType)
}
}
if bc != nil && bc.GetMonths() >= 1 && bc.GetMonths() < 10 {
@@ -347,7 +343,7 @@ func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, Su
ret := Ret{}
err := self.DoAction("CreateUHostInstance", params, &ret)
if err != nil {
return "", err
return "", errors.Wrapf(err, "CreateUHostInstance")
}
if len(ret.UHostIds) == 1 {
+34 -54
View File
@@ -55,6 +55,8 @@ type SInstance struct {
State string `json:"State"`
NetworkState string `json:"NetworkState"`
HostType string `json:"HostType"`
MachineType string `json:"MachineType"`
GpuType string `json:"GpuType"`
StorageType string `json:"StorageType"`
TotalDiskSpace int `json:"TotalDiskSpace"`
DiskSet []DiskSet `json:"DiskSet"`
@@ -175,7 +177,7 @@ func (self *SInstance) GetStatus() string {
}
func (self *SInstance) Refresh() error {
new, err := self.host.zone.region.GetInstanceByID(self.GetId())
new, err := self.host.zone.region.GetInstance(self.GetId())
if err != nil {
return err
}
@@ -235,22 +237,17 @@ func (self *SInstance) GetLocalDisk(diskId, storageType string, sizeGB int, isBo
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
localDisks := make([]SDisk, 0)
diskIds := make([]string, 0)
for _, disk := range self.DiskSet {
if utils.IsInStringArray(disk.DiskType, []string{api.STORAGE_UCLOUD_LOCAL_NORMAL, api.STORAGE_UCLOUD_LOCAL_SSD}) {
localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot))
} else {
diskIds = append(diskIds, disk.DiskID)
}
}
disks := []SDisk{}
var err error
if len(diskIds) > 0 {
disks, err = self.host.zone.region.GetDisks("", "", diskIds)
for _, disk := range self.DiskSet {
if utils.IsInStringArray(disk.DiskType, api.UCLOUD_LOCAL_STORAGES) {
localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot))
continue
}
disk, err := self.host.zone.region.GetDisk(disk.DiskID)
if err != nil {
return nil, err
}
disks = append(disks, *disk)
}
disks = append(disks, localDisks...)
@@ -302,12 +299,12 @@ func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
for _, ip := range self.IPSet {
if len(ip.IPId) > 0 {
eip, err := self.host.zone.region.GetEipById(ip.IPId)
eip, err := self.host.zone.region.GetEip(ip.IPId)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "GetEip %s", ip.IPId)
}
return &eip, nil
return eip, nil
}
}
@@ -374,13 +371,22 @@ func (self *SInstance) GetMachine() string {
return "pc"
}
func (self *SInstance) GetInstanceType() string {
// C1.c8.m24
if strings.HasPrefix(self.HostType, "G") {
return fmt.Sprintf("%s.c%d.m%d.g%d", self.HostType, self.CPU, self.MemoryMB/1014, self.GPU)
} else {
return fmt.Sprintf("%s.c%d.m%d", self.HostType, self.CPU, self.MemoryMB/1014)
func (self *SInstance) instanceTypeHostPrefix() string {
if self.GPU > 0 && len(self.GpuType) > 0 {
return self.GpuType
}
if len(self.UHostType) > 0 {
return self.UHostType
}
if len(self.MachineType) > 0 {
return self.MachineType
}
return self.HostType
}
func (self *SInstance) GetInstanceType() string {
memGB := self.MemoryMB / 1024
return formatInstanceSpec(self.instanceTypeHostPrefix(), self.CPU, memGB, self.GPU)
}
// https://docs.ucloud.cn/api/unet-api/grant_firewall
@@ -437,34 +443,7 @@ func (self *SInstance) UpdateUserData(userData string) error {
}
// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance
// 1.请确认在重新安装之前,该实例已被关闭;
// 2.请确认该实例未挂载UDisk;
// todo:// 3.将原系统重装为不同类型的系统时(Linux-&gt;Windows),不可选择保留数据盘;
// 4.重装不同版本的系统时(CentOS6-&gt;CentOS7),若选择保留数据盘,请注意数据盘的文件系统格式;
// 5.若主机CPU低于2核,不可重装为Windows系统。
func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
if len(desc.PublicKey) > 0 {
return "", fmt.Errorf("DeployVM not support assign ssh keypair")
}
if self.GetStatus() != api.VM_READY {
return "", fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY)
}
if len(self.DiskSet) > 1 {
for _, disk := range self.DiskSet {
if disk.Type == "Data" {
err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID)
if err != nil {
return "", fmt.Errorf("RebuildRoot detach disk %s", err)
}
defer self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID)
}
}
}
err := self.host.zone.region.RebuildRoot(self.GetId(), desc.ImageId, desc.Password)
if err != nil {
return "", err
@@ -475,12 +454,12 @@ func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SMan
return "", errors.Wrap(err, "RebuildRoot")
}
disks, err := self.GetIDisks()
if len(disks) > 0 {
return disks[0].GetId(), nil
} else {
return "", fmt.Errorf("RebuildRoot %s", err)
for _, disk := range self.DiskSet {
if disk.Type == "SystemDisk" {
return disk.DiskID, nil
}
}
return "", errors.Wrapf(cloudprovider.ErrNotFound, "SystemDisk not found")
}
func (self *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
@@ -614,6 +593,7 @@ func (self *SRegion) DeleteVM(instanceId string) error {
params := NewUcloudParams()
params.Set("UHostId", instanceId)
params.Set("Destroy", 1) // 跳过回收站,直接删除
params.Set("ReleaseUDisk", true)
return self.DoAction("TerminateUHostInstance", params, nil)
}
+1 -5
View File
@@ -326,11 +326,7 @@ func (self *SRegion) GetZoneStorageTypes(zoneId string) ([]string, error) {
if err != nil {
return nil, err
}
storageTypes := collectStorageTypesFromInstanceTypes(types, zoneId)
if len(storageTypes) == 0 {
return nil, fmt.Errorf("no storage types found for zone %s", zoneId)
}
return storageTypes, nil
return collectStorageTypesFromInstanceTypes(types, zoneId), nil
}
// GetAvailableInstanceTypes 获取地域/可用区下可售机型信息。
+10 -14
View File
@@ -19,6 +19,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/rbacscope"
@@ -142,9 +143,6 @@ func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) {
}
func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
if len(networkId) == 0 {
return nil, fmt.Errorf("getNetwork network id should not be empty")
}
networks := make([]SNetwork, 0)
params := NewUcloudParams()
@@ -154,19 +152,17 @@ func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
return nil, err
}
if len(networks) == 1 {
network := networks[0]
vpc, err := self.GetVpc(network.VpcId)
if err != nil {
return nil, err
for i := range networks {
if networks[i].SubnetID == networkId {
vpc, err := self.GetVpc(networks[i].VpcId)
if err != nil {
return nil, err
}
networks[i].wire = &SWire{vpc: vpc}
return &networks[i], nil
}
network.wire = &SWire{vpc: vpc}
return &network, nil
} else if len(networks) == 0 {
return nil, cloudprovider.ErrNotFound
} else {
return nil, fmt.Errorf("getNetwork %s %d found", networkId, len(networks))
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "getNetwork %s", networkId)
}
// https://docs.ucloud.cn/api/vpc2.0-api/delete_subnet
+22 -22
View File
@@ -71,11 +71,11 @@ func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
}
func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
instance, err := self.GetInstanceByID(id)
instance, err := self.GetInstance(id)
if err != nil {
return nil, err
}
return &instance, nil
return instance, nil
}
func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
@@ -144,29 +144,30 @@ func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetEipById(eipId string) (SEip, error) {
func (self *SRegion) GetEip(eipId string) (*SEip, error) {
params := NewUcloudParams()
params.Set("EIPIds.0", eipId)
eips := make([]SEip, 0)
err := self.DoListAll("DescribeEIP", params, &eips)
if err != nil {
return SEip{}, err
return nil, err
}
if len(eips) == 1 {
eip := eips[0]
eip.region = self
return eip, nil
} else if len(eips) == 0 {
return SEip{}, cloudprovider.ErrNotFound
} else {
return SEip{}, fmt.Errorf("GetEipById %d eip found", len(eips))
for i := range eips {
if eips[i].EIPID == eipId {
eips[i].region = self
return &eips[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetEip %s", eipId)
}
func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) {
eip, err := self.GetEipById(id)
return &eip, err
eip, err := self.GetEip(id)
if err != nil {
return nil, err
}
return eip, nil
}
// https://docs.ucloud.cn/api/unet-api/delete_firewall
@@ -387,22 +388,21 @@ func (self *SRegion) GetZones() ([]SZone, error) {
}
// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance
func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) {
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
params := NewUcloudParams()
params.Set("UHostIds.0", instanceId)
instances := make([]SInstance, 0)
err := self.DoAction("DescribeUHostInstance", params, &instances)
if err != nil {
return SInstance{}, err
return nil, errors.Wrapf(err, "DescribeUHostInstance")
}
if len(instances) == 1 {
return instances[0], nil
} else if len(instances) == 0 {
return SInstance{}, cloudprovider.ErrNotFound
} else {
return SInstance{}, fmt.Errorf("GetInstanceByID %s %d found.", instanceId, len(instances))
for i := range instances {
if instances[i].UHostID == instanceId {
return &instances[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetInstance %s", instanceId)
}
func (self *SRegion) GetClient() *SUcloudClient {
+22 -25
View File
@@ -23,6 +23,7 @@ import (
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
"yunion.io/x/pkg/utils"
)
type SStorage struct {
@@ -65,30 +66,18 @@ func (self *SStorage) GetIZone() cloudprovider.ICloudZone {
}
func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := self.zone.region.GetDisks(self.zone.GetId(), "", nil)
if err != nil {
return nil, err
}
filtedDisks := make([]SDisk, 0)
for _, disk := range disks {
// ssd 盘
if self.storageType == api.STORAGE_UCLOUD_CLOUD_SSD && strings.Contains(disk.DiskType, "SSD") {
filtedDisks = append(filtedDisks, disk)
ret := []cloudprovider.ICloudDisk{}
for _, isBoot := range []string{"True", "False"} {
disks, err := self.zone.region.GetDisks(self.zone.GetId(), self.storageType, isBoot, "")
if err != nil {
return nil, err
}
// 普通盘
if self.storageType == api.STORAGE_UCLOUD_CLOUD_NORMAL && !strings.Contains(disk.DiskType, "SSD") {
filtedDisks = append(filtedDisks, disk)
for _, disk := range disks {
disk.storage = self
ret = append(ret, &disk)
}
}
idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks))
for i := 0; i < len(filtedDisks); i += 1 {
filtedDisks[i].storage = self
idisks[i] = &filtedDisks[i]
}
return idisks, nil
return ret, nil
}
func (self *SStorage) GetStorageType() string {
@@ -124,6 +113,10 @@ func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudpr
switch self.storageType {
case api.STORAGE_UCLOUD_CLOUD_SSD:
diskType = "SSDDataDisk"
case api.STORAGE_UCLOUD_CLOUD_ESSD:
diskType = "ESSDDataDisk"
case api.STORAGE_UCLOUD_CLOUD_RSSD:
diskType = "RSSDDataDisk"
}
diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), diskType, opts)
if err != nil {
@@ -140,12 +133,12 @@ func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudpr
}
func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
if disk, err := self.zone.region.GetDisk(idStr); err != nil {
disk, err := self.zone.region.GetDisk(idStr)
if err != nil {
return nil, err
} else {
disk.storage = self
return disk, nil
}
disk.storage = self
return disk, nil
}
func (self *SStorage) GetMountPoint() string {
@@ -155,3 +148,7 @@ func (self *SStorage) GetMountPoint() string {
func (self *SStorage) IsSysDiskStore() bool {
return true
}
func (self *SStorage) DisableSync() bool {
return utils.IsInStringArray(self.storageType, api.UCLOUD_LOCAL_STORAGES)
}
+12 -10
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
)
var responseMetaKeys = map[string]bool{
@@ -99,24 +100,21 @@ func detectArrayResultKey(resp jsonutils.JSONObject) string {
return candidates[0]
}
func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}) error {
if respErr != nil {
return respErr
}
func unmarshalResult(resp jsonutils.JSONObject, result interface{}) error {
if result == nil {
return nil
}
var err error
resultKey := detectResultKey(resp, result)
if len(resultKey) > 0 {
respErr = resp.Unmarshal(result, resultKey)
err = resp.Unmarshal(result, resultKey)
} else {
respErr = resp.Unmarshal(result)
err = resp.Unmarshal(result)
}
if respErr != nil {
log.Errorf("unmarshal json error %s", respErr)
if err != nil {
return errors.Wrapf(err, "unmarshalResult")
}
return nil
@@ -154,7 +152,11 @@ func doListPart(client *SUcloudClient, action string, params SParams, result int
func DoAction(client *SUcloudClient, action string, params SParams, result interface{}) error {
params.SetAction(action)
resp, err := jsonRequest(client, params)
return unmarshalResult(resp, err, result)
if err != nil {
log.Debugf("DoAction %s %s error %s", action, params.PrettyString(), err)
return err
}
return unmarshalResult(resp, result)
}
// 遍历所有结果
+6
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
@@ -52,6 +53,11 @@ func (self *SZone) fetchStorages() error {
if err != nil {
return err
}
for _, storageType := range api.UCLOUD_LOCAL_STORAGES {
if !utils.IsInStringArray(storageType, storageTypes) {
storageTypes = append(storageTypes, storageType)
}
}
self.storageTypes = storageTypes
self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes))
for i, sc := range self.storageTypes {