yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/mongodb.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package qcloud
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
    23  
    24  	"yunion.io/x/jsonutils"
    25  	"yunion.io/x/pkg/errors"
    26  	"yunion.io/x/pkg/utils"
    27  
    28  	billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
    29  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    30  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    31  	"yunion.io/x/cloudmux/pkg/multicloud"
    32  )
    33  
    34  type SMongoDB struct {
    35  	QcloudTags
    36  	multicloud.SVirtualResourceBase
    37  	multicloud.SBillingBase
    38  	multicloud.SMongodbBase
    39  
    40  	region *SRegion
    41  
    42  	IOPS                int
    43  	NetworkAddress      string
    44  	AutoRenewFlag       int           `json:"AutoRenewFlag"`
    45  	CloneInstances      []interface{} `json:"CloneInstances"`
    46  	ClusterType         int           `json:"ClusterType"`
    47  	ClusterVer          int           `json:"ClusterVer"`
    48  	ConfigServerCpuNum  int           `json:"ConfigServerCpuNum"`
    49  	ConfigServerMemory  int           `json:"ConfigServerMemory"`
    50  	ConfigServerNodeNum int           `json:"ConfigServerNodeNum"`
    51  	ConfigServerVolume  int           `json:"ConfigServerVolume"`
    52  	CpuNum              int           `json:"CpuNum"`
    53  	CreateTime          time.Time     `json:"CreateTime"`
    54  	DeadLine            string        `json:"DeadLine"`
    55  	InstanceId          string        `json:"InstanceId"`
    56  	InstanceName        string        `json:"InstanceName"`
    57  	InstanceStatusDesc  string        `json:"InstanceStatusDesc"`
    58  	InstanceTaskDesc    string        `json:"InstanceTaskDesc"`
    59  	InstanceTaskId      int           `json:"InstanceTaskId"`
    60  	InstanceType        int           `json:"InstanceType"`
    61  	InstanceVer         int           `json:"InstanceVer"`
    62  	MachineType         string        `json:"MachineType"`
    63  	MaintenanceEnd      string        `json:"MaintenanceEnd"`
    64  	MaintenanceStart    string        `json:"MaintenanceStart"`
    65  	Memory              int           `json:"Memory"`
    66  	MongoVersion        string        `json:"MongoVersion"`
    67  	MongosCpuNum        int           `json:"MongosCpuNum"`
    68  	MongosMemory        int           `json:"MongosMemory"`
    69  	MongosNodeNum       int           `json:"MongosNodeNum"`
    70  	NetType             int           `json:"NetType"`
    71  	PayMode             int           `json:"PayMode"`
    72  	ProjectId           int           `json:"ProjectId"`
    73  	Protocol            int           `json:"Protocol"`
    74  	Readonlyinstances   []interface{} `json:"ReadonlyInstances"`
    75  	RealInstanceId      string        `json:"RealInstanceId"`
    76  	Region              string        `json:"Region"`
    77  	Relatedinstance     struct {
    78  		InstanceId string `json:"InstanceId"`
    79  		Region     string `json:"Region"`
    80  	} `json:"RelatedInstance"`
    81  	Replicasets []struct {
    82  		Memory           int    `json:"Memory"`
    83  		OplogSize        int    `json:"OplogSize"`
    84  		RealReplicasetId string `json:"RealReplicaSetId"`
    85  		ReplicaSetId     string `json:"ReplicaSetId"`
    86  		ReplicaSetName   string `json:"ReplicaSetName"`
    87  		SecondaryNum     int    `json:"SecondaryNum"`
    88  		UsedVolume       int    `json:"UsedVolume"`
    89  		Volume           int    `json:"Volume"`
    90  	} `json:"ReplicaSets"`
    91  	ReplicationSetNum int           `json:"ReplicationSetNum"`
    92  	SecondaryNum      int           `json:"SecondaryNum"`
    93  	StandbyInstances  []interface{} `json:"StandbyInstances"`
    94  	Status            int           `json:"Status"`
    95  	SubnetId          string        `json:"SubnetId"`
    96  	UsedVolume        int           `json:"UsedVolume"`
    97  	Vip               string        `json:"Vip"`
    98  	Volume            int           `json:"Volume"`
    99  	VpcId             string        `json:"VpcId"`
   100  	Vport             int           `json:"Vport"`
   101  	Zone              string        `json:"Zone"`
   102  }
   103  
   104  func (self *SMongoDB) GetGlobalId() string {
   105  	return self.InstanceId
   106  }
   107  
   108  func (self *SMongoDB) GetId() string {
   109  	return self.InstanceId
   110  }
   111  
   112  func (self *SMongoDB) GetName() string {
   113  	return self.InstanceName
   114  }
   115  
   116  func (self *SMongoDB) GetStatus() string {
   117  	switch self.Status {
   118  	case 0, 1:
   119  		return api.MONGO_DB_STATUS_CREATING
   120  	case 2:
   121  		return api.MONGO_DB_STATUS_RUNNING
   122  	case -2, -3:
   123  		return api.MONGO_DB_STATUS_DELETING
   124  	}
   125  	return fmt.Sprintf("%d", self.Status)
   126  }
   127  
   128  func (self *SMongoDB) Refresh() error {
   129  	ins, err := self.region.GetMongoDB(self.InstanceId)
   130  	if err != nil {
   131  		return errors.Wrapf(err, "GetMongoDB")
   132  	}
   133  	return jsonutils.Update(self, ins)
   134  }
   135  
   136  func (self *SMongoDB) GetProjectId() string {
   137  	return fmt.Sprintf("%d", self.ProjectId)
   138  }
   139  
   140  func (self *SMongoDB) GetVpcId() string {
   141  	return self.VpcId
   142  }
   143  
   144  func (self *SMongoDB) GetNetworkId() string {
   145  	return self.SubnetId
   146  }
   147  
   148  func (self *SMongoDB) GetCreatedAt() time.Time {
   149  	return self.CreateTime.Add(time.Hour * -8)
   150  }
   151  
   152  func (self *SMongoDB) GetExpiredAt() time.Time {
   153  	return time.Time{}
   154  }
   155  
   156  func (self *SMongoDB) GetIpAddr() string {
   157  	return self.Vip
   158  }
   159  
   160  func (self *SMongoDB) GetVcpuCount() int {
   161  	return self.CpuNum
   162  }
   163  
   164  func (self *SMongoDB) GetVmemSizeMb() int {
   165  	return self.Memory
   166  }
   167  
   168  func (self *SMongoDB) GetReplicationNum() int {
   169  	switch self.GetCategory() {
   170  	case api.MONGO_DB_CATEGORY_SHARDING:
   171  		return self.ReplicationSetNum
   172  	case api.MONGO_DB_CATEGORY_REPLICATE:
   173  		return 3
   174  	}
   175  	return self.ReplicationSetNum
   176  }
   177  
   178  func (self *SMongoDB) GetDiskSizeMb() int {
   179  	return self.Volume
   180  }
   181  
   182  func (self *SMongoDB) GetZoneId() string {
   183  	return self.Zone
   184  }
   185  
   186  func (self *SMongoDB) GetBillingType() string {
   187  	// 计费模式:0-按量计费,1-包年包月
   188  	if self.PayMode == 1 {
   189  		return billing_api.BILLING_TYPE_PREPAID
   190  	} else {
   191  		return billing_api.BILLING_TYPE_POSTPAID
   192  	}
   193  }
   194  
   195  func (self *SMongoDB) IsAutoRenew() bool {
   196  	return self.AutoRenewFlag == 1
   197  }
   198  
   199  func (self *SMongoDB) GetCategory() string {
   200  	switch self.ClusterType {
   201  	case 0:
   202  		return api.MONGO_DB_CATEGORY_REPLICATE
   203  	case 1:
   204  		return api.MONGO_DB_CATEGORY_SHARDING
   205  	default:
   206  		return fmt.Sprintf("%d", self.ClusterType)
   207  	}
   208  }
   209  
   210  func (self *SMongoDB) GetEngine() string {
   211  	if utils.IsInStringArray("WT", strings.Split(self.MongoVersion, "_")) {
   212  		return api.MONGO_DB_ENGINE_WIRED_TIGER
   213  	}
   214  	return api.MONGO_DB_ENGINE_ROCKS
   215  }
   216  
   217  func (self *SMongoDB) GetEngineVersion() string {
   218  	vers := strings.Split(self.MongoVersion, "_")
   219  	if len(vers) > 1 {
   220  		return strings.Join(strings.Split(vers[1], ""), ".")
   221  	}
   222  	return ""
   223  }
   224  
   225  func (self *SMongoDB) GetInstanceType() string {
   226  	return self.MachineType
   227  }
   228  
   229  func (self *SMongoDB) GetMaintainTime() string {
   230  	return fmt.Sprintf("%s-%s", self.MaintenanceStart, self.MaintenanceEnd)
   231  }
   232  
   233  func (self *SMongoDB) GetPort() int {
   234  	return self.Vport
   235  }
   236  
   237  func (self *SMongoDB) Delete() error {
   238  	return self.region.DeleteMongoDB(self.InstanceId)
   239  }
   240  
   241  func (self *SRegion) DeleteMongoDB(id string) error {
   242  	err := self.IsolateMongoDB(id)
   243  	if err != nil {
   244  		return errors.Wrapf(err, "IsolateDBInstance")
   245  	}
   246  	return cloudprovider.Wait(time.Second*10, time.Minute*3, func() (bool, error) {
   247  		err = self.OfflineIsolatedMongoDB(id)
   248  		if err == nil {
   249  			return true, nil
   250  		}
   251  		if e, ok := errors.Cause(err).(*sdkerrors.TencentCloudSDKError); ok && e.Code == "InvalidParameterValue.LockFailed" {
   252  			return false, nil
   253  		}
   254  		return true, err
   255  	})
   256  }
   257  
   258  func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error {
   259  	return self.region.SetResourceTags("mongodb", "instance", []string{self.InstanceId}, tags, replace)
   260  }
   261  
   262  func (self *SMongoDB) GetIBackups() ([]cloudprovider.SMongoDBBackup, error) {
   263  	return self.region.GetMongoDBBackups(self.InstanceId)
   264  }
   265  
   266  func (self *SRegion) IsolateMongoDB(id string) error {
   267  	params := map[string]string{
   268  		"InstanceId": id,
   269  	}
   270  	_, err := self.mongodbRequest("IsolateDBInstance", params)
   271  	return errors.Wrapf(err, "IsolateDBInstance")
   272  }
   273  
   274  func (self *SRegion) OfflineIsolatedMongoDB(id string) error {
   275  	params := map[string]string{
   276  		"InstanceId": id,
   277  	}
   278  	_, err := self.mongodbRequest("OfflineIsolatedDBInstance", params)
   279  	return errors.Wrapf(err, "OfflineIsolatedDBInstance")
   280  }
   281  
   282  func (self *SRegion) GetMongoDBs(ids []string, limit, offset int) ([]SMongoDB, int, error) {
   283  	if limit < 1 || limit > 100 {
   284  		limit = 100
   285  	}
   286  	params := map[string]string{
   287  		"Limit":  fmt.Sprintf("%d", limit),
   288  		"Offset": fmt.Sprintf("%d", offset),
   289  	}
   290  	for i, id := range ids {
   291  		params[fmt.Sprintf("InstanceIds.%d", i)] = id
   292  	}
   293  	resp, err := self.mongodbRequest("DescribeDBInstances", params)
   294  	if err != nil {
   295  		return nil, 0, errors.Wrapf(err, "DescribeDBInstances")
   296  	}
   297  	dbs := []SMongoDB{}
   298  	err = resp.Unmarshal(&dbs, "InstanceDetails")
   299  	if err != nil {
   300  		return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
   301  	}
   302  	totalCount, _ := resp.Float("TotalCount")
   303  	return dbs, int(totalCount), nil
   304  }
   305  
   306  func (self *SMongoDB) GetIops() int {
   307  	return self.IOPS
   308  }
   309  
   310  func (self *SMongoDB) GetNetworkAddress() string {
   311  	return self.NetworkAddress
   312  }
   313  
   314  func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) {
   315  	dbs := []SMongoDB{}
   316  	for {
   317  		part, total, err := self.GetMongoDBs(nil, 100, len(dbs))
   318  		if err != nil {
   319  			return nil, errors.Wrapf(err, "GetMongoDBs")
   320  		}
   321  		dbs = append(dbs, part...)
   322  		if len(dbs) >= total {
   323  			break
   324  		}
   325  	}
   326  	ret := []cloudprovider.ICloudMongoDB{}
   327  	for i := range dbs {
   328  		dbs[i].region = self
   329  		ret = append(ret, &dbs[i])
   330  	}
   331  	return ret, nil
   332  }
   333  
   334  func (self *SRegion) GetMongoDBBackups(id string) ([]cloudprovider.SMongoDBBackup, error) {
   335  	params := map[string]string{
   336  		"BackupMethod": "2",
   337  		"InstanceId":   id,
   338  	}
   339  	resp, err := self.mongodbRequest("DescribeDBBackups", params)
   340  	if err != nil {
   341  		return nil, errors.Wrapf(err, "DescribeDBBackups")
   342  	}
   343  	backups := []struct {
   344  		InstanceId   string
   345  		BackupType   int
   346  		BackupName   string
   347  		BackupDesc   string
   348  		BackupSize   int
   349  		StartTime    time.Time
   350  		EndTime      time.Time
   351  		Status       int
   352  		BackupMethod int
   353  	}{}
   354  	err = resp.Unmarshal(&backups, "BackupList")
   355  	if err != nil {
   356  		return nil, errors.Wrapf(err, "resp.Unmarshal")
   357  	}
   358  	ret := []cloudprovider.SMongoDBBackup{}
   359  	for _, backup := range backups {
   360  		b := cloudprovider.SMongoDBBackup{
   361  			Name:         backup.BackupName,
   362  			Description:  backup.BackupDesc,
   363  			BackupSizeKb: backup.BackupSize,
   364  		}
   365  		b.StartTime = backup.StartTime.Add(time.Hour * -8)
   366  		b.EndTime = backup.EndTime.Add(time.Hour * -8)
   367  		switch backup.Status {
   368  		case 1:
   369  			b.Status = cloudprovider.MongoDBBackupStatusCreating
   370  		case 2:
   371  			b.Status = cloudprovider.MongoDBBackupStatusAvailable
   372  		default:
   373  			b.Status = cloudprovider.MongoDBBackupStatusUnknown
   374  		}
   375  		b.BackupMethod = cloudprovider.MongoDBBackupMethodLogical
   376  		if backup.BackupMethod == 0 {
   377  			b.BackupMethod = cloudprovider.MongoDBBackupMethodPhysical
   378  		}
   379  		b.BackupType = cloudprovider.MongoDBBackupTypeAuto
   380  		if backup.BackupType == 1 {
   381  			b.BackupType = cloudprovider.MongoDBBackupTypeManual
   382  		}
   383  		ret = append(ret, b)
   384  	}
   385  	return ret, nil
   386  }
   387  
   388  func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) {
   389  	dbs, _, err := self.GetMongoDBs([]string{id}, 1, 0)
   390  	if err != nil {
   391  		return nil, errors.Wrapf(err, "GetMongoDB(%s)", id)
   392  	}
   393  	for i := range dbs {
   394  		dbs[i].region = self
   395  		return &dbs[i], nil
   396  	}
   397  	return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
   398  }
   399  
   400  func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) {
   401  	db, err := self.GetMongoDB(id)
   402  	if err != nil {
   403  		return nil, errors.Wrapf(err, "GetMongoDB")
   404  	}
   405  	return db, nil
   406  }