mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-31 01:35:56 +08:00
ucloud sync
This commit is contained in:
@@ -46,6 +46,7 @@ const (
|
||||
CLOUD_PROVIDER_AWS = "Aws"
|
||||
CLOUD_PROVIDER_HUAWEI = "Huawei"
|
||||
CLOUD_PROVIDER_OPENSTACK = "OpenStack"
|
||||
CLOUD_PROVIDER_UCLOUD = "Ucloud"
|
||||
|
||||
CLOUD_PROVIDER_HEALTH_NORMAL = "normal" // 远端处于健康状态
|
||||
CLOUD_PROVIDER_HEALTH_SUSPENDED = "suspended" // 远端处于冻结状态
|
||||
@@ -64,6 +65,7 @@ var (
|
||||
CLOUD_PROVIDER_AWS,
|
||||
CLOUD_PROVIDER_HUAWEI,
|
||||
CLOUD_PROVIDER_OPENSTACK,
|
||||
CLOUD_PROVIDER_UCLOUD,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ const (
|
||||
HYPERVISOR_AWS = "aws"
|
||||
HYPERVISOR_HUAWEI = "huawei"
|
||||
HYPERVISOR_OPENSTACK = "openstack"
|
||||
HYPERVISOR_UCLOUD = "ucloud"
|
||||
|
||||
// HYPERVISOR_DEFAULT = HYPERVISOR_KVM
|
||||
HYPERVISOR_DEFAULT = HYPERVISOR_KVM
|
||||
@@ -161,6 +162,7 @@ var HYPERVISORS = []string{HYPERVISOR_KVM,
|
||||
HYPERVISOR_QCLOUD,
|
||||
HYPERVISOR_HUAWEI,
|
||||
HYPERVISOR_OPENSTACK,
|
||||
HYPERVISOR_UCLOUD,
|
||||
}
|
||||
|
||||
var PUBLIC_CLOUD_HYPERVISORS = []string{
|
||||
@@ -170,6 +172,7 @@ var PUBLIC_CLOUD_HYPERVISORS = []string{
|
||||
HYPERVISOR_QCLOUD,
|
||||
HYPERVISOR_HUAWEI,
|
||||
HYPERVISOR_OPENSTACK,
|
||||
HYPERVISOR_UCLOUD,
|
||||
}
|
||||
|
||||
// var HYPERVISORS = []string{HYPERVISOR_ALIYUN}
|
||||
@@ -185,6 +188,7 @@ var HYPERVISOR_HOSTTYPE = map[string]string{
|
||||
HYPERVISOR_QCLOUD: HOST_TYPE_QCLOUD,
|
||||
HYPERVISOR_HUAWEI: HOST_TYPE_HUAWEI,
|
||||
HYPERVISOR_OPENSTACK: HOST_TYPE_OPENSTACK,
|
||||
HYPERVISOR_UCLOUD: HOST_TYPE_UCLOUD,
|
||||
}
|
||||
|
||||
var HOSTTYPE_HYPERVISOR = map[string]string{
|
||||
@@ -198,6 +202,7 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
|
||||
HOST_TYPE_QCLOUD: HYPERVISOR_QCLOUD,
|
||||
HOST_TYPE_HUAWEI: HYPERVISOR_HUAWEI,
|
||||
HOST_TYPE_OPENSTACK: HYPERVISOR_OPENSTACK,
|
||||
HOST_TYPE_UCLOUD: HYPERVISOR_UCLOUD,
|
||||
}
|
||||
|
||||
type SGuestManager struct {
|
||||
|
||||
@@ -51,6 +51,7 @@ const (
|
||||
HOST_TYPE_AZURE = "azure"
|
||||
HOST_TYPE_HUAWEI = "huawei"
|
||||
HOST_TYPE_OPENSTACK = "openstack"
|
||||
HOST_TYPE_UCLOUD = "ucloud"
|
||||
|
||||
HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR
|
||||
|
||||
|
||||
@@ -62,6 +62,10 @@ const (
|
||||
|
||||
// openstack
|
||||
STORAGE_OPENSTACK_ISCSI = "iscsi"
|
||||
|
||||
// Ucloud storage type
|
||||
STORAGE_UCLOUD_SATA = "SATA" // 普通盘
|
||||
STORAGE_UCLOUD_SSD = "SSD" // SSD盘
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -91,7 +95,7 @@ var (
|
||||
STORAGE_GP2_SSD, STORAGE_IO1_SSD, STORAGE_ST1_HDD, STORAGE_SC1_HDD, STORAGE_STANDARD_HDD,
|
||||
STORAGE_LOCAL_BASIC, STORAGE_LOCAL_SSD, STORAGE_CLOUD_BASIC, STORAGE_CLOUD_PREMIUM,
|
||||
STORAGE_HUAWEI_SSD, STORAGE_HUAWEI_SAS, STORAGE_HUAWEI_SATA,
|
||||
STORAGE_OPENSTACK_ISCSI,
|
||||
STORAGE_OPENSTACK_ISCSI, STORAGE_UCLOUD_SATA, STORAGE_UCLOUD_SSD,
|
||||
}
|
||||
|
||||
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
_ "yunion.io/x/onecloud/pkg/util/huawei/provider"
|
||||
_ "yunion.io/x/onecloud/pkg/util/openstack/provider"
|
||||
_ "yunion.io/x/onecloud/pkg/util/qcloud/provider"
|
||||
_ "yunion.io/x/onecloud/pkg/util/ucloud/provider"
|
||||
)
|
||||
|
||||
func StartService() {
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
)
|
||||
|
||||
const UCLOUD_API_HOST = "https://api.ucloud.cn"
|
||||
|
||||
// API返回结果对应的字段名
|
||||
var UCLOUD_API_RESULT_KEYS = map[string]string{
|
||||
"GetProjectList": "ProjectSet",
|
||||
"GetRegion": "Regions",
|
||||
"DescribeVPC": "DataSet",
|
||||
"DescribeImage": "ImageSet",
|
||||
"DescribeIsolationGroup": "IsolationGroupSet",
|
||||
"DescribeUHostInstance": "UHostSet",
|
||||
"DescribeUHostTags": "TagSet",
|
||||
"DescribeUDSet": "UDSet",
|
||||
"DescribeUDisk": "DataSet",
|
||||
"DescribeUDiskSnapshot": "DataSet",
|
||||
"DescribeEIP": "EIPSet",
|
||||
"DescribeFirewall": "DataSet",
|
||||
"DescribeSubnet": "DataSet",
|
||||
}
|
||||
|
||||
type SParams struct {
|
||||
data jsonutils.JSONDict
|
||||
}
|
||||
|
||||
type SUcloudError struct {
|
||||
Action string `json:"Action"`
|
||||
Message string `json:"Message"`
|
||||
RetCode int64 `json:"RetCode"`
|
||||
}
|
||||
|
||||
func (self *SUcloudError) Error() string {
|
||||
return fmt.Sprintf("Do %s failed, code: %d, %s", self.Action, self.RetCode, self.Message)
|
||||
}
|
||||
|
||||
func NewUcloudParams() SParams {
|
||||
data := jsonutils.NewDict()
|
||||
return SParams{data: *data}
|
||||
}
|
||||
|
||||
func (self *SParams) Set(key string, value interface{}) {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
self.data.Set(key, jsonutils.NewString(v))
|
||||
case int64:
|
||||
self.data.Set(key, jsonutils.NewInt(v))
|
||||
case int:
|
||||
self.data.Set(key, jsonutils.NewInt(int64(v)))
|
||||
case bool:
|
||||
self.data.Set(key, jsonutils.NewBool(v))
|
||||
case float64:
|
||||
self.data.Set(key, jsonutils.NewFloat(v))
|
||||
case float32:
|
||||
self.data.Set(key, jsonutils.NewFloat(float64(v)))
|
||||
case []string:
|
||||
self.data.Set(key, jsonutils.NewStringArray(v))
|
||||
default:
|
||||
log.Debugf("unsuported params type %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SParams) SetAction(action string) {
|
||||
self.data.Set("Action", jsonutils.NewString(action))
|
||||
}
|
||||
|
||||
func (self *SParams) SetPagination(limit, offset int) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
|
||||
self.data.Set("Limit", jsonutils.NewInt(int64(limit)))
|
||||
self.data.Set("Offset", jsonutils.NewInt(int64(offset)))
|
||||
}
|
||||
|
||||
func (self *SParams) String() string {
|
||||
return self.data.String()
|
||||
}
|
||||
|
||||
func (self *SParams) PrettyString() string {
|
||||
return self.data.PrettyString()
|
||||
}
|
||||
|
||||
func (self *SParams) GetParams() jsonutils.JSONDict {
|
||||
return self.data
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/summary/signature
|
||||
func BuildParams(params SParams, privateKey string) jsonutils.JSONObject {
|
||||
data := params.GetParams()
|
||||
// remove old Signature
|
||||
data.Remove("Signature")
|
||||
|
||||
// 排序并计算signture
|
||||
keys := data.SortedKeys()
|
||||
lst := []string{}
|
||||
for _, k := range keys {
|
||||
lst = append(lst, k)
|
||||
v, _ := data.GetString(k)
|
||||
lst = append(lst, v)
|
||||
}
|
||||
|
||||
raw := strings.Join(lst, "") + privateKey
|
||||
signture := fmt.Sprintf("%x", sha1.Sum([]byte(raw)))
|
||||
|
||||
data.Set("Signature", jsonutils.NewString(signture))
|
||||
return &data
|
||||
}
|
||||
|
||||
func GetSignature(params SParams, privateKey string) string {
|
||||
sign, _ := BuildParams(params, privateKey).GetString("Signature")
|
||||
return sign
|
||||
}
|
||||
|
||||
func parseUcloudResponse(resp jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
err := &SUcloudError{}
|
||||
e := resp.Unmarshal(err)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if err.RetCode > 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func jsonRequest(client *SUcloudClient, params SParams) (jsonutils.JSONObject, error) {
|
||||
ctx := context.Background()
|
||||
MAX_RETRY := 3
|
||||
retry := 0
|
||||
|
||||
for retry < MAX_RETRY {
|
||||
_, resp, err := httputils.JSONRequest(
|
||||
client.httpClient,
|
||||
ctx,
|
||||
httputils.POST,
|
||||
UCLOUD_API_HOST,
|
||||
nil,
|
||||
BuildParams(params, client.accessKeySecret),
|
||||
client.Debug)
|
||||
|
||||
if err == nil {
|
||||
return parseUcloudResponse(resp)
|
||||
}
|
||||
|
||||
switch e := err.(type) {
|
||||
case *httputils.JSONClientError:
|
||||
if e.Code >= 500 {
|
||||
time.Sleep(3 * time.Second)
|
||||
retry += 1
|
||||
continue
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("timeout for request: %s", params)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
)
|
||||
|
||||
func TestGetSignature(t *testing.T) {
|
||||
type args struct {
|
||||
params SParams
|
||||
privateKey string
|
||||
}
|
||||
|
||||
_obj, _ := jsonutils.ParseString(`{
|
||||
"Password" : "VUNsb3VkLmNu",
|
||||
"Region" : "cn-bj2",
|
||||
"Zone" : "cn-bj2-04",
|
||||
"ImageId" : "f43736e1-65a5-4bea-ad2e-8a46e18883c2",
|
||||
"CPU" : 2,
|
||||
"Memory" : 2048,
|
||||
"DiskSpace" : 10,
|
||||
"LoginMode" : "Password",
|
||||
"Action" : "CreateUHostInstance",
|
||||
"Name" : "Host01",
|
||||
"ChargeType" : "Month",
|
||||
"Quantity" : 1,
|
||||
"PublicKey" : "ucloudsomeone@example.com1296235120854146120"
|
||||
}`)
|
||||
|
||||
obj := _obj.(*jsonutils.JSONDict)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Ucloud api signature validate",
|
||||
args: args{
|
||||
params: SParams{data: *obj},
|
||||
privateKey: "46f09bb9fab4f12dfc160dae12273d5332b5debe",
|
||||
},
|
||||
want: "4f9ef5df2abab2c6fccd1e9515cb7e2df8c6bb65",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetSignature(tt.args.params, tt.args.privateKey); got != tt.want {
|
||||
t.Errorf("GetSignature() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package ucloud
|
||||
|
||||
// https://docs.ucloud.cn/api/summary/regionlist
|
||||
var UCLOUD_REGION_NAMES = map[string]string{
|
||||
"cn-bj1": "北京一",
|
||||
"cn-bj2": "北京二",
|
||||
"cn-sh": "上海金融云",
|
||||
"cn-sh2": "上海二",
|
||||
"cn-gd": "广州",
|
||||
"hk": "香港",
|
||||
"us-ca": "洛杉矶",
|
||||
"us-ws": "华盛顿",
|
||||
"ge-fra": "法兰克福",
|
||||
"th-bkk": "曼谷",
|
||||
"kr-seoul": "首尔",
|
||||
"sg": "新加坡",
|
||||
"tw-tp": "台北",
|
||||
"tw-kh": "高雄",
|
||||
"jpn-tky": "东京",
|
||||
"rus-mosc": "莫斯科",
|
||||
"uae-dubai": "迪拜",
|
||||
"idn-jakarta": "雅加达",
|
||||
"ind-mumbai": "孟买",
|
||||
"bra-saopaulo": "圣保罗",
|
||||
"uk-london": "伦敦",
|
||||
"afr-nigeria": "拉各斯",
|
||||
"vn-sng": "胡志明市",
|
||||
}
|
||||
|
||||
var UCLOUD_ZONE_NAMES = map[string]string{
|
||||
"cn-bj1-01": "北京一可用区A",
|
||||
"cn-bj2-02": "北京二可用区B",
|
||||
"cn-bj2-03": "北京二可用区C",
|
||||
"cn-bj2-04": "北京二可用区D",
|
||||
"cn-bj2-05": "北京二可用区E",
|
||||
"cn-sh-01": "上海一可用区A",
|
||||
"cn-sh2-01": "上海二可用区A",
|
||||
"cn-sh2-02": "上海二可用区B",
|
||||
"cn-gd-02": "广州可用区B",
|
||||
"hk-01": "香港可用区A",
|
||||
"hk-02": "香港可用区B",
|
||||
"us-ca-01": "洛杉矶可用区A",
|
||||
"us-ws-01": "华盛顿可用区A",
|
||||
"ge-fra-01": "法兰克福可用区A",
|
||||
"th-bkk-01": "曼谷可用区A",
|
||||
"kr-seoul-01": "首尔可用区A",
|
||||
"sg-01": "新加坡可用区A",
|
||||
"tw-kh-01": "高雄可用区A",
|
||||
"tw-tp-01": "台北可用区A",
|
||||
"jpn-tky-01": "东京可用区A",
|
||||
"rus-mosc-01": "莫斯科可用区A",
|
||||
"uae-dubai-01": "迪拜可用区A",
|
||||
"idn-jakarta-01": "雅加达可用区A",
|
||||
"ind-mumbai-01": "孟买可用区A",
|
||||
"bra-saopaulo-01": "圣保罗可用区A",
|
||||
"uk-london-01": "伦敦可用区A",
|
||||
"afr-nigeria-01": "拉各斯可用区A",
|
||||
"vn-sng-01": "胡志明市可用区A",
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/pkg/utils"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/udisk-api/describe_udisk
|
||||
type SDisk struct {
|
||||
storage *SStorage
|
||||
|
||||
Status string `json:"Status"`
|
||||
DeviceName string `json:"DeviceName"`
|
||||
UHostID string `json:"UHostId"`
|
||||
Tag string `json:"Tag"`
|
||||
Version string `json:"Version"`
|
||||
Name string `json:"Name"`
|
||||
Zone string `json:"Zone"`
|
||||
UHostIP string `json:"UHostIP"`
|
||||
DiskType string `json:"DiskType"`
|
||||
UDataArkMode string `json:"UDataArkMode"`
|
||||
SnapshotLimit int `json:"SnapshotLimit"`
|
||||
ExpiredTime int64 `json:"ExpiredTime"`
|
||||
SnapshotCount int `json:"SnapshotCount"`
|
||||
IsExpire string `json:"IsExpire"`
|
||||
UDiskID string `json:"UDiskId"`
|
||||
ChargeType string `json:"ChargeType"`
|
||||
UHostName string `json:"UHostName"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
SizeGB int `json:"Size"`
|
||||
}
|
||||
|
||||
func (self *SDisk) GetProjectId() string {
|
||||
return self.storage.zone.region.client.projectId
|
||||
}
|
||||
|
||||
func (self *SDisk) GetId() string {
|
||||
return self.UDiskID
|
||||
}
|
||||
|
||||
func (self *SDisk) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *SDisk) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SDisk) GetStatus() string {
|
||||
switch self.Status {
|
||||
case "Available":
|
||||
return models.DISK_READY
|
||||
case "Attaching":
|
||||
return models.DISK_ATTACHING
|
||||
case "InUse":
|
||||
return models.DISK_READY
|
||||
case "Detaching":
|
||||
return models.DISK_DETACHING
|
||||
case "Initializating":
|
||||
return models.DISK_ALLOCATING
|
||||
case "Failed":
|
||||
return models.DISK_ALLOC_FAILED
|
||||
case "Cloning":
|
||||
return models.DISK_SAVING // ??????
|
||||
case "Restoring":
|
||||
return models.DISK_BACKUP_STARTALLOC // ???
|
||||
case "RestoreFailed":
|
||||
return models.DISK_BACKUP_ALLOC_FAILED // ??
|
||||
default:
|
||||
return models.DISK_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SDisk) Refresh() error {
|
||||
new, err := self.storage.zone.region.GetDisk(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SDisk) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SDisk) GetMetadata() *jsonutils.JSONDict {
|
||||
// todo: add price key
|
||||
data := jsonutils.NewDict()
|
||||
data.Add(jsonutils.NewString(models.HYPERVISOR_UCLOUD), "hypervisor")
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Year,Month,Dynamic,Trial
|
||||
func (self *SDisk) GetBillingType() string {
|
||||
switch self.ChargeType {
|
||||
case "Year", "Month":
|
||||
return models.BILLING_TYPE_PREPAID
|
||||
default:
|
||||
return models.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SDisk) GetExpiredAt() time.Time {
|
||||
return time.Unix(self.ExpiredTime, 0)
|
||||
}
|
||||
|
||||
func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
return self.storage, nil
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDiskFormat() string {
|
||||
return "vhd"
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDiskSizeMB() int {
|
||||
return self.SizeGB * 1024
|
||||
}
|
||||
|
||||
func (self *SDisk) GetIsAutoDelete() bool {
|
||||
if self.DiskType == "SystemDisk" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SDisk) GetTemplateId() string {
|
||||
if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 {
|
||||
ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
|
||||
return ins.ImageID
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDiskType() string {
|
||||
if strings.Contains(self.DiskType, "SystemDisk") {
|
||||
return models.DISK_TYPE_SYS
|
||||
}
|
||||
|
||||
return models.DISK_TYPE_DATA
|
||||
}
|
||||
|
||||
func (self *SDisk) GetFsFormat() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SDisk) GetIsNonPersistent() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDriver() string {
|
||||
return "scsi"
|
||||
}
|
||||
|
||||
func (self *SDisk) GetCacheMode() string {
|
||||
return "none"
|
||||
}
|
||||
|
||||
func (self *SDisk) GetMountpoint() string {
|
||||
return self.DeviceName
|
||||
}
|
||||
|
||||
func (self *SDisk) GetAccessPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SDisk) Delete(ctx context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) {
|
||||
snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId)
|
||||
return &snapshot, err
|
||||
}
|
||||
|
||||
func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) {
|
||||
snapshot, err := self.getSnapshot(idStr)
|
||||
return snapshot, err
|
||||
}
|
||||
|
||||
func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
snapshots, err := self.storage.zone.region.GetSnapshots(self.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots))
|
||||
for i := 0; i < len(snapshots); i++ {
|
||||
isnapshots[i] = &snapshots[i]
|
||||
}
|
||||
return isnapshots, nil
|
||||
}
|
||||
|
||||
func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SDisk) Rebuild(ctx context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
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})
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
disks := make([]SDisk, 0)
|
||||
params := NewUcloudParams()
|
||||
if len(zoneId) > 0 {
|
||||
params.Set("Zone", zoneId)
|
||||
}
|
||||
|
||||
if len(diskType) > 0 {
|
||||
params.Set("DiskType", diskType)
|
||||
}
|
||||
|
||||
err := self.DoListAll("DescribeUDisk", params, &disks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if diskIds != nil && len(diskIds) > 0 {
|
||||
filtedDisks := make([]SDisk, 0)
|
||||
for _, disk := range disks {
|
||||
if utils.IsInStringArray(disk.UDiskID, diskIds) {
|
||||
filtedDisks = append(filtedDisks, disk)
|
||||
}
|
||||
}
|
||||
|
||||
return filtedDisks, nil
|
||||
}
|
||||
|
||||
return disks, nil
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/log"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/describe_eip
|
||||
type SEip struct {
|
||||
region *SRegion
|
||||
|
||||
BandwidthMb int `json:"Bandwidth"`
|
||||
BandwidthType int `json:"BandwidthType"`
|
||||
ChargeType string `json:"ChargeType"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
EIPAddr []EIPAddr `json:"EIPAddr"`
|
||||
EIPID string `json:"EIPId"`
|
||||
Expire bool `json:"Expire"`
|
||||
ExpireTime int64 `json:"ExpireTime"`
|
||||
Name string `json:"Name"`
|
||||
PayMode string `json:"PayMode"`
|
||||
Remark string `json:"Remark"`
|
||||
Resource Resource `json:"Resource"`
|
||||
ShareBandwidthSet ShareBandwidthSet `json:"ShareBandwidthSet"`
|
||||
Status string `json:"Status"`
|
||||
Tag string `json:"Tag"`
|
||||
Weight int `json:"Weight"`
|
||||
}
|
||||
|
||||
func (self *SEip) GetProjectId() string {
|
||||
return self.region.client.projectId
|
||||
}
|
||||
|
||||
type EIPAddr struct {
|
||||
IP string `json:"IP"`
|
||||
OperatorName string `json:"OperatorName"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
ResourceID string `json:"ResourceID"`
|
||||
ResourceName string `json:"ResourceName"`
|
||||
ResourceType string `json:"ResourceType"`
|
||||
Zone string `json:"Zone"`
|
||||
}
|
||||
|
||||
type ShareBandwidthSet struct {
|
||||
ShareBandwidth int `json:"ShareBandwidth"`
|
||||
ShareBandwidthID string `json:"ShareBandwidthId"`
|
||||
ShareBandwidthName string `json:"ShareBandwidthName"`
|
||||
}
|
||||
|
||||
func (self *SEip) GetId() string {
|
||||
return self.EIPID
|
||||
}
|
||||
|
||||
func (self *SEip) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *SEip) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
// 弹性IP的资源绑定状态, 枚举值为: used: 已绑定, free: 未绑定, freeze: 已冻结
|
||||
func (self *SEip) GetStatus() string {
|
||||
switch self.Status {
|
||||
case "used":
|
||||
return models.EIP_STATUS_ASSOCIATE // ?
|
||||
case "free":
|
||||
return models.EIP_STATUS_READY
|
||||
case "freeze":
|
||||
return models.EIP_STATUS_UNKNOWN
|
||||
default:
|
||||
return models.EIP_STATUS_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SEip) Refresh() error {
|
||||
if self.IsEmulated() {
|
||||
return nil
|
||||
}
|
||||
new, err := self.region.GetEipById(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SEip) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SEip) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 付费方式, 枚举值为: Year, 按年付费; Month, 按月付费; Dynamic, 按小时付费; Trial, 试用. 按小时付费和试用这两种付费模式需要开通权限.
|
||||
func (self *SEip) GetBillingType() string {
|
||||
switch self.ChargeType {
|
||||
case "Year", "Month":
|
||||
return models.BILLING_TYPE_PREPAID
|
||||
default:
|
||||
return models.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SEip) GetExpiredAt() time.Time {
|
||||
return time.Unix(self.ExpireTime, 0)
|
||||
}
|
||||
|
||||
func (self *SEip) GetIpAddr() string {
|
||||
if len(self.EIPAddr) > 1 {
|
||||
log.Warning("GetIpAddr %d eip addr found", len(self.EIPAddr))
|
||||
} else if len(self.EIPAddr) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return self.EIPAddr[0].IP
|
||||
}
|
||||
|
||||
func (self *SEip) GetMode() string {
|
||||
return models.EIP_MODE_STANDALONE_EIP
|
||||
}
|
||||
|
||||
func (self *SEip) GetAssociationType() string {
|
||||
return "server"
|
||||
}
|
||||
|
||||
// 已绑定的资源类型, 枚举值为: uhost, 云主机;natgw:NAT网关;ulb:负载均衡器;upm: 物理机; hadoophost: 大数据集群;fortresshost:堡垒机;udockhost:容器;udhost:私有专区主机;vpngw:IPSec VPN;ucdr:云灾备;dbaudit:数据库审计。
|
||||
func (self *SEip) GetAssociationExternalId() string {
|
||||
if self.Resource.ResourceType == "uhost" {
|
||||
return self.Resource.ResourceID
|
||||
} else if self.Resource.ResourceType != "" {
|
||||
log.Warningf("GetAssociationExternalId bind with %s %s.expect bind with uhost", self.Resource.ResourceType, self.Resource.ResourceID)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SEip) GetBandwidth() int {
|
||||
return self.BandwidthMb
|
||||
}
|
||||
|
||||
// 弹性IP的计费模式, 枚举值为: "Bandwidth", 带宽计费; "Traffic", 流量计费; "ShareBandwidth",共享带宽模式. 默认为 "Bandwidth".
|
||||
func (self *SEip) GetInternetChargeType() string {
|
||||
switch self.PayMode {
|
||||
case "Bandwidth":
|
||||
return models.EIP_CHARGE_TYPE_BY_BANDWIDTH
|
||||
case "Traffic":
|
||||
return models.EIP_CHARGE_TYPE_BY_TRAFFIC
|
||||
default:
|
||||
return models.EIP_CHARGE_TYPE_BY_TRAFFIC
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SEip) GetManagerId() string {
|
||||
return self.region.client.providerId
|
||||
}
|
||||
|
||||
func (self *SEip) Delete() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SEip) Associate(instanceId string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SEip) Dissociate() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SEip) ChangeBandwidth(bw int) error {
|
||||
panic("implement me")
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SHost struct {
|
||||
zone *SZone
|
||||
|
||||
projectId string
|
||||
}
|
||||
|
||||
func (self *SHost) GetId() string {
|
||||
return fmt.Sprintf("%s-%s", self.zone.region.client.providerId, self.zone.GetId())
|
||||
}
|
||||
|
||||
func (self *SHost) GetName() string {
|
||||
return fmt.Sprintf("%s-%s", self.zone.region.client.providerName, self.zone.GetId())
|
||||
}
|
||||
|
||||
func (self *SHost) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SHost) GetStatus() string {
|
||||
return models.HOST_STATUS_RUNNING
|
||||
}
|
||||
|
||||
func (self *SHost) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHost) IsEmulated() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SHost) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := self.zone.GetInstances()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
vms[i].host = self
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
vm, err := self.zone.region.GetInstanceByID(id)
|
||||
vm.host = self
|
||||
return &vm, err
|
||||
}
|
||||
|
||||
func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
return self.zone.GetIWires()
|
||||
}
|
||||
|
||||
func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
return self.zone.GetIStorages()
|
||||
}
|
||||
|
||||
func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
return self.zone.GetIStorageById(id)
|
||||
}
|
||||
|
||||
func (self *SHost) GetEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SHost) GetHostStatus() string {
|
||||
return models.HOST_ONLINE
|
||||
}
|
||||
|
||||
func (self *SHost) GetAccessIp() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SHost) GetAccessMac() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SHost) GetSysInfo() jsonutils.JSONObject {
|
||||
info := jsonutils.NewDict()
|
||||
info.Add(jsonutils.NewString(CLOUD_PROVIDER_UCLOUD), "manufacture")
|
||||
return info
|
||||
}
|
||||
|
||||
func (self *SHost) GetSN() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SHost) GetCpuCount() int8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SHost) GetNodeCount() int8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SHost) GetCpuDesc() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SHost) GetCpuMhz() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SHost) GetMemSizeMB() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SHost) GetStorageSizeMB() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SHost) GetStorageType() string {
|
||||
return models.DISK_TYPE_HYBRID
|
||||
}
|
||||
|
||||
func (self *SHost) GetHostType() string {
|
||||
return models.HOST_TYPE_UCLOUD
|
||||
}
|
||||
|
||||
func (self *SHost) GetIsMaintenance() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SHost) GetVersion() string {
|
||||
return UCLOUD_API_VERSION
|
||||
}
|
||||
|
||||
func (self *SHost) GetManagerId() string {
|
||||
return self.zone.region.client.providerId
|
||||
}
|
||||
|
||||
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/imagetools"
|
||||
)
|
||||
|
||||
type SImage struct {
|
||||
storageCache *SStoragecache
|
||||
|
||||
Zone string `json:"Zone"`
|
||||
ImageDescription string `json:"ImageDescription"`
|
||||
OSName string `json:"OsName"`
|
||||
ImageID string `json:"ImageId"`
|
||||
State string `json:"State"`
|
||||
ImageName string `json:"ImageName"`
|
||||
OSType string `json:"OsType"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
ImageType string `json:"ImageType"`
|
||||
ImageSizeGB int64 `json:"ImageSize"`
|
||||
}
|
||||
|
||||
func (self *SImage) GetMinRamSizeMb() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SImage) GetId() string {
|
||||
return self.ImageID
|
||||
}
|
||||
|
||||
func (self *SImage) GetName() string {
|
||||
if len(self.ImageName) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.ImageName
|
||||
}
|
||||
|
||||
func (self *SImage) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
// 镜像状态, 可用:Available,制作中:Making, 不可用:Unavailable
|
||||
func (self *SImage) GetStatus() string {
|
||||
switch self.State {
|
||||
case "Available":
|
||||
return cloudprovider.IMAGE_STATUS_ACTIVE
|
||||
case "Making":
|
||||
return cloudprovider.IMAGE_STATUS_QUEUED
|
||||
case "Unavailable":
|
||||
return cloudprovider.IMAGE_STATUS_KILLED
|
||||
default:
|
||||
return cloudprovider.IMAGE_STATUS_KILLED
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SImage) Refresh() error {
|
||||
new, err := self.storageCache.region.GetImage(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SImage) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SImage) GetMetadata() *jsonutils.JSONDict {
|
||||
imageInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "")
|
||||
data := jsonutils.NewDict()
|
||||
if len(imageInfo.OsArch) > 0 {
|
||||
data.Add(jsonutils.NewString(imageInfo.OsArch), "os_arch")
|
||||
}
|
||||
if len(imageInfo.OsType) > 0 {
|
||||
data.Add(jsonutils.NewString(imageInfo.OsType), "os_name")
|
||||
}
|
||||
if len(imageInfo.OsDistro) > 0 {
|
||||
data.Add(jsonutils.NewString(imageInfo.OsDistro), "os_distribution")
|
||||
}
|
||||
if len(imageInfo.OsVersion) > 0 {
|
||||
data.Add(jsonutils.NewString(imageInfo.OsVersion), "os_version")
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (self *SImage) Delete(ctx context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
|
||||
return self.storageCache
|
||||
}
|
||||
|
||||
func (self *SImage) GetSize() int64 {
|
||||
return self.ImageSizeGB * 1024 * 1024 * 1024
|
||||
}
|
||||
|
||||
// 镜像类型。标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型
|
||||
func (self *SImage) GetImageType() string {
|
||||
switch self.ImageType {
|
||||
case "Base":
|
||||
return cloudprovider.CachedImageTypeSystem
|
||||
case "Custom":
|
||||
return cloudprovider.CachedImageTypeCustomized
|
||||
case "Business":
|
||||
return cloudprovider.CachedImageTypeShared
|
||||
default:
|
||||
return cloudprovider.CachedImageTypeCustomized
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SImage) GetImageStatus() string {
|
||||
switch self.State {
|
||||
case "Available":
|
||||
return models.CACHED_IMAGE_STATUS_READY
|
||||
case "Making":
|
||||
return models.CACHED_IMAGE_STATUS_CACHING
|
||||
case "Unavailable":
|
||||
return models.CACHED_IMAGE_STATUS_CACHE_FAILED
|
||||
default:
|
||||
return models.CACHED_IMAGE_STATUS_CACHE_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SImage) GetOsType() string {
|
||||
imageInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "")
|
||||
return imageInfo.OsType
|
||||
}
|
||||
|
||||
func (self *SImage) GetOsDist() string {
|
||||
imageInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "")
|
||||
return imageInfo.OsDistro
|
||||
}
|
||||
|
||||
func (self *SImage) GetOsVersion() string {
|
||||
imageInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "")
|
||||
return imageInfo.OsVersion
|
||||
}
|
||||
|
||||
func (self *SImage) GetOsArch() string {
|
||||
imageInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "")
|
||||
return imageInfo.OsArch
|
||||
}
|
||||
|
||||
func (self *SImage) GetMinOsDiskSizeGb() int {
|
||||
return int(self.ImageSizeGB)
|
||||
}
|
||||
|
||||
func (self *SImage) GetImageFormat() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SImage) GetCreateTime() time.Time {
|
||||
return time.Unix(self.CreateTime, 0)
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/describe_image
|
||||
func (self *SRegion) GetImage(imageId string) (SImage, error) {
|
||||
params := NewUcloudParams()
|
||||
params.Set("ImageId", imageId)
|
||||
|
||||
images := make([]SImage, 0)
|
||||
err := self.DoListAll("DescribeImage", params, &images)
|
||||
if err != nil {
|
||||
return SImage{}, err
|
||||
}
|
||||
|
||||
if len(images) == 1 {
|
||||
return images[0], nil
|
||||
} else if len(images) == 0 {
|
||||
return SImage{}, cloudprovider.ErrNotFound
|
||||
} else {
|
||||
return SImage{}, fmt.Errorf("GetImage %s %d found.", imageId, len(images))
|
||||
}
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/describe_image
|
||||
// ImageType 标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型
|
||||
func (self *SRegion) GetImages(imageType string, imageId string) ([]SImage, error) {
|
||||
params := NewUcloudParams()
|
||||
|
||||
if len(imageId) > 0 {
|
||||
params.Set("ImageId", imageId)
|
||||
}
|
||||
|
||||
if len(imageType) > 0 {
|
||||
params.Set("ImageType", imageType)
|
||||
}
|
||||
|
||||
images := make([]SImage, 0)
|
||||
err := self.DoListAll("DescribeImage", params, &images)
|
||||
return images, err
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
"yunion.io/x/pkg/util/osprofile"
|
||||
)
|
||||
|
||||
type SInstance struct {
|
||||
host *SHost
|
||||
|
||||
UHostID string `json:"UHostId"`
|
||||
Zone string `json:"Zone"`
|
||||
LifeCycle string `json:"LifeCycle"`
|
||||
OSName string `json:"OsName"`
|
||||
ImageID string `json:"ImageId"`
|
||||
BasicImageID string `json:"BasicImageId"`
|
||||
BasicImageName string `json:"BasicImageName"`
|
||||
Tag string `json:"Tag"`
|
||||
Name string `json:"Name"`
|
||||
Remark string `json:"Remark"`
|
||||
State string `json:"State"`
|
||||
NetworkState string `json:"NetworkState"`
|
||||
HostType string `json:"HostType"`
|
||||
StorageType string `json:"StorageType"`
|
||||
TotalDiskSpace int `json:"TotalDiskSpace"`
|
||||
DiskSet []DiskSet `json:"DiskSet"`
|
||||
NetCapability string `json:"NetCapability"`
|
||||
IPSet []IPSet `json:"IPSet"`
|
||||
SubnetType string `json:"SubnetType"`
|
||||
ChargeType string `json:"ChargeType"`
|
||||
ExpireTime int64 `json:"ExpireTime"`
|
||||
AutoRenew string `json:"AutoRenew"`
|
||||
IsExpire string `json:"IsExpire"`
|
||||
UHostType string `json:"UHostType"`
|
||||
OSType string `json:"OsType"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
CPU int `json:"CPU"`
|
||||
GPU int `json:"GPU"`
|
||||
MemoryMB int `json:"Memory"`
|
||||
TimemachineFeature string `json:"TimemachineFeature"`
|
||||
HotplugFeature bool `json:"HotplugFeature"`
|
||||
NetCapFeature bool `json:"NetCapFeature"`
|
||||
BootDiskState string `json:"BootDiskState"`
|
||||
}
|
||||
|
||||
func (self *SInstance) GetProjectId() string {
|
||||
return self.host.zone.region.client.projectId
|
||||
}
|
||||
|
||||
func (self *SInstance) GetError() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
type DiskSet struct {
|
||||
DiskID string `json:"DiskId"`
|
||||
Drive string `json:"Drive"`
|
||||
Size int `json:"Size"`
|
||||
Encrypted string `json:"Encrypted"`
|
||||
Type string `json:"Type"`
|
||||
}
|
||||
|
||||
type IPSet struct {
|
||||
Type string `json:"Type"`
|
||||
IP string `json:"IP"`
|
||||
IPId string `json:"IPId"` // IP资源ID (内网IP无对应的资源ID)
|
||||
MAC string `json:"Mac"`
|
||||
VPCID string `json:"VPCId"`
|
||||
SubnetID string `json:"SubnetId"`
|
||||
}
|
||||
|
||||
type SVncInfo struct {
|
||||
VNCIP string `json:"VncIP"`
|
||||
VNCPassword string `json:"VncPassword"`
|
||||
UHostID string `json:"UHostId"`
|
||||
Action string `json:"Action"`
|
||||
VNCPort string `json:"VncPort"`
|
||||
}
|
||||
|
||||
func (self *SInstance) GetId() string {
|
||||
return self.UHostID
|
||||
}
|
||||
|
||||
func (self *SInstance) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *SInstance) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
// 实例状态,枚举值:
|
||||
// >初始化: Initializing;
|
||||
// >启动中: Starting;
|
||||
// > 运行中: Running;
|
||||
// > 关机中: Stopping;
|
||||
// >关机: Stopped
|
||||
// >安装失败: Install Fail;
|
||||
// >重启中: Rebooting
|
||||
func (self *SInstance) GetStatus() string {
|
||||
switch self.State {
|
||||
case "Running":
|
||||
return models.VM_RUNNING
|
||||
case "Stopped":
|
||||
return models.VM_READY
|
||||
case "Rebooting":
|
||||
return models.VM_STOPPING
|
||||
case "Initializing":
|
||||
return models.VM_INIT
|
||||
case "Starting":
|
||||
return models.VM_STARTING
|
||||
case "Stopping":
|
||||
return models.VM_STOPPING
|
||||
case "Install Fail":
|
||||
return models.VM_CREATE_FAILED
|
||||
default:
|
||||
return models.VM_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SInstance) Refresh() error {
|
||||
new, err := self.host.zone.region.GetInstanceByID(self.GetId())
|
||||
new.host = self.host
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SInstance) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
|
||||
data := jsonutils.NewDict()
|
||||
// todo: add price key here
|
||||
data.Add(jsonutils.NewString(self.host.zone.GetGlobalId()), "zone_ext_id")
|
||||
if len(self.BasicImageID) > 0 {
|
||||
if image, err := self.host.zone.region.GetImage(self.BasicImageID); err != nil {
|
||||
log.Errorf("Failed to find image %s for instance %s", self.BasicImageID, self.GetName())
|
||||
} else if meta := image.GetMetadata(); meta != nil {
|
||||
data.Update(meta)
|
||||
}
|
||||
}
|
||||
|
||||
secgroups, err := self.GetSecurityGroups()
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
secgroupIds := jsonutils.NewArray()
|
||||
for _, secgroup := range secgroups {
|
||||
secgroupIds.Add(jsonutils.NewString(secgroup.GetId()))
|
||||
}
|
||||
data.Add(secgroupIds, "secgroupIds")
|
||||
return data
|
||||
}
|
||||
|
||||
// 计费模式,枚举值为: Year,按年付费; Month,按月付费; Dynamic,按需付费(需开启权限);
|
||||
func (self *SInstance) GetBillingType() string {
|
||||
switch self.ChargeType {
|
||||
case "Year", "Month":
|
||||
return models.BILLING_TYPE_PREPAID
|
||||
default:
|
||||
return models.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SInstance) GetExpiredAt() time.Time {
|
||||
return time.Unix(self.ExpireTime, 0)
|
||||
}
|
||||
|
||||
func (self *SInstance) GetCreateTime() time.Time {
|
||||
return time.Unix(self.CreateTime, 0)
|
||||
}
|
||||
|
||||
func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
|
||||
return self.host
|
||||
}
|
||||
|
||||
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
diskIds := make([]string, 0)
|
||||
for _, disk := range self.DiskSet {
|
||||
diskIds = append(diskIds, disk.DiskID)
|
||||
}
|
||||
|
||||
disks, err := self.host.zone.region.GetDisks("", "", diskIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idisks := make([]cloudprovider.ICloudDisk, len(disks))
|
||||
for i := 0; i < len(disks); i += 1 {
|
||||
idisks[i] = &disks[i]
|
||||
// 将系统盘放到第0个位置
|
||||
if disks[i].GetDiskType() == models.DISK_TYPE_SYS {
|
||||
_temp := idisks[0]
|
||||
idisks[0] = &disks[i]
|
||||
idisks[i] = _temp
|
||||
}
|
||||
}
|
||||
|
||||
return idisks, nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
||||
nics := make([]cloudprovider.ICloudNic, 0)
|
||||
|
||||
for _, ip := range self.IPSet {
|
||||
if len(ip.SubnetID) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nic := SInstanceNic{instance: self, ipAddr: ip.IP}
|
||||
nics = append(nics, &nic)
|
||||
}
|
||||
|
||||
return nics, nil
|
||||
}
|
||||
|
||||
// 国际: Internation,BGP: BGP,内网: Private
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &eip, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVcpuCount() int8 {
|
||||
return int8(self.CPU)
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVmemSizeMB() int {
|
||||
return self.MemoryMB
|
||||
}
|
||||
|
||||
func (self *SInstance) GetBootOrder() string {
|
||||
return "dcn"
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVga() string {
|
||||
return "std"
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVdi() string {
|
||||
return "vnc"
|
||||
}
|
||||
|
||||
func (self *SInstance) GetOSType() string {
|
||||
return osprofile.NormalizeOSType(self.OSType)
|
||||
}
|
||||
|
||||
func (self *SInstance) GetOSName() string {
|
||||
return self.OSName
|
||||
}
|
||||
|
||||
func (self *SInstance) GetBios() string {
|
||||
return "BIOS"
|
||||
}
|
||||
|
||||
func (self *SInstance) GetMachine() string {
|
||||
return "pc"
|
||||
}
|
||||
|
||||
func (self *SInstance) GetInstanceType() string {
|
||||
return self.UHostType
|
||||
}
|
||||
|
||||
func (self *SInstance) AssignSecurityGroup(secgroupId string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) GetHypervisor() string {
|
||||
return models.HYPERVISOR_UCLOUD
|
||||
}
|
||||
|
||||
func (self *SInstance) StartVM(ctx context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) StopVM(ctx context.Context, isForce bool) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) UpdateUserData(userData string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
|
||||
return self.host.zone.region.GetInstanceVNCUrl(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) Renew(bc billing.SBillingCycle) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SInstance) GetSecurityGroups() ([]SSecurityGroup, error) {
|
||||
return self.host.zone.region.GetSecurityGroups("", self.GetId())
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/get_uhost_instance_vnc_info
|
||||
// todo: implement me
|
||||
func (self *SRegion) GetInstanceVNCUrl(instanceId string) (jsonutils.JSONObject, error) {
|
||||
params := NewUcloudParams()
|
||||
params.Set("UHostId", instanceId)
|
||||
vnc := SVncInfo{}
|
||||
err := self.DoAction("GetUHostInstanceVncInfo", params, &vnc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return jsonutils.Marshal(&vnc), nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
type SInstanceNic struct {
|
||||
instance *SInstance
|
||||
ipAddr string
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetIP() string {
|
||||
return self.ipAddr
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetMAC() string {
|
||||
ip, _ := netutils.NewIPV4Addr(self.ipAddr)
|
||||
return ip.ToMac("00:16:")
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetDriver() string {
|
||||
return "virtio"
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
|
||||
for _, ip := range self.instance.IPSet {
|
||||
if ip.IP == self.ipAddr {
|
||||
network, _ := self.instance.host.zone.region.getNetwork(ip.SubnetID)
|
||||
return network
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package ucloud
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
|
||||
// https://docs.ucloud.cn/api/summary/regionlist
|
||||
var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{
|
||||
"cn-bj1": {Latitude: 39.9041999, Longitude: 116.4073963, City: "Beijing", CountryCode: "CN"},
|
||||
"cn-bj2": {Latitude: 39.9041999, Longitude: 116.4073963, City: "Beijing", CountryCode: "CN"},
|
||||
"cn-sh": {Latitude: 31.2303904, Longitude: 121.4737021, City: "Shanghai", CountryCode: "CN"},
|
||||
"cn-sh2": {Latitude: 31.2303904, Longitude: 121.4737021, City: "Shanghai", CountryCode: "CN"},
|
||||
"cn-gd": {Latitude: 23.12911, Longitude: 113.264385, City: "Guangzhou", CountryCode: "CN"},
|
||||
"hk": {Latitude: 22.396428, Longitude: 114.109497, City: "Hong Kong", CountryCode: "CN"},
|
||||
"us-ca": {Latitude: 34.0522342, Longitude: -118.2436849, City: "Los Angeles", CountryCode: "US"},
|
||||
"us-ws": {Latitude: 38.9071923, Longitude: -77.0368707, City: "Washington", CountryCode: "US"},
|
||||
"ge-fra": {Latitude: 50.1109221, Longitude: 8.6821267, City: "Frankfurt", CountryCode: "GE"},
|
||||
"th-bkk": {Latitude: 13.7563309, Longitude: 100.5017651, City: "Bangkok", CountryCode: "TH"},
|
||||
"kr-seoul": {Latitude: 37.566535, Longitude: 126.9779692, City: "Seoul", CountryCode: "KR"},
|
||||
"sg": {Latitude: 1.352083, Longitude: 103.819836, City: "Singapore", CountryCode: "SG"},
|
||||
"tw-tp": {Latitude: 25.0329694, Longitude: 121.5654177, City: "Taipei", CountryCode: "CN"},
|
||||
"tw-kh": {Latitude: 22.6272784, Longitude: 120.3014353, City: "Kaohsiung", CountryCode: "CN"},
|
||||
"jpn-tky": {Latitude: 35.7090259, Longitude: 139.7319925, City: "Tokyo", CountryCode: "JP"},
|
||||
"rus-mosc": {Latitude: 55.755826, Longitude: 37.6172999, City: "Moscow", CountryCode: "RU"},
|
||||
"uae-dubai": {Latitude: 25.2048493, Longitude: 55.2707828, City: "Dubai", CountryCode: "UA"},
|
||||
"idn-jakarta": {Latitude: -6.2087634, Longitude: 106.845599, City: "Jakarta", CountryCode: "ID"},
|
||||
"ind-mumbai": {Latitude: 19.0759837, Longitude: 72.8776559, City: "Mumbai", CountryCode: "IN"},
|
||||
"bra-saopaulo": {Latitude: -23.5505199, Longitude: -46.6333094, City: "São Paulo", CountryCode: "BR"},
|
||||
"uk-london": {Latitude: 51.5073509, Longitude: -0.1277583, City: "London", CountryCode: "UK"},
|
||||
"afr-nigeria": {Latitude: 6.5243793, Longitude: 3.3792057, City: "Lagos", CountryCode: "AF"},
|
||||
"vn-sng": {Latitude: 10.8230989, Longitude: 106.6296638, City: "Ho Chi Minh", CountryCode: "VN"},
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet
|
||||
type SNetwork struct {
|
||||
wire *SWire
|
||||
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
Gateway string `json:"Gateway"`
|
||||
HasNATGW bool `json:"HasNATGW"`
|
||||
Name string `json:"Name"`
|
||||
Netmask string `json:"Netmask"`
|
||||
Remark string `json:"Remark"`
|
||||
RouteTableID string `json:"RouteTableId"`
|
||||
Subnet string `json:"Subnet"`
|
||||
SubnetID string `json:"SubnetId"`
|
||||
SubnetName string `json:"SubnetName"`
|
||||
SubnetType int `json:"SubnetType"`
|
||||
Tag string `json:"Tag"`
|
||||
VPCID string `json:"VPCId"`
|
||||
VPCName string `json:"VPCName"`
|
||||
VRouterID string `json:"VRouterId"`
|
||||
Zone string `json:"Zone"`
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetProjectId() string {
|
||||
return self.wire.region.client.projectId
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetId() string {
|
||||
return self.SubnetID
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetName() string {
|
||||
if len(self.SubnetName) > 0 {
|
||||
return self.SubnetName
|
||||
}
|
||||
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetStatus() string {
|
||||
return models.NETWORK_STATUS_AVAILABLE
|
||||
}
|
||||
|
||||
func (self *SNetwork) Refresh() error {
|
||||
log.Debugf("network refresh %s", self.GetId())
|
||||
new, err := self.wire.region.getNetwork(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SNetwork) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIWire() cloudprovider.ICloudWire {
|
||||
return self.wire
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIpStart() string {
|
||||
pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask)
|
||||
startIp := pref.Address.NetAddr(pref.MaskLen) // 0
|
||||
startIp = startIp.StepUp() // 1
|
||||
return startIp.String()
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIpEnd() string {
|
||||
pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask)
|
||||
endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
|
||||
endIp = endIp.StepDown() // 254
|
||||
endIp = endIp.StepDown() // 253
|
||||
endIp = endIp.StepDown() // 252
|
||||
return endIp.String()
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIpMask() int8 {
|
||||
pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask)
|
||||
return pref.MaskLen
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetGateway() string {
|
||||
pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask)
|
||||
endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
|
||||
endIp = endIp.StepDown() // 254
|
||||
return endIp.String()
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetServerType() string {
|
||||
return models.NETWORK_TYPE_GUEST
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIsPublic() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SNetwork) Delete() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetAllocTimeoutSeconds() int {
|
||||
return 120 // 2 minutes
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet
|
||||
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()
|
||||
params.Set("SubnetId", networkId)
|
||||
err := self.DoListAll("DescribeSubnet", params, &networks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(networks) == 1 {
|
||||
return &networks[0], nil
|
||||
} else if len(networks) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
} else {
|
||||
return nil, fmt.Errorf("getNetwork %s %d found", networkId, len(networks))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ucloud
|
||||
|
||||
import "yunion.io/x/jsonutils"
|
||||
|
||||
// https://docs.ucloud.cn/api/summary/get_project_list
|
||||
type SProject struct {
|
||||
ProjectID string `json:"ProjectId"`
|
||||
ProjectName string `json:"ProjectName"`
|
||||
ParentID string `json:"ParentId"`
|
||||
ParentName string `json:"ParentName"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
IsDefault bool `json:"IsDefault"`
|
||||
MemberCount int64 `json:"MemberCount"`
|
||||
ResourceCount int64 `json:"ResourceCount"`
|
||||
}
|
||||
|
||||
func (self *SProject) GetId() string {
|
||||
return self.ProjectID
|
||||
}
|
||||
|
||||
func (self *SProject) GetName() string {
|
||||
return self.ProjectName
|
||||
}
|
||||
|
||||
func (self *SProject) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SProject) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SProject) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SProject) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SProject) GetMetadata() *jsonutils.JSONDict {
|
||||
return jsonutils.NewDict()
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) FetchProjects() ([]SProject, error) {
|
||||
params := NewUcloudParams()
|
||||
projects := make([]SProject, 0)
|
||||
err := self.DoListAll("GetProjectList", params, &projects)
|
||||
return projects, err
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/ucloud"
|
||||
)
|
||||
|
||||
// tag:finished
|
||||
type SUcloudProviderFactory struct {
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) GetId() string {
|
||||
return ucloud.CLOUD_PROVIDER_UCLOUD
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) GetName() string {
|
||||
return ucloud.CLOUD_PROVIDER_UCLOUD_CN
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) IsPublicCloud() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) IsOnPremise() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) IsSupportPrepaidResources() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) NeedSyncSkuFromCloud() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) error {
|
||||
accessKeyID, _ := data.GetString("access_key_id")
|
||||
if len(accessKeyID) == 0 {
|
||||
return httperrors.NewMissingParameterError("access_key_id")
|
||||
}
|
||||
accessKeySecret, _ := data.GetString("access_key_secret")
|
||||
if len(accessKeySecret) == 0 {
|
||||
return httperrors.NewMissingParameterError("access_key_secret")
|
||||
}
|
||||
data.Set("account", jsonutils.NewString(accessKeyID))
|
||||
data.Set("secret", jsonutils.NewString(accessKeySecret))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject, cloudaccount string) (*cloudprovider.SCloudaccount, error) {
|
||||
|
||||
accessKeyID, _ := data.GetString("access_key_id")
|
||||
if len(accessKeyID) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("access_key_id")
|
||||
}
|
||||
accessKeySecret, _ := data.GetString("access_key_secret")
|
||||
if len(accessKeySecret) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("access_key_secret")
|
||||
}
|
||||
account := &cloudprovider.SCloudaccount{
|
||||
Account: accessKeyID,
|
||||
Secret: accessKeySecret,
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) {
|
||||
client, err := ucloud.NewUcloudClient(providerId, providerName, account, secret, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SUcloudProvider{
|
||||
SBaseProvider: cloudprovider.NewBaseProvider(self),
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
factory := SUcloudProviderFactory{}
|
||||
cloudprovider.RegisterFactory(&factory)
|
||||
}
|
||||
|
||||
type SUcloudProvider struct {
|
||||
cloudprovider.SBaseProvider
|
||||
client *ucloud.SUcloudClient
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
projects, err := self.client.FetchProjects()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iprojects := make([]cloudprovider.ICloudProject, len(projects))
|
||||
for i := range projects {
|
||||
iprojects[i] = &projects[i]
|
||||
}
|
||||
|
||||
return iprojects, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) {
|
||||
regions := self.client.GetIRegions()
|
||||
info := jsonutils.NewDict()
|
||||
info.Add(jsonutils.NewInt(int64(len(regions))), "region_count")
|
||||
info.Add(jsonutils.NewString(ucloud.UCLOUD_API_VERSION), "api_version")
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetVersion() string {
|
||||
return ucloud.UCLOUD_API_VERSION
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
|
||||
return self.client.GetIRegionById(extId)
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetBalance() (float64, error) {
|
||||
return 0.0, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
)
|
||||
|
||||
type SRegion struct {
|
||||
client *SUcloudClient
|
||||
|
||||
RegionID string
|
||||
|
||||
izones []cloudprovider.ICloudZone
|
||||
ivpcs []cloudprovider.ICloudVpc
|
||||
|
||||
storageCache *SStoragecache
|
||||
|
||||
latitude float64
|
||||
longitude float64
|
||||
fetchLocation bool
|
||||
}
|
||||
|
||||
func (self *SRegion) GetId() string {
|
||||
return self.RegionID
|
||||
}
|
||||
|
||||
func (self *SRegion) GetName() string {
|
||||
if name, exist := UCLOUD_REGION_NAMES[self.GetId()]; exist {
|
||||
return name
|
||||
}
|
||||
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SRegion) GetGlobalId() string {
|
||||
return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_UCLOUD, self.GetId())
|
||||
}
|
||||
|
||||
func (self *SRegion) GetStatus() string {
|
||||
return models.CLOUD_REGION_STATUS_INSERVER
|
||||
}
|
||||
|
||||
func (self *SRegion) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SRegion) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
|
||||
if info, ok := LatitudeAndLongitude[self.GetId()]; ok {
|
||||
return info
|
||||
}
|
||||
return cloudprovider.SGeographicInfo{}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
|
||||
if self.izones == nil {
|
||||
var err error
|
||||
err = self.fetchInfrastructure()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.izones, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
|
||||
if self.ivpcs == nil {
|
||||
err := self.fetchInfrastructure()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.ivpcs, nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/describe_eip
|
||||
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
||||
params := NewUcloudParams()
|
||||
eips := make([]SEip, 0)
|
||||
err := self.DoListAll("DescribeEIP", params, &eips)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ieips := []cloudprovider.ICloudEIP{}
|
||||
for _, eip := range eips {
|
||||
eip.region = self
|
||||
ieips = append(ieips, &eip)
|
||||
}
|
||||
|
||||
return ieips, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
|
||||
ivpcs, err := self.GetIVpcs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(ivpcs); i += 1 {
|
||||
if ivpcs[i].GetGlobalId() == id {
|
||||
return ivpcs[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(izones); i += 1 {
|
||||
if izones[i].GetGlobalId() == id {
|
||||
return izones[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) GetEipById(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
|
||||
}
|
||||
|
||||
if len(eips) == 1 {
|
||||
return eips[0], nil
|
||||
} else {
|
||||
return SEip{}, fmt.Errorf("GetEipById %d eip found", len(eips))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) {
|
||||
eip, err := self.GetEipById(id)
|
||||
return &eip, err
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/delete_firewall
|
||||
func (self *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error {
|
||||
params := NewUcloudParams()
|
||||
params.Set("FWId", secgroupId)
|
||||
return self.DoAction("DeleteFirewall", params, nil)
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/describe_firewall
|
||||
// 绑定防火墙组的资源类型,默认为全部资源类型。枚举值为:"unatgw",NAT网关; "uhost",云主机; "upm",物理云主机; "hadoophost",hadoop节点; "fortresshost",堡垒机; "udhost",私有专区主机;"udockhost",容器;"dbaudit",数据库审计.
|
||||
// todo: 是否需要过滤出仅绑定云主机的安全组?
|
||||
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
|
||||
if len(secgroupId) > 0 {
|
||||
_, err := self.GetSecurityGroupById(secgroupId)
|
||||
if err == cloudprovider.ErrNotSupported {
|
||||
secgroupId = ""
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if len(secgroupId) == 0 {
|
||||
extID, err := self.CreateSecurityGroup(name, desc)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
secgroupId = extID
|
||||
}
|
||||
|
||||
// todo: implement me
|
||||
return secgroupId, self.syncSecgroupRules(secgroupId, rules)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
|
||||
params := NewUcloudParams()
|
||||
params.Set("Name", name)
|
||||
params.Set("Remark", desc)
|
||||
for i, cidr := range strings.Split(cidr, ",") {
|
||||
params.Set(fmt.Sprintf("Network.%d", i), cidr)
|
||||
}
|
||||
|
||||
vpcId := ""
|
||||
err := self.DoAction("CreateVPC", params, &vpcId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return self.GetIVpcById(vpcId)
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/allocate_eip
|
||||
// 增加共享带宽模式ShareBandwidth
|
||||
func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
|
||||
params := NewUcloudParams()
|
||||
params.Set("OperatorName", bgpType)
|
||||
params.Set("Bandwidth", bwMbps)
|
||||
params.Set("Name", name)
|
||||
var payMode string
|
||||
switch chargeType {
|
||||
case models.EIP_CHARGE_TYPE_BY_TRAFFIC:
|
||||
payMode = "Traffic"
|
||||
case models.EIP_CHARGE_TYPE_BY_BANDWIDTH:
|
||||
payMode = "Bandwidth"
|
||||
}
|
||||
params.Set("PayMode", payMode)
|
||||
|
||||
eips := make([]SEip, 0)
|
||||
err := self.DoAction("AllocateEIP", params, &eips)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(eips) == 1 {
|
||||
return &eips[0], nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("CreateEIP %d eip created", len(eips))
|
||||
}
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot
|
||||
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
params := NewUcloudParams()
|
||||
snapshots := make([]SSnapshot, 0)
|
||||
err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isnapshots := make([]cloudprovider.ICloudSnapshot, 0)
|
||||
for _, snapshot := range snapshots {
|
||||
snapshot.region = self
|
||||
isnapshots = append(isnapshots, &snapshot)
|
||||
}
|
||||
|
||||
return isnapshots, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
|
||||
params := NewUcloudParams()
|
||||
params.Set("SnapshotId", snapshotId)
|
||||
snapshots := make([]SSnapshot, 0)
|
||||
err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(snapshots) == 1 {
|
||||
snapshot := snapshots[0]
|
||||
snapshot.region = self
|
||||
return &snapshot, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("GetISnapshotById %s %d snapshot found", snapshotId, len(snapshots))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
|
||||
iHosts := make([]cloudprovider.ICloudHost, 0)
|
||||
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(izones); i += 1 {
|
||||
iZoneHost, err := izones[i].GetIHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iHosts = append(iHosts, iZoneHost...)
|
||||
}
|
||||
return iHosts, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(izones); i += 1 {
|
||||
ihost, err := izones[i].GetIHostById(id)
|
||||
if err == nil {
|
||||
return ihost, nil
|
||||
} else if err != cloudprovider.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
iStores := make([]cloudprovider.ICloudStorage, 0)
|
||||
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(izones); i += 1 {
|
||||
iZoneStores, err := izones[i].GetIStorages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iStores = append(iStores, iZoneStores...)
|
||||
}
|
||||
return iStores, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(izones); i += 1 {
|
||||
istore, err := izones[i].GetIStorageById(id)
|
||||
if err == nil {
|
||||
return istore, nil
|
||||
} else if err != cloudprovider.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) getStoragecache() *SStoragecache {
|
||||
if self.storageCache == nil {
|
||||
self.storageCache = &SStoragecache{region: self}
|
||||
}
|
||||
return self.storageCache
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) {
|
||||
storageCache := self.getStoragecache()
|
||||
return []cloudprovider.ICloudStoragecache{storageCache}, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
|
||||
storageCache := self.getStoragecache()
|
||||
if storageCache.GetGlobalId() == id {
|
||||
return storageCache, nil
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetProvider() string {
|
||||
return CLOUD_PROVIDER_UCLOUD
|
||||
}
|
||||
|
||||
func (self *SRegion) DoListAll(action string, params SParams, result interface{}) error {
|
||||
params.Set("Region", self.GetId())
|
||||
return self.client.DoListAll(action, params, result)
|
||||
}
|
||||
|
||||
// return total,lenght,error
|
||||
func (self *SRegion) DoListPart(action string, limit int, offset int, params SParams, result interface{}) (int, int, error) {
|
||||
params.Set("Region", self.GetId())
|
||||
return self.client.DoListPart(action, limit, offset, params, result)
|
||||
}
|
||||
|
||||
func (self *SRegion) DoAction(action string, params SParams, result interface{}) error {
|
||||
params.Set("Region", self.GetId())
|
||||
return self.client.DoAction(action, params, result)
|
||||
}
|
||||
|
||||
func (self *SRegion) fetchInfrastructure() error {
|
||||
if err := self.fetchZones(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.fetchIVpcs(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(self.ivpcs); i += 1 {
|
||||
vpc := self.ivpcs[i].(*SVPC)
|
||||
wire := SWire{region: self, vpc: vpc}
|
||||
vpc.addWire(&wire)
|
||||
|
||||
for j := 0; j < len(self.izones); j += 1 {
|
||||
zone := self.izones[j].(*SZone)
|
||||
zone.addWire(&wire)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) fetchZones() error {
|
||||
type Region struct {
|
||||
RegionID int64 `json:"RegionId"`
|
||||
RegionName string `json:"RegionName"`
|
||||
IsDefault bool `json:"IsDefault"`
|
||||
BitMaps string `json:"BitMaps"`
|
||||
Region string `json:"Region"`
|
||||
Zone string `json:"Zone"`
|
||||
}
|
||||
|
||||
params := NewUcloudParams()
|
||||
regions := make([]Region, 0)
|
||||
err := self.client.DoListAll("GetRegion", params, ®ions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range regions {
|
||||
if r.Region != self.GetId() {
|
||||
continue
|
||||
}
|
||||
|
||||
szone := SZone{}
|
||||
szone.ZoneId = r.Zone
|
||||
szone.RegionId = r.Region
|
||||
szone.region = self
|
||||
self.izones = append(self.izones, &szone)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) fetchIVpcs() error {
|
||||
vpcs := make([]SVPC, 0)
|
||||
params := NewUcloudParams()
|
||||
err := self.DoListAll("DescribeVPC", params, &vpcs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, vpc := range vpcs {
|
||||
vpc.region = self
|
||||
self.ivpcs = append(self.ivpcs, &vpc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance
|
||||
func (self *SRegion) GetInstanceByID(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
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/describe_firewall
|
||||
type SSecurityGroup struct {
|
||||
region *SRegion
|
||||
vpc *SVPC // 安全组在UCLOUD实际上与VPC是没有直接关联的。这里的vpc字段只是为了统一,仅仅是标记是哪个VPC在操作该安全组。
|
||||
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
FWID string `json:"FWId"`
|
||||
GroupID string `json:"GroupId"`
|
||||
Name string `json:"Name"`
|
||||
Remark string `json:"Remark"`
|
||||
ResourceCount int `json:"ResourceCount"`
|
||||
Rule []Rule `json:"Rule"`
|
||||
Tag string `json:"Tag"`
|
||||
Type string `json:"Type"`
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetProjectId() string {
|
||||
return self.region.client.projectId
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
DstPort string `json:"DstPort"`
|
||||
Priority string `json:"Priority"`
|
||||
ProtocolType string `json:"ProtocolType"`
|
||||
RuleAction string `json:"RuleAction"`
|
||||
SrcIP string `json:"SrcIP"`
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetId() string {
|
||||
return self.FWID
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) Refresh() error {
|
||||
if new, err := self.region.GetSecurityGroupById(self.GetId()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetMetadata() *jsonutils.JSONDict {
|
||||
data := jsonutils.NewDict()
|
||||
return data
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetDescription() string {
|
||||
return self.Remark
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) secrules.SecurityRule {
|
||||
secrule := secrules.SecurityRule{}
|
||||
switch rule.Priority {
|
||||
case "HIGH":
|
||||
secrule.Priority = 90
|
||||
case "MEDIUM":
|
||||
secrule.Priority = 60
|
||||
case "LOW":
|
||||
secrule.Priority = 30
|
||||
default:
|
||||
secrule.Priority = 1
|
||||
}
|
||||
|
||||
switch rule.RuleAction {
|
||||
case "ACCEPT":
|
||||
secrule.Action = secrules.SecurityRuleAllow
|
||||
case "DROP":
|
||||
secrule.Action = secrules.SecurityRuleDeny
|
||||
default:
|
||||
secrule.Action = secrules.SecurityRuleDeny
|
||||
}
|
||||
|
||||
_, ipNet, err := net.ParseCIDR(rule.SrcIP)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
|
||||
secrule.IPNet = ipNet
|
||||
secrule.Protocol = strings.ToLower(rule.ProtocolType)
|
||||
secrule.Direction = secrules.SecurityRuleIngress
|
||||
if rule.DstPort == "" {
|
||||
secrule.PortStart = -1
|
||||
secrule.PortEnd = -1
|
||||
} else if strings.Contains(rule.DstPort, "-") {
|
||||
segs := strings.Split(rule.DstPort, "-")
|
||||
s, err := strconv.Atoi(segs[0])
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
e, err := strconv.Atoi(segs[1])
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
secrule.PortStart = s
|
||||
secrule.PortEnd = e
|
||||
} else {
|
||||
port, err := strconv.Atoi(rule.DstPort)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
|
||||
secrule.PortStart = port
|
||||
secrule.PortEnd = port
|
||||
}
|
||||
|
||||
return secrule
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/network/firewall/firewall
|
||||
// 貌似没有出方向规则
|
||||
// todo: fix me
|
||||
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
|
||||
rules := make([]secrules.SecurityRule, 0)
|
||||
for _, r := range self.Rule {
|
||||
rule := self.UcloudSecRuleToOnecloud(r)
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroup) GetVpcId() string {
|
||||
// 无vpc关联的安全组统一返回normal
|
||||
return "normal"
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSecurityGroupById(secGroupId string) (*SSecurityGroup, error) {
|
||||
secgroups, err := self.GetSecurityGroups(secGroupId, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(secgroups) == 1 {
|
||||
return &secgroups[0], nil
|
||||
} else if len(secgroups) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
} else {
|
||||
return nil, fmt.Errorf("GetSecurityGroupById %s %d found", secGroupId, len(secgroups))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateSecurityGroup(name, description string) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/unet-api/describe_firewall
|
||||
func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string) ([]SSecurityGroup, error) {
|
||||
secgroups := make([]SSecurityGroup, 0)
|
||||
|
||||
params := NewUcloudParams()
|
||||
if len(secGroupId) > 0 {
|
||||
params.Set("FWId", secGroupId)
|
||||
}
|
||||
|
||||
if len(resourceId) > 0 {
|
||||
params.Set("ResourceId", resourceId)
|
||||
params.Set("ResourceType", "uhost") // 默认只支持"uhost",云主机
|
||||
}
|
||||
err := self.DoListAll("DescribeFirewall", params, &secgroups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range secgroups {
|
||||
secgroups[i].region = self
|
||||
}
|
||||
|
||||
return secgroups, nil
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot
|
||||
type SSnapshot struct {
|
||||
region *SRegion
|
||||
|
||||
Comment string `json:"Comment"`
|
||||
ChargeType string `json:"ChargeType"`
|
||||
Name string `json:"Name"`
|
||||
UDiskName string `json:"UDiskName"`
|
||||
ExpiredTime int64 `json:"ExpiredTime"`
|
||||
UDiskID string `json:"UDiskId"`
|
||||
SnapshotID string `json:"SnapshotId"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
SizeGB int32 `json:"Size"`
|
||||
Status string `json:"Status"`
|
||||
IsUDiskAvailable bool `json:"IsUDiskAvailable"`
|
||||
Version string `json:"Version"`
|
||||
DiskType int `json:"DiskType"`
|
||||
UHostID string `json:"UHostId"`
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetProjectId() string {
|
||||
return self.region.client.projectId
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetId() string {
|
||||
return self.SnapshotID
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
// 快照状态,Normal:正常,Failed:失败,Creating:制作中
|
||||
func (self *SSnapshot) GetStatus() string {
|
||||
switch self.Status {
|
||||
case "Normal":
|
||||
return models.SNAPSHOT_READY
|
||||
case "Failed":
|
||||
return models.SNAPSHOT_FAILED
|
||||
case "Creating":
|
||||
return models.SNAPSHOT_CREATING
|
||||
default:
|
||||
return models.SNAPSHOT_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SSnapshot) Refresh() error {
|
||||
snapshot, err := self.region.GetSnapshotById(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := jsonutils.Update(self, snapshot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SSnapshot) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetSize() int32 {
|
||||
return self.SizeGB
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetDiskId() string {
|
||||
return self.UDiskID
|
||||
}
|
||||
|
||||
// 磁盘类型,0:数据盘,1:系统盘
|
||||
func (self *SSnapshot) GetDiskType() string {
|
||||
if self.DiskType == 1 {
|
||||
return models.DISK_TYPE_SYS
|
||||
} else {
|
||||
return models.DISK_TYPE_DATA
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SSnapshot) Delete() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) {
|
||||
snapshots, err := self.GetSnapshots("", snapshotId)
|
||||
if err != nil {
|
||||
return SSnapshot{}, err
|
||||
}
|
||||
|
||||
if len(snapshots) == 1 {
|
||||
return snapshots[0], nil
|
||||
} else if len(snapshots) == 0 {
|
||||
return SSnapshot{}, cloudprovider.ErrNotFound
|
||||
} else {
|
||||
return SSnapshot{}, fmt.Errorf("GetSnapshotById %s %d found", snapshotId, len(snapshots))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSnapshots(diskId string, snapshotId string) ([]SSnapshot, error) {
|
||||
snapshots := make([]SSnapshot, 0)
|
||||
params := NewUcloudParams()
|
||||
if len(diskId) == 0 {
|
||||
params.Set("UDiskId", diskId)
|
||||
}
|
||||
|
||||
if len(snapshotId) == 0 {
|
||||
params.Set("SnapshotId", snapshotId)
|
||||
}
|
||||
|
||||
err := self.DoAction("DescribeUDiskSnapshot", params, &snapshots)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return snapshots, nil
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SStorage struct {
|
||||
zone *SZone
|
||||
storageType string
|
||||
}
|
||||
|
||||
func (self *SStorage) GetId() string {
|
||||
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerId, self.zone.GetId(), self.storageType)
|
||||
}
|
||||
|
||||
func (self *SStorage) GetName() string {
|
||||
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerName, self.zone.GetId(), self.storageType)
|
||||
}
|
||||
|
||||
func (self *SStorage) GetGlobalId() string {
|
||||
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerId, self.zone.GetGlobalId(), self.storageType)
|
||||
}
|
||||
|
||||
func (self *SStorage) GetStatus() string {
|
||||
return models.STORAGE_ONLINE
|
||||
}
|
||||
|
||||
func (self *SStorage) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStorage) IsEmulated() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SStorage) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
|
||||
return self.zone.region.getStoragecache()
|
||||
}
|
||||
|
||||
func (self *SStorage) GetIZone() cloudprovider.ICloudZone {
|
||||
return self.zone
|
||||
}
|
||||
|
||||
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 == models.STORAGE_UCLOUD_SSD && strings.Contains(disk.DiskType, models.STORAGE_UCLOUD_SSD) {
|
||||
filtedDisks = append(filtedDisks, disk)
|
||||
}
|
||||
|
||||
// 普通盘
|
||||
if self.storageType == models.STORAGE_UCLOUD_SATA && !strings.Contains(disk.DiskType, models.STORAGE_UCLOUD_SSD) {
|
||||
filtedDisks = append(filtedDisks, 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
|
||||
}
|
||||
|
||||
func (self *SStorage) GetStorageType() string {
|
||||
return self.storageType
|
||||
}
|
||||
|
||||
func (self *SStorage) GetMediumType() string {
|
||||
if self.storageType == models.STORAGE_UCLOUD_SSD {
|
||||
return models.DISK_TYPE_SSD
|
||||
} else {
|
||||
return models.DISK_TYPE_ROTATE
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SStorage) GetCapacityMB() int {
|
||||
return 0 // unlimited
|
||||
}
|
||||
|
||||
func (self *SStorage) GetStorageConf() jsonutils.JSONObject {
|
||||
return jsonutils.NewDict()
|
||||
}
|
||||
|
||||
func (self *SStorage) GetEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SStorage) GetManagerId() string {
|
||||
return self.zone.region.client.providerId
|
||||
}
|
||||
|
||||
func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
|
||||
if disk, err := self.zone.region.GetDisk(idStr); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
disk.storage = self
|
||||
return disk, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SStorage) GetMountPoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SStorage) IsSysDiskStore() bool {
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type SStoragecache struct {
|
||||
region *SRegion
|
||||
|
||||
iimages []cloudprovider.ICloudImage
|
||||
}
|
||||
|
||||
func (self *SStoragecache) fetchImages() error {
|
||||
images, err := self.region.GetImages("", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
image.storageCache = self
|
||||
self.iimages = append(self.iimages, &image)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetId() string {
|
||||
return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetId())
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetName() string {
|
||||
return fmt.Sprintf("%s-%s", self.region.client.providerName, self.region.GetId())
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetGlobalId() string {
|
||||
return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetGlobalId())
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetStatus() string {
|
||||
return "available"
|
||||
}
|
||||
|
||||
func (self *SStoragecache) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) {
|
||||
if self.iimages == nil {
|
||||
err := self.fetchImages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.iimages, nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) {
|
||||
image, err := self.region.GetImage(extId)
|
||||
image.storageCache = self
|
||||
return &image, err
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SStoragecache) GetManagerId() string {
|
||||
return self.region.client.providerId
|
||||
}
|
||||
|
||||
func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist, osVersion string, extId string, isForce bool) (string, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
/*
|
||||
UCLOUD 项目:https://docs.ucloud.cn/management_monitor/uproject/projects
|
||||
项目可认为是云账户下承载资源的容器,当您注册一个UCloud云账户后,系统会默认创建一个项目,您属于的资源都落在此项目下。如您有新的业务要使用云服务,可创建一个新项目,并将新业务部署在新项目下,实现业务之间的网络与逻辑隔离。
|
||||
|
||||
1、项目之间默认网络与逻辑隔离,即项目A的主机无法绑定项目B的EIP,默认也无法与项目B的主机内网通信。但联通项目后,uhost、udb、umem可实现内网通信。
|
||||
|
||||
2、资源不能在项目间迁移,即项目A内的主机无法迁移至项目B,因其不在一个基础网络内,且逻辑上也是隔离的。但诸如自主镜像等静态资源,您可以提交工单申请迁移至其他项目。
|
||||
|
||||
3、只有云账户本身,才能删除项目,且必须是项目被没有资源、没有任何子成员、未与其他项目联通的情况下才可删除。
|
||||
|
||||
|
||||
UCloud DiskType貌似也是一个奇葩的存在
|
||||
1.在主机创建查询接口中 DISK type 对应 CLOUD_SSD|CLOUD_SSD
|
||||
2.在数据盘创建中对应 DataDisk|SSDDataDisk
|
||||
3.在数据盘查询接口请求中对应 DataDisk|SystemDisk 。在结果中对应DataDisk|SSDDataDisk|SSDSystemDisk|SystemDisk
|
||||
*/
|
||||
|
||||
const (
|
||||
CLOUD_PROVIDER_UCLOUD = models.CLOUD_PROVIDER_UCLOUD
|
||||
CLOUD_PROVIDER_UCLOUD_CN = "UCloud"
|
||||
|
||||
UCLOUD_DEFAULT_REGION = "cn-bj2"
|
||||
|
||||
UCLOUD_API_VERSION = "2019-02-28"
|
||||
)
|
||||
|
||||
type SUcloudClient struct {
|
||||
providerId string
|
||||
providerName string
|
||||
accessKeyId string
|
||||
accessKeySecret string
|
||||
projectId string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
httpClient *http.Client
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func parseAccount(account string) (accessKey string, projectId string) {
|
||||
segs := strings.Split(account, "::")
|
||||
if len(segs) == 2 {
|
||||
accessKey = segs[0]
|
||||
projectId = segs[1]
|
||||
} else {
|
||||
accessKey = account
|
||||
projectId = ""
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。
|
||||
// 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空,只能进行同步子账号(项目)、查询region列表等projectId无关的操作。
|
||||
func NewUcloudClient(providerId string, providerName string, account string, secret string, isDebug bool) (*SUcloudClient, error) {
|
||||
accessKey, projectId := parseAccount(account)
|
||||
client := SUcloudClient{
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
accessKeyId: accessKey,
|
||||
accessKeySecret: secret,
|
||||
projectId: projectId,
|
||||
Debug: isDebug,
|
||||
}
|
||||
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) UpdateAccount(accessKey, secret string) error {
|
||||
if self.accessKeyId != accessKey || self.accessKeySecret != secret {
|
||||
self.accessKeyId = accessKey
|
||||
self.accessKeySecret = secret
|
||||
return self.fetchRegions()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) commonParams(params SParams, action string) (string, SParams) {
|
||||
resultKey, exists := UCLOUD_API_RESULT_KEYS[action]
|
||||
if !exists || len(resultKey) == 0 {
|
||||
log.Debugf("Do %s no result key found or result key is empty", action)
|
||||
}
|
||||
|
||||
if len(self.projectId) > 0 {
|
||||
params.Set("ProjectId", self.projectId)
|
||||
}
|
||||
params.Set("PublicKey", self.accessKeyId)
|
||||
|
||||
return resultKey, params
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) DoListAll(action string, params SParams, result interface{}) error {
|
||||
resultKey, params := self.commonParams(params, action)
|
||||
return DoListAll(self, action, params, resultKey, result)
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) DoListPart(action string, limit int, offset int, params SParams, result interface{}) (int, int, error) {
|
||||
resultKey, params := self.commonParams(params, action)
|
||||
params.SetPagination(limit, offset)
|
||||
return doListPart(self, action, params, resultKey, result)
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) DoAction(action string, params SParams, result interface{}) error {
|
||||
resultKey, params := self.commonParams(params, action)
|
||||
return DoAction(self, action, params, resultKey, result)
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) fetchRegions() error {
|
||||
type Region struct {
|
||||
RegionID int64 `json:"RegionId"`
|
||||
RegionName string `json:"RegionName"`
|
||||
IsDefault bool `json:"IsDefault"`
|
||||
BitMaps string `json:"BitMaps"`
|
||||
Region string `json:"Region"`
|
||||
Zone string `json:"Zone"`
|
||||
}
|
||||
|
||||
params := NewUcloudParams()
|
||||
regions := make([]Region, 0)
|
||||
err := self.DoListAll("GetRegion", params, ®ions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
regionSet := make(map[string]string, 0)
|
||||
for _, region := range regions {
|
||||
regionSet[region.Region] = region.Region
|
||||
}
|
||||
|
||||
sregions := make([]SRegion, len(regionSet))
|
||||
self.iregions = make([]cloudprovider.ICloudRegion, len(regionSet))
|
||||
i := 0
|
||||
for regionId := range regionSet {
|
||||
sregions[i].client = self
|
||||
sregions[i].RegionID = regionId
|
||||
self.iregions[i] = &sregions[i]
|
||||
i += 1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
for i := 0; i < len(regions); i += 1 {
|
||||
region := self.iregions[i].(*SRegion)
|
||||
regions[i] = *region
|
||||
}
|
||||
return regions
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
projects, err := self.FetchProjects()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subAccounts := make([]cloudprovider.SSubAccount, 0)
|
||||
for _, project := range projects {
|
||||
subAccount := cloudprovider.SSubAccount{}
|
||||
subAccount.Name = self.providerName
|
||||
// ucloud账号ID中可能包含/。因此使用::作为分割符号
|
||||
subAccount.Account = fmt.Sprintf("%s::%s", self.accessKeyId, project.ProjectID)
|
||||
subAccount.HealthStatus = models.CLOUD_PROVIDER_HEALTH_NORMAL
|
||||
|
||||
subAccounts = append(subAccounts, subAccount)
|
||||
}
|
||||
|
||||
return subAccounts, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.iregions
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetGlobalId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetRegion(regionId string) *SRegion {
|
||||
if len(regionId) == 0 {
|
||||
regionId = UCLOUD_DEFAULT_REGION
|
||||
}
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == regionId {
|
||||
return self.iregions[i].(*SRegion)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
ihost, err := self.iregions[i].GetIHostById(id)
|
||||
if err == nil {
|
||||
return ihost, nil
|
||||
} else if err != cloudprovider.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
ihost, err := self.iregions[i].GetIVpcById(id)
|
||||
if err == nil {
|
||||
return ihost, nil
|
||||
} else if err != cloudprovider.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
ihost, err := self.iregions[i].GetIStorageById(id)
|
||||
if err == nil {
|
||||
return ihost, nil
|
||||
} else if err != cloudprovider.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
func unmarshalResult(resp jsonutils.JSONObject, respErr error, resultKey string, result interface{}) error {
|
||||
if respErr != nil {
|
||||
return respErr
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(resultKey) > 0 {
|
||||
respErr = resp.Unmarshal(result, resultKey)
|
||||
} else {
|
||||
respErr = resp.Unmarshal(result)
|
||||
}
|
||||
|
||||
if respErr != nil {
|
||||
log.Errorf("unmarshal json error %s", respErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func doListPart(client *SUcloudClient, action string, params SParams, resultKey string, result interface{}) (int, int, error) {
|
||||
params.SetAction(action)
|
||||
ret, err := jsonRequest(client, params)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
total, err := ret.Int("TotalCount")
|
||||
if err != nil {
|
||||
log.Debugf("%s TotalCount", action)
|
||||
// return 0, 0, err
|
||||
}
|
||||
|
||||
var lst []jsonutils.JSONObject
|
||||
lst, err = ret.GetArray(resultKey)
|
||||
if err != nil {
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
resultValue := reflect.Indirect(reflect.ValueOf(result))
|
||||
elemType := resultValue.Type().Elem()
|
||||
for i := range lst {
|
||||
elemPtr := reflect.New(elemType)
|
||||
err = lst[i].Unmarshal(elemPtr.Interface())
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
resultValue.Set(reflect.Append(resultValue, elemPtr.Elem()))
|
||||
}
|
||||
return int(total), len(lst), nil
|
||||
}
|
||||
|
||||
// 执行操作
|
||||
func DoAction(client *SUcloudClient, action string, params SParams, resultKey string, result interface{}) error {
|
||||
params.SetAction(action)
|
||||
resp, err := jsonRequest(client, params)
|
||||
return unmarshalResult(resp, err, resultKey, result)
|
||||
}
|
||||
|
||||
// 遍历所有结果
|
||||
func DoListAll(client *SUcloudClient, action string, params SParams, resultKey string, result interface{}) error {
|
||||
pageLimit := 100
|
||||
offset := 0
|
||||
|
||||
resultValue := reflect.Indirect(reflect.ValueOf(result))
|
||||
params.SetPagination(pageLimit, offset)
|
||||
for {
|
||||
total, part, err := doListPart(client, action, params, resultKey, result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) {
|
||||
break
|
||||
}
|
||||
|
||||
params.SetPagination(pageLimit, offset+resultValue.Len())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SVPC struct {
|
||||
region *SRegion
|
||||
|
||||
iwires []cloudprovider.ICloudWire
|
||||
secgroups []cloudprovider.ICloudSecurityGroup
|
||||
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
Name string `json:"Name"`
|
||||
Network []string `json:"Network"`
|
||||
NetworkInfo []NetworkInfo `json:"NetworkInfo"`
|
||||
SubnetCount int `json:"SubnetCount"`
|
||||
Tag string `json:"Tag"`
|
||||
UpdateTime int64 `json:"UpdateTime"`
|
||||
VPCID string `json:"VPCId"`
|
||||
}
|
||||
|
||||
type NetworkInfo struct {
|
||||
Network string `json:"Network"`
|
||||
SubnetCount int `json:"SubnetCount"`
|
||||
}
|
||||
|
||||
func (self *SVPC) addWire(wire *SWire) {
|
||||
if self.iwires == nil {
|
||||
self.iwires = make([]cloudprovider.ICloudWire, 0)
|
||||
}
|
||||
self.iwires = append(self.iwires, wire)
|
||||
}
|
||||
|
||||
func (self *SVPC) GetId() string {
|
||||
return self.VPCID
|
||||
}
|
||||
|
||||
func (self *SVPC) GetName() string {
|
||||
if len(self.Name) > 0 {
|
||||
return self.Name
|
||||
}
|
||||
return self.VPCID
|
||||
}
|
||||
|
||||
func (self *SVPC) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SVPC) GetStatus() string {
|
||||
return models.VPC_STATUS_AVAILABLE
|
||||
}
|
||||
|
||||
func (self *SVPC) Refresh() error {
|
||||
new, err := self.region.getVpc(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SVPC) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SVPC) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SVPC) GetRegion() cloudprovider.ICloudRegion {
|
||||
return self.region
|
||||
}
|
||||
|
||||
func (self *SVPC) GetIsDefault() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SVPC) GetCidrBlock() string {
|
||||
return strings.Join(self.Network, ",")
|
||||
}
|
||||
|
||||
func (self *SVPC) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
if self.iwires == nil {
|
||||
err := self.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.iwires, nil
|
||||
}
|
||||
|
||||
// 由于Ucloud 安全组和vpc没有直接关联,这里是返回同一个项目下的防火墙列表,会导致重复同步的问题。
|
||||
// https://docs.ucloud.cn/api/unet-api/grant_firewall
|
||||
func (self *SVPC) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) {
|
||||
if self.secgroups == nil {
|
||||
err := self.fetchSecurityGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.secgroups, nil
|
||||
}
|
||||
|
||||
func (self *SVPC) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
|
||||
rts := []cloudprovider.ICloudRouteTable{}
|
||||
return rts, nil
|
||||
}
|
||||
|
||||
func (self *SVPC) GetManagerId() string {
|
||||
return self.region.client.providerId
|
||||
}
|
||||
|
||||
func (self *SVPC) Delete() error {
|
||||
return self.region.DeleteVpc(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SVPC) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) {
|
||||
if self.iwires == nil {
|
||||
err := self.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(self.iwires); i += 1 {
|
||||
if self.iwires[i].GetGlobalId() == wireId {
|
||||
return self.iwires[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SVPC) fetchNetworks() error {
|
||||
networks, err := self.region.GetNetworks(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(networks); i += 1 {
|
||||
wire := self.getWireByRegionId(self.region.GetId())
|
||||
networks[i].wire = wire
|
||||
wire.addNetwork(&networks[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SVPC) getWireByRegionId(regionId string) *SWire {
|
||||
if len(regionId) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(self.iwires); i++ {
|
||||
wire := self.iwires[i].(*SWire)
|
||||
|
||||
if wire.region.GetId() == regionId {
|
||||
return wire
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) getVpc(vpcId string) (*SVPC, error) {
|
||||
vpcs, err := self.GetVpcs(vpcId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(vpcs) == 1 {
|
||||
return &vpcs[0], nil
|
||||
} else if len(vpcs) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
} else {
|
||||
return nil, fmt.Errorf("getVpc %s %d found", vpcId, len(vpcs))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteVpc(vpcId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html
|
||||
func (self *SRegion) GetVpcs(vpcId string) ([]SVPC, error) {
|
||||
vpcs := make([]SVPC, 0)
|
||||
params := NewUcloudParams()
|
||||
if len(vpcId) > 0 {
|
||||
params.Set("VPCIds.0", vpcId)
|
||||
}
|
||||
|
||||
err := self.DoListAll("DescribeVPC", params, &vpcs)
|
||||
return vpcs, err
|
||||
}
|
||||
|
||||
func (self *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) {
|
||||
params := NewUcloudParams()
|
||||
if len(vpcId) == 0 {
|
||||
params.Set("VPCId", vpcId)
|
||||
}
|
||||
|
||||
networks := make([]SNetwork, 0)
|
||||
err := self.DoAction("DescribeSubnet", params, &networks)
|
||||
return networks, err
|
||||
}
|
||||
|
||||
// UCLOUD 同一个项目共用安全组(防火墙)
|
||||
func (self *SVPC) fetchSecurityGroups() error {
|
||||
secgroups, err := self.region.GetSecurityGroups("", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups))
|
||||
for i := 0; i < len(secgroups); i++ {
|
||||
secgroups[i].vpc = self
|
||||
secgroups[i].region = self.region
|
||||
self.secgroups[i] = &secgroups[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
// 子网在整个region可用
|
||||
type SWire struct {
|
||||
region *SRegion
|
||||
vpc *SVPC
|
||||
|
||||
inetworks []cloudprovider.ICloudNetwork
|
||||
}
|
||||
|
||||
func (self *SWire) GetId() string {
|
||||
return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId())
|
||||
}
|
||||
|
||||
func (self *SWire) GetName() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SWire) GetGlobalId() string {
|
||||
return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId())
|
||||
}
|
||||
|
||||
func (self *SWire) GetStatus() string {
|
||||
return "available"
|
||||
}
|
||||
|
||||
func (self *SWire) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SWire) IsEmulated() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SWire) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SWire) GetIVpc() cloudprovider.ICloudVpc {
|
||||
return self.vpc
|
||||
}
|
||||
|
||||
func (self *SWire) GetIZone() cloudprovider.ICloudZone {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) {
|
||||
if self.inetworks == nil {
|
||||
err := self.vpc.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return self.inetworks, nil
|
||||
}
|
||||
|
||||
func (self *SWire) GetBandwidth() int {
|
||||
return 10000
|
||||
}
|
||||
|
||||
func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) {
|
||||
networks, err := self.GetINetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(networks); i += 1 {
|
||||
if networks[i].GetGlobalId() == netid {
|
||||
return networks[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (self *SWire) addNetwork(network *SNetwork) {
|
||||
if self.inetworks == nil {
|
||||
self.inetworks = make([]cloudprovider.ICloudNetwork, 0)
|
||||
}
|
||||
find := false
|
||||
for i := 0; i < len(self.inetworks); i += 1 {
|
||||
if self.inetworks[i].GetId() == network.GetId() {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
self.inetworks = append(self.inetworks, network)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
// https://docs.ucloud.cn/api/udisk-api/create_udisk
|
||||
// UDisk 类型: DataDisk(普通数据盘),SSDDataDisk(SSD数据盘),默认值(DataDisk)
|
||||
var StorageTypes = []string{
|
||||
models.STORAGE_UCLOUD_SATA,
|
||||
models.STORAGE_UCLOUD_SSD,
|
||||
}
|
||||
|
||||
type SZone struct {
|
||||
region *SRegion
|
||||
host *SHost
|
||||
|
||||
iwires []cloudprovider.ICloudWire
|
||||
istorages []cloudprovider.ICloudStorage
|
||||
|
||||
RegionId string
|
||||
ZoneId string
|
||||
|
||||
/* 支持的磁盘种类集合 */
|
||||
storageTypes []string
|
||||
}
|
||||
|
||||
func (self *SZone) addWire(wire *SWire) {
|
||||
if self.iwires == nil {
|
||||
self.iwires = make([]cloudprovider.ICloudWire, 0)
|
||||
}
|
||||
self.iwires = append(self.iwires, wire)
|
||||
}
|
||||
|
||||
func (self *SZone) getHost() *SHost {
|
||||
if self.host == nil {
|
||||
self.host = &SHost{zone: self, projectId: self.region.client.projectId}
|
||||
}
|
||||
return self.host
|
||||
}
|
||||
|
||||
func (self *SZone) getStorageType() {
|
||||
if len(self.storageTypes) == 0 {
|
||||
self.storageTypes = StorageTypes
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SZone) fetchStorages() error {
|
||||
self.getStorageType()
|
||||
self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes))
|
||||
|
||||
for i, sc := range self.storageTypes {
|
||||
storage := SStorage{zone: self, storageType: sc}
|
||||
self.istorages[i] = &storage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SZone) GetId() string {
|
||||
return self.ZoneId
|
||||
}
|
||||
|
||||
func (self *SZone) GetName() string {
|
||||
if name, exists := UCLOUD_ZONE_NAMES[self.GetId()]; exists {
|
||||
return name
|
||||
}
|
||||
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SZone) GetGlobalId() string {
|
||||
return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.GetId())
|
||||
}
|
||||
|
||||
func (self *SZone) GetStatus() string {
|
||||
return models.ZONE_ENABLE
|
||||
}
|
||||
|
||||
func (self *SZone) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SZone) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SZone) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SZone) GetIRegion() cloudprovider.ICloudRegion {
|
||||
return self.region
|
||||
}
|
||||
|
||||
func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) {
|
||||
return []cloudprovider.ICloudHost{self.getHost()}, nil
|
||||
}
|
||||
|
||||
func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
||||
host := self.getHost()
|
||||
if host.GetGlobalId() == id {
|
||||
return host, nil
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
if self.istorages == nil {
|
||||
self.fetchStorages()
|
||||
}
|
||||
return self.istorages, nil
|
||||
}
|
||||
|
||||
func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
if self.istorages == nil {
|
||||
self.fetchStorages()
|
||||
}
|
||||
for i := 0; i < len(self.istorages); i += 1 {
|
||||
if self.istorages[i].GetGlobalId() == id {
|
||||
return self.istorages[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance
|
||||
func (self *SZone) GetInstances() ([]SInstance, error) {
|
||||
return self.region.GetInstances(self.GetId(), "")
|
||||
}
|
||||
|
||||
func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
return self.iwires, nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance
|
||||
func (self *SRegion) GetInstances(zoneId string, instanceId string) ([]SInstance, error) {
|
||||
instances := make([]SInstance, 0)
|
||||
|
||||
params := NewUcloudParams()
|
||||
if len(zoneId) > 0 {
|
||||
params.Set("Zone", zoneId)
|
||||
}
|
||||
|
||||
if len(instanceId) > 0 {
|
||||
params.Set("UHostIds.0", instanceId)
|
||||
}
|
||||
|
||||
err := self.DoListAll("DescribeUHostInstance", params, &instances)
|
||||
return instances, err
|
||||
}
|
||||
Reference in New Issue
Block a user