mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 14:19:49 +08:00
fix(region): refactor huawei api for support organization (#19068)
This commit is contained in:
@@ -88,7 +88,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.20231220031827-28bfe13ab842
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0
|
||||
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
|
||||
|
||||
@@ -1201,8 +1201,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.20231220031827-28bfe13ab842 h1:4AjLgwOnaAexsd+nrUodqg4m6cm4sB+HaA9deBkd9Tc=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220031827-28bfe13ab842/go.mod h1:aj1gR9PPb6eqqKOwvANe26CoZFY8ydmXy0fuvgKYXH0=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0 h1:2Sj/zBlEgWaQGNxQXh1ZYLlNzZh0DAsTe3J/+eYBXZE=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0/go.mod h1:aj1gR9PPb6eqqKOwvANe26CoZFY8ydmXy0fuvgKYXH0=
|
||||
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=
|
||||
|
||||
@@ -590,6 +590,9 @@ func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestForCreate(ctx contex
|
||||
if err == nil || !options.Options.EnableAutoSwitchServerSku {
|
||||
return iVM, err
|
||||
}
|
||||
if errors.Cause(err) != cloudprovider.ErrInvalidSku {
|
||||
return iVM, err
|
||||
}
|
||||
skus, e := models.ServerSkuManager.GetSkus(host.GetProviderName(), guest.VcpuCount, guest.VmemSize)
|
||||
if e != nil {
|
||||
return iVM, errors.Wrapf(e, "GetSkus")
|
||||
|
||||
@@ -102,7 +102,7 @@ type SElasticcache struct {
|
||||
CapacityMB int `nullable:"false" list:"user" create:"optional" json:"capacity_mb"`
|
||||
|
||||
// 对应Sku
|
||||
LocalCategory string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"local_category"`
|
||||
LocalCategory string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"local_category"`
|
||||
|
||||
// 类型
|
||||
// single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读)
|
||||
@@ -212,22 +212,23 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns(
|
||||
virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
|
||||
netIds := make([]string, len(objs))
|
||||
cacheIds := make([]string, len(objs))
|
||||
vpcIds := make([]string, len(objs))
|
||||
zoneIds := []string{}
|
||||
for i := range rows {
|
||||
rows[i] = api.ElasticcacheDetails{
|
||||
VirtualResourceDetails: virtRows[i],
|
||||
VpcResourceInfo: vpcRows[i],
|
||||
ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase,
|
||||
}
|
||||
rows[i].ManagedResourceInfo = manRows[i]
|
||||
rows[i].CloudregionResourceInfo = regRows[i]
|
||||
netIds[i] = objs[i].(*SElasticcache).NetworkId
|
||||
cacheIds[i] = objs[i].(*SElasticcache).Id
|
||||
cache := objs[i].(*SElasticcache)
|
||||
netIds[i] = cache.NetworkId
|
||||
cacheIds[i] = cache.Id
|
||||
vpcIds[i] = cache.VpcId
|
||||
|
||||
sz := strings.Split(objs[i].(*SElasticcache).SlaveZones, ",")
|
||||
for j := range sz {
|
||||
@@ -237,8 +238,15 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns(
|
||||
}
|
||||
}
|
||||
|
||||
vpcs := make(map[string]SVpc)
|
||||
err := db.FetchStandaloneObjectsByIds(VpcManager, vpcIds, vpcs)
|
||||
if err != nil {
|
||||
log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
networks := make(map[string]SNetwork)
|
||||
err := db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks)
|
||||
err = db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks)
|
||||
if err != nil {
|
||||
log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
|
||||
return rows
|
||||
@@ -248,6 +256,11 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns(
|
||||
if net, ok := networks[netIds[i]]; ok {
|
||||
rows[i].Network = net.Name
|
||||
}
|
||||
if vpc, ok := vpcs[vpcIds[i]]; ok {
|
||||
rows[i].Vpc = vpc.Name
|
||||
rows[i].VpcExtId = vpc.ExternalId
|
||||
rows[i].IsDefaultVpc = vpc.IsDefault
|
||||
}
|
||||
}
|
||||
|
||||
if len(fields) == 0 || fields.Contains("secgroups") || fields.Contains("secgroup") {
|
||||
|
||||
@@ -354,11 +354,15 @@ func (self *SVpcPeeringConnection) syncRemove(ctx context.Context, userCred mccl
|
||||
return self.RealDelete(ctx, userCred)
|
||||
}
|
||||
|
||||
func (self *SVpcPeeringConnection) SyncWithCloudPeerConnection(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudVpcPeeringConnection, provider *SCloudprovider) error {
|
||||
func (self *SVpcPeeringConnection) SyncWithCloudPeerConnection(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudVpcPeeringConnection) error {
|
||||
vpc, err := self.GetVpc()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetVpc")
|
||||
}
|
||||
provider := vpc.GetCloudprovider()
|
||||
if provider == nil {
|
||||
return errors.Wrapf(cloudprovider.ErrNotFound, "cloudprovider for vpc %s", vpc.Name)
|
||||
}
|
||||
_, err = db.Update(self, func() error {
|
||||
self.Status = ext.GetStatus()
|
||||
self.ExternalId = ext.GetGlobalId()
|
||||
|
||||
@@ -1742,7 +1742,7 @@ func (svpc *SVpc) SyncVpcPeeringConnections(
|
||||
|
||||
if !xor {
|
||||
for i := 0; i < len(commondb); i += 1 {
|
||||
err = commondb[i].SyncWithCloudPeerConnection(ctx, userCred, commonext[i], provider)
|
||||
err = commondb[i].SyncWithCloudPeerConnection(ctx, userCred, commonext[i])
|
||||
if err != nil {
|
||||
result.UpdateError(err)
|
||||
continue
|
||||
|
||||
@@ -90,7 +90,7 @@ func (self *VpcPeeringConnectionCreateTask) OnInit(ctx context.Context, obj db.I
|
||||
}
|
||||
|
||||
iPeerConnection.Refresh()
|
||||
err = peer.SyncWithCloudPeerConnection(ctx, self.GetUserCred(), iPeerConnection, nil)
|
||||
err = peer.SyncWithCloudPeerConnection(ctx, self.GetUserCred(), iPeerConnection)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, peer, errors.Wrapf(err, "SyncWithCloudPeerConnection"))
|
||||
return
|
||||
|
||||
@@ -69,7 +69,7 @@ func (self *VpcPeeringConnectionSyncstatusTask) OnInit(ctx context.Context, obj
|
||||
return
|
||||
}
|
||||
|
||||
err = peer.SyncWithCloudPeerConnection(ctx, self.UserCred, ipeer, nil)
|
||||
err = peer.SyncWithCloudPeerConnection(ctx, self.UserCred, ipeer)
|
||||
if err != nil {
|
||||
self.taskFail(ctx, peer, errors.Wrapf(err, "SyncWithCloudPeerConnection(ctx, self.UserCred, %s, nil)", jsonutils.Marshal(ipeer).String()))
|
||||
return
|
||||
|
||||
Vendored
+1
-9
@@ -1465,7 +1465,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.20231220031827-28bfe13ab842
|
||||
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0
|
||||
## explicit; go 1.18
|
||||
yunion.io/x/cloudmux/pkg/apis
|
||||
yunion.io/x/cloudmux/pkg/apis/billing
|
||||
@@ -1509,14 +1509,6 @@ yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests
|
||||
yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses
|
||||
yunion.io/x/cloudmux/pkg/multicloud/hcso/provider
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/obs
|
||||
yunion.io/x/cloudmux/pkg/multicloud/huawei/provider
|
||||
yunion.io/x/cloudmux/pkg/multicloud/jdcloud
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ const (
|
||||
ErrNoPermission = errors.Error("NoPermission")
|
||||
ErrNoSuchProvder = errors.Error("no such provider")
|
||||
ErrTooManyRequests = errors.Error("TooManyRequests")
|
||||
ErrInvalidSku = errors.Error("InvalidSku")
|
||||
|
||||
ErrNotFound = errors.ErrNotFound
|
||||
ErrDuplicateId = errors.ErrDuplicateId
|
||||
|
||||
+41
-9
@@ -23,13 +23,45 @@ import (
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests"
|
||||
hw_mod "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
type SCloudEyeManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type SMetricDimension struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type SDatapoint struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Max float64 `json:"max,omitzero"`
|
||||
Min float64 `json:"min,omitzero"`
|
||||
Average float64 `json:"average,omitzero"`
|
||||
Sum float64 `json:"sum,omitzero"`
|
||||
Variance float64 `json:"variance,omitzero"`
|
||||
}
|
||||
|
||||
type SMetricData struct {
|
||||
SMetricMeta
|
||||
|
||||
Datapoints []SDatapoint
|
||||
}
|
||||
|
||||
type SMetricMeta struct {
|
||||
SMetric
|
||||
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
|
||||
type SMetric struct {
|
||||
MetricName string `json:"metric_name"`
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
Dimensions []SMetricDimension `json:"dimensions"`
|
||||
}
|
||||
|
||||
func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager {
|
||||
return &SCloudEyeManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
@@ -43,8 +75,8 @@ func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager {
|
||||
}}
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) {
|
||||
metrics := make([]hw_mod.SMetricMeta, 0)
|
||||
func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) {
|
||||
metrics := make([]SMetricMeta, 0)
|
||||
next := ""
|
||||
for {
|
||||
marker, data, err := ces.listMetricsInternal(next)
|
||||
@@ -60,7 +92,7 @@ func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) {
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod.SMetricMeta, error) {
|
||||
func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) {
|
||||
request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword)
|
||||
request.AddQueryParam("limit", "1000")
|
||||
if len(start) > 0 {
|
||||
@@ -71,7 +103,7 @@ func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod
|
||||
return "", nil, errors.Wrap(err, "ces.jsonRequest")
|
||||
}
|
||||
marker, _ := resp.GetString("meta_data", "marker")
|
||||
metrics := make([]hw_mod.SMetricMeta, 0)
|
||||
metrics := make([]SMetricMeta, 0)
|
||||
err = resp.Unmarshal(&metrics, "metrics")
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "resp.Unmarshal metrics")
|
||||
@@ -80,7 +112,7 @@ func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod
|
||||
}
|
||||
|
||||
type SBatchQueryMetricDataInput struct {
|
||||
Metrics []hw_mod.SMetric `json:"metrics"`
|
||||
Metrics []SMetric `json:"metrics"`
|
||||
|
||||
From int64 `json:"from"`
|
||||
To int64 `json:"to"`
|
||||
@@ -88,11 +120,11 @@ type SBatchQueryMetricDataInput struct {
|
||||
Filter string `json:"filter"`
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since time.Time, until time.Time) ([]hw_mod.SMetricData, error) {
|
||||
func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) {
|
||||
if len(metrics) > 10 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrTooLarge, "request more than 10 metrics")
|
||||
}
|
||||
metricReq := make([]hw_mod.SMetric, len(metrics))
|
||||
metricReq := make([]SMetric, len(metrics))
|
||||
for i := range metrics {
|
||||
metricReq[i] = metrics[i].SMetric
|
||||
}
|
||||
@@ -111,7 +143,7 @@ func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since
|
||||
return nil, errors.Wrap(err, "ces.jsonRequest")
|
||||
}
|
||||
//log.Debugf("%s", resp)
|
||||
result := make([]hw_mod.SMetricData, 0)
|
||||
result := make([]SMetricData, 0)
|
||||
err = resp.Unmarshal(&result, "metrics")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules"
|
||||
)
|
||||
|
||||
type MetricData struct {
|
||||
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// 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 auth
|
||||
|
||||
type Credential interface {
|
||||
}
|
||||
Generated
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
// 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 credentials
|
||||
|
||||
type AccessKeyCredential struct {
|
||||
AccessKeyId string
|
||||
AccessKeySecret string
|
||||
}
|
||||
|
||||
func NewAccessKeyCredential(accessKeyId, accessKeySecret string) *AccessKeyCredential {
|
||||
return &AccessKeyCredential{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 credentials // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials"
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 auth // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth"
|
||||
-215
@@ -1,215 +0,0 @@
|
||||
// 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 auth
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
)
|
||||
|
||||
type Signer interface {
|
||||
GetName() string // 签名算法名称
|
||||
GetAccessKeyId() (accessKeyId string, err error) // 签名access key
|
||||
GetSecretKey() (secretKey string, err error) // access secret
|
||||
Sign(stringToSign, secretSuffix string) string // 生成签名结果
|
||||
}
|
||||
|
||||
func NewSignerWithCredential(credential Credential) (signer Signer, err error) {
|
||||
switch instance := credential.(type) {
|
||||
case *credentials.AccessKeyCredential:
|
||||
return signers.NewAccessKeySigner(instance), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported credential error")
|
||||
}
|
||||
}
|
||||
|
||||
// 对request进行签名
|
||||
func Sign(request requests.IRequest, signer Signer) (err error) {
|
||||
return signRequest(request, signer)
|
||||
}
|
||||
|
||||
func signRequest(request requests.IRequest, signer Signer) error {
|
||||
// https://support.huaweicloud.com/api-dis/dis_02_0508.html
|
||||
// requestTime
|
||||
reqTime := time.Now()
|
||||
// 添加 必须的Headers
|
||||
fillRequiredHeaders(request, reqTime)
|
||||
// 计算CanonicalRequest
|
||||
canonicalRequest := canonicalRequest(request)
|
||||
// stringToSign
|
||||
credentialScope := strings.Join([]string{
|
||||
formattedSignTime(reqTime, "Date"),
|
||||
request.GetRegionId(),
|
||||
request.GetProduct(),
|
||||
"sdk_request",
|
||||
}, "/")
|
||||
stringToSign := strings.Join([]string{"SDK-HMAC-SHA256",
|
||||
formattedSignTime(reqTime, "DateTime"),
|
||||
credentialScope,
|
||||
hashSha256([]byte(canonicalRequest)),
|
||||
}, "\n")
|
||||
// 计算SigningKey
|
||||
secret, _ := signer.GetSecretKey()
|
||||
signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"),
|
||||
request.GetRegionId(), request.GetProduct())
|
||||
// 计算Signature
|
||||
signature := signer.Sign(stringToSign, signKey)
|
||||
accesskey, _ := signer.GetAccessKeyId()
|
||||
addAuthorizationHeader(request, accesskey, credentialScope, signature)
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html
|
||||
// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。
|
||||
func fillRequiredHeaders(request requests.IRequest, t time.Time) {
|
||||
request.AddHeaderParam("HOST", request.GetHost())
|
||||
request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime"))
|
||||
if len(request.GetProjectId()) > 0 {
|
||||
request.AddHeaderParam("X-Project-Id", request.GetProjectId())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func buildRequestStringToSign(request requests.IRequest) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func formattedSignTime(t time.Time, format string) string {
|
||||
switch format {
|
||||
case "Date":
|
||||
return t.UTC().Format("20060102")
|
||||
case "DateTime":
|
||||
return t.UTC().Format("20060102T150405Z")
|
||||
default:
|
||||
return t.UTC().Format("20060102T150405Z")
|
||||
}
|
||||
}
|
||||
|
||||
func contentSha256(request requests.IRequest) string {
|
||||
method := strings.ToUpper(request.GetMethod())
|
||||
content := []byte{}
|
||||
body := request.GetBodyReader()
|
||||
content, _ = ioutil.ReadAll(body)
|
||||
if method == "POST" {
|
||||
if len(content) == 0 {
|
||||
// other http method use query as content
|
||||
content = []byte(request.BuildQueries())
|
||||
}
|
||||
}
|
||||
|
||||
return hashSha256(content)
|
||||
}
|
||||
|
||||
func hashSha256(msg []byte) string {
|
||||
sh256 := sha256.New()
|
||||
sh256.Write(msg)
|
||||
|
||||
return hex.EncodeToString(sh256.Sum(nil))
|
||||
}
|
||||
|
||||
func canonicalRequest(request requests.IRequest) string {
|
||||
sha256 := contentSha256(request)
|
||||
uri := request.GetURI()
|
||||
if !strings.HasSuffix(uri, "/") {
|
||||
uri = uri + "/"
|
||||
}
|
||||
|
||||
return strings.Join([]string{
|
||||
request.GetMethod(),
|
||||
uri,
|
||||
canonicalQueryString(request),
|
||||
canonicalHeaders(request),
|
||||
canonicalHeaderNames(request),
|
||||
sha256,
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func sortedHeaderNames(request requests.IRequest) []string {
|
||||
headers := request.GetHeaders()
|
||||
keys := make([]string, 0)
|
||||
for k := range headers {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return strings.ToLower(keys[i]) < strings.ToLower(keys[j])
|
||||
})
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
func canonicalQueryString(request requests.IRequest) string {
|
||||
if strings.ToUpper(request.GetMethod()) != "POST" {
|
||||
return request.BuildQueries()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func canonicalHeaders(request requests.IRequest) string {
|
||||
keys := sortedHeaderNames(request)
|
||||
headers := request.GetHeaders()
|
||||
ret := []string{}
|
||||
for _, k := range keys {
|
||||
ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k]))
|
||||
}
|
||||
|
||||
return strings.Join(ret, "\n") + "\n"
|
||||
}
|
||||
|
||||
func canonicalHeaderNames(request requests.IRequest) string {
|
||||
keys := sortedHeaderNames(request)
|
||||
ret := strings.Join(keys, ";")
|
||||
return strings.ToLower(ret)
|
||||
}
|
||||
|
||||
var SigningKeyCache sync.Map // map[string][]byte{}
|
||||
|
||||
func getSigningKey(secretKey, date, regionId, service string) string {
|
||||
joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "")
|
||||
cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey)))
|
||||
if v, ok := SigningKeyCache.Load(cacheKey); ok {
|
||||
return v.(string)
|
||||
}
|
||||
|
||||
ret := []byte("SDK" + secretKey)
|
||||
for _, k := range []string{date, regionId, service, "sdk_request"} {
|
||||
ret = signers.HmacSha256(k, ret)
|
||||
}
|
||||
|
||||
SigningKeyCache.Store(cacheKey, string(ret))
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) {
|
||||
auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{
|
||||
"Credential=" + accessKey + "/" + credentialScope,
|
||||
"SignedHeaders=" + canonicalHeaderNames(request),
|
||||
"Signature=" + signature,
|
||||
}, ", ")
|
||||
|
||||
request.AddHeaderParam("Authorization", auth)
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 signers // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers"
|
||||
Generated
Vendored
-55
@@ -1,55 +0,0 @@
|
||||
// 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 signers
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials"
|
||||
)
|
||||
|
||||
type AccessKeySigner struct {
|
||||
credential *credentials.AccessKeyCredential
|
||||
}
|
||||
|
||||
func (signer *AccessKeySigner) GetName() string {
|
||||
return "HmacSha256"
|
||||
}
|
||||
|
||||
func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) {
|
||||
return signer.credential.AccessKeyId, nil
|
||||
}
|
||||
|
||||
func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) {
|
||||
return signer.credential.AccessKeySecret, nil
|
||||
}
|
||||
|
||||
func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string {
|
||||
return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix)))
|
||||
}
|
||||
|
||||
func HmacSha256(data string, key []byte) []byte {
|
||||
mac := hmac.New(sha256.New, key)
|
||||
mac.Write([]byte(data))
|
||||
return mac.Sum(nil)
|
||||
}
|
||||
|
||||
func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner {
|
||||
return &AccessKeySigner{
|
||||
credential: credential,
|
||||
}
|
||||
}
|
||||
-232
@@ -1,232 +0,0 @@
|
||||
// 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 client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
cfg *SClientConfig
|
||||
// 标记初始化状态
|
||||
init bool
|
||||
|
||||
Credentials *modules.SCredentialManager
|
||||
Disks *modules.SDiskManager
|
||||
Domains *modules.SDomainManager
|
||||
Elasticcache *modules.SElasticcacheManager
|
||||
DcsAvailableZone *modules.SDcsAvailableZoneManager
|
||||
Flavors *modules.SFlavorManager
|
||||
Images *modules.SImageManager
|
||||
OpenStackImages *modules.SImageManager
|
||||
Interface *modules.SInterfaceManager
|
||||
Jobs *modules.SJobManager
|
||||
Orders *modules.SOrderManager
|
||||
Port *modules.SPortManager
|
||||
Projects *modules.SProjectManager
|
||||
Regions *modules.SRegionManager
|
||||
Servers *modules.SServerManager
|
||||
ServersV2 *modules.SServerManager
|
||||
NovaServers *modules.SServerManager
|
||||
Snapshots *modules.SSnapshotManager
|
||||
OsSnapshots *modules.SSnapshotManager
|
||||
Subnets *modules.SSubnetManager
|
||||
Users *modules.SUserManager
|
||||
Vpcs *modules.SVpcManager
|
||||
Zones *modules.SZoneManager
|
||||
VpcRoutes *modules.SVpcRouteManager
|
||||
SNatRules *modules.SNatSRuleManager
|
||||
DNatRules *modules.SNatDRuleManager
|
||||
NatGateways *modules.SNatGatewayManager
|
||||
VpcPeerings *modules.SVpcPeeringManager
|
||||
DBInstance *modules.SDBInstanceManager
|
||||
DBInstanceBackup *modules.SDBInstanceBackupManager
|
||||
DBInstanceFlavor *modules.SDBInstanceFlavorManager
|
||||
DBInstanceJob *modules.SDBInstanceJobManager
|
||||
Traces *modules.STraceManager
|
||||
CloudEye *modules.SCloudEyeManager
|
||||
EnterpriseProjects *modules.SEnterpriseProjectManager
|
||||
Roles *modules.SRoleManager
|
||||
Groups *modules.SGroupManager
|
||||
SAMLProviders *modules.SAMLProviderManager
|
||||
SAMLProviderMappings *modules.SAMLProviderMappingManager
|
||||
SfsTurbos *modules.SfsTurboManager
|
||||
RouteTables *modules.SRouteTableManager
|
||||
}
|
||||
|
||||
type SClientConfig struct {
|
||||
signer auth.Signer
|
||||
endpoint string // myhuaweicloud.com
|
||||
regionId string
|
||||
domainId string
|
||||
projectId string
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetSigner() auth.Signer {
|
||||
return self.signer
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetEndpoint() string {
|
||||
return self.endpoint
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetRegionId() string {
|
||||
return self.regionId
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetDomainId() string {
|
||||
return self.domainId
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetProjectId() string {
|
||||
return self.projectId
|
||||
}
|
||||
|
||||
func (self *SClientConfig) GetDebug() bool {
|
||||
return self.debug
|
||||
}
|
||||
|
||||
func (self *Client) SetHttpClient(httpClient *http.Client) {
|
||||
self.Credentials.SetHttpClient(httpClient)
|
||||
self.Servers.SetHttpClient(httpClient)
|
||||
self.ServersV2.SetHttpClient(httpClient)
|
||||
self.NovaServers.SetHttpClient(httpClient)
|
||||
self.Snapshots.SetHttpClient(httpClient)
|
||||
self.OsSnapshots.SetHttpClient(httpClient)
|
||||
self.Images.SetHttpClient(httpClient)
|
||||
self.OpenStackImages.SetHttpClient(httpClient)
|
||||
self.Projects.SetHttpClient(httpClient)
|
||||
self.Regions.SetHttpClient(httpClient)
|
||||
self.Zones.SetHttpClient(httpClient)
|
||||
self.Vpcs.SetHttpClient(httpClient)
|
||||
self.Elasticcache.SetHttpClient(httpClient)
|
||||
self.DcsAvailableZone.SetHttpClient(httpClient)
|
||||
self.Disks.SetHttpClient(httpClient)
|
||||
self.Domains.SetHttpClient(httpClient)
|
||||
self.Orders.SetHttpClient(httpClient)
|
||||
self.Subnets.SetHttpClient(httpClient)
|
||||
self.Users.SetHttpClient(httpClient)
|
||||
self.Interface.SetHttpClient(httpClient)
|
||||
self.Jobs.SetHttpClient(httpClient)
|
||||
self.Port.SetHttpClient(httpClient)
|
||||
self.Flavors.SetHttpClient(httpClient)
|
||||
self.VpcRoutes.SetHttpClient(httpClient)
|
||||
self.SNatRules.SetHttpClient(httpClient)
|
||||
self.DNatRules.SetHttpClient(httpClient)
|
||||
self.NatGateways.SetHttpClient(httpClient)
|
||||
self.DBInstance.SetHttpClient(httpClient)
|
||||
self.DBInstanceBackup.SetHttpClient(httpClient)
|
||||
self.DBInstanceFlavor.SetHttpClient(httpClient)
|
||||
self.DBInstanceJob.SetHttpClient(httpClient)
|
||||
self.Traces.SetHttpClient(httpClient)
|
||||
self.CloudEye.SetHttpClient(httpClient)
|
||||
self.EnterpriseProjects.SetHttpClient(httpClient)
|
||||
self.Roles.SetHttpClient(httpClient)
|
||||
self.Groups.SetHttpClient(httpClient)
|
||||
self.SAMLProviders.SetHttpClient(httpClient)
|
||||
self.SAMLProviderMappings.SetHttpClient(httpClient)
|
||||
self.SfsTurbos.SetHttpClient(httpClient)
|
||||
self.RouteTables.SetHttpClient(httpClient)
|
||||
}
|
||||
|
||||
func (self *Client) InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) error {
|
||||
// accessKey signer
|
||||
credential := &credentials.AccessKeyCredential{
|
||||
AccessKeyId: accessKey,
|
||||
AccessKeySecret: secretKey,
|
||||
}
|
||||
|
||||
// 从signer中初始化
|
||||
signer, err := auth.NewSignerWithCredential(credential)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.cfg = &SClientConfig{
|
||||
signer: signer,
|
||||
endpoint: endpoint,
|
||||
regionId: regionId,
|
||||
domainId: domainId,
|
||||
projectId: projectId,
|
||||
debug: debug,
|
||||
}
|
||||
|
||||
// 初始化 resource manager
|
||||
self.initManagers()
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *Client) initManagers() {
|
||||
if !self.init {
|
||||
self.Servers = modules.NewServerManager(self.cfg)
|
||||
self.ServersV2 = modules.NewServerV2Manager(self.cfg)
|
||||
self.NovaServers = modules.NewNovaServerManager(self.cfg)
|
||||
self.Snapshots = modules.NewSnapshotManager(self.cfg)
|
||||
self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg)
|
||||
self.Images = modules.NewImageManager(self.cfg)
|
||||
self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg)
|
||||
self.Projects = modules.NewProjectManager(self.cfg)
|
||||
self.Regions = modules.NewRegionManager(self.cfg)
|
||||
self.Zones = modules.NewZoneManager(self.cfg)
|
||||
self.Vpcs = modules.NewVpcManager(self.cfg)
|
||||
self.Elasticcache = modules.NewElasticcacheManager(self.cfg)
|
||||
self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg)
|
||||
self.Disks = modules.NewDiskManager(self.cfg)
|
||||
self.Domains = modules.NewDomainManager(self.cfg)
|
||||
self.Orders = modules.NewOrderManager(self.cfg)
|
||||
self.Subnets = modules.NewSubnetManager(self.cfg)
|
||||
self.Users = modules.NewUserManager(self.cfg)
|
||||
self.Interface = modules.NewInterfaceManager(self.cfg)
|
||||
self.Jobs = modules.NewJobManager(self.cfg)
|
||||
self.Credentials = modules.NewCredentialManager(self.cfg)
|
||||
self.Port = modules.NewPortManager(self.cfg)
|
||||
self.Flavors = modules.NewFlavorManager(self.cfg)
|
||||
self.VpcRoutes = modules.NewVpcRouteManager(self.cfg)
|
||||
self.SNatRules = modules.NewNatSManager(self.cfg)
|
||||
self.DNatRules = modules.NewNatDManager(self.cfg)
|
||||
self.NatGateways = modules.NewNatGatewayManager(self.cfg)
|
||||
self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg)
|
||||
self.DBInstance = modules.NewDBInstanceManager(self.cfg)
|
||||
self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg)
|
||||
self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg)
|
||||
self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg)
|
||||
self.Traces = modules.NewTraceManager(self.cfg)
|
||||
self.CloudEye = modules.NewCloudEyeManager(self.cfg)
|
||||
self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg)
|
||||
self.Roles = modules.NewRoleManager(self.cfg)
|
||||
self.Groups = modules.NewGroupManager(self.cfg)
|
||||
self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg)
|
||||
self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg)
|
||||
self.SfsTurbos = modules.NewSfsTurboManager(self.cfg)
|
||||
self.RouteTables = modules.NewRouteTableManager(self.cfg)
|
||||
}
|
||||
|
||||
self.init = true
|
||||
}
|
||||
|
||||
func NewClientWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) {
|
||||
c := &Client{}
|
||||
err := c.InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey, debug)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func NewPublicCloudClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) {
|
||||
return NewClientWithAccessKey("myhuaweicloud.com", regionId, domainId, projectId, accessKey, secretKey, debug)
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 client // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client"
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 manager // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
// 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 manager
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type IManagerContext interface {
|
||||
GetPath() string
|
||||
}
|
||||
|
||||
type IBaseManager interface {
|
||||
Version() string
|
||||
KeyString() string
|
||||
ServiceType() string
|
||||
GetColumns() []string
|
||||
}
|
||||
|
||||
type IManager interface {
|
||||
IBaseManager
|
||||
// 获取资源列表 GET <base_url>/cloudservers/?<queries>
|
||||
List(queries map[string]string) (*responses.ListResult, error)
|
||||
// 根据上文获取资源列表 GET <base_url>/cloudservers/<cloudserver_id>/nics?<queries>
|
||||
ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error)
|
||||
ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error)
|
||||
|
||||
// 查询单个资源 GET <base_url>/cloudservers/<cloudserver_id>?<queries>
|
||||
Get(id string, queries map[string]string) (jsonutils.JSONObject, error)
|
||||
// 根据上文获取资源查询单个资源 GET <base_url>/cloudservers/<cloudserver_id>/nics/<nic_id>?<queries>
|
||||
GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error)
|
||||
|
||||
// 创建单个资源 POST <base_url>/cloudservers
|
||||
Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 根据上文创建单个资源 POST <base_url>/cloudservers/<cloudserver_id>/nics/<nic_id>
|
||||
CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 异步任务创建 POST <base_url>/cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象
|
||||
AsyncCreate(params jsonutils.JSONObject) (string, error)
|
||||
|
||||
// 更新单个资源 PUT <base_url>/cloudservers/<cloudserver_id>
|
||||
Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 根据上文更新单个资源 PUT <base_url>/cloudservers/<cloudserver_id>/nics/<nic_id>
|
||||
UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password
|
||||
UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error)
|
||||
|
||||
// 删除单个资源 DELETE <base_url>/cloudservers/<cloudserver_id>
|
||||
Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 根据上文删除单个资源 DELETE <base_url>/cloudservers/<cloudserver_id>/nics/<nic_id>
|
||||
DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 根据上文和spec删除单个资源
|
||||
DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error)
|
||||
// 批量执行操作 POST <base_url>/cloudservers/<action>
|
||||
// BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
// 执行操作 POST <base_url>/cloudservers/<cloudserver_id>/<action>
|
||||
PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
}
|
||||
|
||||
type IManagerConfig interface {
|
||||
GetSigner() auth.Signer
|
||||
GetEndpoint() string
|
||||
GetRegionId() string
|
||||
GetDomainId() string
|
||||
GetProjectId() string
|
||||
GetDebug() bool
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 modules // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type IRequestHook interface {
|
||||
Process(r requests.IRequest)
|
||||
}
|
||||
|
||||
type SBaseManager struct {
|
||||
cfg manager.IManagerConfig
|
||||
httpClient *http.Client
|
||||
requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。
|
||||
|
||||
columns []string
|
||||
debug bool
|
||||
}
|
||||
|
||||
type sThrottlingThreshold struct {
|
||||
locked bool
|
||||
lockTime time.Time
|
||||
}
|
||||
|
||||
func (t *sThrottlingThreshold) CheckingLock() {
|
||||
if !t.locked {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if t.lockTime.Sub(time.Now()).Seconds() < 0 {
|
||||
return
|
||||
}
|
||||
log.Debugf("throttling threshold has been reached. release at %s", t.lockTime)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *sThrottlingThreshold) Lock() {
|
||||
// 锁定至少15秒
|
||||
t.locked = true
|
||||
t.lockTime = time.Now().Add(15 * time.Second)
|
||||
}
|
||||
|
||||
var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}}
|
||||
|
||||
func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager {
|
||||
return SBaseManager{
|
||||
cfg: cfg,
|
||||
httpClient: httputils.GetDefaultClient(),
|
||||
debug: cfg.GetDebug(),
|
||||
requestHook: requesthk,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBaseManager(cfg manager.IManagerConfig) SBaseManager {
|
||||
return NewBaseManager2(cfg, nil)
|
||||
}
|
||||
|
||||
func (self *SBaseManager) GetEndpoint() string {
|
||||
return self.cfg.GetEndpoint()
|
||||
}
|
||||
|
||||
func (self *SBaseManager) GetColumns() []string {
|
||||
return self.columns
|
||||
}
|
||||
|
||||
func (self *SBaseManager) SetHttpClient(httpClient *http.Client) {
|
||||
self.httpClient = httpClient
|
||||
}
|
||||
|
||||
func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) {
|
||||
_, body, err := self.jsonRequest(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if body == nil {
|
||||
log.Warningf("empty response")
|
||||
return &responses.ListResult{}, nil
|
||||
}
|
||||
|
||||
rets, err := body.GetArray(responseKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "body.GetArray %s", responseKey)
|
||||
}
|
||||
total, _ := body.Int("count")
|
||||
// if err != nil {
|
||||
// total = int64(len(rets))
|
||||
//}
|
||||
|
||||
//if total == 0 {
|
||||
// total = int64(len(rets))
|
||||
//}
|
||||
|
||||
limit := 0
|
||||
if v, exists := request.GetQueryParams()["limit"]; exists {
|
||||
limit, _ = strconv.Atoi(v)
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if v, exists := request.GetQueryParams()["offset"]; exists {
|
||||
offset, _ = strconv.Atoi(v)
|
||||
}
|
||||
|
||||
return &responses.ListResult{
|
||||
Data: rets,
|
||||
Total: int(total),
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) {
|
||||
_, resp, e := self.jsonRequest(request)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if resp == nil { // no reslt
|
||||
return jsonutils.NewDict(), nil
|
||||
}
|
||||
|
||||
if len(responseKey) == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
ret, e := resp.Get(responseKey)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) {
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
type HuaweiClientError struct {
|
||||
Code int
|
||||
Errorcode []string
|
||||
err error
|
||||
Details string
|
||||
ErrorCode string
|
||||
}
|
||||
|
||||
func (ce *HuaweiClientError) Error() string {
|
||||
return jsonutils.Marshal(ce).String()
|
||||
}
|
||||
|
||||
func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, status string, body jsonutils.JSONObject) error {
|
||||
if body != nil {
|
||||
body.Unmarshal(ce)
|
||||
}
|
||||
if ce.Code == 0 {
|
||||
ce.Code = statusCode
|
||||
}
|
||||
if len(ce.Details) == 0 && body != nil {
|
||||
ce.Details = body.String()
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) {
|
||||
ThrottlingLock.CheckingLock()
|
||||
ctx := context.Background()
|
||||
// hook request
|
||||
if self.requestHook != nil {
|
||||
self.requestHook.Process(request)
|
||||
}
|
||||
// 拼接、编译、签名 requests here。
|
||||
err := self.buildRequestWithSigner(request, self.cfg.GetSigner())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
header := http.Header{}
|
||||
for k, v := range request.GetHeaders() {
|
||||
header.Set(k, v)
|
||||
}
|
||||
|
||||
var jsonBody jsonutils.JSONObject
|
||||
content := request.GetContent()
|
||||
if len(content) > 0 {
|
||||
jsonBody, err = jsonutils.Parse(content)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("not a json body")
|
||||
}
|
||||
}
|
||||
|
||||
client := httputils.NewJsonClient(self.httpClient)
|
||||
req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody)
|
||||
req.SetHeader(header)
|
||||
resp := &HuaweiClientError{}
|
||||
const MAX_RETRY = 3
|
||||
retry := MAX_RETRY
|
||||
for {
|
||||
h, b, e := client.Send(ctx, req, resp, self.debug)
|
||||
if e == nil {
|
||||
return h, b, nil
|
||||
}
|
||||
|
||||
log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e)
|
||||
|
||||
switch err := e.(type) {
|
||||
case *HuaweiClientError:
|
||||
if err.ErrorCode == "APIGW.0301" {
|
||||
return h, b, errors.Wrapf(cloudprovider.ErrInvalidAccessKey, e.Error())
|
||||
} else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" {
|
||||
retry -= 1
|
||||
time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry))
|
||||
} else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") ||
|
||||
strings.Contains(err.Error(), "Not Found") ||
|
||||
strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" {
|
||||
return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
|
||||
} else if err.Code == 429 && retry > 0 {
|
||||
// 当前请求过多。
|
||||
ThrottlingLock.Lock()
|
||||
retry -= 1
|
||||
time.Sleep(15 * time.Second)
|
||||
} else {
|
||||
return h, b, e
|
||||
}
|
||||
default:
|
||||
return h, b, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) {
|
||||
ctx := context.Background()
|
||||
// 拼接、编译requests here。
|
||||
header := http.Header{}
|
||||
for k, v := range request.GetHeaders() {
|
||||
header.Set(k, v)
|
||||
}
|
||||
return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug)
|
||||
}
|
||||
|
||||
func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error {
|
||||
return auth.Sign(request, signer)
|
||||
}
|
||||
Generated
Vendored
-298
@@ -1,298 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type ServiceNameType string
|
||||
|
||||
const HuaWeiDefaultDomain = "myhuaweicloud.com"
|
||||
|
||||
const (
|
||||
ServiceNameECS ServiceNameType = "ecs" // 弹性云服务
|
||||
ServiceNameCCE ServiceNameType = "cce" // 云容器服务
|
||||
ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务
|
||||
ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务
|
||||
ServiceNameIMS ServiceNameType = "ims" // 镜像服务
|
||||
ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务
|
||||
ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI
|
||||
ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器
|
||||
ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS
|
||||
ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS
|
||||
ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS
|
||||
ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC
|
||||
ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB
|
||||
ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力
|
||||
ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT
|
||||
ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务
|
||||
ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS
|
||||
ServiceNameCTS ServiceNameType = "cts" // 云审计服务
|
||||
ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye
|
||||
ServiceNameEPS ServiceNameType = "eps" // 企业项目
|
||||
|
||||
ServiceNameModelarts ServiceNameType = "modelarts" // AI ModelArts
|
||||
|
||||
ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统
|
||||
)
|
||||
|
||||
type SManagerContext struct {
|
||||
InstanceManager manager.IManager
|
||||
InstanceId string
|
||||
}
|
||||
|
||||
func (self *SManagerContext) GetPath() string {
|
||||
path := self.InstanceManager.KeyString()
|
||||
if len(self.InstanceId) > 0 {
|
||||
path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId))
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
type SResourceManager struct {
|
||||
SBaseManager
|
||||
ctx manager.IManagerContext
|
||||
ServiceName ServiceNameType // 服务名称: ecs
|
||||
Region string // 区域: cn-north-1
|
||||
DomainId string
|
||||
ProjectId string // 项目ID: uuid
|
||||
version string // api 版本号
|
||||
Keyword string // 资源名称单数。构建URL时使用
|
||||
KeywordPlural string // 资源名称复数形式。构建URL时使用
|
||||
|
||||
ResourceKeyword string // 资源名称。url中使用
|
||||
}
|
||||
|
||||
func getContent(params jsonutils.JSONObject) string {
|
||||
if params == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return params.String()
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Version() string {
|
||||
return self.version
|
||||
}
|
||||
|
||||
func (self *SResourceManager) KeyString() string {
|
||||
return self.ResourceKeyword
|
||||
}
|
||||
|
||||
func (self *SResourceManager) ServiceType() string {
|
||||
return string(self.ServiceName)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) GetColumns() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (self *SResourceManager) SetDomainId(domainId string) {
|
||||
self.DomainId = domainId
|
||||
}
|
||||
|
||||
func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string {
|
||||
segs := []string{}
|
||||
if ctx != nil {
|
||||
segs = append(segs, ctx.GetPath())
|
||||
}
|
||||
|
||||
segs = append(segs, self.KeyString())
|
||||
|
||||
if len(rid) > 0 {
|
||||
segs = append(segs, url.PathEscape(rid))
|
||||
}
|
||||
|
||||
if len(spec) > 0 {
|
||||
specSegs := strings.Split(spec, "/")
|
||||
for _, specSeg := range specSegs {
|
||||
segs = append(segs, url.PathEscape(specSeg))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(segs, "/")
|
||||
}
|
||||
|
||||
func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest {
|
||||
resourcePath := self.getReourcePath(ctx, rid, spec)
|
||||
return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) {
|
||||
return self.ListInContext(self.ctx, queries)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) {
|
||||
return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) {
|
||||
request := self.newRequest("GET", "", spec, ctx)
|
||||
for k, v := range queries {
|
||||
request.AddQueryParam(k, v)
|
||||
}
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._list(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) {
|
||||
return self.GetInContext(self.ctx, id, queries)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) {
|
||||
return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("GET", id, spec, ctx)
|
||||
for k, v := range queries {
|
||||
request.AddQueryParam(k, v)
|
||||
}
|
||||
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._get(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.CreateInContext(self.ctx, params)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.CreateInContextWithSpec(ctx, "", params, self.Keyword)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("POST", "", spec, ctx)
|
||||
request.SetContent([]byte(params.String()))
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) {
|
||||
return "", fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.UpdateInContext(self.ctx, id, params)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("PUT", id, spec, ctx)
|
||||
content := getContent(params)
|
||||
if len(content) > 0 {
|
||||
request.SetContent([]byte(content))
|
||||
}
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.PatchInContext(self.ctx, id, params)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("PATCH", id, spec, ctx)
|
||||
content := getContent(params)
|
||||
if len(content) > 0 {
|
||||
request.SetContent([]byte(content))
|
||||
}
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.DeleteInContext(self.ctx, id, params)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "")
|
||||
}
|
||||
|
||||
func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("DELETE", id, spec, ctx)
|
||||
for k, v := range queries {
|
||||
request.AddQueryParam(k, v)
|
||||
}
|
||||
|
||||
content := getContent(params)
|
||||
if len(content) > 0 {
|
||||
request.SetContent([]byte(content))
|
||||
}
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.PerformAction2(action, id, params, self.Keyword)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("POST", id, action, nil)
|
||||
request.SetContent([]byte(getContent(params)))
|
||||
if len(self.DomainId) > 0 {
|
||||
request.AddHeaderParam("X-Domain-Id", self.DomainId)
|
||||
}
|
||||
|
||||
return self._do(request, responseKey)
|
||||
}
|
||||
|
||||
func (self *SResourceManager) SetVersion(v string) {
|
||||
self.version = v
|
||||
}
|
||||
|
||||
func (self *SResourceManager) versionedURL(path string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// todo: Init a manager with environment variables
|
||||
func (self *SResourceManager) Init() error {
|
||||
return nil
|
||||
}
|
||||
-152
@@ -1,152 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
)
|
||||
|
||||
type SCloudEyeManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager {
|
||||
return &SCloudEyeManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameCES,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "V1.0",
|
||||
Keyword: "",
|
||||
KeywordPlural: "metrics",
|
||||
ResourceKeyword: "metrics",
|
||||
}}
|
||||
}
|
||||
|
||||
type SMetricDimension struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type SDatapoint struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Max float64 `json:"max,omitzero"`
|
||||
Min float64 `json:"min,omitzero"`
|
||||
Average float64 `json:"average,omitzero"`
|
||||
Sum float64 `json:"sum,omitzero"`
|
||||
Variance float64 `json:"variance,omitzero"`
|
||||
}
|
||||
|
||||
type SMetricData struct {
|
||||
SMetricMeta
|
||||
|
||||
Datapoints []SDatapoint
|
||||
}
|
||||
|
||||
type SMetricMeta struct {
|
||||
SMetric
|
||||
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
|
||||
type SMetric struct {
|
||||
MetricName string `json:"metric_name"`
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
Dimensions []SMetricDimension `json:"dimensions"`
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) {
|
||||
metrics := make([]SMetricMeta, 0)
|
||||
next := ""
|
||||
for {
|
||||
marker, data, err := ces.listMetricsInternal(next)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ces.listMetricsInternal")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
break
|
||||
}
|
||||
metrics = append(metrics, data...)
|
||||
next = marker
|
||||
}
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) {
|
||||
request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword)
|
||||
request.AddQueryParam("limit", "1000")
|
||||
if len(start) > 0 {
|
||||
request.AddQueryParam("start", start)
|
||||
}
|
||||
_, resp, err := ces.jsonRequest(request)
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "ces.jsonRequest")
|
||||
}
|
||||
marker, _ := resp.GetString("meta_data", "marker")
|
||||
metrics := make([]SMetricMeta, 0)
|
||||
err = resp.Unmarshal(&metrics, "metrics")
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "resp.Unmarshal metrics")
|
||||
}
|
||||
return marker, metrics, nil
|
||||
}
|
||||
|
||||
type SBatchQueryMetricDataInput struct {
|
||||
Metrics []SMetric `json:"metrics"`
|
||||
|
||||
From int64 `json:"from"`
|
||||
To int64 `json:"to"`
|
||||
Period string `json:"period"`
|
||||
Filter string `json:"filter"`
|
||||
}
|
||||
|
||||
func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) {
|
||||
if len(metrics) > 10 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrTooLarge, "request more than 10 metrics")
|
||||
}
|
||||
metricReq := make([]SMetric, len(metrics))
|
||||
for i := range metrics {
|
||||
metricReq[i] = metrics[i].SMetric
|
||||
}
|
||||
request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data")
|
||||
input := SBatchQueryMetricDataInput{
|
||||
Metrics: metricReq,
|
||||
From: since.Unix() * 1000,
|
||||
To: until.Unix() * 1000,
|
||||
Period: "1",
|
||||
Filter: "average",
|
||||
}
|
||||
body := jsonutils.Marshal(&input).String()
|
||||
request.SetContent([]byte(body))
|
||||
_, resp, err := ces.jsonRequest(request)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ces.jsonRequest")
|
||||
}
|
||||
//log.Debugf("%s", resp)
|
||||
result := make([]SMetricData, 0)
|
||||
err = resp.Unmarshal(&result, "metrics")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SCredentialManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager {
|
||||
return &SCredentialManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3.0",
|
||||
Keyword: "credential",
|
||||
KeywordPlural: "credentials",
|
||||
|
||||
ResourceKeyword: "OS-CREDENTIAL/credentials",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-103
@@ -1,103 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SDBInstanceManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager {
|
||||
return &SDBInstanceManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameRDS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v3",
|
||||
Keyword: "",
|
||||
KeywordPlural: "instances",
|
||||
|
||||
ResourceKeyword: "instances",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) {
|
||||
if len(id) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instances, err := resp.GetArray("instances")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(instances) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
} else if len(instances) == 1 {
|
||||
return instances[0], nil
|
||||
}
|
||||
return nil, cloudprovider.ErrDuplicateId
|
||||
}
|
||||
|
||||
func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) {
|
||||
id, _ := queries["instance_id"]
|
||||
if len(id) == 0 {
|
||||
return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id")
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters")
|
||||
}
|
||||
|
||||
func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) {
|
||||
id, _ := queries["instance_id"]
|
||||
if len(id) == 0 {
|
||||
return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id")
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases")
|
||||
}
|
||||
|
||||
func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) {
|
||||
id, _ := queries["instance_id"]
|
||||
if len(id) == 0 {
|
||||
return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id")
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users")
|
||||
}
|
||||
|
||||
func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) {
|
||||
id, _ := queries["instance_id"]
|
||||
if len(id) == 0 {
|
||||
return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id")
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases")
|
||||
}
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SDBInstanceBackupManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager {
|
||||
return &SDBInstanceBackupManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameRDS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v3",
|
||||
Keyword: "backup",
|
||||
KeywordPlural: "backups",
|
||||
|
||||
ResourceKeyword: "backups",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SDBInstanceFlavorManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager {
|
||||
return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameRDS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v3",
|
||||
Keyword: "flavor",
|
||||
KeywordPlural: "flavor",
|
||||
|
||||
ResourceKeyword: "flavors",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-43
@@ -1,43 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SDBInstanceJobManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager {
|
||||
return &SDBInstanceJobManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameRDS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v3",
|
||||
Keyword: "",
|
||||
KeywordPlural: "",
|
||||
|
||||
ResourceKeyword: "jobs",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) {
|
||||
return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job")
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SDiskManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager {
|
||||
return &SDiskManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameEVS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "volume",
|
||||
KeywordPlural: "volumes",
|
||||
|
||||
ResourceKeyword: "cloudvolumes",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural)
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/evs_04_2003.html
|
||||
func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) {
|
||||
origin_version := self.version
|
||||
self.version = "v2.1"
|
||||
defer func() { self.version = origin_version }()
|
||||
|
||||
ret, err := self.CreateInContextWithSpec(nil, "", params, "")
|
||||
if err != nil {
|
||||
log.Debugf("AsyncCreate %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Debugf("AsyncCreate result %s", ret.String())
|
||||
// 按需机器
|
||||
jobId, err := ret.GetString("job_id")
|
||||
if err == nil {
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
// 包年包月机器
|
||||
return ret.GetString("order_id")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/evs_04_2003.html
|
||||
func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) {
|
||||
originKeyword := self.ResourceKeyword
|
||||
self.ResourceKeyword = ""
|
||||
defer func() { self.ResourceKeyword = originKeyword }()
|
||||
return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types")
|
||||
}
|
||||
Generated
Vendored
-41
@@ -1,41 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SNatDRuleManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager {
|
||||
man := &SNatDRuleManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameNAT,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2.0",
|
||||
Keyword: "dnat_rule",
|
||||
KeywordPlural: "dnat_rules",
|
||||
|
||||
ResourceKeyword: "dnat_rules",
|
||||
}}
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
man.requestHook = &sProjectHook{cfg.GetProjectId()}
|
||||
}
|
||||
return man
|
||||
}
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SDomainManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager {
|
||||
m := &SDomainManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3/auth",
|
||||
Keyword: "domain",
|
||||
KeywordPlural: "domains",
|
||||
|
||||
ResourceKeyword: "domains",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
|
||||
func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error {
|
||||
if len(domainId) == 0 {
|
||||
return fmt.Errorf("missing domainId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return fmt.Errorf("missing groupId")
|
||||
}
|
||||
if len(roleId) == 0 {
|
||||
return fmt.Errorf("missing roleId")
|
||||
}
|
||||
manager.SetVersion("v3")
|
||||
defer manager.SetVersion("v3/auth")
|
||||
res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId)
|
||||
_, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "")
|
||||
if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) {
|
||||
if len(domainId) == 0 {
|
||||
return nil, fmt.Errorf("missing domainId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return nil, fmt.Errorf("missing groupId")
|
||||
}
|
||||
manager.SetVersion("v3")
|
||||
defer manager.SetVersion("v3/auth")
|
||||
res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId)
|
||||
return manager.ListInContextWithSpec(nil, res, nil, "roles")
|
||||
}
|
||||
|
||||
func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error {
|
||||
if len(domainId) == 0 {
|
||||
return fmt.Errorf("missing domainId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return fmt.Errorf("missing groupId")
|
||||
}
|
||||
if len(roleId) == 0 {
|
||||
return fmt.Errorf("missing roleId")
|
||||
}
|
||||
manager.SetVersion("v3")
|
||||
defer manager.SetVersion("v3/auth")
|
||||
res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId)
|
||||
_, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "")
|
||||
return err
|
||||
}
|
||||
Generated
Vendored
-118
@@ -1,118 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SElasticcacheManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type SDcsAvailableZoneManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager {
|
||||
return &SElasticcacheManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameDCS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1.0",
|
||||
Keyword: "",
|
||||
KeywordPlural: "instances",
|
||||
|
||||
ResourceKeyword: "instances",
|
||||
}}
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html
|
||||
func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) {
|
||||
var spec string
|
||||
if id, _ := queries["instance_id"]; len(id) == 0 {
|
||||
return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id")
|
||||
} else {
|
||||
spec = fmt.Sprintf("%s/backups", id)
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html
|
||||
func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) {
|
||||
var spec string
|
||||
if id, _ := queries["instance_id"]; len(id) == 0 {
|
||||
return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id")
|
||||
} else {
|
||||
spec = fmt.Sprintf("%s/configs", id)
|
||||
}
|
||||
|
||||
delete(queries, "instance_id")
|
||||
return self.ListInContextWithSpec(nil, spec, queries, "redis_config")
|
||||
}
|
||||
|
||||
func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances")
|
||||
params.Add(jsonutils.NewString("restart"), "action")
|
||||
return self.UpdateInContextWithSpec(nil, "", "status", params, "")
|
||||
}
|
||||
|
||||
// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。
|
||||
func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances")
|
||||
params.Add(jsonutils.NewString("flush"), "action")
|
||||
return self.UpdateInContextWithSpec(nil, "", "status", params, "")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html
|
||||
func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id")
|
||||
|
||||
return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html
|
||||
func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("new_capacity", jsonutils.NewInt(newCapacity))
|
||||
params.Set("spec_code", jsonutils.NewString(specCode))
|
||||
|
||||
return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "")
|
||||
}
|
||||
|
||||
func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager {
|
||||
return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameDCS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v1.0",
|
||||
Keyword: "available_zone",
|
||||
KeywordPlural: "available_zones",
|
||||
|
||||
ResourceKeyword: "availableZones",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SEnterpriseProjectManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager {
|
||||
m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameEPS,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v1.0",
|
||||
Keyword: "enterprise_project",
|
||||
KeywordPlural: "enterprise_projects",
|
||||
|
||||
ResourceKeyword: "enterprise-projects",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SFlavorManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager {
|
||||
return &SFlavorManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "flavor",
|
||||
KeywordPlural: "flavors",
|
||||
|
||||
ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。
|
||||
}}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SGroupManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager {
|
||||
m := &SGroupManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3",
|
||||
Keyword: "group",
|
||||
KeywordPlural: "groups",
|
||||
|
||||
ResourceKeyword: "groups",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
)
|
||||
|
||||
type SImageManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type imageProject struct {
|
||||
projectId string
|
||||
}
|
||||
|
||||
// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊)
|
||||
// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID
|
||||
func (self *imageProject) Process(request requests.IRequest) {
|
||||
request.AddHeaderParam("X-Project-Id", self.projectId)
|
||||
}
|
||||
|
||||
func NewImageManager(cfg manager.IManagerConfig) *SImageManager {
|
||||
var requestHook imageProject
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
requestHook = imageProject{projectId: cfg.GetProjectId()}
|
||||
}
|
||||
|
||||
return &SImageManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager2(cfg, &requestHook),
|
||||
ServiceName: ServiceNameIMS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2",
|
||||
Keyword: "image",
|
||||
KeywordPlural: "images",
|
||||
|
||||
ResourceKeyword: "cloudimages",
|
||||
}}
|
||||
}
|
||||
|
||||
//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html
|
||||
func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) {
|
||||
if querys == nil {
|
||||
querys = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
querys["id"] = id
|
||||
// 这里默认使用private
|
||||
// if t, exists := querys["__imagetype"]; !exists || len(t) == 0 {
|
||||
// querys["__imagetype"] = "private"
|
||||
// }
|
||||
|
||||
ret, err := self.ListInContext(nil, querys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ret.Data == nil || len(ret.Data) == 0 {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "image %s not found", id)
|
||||
}
|
||||
|
||||
return ret.Data[0], nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html
|
||||
// 删除image只能用这个manager
|
||||
func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager {
|
||||
var requestHook imageProject
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
requestHook = imageProject{projectId: cfg.GetProjectId()}
|
||||
}
|
||||
|
||||
return &SImageManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager2(cfg, &requestHook),
|
||||
ServiceName: ServiceNameIMS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2",
|
||||
Keyword: "image",
|
||||
KeywordPlural: "images",
|
||||
|
||||
ResourceKeyword: "images",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-38
@@ -1,38 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SInterfaceManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
// 不建议使用
|
||||
func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager {
|
||||
return &SInterfaceManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "interfaceAttachment",
|
||||
KeywordPlural: "interfaceAttachments",
|
||||
|
||||
ResourceKeyword: "os-interface",
|
||||
}}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SJobManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewJobManager(cfg manager.IManagerConfig) *SJobManager {
|
||||
return &SJobManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: "",
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "",
|
||||
KeywordPlural: "",
|
||||
|
||||
ResourceKeyword: "jobs",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) {
|
||||
processedQuery, err := self.processQueryParam(querys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return self.GetInContext(nil, id, processedQuery)
|
||||
}
|
||||
|
||||
func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
processedQuery, err := self.processQueryParam(querys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.ListInContext(nil, processedQuery)
|
||||
}
|
||||
|
||||
// 兼容查询不同ServiceName服务的Job做的特殊处理。
|
||||
func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) {
|
||||
service_type, exists := querys["service_type"]
|
||||
if !exists {
|
||||
return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam")
|
||||
}
|
||||
|
||||
self.ServiceName = ServiceNameType(service_type)
|
||||
delete(querys, "service_type")
|
||||
return querys, nil
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SAMLProviderMappingManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager {
|
||||
m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3/OS-FEDERATION",
|
||||
Keyword: "mapping",
|
||||
KeywordPlural: "mappings",
|
||||
|
||||
ResourceKeyword: "mappings",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-50
@@ -1,50 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
)
|
||||
|
||||
type SNatGatewayManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type sProjectHook struct {
|
||||
projectId string
|
||||
}
|
||||
|
||||
func (self *sProjectHook) Process(request requests.IRequest) {
|
||||
request.AddHeaderParam("X-Project-Id", self.projectId)
|
||||
}
|
||||
|
||||
func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager {
|
||||
man := &SNatGatewayManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameNAT,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2.0",
|
||||
Keyword: "nat_gateway",
|
||||
KeywordPlural: "nat_gateways",
|
||||
|
||||
ResourceKeyword: "nat_gateways",
|
||||
}}
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
man.requestHook = &sProjectHook{cfg.GetProjectId()}
|
||||
}
|
||||
return man
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
// domian 客户账号ID https://support.huaweicloud.com/oce_faq/zh-cn_topic_0113714840.html
|
||||
type SOrderManager struct {
|
||||
orderCtx manager.IManagerContext
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type orderCtx struct {
|
||||
domainId string
|
||||
}
|
||||
|
||||
// {domain_id}/common/
|
||||
// 这个manager非常特殊。url hardcode
|
||||
func (self *orderCtx) GetPath() string {
|
||||
return fmt.Sprintf("%s/common", self.domainId)
|
||||
}
|
||||
|
||||
// 客户运营能力API的Endpoint为“bss.cn-north-1.myhuaweicloud.com”。该Endpoint为全局Endpoint,中国站所有区域均可使用。
|
||||
// https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html
|
||||
func NewOrderManager(cfg manager.IManagerConfig) *SOrderManager {
|
||||
return &SOrderManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameBSS,
|
||||
Region: "cn-north-1",
|
||||
ProjectId: "",
|
||||
version: "v1.0",
|
||||
Keyword: "",
|
||||
KeywordPlural: "",
|
||||
|
||||
ResourceKeyword: "order-mgr",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SOrderManager) SetDomainId(domainId string) error {
|
||||
if len(domainId) == 0 {
|
||||
return fmt.Errorf("SetDomainId domain id should not be emtpy")
|
||||
}
|
||||
|
||||
self.orderCtx = &orderCtx{domainId: domainId}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查询客户包周期资源列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html
|
||||
func (self *SOrderManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
return nil, fmt.Errorf("Not Suppport List Order")
|
||||
}
|
||||
|
||||
// 查询订单的资源开通详情 https://support.huaweicloud.com/api-oce/api_order_00001.html
|
||||
func (self *SOrderManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) {
|
||||
if self.orderCtx == nil {
|
||||
return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.")
|
||||
}
|
||||
|
||||
// !!!特殊调用
|
||||
return self.GetInContextWithSpec(self.orderCtx, "orders-resource", id, querys, "")
|
||||
}
|
||||
|
||||
func (self *SOrderManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
request := self.newRequest("POST", id, action, self.orderCtx)
|
||||
request.SetContent([]byte(getContent(params)))
|
||||
|
||||
return self._do(request, "")
|
||||
}
|
||||
|
||||
func (self *SOrderManager) GetPeriodResourceList(querys map[string]string) (*responses.ListResult, error) {
|
||||
if self.orderCtx == nil {
|
||||
return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.")
|
||||
}
|
||||
|
||||
return self.ListInContextWithSpec(self.orderCtx, "resources/detail", querys, "data")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0082522029.html
|
||||
func (self *SOrderManager) RenewPeriodResource(params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if self.orderCtx == nil {
|
||||
return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.")
|
||||
}
|
||||
|
||||
return self.CreateInContextWithSpec(self.orderCtx, "resources/renew", params, "order_ids")
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
)
|
||||
|
||||
type SPortManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
type portProject struct {
|
||||
projectId string
|
||||
}
|
||||
|
||||
// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊)
|
||||
// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID
|
||||
func (self *portProject) Process(request requests.IRequest) {
|
||||
request.AddHeaderParam("X-Project-Id", self.projectId)
|
||||
}
|
||||
|
||||
func NewPortManager(cfg manager.IManagerConfig) *SPortManager {
|
||||
var requestHook portProject
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
requestHook = portProject{projectId: cfg.GetProjectId()}
|
||||
}
|
||||
|
||||
return &SPortManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager2(cfg, &requestHook),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "port",
|
||||
KeywordPlural: "ports",
|
||||
|
||||
ResourceKeyword: "ports",
|
||||
}}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SProjectManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager {
|
||||
m := &SProjectManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3",
|
||||
Keyword: "project",
|
||||
KeywordPlural: "projects",
|
||||
|
||||
ResourceKeyword: "projects",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
|
||||
func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) {
|
||||
if len(projectId) == 0 {
|
||||
return nil, fmt.Errorf("missing projectId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return nil, fmt.Errorf("missing groupId")
|
||||
}
|
||||
res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId)
|
||||
return manager.ListInContextWithSpec(nil, res, nil, "roles")
|
||||
}
|
||||
|
||||
func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error {
|
||||
if len(projectId) == 0 {
|
||||
return fmt.Errorf("missing projectId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return fmt.Errorf("missing groupId")
|
||||
}
|
||||
if len(roleId) == 0 {
|
||||
return fmt.Errorf("missing roleId")
|
||||
}
|
||||
res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId)
|
||||
_, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "")
|
||||
if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error {
|
||||
if len(projectId) == 0 {
|
||||
return fmt.Errorf("missing projectId")
|
||||
}
|
||||
if len(groupId) == 0 {
|
||||
return fmt.Errorf("missing groupId")
|
||||
}
|
||||
if len(roleId) == 0 {
|
||||
return fmt.Errorf("missing roleId")
|
||||
}
|
||||
res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId)
|
||||
_, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "")
|
||||
return err
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SRegionManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager {
|
||||
return &SRegionManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3",
|
||||
Keyword: "region",
|
||||
KeywordPlural: "regions",
|
||||
|
||||
ResourceKeyword: "regions",
|
||||
}}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SRoleManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager {
|
||||
m := &SRoleManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3",
|
||||
Keyword: "role",
|
||||
KeywordPlural: "roles",
|
||||
|
||||
ResourceKeyword: "roles",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SRouteTableManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewRouteTableManager(cfg manager.IManagerConfig) *SRouteTableManager {
|
||||
return &SRouteTableManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "routetable",
|
||||
KeywordPlural: "routetables",
|
||||
|
||||
ResourceKeyword: "routetables",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SAMLProviderManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager {
|
||||
m := &SAMLProviderManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3/OS-FEDERATION",
|
||||
Keyword: "identity_provider",
|
||||
KeywordPlural: "identity_providers",
|
||||
|
||||
ResourceKeyword: "identity_providers",
|
||||
}}
|
||||
m.SetDomainId(cfg.GetDomainId())
|
||||
return m
|
||||
}
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SServerManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html
|
||||
// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html
|
||||
func NewServerManager(cfg manager.IManagerConfig) *SServerManager {
|
||||
return &SServerManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "server",
|
||||
KeywordPlural: "servers",
|
||||
|
||||
ResourceKeyword: "cloudservers",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
if offset, exists := querys["offset"]; !exists {
|
||||
// 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。
|
||||
// 另外部分接口使用pager分页 或者 maker分页
|
||||
querys["offset"] = "1"
|
||||
} else {
|
||||
n, err := strconv.Atoi(offset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("offset is invalid: %s", offset)
|
||||
}
|
||||
querys["offset"] = strconv.Itoa(n + 1)
|
||||
}
|
||||
return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural)
|
||||
}
|
||||
|
||||
/*
|
||||
返回job id 或者 order id
|
||||
|
||||
https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html
|
||||
创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b")
|
||||
包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL")
|
||||
*/
|
||||
func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) {
|
||||
origin_version := self.version
|
||||
self.version = "v1.1"
|
||||
defer func() { self.version = origin_version }()
|
||||
|
||||
ret, err := self.CreateInContextWithSpec(nil, "", params, "")
|
||||
if err != nil {
|
||||
log.Debugf("AsyncCreate %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Debugf("AsyncCreate result %s", ret.String())
|
||||
// 按需机器
|
||||
jobId, err := ret.GetString("job_id")
|
||||
if err == nil {
|
||||
return jobId, nil
|
||||
}
|
||||
|
||||
// 包年包月机器
|
||||
return ret.GetString("order_id")
|
||||
}
|
||||
|
||||
func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return nil, fmt.Errorf("not supported.please use AsyncCreate")
|
||||
}
|
||||
|
||||
// 不推荐使用这个manager
|
||||
func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager {
|
||||
return &SServerManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2.1",
|
||||
Keyword: "server",
|
||||
KeywordPlural: "servers",
|
||||
|
||||
ResourceKeyword: "servers",
|
||||
}}
|
||||
}
|
||||
|
||||
// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager
|
||||
func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager {
|
||||
return &SServerManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "server",
|
||||
KeywordPlural: "servers",
|
||||
|
||||
ResourceKeyword: "cloudservers",
|
||||
}}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SfsTurboManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager {
|
||||
return &SfsTurboManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameSFSTurbo,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "",
|
||||
KeywordPlural: "shares",
|
||||
|
||||
ResourceKeyword: "sfs-turbo/shares",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural)
|
||||
}
|
||||
|
||||
func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
return self.CreateInContextWithSpec(self.ctx, "", params, "")
|
||||
}
|
||||
Generated
Vendored
-59
@@ -1,59 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SSnapshotManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager {
|
||||
return &SSnapshotManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameEVS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "snapshot",
|
||||
KeywordPlural: "snapshots",
|
||||
|
||||
ResourceKeyword: "snapshots",
|
||||
}}
|
||||
}
|
||||
|
||||
func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural)
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html
|
||||
// 回滚快照只能用这个manger。其他情况请不要使用
|
||||
// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html
|
||||
func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager {
|
||||
return &SSnapshotManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameEVS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "snapshot",
|
||||
KeywordPlural: "snapshots",
|
||||
|
||||
ResourceKeyword: "os-vendor-snapshots",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-41
@@ -1,41 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SNatSRuleManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager {
|
||||
man := &SNatSRuleManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameNAT,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2.0",
|
||||
Keyword: "snat_rule",
|
||||
KeywordPlural: "snat_rules",
|
||||
|
||||
ResourceKeyword: "snat_rules",
|
||||
}}
|
||||
if len(cfg.GetProjectId()) > 0 {
|
||||
man.requestHook = &sProjectHook{cfg.GetProjectId()}
|
||||
}
|
||||
return man
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SSubnetManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager {
|
||||
return &SSubnetManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "subnet",
|
||||
KeywordPlural: "subnets",
|
||||
|
||||
ResourceKeyword: "subnets",
|
||||
}}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type STraceManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewTraceManager(cfg manager.IManagerConfig) *STraceManager {
|
||||
return &STraceManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameCTS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2.0",
|
||||
Keyword: "trace",
|
||||
KeywordPlural: "traces",
|
||||
|
||||
ResourceKeyword: "system/trace",
|
||||
}}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
)
|
||||
|
||||
type SUserManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewUserManager(cfg manager.IManagerConfig) *SUserManager {
|
||||
user := &SUserManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameIAM,
|
||||
Region: "",
|
||||
ProjectId: "",
|
||||
version: "v3.0/OS-USER",
|
||||
Keyword: "user",
|
||||
KeywordPlural: "users",
|
||||
|
||||
ResourceKeyword: "users",
|
||||
}}
|
||||
user.SetDomainId(cfg.GetDomainId())
|
||||
return user
|
||||
}
|
||||
|
||||
func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) {
|
||||
self.SetVersion("v3")
|
||||
return self.SResourceManager.List(querys)
|
||||
}
|
||||
|
||||
func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) {
|
||||
self.SetVersion("v3")
|
||||
return self.SResourceManager.Delete(id, nil)
|
||||
}
|
||||
|
||||
func (self *SUserManager) ResetPassword(id, password string) error {
|
||||
params := map[string]interface{}{
|
||||
"user": map[string]string{
|
||||
"password": password,
|
||||
},
|
||||
}
|
||||
_, err := self.SResourceManager.Update(id, jsonutils.Marshal(params))
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) {
|
||||
self.SetVersion("v3")
|
||||
return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups")
|
||||
}
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SVpcPeeringManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager {
|
||||
return &SVpcPeeringManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: "",
|
||||
version: "v2.0",
|
||||
Keyword: "peering",
|
||||
KeywordPlural: "peerings",
|
||||
|
||||
ResourceKeyword: "vpc/peerings",
|
||||
}}
|
||||
}
|
||||
Generated
Vendored
-38
@@ -1,38 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SVpcRouteManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager {
|
||||
return &SVpcRouteManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
// the url should not include the field "projectid" in huawei cloud api v2.0
|
||||
ProjectId: "",
|
||||
version: "v2.0",
|
||||
Keyword: "route",
|
||||
KeywordPlural: "routes",
|
||||
|
||||
ResourceKeyword: "vpc/routes",
|
||||
}}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SVpcManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager {
|
||||
return &SVpcManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameVPC,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v1",
|
||||
Keyword: "vpc",
|
||||
KeywordPlural: "vpcs",
|
||||
|
||||
ResourceKeyword: "vpcs",
|
||||
}}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// 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 modules
|
||||
|
||||
import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager"
|
||||
)
|
||||
|
||||
type SZoneManager struct {
|
||||
SResourceManager
|
||||
}
|
||||
|
||||
func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager {
|
||||
return &SZoneManager{SResourceManager: SResourceManager{
|
||||
SBaseManager: NewBaseManager(cfg),
|
||||
ServiceName: ServiceNameECS,
|
||||
Region: cfg.GetRegionId(),
|
||||
ProjectId: cfg.GetProjectId(),
|
||||
version: "v2",
|
||||
Keyword: "availabilityZoneInfo",
|
||||
KeywordPlural: "availabilityZoneInfo",
|
||||
|
||||
ResourceKeyword: "os-availability-zone",
|
||||
}}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 requests // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests"
|
||||
-276
@@ -1,276 +0,0 @@
|
||||
// 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 requests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IRequest interface {
|
||||
GetScheme() string
|
||||
GetMethod() string
|
||||
GetDomain() string
|
||||
GetPort() string
|
||||
GetRegionId() string
|
||||
GetProjectId() string
|
||||
GetHost() string
|
||||
GetURI() string
|
||||
GetHeaders() map[string]string
|
||||
GetQueryParams() map[string]string
|
||||
GetFormParams() map[string]string
|
||||
GetContent() []byte
|
||||
GetBodyReader() io.Reader
|
||||
GetProduct() string
|
||||
GetVersion() string
|
||||
|
||||
SetStringToSign(stringToSign string)
|
||||
GetStringToSign() string
|
||||
|
||||
SetDomain(domain string)
|
||||
SetContent(content []byte)
|
||||
SetScheme(scheme string)
|
||||
BuildUrl() string
|
||||
BuildQueries() string
|
||||
|
||||
AddHeaderParam(key, value string)
|
||||
AddQueryParam(key, value string)
|
||||
AddFormParam(key, value string)
|
||||
}
|
||||
|
||||
type SRequest struct {
|
||||
Scheme string // HTTP、HTTPS
|
||||
Method string // GET、PUT、DELETE、POST、PATCH
|
||||
Domain string // myhuaweicloud.com
|
||||
Port string // 80
|
||||
RegionId string // cn-north-1
|
||||
|
||||
product string // 弹性云服务 ECS : ecs
|
||||
version string // API版本: v2
|
||||
projectId string // 项目ID: 43cbe5e77aaf4665bbb962062dc1fc9d.可以为空。
|
||||
|
||||
resourcePath string // /users/{user_id}/groups
|
||||
QueryParams map[string]string
|
||||
Headers map[string]string
|
||||
FormParams map[string]string
|
||||
Content []byte
|
||||
|
||||
queries string
|
||||
|
||||
stringToSign string
|
||||
}
|
||||
|
||||
func (self *SRequest) GetProjectId() string {
|
||||
return self.projectId
|
||||
}
|
||||
|
||||
func (self *SRequest) GetScheme() string {
|
||||
return self.Scheme
|
||||
}
|
||||
|
||||
func (self *SRequest) GetMethod() string {
|
||||
return self.Method
|
||||
}
|
||||
|
||||
func (self *SRequest) GetDomain() string {
|
||||
return self.Domain
|
||||
}
|
||||
|
||||
func (self *SRequest) GetPort() string {
|
||||
return self.Port
|
||||
}
|
||||
|
||||
func (self *SRequest) GetRegionId() string {
|
||||
return self.RegionId
|
||||
}
|
||||
|
||||
func (self *SRequest) GetHeaders() map[string]string {
|
||||
return self.Headers
|
||||
}
|
||||
|
||||
func (self *SRequest) GetQueryParams() map[string]string {
|
||||
return self.QueryParams
|
||||
}
|
||||
|
||||
func (self *SRequest) GetFormParams() map[string]string {
|
||||
return self.FormParams
|
||||
}
|
||||
|
||||
func (self *SRequest) GetContent() []byte {
|
||||
return self.Content
|
||||
}
|
||||
|
||||
func (self *SRequest) GetBodyReader() io.Reader {
|
||||
if self.FormParams != nil && len(self.FormParams) > 0 {
|
||||
formData := GetUrlFormedMap(self.FormParams)
|
||||
return strings.NewReader(formData)
|
||||
} else {
|
||||
return strings.NewReader(string(self.Content))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRequest) GetProduct() string {
|
||||
return self.product
|
||||
}
|
||||
|
||||
func (self *SRequest) GetVersion() string {
|
||||
return self.version
|
||||
}
|
||||
|
||||
func (self *SRequest) SetStringToSign(stringToSign string) {
|
||||
self.stringToSign = stringToSign
|
||||
}
|
||||
|
||||
func (self *SRequest) GetStringToSign() string {
|
||||
return self.stringToSign
|
||||
}
|
||||
|
||||
func (self *SRequest) SetDomain(domain string) {
|
||||
self.Domain = domain
|
||||
}
|
||||
|
||||
func (self *SRequest) SetContent(content []byte) {
|
||||
self.Content = content
|
||||
}
|
||||
|
||||
func (self *SRequest) SetScheme(scheme string) {
|
||||
self.Scheme = scheme
|
||||
}
|
||||
|
||||
func (self *SRequest) BuildUrl() string {
|
||||
scheme := strings.ToLower(self.Scheme)
|
||||
baseUrl := fmt.Sprintf("%s://%s", scheme, self.GetHost())
|
||||
queries := self.BuildQueries()
|
||||
if len(queries) > 0 {
|
||||
return baseUrl + self.GetURI() + "?" + queries
|
||||
} else {
|
||||
return baseUrl + self.GetURI()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRequest) GetHost() string {
|
||||
scheme := strings.ToLower(self.Scheme)
|
||||
host := self.getEndpoint()
|
||||
if len(self.Port) > 0 {
|
||||
if (scheme == "http" && self.Port == "80") || (scheme == "https" && self.Port == "443") {
|
||||
host = fmt.Sprintf("%s:%s", host, self.Port)
|
||||
}
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
|
||||
func (self *SRequest) GetURI() string {
|
||||
// URI
|
||||
uri := ""
|
||||
for _, m := range []string{self.version, self.projectId} {
|
||||
if len(m) > 0 {
|
||||
uri += fmt.Sprintf("/%s", m)
|
||||
}
|
||||
}
|
||||
|
||||
if len(self.resourcePath) > 0 {
|
||||
s := ""
|
||||
if !strings.HasPrefix(self.resourcePath, "/") {
|
||||
s = "/"
|
||||
}
|
||||
|
||||
if strings.HasSuffix(self.resourcePath, "/") {
|
||||
strings.TrimSuffix(s, "/")
|
||||
}
|
||||
|
||||
uri = uri + s + self.resourcePath
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
||||
|
||||
func (self *SRequest) getEndpoint() string {
|
||||
// ecs.cn-north-1.myhuaweicloud.com
|
||||
items := []string{}
|
||||
for _, item := range []string{self.product, self.RegionId, self.Domain} {
|
||||
if len(item) > 0 {
|
||||
items = append(items, item)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(items, ".")
|
||||
}
|
||||
|
||||
func (self *SRequest) BuildQueries() string {
|
||||
self.queries = GetUrlFormedMap(self.QueryParams)
|
||||
return self.queries
|
||||
}
|
||||
|
||||
func (self *SRequest) AddHeaderParam(key, value string) {
|
||||
self.Headers[key] = value
|
||||
}
|
||||
|
||||
func (self *SRequest) AddQueryParam(key, value string) {
|
||||
self.QueryParams[key] = value
|
||||
}
|
||||
|
||||
func (self *SRequest) AddFormParam(key, value string) {
|
||||
self.FormParams[key] = value
|
||||
}
|
||||
|
||||
func GetUrlFormedMap(source map[string]string) string {
|
||||
// 按key排序后编译
|
||||
keys := make([]string, 0)
|
||||
for k := range source {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return strings.ToLower(keys[i]) < strings.ToLower(keys[j])
|
||||
})
|
||||
|
||||
urlEncoder := url.Values{}
|
||||
for _, k := range keys {
|
||||
urlEncoder.Add(k, source[k])
|
||||
}
|
||||
|
||||
return urlEncoder.Encode()
|
||||
}
|
||||
|
||||
func defaultRequest() (request *SRequest) {
|
||||
request = &SRequest{
|
||||
Scheme: "HTTPS",
|
||||
Method: "GET",
|
||||
QueryParams: make(map[string]string),
|
||||
Headers: map[string]string{},
|
||||
FormParams: make(map[string]string),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NewResourceRequest(domain, method, product, version, region, project, resourcePath string) *SRequest {
|
||||
return &SRequest{
|
||||
Scheme: "HTTPS",
|
||||
Method: method,
|
||||
Domain: domain,
|
||||
product: product,
|
||||
RegionId: region,
|
||||
version: version,
|
||||
projectId: project,
|
||||
resourcePath: resourcePath,
|
||||
QueryParams: make(map[string]string),
|
||||
Headers: map[string]string{},
|
||||
FormParams: make(map[string]string),
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// 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 responses // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses"
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
// 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 responses
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
)
|
||||
|
||||
type ListResult struct {
|
||||
Data []jsonutils.JSONObject
|
||||
Total int
|
||||
Limit int
|
||||
Offset int
|
||||
NextLink string
|
||||
}
|
||||
|
||||
func ListResult2JSONWithKey(result *ListResult, key string) jsonutils.JSONObject {
|
||||
obj := jsonutils.NewDict()
|
||||
if result.Total > 0 {
|
||||
obj.Add(jsonutils.NewInt(int64(result.Total)), "total")
|
||||
}
|
||||
if result.Limit > 0 {
|
||||
obj.Add(jsonutils.NewInt(int64(result.Limit)), "limit")
|
||||
}
|
||||
if result.Offset > 0 {
|
||||
obj.Add(jsonutils.NewInt(int64(result.Offset)), "offset")
|
||||
}
|
||||
arr := jsonutils.NewArray(result.Data...)
|
||||
obj.Add(arr, key)
|
||||
return obj
|
||||
}
|
||||
|
||||
func ListResult2JSON(result *ListResult) jsonutils.JSONObject {
|
||||
return ListResult2JSONWithKey(result, "data")
|
||||
}
|
||||
|
||||
func JSON2ListResult(result jsonutils.JSONObject) *ListResult {
|
||||
total, _ := result.Int("total")
|
||||
limit, _ := result.Int("limit")
|
||||
offset, _ := result.Int("offset")
|
||||
data, _ := result.GetArray("data")
|
||||
return &ListResult{Data: data, Total: int(total), Limit: int(limit), Offset: int(offset)}
|
||||
}
|
||||
|
||||
// 将key中的冒号替换成
|
||||
func TransColonToDot(obj jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
re, _ := regexp.Compile("[a-zA-Z0-9](:+)[^\"]+\"\\s*:\\s*")
|
||||
|
||||
if obj == nil {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
newStr := re.ReplaceAllStringFunc(obj.String(), func(s string) string {
|
||||
count := strings.Count(s, ":")
|
||||
if count > 1 {
|
||||
return strings.Replace(s, ":", ".", count-1)
|
||||
}
|
||||
return s
|
||||
})
|
||||
|
||||
return jsonutils.ParseString(newStr)
|
||||
}
|
||||
+111
-102
@@ -16,9 +16,9 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
@@ -134,24 +134,24 @@ func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListGroups
|
||||
func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) {
|
||||
params := map[string]string{}
|
||||
query := url.Values{}
|
||||
if len(domainId) > 0 {
|
||||
params["domain_id"] = self.ownerId
|
||||
query.Set("domain_id", self.ownerId)
|
||||
}
|
||||
if len(name) > 0 {
|
||||
params["name"] = name
|
||||
}
|
||||
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
query.Set("name", name)
|
||||
}
|
||||
|
||||
groups := []SCloudgroup{}
|
||||
err = doListAllWithNextLink(client.Groups.List, params, &groups)
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", "groups", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doListAllWithOffset")
|
||||
return nil, err
|
||||
}
|
||||
err = resp.Unmarshal(&groups, "groups")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
@@ -171,59 +171,53 @@ func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListUsersForGroupByAdmin
|
||||
func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users", groupId), nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
|
||||
resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
return nil, errors.Wrapf(err, "list group users")
|
||||
}
|
||||
users := []SClouduser{}
|
||||
err = jsonutils.Update(&users, resp.Data)
|
||||
err = resp.Unmarshal(&users, "users")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jsonutils.Update")
|
||||
return nil, errors.Wrap(err, "Unmarshal")
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCheckDomainPermissionForGroup
|
||||
func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
resp, err := client.Domains.ListRoles(self.ownerId, groupId)
|
||||
res := fmt.Sprintf("domains/%s/groups/%s/roles", self.ownerId, groupId)
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", res, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ListRoles")
|
||||
}
|
||||
roles := []SRole{}
|
||||
err = jsonutils.Update(&roles, resp.Data)
|
||||
err = resp.Unmarshal(&roles, "roles")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jsonutils.Update")
|
||||
return nil, errors.Wrap(err, "Unmarshal")
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateGroup
|
||||
func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) {
|
||||
params := map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
}
|
||||
if len(desc) > 0 {
|
||||
params["description"] = desc
|
||||
}
|
||||
client, err := self.newGeneralAPIClient()
|
||||
resp, err := self.post(SERVICE_IAM_V3, "", "groups", map[string]interface{}{"group": params})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
group := SCloudgroup{client: self}
|
||||
err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group)
|
||||
group := &SCloudgroup{client: self}
|
||||
err = resp.Unmarshal(group, "group")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DoCreate")
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return &group, nil
|
||||
return group, nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) {
|
||||
@@ -234,12 +228,10 @@ func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.I
|
||||
return group, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteGroup
|
||||
func (self *SHuaweiClient) DeleteGroup(id string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil)
|
||||
_, err := self.delete(SERVICE_IAM_V3, "", "groups/"+id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) {
|
||||
@@ -257,41 +249,46 @@ func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.IClo
|
||||
return &groups[0], nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAddUserToGroup
|
||||
func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
_, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "")
|
||||
_, err := self.put(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveUserFromGroup
|
||||
func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
_, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "")
|
||||
_, err := self.delete(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId))
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ListCustomPolicies
|
||||
func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) {
|
||||
params := map[string]string{}
|
||||
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
query := url.Values{}
|
||||
query.Set("per_page", "300")
|
||||
page := 1
|
||||
query.Set("page", fmt.Sprintf("%d", page))
|
||||
ret := []SRole{}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_IAM, "", "OS-ROLE/roles", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Roles []SRole
|
||||
TotalNumber int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Roles...)
|
||||
if len(ret) >= part.TotalNumber || len(part.Roles) == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
query.Set("page", fmt.Sprintf("%d", page))
|
||||
}
|
||||
|
||||
client.Roles.SetVersion("v3.0/OS-ROLE")
|
||||
defer client.Roles.SetVersion("v3.0")
|
||||
|
||||
roles := []SRole{}
|
||||
err = doListAllWithNextLink(client.Roles.List, params, &roles)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doListAllWithOffset")
|
||||
}
|
||||
return roles, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) {
|
||||
@@ -321,23 +318,19 @@ func (self *SHuaweiClient) GetRole(name string) (*SRole, error) {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
role, err := self.GetRole(roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetRole(%s)", roleId)
|
||||
}
|
||||
if role.Type == "AX" || role.Type == "AA" {
|
||||
err = client.Domains.AddRole(self.ownerId, groupId, role.Id)
|
||||
err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddRole")
|
||||
return errors.Wrapf(err, "remove domain role")
|
||||
}
|
||||
if strings.Contains(strings.ToLower(role.Policy.String()), "obs") {
|
||||
err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id)
|
||||
err := self.KeystoneRemoveProjectPermissionFromGroup(self.GetMosProjectId(), groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "remove project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,33 +340,57 @@ func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error {
|
||||
return errors.Wrapf(err, "GetProjects")
|
||||
}
|
||||
for _, project := range projects {
|
||||
err = client.Projects.AddProjectRole(project.ID, groupId, role.Id)
|
||||
err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "remove project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveProjectPermissionFromGroup
|
||||
func (self *SHuaweiClient) KeystoneRemoveProjectPermissionFromGroup(projectId, groupId, roleId string) error {
|
||||
res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", projectId, groupId, roleId)
|
||||
_, err := self.delete(SERVICE_IAM_V3, "", res)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithProjectPermission
|
||||
func (self *SHuaweiClient) KeystoneAssociateGroupWithProjectPermission(projectId, groupId, roleId string) error {
|
||||
res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", self.GetMosProjectId(), groupId, roleId)
|
||||
_, err := self.put(SERVICE_IAM_V3, "", res, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithDomainPermission
|
||||
func (self *SHuaweiClient) KeystoneAssociateGroupWithDomainPermission(domainId, groupId, roleId string) error {
|
||||
res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId)
|
||||
_, err := self.put(SERVICE_IAM_V3, "", res, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveDomainPermissionFromGroup
|
||||
func (self *SHuaweiClient) KeystoneRemoveDomainPermissionFromGroup(domainId, groupId, roleId string) error {
|
||||
res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId)
|
||||
_, err := self.delete(SERVICE_IAM_V3, "", res)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
role, err := self.GetRole(roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetRole(%s)", roleId)
|
||||
}
|
||||
if role.Type == "AX" || role.Type == "AA" {
|
||||
err = client.Domains.AddRole(self.ownerId, groupId, role.Id)
|
||||
err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddRole")
|
||||
}
|
||||
if strings.Contains(strings.ToLower(role.Policy.String()), "obs") {
|
||||
err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id)
|
||||
err := self.KeystoneAssociateGroupWithProjectPermission(self.GetMosProjectId(), groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "add project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,9 +400,9 @@ func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error {
|
||||
return errors.Wrapf(err, "GetProjects")
|
||||
}
|
||||
for _, project := range projects {
|
||||
err = client.Projects.AddProjectRole(project.ID, groupId, role.Id)
|
||||
err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "add project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,23 +410,19 @@ func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
role, err := self.GetCustomRole(roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetRole(%s)", roleId)
|
||||
}
|
||||
if role.Type == "AX" || role.Type == "AA" {
|
||||
err = client.Domains.AddRole(self.ownerId, groupId, role.Id)
|
||||
err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddRole")
|
||||
}
|
||||
if strings.Contains(strings.ToLower(role.Policy.String()), "obs") {
|
||||
err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id)
|
||||
err = self.KeystoneAssociateGroupWithProjectPermission(self.GetMosProjectId(), groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "add project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,9 +432,9 @@ func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error {
|
||||
return errors.Wrapf(err, "GetProjects")
|
||||
}
|
||||
for _, project := range projects {
|
||||
err = client.Projects.AddProjectRole(project.ID, groupId, role.Id)
|
||||
err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AddProjectRole")
|
||||
return errors.Wrapf(err, "add project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,23 +442,19 @@ func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
role, err := self.GetCustomRole(roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetCustomRole(%s)", roleId)
|
||||
}
|
||||
if role.Type == "AX" || role.Type == "AA" {
|
||||
err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id)
|
||||
err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "DeleteRole")
|
||||
}
|
||||
if strings.Contains(strings.ToLower(role.Policy.String()), "obs") {
|
||||
err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id)
|
||||
err := self.KeystoneRemoveProjectPermissionFromGroup(self.GetMosProjectId(), groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "DeleteProjectRole")
|
||||
return errors.Wrapf(err, "remove project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,9 +464,9 @@ func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error {
|
||||
return errors.Wrapf(err, "GetProjects")
|
||||
}
|
||||
for _, project := range projects {
|
||||
err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id)
|
||||
err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "DeleteProjectRole")
|
||||
return errors.Wrapf(err, "remove project role ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-40
@@ -15,14 +15,14 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
type SLink struct {
|
||||
@@ -111,45 +111,40 @@ func (user *SClouduser) ResetPassword(password string) error {
|
||||
return user.client.ResetClouduserPassword(user.Id, password)
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteUser
|
||||
func (self *SHuaweiClient) DeleteClouduser(id string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
_, err = client.Users.Delete(id)
|
||||
_, err := self.delete(SERVICE_IAM_V3, "", "users/"+id)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListGroupsForUser
|
||||
func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("users/%s/groups", userId), nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
result, err := client.Users.ListGroups(userId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Users.ListGroups")
|
||||
return nil, err
|
||||
}
|
||||
groups := []SCloudgroup{}
|
||||
err = jsonutils.Update(&groups, result.Data)
|
||||
err = resp.Unmarshal(&groups, "groups")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jsonutils.Update")
|
||||
return nil, err
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListUsers
|
||||
func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) {
|
||||
params := map[string]string{}
|
||||
params := url.Values{}
|
||||
if len(name) > 0 {
|
||||
params["name"] = name
|
||||
params.Set("name", name)
|
||||
}
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", "users", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := []SClouduser{}
|
||||
client, err := self.newGeneralAPIClient()
|
||||
err = resp.Unmarshal(&users, "users")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
err = doListAllWithOffset(client.Users.List, params, &users)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doListAllWithOffset")
|
||||
return nil, err
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
@@ -188,8 +183,9 @@ func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreate
|
||||
return self.CreateClouduser(conf.Name, conf.Password, conf.Desc)
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=CreateUser
|
||||
func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) {
|
||||
params := map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"domain_id": self.ownerId,
|
||||
}
|
||||
@@ -199,28 +195,29 @@ func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SCloud
|
||||
if len(desc) > 0 {
|
||||
params["description"] = desc
|
||||
}
|
||||
client, err := self.newGeneralAPIClient()
|
||||
resp, err := self.post(SERVICE_IAM, "", "OS-USER/users", map[string]interface{}{"user": params})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
user := SClouduser{client: self}
|
||||
err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user)
|
||||
if err != nil {
|
||||
ce, ok := err.(*modules.HuaweiClientError)
|
||||
if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" {
|
||||
if strings.Contains(err.Error(), "1101") {
|
||||
return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html
|
||||
}
|
||||
return nil, errors.Wrap(err, "DoCreate")
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
user := &SClouduser{client: self}
|
||||
err = resp.Unmarshal(user, "user")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=UpdateUser
|
||||
func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
return client.Users.ResetPassword(id, password)
|
||||
_, err := self.put(SERVICE_IAM, "", "OS-USER/users/"+id, map[string]interface{}{
|
||||
"user": map[string]interface{}{
|
||||
"password": password,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
type SAccessKey struct {
|
||||
@@ -233,6 +230,7 @@ type SAccessKey struct {
|
||||
CreatedAt time.Time `json:"create_time"`
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ListPermanentAccessKeys
|
||||
func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) {
|
||||
query := url.Values{}
|
||||
query.Set("user_id", id)
|
||||
@@ -253,6 +251,7 @@ func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=CreatePermanentAccessKey
|
||||
func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) {
|
||||
params := map[string]interface{}{
|
||||
"credential": map[string]interface{}{
|
||||
@@ -265,7 +264,10 @@ func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKe
|
||||
return nil, errors.Wrap(err, "SHuaweiClient.createAKSK")
|
||||
}
|
||||
ak := SAccessKey{}
|
||||
obj.Unmarshal(&ak, "credential")
|
||||
err = obj.Unmarshal(&ak, "credential")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
res := cloudprovider.SAccessKey{
|
||||
Name: ak.Description,
|
||||
AccessKey: ak.AccessKey,
|
||||
@@ -274,6 +276,7 @@ func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKe
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=DeletePermanentAccessKey
|
||||
func (self *SHuaweiClient) DeleteAKSK(accessKey string) error {
|
||||
_, err := self.delete(SERVICE_IAM, "", "OS-CREDENTIAL/credentials/"+accessKey)
|
||||
return err
|
||||
|
||||
+107
-56
@@ -17,6 +17,7 @@ package huawei
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -97,20 +98,46 @@ type SDBInstance struct {
|
||||
EnterpriseProjectId string
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstances() ([]SDBInstance, error) {
|
||||
params := map[string]string{}
|
||||
dbinstances := []SDBInstance{}
|
||||
err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances)
|
||||
return dbinstances, err
|
||||
func (region *SRegion) GetDBInstances(id string) ([]SDBInstance, error) {
|
||||
query := url.Values{}
|
||||
if len(id) > 0 {
|
||||
query.Set("id", id)
|
||||
}
|
||||
ret := []SDBInstance{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_RDS, "instances", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list instances")
|
||||
}
|
||||
part := struct {
|
||||
Instances []SDBInstance
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Instances...)
|
||||
if len(ret) >= part.TotalCount || len(part.Instances) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("offset", fmt.Sprintf("%d", len(ret)))
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) {
|
||||
if len(instanceId) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
ret, err := region.GetDBInstances(instanceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance := SDBInstance{region: region}
|
||||
err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance)
|
||||
return &instance, err
|
||||
for i := range ret {
|
||||
if ret[i].Id == instanceId {
|
||||
ret[i].region = region
|
||||
return &ret[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, instanceId)
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) GetName() string {
|
||||
@@ -160,8 +187,12 @@ func (rds *SDBInstance) GetStatus() string {
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) GetBillingType() string {
|
||||
_, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id))
|
||||
orders, err := rds.region.client.GetOrderResources()
|
||||
if err != nil {
|
||||
return billing_api.BILLING_TYPE_PREPAID
|
||||
}
|
||||
_, ok := orders[rds.Id]
|
||||
if ok {
|
||||
return billing_api.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
return billing_api.BILLING_TYPE_PREPAID
|
||||
@@ -184,11 +215,15 @@ func (rds *SDBInstance) fetchFlavor() error {
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) GetExpiredAt() time.Time {
|
||||
order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id))
|
||||
orders, err := rds.region.client.GetOrderResources()
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return order.ExpireTime
|
||||
order, ok := orders[rds.Id]
|
||||
if ok {
|
||||
return order.ExpireTime
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) GetStorageType() string {
|
||||
@@ -353,7 +388,7 @@ func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.IClo
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) {
|
||||
instances, err := region.GetDBInstances()
|
||||
instances, err := region.GetDBInstances("")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "region.GetDBInstances()")
|
||||
}
|
||||
@@ -420,7 +455,7 @@ func (rds *SDBInstance) Delete() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteDBInstance(instanceId string) error {
|
||||
_, err := region.ecsClient.DBInstance.Delete(instanceId, nil)
|
||||
_, err := region.delete(SERVICE_RDS, "instances/"+instanceId)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -506,7 +541,7 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
|
||||
}
|
||||
params["flavor_ref"] = desc.InstanceType
|
||||
params["availability_zone"] = desc.ZoneId
|
||||
resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
|
||||
resp, err := region.post(SERVICE_RDS, "instances", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Create")
|
||||
}
|
||||
@@ -518,20 +553,15 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
|
||||
}
|
||||
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
||||
err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) {
|
||||
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
||||
job, err := region.GetDBInstanceJob(jobId)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
status, _ := job.GetString("status")
|
||||
process, _ := job.GetString("process")
|
||||
log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process)
|
||||
if status == "Completed" {
|
||||
region.UpdateVM(instance.Id, cloudprovider.SInstanceUpdateOptions{
|
||||
Description: desc.Description,
|
||||
})
|
||||
log.Debugf("create dbinstance job %s status: %s process: %s", jobId, job.Status, job.Process)
|
||||
if job.Status == "Completed" {
|
||||
return true, nil
|
||||
}
|
||||
if status == "Failed" {
|
||||
if job.Status == "Failed" {
|
||||
return false, fmt.Errorf("create failed")
|
||||
}
|
||||
return false, nil
|
||||
@@ -554,25 +584,43 @@ func (rds *SDBInstance) ClosePublicConnection() error {
|
||||
//return rds.region.PublicConnectionAction(rds.Id, "closeRC")
|
||||
}
|
||||
|
||||
type SDBInstanceJob struct {
|
||||
Status string
|
||||
Process string
|
||||
}
|
||||
|
||||
func (self *SRegion) GetDBInstanceJob(id string) (*SDBInstanceJob, error) {
|
||||
query := url.Values{}
|
||||
query.Set("id", id)
|
||||
resp, err := self.list(SERVICE_RDS, "jobs", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := &SDBInstanceJob{}
|
||||
err = resp.Unmarshal(ret, "job")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) PublicConnectionAction(instanceId string, action string) error {
|
||||
resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "")
|
||||
resp, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/%s", instanceId, action), nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "rds.%s", action)
|
||||
}
|
||||
|
||||
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
||||
err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool {
|
||||
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
||||
job, err := region.GetDBInstanceJob(jobId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get job %s info error: %v", jobId, err)
|
||||
return false
|
||||
}
|
||||
status, _ := job.GetString("status")
|
||||
process, _ := job.GetString("process")
|
||||
if status == "Completed" {
|
||||
if job.Status == "Completed" {
|
||||
return true
|
||||
}
|
||||
log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process)
|
||||
log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process)
|
||||
return false
|
||||
})
|
||||
}
|
||||
@@ -582,26 +630,23 @@ func (region *SRegion) PublicConnectionAction(instanceId string, action string)
|
||||
}
|
||||
|
||||
func (region *SRegion) RebootDBInstance(instanceId string) error {
|
||||
params := jsonutils.Marshal(map[string]interface{}{
|
||||
params := map[string]interface{}{
|
||||
"restart": map[string]string{},
|
||||
})
|
||||
resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "")
|
||||
}
|
||||
resp, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
||||
err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool {
|
||||
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
||||
job, err := region.GetDBInstanceJob(jobId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get job %s info error: %v", jobId, err)
|
||||
return false
|
||||
}
|
||||
status, _ := job.GetString("status")
|
||||
process, _ := job.GetString("process")
|
||||
if status == "Completed" {
|
||||
if job.Status == "Completed" {
|
||||
return true
|
||||
}
|
||||
log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process)
|
||||
log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, job.Status, job.Process)
|
||||
return false
|
||||
})
|
||||
}
|
||||
@@ -616,12 +661,20 @@ type SDBInstanceFlavor struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) {
|
||||
flavors := []SDBInstanceFlavor{}
|
||||
resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors")
|
||||
query := url.Values{}
|
||||
if len(version) > 0 {
|
||||
query.Set("version_name", version)
|
||||
}
|
||||
resp, err := region.list(SERVICE_RDS, "flavors/"+engine, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flavors, jsonutils.Update(&flavors, resp.Data)
|
||||
flavors := []SDBInstanceFlavor{}
|
||||
err = resp.Unmarshal(&flavors, "flavors")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flavors, nil
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error {
|
||||
@@ -629,11 +682,11 @@ func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCrea
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error {
|
||||
params := map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"name": account,
|
||||
"password": password,
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "")
|
||||
_, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user", instanceId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -642,11 +695,11 @@ func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCr
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error {
|
||||
params := map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"name": database,
|
||||
"character_set": characterSet,
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "")
|
||||
_, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/database", instanceId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -661,24 +714,24 @@ func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType st
|
||||
}
|
||||
|
||||
if len(instanceType) > 0 {
|
||||
params := map[string]map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"resize_flavor": map[string]string{
|
||||
"spec_code": instanceType,
|
||||
},
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params))
|
||||
_, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "resize_flavor")
|
||||
}
|
||||
cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30)
|
||||
}
|
||||
if diskSizeGb > 0 {
|
||||
params := map[string]map[string]int{
|
||||
params := map[string]interface{}{
|
||||
"enlarge_volume": map[string]int{
|
||||
"size": diskSizeGb,
|
||||
},
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params))
|
||||
_, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "enlarge_volume")
|
||||
}
|
||||
@@ -726,8 +779,7 @@ func (self *SRegion) DeleteRdsTags(instanceId string, tagsKey []string) error {
|
||||
tagsObj = append(tagsObj, map[string]string{"key": k})
|
||||
}
|
||||
params["tags"] = tagsObj
|
||||
|
||||
_, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "")
|
||||
_, err := self.post(SERVICE_RDS, fmt.Sprintf("instances/%s/tags/action", instanceId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -741,8 +793,7 @@ func (self *SRegion) CreateRdsTags(instanceId string, tags map[string]string) er
|
||||
tagsObj = append(tagsObj, map[string]string{"key": k, "value": v})
|
||||
}
|
||||
params["tags"] = tagsObj
|
||||
|
||||
_, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "")
|
||||
_, err := self.post(SERVICE_RDS, fmt.Sprintf("instances/%s/tags/action", instanceId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -770,7 +821,7 @@ func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backu
|
||||
"instance_id": target,
|
||||
},
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params))
|
||||
_, err := region.post(SERVICE_RDS, "instances/recovery", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbinstance.recovery")
|
||||
}
|
||||
|
||||
+66
-24
@@ -16,12 +16,12 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"net/url"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
)
|
||||
|
||||
type SDBInstanceAccount struct {
|
||||
@@ -40,11 +40,12 @@ func (account *SDBInstanceAccount) Delete() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error {
|
||||
return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil)
|
||||
_, err := region.delete(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/%s", instanceId, account))
|
||||
return err
|
||||
}
|
||||
|
||||
func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) {
|
||||
privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name)
|
||||
privileges, err := account.instance.region.GetDBInstancePrivileges(account.instance.Id, account.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -57,28 +58,63 @@ func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudpro
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) {
|
||||
params := map[string]string{
|
||||
"instance_id": instanceId,
|
||||
params := url.Values{}
|
||||
params.Set("limit", "100")
|
||||
page := 1
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
ret := []SDBInstanceAccount{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/detail", instanceId), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Users []SDBInstanceAccount
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Users...)
|
||||
if len(ret) >= part.TotalCount || len(part.Users) == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
}
|
||||
accounts := []SDBInstanceAccount{}
|
||||
err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return accounts, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) {
|
||||
params := map[string]string{
|
||||
"instance_id": instanceId,
|
||||
"user-name": username,
|
||||
func (region *SRegion) GetDBInstancePrivileges(instanceId string, username string) ([]SDatabasePrivilege, error) {
|
||||
params := url.Values{}
|
||||
params.Set("instance_id", instanceId)
|
||||
params.Set("user-name", username)
|
||||
params.Set("limit", "100")
|
||||
page := 1
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
ret := []SDatabasePrivilege{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/database", instanceId), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Databases []SDatabasePrivilege
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Databases...)
|
||||
if len(ret) >= part.TotalCount || len(part.Databases) == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
}
|
||||
privileges := []SDatabasePrivilege{}
|
||||
err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return privileges, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (account *SDBInstanceAccount) RevokePrivilege(database string) error {
|
||||
@@ -94,7 +130,13 @@ func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, dat
|
||||
},
|
||||
},
|
||||
}
|
||||
return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("instances/%s/db_privilege", instanceId)
|
||||
url, err := region.client.getUrl(SERVICE_RDS, region.ID, resource, httputils.DELETE, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = region.client.request(httputils.DELETE, url, nil, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error {
|
||||
@@ -119,7 +161,7 @@ func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, data
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params))
|
||||
_, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/db_privilege", instanceId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
+33
-20
@@ -15,6 +15,8 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -115,7 +117,7 @@ func (backup *SDBInstanceBackup) Delete() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteDBInstanceBackup(backupId string) error {
|
||||
_, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil)
|
||||
_, err := region.delete(SERVICE_RDS, "backups/"+backupId)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -124,16 +126,30 @@ func (backup *SDBInstanceBackup) GetDBInstanceId() string {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) {
|
||||
params := map[string]string{
|
||||
"instance_id": instanceId,
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("instance_id", instanceId)
|
||||
if len(backupId) > 0 {
|
||||
params["backup_id"] = backupId
|
||||
params.Set("backup_id", backupId)
|
||||
}
|
||||
backups := []SDBInstanceBackup{}
|
||||
err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for {
|
||||
resp, err := region.list(SERVICE_RDS, "backups", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Backups []SDBInstanceBackup
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backups = append(backups, part.Backups...)
|
||||
if len(backups) >= part.TotalCount || len(part.Backups) == 0 {
|
||||
break
|
||||
}
|
||||
params.Set("offset", fmt.Sprintf("%d", len(backups)))
|
||||
}
|
||||
return backups, nil
|
||||
}
|
||||
@@ -194,19 +210,15 @@ func (backup *SDBInstanceBackup) Refresh() error {
|
||||
}
|
||||
|
||||
func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
|
||||
backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases)
|
||||
backup, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
backup, err := rds.region.GetIDBInstanceBackupById(backupId)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "region.GetIDBInstanceBackupById")
|
||||
}
|
||||
cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30)
|
||||
return backupId, nil
|
||||
return backup.GetGlobalId(), nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) {
|
||||
func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (*SDBInstanceBackup, error) {
|
||||
params := map[string]interface{}{
|
||||
"instance_id": instanceId,
|
||||
"name": name,
|
||||
@@ -219,15 +231,16 @@ func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, de
|
||||
}
|
||||
params["databases"] = dbs
|
||||
}
|
||||
resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params))
|
||||
resp, err := region.post(SERVICE_RDS, "backups", params)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "DBInstanceBackup.Create")
|
||||
return nil, errors.Wrap(err, "DBInstanceBackup.Create")
|
||||
}
|
||||
backupId, err := resp.GetString("id")
|
||||
ret := &SDBInstanceBackup{region: region}
|
||||
err = resp.Unmarshal(ret, "backup")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "resp.GetBackupId")
|
||||
return nil, err
|
||||
}
|
||||
return backupId, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
|
||||
|
||||
+28
-9
@@ -16,6 +16,7 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
@@ -55,18 +56,36 @@ func (database *SDBInstanceDatabase) Delete() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error {
|
||||
_, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "")
|
||||
_, err := region.delete(SERVICE_RDS, fmt.Sprintf("instances/%s/database/%s", instanceId, database))
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) {
|
||||
params := map[string]string{
|
||||
"instance_id": instanceId,
|
||||
params := url.Values{}
|
||||
params.Set("instance_id", instanceId)
|
||||
params.Set("limit", "100")
|
||||
page := 1
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
ret := []SDBInstanceDatabase{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/database/detail", instanceId), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Databases []SDBInstanceDatabase
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Databases...)
|
||||
if len(ret) >= part.TotalCount || len(part.Databases) == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
params.Set("page", fmt.Sprintf("%d", page))
|
||||
}
|
||||
databases := []SDBInstanceDatabase{}
|
||||
err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return databases, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+13
-6
@@ -14,6 +14,12 @@
|
||||
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type SDBInstanceParameter struct {
|
||||
instance *SDBInstance
|
||||
|
||||
@@ -27,15 +33,16 @@ type SDBInstanceParameter struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDBInstanceParameters(dbinstanceId string) ([]SDBInstanceParameter, error) {
|
||||
params := map[string]string{
|
||||
"instance_id": dbinstanceId,
|
||||
}
|
||||
paramters := []SDBInstanceParameter{}
|
||||
err := doListAll(region.ecsClient.DBInstance.ListParameters, params, ¶mters)
|
||||
resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/configurations", dbinstanceId), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paramters, nil
|
||||
ret := []SDBInstanceParameter{}
|
||||
err = resp.Unmarshal(&ret, "configuration_parameters")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (param *SDBInstanceParameter) GetGlobalId() string {
|
||||
|
||||
+101
-158
@@ -16,6 +16,8 @@ package huawei
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -59,6 +61,7 @@ type DiskMeta struct {
|
||||
ResourceType string `json:"resourceType"`
|
||||
AttachedMode string `json:"attached_mode"`
|
||||
Readonly string `json:"readonly"`
|
||||
OrderId string `json:"orderID"`
|
||||
}
|
||||
|
||||
type VolumeImageMetadata struct {
|
||||
@@ -92,7 +95,6 @@ type SDisk struct {
|
||||
storage *SStorage
|
||||
multicloud.SDisk
|
||||
HuaweiDiskTags
|
||||
details *SResourceDetail
|
||||
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -136,7 +138,6 @@ func (self *SDisk) GetGlobalId() string {
|
||||
}
|
||||
|
||||
func (self *SDisk) GetStatus() string {
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html
|
||||
switch self.Status {
|
||||
case "creating", "downloading":
|
||||
return api.DISK_ALLOCATING
|
||||
@@ -174,39 +175,18 @@ func (self *SDisk) GetStatus() string {
|
||||
}
|
||||
|
||||
func (self *SDisk) Refresh() error {
|
||||
new, err := self.storage.zone.region.GetDisk(self.GetId())
|
||||
disk, 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) getResourceDetails() *SResourceDetail {
|
||||
if self.details != nil {
|
||||
return self.details
|
||||
}
|
||||
|
||||
res, err := self.storage.zone.region.GetOrderResourceDetail(self.GetId())
|
||||
if err != nil {
|
||||
log.Debugln(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
self.details = &res
|
||||
return self.details
|
||||
return jsonutils.Update(self, disk)
|
||||
}
|
||||
|
||||
func (self *SDisk) GetBillingType() string {
|
||||
details := self.getResourceDetails()
|
||||
if details == nil {
|
||||
return billing_api.BILLING_TYPE_POSTPAID
|
||||
} else {
|
||||
if len(self.Metadata.OrderId) > 0 {
|
||||
return billing_api.BILLING_TYPE_PREPAID
|
||||
}
|
||||
return billing_api.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
|
||||
func (self *SDisk) GetCreatedAt() time.Time {
|
||||
@@ -214,13 +194,15 @@ func (self *SDisk) GetCreatedAt() time.Time {
|
||||
}
|
||||
|
||||
func (self *SDisk) GetExpiredAt() time.Time {
|
||||
var expiredTime time.Time
|
||||
details := self.getResourceDetails()
|
||||
if details != nil {
|
||||
expiredTime = details.ExpireTime
|
||||
orders, err := self.storage.zone.region.client.GetOrderResources()
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
return expiredTime
|
||||
order, ok := orders[self.ID]
|
||||
if ok {
|
||||
return order.ExpireTime
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
@@ -228,7 +210,6 @@ func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDiskFormat() string {
|
||||
// self.volume_type ?
|
||||
return "vhd"
|
||||
}
|
||||
|
||||
@@ -241,7 +222,7 @@ func (self *SDisk) checkAutoDelete(attachments []Attachment) bool {
|
||||
for _, attach := range attachments {
|
||||
if len(attach.ServerID) > 0 {
|
||||
// todo : 忽略错误??
|
||||
vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID)
|
||||
vm, err := self.storage.zone.region.GetInstance(attach.ServerID)
|
||||
if err != nil {
|
||||
volumes := vm.OSExtendedVolumesVolumesAttached
|
||||
for _, vol := range volumes {
|
||||
@@ -270,14 +251,11 @@ func (self *SDisk) GetTemplateId() string {
|
||||
return self.VolumeImageMetadata.ImageID
|
||||
}
|
||||
|
||||
// Bootable 表示硬盘是否为启动盘。
|
||||
// 启动盘 != 系统盘(必须是启动盘且挂载在root device上)
|
||||
func (self *SDisk) GetDiskType() string {
|
||||
if self.Bootable == "true" {
|
||||
return api.DISK_TYPE_SYS
|
||||
} else {
|
||||
return api.DISK_TYPE_DATA
|
||||
}
|
||||
return api.DISK_TYPE_DATA
|
||||
}
|
||||
|
||||
func (self *SDisk) GetFsFormat() string {
|
||||
@@ -289,9 +267,6 @@ func (self *SDisk) GetIsNonPersistent() bool {
|
||||
}
|
||||
|
||||
func (self *SDisk) GetDriver() string {
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html
|
||||
// scsi or vbd?
|
||||
// todo: implement me
|
||||
return "scsi"
|
||||
}
|
||||
|
||||
@@ -340,28 +315,19 @@ func (self *SDisk) Delete(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) {
|
||||
if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), name, desc); err != nil {
|
||||
log.Errorf("createSnapshot fail %s", err)
|
||||
return nil, err
|
||||
} else if snapshot, err := self.getSnapshot(snapshotId); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
snapshot.region = self.storage.zone.region
|
||||
if err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return snapshot, nil
|
||||
snapshot, err := self.storage.zone.region.CreateSnapshot(self.GetId(), name, desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CreateSnapshot")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) {
|
||||
snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId)
|
||||
return &snapshot, err
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
|
||||
snapshot, err := self.getSnapshot(snapshotId)
|
||||
return snapshot, err
|
||||
snapshot, err := self.storage.zone.region.GetSnapshot(snapshotId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
@@ -378,17 +344,11 @@ func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
}
|
||||
|
||||
func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error {
|
||||
err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sizeGb := newSizeMB / 1024
|
||||
err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb)
|
||||
err := self.storage.zone.region.ResizeDisk(self.GetId(), sizeGb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
@@ -417,140 +377,123 @@ func (self *SDisk) Detach() error {
|
||||
func (self *SDisk) Attach(device string) error {
|
||||
err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device)
|
||||
if err != nil {
|
||||
log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err)
|
||||
return err
|
||||
return errors.Wrapf(err, "AttachDisk")
|
||||
}
|
||||
|
||||
return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html
|
||||
// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载
|
||||
func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
|
||||
mountpoint := self.GetMountpoint()
|
||||
if len(mountpoint) > 0 {
|
||||
err := self.Detach()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId)
|
||||
if err != nil {
|
||||
return diskId, err
|
||||
}
|
||||
|
||||
err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(mountpoint) > 0 {
|
||||
err := self.Attach(mountpoint)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return diskId, nil
|
||||
return "", cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// 华为云不支持重置
|
||||
func (self *SDisk) Rebuild(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ShowVolume
|
||||
func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
|
||||
if len(diskId) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
resp, err := self.list(SERVICE_EVS, "cloudvolumes/"+diskId, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "show volume")
|
||||
}
|
||||
var disk SDisk
|
||||
err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk)
|
||||
return &disk, err
|
||||
ret := &SDisk{}
|
||||
err = resp.Unmarshal(ret, "volume")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ListVolumes
|
||||
func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) {
|
||||
queries := map[string]string{}
|
||||
ret := []SDisk{}
|
||||
query := url.Values{}
|
||||
if len(zoneId) > 0 {
|
||||
queries["availability_zone"] = zoneId
|
||||
query.Set("availability_zone", zoneId)
|
||||
}
|
||||
|
||||
disks := make([]SDisk, 0)
|
||||
err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks)
|
||||
return disks, err
|
||||
for {
|
||||
resp, err := self.list(SERVICE_EVS, "cloudvolumes/detail", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list volumes")
|
||||
}
|
||||
part := struct {
|
||||
Volumes []SDisk
|
||||
Count int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
ret = append(ret, part.Volumes...)
|
||||
if len(ret) >= part.Count || len(part.Volumes) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("offset", fmt.Sprintf("%d", len(ret)))
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=CreateVolume
|
||||
func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) {
|
||||
params := jsonutils.NewDict()
|
||||
volumeObj := jsonutils.NewDict()
|
||||
volumeObj.Add(jsonutils.NewString(name), "name")
|
||||
volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone")
|
||||
volumeObj.Add(jsonutils.NewString(desc), "description")
|
||||
volumeObj.Add(jsonutils.NewString(category), "volume_type")
|
||||
volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size")
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"availability_zone": zoneId,
|
||||
"description": desc,
|
||||
"volume_type": category,
|
||||
"size": sizeGb,
|
||||
}
|
||||
if len(snapshotId) > 0 {
|
||||
volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id")
|
||||
params["snapshot_id"] = snapshotId
|
||||
}
|
||||
if len(projectId) > 0 {
|
||||
volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id")
|
||||
params["enterprise_project_id"] = projectId
|
||||
}
|
||||
|
||||
params.Add(volumeObj, "volume")
|
||||
// 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id
|
||||
_id, err := self.ecsClient.Disks.AsyncCreate(params)
|
||||
resp, err := self.post(SERVICE_EVS_V2_1, "cloudvolumes", map[string]interface{}{"volume": params})
|
||||
if err != nil {
|
||||
log.Debugf("AsyncCreate with params: %s", params)
|
||||
return "", errors.Wrap(err, "AsyncCreate")
|
||||
return "", errors.Wrapf(err, "create volume")
|
||||
}
|
||||
|
||||
ret := struct {
|
||||
JobId string
|
||||
OrderId string
|
||||
}{}
|
||||
err = resp.Unmarshal(&ret)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
|
||||
id := ret.JobId + ret.OrderId
|
||||
|
||||
// 按需计费
|
||||
volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id")
|
||||
volumeId, err := self.GetTaskEntityID(SERVICE_EVS_V1, id, "volume_id")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetAllSubTaskEntityIDs")
|
||||
}
|
||||
|
||||
if len(volumeId) == 0 {
|
||||
return "", errors.Errorf("CreateInstance job %s result is emtpy", _id)
|
||||
} else {
|
||||
return volumeId, nil
|
||||
return "", errors.Errorf("CreateInstance job %s result is emtpy", id)
|
||||
}
|
||||
return volumeId, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html
|
||||
// 默认删除云硬盘关联的所有快照
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=DeleteVolume
|
||||
func (self *SRegion) DeleteDisk(diskId string) error {
|
||||
return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil)
|
||||
}
|
||||
|
||||
/*
|
||||
扩容状态为available的云硬盘时,没有约束限制。
|
||||
扩容状态为in-use的云硬盘时,有以下约束:
|
||||
不支持共享云硬盘,即multiattach参数值必须为false。
|
||||
云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容
|
||||
*/
|
||||
func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error {
|
||||
params := jsonutils.NewDict()
|
||||
osExtendObj := jsonutils.NewDict()
|
||||
osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB
|
||||
params.Add(osExtendObj, "os-extend")
|
||||
_, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "")
|
||||
res := fmt.Sprintf("cloudvolumes/%s", diskId)
|
||||
_, err := self.delete(SERVICE_EVS, res)
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html
|
||||
只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。
|
||||
只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。
|
||||
*/
|
||||
func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) {
|
||||
params := jsonutils.NewDict()
|
||||
rollbackObj := jsonutils.NewDict()
|
||||
rollbackObj.Add(jsonutils.NewString(diskId), "volume_id")
|
||||
params.Add(rollbackObj, "rollback")
|
||||
_, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "")
|
||||
return diskId, err
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ResizeVolume
|
||||
func (self *SRegion) ResizeDisk(diskId string, sizeGB int64) error {
|
||||
params := map[string]interface{}{
|
||||
"os-extend": map[string]interface{}{
|
||||
"new_size": sizeGB,
|
||||
},
|
||||
}
|
||||
_, err := self.post(SERVICE_EVS_V2_1, fmt.Sprintf("cloudvolumes/%s/action", diskId), params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SDisk) GetProjectId() string {
|
||||
|
||||
+11
-4
@@ -26,11 +26,18 @@ type SDomain struct {
|
||||
Tagflag int `json:"tagflag"`
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListAuthDomains
|
||||
func (self *SHuaweiClient) GetDomains() ([]SDomain, error) {
|
||||
huawei, _ := self.newGeneralAPIClient()
|
||||
domains := make([]SDomain, 0)
|
||||
err := doListAll(huawei.Domains.List, nil, &domains)
|
||||
return domains, err
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", "auth/domains", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []SDomain{}
|
||||
err = resp.Unmarshal(&ret, "domains")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) getEnabledDomains() ([]SDomain, error) {
|
||||
|
||||
+35
-17
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
|
||||
billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
@@ -219,6 +218,7 @@ func (self *SRegion) GetInstancePortId(instanceId string) (string, error) {
|
||||
return ports[0].ID, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=CreatePublicip
|
||||
func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) {
|
||||
if len(opts.BGPType) == 0 {
|
||||
switch self.GetId() {
|
||||
@@ -270,8 +270,9 @@ func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error)
|
||||
return eip, resp.Unmarshal(eip, "publicip")
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=ShowPublicip
|
||||
func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) {
|
||||
resp, err := self.list(SERVICE_VPC, "eip/publicips/"+eipId, nil)
|
||||
resp, err := self.list(SERVICE_VPC_V3, "eip/publicips/"+eipId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -279,11 +280,13 @@ func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) {
|
||||
return eip, resp.Unmarshal(eip, "publicip")
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=DeletePublicip
|
||||
func (self *SRegion) DeallocateEIP(eipId string) error {
|
||||
_, err := self.delete(SERVICE_VPC, "publicips/"+eipId)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=AssociatePublicips
|
||||
func (self *SRegion) AssociateEip(eipId string, associateId, associateType string) error {
|
||||
params := map[string]interface{}{
|
||||
"publicip": map[string]interface{}{
|
||||
@@ -292,16 +295,18 @@ func (self *SRegion) AssociateEip(eipId string, associateId, associateType strin
|
||||
},
|
||||
}
|
||||
res := fmt.Sprintf("eip/publicips/%s/associate-instance", eipId)
|
||||
_, err := self.post(SERVICE_VPC, res, params)
|
||||
_, err := self.post(SERVICE_VPC_V3, res, params)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=DisassociatePublicips
|
||||
func (self *SRegion) DissociateEip(eipId string) error {
|
||||
res := fmt.Sprintf("eip/publicips/%s/disassociate-instance", eipId)
|
||||
_, err := self.post(SERVICE_VPC, res, nil)
|
||||
_, err := self.post(SERVICE_VPC_V3, res, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=UpdateBandwidth
|
||||
func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error {
|
||||
params := map[string]interface{}{
|
||||
"bandwidth": map[string]interface{}{
|
||||
@@ -316,6 +321,7 @@ func (self *SEipAddress) GetProjectId() string {
|
||||
return self.EnterpriseProjectId
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=ListPublicips
|
||||
func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, error) {
|
||||
query := url.Values{}
|
||||
for _, addr := range addrs {
|
||||
@@ -326,7 +332,7 @@ func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, erro
|
||||
}
|
||||
eips := []SEipAddress{}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_VPC, "eip/publicips", query)
|
||||
resp, err := self.list(SERVICE_VPC_V3, "eip/publicips", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -350,6 +356,28 @@ func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, erro
|
||||
return eips, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=DeletePublicipTag
|
||||
func (self *SRegion) DeletePublicipTag(eipId string, key string) error {
|
||||
res := fmt.Sprintf("publicips/%s/tags/%s", eipId, key)
|
||||
_, err := self.delete(SERVICE_VPC_V2_0, res)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=CreatePublicipTag
|
||||
func (self *SRegion) CreatePublicipTag(eipId string, tags map[string]string) error {
|
||||
params := map[string]interface{}{
|
||||
"action": "create",
|
||||
}
|
||||
add := []map[string]string{}
|
||||
for k, v := range tags {
|
||||
add = append(add, map[string]string{"key": k, "value": v})
|
||||
}
|
||||
params["tags"] = add
|
||||
res := fmt.Sprintf("publicips/%s/tags/action", eipId)
|
||||
_, err := self.post(SERVICE_VPC_V2_0, res, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SRegion) setEipTags(id string, existedTags, tags map[string]string, replace bool) error {
|
||||
deleteTagsKey := []string{}
|
||||
for k := range existedTags {
|
||||
@@ -363,24 +391,14 @@ func (self *SRegion) setEipTags(id string, existedTags, tags map[string]string,
|
||||
}
|
||||
if len(deleteTagsKey) > 0 {
|
||||
for _, k := range deleteTagsKey {
|
||||
url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/publicips/%s/tags/%s", self.ID, self.client.projectId, id, k)
|
||||
_, err := self.client.request(httputils.DELETE, url, nil, nil)
|
||||
err := self.DeletePublicipTag(self.ID, k)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "remove tags")
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(tags) > 0 {
|
||||
params := map[string]interface{}{
|
||||
"action": "create",
|
||||
}
|
||||
add := []map[string]string{}
|
||||
for k, v := range tags {
|
||||
add = append(add, map[string]string{"key": k, "value": v})
|
||||
}
|
||||
params["tags"] = add
|
||||
url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/publicips/%s/tags/action", self.ID, self.client.projectId, id)
|
||||
_, err := self.client.request(httputils.POST, url, nil, params)
|
||||
err := self.CreatePublicipTag(self.ID, tags)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "add tags")
|
||||
}
|
||||
|
||||
+5
-27
@@ -17,9 +17,6 @@ package huawei
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
@@ -60,35 +57,16 @@ func (self *SElasticcacheAccount) GetAccountPrivilege() string {
|
||||
return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html
|
||||
// 未找到关闭密码的开放api, 不支持开启/关闭密码访问
|
||||
// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset
|
||||
// new_password: "26db46e2!"
|
||||
// no_password_access: false
|
||||
func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error {
|
||||
if input.OldPassword == nil {
|
||||
return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty")
|
||||
}
|
||||
|
||||
type ResetPasswordResult struct {
|
||||
Result string `json:"result"`
|
||||
Message string `json:"message"`
|
||||
params := map[string]interface{}{
|
||||
"old_password": *input.OldPassword,
|
||||
"new_password": input.NewPassword,
|
||||
}
|
||||
|
||||
result := ResetPasswordResult{}
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("old_password", jsonutils.NewString(*input.OldPassword))
|
||||
params.Set("new_password", jsonutils.NewString(input.NewPassword))
|
||||
err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcacheAccount.ResetPassword")
|
||||
}
|
||||
|
||||
if result.Result != "success" {
|
||||
return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword")
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.cacheDB.region.put(SERVICE_DCS, fmt.Sprintf("instances/%s/password", self.cacheDB.InstanceID), params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error {
|
||||
|
||||
+5
-6
@@ -15,6 +15,7 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -127,12 +128,10 @@ func (self *SElasticcacheBackup) Delete() error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html
|
||||
func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error {
|
||||
_, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId())
|
||||
if err != nil {
|
||||
return nil
|
||||
params := map[string]interface{}{
|
||||
"backup_id": self.BackupID,
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.cacheDB.region.post(SERVICE_DCS, fmt.Sprintf("instances/%s/restores", self.cacheDB.InstanceID), params)
|
||||
return err
|
||||
}
|
||||
|
||||
+198
-285
@@ -16,7 +16,7 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html
|
||||
type SElasticcache struct {
|
||||
multicloud.SElasticcacheBase
|
||||
HuaweiTags
|
||||
@@ -162,21 +161,18 @@ func (self *SElasticcache) GetCreatedAt() time.Time {
|
||||
}
|
||||
|
||||
func (self *SElasticcache) GetExpiredAt() time.Time {
|
||||
var expiredTime time.Time
|
||||
if self.ChargingMode == 1 {
|
||||
res, err := self.region.GetOrderResourceDetail(self.GetId())
|
||||
if err != nil {
|
||||
log.Debugln(err)
|
||||
}
|
||||
|
||||
expiredTime = res.ExpireTime
|
||||
orders, err := self.region.client.GetOrderResources()
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
return expiredTime
|
||||
order, ok := orders[self.InstanceID]
|
||||
if ok {
|
||||
return order.ExpireTime
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (self *SElasticcache) GetInstanceType() string {
|
||||
// todo: ??
|
||||
return self.ResourceSpecCode
|
||||
}
|
||||
|
||||
@@ -185,33 +181,27 @@ func (self *SElasticcache) GetCapacityMB() int {
|
||||
}
|
||||
|
||||
func (self *SElasticcache) GetArchType() string {
|
||||
/*
|
||||
资源规格标识。
|
||||
|
||||
dcs.single_node:表示实例类型为单机
|
||||
dcs.master_standby:表示实例类型为主备
|
||||
dcs.cluster:表示实例类型为集群
|
||||
*/
|
||||
if strings.Contains(self.ResourceSpecCode, "single") {
|
||||
return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE
|
||||
} else if strings.Contains(self.ResourceSpecCode, "ha") {
|
||||
}
|
||||
if strings.Contains(self.ResourceSpecCode, "ha") {
|
||||
return api.ELASTIC_CACHE_ARCH_TYPE_MASTER
|
||||
} else if strings.Contains(self.ResourceSpecCode, "cluster") {
|
||||
return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER
|
||||
} else if strings.Contains(self.ResourceSpecCode, "proxy") {
|
||||
}
|
||||
if strings.Contains(self.ResourceSpecCode, "cluster") {
|
||||
return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER
|
||||
}
|
||||
|
||||
return ""
|
||||
if strings.Contains(self.ResourceSpecCode, "proxy") {
|
||||
return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER
|
||||
}
|
||||
return self.ResourceSpecCode
|
||||
}
|
||||
|
||||
func (self *SElasticcache) GetNodeType() string {
|
||||
// single(单副本) | double(双副本)
|
||||
if strings.Contains(self.ResourceSpecCode, "single") {
|
||||
return "single"
|
||||
} else {
|
||||
return "double"
|
||||
}
|
||||
return "double"
|
||||
}
|
||||
|
||||
func (self *SElasticcache) GetEngine() string {
|
||||
@@ -324,69 +314,83 @@ func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.IC
|
||||
return iparameters, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html
|
||||
func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) {
|
||||
params := make(map[string]string)
|
||||
params["instance_id"] = instanceId
|
||||
params["beginTime"] = startTime
|
||||
params["endTime"] = endTime
|
||||
params := url.Values{}
|
||||
params.Set("begin_time", startTime)
|
||||
params.Set("end_time", endTime)
|
||||
|
||||
backups := make([]SElasticcacheBackup, 0)
|
||||
err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return backups, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html
|
||||
func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) {
|
||||
params := make(map[string]string)
|
||||
params["instance_id"] = instanceId
|
||||
|
||||
parameters := make([]SElasticcacheParameter, 0)
|
||||
err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parameters, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html
|
||||
func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) {
|
||||
params := make(map[string]string)
|
||||
caches := make([]SElasticcache, 0)
|
||||
err := doListAll(self.ecsClient.Elasticcache.List, params, &caches)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.GetElasticCaches")
|
||||
}
|
||||
|
||||
for i := range caches {
|
||||
cache, err := self.GetElasticCache(caches[i].GetId())
|
||||
ret := make([]SElasticcacheBackup, 0)
|
||||
for {
|
||||
resp, err := self.list(SERVICE_DCS, fmt.Sprintf("instances/%s/backups", instanceId), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
caches[i] = *cache
|
||||
}
|
||||
|
||||
caches[i].region = self
|
||||
part := struct {
|
||||
BackupRecordResponse []SElasticcacheBackup
|
||||
TotalNum int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.BackupRecordResponse...)
|
||||
if len(ret) >= part.TotalNum || len(part.BackupRecordResponse) == 0 {
|
||||
break
|
||||
}
|
||||
params.Set("offset", fmt.Sprintf("%d", len(ret)))
|
||||
}
|
||||
|
||||
return caches, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html
|
||||
func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) {
|
||||
cache := SElasticcache{}
|
||||
err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache)
|
||||
func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) {
|
||||
resp, err := self.list(SERVICE_DCS, fmt.Sprintf("instances/%s/configs", instanceId), nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId)
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]SElasticcacheParameter, 0)
|
||||
err = resp.Unmarshal(&ret, "redis_config")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
cache.region = self
|
||||
return &cache, nil
|
||||
func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) {
|
||||
ret := make([]SElasticcache, 0)
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_DCS, "instances", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Instances []SElasticcache
|
||||
InstanceNum int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Instances...)
|
||||
if len(ret) >= part.InstanceNum || len(part.Instances) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("offset", fmt.Sprintf("%d", len(ret)))
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) {
|
||||
resp, err := self.list(SERVICE_DCS, "instances/"+instanceId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := &SElasticcache{region: self}
|
||||
err = resp.Unmarshal(ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) {
|
||||
@@ -398,188 +402,124 @@ func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasti
|
||||
return ec, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html
|
||||
func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) {
|
||||
type Z struct {
|
||||
ID string `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Port string `json:"port"`
|
||||
ResourceAvailability string `json:"resource_availability"`
|
||||
}
|
||||
|
||||
rs := []Z{}
|
||||
err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds")
|
||||
}
|
||||
|
||||
zoneMap := map[string]string{}
|
||||
for i := range rs {
|
||||
if rs[i].ResourceAvailability == "true" {
|
||||
zoneMap[rs[i].Code] = rs[i].ID
|
||||
}
|
||||
}
|
||||
|
||||
ret := []string{}
|
||||
for _, zone := range zoneIds {
|
||||
if id, ok := zoneMap[zone]; ok {
|
||||
ret = append(ret, id)
|
||||
} else {
|
||||
return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds")
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html
|
||||
func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("name", jsonutils.NewString(ec.InstanceName))
|
||||
params.Set("engine", jsonutils.NewString(ec.Engine))
|
||||
params.Set("engine_version", jsonutils.NewString(ec.EngineVersion))
|
||||
params.Set("capacity", jsonutils.NewInt(ec.CapacityGB))
|
||||
params.Set("vpc_id", jsonutils.NewString(ec.VpcId))
|
||||
if len(ec.SecurityGroupIds) > 0 {
|
||||
params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0]))
|
||||
}
|
||||
params.Set("subnet_id", jsonutils.NewString(ec.NetworkId))
|
||||
params.Set("product_id", jsonutils.NewString(ec.InstanceType))
|
||||
zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds)
|
||||
func (self *SRegion) CreateIElasticcaches(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) {
|
||||
ret, err := self.CreateElasticcache(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params.Set("available_zones", jsonutils.NewStringArray(zones))
|
||||
|
||||
if len(ec.ProjectId) > 0 {
|
||||
params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId))
|
||||
}
|
||||
|
||||
if len(ec.Password) > 0 {
|
||||
params.Set("no_password_access", jsonutils.NewString("false"))
|
||||
params.Set("password", jsonutils.NewString(ec.Password))
|
||||
|
||||
// todo: 这里换成常量
|
||||
if ec.Engine == "Memcache" {
|
||||
params.Set("access_user", jsonutils.NewString(ec.UserName))
|
||||
}
|
||||
} else {
|
||||
params.Set("no_password_access", jsonutils.NewString("true"))
|
||||
}
|
||||
|
||||
if len(ec.EipId) > 0 {
|
||||
params.Set("enable_publicip", jsonutils.NewString("true"))
|
||||
params.Set("publicip_id", jsonutils.NewString(ec.EipId))
|
||||
// enable_ssl
|
||||
} else {
|
||||
params.Set("enable_publicip", jsonutils.NewString("false"))
|
||||
}
|
||||
|
||||
if len(ec.PrivateIpAddress) > 0 {
|
||||
params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress))
|
||||
}
|
||||
|
||||
if len(ec.MaintainBegin) > 0 {
|
||||
params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin))
|
||||
params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd))
|
||||
}
|
||||
|
||||
if ec.BillingCycle != nil {
|
||||
bssParam := jsonutils.NewDict()
|
||||
bssParam.Set("charging_mode", jsonutils.NewString("prePaid"))
|
||||
bssParam.Set("is_auto_pay", jsonutils.NewString("true"))
|
||||
bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew)))
|
||||
if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 {
|
||||
bssParam.Set("period_type", jsonutils.NewString("month"))
|
||||
bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths())))
|
||||
} else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 {
|
||||
bssParam.Set("period_type", jsonutils.NewString("year"))
|
||||
bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears())))
|
||||
} else {
|
||||
return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)")
|
||||
}
|
||||
|
||||
params.Set("bss_param", bssParam)
|
||||
}
|
||||
|
||||
ret := &SElasticcache{}
|
||||
err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.CreateIElasticcaches")
|
||||
}
|
||||
|
||||
ret.region = self
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html
|
||||
func (self *SElasticcache) Restart() error {
|
||||
resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.Restart")
|
||||
func (self *SRegion) CreateElasticcache(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) {
|
||||
params := map[string]interface{}{
|
||||
"name": opts.InstanceName,
|
||||
"engine": opts.Engine,
|
||||
"engine_version": opts.EngineVersion,
|
||||
"capacity": opts.CapacityGB,
|
||||
"vpc_id": opts.VpcId,
|
||||
"subnet_id": opts.NetworkId,
|
||||
"product_id": opts.InstanceType,
|
||||
"zone_codes": opts.ZoneIds,
|
||||
"no_password_access": true,
|
||||
"enable_publicip": false,
|
||||
}
|
||||
if len(opts.SecurityGroupIds) > 0 {
|
||||
params["security_group_id"] = opts.SecurityGroupIds[0]
|
||||
}
|
||||
|
||||
rets, err := resp.GetArray("results")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.results")
|
||||
if len(opts.ProjectId) > 0 {
|
||||
params["enterprise_project_id"] = opts.ProjectId
|
||||
}
|
||||
|
||||
for _, r := range rets {
|
||||
if ret, _ := r.GetString("result"); ret != "success" {
|
||||
return fmt.Errorf("elasticcache.Restart failed")
|
||||
if len(opts.Password) > 0 {
|
||||
params["no_password_access"] = false
|
||||
params["password"] = opts.Password
|
||||
|
||||
if opts.Engine == "Memcache" {
|
||||
params["access_user"] = opts.UserName
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
if len(opts.EipId) > 0 {
|
||||
params["enable_publicip"] = true
|
||||
params["publicip_id"] = opts.EipId
|
||||
}
|
||||
|
||||
if len(opts.PrivateIpAddress) > 0 {
|
||||
params["private_ip"] = opts.PrivateIpAddress
|
||||
}
|
||||
|
||||
if len(opts.MaintainBegin) > 0 {
|
||||
params["maintain_begin"] = opts.MaintainBegin
|
||||
params["maintain_end"] = opts.MaintainEnd
|
||||
}
|
||||
|
||||
if opts.BillingCycle != nil {
|
||||
bssParam := map[string]interface{}{
|
||||
"charging_mode": "prePaid",
|
||||
"is_auto_pay": true,
|
||||
"is_auto_renew": opts.BillingCycle.AutoRenew,
|
||||
}
|
||||
if opts.BillingCycle.GetMonths() >= 1 && opts.BillingCycle.GetMonths() >= 9 {
|
||||
bssParam["period_type"] = "month"
|
||||
bssParam["period_num"] = opts.BillingCycle.GetMonths()
|
||||
} else if opts.BillingCycle.GetYears() >= 1 && opts.BillingCycle.GetYears() <= 3 {
|
||||
bssParam["period_type"] = "year"
|
||||
bssParam["period_num"] = opts.BillingCycle.GetYears()
|
||||
} else {
|
||||
return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)")
|
||||
}
|
||||
params["bss_param"] = bssParam
|
||||
}
|
||||
resp, err := self.post(SERVICE_DCS, "instances", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := struct {
|
||||
OrderId string
|
||||
Instances []SElasticcache
|
||||
}{}
|
||||
err = resp.Unmarshal(&ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range ret.Instances {
|
||||
ret.Instances[i].region = self
|
||||
return &ret.Instances[i], nil
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after created %s", resp.String())
|
||||
}
|
||||
|
||||
func (self *SElasticcache) Restart() error {
|
||||
params := map[string]interface{}{
|
||||
"instances": []string{self.InstanceID},
|
||||
"action": "restart",
|
||||
}
|
||||
_, err := self.region.put(SERVICE_DCS, "instances/status", params)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html
|
||||
func (self *SElasticcache) Delete() error {
|
||||
err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.Delete")
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.delete(SERVICE_DCS, "instances/"+self.GetId())
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html
|
||||
func (self *SElasticcache) ChangeInstanceSpec(spec string) error {
|
||||
segs := strings.Split(spec, ":")
|
||||
if len(segs) < 2 {
|
||||
return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec)
|
||||
params := map[string]interface{}{
|
||||
"spec_code": spec,
|
||||
"new_capacity": self.CapacityGB,
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") {
|
||||
return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec)
|
||||
}
|
||||
|
||||
newCapacity := segs[1][1 : len(segs[1])-1]
|
||||
capacity, err := strconv.Atoi(newCapacity)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec")
|
||||
}
|
||||
|
||||
_, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.ChangeInstanceSpec")
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.post(SERVICE_DCS, fmt.Sprintf("instances/%s/resize", self.InstanceID), params)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html
|
||||
func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("maintain_begin", jsonutils.NewString(maintainStartTime))
|
||||
params.Set("maintain_end", jsonutils.NewString(maintainEndTime))
|
||||
err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.SetMaintainTime")
|
||||
params := map[string]interface{}{
|
||||
"maintain_begin": maintainStartTime,
|
||||
"maintain_end": maintainEndTime,
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.put(SERVICE_DCS, "instances/"+self.InstanceID, params)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html
|
||||
@@ -598,22 +538,16 @@ func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCach
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html
|
||||
|
||||
func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html
|
||||
func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("redis_config", config)
|
||||
err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.UpdateInstanceParameters")
|
||||
params := map[string]interface{}{
|
||||
"redis_config": config,
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.put(SERVICE_DCS, fmt.Sprintf("instances/%s/async-configs", self.InstanceID), params)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html
|
||||
@@ -646,48 +580,27 @@ func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdate
|
||||
return ret
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html
|
||||
func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error {
|
||||
params := jsonutils.NewDict()
|
||||
policy := jsonutils.NewDict()
|
||||
policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays)))
|
||||
policy.Set("backup_type", jsonutils.NewString(config.BackupType))
|
||||
plan := jsonutils.NewDict()
|
||||
backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "")
|
||||
backupPeriod := backupPeriodTrans(config)
|
||||
plan.Set("begin_at", jsonutils.NewString(backTime))
|
||||
plan.Set("period_type", jsonutils.NewString("weekly"))
|
||||
plan.Set("backup_at", backupPeriod)
|
||||
policy.Set("periodical_backup_plan", plan)
|
||||
params.Set("instance_backup_policy", policy)
|
||||
err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.UpdateInstanceParameters")
|
||||
func (self *SElasticcache) UpdateBackupPolicy(opts cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error {
|
||||
params := map[string]interface{}{
|
||||
"save_days": opts.BackupReservedDays,
|
||||
"backup_type": opts.BackupType,
|
||||
"periodical_backup_plan": map[string]interface{}{
|
||||
"begin_at": strings.ReplaceAll(opts.PreferredBackupTime, "Z", ""),
|
||||
"period_type": "weekly",
|
||||
"backup_at": backupPeriodTrans(opts),
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.put(SERVICE_DCS, "instances/"+self.InstanceID, map[string]interface{}{"instance_backup_policy": params})
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html
|
||||
// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。
|
||||
func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error {
|
||||
resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.FlushInstance")
|
||||
params := map[string]interface{}{
|
||||
"instances": []string{self.InstanceID},
|
||||
"action": "flush",
|
||||
}
|
||||
|
||||
rets, err := resp.GetArray("results")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "elasticcache.FlushInstance")
|
||||
}
|
||||
|
||||
for _, r := range rets {
|
||||
if ret, _ := r.GetString("result"); ret != "success" {
|
||||
return fmt.Errorf("elasticcache.FlushInstance failed")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := self.region.put(SERVICE_DCS, "instances/status", params)
|
||||
return err
|
||||
}
|
||||
|
||||
// SElasticcacheAccount => ResetPassword
|
||||
|
||||
+28
-20
@@ -15,10 +15,11 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
|
||||
// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html
|
||||
type SEnterpriseProject struct {
|
||||
multicloud.SProjectBase
|
||||
HuaweiTags
|
||||
@@ -40,16 +40,28 @@ type SEnterpriseProject struct {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) {
|
||||
projects := []SEnterpriseProject{}
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
ret := []SEnterpriseProject{}
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_EPS, "", "enterprise-projects", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list")
|
||||
}
|
||||
part := struct {
|
||||
EnterpriseProjects []SEnterpriseProject
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.EnterpriseProjects...)
|
||||
if len(part.EnterpriseProjects) == 0 || len(ret) > part.TotalCount {
|
||||
break
|
||||
}
|
||||
query.Set("offset", fmt.Sprintf("%d", len(ret)))
|
||||
}
|
||||
err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doListAllWithOffset")
|
||||
}
|
||||
return projects, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ep *SEnterpriseProject) GetId() string {
|
||||
@@ -72,17 +84,13 @@ func (ep *SEnterpriseProject) GetName() string {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) {
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newGeneralAPIClient")
|
||||
}
|
||||
params := map[string]string{
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
}
|
||||
if len(desc) > 0 {
|
||||
params["description"] = desc
|
||||
}
|
||||
resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params))
|
||||
resp, err := self.post(SERVICE_EPS, "", "enterprise-projects", params)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "EPS.0004") {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
@@ -92,12 +100,12 @@ func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpr
|
||||
}
|
||||
return nil, errors.Wrap(err, "EnterpriseProjects.Create")
|
||||
}
|
||||
project := &SEnterpriseProject{}
|
||||
err = resp.Unmarshal(&project)
|
||||
ret := &SEnterpriseProject{}
|
||||
err = resp.Unmarshal(&ret, "enterprise_project")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return project, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) {
|
||||
|
||||
+47
-104
@@ -16,13 +16,11 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/billing"
|
||||
"yunion.io/x/pkg/util/osprofile"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
@@ -61,30 +59,28 @@ func (self *SHost) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := self.zone.region.GetInstances()
|
||||
vms, err := self.zone.region.GetInstances("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filtedVms := make([]SInstance, 0)
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() {
|
||||
filtedVms = append(filtedVms, vms[i])
|
||||
vms[i].host = self
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
}
|
||||
|
||||
ivms := make([]cloudprovider.ICloudVM, len(filtedVms))
|
||||
for i := 0; i < len(filtedVms); i += 1 {
|
||||
filtedVms[i].host = self
|
||||
ivms[i] = &filtedVms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
vm, err := self.zone.region.GetInstanceByID(id)
|
||||
vm, err := self.zone.region.GetInstance(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.host = self
|
||||
return &vm, err
|
||||
return vm, err
|
||||
}
|
||||
|
||||
func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
@@ -161,35 +157,29 @@ func (self *SHost) GetVersion() string {
|
||||
return HUAWEI_API_VERSION
|
||||
}
|
||||
|
||||
func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
|
||||
instance, err := self.zone.region.GetInstanceByID(instanceId)
|
||||
func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
vmId, err := self._createVM(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance.host = self
|
||||
return &instance, nil
|
||||
}
|
||||
cloudprovider.Wait(time.Second*5, time.Minute, func() (bool, error) {
|
||||
_, err := self.zone.region.GetInstance(vmId)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
})
|
||||
|
||||
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
vmId, err := self._createVM(
|
||||
desc.Name, desc.ExternalImageId, desc.SysDisk,
|
||||
desc.Cpu, desc.MemoryMB, desc.InstanceType,
|
||||
desc.ExternalNetworkId, desc.IpAddr,
|
||||
desc.Description, desc.Account,
|
||||
desc.Password, desc.DataDisks,
|
||||
desc.PublicKey, desc.ExternalSecgroupIds,
|
||||
desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags)
|
||||
vm, err := self.zone.region.GetInstance(vmId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vm, err := self.GetInstanceById(vmId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vm, err
|
||||
vm.host = self
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
|
||||
@@ -200,102 +190,55 @@ func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error
|
||||
return cloudprovider.GetHostNetifs(host, wires), nil
|
||||
}
|
||||
|
||||
func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string,
|
||||
networkId string, ipAddr string, desc string, account string, passwd string,
|
||||
diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupIds []string,
|
||||
userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) {
|
||||
net := self.zone.getNetworkById(networkId)
|
||||
if net == nil {
|
||||
return "", fmt.Errorf("invalid network ID %s", networkId)
|
||||
}
|
||||
|
||||
if net.wire == nil {
|
||||
log.Errorf("network's wire is empty")
|
||||
return "", fmt.Errorf("network's wire is empty")
|
||||
}
|
||||
|
||||
if net.wire.vpc == nil {
|
||||
log.Errorf("wire's vpc is empty")
|
||||
return "", fmt.Errorf("wire's vpc is empty")
|
||||
}
|
||||
|
||||
func (self *SHost) _createVM(opts *cloudprovider.SManagedVMCreateConfig) (string, error) {
|
||||
// 同步keypair
|
||||
var err error
|
||||
keypair := ""
|
||||
if len(publicKey) > 0 {
|
||||
keypair, err = self.zone.region.syncKeypair(publicKey)
|
||||
var err error
|
||||
if len(opts.PublicKey) > 0 {
|
||||
keypair, err = self.zone.region.syncKeypair(opts.PublicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// 镜像及硬盘配置
|
||||
img, err := self.zone.region.GetImage(imgId)
|
||||
img, err := self.zone.region.GetImage(opts.ExternalImageId)
|
||||
if err != nil {
|
||||
log.Errorf("getiamge %s fail %s", imgId, err)
|
||||
return "", err
|
||||
return "", errors.Wrapf(err, "GetImage")
|
||||
}
|
||||
if img.Status != ImageStatusActive {
|
||||
log.Errorf("image %s status %s", imgId, img.Status)
|
||||
return "", fmt.Errorf("image not ready")
|
||||
}
|
||||
// passwd, windows机型直接使用密码比较方便
|
||||
if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 {
|
||||
keypair = ""
|
||||
}
|
||||
|
||||
if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) {
|
||||
if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil {
|
||||
userData = u
|
||||
} else {
|
||||
return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData")
|
||||
}
|
||||
}
|
||||
|
||||
disks := make([]SDisk, len(diskSizes)+1)
|
||||
disks[0].SizeGB = img.SizeGB
|
||||
if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB {
|
||||
disks[0].SizeGB = sysDisk.SizeGB
|
||||
}
|
||||
disks[0].VolumeType = sysDisk.StorageType
|
||||
|
||||
for i, dataDisk := range diskSizes {
|
||||
disks[i+1].SizeGB = dataDisk.SizeGB
|
||||
disks[i+1].VolumeType = dataDisk.StorageType
|
||||
if img.SizeGB > opts.SysDisk.SizeGB {
|
||||
opts.SysDisk.SizeGB = img.SizeGB
|
||||
}
|
||||
|
||||
// 创建实例
|
||||
if len(instanceType) > 0 {
|
||||
log.Debugf("Try instancetype : %s", instanceType)
|
||||
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupIds, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags)
|
||||
if len(opts.InstanceType) > 0 {
|
||||
log.Debugf("Try instancetype : %s", opts.InstanceType)
|
||||
vmId, err := self.zone.region.CreateInstance(keypair, self.zone.ZoneName, opts)
|
||||
if err != nil {
|
||||
log.Errorf("Failed for %s: %s", instanceType, err)
|
||||
return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err))
|
||||
} else {
|
||||
return vmId, nil
|
||||
return "", errors.Wrapf(err, "CreateInstance")
|
||||
}
|
||||
return vmId, nil
|
||||
}
|
||||
|
||||
// 匹配实例类型
|
||||
instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId())
|
||||
instanceTypes, err := self.zone.region.GetMatchInstanceTypes(opts.Cpu, opts.MemoryMB, self.zone.GetId())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(instanceTypes) == 0 {
|
||||
return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB)
|
||||
return "", fmt.Errorf("instance type %dC%dMB not avaiable", opts.Cpu, opts.MemoryMB)
|
||||
}
|
||||
|
||||
var vmId string
|
||||
for _, instType := range instanceTypes {
|
||||
instanceTypeId := instType.Name
|
||||
log.Debugf("Try instancetype : %s", instanceTypeId)
|
||||
vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupIds, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags)
|
||||
opts.InstanceType = instType.Name
|
||||
log.Debugf("Try instancetype : %s", opts.InstanceType)
|
||||
vmId, err = self.zone.region.CreateInstance(keypair, self.zone.ZoneName, opts)
|
||||
if err != nil {
|
||||
log.Errorf("Failed for %s: %s", instanceTypeId, err)
|
||||
} else {
|
||||
return vmId, nil
|
||||
log.Errorf("Failed for %s: %s", opts.InstanceType, err)
|
||||
}
|
||||
return vmId, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("create failed: %s", ErrMessage(err))
|
||||
return "", errors.Wrapf(err, "CreateInstance")
|
||||
}
|
||||
|
||||
+66
-131
@@ -35,20 +35,9 @@ import (
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/obs"
|
||||
)
|
||||
|
||||
/*
|
||||
待解决问题:
|
||||
1.同步的子账户中有一条空记录.需要查原因
|
||||
2.安全组同步需要进一步确认
|
||||
3.实例接口需要进一步确认
|
||||
4.BGP type 目前是hard code在代码中。需要考虑从cloudmeta服务中查询
|
||||
*/
|
||||
|
||||
const (
|
||||
CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HUAWEI
|
||||
CLOUD_PROVIDER_HUAWEI_CN = "华为云"
|
||||
@@ -62,13 +51,21 @@ const (
|
||||
HUAWEI_API_VERSION = "2018-12-25"
|
||||
|
||||
SERVICE_IAM = "iam"
|
||||
SERVICE_IAM_V3 = "iam_v3"
|
||||
SERVICE_IAM_V3_EXT = "iam_v3_ext"
|
||||
SERVICE_ELB = "elb"
|
||||
SERVICE_VPC = "vpc"
|
||||
SERVICE_VPC_V2_0 = "vpc_v2.0"
|
||||
SERVICE_VPC_V3 = "vpc_v3"
|
||||
SERVICE_CES = "ces"
|
||||
SERVICE_RDS = "rds"
|
||||
SERVICE_ECS = "ecs"
|
||||
SERVICE_ECS_V1_1 = "ecs_v1.1"
|
||||
SERVICE_ECS_V2_1 = "ecs_v2.1"
|
||||
SERVICE_EPS = "eps"
|
||||
SERVICE_EVS = "evs"
|
||||
SERVICE_EVS_V1 = "evs_v1"
|
||||
SERVICE_EVS_V2_1 = "evs_v2.1"
|
||||
SERVICE_BSS = "bss"
|
||||
SERVICE_SFS = "sfs-turbo"
|
||||
SERVICE_CTS = "cts"
|
||||
@@ -77,10 +74,12 @@ const (
|
||||
SERVICE_CCI = "cci"
|
||||
SERVICE_CSBS = "csbs"
|
||||
SERVICE_IMS = "ims"
|
||||
SERVICE_IMS_V1 = "ims_v1"
|
||||
SERVICE_AS = "as"
|
||||
SERVICE_CCE = "cce"
|
||||
SERVICE_DCS = "dcs"
|
||||
SERVICE_MODELARTS = "modelarts"
|
||||
SERVICE_MODELARTS_V1 = "modelarts_v1"
|
||||
SERVICE_SCM = "scm"
|
||||
SERVICE_CDN = "cdn"
|
||||
SERVICE_GAUSSDB = "gaussdb"
|
||||
@@ -100,17 +99,15 @@ type HuaweiClientConfig struct {
|
||||
cpcfg cloudprovider.ProviderConfig
|
||||
|
||||
projectId string // 华为云项目ID.
|
||||
cloudEnv string // 服务区域 ChinaCloud | InternationalCloud
|
||||
accessKey string
|
||||
accessSecret string
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
func NewHuaweiClientConfig(cloudEnv, accessKey, accessSecret, projectId string) *HuaweiClientConfig {
|
||||
func NewHuaweiClientConfig(accessKey, accessSecret, projectId string) *HuaweiClientConfig {
|
||||
cfg := &HuaweiClientConfig{
|
||||
projectId: projectId,
|
||||
cloudEnv: cloudEnv,
|
||||
accessKey: accessKey,
|
||||
accessSecret: accessSecret,
|
||||
}
|
||||
@@ -130,8 +127,6 @@ func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig {
|
||||
type SHuaweiClient struct {
|
||||
*HuaweiClientConfig
|
||||
|
||||
signer auth.Signer
|
||||
|
||||
isMainProject bool // whether the project is the main project in the region
|
||||
clientRegion string
|
||||
|
||||
@@ -147,6 +142,8 @@ type SHuaweiClient struct {
|
||||
regions []SRegion
|
||||
|
||||
httpClient *http.Client
|
||||
|
||||
orders map[string]SOrderResource
|
||||
}
|
||||
|
||||
// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。
|
||||
@@ -169,10 +166,6 @@ func (self *SHuaweiClient) init() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = self.initSigner()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initSigner")
|
||||
}
|
||||
err = self.initOwner()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetchOwner")
|
||||
@@ -183,16 +176,6 @@ func (self *SHuaweiClient) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) initSigner() error {
|
||||
var err error
|
||||
cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey)
|
||||
self.signer, err = auth.NewSignerWithCredential(cred)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) getDefaultClient() *http.Client {
|
||||
if self.httpClient != nil {
|
||||
return self.httpClient
|
||||
@@ -221,30 +204,10 @@ func (self *SHuaweiClient) getDefaultClient() *http.Client {
|
||||
return self.httpClient
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) {
|
||||
projectId := self.projectId
|
||||
if len(regionId) == 0 {
|
||||
projectId = ""
|
||||
}
|
||||
cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, projectId, self.accessKey, self.accessSecret, self.debug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClient := self.getDefaultClient()
|
||||
cli.SetHttpClient(httpClient)
|
||||
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
type sPageInfo struct {
|
||||
NextMarker string
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) {
|
||||
return self.newRegionAPIClient("")
|
||||
}
|
||||
|
||||
type akClient struct {
|
||||
client *http.Client
|
||||
aksk aksk.SignOptions
|
||||
@@ -287,6 +250,7 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que
|
||||
}
|
||||
if (strings.Contains(url, "/OS-CREDENTIAL/") ||
|
||||
strings.Contains(url, "/users") ||
|
||||
strings.Contains(url, "/groups") ||
|
||||
strings.Contains(url, "eps.myhuaweicloud.com")) && len(self.ownerId) > 0 {
|
||||
header.Set("X-Domain-Id", self.ownerId)
|
||||
}
|
||||
@@ -300,8 +264,8 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListRegions
|
||||
func (self *SHuaweiClient) fetchRegions() error {
|
||||
huawei, _ := self.newGeneralAPIClient()
|
||||
if self.regions == nil {
|
||||
userId, err := self.GetUserId()
|
||||
if err != nil {
|
||||
@@ -309,12 +273,15 @@ func (self *SHuaweiClient) fetchRegions() error {
|
||||
}
|
||||
|
||||
if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); !ok || regionsCache.(*userRegionsCache).ExpireAt.Sub(time.Now()).Seconds() > 0 {
|
||||
regions := make([]SRegion, 0)
|
||||
err := doListAll(huawei.Regions.List, nil, ®ions)
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", "regions", nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Regions.List")
|
||||
return errors.Wrapf(err, "list regions")
|
||||
}
|
||||
regions := make([]SRegion, 0)
|
||||
err = resp.Unmarshal(®ions, "regions")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
|
||||
HUAWEI_REGION_CACHES.Store(userId, &userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions})
|
||||
}
|
||||
|
||||
@@ -350,10 +317,6 @@ func (self *SHuaweiClient) fetchRegions() error {
|
||||
self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions))
|
||||
for i := 0; i < len(filtedRegions); i += 1 {
|
||||
filtedRegions[i].client = self
|
||||
_, err := filtedRegions[i].getECSClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.iregions[i] = &filtedRegions[i]
|
||||
}
|
||||
return nil
|
||||
@@ -448,16 +411,6 @@ func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error {
|
||||
if self.accessKey != accessKey || self.accessSecret != secret {
|
||||
self.accessKey = accessKey
|
||||
self.accessSecret = secret
|
||||
return self.fetchRegions()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
for i := 0; i < len(regions); i += 1 {
|
||||
@@ -597,7 +550,6 @@ func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStora
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/BSS/debug?api=ShowCustomerAccountBalances
|
||||
type SBalance struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
@@ -608,7 +560,7 @@ type SBalance struct {
|
||||
MeasureUnit int64 `json:"measure_unit"`
|
||||
}
|
||||
|
||||
// 这里的余额指的是所有租户的总余额
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/BSS/doc?api=ShowCustomerAccountBalances
|
||||
func (self *SHuaweiClient) QueryAccountBalance() (*SBalance, error) {
|
||||
resp, err := self.list(SERVICE_BSS, "", "accounts/customer-accounts/balances", nil)
|
||||
if err != nil {
|
||||
@@ -645,17 +597,6 @@ func (self *SHuaweiClient) GetVersion() string {
|
||||
return HUAWEI_API_VERSION
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetAccessEnv() string {
|
||||
switch self.cloudEnv {
|
||||
case HUAWEI_INTERNATIONAL_CLOUDENV:
|
||||
return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL
|
||||
case HUAWEI_CHINA_CLOUDENV:
|
||||
return api.CLOUD_ACCESS_ENV_HUAWEI_CHINA
|
||||
default:
|
||||
return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetCapabilities() []string {
|
||||
caps := []string{
|
||||
cloudprovider.CLOUD_CAPABILITY_PROJECT,
|
||||
@@ -686,54 +627,56 @@ func (self *SHuaweiClient) GetCapabilities() []string {
|
||||
return caps
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ShowPermanentAccessKey
|
||||
func (self *SHuaweiClient) GetUserId() (string, error) {
|
||||
if len(self.userId) > 0 {
|
||||
return self.userId, nil
|
||||
}
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient")
|
||||
}
|
||||
|
||||
type cred struct {
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
|
||||
ret := &cred{}
|
||||
err = DoGet(client.Credentials.Get, self.accessKey, nil, ret)
|
||||
resp, err := self.list(SERVICE_IAM, "", "OS-CREDENTIAL/credentials/"+self.accessKey, nil)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet")
|
||||
return "", errors.Wrapf(err, "show credential")
|
||||
}
|
||||
err = resp.Unmarshal(ret, "credential")
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
self.userId = ret.UserId
|
||||
return self.userId, nil
|
||||
}
|
||||
|
||||
// owner id == domain_id == account id
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ShowUser
|
||||
func (self *SHuaweiClient) GetOwnerId() (string, error) {
|
||||
if len(self.ownerId) > 0 {
|
||||
return self.ownerId, nil
|
||||
}
|
||||
|
||||
userId, err := self.GetUserId()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId")
|
||||
}
|
||||
|
||||
client, err := self.newGeneralAPIClient()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient")
|
||||
}
|
||||
|
||||
type user struct {
|
||||
DomainId string `json:"domain_id"`
|
||||
Name string `json:"name"`
|
||||
CreateTime string
|
||||
}
|
||||
|
||||
ret := &user{}
|
||||
err = DoGet(client.Users.Get, userId, nil, ret)
|
||||
resp, err := self.list(SERVICE_IAM, "", "OS-USER/users/"+userId, nil)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet")
|
||||
return "", errors.Wrapf(err, "show user")
|
||||
}
|
||||
ret := &user{}
|
||||
err = resp.Unmarshal(ret, "user")
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
|
||||
self.ownerName = ret.Name
|
||||
// 2021-02-02 02:43:28.0
|
||||
self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0"))
|
||||
@@ -820,65 +763,57 @@ func (self *SHuaweiClient) getUrl(service, regionId, resource string, method htt
|
||||
switch service {
|
||||
case SERVICE_IAM:
|
||||
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3.0/%s", resource)
|
||||
if !strings.HasPrefix(resource, "OS-") {
|
||||
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3/%s", resource)
|
||||
}
|
||||
case SERVICE_IAM_V3:
|
||||
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3/%s", resource)
|
||||
case SERVICE_IAM_V3_EXT:
|
||||
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3-ext/%s", resource)
|
||||
case SERVICE_ELB:
|
||||
url = fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_VPC:
|
||||
version := "v1"
|
||||
if strings.HasPrefix(resource, "vpc/") || strings.HasPrefix(resource, "eip/") {
|
||||
version = "v3"
|
||||
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_VPC_V2_0:
|
||||
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/%s", regionId, self.projectId, resource)
|
||||
if strings.Contains(resource, "/peerings") {
|
||||
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s", regionId, resource)
|
||||
}
|
||||
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource)
|
||||
case SERVICE_VPC_V3:
|
||||
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_CES:
|
||||
url = fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_MODELARTS:
|
||||
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
|
||||
if strings.HasPrefix(resource, "networks") || strings.HasPrefix(resource, "resourceflavors") {
|
||||
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
}
|
||||
case SERVICE_MODELARTS_V1:
|
||||
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_RDS:
|
||||
url = fmt.Sprintf("https://rds.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_ECS:
|
||||
version := "v1"
|
||||
for _, prefix := range []string{
|
||||
"os-availability-zone",
|
||||
"servers",
|
||||
"os-keypairs",
|
||||
} {
|
||||
if strings.HasPrefix(resource, prefix) || strings.Contains(resource, "os-security-groups") {
|
||||
version = "v2.1"
|
||||
break
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(resource, "action") && !gotypes.IsNil(params) {
|
||||
for _, k := range []string{"addSecurityGroup", "removeSecurityGroup"} {
|
||||
_, ok := params[k]
|
||||
if ok {
|
||||
version = "v2.1"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource)
|
||||
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_ECS_V1_1:
|
||||
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1.1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_ECS_V2_1:
|
||||
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_EPS:
|
||||
url = fmt.Sprintf("https://eps.myhuaweicloud.com/v1.0/%s", resource)
|
||||
case SERVICE_EVS_V1:
|
||||
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_EVS:
|
||||
version := "v2"
|
||||
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource)
|
||||
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_EVS_V2_1:
|
||||
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_BSS:
|
||||
url = fmt.Sprintf("https://bss.myhuaweicloud.com/v2/%s", resource)
|
||||
case SERVICE_SFS:
|
||||
url = fmt.Sprintf("https://sfs-turbo.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_IMS:
|
||||
url = fmt.Sprintf("https://ims.%s.myhuaweicloud.com/v2/%s", regionId, resource)
|
||||
case SERVICE_IMS_V1:
|
||||
url = fmt.Sprintf("https://ims.%s.myhuaweicloud.com/v1/%s", regionId, resource)
|
||||
case SERVICE_DCS:
|
||||
url = fmt.Sprintf("https://dcs.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_CTS:
|
||||
url = fmt.Sprintf("https://cts.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_NAT:
|
||||
url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
|
||||
url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
|
||||
case SERVICE_SCM:
|
||||
url = fmt.Sprintf("https://scm.cn-north-4.myhuaweicloud.com/v3/%s", resource)
|
||||
case SERVICE_CDN:
|
||||
|
||||
+88
-147
@@ -17,6 +17,7 @@ package huawei
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -31,17 +32,6 @@ import (
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
|
||||
type TImageOwnerType string
|
||||
|
||||
const (
|
||||
ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold
|
||||
ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private
|
||||
ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared
|
||||
|
||||
EnvFusionCompute = "FusionCompute"
|
||||
EnvIronic = "Ironic"
|
||||
)
|
||||
|
||||
const (
|
||||
ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。
|
||||
ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。
|
||||
@@ -50,7 +40,6 @@ const (
|
||||
ImageStatusActive = "active" // active:表示镜像可以正常使用
|
||||
)
|
||||
|
||||
// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html
|
||||
type SImage struct {
|
||||
multicloud.SImageBase
|
||||
HuaweiTags
|
||||
@@ -141,11 +130,11 @@ func (self *SImage) GetImageStatus() string {
|
||||
}
|
||||
|
||||
func (self *SImage) Refresh() error {
|
||||
new, err := self.storageCache.region.GetImage(self.GetId())
|
||||
image, err := self.storageCache.region.GetImage(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
return jsonutils.Update(self, image)
|
||||
}
|
||||
|
||||
func (self *SImage) GetImageType() cloudprovider.TImageType {
|
||||
@@ -218,10 +207,6 @@ func (self *SImage) GetCreatedAt() time.Time {
|
||||
return self.CreatedAt
|
||||
}
|
||||
|
||||
func (self *SImage) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SImage) Delete(ctx context.Context) error {
|
||||
return self.storageCache.region.DeleteImage(self.GetId())
|
||||
}
|
||||
@@ -231,145 +216,101 @@ func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
|
||||
}
|
||||
|
||||
func (self *SRegion) GetImage(imageId string) (*SImage, error) {
|
||||
image := &SImage{}
|
||||
err := DoGet(self.ecsClient.Images.Get, imageId, nil, image)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DoGet")
|
||||
}
|
||||
return image, nil
|
||||
}
|
||||
|
||||
func excludeImage(image SImage) bool {
|
||||
if image.VirtualEnvType == "Ironic" {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportDiskIntensive) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportKVMGPUType) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportKVMNVMEHIGHIO) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportGPUT4) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportXENGPUType) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportHighPerformance) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(image.SupportArm) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html
|
||||
func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) {
|
||||
queries := map[string]string{}
|
||||
if len(status) > 0 {
|
||||
queries["status"] = status
|
||||
}
|
||||
|
||||
if len(imagetype) > 0 {
|
||||
queries["__imagetype"] = string(imagetype)
|
||||
if imagetype == ImageOwnerPublic {
|
||||
queries["protected"] = "True"
|
||||
}
|
||||
}
|
||||
if len(envType) > 0 {
|
||||
queries["virtual_env_type"] = envType
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
queries["name"] = name
|
||||
}
|
||||
|
||||
images := make([]SImage, 0)
|
||||
err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images)
|
||||
|
||||
// 排除掉需要特定镜像才能创建的实例类型
|
||||
// https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250
|
||||
// https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html
|
||||
filtedImages := make([]SImage, 0)
|
||||
for i := range images {
|
||||
if !excludeImage(images[i]) {
|
||||
filtedImages = append(filtedImages, images[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtedImages, err
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteImage(imageId string) error {
|
||||
return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetImageByName(name string) (*SImage, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, fmt.Errorf("image name should not be empty")
|
||||
}
|
||||
|
||||
images, err := self.GetImages("", TImageOwnerType(""), name, "")
|
||||
images, err := self.GetImages(imageId, "", "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(images) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
for i := range images {
|
||||
if images[i].ID == imageId {
|
||||
return &images[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("%d image found match name %s", len(images), name)
|
||||
return &images[0], nil
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, imageId)
|
||||
}
|
||||
|
||||
/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html
|
||||
os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html
|
||||
用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。
|
||||
目前支持vhd,zvhd、raw,qcow2
|
||||
todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html
|
||||
使用OBS文件创建镜像
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/IMS/doc?api=ListImages
|
||||
func (self *SRegion) GetImages(id, status string, imagetype string, name string) ([]SImage, error) {
|
||||
query := url.Values{}
|
||||
query.Set("virtual_env_type", "FusionCompute")
|
||||
if len(status) > 0 {
|
||||
query.Set("status", status)
|
||||
}
|
||||
|
||||
if len(id) > 0 {
|
||||
query.Set("id", id)
|
||||
}
|
||||
|
||||
if len(imagetype) > 0 {
|
||||
query.Set("__imagetype", string(imagetype))
|
||||
if imagetype == "gold" {
|
||||
query.Set("protected", "True")
|
||||
}
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
query.Set("name", name)
|
||||
}
|
||||
|
||||
ret := []SImage{}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_IMS, "cloudimages", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Images []SImage
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
ret = append(ret, part.Images...)
|
||||
if len(part.Images) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part.Images[len(part.Images)-1].ID)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteImage(imageId string) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetImageByName(name string) (*SImage, error) {
|
||||
images, err := self.GetImages("", "", "", name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range images {
|
||||
if images[i].Name == name {
|
||||
return &images[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, name)
|
||||
}
|
||||
|
||||
* openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html
|
||||
*/
|
||||
func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) {
|
||||
os_version, err := stdVersion(osDist, osVersion, osArch)
|
||||
log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB)
|
||||
osVersion, err := stdVersion(osDist, osVersion, osArch)
|
||||
log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, osVersion, minDiskGB)
|
||||
|
||||
imageUrl := fmt.Sprintf("%s:%s", bucket, key)
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"image_url": imageUrl,
|
||||
"is_config_init": true,
|
||||
"is_config": true,
|
||||
"min_disk": minDiskGB,
|
||||
}
|
||||
if len(osVersion) > 0 {
|
||||
params["os_version"] = osVersion
|
||||
}
|
||||
resp, err := self.post(SERVICE_IMS, "cloudimages/quickimport/action", params)
|
||||
if err != nil {
|
||||
log.Debugln(err)
|
||||
return "", errors.Wrapf(err, "import image")
|
||||
}
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(name), "name")
|
||||
image_url := fmt.Sprintf("%s:%s", bucket, key)
|
||||
params.Add(jsonutils.NewString(image_url), "image_url")
|
||||
if len(os_version) > 0 {
|
||||
params.Add(jsonutils.NewString(os_version), "os_version")
|
||||
}
|
||||
params.Add(jsonutils.NewBool(true), "is_config_init")
|
||||
params.Add(jsonutils.NewBool(true), "is_config")
|
||||
params.Add(jsonutils.NewInt(minDiskGB), "min_disk")
|
||||
|
||||
ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ret.GetString("job_id")
|
||||
return resp.GetString("job_id")
|
||||
}
|
||||
|
||||
func formatVersion(osDist string, osVersion string) (string, error) {
|
||||
|
||||
+303
-745
File diff suppressed because it is too large
Load Diff
+22
-52
@@ -15,46 +15,13 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"yunion.io/x/log"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
// ===========================================
|
||||
type Interface struct {
|
||||
PortState string `json:"port_state"`
|
||||
FixedIPS []FixedIP `json:"fixed_ips"`
|
||||
NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID
|
||||
PortID string `json:"port_id"`
|
||||
MACAddr string `json:"mac_addr"`
|
||||
}
|
||||
|
||||
/*
|
||||
subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…}
|
||||
availability_zone: "cn-north-1b"
|
||||
cidr: "192.168.0.0/24"
|
||||
dhcp_enable: true
|
||||
dnsList: ["100.125.1.250", "100.125.21.250"]
|
||||
gateway_ip: "192.168.0.1"
|
||||
id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233"
|
||||
ipv6_enable: false
|
||||
name: "subnet-149c"
|
||||
neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233"
|
||||
neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7"
|
||||
primary_dns: "100.125.1.250"
|
||||
secondary_dns: "100.125.21.250"
|
||||
status: "ACTIVE"
|
||||
tags: []
|
||||
vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"}
|
||||
*/
|
||||
type FixedIP struct {
|
||||
SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。
|
||||
IPAddress string `json:"ip_address"`
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
|
||||
type SInstanceNic struct {
|
||||
instance *SInstance
|
||||
ipAddr string
|
||||
@@ -89,28 +56,31 @@ func (self *SInstanceNic) InClassicNetwork() bool {
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetINetworkId() string {
|
||||
instanceId := self.instance.GetId()
|
||||
subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId)
|
||||
if err != nil || len(subnets) == 0 {
|
||||
log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error())
|
||||
return ""
|
||||
subnets, _ := self.instance.host.zone.region.getSubnetIdsByInstanceId(self.instance.GetId())
|
||||
for _, id := range subnets {
|
||||
return id
|
||||
}
|
||||
|
||||
return subnets[0]
|
||||
return ""
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListServerInterfaces
|
||||
func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) {
|
||||
ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId}
|
||||
interfaces := make([]Interface, 0)
|
||||
err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces)
|
||||
resp, err := self.list(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/os-interface", instanceId), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "list os interface")
|
||||
}
|
||||
|
||||
subnets := make([]string, 0)
|
||||
for _, i := range interfaces {
|
||||
subnets = append(subnets, i.NetID)
|
||||
ret := struct {
|
||||
InterfaceAttachments []struct {
|
||||
NetId string
|
||||
}
|
||||
}{}
|
||||
err = resp.Unmarshal(&ret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
subnets := []string{}
|
||||
for _, att := range ret.InterfaceAttachments {
|
||||
subnets = append(subnets, att.NetId)
|
||||
}
|
||||
|
||||
return subnets, nil
|
||||
}
|
||||
|
||||
+19
-11
@@ -15,10 +15,12 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html
|
||||
type SInstanceType struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -31,27 +33,33 @@ type OSExtraSpecs struct {
|
||||
EcsPerformancetype string `json:"ecs:performancetype"`
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html
|
||||
func (self *SRegion) fetchInstanceTypes(zoneId string) ([]SInstanceType, error) {
|
||||
querys := map[string]string{}
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListFlavors
|
||||
func (self *SRegion) GetInstanceTypes(zoneId string) ([]SInstanceType, error) {
|
||||
query := url.Values{}
|
||||
if len(zoneId) > 0 {
|
||||
querys["availability_zone"] = zoneId
|
||||
query.Set("available_zone", zoneId)
|
||||
}
|
||||
|
||||
instanceTypes := make([]SInstanceType, 0)
|
||||
err := doListAll(self.ecsClient.Flavors.List, querys, &instanceTypes)
|
||||
return instanceTypes, err
|
||||
resp, err := self.list(SERVICE_ECS, "cloudservers/flavors", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list flavors")
|
||||
}
|
||||
ret := []SInstanceType{}
|
||||
err = resp.Unmarshal(&ret, "flavors")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) {
|
||||
instanceTypes, err := self.fetchInstanceTypes(zoneId)
|
||||
instanceTypes, err := self.GetInstanceTypes(zoneId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]SInstanceType, 0)
|
||||
for _, t := range instanceTypes {
|
||||
// cpu & mem & disk都匹配才行
|
||||
// cpu & mem 都匹配才行
|
||||
if t.Vcpus == strconv.Itoa(cpu) && t.RamMB == memMB {
|
||||
ret = append(ret, t)
|
||||
}
|
||||
|
||||
+3
-2
@@ -45,10 +45,11 @@ func (self *SRegion) getFingerprint(publicKey string) (string, error) {
|
||||
return fingerprint, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaListKeypairs
|
||||
func (self *SRegion) GetKeypairs() ([]SKeypair, error) {
|
||||
ret := []SKeypair{}
|
||||
query := url.Values{}
|
||||
resp, err := self.list(SERVICE_ECS, "os-keypairs", query)
|
||||
resp, err := self.list(SERVICE_ECS_V2_1, "os-keypairs", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list os-keypairs")
|
||||
}
|
||||
@@ -85,7 +86,7 @@ func (self *SRegion) ImportKeypair(name, publicKey string) (*SKeypair, error) {
|
||||
"name": name,
|
||||
"public_key": publicKey,
|
||||
}
|
||||
resp, err := self.post(SERVICE_ECS, "os-keypairs", map[string]interface{}{"keypair": params})
|
||||
resp, err := self.post(SERVICE_ECS_V2_1, "os-keypairs", map[string]interface{}{"keypair": params})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "create os-keypairs")
|
||||
}
|
||||
|
||||
+19
-12
@@ -167,7 +167,7 @@ func (self *SLoadbalancer) GetNetwork() *SNetwork {
|
||||
if self.subnet == nil {
|
||||
port, err := self.region.GetPort(self.VipPortId)
|
||||
if err == nil {
|
||||
net, err := self.region.getNetwork(port.NetworkID)
|
||||
net, err := self.region.GetNetwork(port.NetworkID)
|
||||
if err == nil {
|
||||
self.subnet = net
|
||||
} else {
|
||||
@@ -225,7 +225,7 @@ func (self *SLoadbalancer) GetEgressMbps() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteLoadBalancer
|
||||
func (self *SLoadbalancer) Delete(ctx context.Context) error {
|
||||
for _, res := range self.Pools {
|
||||
backends, err := self.region.getLoadBalancerBackends(res.Id)
|
||||
@@ -312,13 +312,12 @@ func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(opts *cloudprovider.S
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html
|
||||
func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error {
|
||||
_, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowPool
|
||||
func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
||||
ret := &SElbBackendGroup{lb: self, region: self.region}
|
||||
resp, err := self.region.list(SERVICE_ELB, "elb/pools/"+groupId, nil)
|
||||
@@ -337,6 +336,7 @@ func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, opts
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowListener
|
||||
func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) {
|
||||
ret := &SElbListener{lb: self}
|
||||
resp, err := self.region.list(SERVICE_ELB, "elb/listeners/"+listenerId, nil)
|
||||
@@ -346,6 +346,7 @@ func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (clou
|
||||
return ret, resp.Unmarshal(ret, "listener")
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowLoadBalancer
|
||||
func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) {
|
||||
resp, err := self.list(SERVICE_ELB, "elb/loadbalancers/"+id, nil)
|
||||
if err != nil {
|
||||
@@ -355,12 +356,14 @@ func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) {
|
||||
return ret, resp.Unmarshal(ret, "loadbalancer")
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteLoadBalancer
|
||||
func (self *SRegion) DeleteLoadBalancer(elbId string) error {
|
||||
resource := fmt.Sprintf("elb/loadbalancers/%s", elbId)
|
||||
_, err := self.delete(SERVICE_ELB, resource)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ListListeners
|
||||
func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) {
|
||||
ret := []SElbListener{}
|
||||
params := url.Values{}
|
||||
@@ -370,6 +373,7 @@ func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, erro
|
||||
return ret, self.lbListAll("elb/listeners", params, "listeners", &ret)
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateLoadBalancer
|
||||
func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListenerCreateOptions, lbId string) (*SElbListener, error) {
|
||||
params := map[string]interface{}{
|
||||
"name": listener.Name,
|
||||
@@ -408,7 +412,7 @@ func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbal
|
||||
return ret, resp.Unmarshal(&ret, "listener")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ListPools
|
||||
func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) {
|
||||
query := url.Values{}
|
||||
if len(elbId) > 0 {
|
||||
@@ -419,6 +423,7 @@ func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGr
|
||||
return ret, self.lbListAll("elb/pools", query, "pools", &ret)
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreatePool
|
||||
func (self *SRegion) CreateLoadBalancerBackendGroup(lbId string, opts *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) {
|
||||
params := map[string]interface{}{
|
||||
"name": opts.Name,
|
||||
@@ -455,6 +460,7 @@ func (self *SRegion) CreateLoadBalancerBackendGroup(lbId string, opts *cloudprov
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateHealthMonitor
|
||||
func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) {
|
||||
params := map[string]interface{}{
|
||||
"delay": healthCheck.HealthCheckInterval,
|
||||
@@ -486,7 +492,7 @@ func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, health
|
||||
return ret, resp.Unmarshal(&ret, "healthmonitor")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=UpdateHealthMonitor
|
||||
func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) {
|
||||
params := map[string]interface{}{
|
||||
"delay": healthCheck.HealthCheckInterval,
|
||||
@@ -515,7 +521,7 @@ func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthC
|
||||
return ret, resp.Unmarshal(&ret, "healthmonitor")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteHealthMonitor
|
||||
func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckId string) error {
|
||||
_, err := self.delete(SERVICE_ELB, "elb/healthmonitors/"+healthCheckId)
|
||||
return err
|
||||
@@ -546,8 +552,9 @@ func (self *SRegion) lbListAll(resource string, query url.Values, respKey string
|
||||
return ret.Unmarshal(retVal)
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateLoadBalancer
|
||||
func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateOptions) (*SLoadbalancer, error) {
|
||||
subnet, err := self.getNetwork(opts.NetworkIds[0])
|
||||
subnet, err := self.GetNetwork(opts.NetworkIds[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getNetwork")
|
||||
}
|
||||
@@ -581,13 +588,13 @@ func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateO
|
||||
if len(opts.EipId) > 0 {
|
||||
params["publicip_ids"] = []string{opts.EipId}
|
||||
}
|
||||
err = self.fetchZones()
|
||||
zones, err := self.GetZones()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "fetchZones")
|
||||
return nil, errors.Wrapf(err, "GetZones")
|
||||
}
|
||||
zoneIds := []string{}
|
||||
for i := range self.izones {
|
||||
zone := self.izones[i].(*SZone)
|
||||
for i := range zones {
|
||||
zone := zones[i]
|
||||
zoneIds = append(zoneIds, zone.ZoneName)
|
||||
}
|
||||
params["availability_zone_list"] = zoneIds
|
||||
|
||||
+4
-34
@@ -22,7 +22,6 @@ import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
|
||||
@@ -94,15 +93,13 @@ func (self *SElbBackend) GetBackendRole() string {
|
||||
}
|
||||
|
||||
func (self *SElbBackend) GetBackendId() string {
|
||||
i, err := self.lb.region.getInstanceByIP(self.Address)
|
||||
vms, err := self.region.GetInstances(self.Address)
|
||||
if err != nil {
|
||||
log.Errorf("ElbBackend GetBackendId %s", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
if i != nil {
|
||||
return i.GetId()
|
||||
for _, vm := range vms {
|
||||
return vm.GetId()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -123,33 +120,6 @@ func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) {
|
||||
queries := make(map[string]string)
|
||||
|
||||
if len(self.client.projectId) > 0 {
|
||||
queries["project_id"] = self.client.projectId
|
||||
}
|
||||
|
||||
if len(privateIP) > 0 {
|
||||
queries["ip"] = privateIP
|
||||
}
|
||||
|
||||
instances := make([]SInstance, 0)
|
||||
err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(instances) == 1 {
|
||||
return &instances[0], nil
|
||||
} else if len(instances) > 1 {
|
||||
log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP)
|
||||
return &instances[0], nil
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) {
|
||||
res := fmt.Sprintf("elb/pools/%s/members/%s", pool, id)
|
||||
resp, err := self.list(SERVICE_ELB, res, nil)
|
||||
|
||||
+2
-2
@@ -249,7 +249,7 @@ func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (clou
|
||||
}
|
||||
|
||||
func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) {
|
||||
instance, err := self.lb.region.GetInstanceByID(serverId)
|
||||
instance, err := self.lb.region.GetInstance(serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -268,7 +268,7 @@ func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port
|
||||
return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId)
|
||||
}
|
||||
|
||||
net, err := self.lb.region.getNetwork(subnets[0])
|
||||
net, err := self.lb.region.GetNetwork(subnets[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+3
-3
@@ -156,7 +156,7 @@ func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreat
|
||||
}
|
||||
netId, _ = createNetObj.GetString("metadata", "name")
|
||||
for i := 0; i < 10; i++ {
|
||||
netDetailObj, err := self.list(SERVICE_MODELARTS, "networks/"+netId, nil)
|
||||
netDetailObj, err := self.list(SERVICE_MODELARTS_V1, "networks/"+netId, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SHuaweiClient.NetworkDetail")
|
||||
}
|
||||
@@ -291,7 +291,7 @@ type ModelartsStatistics struct {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) {
|
||||
return self.list(SERVICE_MODELARTS, self.clientRegion, "networks", nil)
|
||||
return self.list(SERVICE_MODELARTS_V1, self.clientRegion, "networks", nil)
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject, error) {
|
||||
@@ -308,7 +308,7 @@ func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject
|
||||
"cidr": cidr,
|
||||
},
|
||||
}
|
||||
return self.post(SERVICE_MODELARTS, self.clientRegion, "networks", params)
|
||||
return self.post(SERVICE_MODELARTS_V1, self.clientRegion, "networks", params)
|
||||
}
|
||||
|
||||
func (self *SModelartsPool) GetCreatedAt() time.Time {
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ type SModelartsResourceflavorsStatus struct {
|
||||
|
||||
func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) {
|
||||
resourceflavors := make([]SModelartsPoolSku, 0)
|
||||
obj, err := self.list(SERVICE_MODELARTS, "resourceflavors", nil)
|
||||
obj, err := self.list(SERVICE_MODELARTS_V1, "resourceflavors", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "list")
|
||||
}
|
||||
|
||||
-9
@@ -25,17 +25,8 @@ import (
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) {
|
||||
return r.ecsClient.CloudEye.ListMetrics()
|
||||
}
|
||||
|
||||
func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) {
|
||||
return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until)
|
||||
}
|
||||
|
||||
type MetricData struct {
|
||||
Namespace string
|
||||
MetricName string
|
||||
|
||||
+30
-27
@@ -15,8 +15,9 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
@@ -91,41 +92,43 @@ func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) {
|
||||
queuies := map[string]string{
|
||||
"nat_gateway_id": natGatewayID,
|
||||
func (region *SRegion) GetNatDTable(natId string) ([]SNatDEntry, error) {
|
||||
query := url.Values{}
|
||||
if len(natId) > 0 {
|
||||
query.Set("gateway_id", natId)
|
||||
}
|
||||
dNatSTableEntries := make([]SNatDEntry, 0, 2)
|
||||
// can't make true that restapi support marker para in Huawei Cloud
|
||||
err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID)
|
||||
}
|
||||
for i := range dNatSTableEntries {
|
||||
nat := &dNatSTableEntries[i]
|
||||
if len(nat.InternalIP) == 0 {
|
||||
port, err := region.GetPort(nat.PortID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID)
|
||||
}
|
||||
nat.InternalIP = port.FixedIps[0].IpAddress
|
||||
ret := []SNatDEntry{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_NAT, "private-nat/dnat-rules", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
DnatRules []SNatDEntry
|
||||
PageInfo sPageInfo
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.DnatRules...)
|
||||
if len(part.PageInfo.NextMarker) == 0 || len(part.DnatRules) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part.PageInfo.NextMarker)
|
||||
}
|
||||
return dNatSTableEntries, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteNatDEntry(entryID string) error {
|
||||
_, err := region.ecsClient.DNatRules.Delete(entryID, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, `delete dnat rule %q failed`, entryID)
|
||||
}
|
||||
return nil
|
||||
func (region *SRegion) DeleteNatDEntry(id string) error {
|
||||
_, err := region.delete(SERVICE_NAT, "private-nat/dnat-rules/"+id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (nat *SNatDEntry) Refresh() error {
|
||||
new, err := nat.gateway.region.GetNatDEntryByID(nat.ID)
|
||||
ret, err := nat.gateway.region.GetNatDEntryByID(nat.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(nat, new)
|
||||
return jsonutils.Update(nat, ret)
|
||||
}
|
||||
|
||||
+80
-58
@@ -15,6 +15,7 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -155,7 +156,7 @@ func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (clou
|
||||
return nil, err
|
||||
}
|
||||
dnat.gateway = gateway
|
||||
return &dnat, nil
|
||||
return dnat, nil
|
||||
}
|
||||
|
||||
func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) {
|
||||
@@ -164,7 +165,7 @@ func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (clou
|
||||
return nil, err
|
||||
}
|
||||
snat.gateway = gateway
|
||||
return &snat, nil
|
||||
return snat, nil
|
||||
}
|
||||
|
||||
func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) {
|
||||
@@ -173,7 +174,7 @@ func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNa
|
||||
return nil, err
|
||||
}
|
||||
dnat.gateway = gateway
|
||||
return &dnat, nil
|
||||
return dnat, nil
|
||||
}
|
||||
|
||||
func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) {
|
||||
@@ -182,29 +183,41 @@ func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNa
|
||||
return nil, err
|
||||
}
|
||||
snat.gateway = gateway
|
||||
return &snat, nil
|
||||
return snat, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) {
|
||||
queues := make(map[string]string)
|
||||
if len(natGatewayID) != 0 {
|
||||
queues["id"] = natGatewayID
|
||||
func (region *SRegion) GetNatGateways(vpcId, id string) ([]SNatGateway, error) {
|
||||
query := url.Values{}
|
||||
if len(id) != 0 {
|
||||
query.Set("id", id)
|
||||
}
|
||||
if len(vpcID) != 0 {
|
||||
queues["router_id"] = vpcID
|
||||
if len(vpcId) != 0 {
|
||||
query.Set("vpc_id", vpcId)
|
||||
}
|
||||
natGateways := make([]SNatGateway, 0, 2)
|
||||
err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid")
|
||||
ret := []SNatGateway{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_NAT, "private-nat/gateways", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := struct {
|
||||
Gateways []SNatGateway
|
||||
PageInfo sPageInfo
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Gateways...)
|
||||
if len(part.PageInfo.NextMarker) == 0 || len(part.Gateways) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part.PageInfo.NextMarker)
|
||||
}
|
||||
for i := range natGateways {
|
||||
natGateways[i].region = region
|
||||
}
|
||||
return natGateways, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) {
|
||||
func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (*SNatDEntry, error) {
|
||||
params := make(map[string]interface{})
|
||||
params["nat_gateway_id"] = gatewayID
|
||||
params["private_ip"] = rule.InternalIP
|
||||
@@ -213,21 +226,21 @@ func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID s
|
||||
params["external_service_port"] = rule.ExternalPort
|
||||
params["protocol"] = rule.Protocol
|
||||
|
||||
packParams := map[string]map[string]interface{}{
|
||||
"dnat_rule": params,
|
||||
}
|
||||
|
||||
ret := SNatDEntry{}
|
||||
err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret)
|
||||
resp, err := region.post(SERVICE_NAT, "private-nat/dnat-rules", map[string]interface{}{"dnat_rule": params})
|
||||
if err != nil {
|
||||
return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID)
|
||||
return nil, errors.Wrapf(err, "create dnat")
|
||||
}
|
||||
ret := &SNatDEntry{}
|
||||
err = resp.Unmarshal(ret, "dnat_rule")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) {
|
||||
func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayId string) (*SNatSEntry, error) {
|
||||
params := make(map[string]interface{})
|
||||
params["nat_gateway_id"] = gatewayID
|
||||
params["nat_gateway_id"] = gatewayId
|
||||
if len(rule.NetworkID) != 0 {
|
||||
params["network_id"] = rule.NetworkID
|
||||
}
|
||||
@@ -235,36 +248,42 @@ func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID s
|
||||
params["cidr"] = rule.SourceCIDR
|
||||
}
|
||||
params["floating_ip_id"] = rule.ExternalIPID
|
||||
|
||||
packParams := map[string]map[string]interface{}{
|
||||
"snat_rule": params,
|
||||
}
|
||||
|
||||
ret := SNatSEntry{}
|
||||
err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret)
|
||||
resp, err := region.post(SERVICE_NAT, "private-nat/snat-rules", map[string]interface{}{"snat_rule": params})
|
||||
if err != nil {
|
||||
return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID)
|
||||
return nil, errors.Wrapf(err, "create snat")
|
||||
}
|
||||
ret := &SNatSEntry{}
|
||||
err = resp.Unmarshal(ret, "snat_rule")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) {
|
||||
dnat := SNatDEntry{}
|
||||
err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat)
|
||||
|
||||
func (region *SRegion) GetNatDEntryByID(id string) (*SNatDEntry, error) {
|
||||
resp, err := region.list(SERVICE_NAT, "private-nat/dnat-rules/"+id, nil)
|
||||
if err != nil {
|
||||
return SNatDEntry{}, err
|
||||
return nil, err
|
||||
}
|
||||
return dnat, nil
|
||||
ret := &SNatDEntry{}
|
||||
err = resp.Unmarshal(ret, "dnat_rule")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) {
|
||||
snat := SNatSEntry{}
|
||||
err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat)
|
||||
func (region *SRegion) GetNatSEntryByID(id string) (*SNatSEntry, error) {
|
||||
resp, err := region.list(SERVICE_NAT, "private-nat/snat-rules/"+id, nil)
|
||||
if err != nil {
|
||||
return SNatSEntry{}, cloudprovider.ErrNotFound
|
||||
return nil, err
|
||||
}
|
||||
return snat, nil
|
||||
ret := &SNatSEntry{}
|
||||
err = resp.Unmarshal(ret, "snat_rule")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func NatResouceStatusTransfer(status string) string {
|
||||
@@ -283,13 +302,16 @@ func NatResouceStatusTransfer(status string) string {
|
||||
}
|
||||
|
||||
func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) {
|
||||
resp, err := self.ecsClient.NatGateways.Get(id, nil)
|
||||
resp, err := self.list(SERVICE_NAT, "private-nat/gateways/"+id, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id)
|
||||
return nil, err
|
||||
}
|
||||
nat := &SNatGateway{region: self}
|
||||
err = resp.Unmarshal(nat)
|
||||
return nat, errors.Wrap(err, "resp.Unmarshal")
|
||||
err = resp.Unmarshal(nat, "gateway")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nat, nil
|
||||
}
|
||||
|
||||
func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) {
|
||||
@@ -312,7 +334,7 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption
|
||||
case api.NAT_SPEC_XLARGE:
|
||||
spec = "4"
|
||||
}
|
||||
params := jsonutils.Marshal(map[string]map[string]interface{}{
|
||||
params := map[string]interface{}{
|
||||
"nat_gateway": map[string]interface{}{
|
||||
"name": opts.Name,
|
||||
"description": opts.Desc,
|
||||
@@ -320,13 +342,13 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption
|
||||
"internal_network_id": opts.NetworkId,
|
||||
"spec": spec,
|
||||
},
|
||||
})
|
||||
resp, err := self.ecsClient.NatGateways.Create(params)
|
||||
}
|
||||
resp, err := self.post(SERVICE_NAT, "private-nat/gateways", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "AsyncCreate")
|
||||
return nil, errors.Wrap(err, "create nat")
|
||||
}
|
||||
nat := &SNatGateway{region: self}
|
||||
err = resp.Unmarshal(nat)
|
||||
err = resp.Unmarshal(nat, "gateway")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "resp.Unmarshal")
|
||||
}
|
||||
@@ -334,6 +356,6 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteNatGateway(id string) error {
|
||||
_, err := self.ecsClient.NatGateways.Delete(id, nil)
|
||||
return errors.Wrapf(err, "NatGateways.Delete(%s)", id)
|
||||
_, err := self.delete(SERVICE_NAT, "private-nat/gateways/"+id)
|
||||
return err
|
||||
}
|
||||
|
||||
+29
-28
@@ -15,8 +15,9 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
)
|
||||
@@ -68,7 +69,6 @@ func (nat *SNatSEntry) Delete() error {
|
||||
return nat.gateway.region.DeleteNatSEntry(nat.GetId())
|
||||
}
|
||||
|
||||
// getNatSTable return all snat rules of gateway
|
||||
func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) {
|
||||
ret, err := gateway.region.GetNatSTable(gateway.GetId())
|
||||
if err != nil {
|
||||
@@ -80,42 +80,43 @@ func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) {
|
||||
queuies := map[string]string{
|
||||
"nat_gateway_id": natGatewayID,
|
||||
func (region *SRegion) GetNatSTable(natId string) ([]SNatSEntry, error) {
|
||||
query := url.Values{}
|
||||
if len(natId) > 0 {
|
||||
query.Set("gateway_id", natId)
|
||||
}
|
||||
sNatSTableEntris := make([]SNatSEntry, 0, 2)
|
||||
err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID)
|
||||
}
|
||||
for i := range sNatSTableEntris {
|
||||
nat := &sNatSTableEntris[i]
|
||||
if len(nat.SourceCIDR) != 0 {
|
||||
continue
|
||||
}
|
||||
subnet := SNetwork{}
|
||||
err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet)
|
||||
ret := []SNatSEntry{}
|
||||
for {
|
||||
resp, err := region.list(SERVICE_NAT, "private-nat/snat-rules", query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID)
|
||||
return nil, err
|
||||
}
|
||||
nat.SourceCIDR = subnet.CIDR
|
||||
part := struct {
|
||||
SnatRules []SNatSEntry
|
||||
PageInfo sPageInfo
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.SnatRules...)
|
||||
if len(part.PageInfo.NextMarker) == 0 || len(part.SnatRules) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part.PageInfo.NextMarker)
|
||||
}
|
||||
return sNatSTableEntris, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteNatSEntry(entryID string) error {
|
||||
_, err := region.ecsClient.SNatRules.Delete(entryID, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, `delete snat rule %q failed`, entryID)
|
||||
}
|
||||
return nil
|
||||
func (region *SRegion) DeleteNatSEntry(id string) error {
|
||||
_, err := region.delete(SERVICE_NAT, "private-nat/snat-rules/"+id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (nat *SNatSEntry) Refresh() error {
|
||||
new, err := nat.gateway.region.GetNatSEntryByID(nat.ID)
|
||||
ret, err := nat.gateway.region.GetNatSEntryByID(nat.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(nat, new)
|
||||
return jsonutils.Update(nat, ret)
|
||||
}
|
||||
|
||||
+48
-27
@@ -15,15 +15,17 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud"
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -81,16 +83,11 @@ func (self *SNetwork) GetStatus() string {
|
||||
}
|
||||
|
||||
func (self *SNetwork) Refresh() error {
|
||||
log.Debugf("network refresh %s", self.GetId())
|
||||
new, err := self.wire.region.getNetwork(self.GetId())
|
||||
net, err := self.wire.vpc.region.GetNetwork(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, new)
|
||||
}
|
||||
|
||||
func (self *SNetwork) IsEmulated() bool {
|
||||
return false
|
||||
return jsonutils.Update(self, net)
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetIWire() cloudprovider.ICloudWire {
|
||||
@@ -139,34 +136,58 @@ func (self *SNetwork) GetPublicScope() rbacscope.TRbacScope {
|
||||
}
|
||||
|
||||
func (self *SNetwork) Delete() error {
|
||||
return self.wire.region.deleteNetwork(self.VpcID, self.GetId())
|
||||
return self.wire.vpc.region.deleteNetwork(self.VpcID, self.GetId())
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetAllocTimeoutSeconds() int {
|
||||
return 120 // 2 minutes
|
||||
}
|
||||
|
||||
func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
|
||||
network := SNetwork{}
|
||||
err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network)
|
||||
return &network, err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html
|
||||
func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) {
|
||||
querys := map[string]string{}
|
||||
if len(vpcId) > 0 {
|
||||
querys["vpc_id"] = vpcId
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ShowSubnet
|
||||
func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) {
|
||||
resp, err := self.list(SERVICE_VPC, "subnets/"+networkId, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "show subnet")
|
||||
}
|
||||
|
||||
networks := make([]SNetwork, 0)
|
||||
err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks)
|
||||
return networks, err
|
||||
network := &SNetwork{}
|
||||
err = resp.Unmarshal(&network, "subnet")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
return network, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListSubnets
|
||||
func (self *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) {
|
||||
ret := []SNetwork{}
|
||||
query := url.Values{}
|
||||
if len(vpcId) > 0 {
|
||||
query.Set("vpc_id", vpcId)
|
||||
}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_VPC, "subnets", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := []SNetwork{}
|
||||
err = resp.Unmarshal(&part, "subnets")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part...)
|
||||
if len(part) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part[len(part)-1].ID)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=DeleteSubnet
|
||||
func (self *SRegion) deleteNetwork(vpcId string, networkId string) error {
|
||||
ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs}
|
||||
return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil)
|
||||
res := fmt.Sprintf("vpcs/%s/subnets/%s", vpcId, networkId)
|
||||
_, err := self.delete(SERVICE_VPC, res)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetProjectId() string {
|
||||
|
||||
+36
-168
@@ -14,180 +14,48 @@
|
||||
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
import "time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SOrder struct {
|
||||
ErrorCode *string `json:"error_code"` // 只有失败时才返回此参数
|
||||
ErrorMsg *string `json:"error_msg"` //只有失败时才返回此参数
|
||||
TotalSize int `json:"totalSize"` // 只有成功时才返回此参数
|
||||
Resources []SResource `json:"resources"`
|
||||
type SOrderResource struct {
|
||||
Id string
|
||||
ResourceId string
|
||||
ExpireTime time.Time
|
||||
}
|
||||
|
||||
type SResource struct {
|
||||
ResourceID string `json:"resourceId"`
|
||||
CloudServiceType string `json:"cloudServiceType"`
|
||||
RegionCode string `json:"regionCode"`
|
||||
ResourceType string `json:"resourceType"`
|
||||
ResourceSpecCode string `json:"resourceSpecCode"`
|
||||
Status int64 `json:"status"`
|
||||
}
|
||||
|
||||
type SResourceDetail struct {
|
||||
ID string `json:"id"`
|
||||
Status int64 `json:"status"`
|
||||
ResourceID string `json:"resource_id"`
|
||||
ResourceName string `json:"resource_name"`
|
||||
RegionCode string `json:"region_code"`
|
||||
CloudServiceTypeCode string `json:"cloud_service_type_code"`
|
||||
ResourceTypeCode string `json:"resource_type_code"`
|
||||
ResourceSpecCode string `json:"resource_spec_code"`
|
||||
ProjectCode string `json:"project_code"`
|
||||
ProductID string `json:"product_id"`
|
||||
MainResourceID string `json:"main_resource_id"`
|
||||
IsMainResource int64 `json:"is_main_resource"`
|
||||
ValidTime time.Time `json:"valid_time"`
|
||||
ExpireTime time.Time `json:"expire_time"`
|
||||
NextOperationPolicy string `json:"next_operation_policy"`
|
||||
}
|
||||
|
||||
func (self *SRegion) getDomianId() (string, error) {
|
||||
domains, err := self.client.getEnabledDomains()
|
||||
if err != nil {
|
||||
return "", err
|
||||
func (self *SHuaweiClient) GetOrderResources() (map[string]SOrderResource, error) {
|
||||
if len(self.orders) > 0 {
|
||||
return self.orders, nil
|
||||
}
|
||||
|
||||
if domains == nil || len(domains) == 0 {
|
||||
return "", fmt.Errorf("GetAllResByOrderId domain is empty")
|
||||
} else if len(domains) > 1 {
|
||||
// not supported??
|
||||
return "", fmt.Errorf("GetAllResByOrderId mutliple domain(%d) found", len(domains))
|
||||
params := map[string]interface{}{
|
||||
"limit": 500,
|
||||
"only_main_resource": 1,
|
||||
"status_list": []int{
|
||||
2, 4,
|
||||
},
|
||||
}
|
||||
|
||||
return domains[0].ID, nil
|
||||
}
|
||||
|
||||
/*
|
||||
获取订单信息 https://support.huaweicloud.com/api-oce/api_order_00001.html
|
||||
*/
|
||||
func (self *SRegion) GetOrder(orderId string) (SOrder, error) {
|
||||
var order SOrder
|
||||
domain, err := self.getDomianId()
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
|
||||
err = self.ecsClient.Orders.SetDomainId(domain)
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
|
||||
err = DoGet(self.ecsClient.Orders.Get, orderId, nil, &order)
|
||||
return order, err
|
||||
}
|
||||
|
||||
/*
|
||||
获取订单资源详情列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html
|
||||
*/
|
||||
func (self *SRegion) GetOrderResources(orderId string, resource_ids []string, only_main_resource bool) ([]SResourceDetail, error) {
|
||||
domain, err := self.getDomianId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.ecsClient.Orders.SetDomainId(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources := make([]SResourceDetail, 0)
|
||||
queries := map[string]string{"customer_id": domain}
|
||||
if len(orderId) > 0 {
|
||||
queries["order_id"] = orderId
|
||||
}
|
||||
|
||||
if len(resource_ids) > 0 {
|
||||
queries["resource_ids"] = strings.Join(resource_ids, ",")
|
||||
}
|
||||
|
||||
if only_main_resource {
|
||||
queries["only_main_resource"] = "1"
|
||||
}
|
||||
|
||||
err = doListAll(self.ecsClient.Orders.GetPeriodResourceList, queries, &resources)
|
||||
return resources, err
|
||||
}
|
||||
|
||||
/*
|
||||
获取资源详情 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html
|
||||
*/
|
||||
func (self *SRegion) GetOrderResourceDetail(resourceId string) (SResourceDetail, error) {
|
||||
var res SResourceDetail
|
||||
if len(resourceId) == 0 {
|
||||
return res, fmt.Errorf("GetOrderResourceDetail resource id should not be empty")
|
||||
}
|
||||
|
||||
resources, err := self.GetOrderResources("", []string{resourceId}, false)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
switch len(resources) {
|
||||
case 0:
|
||||
return res, cloudprovider.ErrNotFound
|
||||
case 1:
|
||||
return resources[0], nil
|
||||
default:
|
||||
return res, fmt.Errorf("%d resources with id %s found, Expect 1", len(resources), resourceId)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetAllResByOrderId(orderId string) ([]SResource, error) {
|
||||
order, err := self.GetOrder(orderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("GetAllResByOrderId %#v", order.Resources)
|
||||
return order.Resources, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) getAllResByType(orderId string, resourceType string) ([]SResource, error) {
|
||||
res, err := self.GetAllResByOrderId(orderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]SResource, 0)
|
||||
for i := range res {
|
||||
r := res[i]
|
||||
if r.ResourceType == resourceType {
|
||||
ret = append(ret, r)
|
||||
ret, cnt := map[string]SOrderResource{}, 0
|
||||
for {
|
||||
resp, err := self.post(SERVICE_BSS, "", "orders/suscriptions/resources/query", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) getAllResIdsByType(orderId string, resourceType string) ([]string, error) {
|
||||
res, err := self.getAllResByType(orderId, resourceType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids := make([]string, 0)
|
||||
for _, r := range res {
|
||||
if len(r.ResourceID) > 0 {
|
||||
ids = append(ids, r.ResourceID)
|
||||
part := struct {
|
||||
Data []SOrderResource
|
||||
TotalCount int
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cnt += len(part.Data)
|
||||
for _, order := range part.Data {
|
||||
ret[order.Id] = order
|
||||
}
|
||||
if cnt >= part.TotalCount || len(part.Data) == 0 {
|
||||
break
|
||||
}
|
||||
params["offset"] = cnt
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
self.orders = ret
|
||||
return self.orders, nil
|
||||
}
|
||||
|
||||
+38
-14
@@ -15,8 +15,10 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
@@ -142,20 +144,42 @@ func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInt
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetPort(portId string) (Port, error) {
|
||||
port := Port{}
|
||||
err := DoGet(self.ecsClient.Port.Get, portId, nil, &port)
|
||||
return port, err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html
|
||||
func (self *SRegion) GetPorts(instanceId string) ([]Port, error) {
|
||||
ports := make([]Port, 0)
|
||||
querys := map[string]string{}
|
||||
if len(instanceId) > 0 {
|
||||
querys["device_id"] = instanceId
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ShowPort
|
||||
func (self *SRegion) GetPort(id string) (*Port, error) {
|
||||
resp, err := self.list(SERVICE_VPC, "ports/"+id, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get port")
|
||||
}
|
||||
port := &Port{}
|
||||
err = resp.Unmarshal(port, "port")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return port, nil
|
||||
}
|
||||
|
||||
err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports)
|
||||
return ports, err
|
||||
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListPorts
|
||||
func (self *SRegion) GetPorts(instanceId string) ([]Port, error) {
|
||||
ret := []Port{}
|
||||
query := url.Values{}
|
||||
if len(instanceId) > 0 {
|
||||
query.Set("device_id", instanceId)
|
||||
}
|
||||
for {
|
||||
resp, err := self.list(SERVICE_VPC, "ports", query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part := []Port{}
|
||||
err = resp.Unmarshal(&part, "ports")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part...)
|
||||
if len(part) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", part[len(part)-1].ID)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
-9
@@ -19,6 +19,7 @@ import (
|
||||
"strings"
|
||||
|
||||
api "yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html
|
||||
@@ -51,18 +52,20 @@ func (self *SProject) GetHealthStatus() string {
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) fetchProjects() ([]SProject, error) {
|
||||
if self.projects != nil {
|
||||
if len(self.projects) > 0 {
|
||||
return self.projects, nil
|
||||
}
|
||||
|
||||
huawei, _ := self.newGeneralAPIClient()
|
||||
projects := make([]SProject, 0)
|
||||
err := doListAll(huawei.Projects.List, nil, &projects)
|
||||
if err == nil {
|
||||
self.projects = projects
|
||||
projects := []SProject{}
|
||||
resp, err := self.list(SERVICE_IAM_V3, "", "auth/projects", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "list projects")
|
||||
}
|
||||
|
||||
return projects, err
|
||||
err = resp.Unmarshal(&projects, "projects")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
self.projects = projects
|
||||
return self.projects, nil
|
||||
}
|
||||
|
||||
// obs 权限必须赋予到mos project之上
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user