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 }