Merge pull request #17718 from ioito/feat/qx-ksyun

feat(region): support ksyun
This commit is contained in:
Zexi Li
2023-08-07 20:21:31 +08:00
committed by GitHub
24 changed files with 903 additions and 7 deletions
+3
View File
@@ -55,6 +55,7 @@ func init() {
cmd.CreateWithKeyword("create-incloudsphere", &options.SInCloudSphereAccountCreateOptions{})
cmd.CreateWithKeyword("create-proxmox", &options.SProxmoxAccountCreateOptions{})
cmd.CreateWithKeyword("create-remotefile", &options.SRemoteFileAccountCreateOptions{})
cmd.CreateWithKeyword("create-ksyun", &options.SKsyunCloudAccountCreateOptions{})
cmd.UpdateWithKeyword("update-vmware", &options.SVMwareCloudAccountUpdateOptions{})
cmd.UpdateWithKeyword("update-aliyun", &options.SAliyunCloudAccountUpdateOptions{})
@@ -76,6 +77,7 @@ func init() {
cmd.UpdateWithKeyword("update-bingocloud", &options.SBingoCloudAccountUpdateOptions{})
cmd.UpdateWithKeyword("update-incloudsphere", &options.SInCloudSphereAccountUpdateOptions{})
cmd.UpdateWithKeyword("update-proxmox", &options.SProxmoxAccountUpdateOptions{})
cmd.UpdateWithKeyword("update-ksyun", &options.SKsyunCloudAccountUpdateOptions{})
cmd.Perform("update-credential", &options.CloudaccountUpdateCredentialOptions{})
@@ -100,6 +102,7 @@ func init() {
cmd.PerformWithKeyword("update-credential-bingocloud", "update-credential", &options.SBingoCloudAccountUpdateCredentialOptions{})
cmd.PerformWithKeyword("update-credential-incloudsphere", "update-credential", &options.SInCloudSphereAccountUpdateCredentialOptions{})
cmd.PerformWithKeyword("update-credential-proxmox", "update-credential", &options.SProxmoxAccountUpdateCredentialOptions{})
cmd.PerformWithKeyword("update-credential-ksyun", "update-credential", &options.SKsyunCloudAccountUpdateCredentialOptions{})
cmd.PerformWithKeyword("test-connectivity-google", "test-connectivity", &options.SGoogleCloudAccountUpdateCredentialOptions{})
cmd.PerformWithKeyword("test-connectivity-vmware", "test-connectivity", &options.SVMwareCloudAccountUpdateCredentialOptions{})
+1
View File
@@ -62,6 +62,7 @@ func init() {
"k8s",
"monitor",
"bingocloud",
"ksyun",
}
const (
+1 -1
View File
@@ -83,7 +83,7 @@ require (
k8s.io/client-go v0.19.3
k8s.io/cluster-bootstrap v0.19.3
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230804055523-9c707c67e05f
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230807074306-1afe20f5d67a
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32
yunion.io/x/jsonutils v1.0.1-0.20230613121553-0f3b41e2ef19
yunion.io/x/log v1.0.1-0.20230411060016-feb3f46ab361
+2 -2
View File
@@ -1174,8 +1174,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230804055523-9c707c67e05f h1:jcMLnQkFGZemhnWbGCpr7ckb7yaIBbS1w2/vbLjf/tY=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230804055523-9c707c67e05f/go.mod h1:2sgCN7nRPQL3woLfdgqLDd92vwAHqtlz3KKiHxC5BAw=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230807074306-1afe20f5d67a h1:AwlwxsGXNxk80dri0FBlDb5oWSOnq5lXHeke6icd0pA=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230807074306-1afe20f5d67a/go.mod h1:2sgCN7nRPQL3woLfdgqLDd92vwAHqtlz3KKiHxC5BAw=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32 h1:v7POYkQwo1XzOxBoIoRVr/k0V9Y5JyjpshlIFa9raug=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
+5
View File
@@ -65,6 +65,7 @@ const (
CLOUD_PROVIDER_PROXMOX = compute.CLOUD_PROVIDER_PROXMOX
CLOUD_PROVIDER_REMOTEFILE = compute.CLOUD_PROVIDER_REMOTEFILE
CLOUD_PROVIDER_H3C = compute.CLOUD_PROVIDER_H3C
CLOUD_PROVIDER_KSYUN = compute.CLOUD_PROVIDER_KSYUN
CLOUD_PROVIDER_GENERICS3 = compute.CLOUD_PROVIDER_GENERICS3
CLOUD_PROVIDER_CEPH = compute.CLOUD_PROVIDER_CEPH
@@ -142,6 +143,7 @@ var (
CLOUD_PROVIDER_PROXMOX,
CLOUD_PROVIDER_REMOTEFILE,
CLOUD_PROVIDER_H3C,
CLOUD_PROVIDER_KSYUN,
}
CLOUD_PROVIDER_HOST_TYPE_MAP = map[string][]string{
@@ -222,6 +224,9 @@ var (
CLOUD_PROVIDER_H3C: {
HOST_TYPE_H3C,
},
CLOUD_PROVIDER_KSYUN: {
HOST_TYPE_KSYUN,
},
}
)
+5
View File
@@ -197,6 +197,7 @@ const (
HYPERVISOR_PROXMOX = compute.HYPERVISOR_PROXMOX
HYPERVISOR_REMOTEFILE = compute.HYPERVISOR_REMOTEFILE
HYPERVISOR_H3C = compute.HYPERVISOR_H3C
HYPERVISOR_KSYUN = compute.HYPERVISOR_KSYUN
// HYPERVISOR_DEFAULT = HYPERVISOR_KVM
HYPERVISOR_DEFAULT = HYPERVISOR_KVM
@@ -270,6 +271,7 @@ var HYPERVISORS = []string{
HYPERVISOR_PROXMOX,
HYPERVISOR_REMOTEFILE,
HYPERVISOR_H3C,
HYPERVISOR_KSYUN,
}
var ONECLOUD_HYPERVISORS = []string{
@@ -289,6 +291,7 @@ var PUBLIC_CLOUD_HYPERVISORS = []string{
HYPERVISOR_CTYUN,
HYPERVISOR_ECLOUD,
HYPERVISOR_JDCLOUD,
HYPERVISOR_KSYUN,
}
var PRIVATE_CLOUD_HYPERVISORS = []string{
@@ -337,6 +340,7 @@ var HYPERVISOR_HOSTTYPE = map[string]string{
HYPERVISOR_PROXMOX: HOST_TYPE_PROXMOX,
HYPERVISOR_REMOTEFILE: HOST_TYPE_REMOTEFILE,
HYPERVISOR_H3C: HOST_TYPE_H3C,
HYPERVISOR_KSYUN: HOST_TYPE_KSYUN,
}
var HOSTTYPE_HYPERVISOR = map[string]string{
@@ -367,6 +371,7 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
HOST_TYPE_PROXMOX: HYPERVISOR_PROXMOX,
HOST_TYPE_REMOTEFILE: HYPERVISOR_REMOTEFILE,
HOST_TYPE_H3C: HYPERVISOR_H3C,
HOST_TYPE_KSYUN: HYPERVISOR_KSYUN,
}
const (
+5 -1
View File
@@ -14,7 +14,9 @@
package compute
import "yunion.io/x/cloudmux/pkg/apis/compute"
import (
"yunion.io/x/cloudmux/pkg/apis/compute"
)
const (
HOST_TYPE_BAREMETAL = "baremetal"
@@ -48,6 +50,7 @@ const (
HOST_TYPE_PROXMOX = compute.HOST_TYPE_PROXMOX
HOST_TYPE_REMOTEFILE = compute.HOST_TYPE_REMOTEFILE
HOST_TYPE_H3C = compute.HOST_TYPE_H3C
HOST_TYPE_KSYUN = compute.HOST_TYPE_KSYUN
HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR
@@ -138,6 +141,7 @@ var HOST_TYPES = []string{
HOST_TYPE_PROXMOX,
HOST_TYPE_REMOTEFILE,
HOST_TYPE_H3C,
HOST_TYPE_KSYUN,
}
var ALL_NIC_TYPES = []compute.TNicType{NIC_TYPE_IPMI, NIC_TYPE_ADMIN, NIC_TYPE_NORMAL}
+104
View File
@@ -0,0 +1,104 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package guestdrivers
import (
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/pkg/util/billing"
"yunion.io/x/pkg/util/rbacscope"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SKsyunGuestDriver struct {
SManagedVirtualizedGuestDriver
}
func init() {
driver := SKsyunGuestDriver{}
models.RegisterGuestDriver(&driver)
}
func (self *SKsyunGuestDriver) DoScheduleSKUFilter() bool { return false }
func (self *SKsyunGuestDriver) GetHypervisor() string {
return api.HYPERVISOR_KSYUN
}
func (self *SKsyunGuestDriver) GetProvider() string {
return api.CLOUD_PROVIDER_KSYUN
}
func (self *SKsyunGuestDriver) GetDefaultSysDiskBackend() string {
return ""
}
func (self *SKsyunGuestDriver) GetMinimalSysDiskSizeGb() int {
return 20
}
func (self *SKsyunGuestDriver) GetComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_KSYUN
keys.Brand = api.CLOUD_PROVIDER_KSYUN
keys.Hypervisor = api.HYPERVISOR_KSYUN
return keys
}
func (self *SKsyunGuestDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
return cloudprovider.SInstanceCapability{
Hypervisor: self.GetHypervisor(),
Provider: self.GetProvider(),
DefaultAccount: cloudprovider.SDefaultAccount{
Linux: cloudprovider.SOsDefaultAccount{
DefaultAccount: api.VM_DEFAULT_LINUX_LOGIN_USER,
Changeable: false,
},
Windows: cloudprovider.SOsDefaultAccount{
DefaultAccount: api.VM_DEFAULT_WINDOWS_LOGIN_USER,
Changeable: false,
},
},
}
}
func (self *SKsyunGuestDriver) GetGuestInitialStateAfterCreate() string {
return api.VM_READY
}
func (self *SKsyunGuestDriver) GetGuestInitialStateAfterRebuild() string {
return api.VM_READY
}
func (self *SKsyunGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SKsyunGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return false
}
func (self *SKsyunGuestDriver) IsSupportPublicipToEip() bool {
return false
}
func (self *SKsyunGuestDriver) IsSupportSetAutoRenew() bool {
return false
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hostdrivers
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SKsyunHostDriver struct {
SManagedVirtualizationHostDriver
}
func init() {
driver := SKsyunHostDriver{}
models.RegisterHostDriver(&driver)
}
func (self *SKsyunHostDriver) GetHostType() string {
return api.HOST_TYPE_KSYUN
}
func (self *SKsyunHostDriver) GetHypervisor() string {
return api.HYPERVISOR_KSYUN
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package regiondrivers
import (
"context"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SKsyunRegionDriver struct {
SManagedVirtualizationRegionDriver
}
func init() {
driver := SKsyunRegionDriver{}
models.RegisterRegionDriver(&driver)
}
func (self *SKsyunRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_KSYUN
}
func (self *SKsyunRegionDriver) IsAllowSecurityGroupNameRepeat() bool {
return true
}
func (self *SKsyunRegionDriver) GenerateSecurityGroupName(name string) string {
return name
}
func (self *SKsyunRegionDriver) IsSecurityGroupBelongVpc() bool {
return true
}
func (self *SKsyunRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SnapshotCreateInput) error {
return nil
}
+1 -1
View File
@@ -245,7 +245,7 @@ type BaseListOptions struct {
Manager []string `help:"List objects belonging to the cloud provider" json:"manager,omitempty"`
Account string `help:"List objects belonging to the cloud account" json:"account,omitempty"`
Provider []string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Apsara|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack|Google|Ctyun|Cloudpods|Nutanix|BingoCloud|IncloudSphere|JDcloud|Proxmox|Ceph|Ecloud|HCSO|HCS|HCSOP|H3C|S3|RemoteFile" json:"provider,omitempty"`
Provider []string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Apsara|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack|Google|Ctyun|Cloudpods|Nutanix|BingoCloud|IncloudSphere|JDcloud|Proxmox|Ceph|Ecloud|HCSO|HCS|HCSOP|H3C|S3|RemoteFile|Ksyun" json:"provider,omitempty"`
Brand []string `help:"List objects belonging to a special brand"`
CloudEnv string `help:"Cloud environment" choices:"public|private|onpremise|private_or_onpremise" json:"cloud_env,omitempty"`
PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"`
+30
View File
@@ -1278,3 +1278,33 @@ func (opts *SRemoteFileAccountCreateOptions) Params() (jsonutils.JSONObject, err
params.(*jsonutils.JSONDict).Add(jsonutils.NewString(api.CLOUD_PROVIDER_REMOTEFILE), "provider")
return params, nil
}
type SKsyunCloudAccountCreateOptions struct {
SCloudAccountCreateBaseOptions
SAccessKeyCredential
}
func (opts *SKsyunCloudAccountCreateOptions) Params() (jsonutils.JSONObject, error) {
params := jsonutils.Marshal(opts)
params.(*jsonutils.JSONDict).Add(jsonutils.NewString("Ksyun"), "provider")
return params, nil
}
type SKsyunCloudAccountUpdateOptions struct {
SCloudAccountUpdateBaseOptions
}
func (opts *SKsyunCloudAccountUpdateOptions) Params() (jsonutils.JSONObject, error) {
params := jsonutils.Marshal(opts).(*jsonutils.JSONDict)
return params, nil
}
type SKsyunCloudAccountUpdateCredentialOptions struct {
SCloudAccountIdOptions
SAccessKeyCredential
}
func (opts *SKsyunCloudAccountUpdateCredentialOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
+1 -1
View File
@@ -44,7 +44,7 @@ type ServerListOptions struct {
Gpu *bool `help:"Show gpu servers"`
Secgroup string `help:"Secgroup ID or Name"`
AdminSecgroup string `help:"AdminSecgroup ID or Name"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud|zstack|openstack|google|ctyun|incloudsphere|nutanix|bingocloud|cloudpods|ecloud|jdcloud|remotefile|h3c|hcs|hcso|hcsop|proxmox"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud|zstack|openstack|google|ctyun|incloudsphere|nutanix|bingocloud|cloudpods|ecloud|jdcloud|remotefile|h3c|hcs|hcso|hcsop|proxmox|ksyun"`
Region string `help:"Show servers in cloudregion"`
WithEip *bool `help:"Show Servers with EIP"`
WithoutEip *bool `help:"Show Servers without EIP"`
+3 -1
View File
@@ -1438,7 +1438,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230804055523-9c707c67e05f
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230807074306-1afe20f5d67a
## explicit; go 1.18
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
@@ -1490,6 +1490,8 @@ yunion.io/x/cloudmux/pkg/multicloud/huawei/obs
yunion.io/x/cloudmux/pkg/multicloud/huawei/provider
yunion.io/x/cloudmux/pkg/multicloud/jdcloud
yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider
yunion.io/x/cloudmux/pkg/multicloud/ksyun
yunion.io/x/cloudmux/pkg/multicloud/ksyun/provider
yunion.io/x/cloudmux/pkg/multicloud/loader
yunion.io/x/cloudmux/pkg/multicloud/nutanix
yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider
+1
View File
@@ -40,6 +40,7 @@ const (
CLOUD_PROVIDER_PROXMOX = "Proxmox"
CLOUD_PROVIDER_REMOTEFILE = "RemoteFile"
CLOUD_PROVIDER_H3C = "H3C"
CLOUD_PROVIDER_KSYUN = "Ksyun"
CLOUD_PROVIDER_GENERICS3 = "S3"
CLOUD_PROVIDER_CEPH = "Ceph"
+1
View File
@@ -25,6 +25,7 @@ const (
CITY_HU_HE_HAO_TE = "Huhehaote" //呼和浩特
CITY_HANG_ZHOU = "Hangzhou" //杭州
CITY_SHANG_HAI = "Shanghai" //上海
CITY_QING_YANG = "Qingyang" //庆阳
CITY_SHEN_ZHEN = "Shenzhen" //深圳
CITY_HONG_KONG = "Hongkong" //香港
CITY_NING_XIA = "Ningxia" //宁夏
+1
View File
@@ -73,6 +73,7 @@ const (
HYPERVISOR_PROXMOX = "proxmox"
HYPERVISOR_REMOTEFILE = "remotefile"
HYPERVISOR_H3C = "h3c"
HYPERVISOR_KSYUN = "ksyun"
)
const (
+1
View File
@@ -42,6 +42,7 @@ const (
HOST_TYPE_PROXMOX = "proxmox"
HOST_TYPE_REMOTEFILE = "remotefile"
HOST_TYPE_H3C = "h3c"
HOST_TYPE_KSYUN = "ksyun"
// # possible status
HOST_ONLINE = "online"
+6
View File
@@ -38,6 +38,12 @@ var (
City: CITY_SHANG_HAI,
CountryCode: COUNTRY_CODE_CN,
}
RegionQingYang = cloudprovider.SGeographicInfo{
Latitude: 35.73,
Longitude: 107.61,
City: CITY_QING_YANG,
CountryCode: COUNTRY_CODE_CN,
}
RegionGuangzhou = cloudprovider.SGeographicInfo{
Latitude: 23.12911,
Longitude: 113.264385,
+1
View File
@@ -19,6 +19,7 @@ const (
STATUS_DELETE_FAILED = "delete_failed"
STATUS_CREATING = "creating"
STATUS_CREATE_FAILED = "create_failed"
STATUS_AVAILABLE = "available"
USER_TAG_PREFIX = "user:"
+305
View File
@@ -0,0 +1,305 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ksyun
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"sort"
"strings"
"sync"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/util/httputils"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
const (
CLOUD_PROVIDER_KSYUN_CN = "金山云"
KSYUN_DEFAULT_REGION = "cn-beijing-6"
)
type KsyunClientConfig struct {
cpcfg cloudprovider.ProviderConfig
accessKeyId string
accessKeySecret string
debug bool
}
type SKsyunClient struct {
*KsyunClientConfig
client *http.Client
lock sync.Mutex
ctx context.Context
customerId string
regions []SRegion
}
func NewKsyunClientConfig(accessKeyId, accessKeySecret string) *KsyunClientConfig {
cfg := &KsyunClientConfig{
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret,
}
return cfg
}
func (self *KsyunClientConfig) Debug(debug bool) *KsyunClientConfig {
self.debug = debug
return self
}
func (self *KsyunClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *KsyunClientConfig {
self.cpcfg = cpcfg
return self
}
func NewKsyunClient(cfg *KsyunClientConfig) (*SKsyunClient, error) {
client := &SKsyunClient{
KsyunClientConfig: cfg,
ctx: context.Background(),
}
client.ctx = context.WithValue(client.ctx, "time", time.Now())
var err error
client.regions, err = client.GetRegions()
return client, err
}
func (self *SKsyunClient) GetRegions() ([]SRegion, error) {
resp, err := self.ec2Request("", "DescribeRegions", nil)
if err != nil {
return nil, err
}
ret := struct {
RegionSet []SRegion
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, err
}
for i := range ret.RegionSet {
ret.RegionSet[i].client = self
}
return ret.RegionSet, nil
}
func (self *SKsyunClient) GetRegion(id string) (*SRegion, error) {
for i := range self.regions {
if self.regions[i].Region == id {
self.regions[i].client = self
return &self.regions[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SKsyunClient) getUrl(service, regionId string) string {
if len(regionId) == 0 {
regionId = KSYUN_DEFAULT_REGION
}
switch service {
case "kingpay":
return "http://kingpay.api.ksyun.com"
case "kec":
return fmt.Sprintf("https://kec.%s.api.ksyun.com", regionId)
}
return ""
}
func (cli *SKsyunClient) getDefaultClient() *http.Client {
cli.lock.Lock()
defer cli.lock.Unlock()
if !gotypes.IsNil(cli.client) {
return cli.client
}
cli.client = httputils.GetAdaptiveTimeoutClient()
httputils.SetClientProxyFunc(cli.client, cli.cpcfg.ProxyFunc)
ts, _ := cli.client.Transport.(*http.Transport)
ts.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
cli.client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
params, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return nil, errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
}
action := params.Get("Action")
for _, prefix := range []string{"Get", "List", "Describe", "Query"} {
if strings.HasPrefix(action, prefix) {
return nil, nil
}
}
if cli.cpcfg.ReadOnly {
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil, nil
})
return cli.client
}
type sKsyunError struct {
StatusCode int `json:"StatusCode"`
RequestId string `json:"RequestId"`
ErrorMsg struct {
Code string `json:"Code"`
Message string `json:"Message"`
Type string `json:"Type"`
} `json:"Error"`
}
func (self *sKsyunError) Error() string {
return jsonutils.Marshal(self).String()
}
func (self *sKsyunError) ParseErrorFromJsonResponse(statusCode int, status string, body jsonutils.JSONObject) error {
if body != nil {
body.Unmarshal(self)
}
self.StatusCode = statusCode
return self
}
func (self *SKsyunClient) sign(req *http.Request) (string, error) {
query, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return "", err
}
keys := []string{}
for k := range query {
keys = append(keys, k)
}
sort.Strings(keys)
var buf bytes.Buffer
for i := range keys {
k := keys[i]
buf.WriteString(strings.Replace(url.QueryEscape(k), "+", "%20", -1))
buf.WriteString("=")
buf.WriteString(strings.Replace(url.QueryEscape(query.Get(k)), "+", "%20", -1))
buf.WriteString("&")
}
buf.Truncate(buf.Len() - 1)
hashed := hmac.New(sha256.New, []byte(self.accessKeySecret))
hashed.Write([]byte(buf.String()))
return hex.EncodeToString(hashed.Sum(nil)), nil
}
func (self *SKsyunClient) Do(req *http.Request) (*http.Response, error) {
client := self.getDefaultClient()
signature, err := self.sign(req)
if err != nil {
return nil, errors.Wrapf(err, "sign")
}
query, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return nil, err
}
query.Set("Signature", signature)
req.URL.RawQuery = query.Encode()
req.Header.Set("Accept", "application/json")
return client.Do(req)
}
func (self *SKsyunClient) ec2Request(regionId, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
return self.request("kec", regionId, apiName, "2016-03-04", params)
}
func (self *SKsyunClient) request(service, regionId, apiName, apiVersion string, params map[string]string) (jsonutils.JSONObject, error) {
uri := self.getUrl(service, regionId)
if params == nil {
params = map[string]string{}
}
params["Action"] = apiName
params["Version"] = apiVersion
params["Accesskey"] = self.accessKeyId
params["SignatureMethod"] = "HMAC-SHA256"
params["Service"] = service
params["Format"] = "json"
params["SignatureVersion"] = "1.0"
params["Timestamp"] = time.Now().UTC().Format("2006-01-02T15:04:05Z")
values := url.Values{}
for k, v := range params {
values.Set(k, v)
}
uri = fmt.Sprintf("%s?%s", uri, values.Encode())
req := httputils.NewJsonRequest(httputils.GET, uri, nil)
ksErr := &sKsyunError{}
client := httputils.NewJsonClient(self)
_, resp, err := client.Send(self.ctx, req, ksErr, self.debug)
return resp, err
}
func (self *SKsyunClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
subAccount := cloudprovider.SSubAccount{}
subAccount.Name = self.cpcfg.Name
subAccount.Account = self.accessKeyId
subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL
return []cloudprovider.SSubAccount{subAccount}, nil
}
func (self *SKsyunClient) GetAccountId() string {
if len(self.customerId) > 0 {
return self.customerId
}
self.QueryCashWalletAction()
return self.customerId
}
type CashWalletDetail struct {
CustomerId string
AvailableAmount float64
RewardAmount string
FrozenAmount string
Currency string
}
func (self *SKsyunClient) QueryCashWalletAction() (*CashWalletDetail, error) {
resp, err := self.request("kingpay", "", "QueryCashWalletAction", "V1", nil)
if err != nil {
return nil, err
}
ret := &CashWalletDetail{}
err = resp.Unmarshal(ret, "data")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
self.customerId = ret.CustomerId
return ret, nil
}
func (self *SKsyunClient) GetCapabilities() []string {
caps := []string{
cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX,
}
return caps
}
+207
View File
@@ -0,0 +1,207 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package provider
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud/ksyun"
)
type SKsyunProviderFactory struct {
cloudprovider.SPublicCloudBaseProviderFactory
}
func (self *SKsyunProviderFactory) GetId() string {
return api.CLOUD_PROVIDER_KSYUN
}
func (self *SKsyunProviderFactory) GetName() string {
return ksyun.CLOUD_PROVIDER_KSYUN_CN
}
func (self *SKsyunProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) {
output := cloudprovider.SCloudaccount{}
if len(input.AccessKeyId) == 0 {
return output, errors.Wrap(cloudprovider.ErrMissingParameter, "access_key_id")
}
if len(input.AccessKeySecret) == 0 {
return output, errors.Wrap(cloudprovider.ErrMissingParameter, "access_key_secret")
}
output.AccessUrl = input.Environment
output.Account = input.AccessKeyId
output.Secret = input.AccessKeySecret
return output, nil
}
func (self *SKsyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) {
output := cloudprovider.SCloudaccount{}
if len(input.AccessKeyId) == 0 {
return output, errors.Wrap(cloudprovider.ErrMissingParameter, "access_key_id")
}
if len(input.AccessKeySecret) == 0 {
return output, errors.Wrap(cloudprovider.ErrMissingParameter, "access_key_secret")
}
output = cloudprovider.SCloudaccount{
Account: input.AccessKeyId,
Secret: input.AccessKeySecret,
}
return output, nil
}
func (self *SKsyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) {
client, err := ksyun.NewKsyunClient(
ksyun.NewKsyunClientConfig(
cfg.Account,
cfg.Secret,
).CloudproviderConfig(cfg),
)
if err != nil {
return nil, err
}
return &SKsyunProvider{
SBaseProvider: cloudprovider.NewBaseProvider(self),
client: client,
}, nil
}
func (self *SKsyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) {
return map[string]string{
"KSYUN_ACCESS_KEY_ID": info.Account,
"KSYUN_ACCESS_KEY_SECRET": info.Secret,
"KSYUN_REGION_ID": ksyun.KSYUN_DEFAULT_REGION,
}, nil
}
func init() {
factory := SKsyunProviderFactory{}
cloudprovider.RegisterFactory(&factory)
}
type SKsyunProvider struct {
cloudprovider.SBaseProvider
client *ksyun.SKsyunClient
}
func (self *SKsyunProvider) GetSysInfo() (jsonutils.JSONObject, error) {
regions, err := self.client.GetRegions()
if err != nil {
return nil, err
}
info := jsonutils.NewDict()
info.Add(jsonutils.NewInt(int64(len(regions))), "region_count")
return info, nil
}
func (self *SKsyunProvider) GetVersion() string {
return ""
}
func (self *SKsyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
return self.client.GetSubAccounts()
}
func (self *SKsyunProvider) GetAccountId() string {
return self.client.GetAccountId()
}
func (self *SKsyunProvider) GetIRegions() []cloudprovider.ICloudRegion {
regions, err := self.client.GetRegions()
if err != nil {
return nil
}
ret := []cloudprovider.ICloudRegion{}
for i := range regions {
ret = append(ret, &regions[i])
}
return ret
}
func (self *SKsyunProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
region, err := self.client.GetRegion(extId)
if err != nil {
return nil, err
}
return region, nil
}
func (self *SKsyunProvider) GetBalance() (*cloudprovider.SBalanceInfo, error) {
ret := &cloudprovider.SBalanceInfo{Currency: "CNY", Status: api.CLOUD_PROVIDER_HEALTH_UNKNOWN}
balance, err := self.client.QueryCashWalletAction()
if err != nil {
return ret, err
}
ret.Status = api.CLOUD_PROVIDER_HEALTH_NORMAL
ret.Currency = balance.Currency
if balance.AvailableAmount <= 0 {
if balance.AvailableAmount < 0 {
ret.Status = api.CLOUD_PROVIDER_HEALTH_ARREARS
} else if balance.AvailableAmount < 100 {
ret.Status = api.CLOUD_PROVIDER_HEALTH_INSUFFICIENT
}
}
ret.Amount = balance.AvailableAmount
return ret, nil
}
func (self *SKsyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
return []cloudprovider.ICloudProject{}, nil
}
func (self *SKsyunProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SKsyunProvider) GetStorageClasses(regionId string) []string {
return []string{}
}
func (self *SKsyunProvider) GetBucketCannedAcls(regionId string) []string {
return []string{
string(cloudprovider.ACLPrivate),
string(cloudprovider.ACLPublicRead),
string(cloudprovider.ACLPublicReadWrite),
}
}
func (self *SKsyunProvider) GetObjectCannedAcls(regionId string) []string {
return []string{
string(cloudprovider.ACLPrivate),
string(cloudprovider.ACLPublicRead),
string(cloudprovider.ACLPublicReadWrite),
}
}
func (self *SKsyunProvider) GetCapabilities() []string {
return self.client.GetCapabilities()
}
func (self *SKsyunProvider) GetIamLoginUrl() string {
return ""
}
func (self *SKsyunProvider) GetCloudRegionExternalIdPrefix() string {
return api.CLOUD_PROVIDER_KSYUN + "/"
}
func (self *SKsyunProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
return nil, cloudprovider.ErrNotImplemented
}
+129
View File
@@ -0,0 +1,129 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ksyun
import (
"fmt"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
)
type SRegion struct {
multicloud.SRegion
multicloud.SNoObjectStorageRegion
multicloud.SNoLbRegion
client *SKsyunClient
Region string
RegionName string
}
func (self *SRegion) GetId() string {
return self.Region
}
func (self *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_KSYUN, self.Region)
}
func (self *SRegion) GetProvider() string {
return api.CLOUD_PROVIDER_KSYUN
}
func (self *SRegion) GetCloudEnv() string {
return api.CLOUD_PROVIDER_KSYUN
}
func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
geo, ok := map[string]cloudprovider.SGeographicInfo{
"cn-northwest-1": api.RegionQingYang,
"ap-singapore-1": api.RegionSingapore,
"cn-beijing-6": api.RegionBeijing,
"cn-guangzhou-1": api.RegionGuangzhou,
"cn-shanghai-2": api.RegionShanghai,
}[self.Region]
if ok {
return geo
}
return cloudprovider.SGeographicInfo{}
}
func (self *SRegion) GetName() string {
return self.RegionName
}
func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
table := cloudprovider.SModelI18nTable{}
table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(self.Region)
return table
}
func (self *SRegion) GetStatus() string {
return api.CLOUD_REGION_STATUS_INSERVER
}
func (self *SRegion) GetClient() *SKsyunClient {
return self.client
}
func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetCapabilities() []string {
return region.client.GetCapabilities()
}
func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
return nil, cloudprovider.ErrNotImplemented
}
+1
View File
@@ -29,6 +29,7 @@ import (
_ "yunion.io/x/cloudmux/pkg/multicloud/hcso/provider"
_ "yunion.io/x/cloudmux/pkg/multicloud/huawei/provider"
_ "yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider" // public clouds
_ "yunion.io/x/cloudmux/pkg/multicloud/ksyun/provider"
_ "yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider" // private clouds
_ "yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider"
_ "yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider"