Files
cloudpods/pkg/util/qcloud/qcloud.go
T
邱剑 48b3a0062e Automatic merge from release/2.3.0 -> release/2.4.0
* commit '434c839a49559d7120b64a7593cdf40dd81d7122':
  添加腾讯云错误重试代码
2018-12-05 15:36:16 +08:00

267 lines
7.8 KiB
Go

package qcloud
import (
"fmt"
"strings"
"time"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
const (
CLOUD_PROVIDER_QCLOUD = models.CLOUD_PROVIDER_QCLOUD
CLOUD_PROVIDER_QCLOUD_CN = "腾讯云"
QCLOUD_DEFAULT_REGION = "ap-beijing"
QCLOUD_API_VERSION = "2017-03-12"
)
type SQcloudClient struct {
providerId string
providerName string
AppID string
SecretID string
SecretKey string
iregions []cloudprovider.ICloudRegion
}
func NewQcloudClient(providerId string, providerName string, secretID string, secretKey string) (*SQcloudClient, error) {
client := SQcloudClient{providerId: providerId, providerName: providerName, SecretID: secretID, SecretKey: secretKey}
if account := strings.Split(secretID, "/"); len(account) == 2 {
client.SecretID = account[0]
client.AppID = account[1]
}
err := client.fetchRegions()
if err != nil {
return nil, err
}
return &client, nil
}
func jsonRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
domain := "cvm.tencentcloudapi.com"
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
domain = "cvm." + region + ".tencentcloudapi.com"
}
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
}
func vpcRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
domain := "vpc.tencentcloudapi.com"
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
domain = "vpc." + region + ".tencentcloudapi.com"
}
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
}
func cbsRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
domain := "cbs.tencentcloudapi.com"
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
domain = "cbs." + region + ".tencentcloudapi.com"
}
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
}
type QcloudResponse struct {
*tchttp.BaseResponse
Response *interface{} `json:"Response"`
}
func _jsonRequest(client *common.Client, domain string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
req := &tchttp.BaseRequest{}
if region, ok := params["Region"]; ok {
client = client.Init(region)
}
client.WithProfile(profile.NewClientProfile())
service := strings.Split(domain, ".")[0]
req.Init().WithApiInfo(service, version, apiName)
req.SetDomain(domain)
for k, v := range params {
if strings.HasSuffix(k, "Ids.0") && len(v) == 0 {
return nil, cloudprovider.ErrNotFound
}
req.GetParams()[k] = v
}
resp := &QcloudResponse{
BaseResponse: &tchttp.BaseResponse{},
}
for i := 1; i <= 3; i++ {
err := client.Send(req, resp)
if err == nil {
break
}
needRetry := false
for _, msg := range []string{"EOF", "TLS handshake timeout", "Code=InternalError", "retry later", "Code=MutexOperation.TaskRunning"} {
if strings.Contains(err.Error(), msg) {
needRetry = true
break
}
}
if needRetry && i != 3 {
log.Errorf("request url %s\nparams: %s\nerror: %v\nafter %d second try again", req.GetDomain(), jsonutils.Marshal(req.GetParams()).PrettyString(), err, i*10)
time.Sleep(time.Second * time.Duration(i*10))
continue
}
log.Errorf("request url: %s\nparams: %s\nresponse: %s\nerror: %v", req.GetDomain(), jsonutils.Marshal(req.GetParams()).PrettyString(), resp.Response, err)
return nil, err
}
return jsonutils.Marshal(resp.Response), nil
}
func (client *SQcloudClient) GetRegions() []SRegion {
regions := make([]SRegion, len(client.iregions))
for i := 0; i < len(regions); i++ {
region := client.iregions[i].(*SRegion)
regions[i] = *region
}
return regions
}
func (client *SQcloudClient) getDefaultClient() (*common.Client, error) {
return common.NewClientWithSecretId(client.SecretID, client.SecretKey, QCLOUD_DEFAULT_REGION)
}
func (client *SQcloudClient) vpcRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return vpcRequest(cli, apiName, params)
}
func (client *SQcloudClient) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return cbsRequest(cli, apiName, params)
}
func (client *SQcloudClient) jsonRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return jsonRequest(cli, apiName, params)
}
func (client *SQcloudClient) fetchRegions() error {
body, err := client.jsonRequest("DescribeRegions", nil)
if err != nil {
log.Errorf("fetchRegions fail %s", err)
return err
}
regions := make([]SRegion, 0)
err = body.Unmarshal(&regions, "RegionSet")
if err != nil {
log.Errorf("unmarshal json error %s", err)
return err
}
client.iregions = make([]cloudprovider.ICloudRegion, len(regions))
for i := 0; i < len(regions); i++ {
regions[i].client = client
client.iregions[i] = &regions[i]
}
return nil
}
func (client *SQcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
err := client.fetchRegions()
if err != nil {
return nil, err
}
subAccount := cloudprovider.SSubAccount{}
subAccount.Name = client.providerName
subAccount.Account = client.SecretID
if len(client.AppID) > 0 {
subAccount.Account = fmt.Sprintf("%s/%s", client.SecretID, client.AppID)
}
return []cloudprovider.SSubAccount{subAccount}, nil
}
func (client *SQcloudClient) GetIRegions() []cloudprovider.ICloudRegion {
return client.iregions
}
func (client *SQcloudClient) getDefaultRegion() (cloudprovider.ICloudRegion, error) {
if len(client.iregions) > 0 {
return client.iregions[0], nil
}
return nil, cloudprovider.ErrNotFound
}
func (client *SQcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
for i := 0; i < len(client.iregions); i++ {
if client.iregions[i].GetGlobalId() == id {
return client.iregions[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (client *SQcloudClient) GetRegion(regionId string) *SRegion {
for i := 0; i < len(client.iregions); i++ {
if client.iregions[i].GetId() == regionId {
return client.iregions[i].(*SRegion)
}
}
return nil
}
func (client *SQcloudClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
for i := 0; i < len(client.iregions); i++ {
ihost, err := client.iregions[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (client *SQcloudClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
for i := 0; i < len(client.iregions); i++ {
ihost, err := client.iregions[i].GetIVpcById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (client *SQcloudClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
for i := 0; i < len(client.iregions); i++ {
ihost, err := client.iregions[i].GetIStorageById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
type SAccountBalance struct {
AvailableAmount float64
AvailableCashAmount float64
CreditAmount float64
MybankCreditAmount float64
Currency string
}
func (client *SQcloudClient) QueryAccountBalance() (*SAccountBalance, error) {
return nil, nil
}