yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/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 aliyun 16 17 import ( 18 "fmt" 19 "regexp" 20 "strconv" 21 "strings" 22 "time" 23 24 "yunion.io/x/jsonutils" 25 "yunion.io/x/log" 26 "yunion.io/x/pkg/errors" 27 "yunion.io/x/pkg/utils" 28 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 SMOngoDBAttribute struct { 35 // 实例最大IOPS 36 MaxIops int 37 ReplicaSets struct { 38 ReplicaSet []struct { 39 ConnectionDomain string `json:"ConnectionDomain"` 40 } 41 } 42 MaxConnections int 43 } 44 45 type SMongoDB struct { 46 region *SRegion 47 AliyunTags 48 multicloud.SBillingBase 49 multicloud.SResourceBase 50 51 ConnectionDomain string `json:"ConnectionDomain"` 52 NetworkAddress string 53 ChargeType TChargeType `json:"ChargeType"` 54 LockMode string `json:"LockMode"` 55 DBInstanceClass string `json:"DBInstanceClass"` 56 ResourceGroupId string `json:"ResourceGroupId"` 57 DBInstanceId string `json:"DBInstanceId"` 58 ZoneId string `json:"ZoneId"` 59 MongosList struct { 60 MongosAttribute []struct { 61 NodeId string `json:"NodeId"` 62 NodeClass string `json:"NodeClass"` 63 } `json:"MongosAttribute"` 64 } `json:"MongosList"` 65 DBInstanceDescription string `json:"DBInstanceDescription"` 66 Engine string `json:"Engine"` 67 CreationTime time.Time `json:"CreationTime"` 68 NetworkType string `json:"NetworkType"` 69 ExpireTime time.Time `json:"ExpireTime"` 70 DBInstanceType string `json:"DBInstanceType"` 71 RegionId string `json:"RegionId"` 72 ShardList struct { 73 ShardAttribute []struct { 74 NodeId string `json:"NodeId"` 75 NodeClass string `json:"NodeClass"` 76 NodeStorage int `json:"NodeStorage"` 77 } `json:"ShardAttribute"` 78 } `json:"ShardList"` 79 EngineVersion string `json:"EngineVersion"` 80 DBInstanceStatus string `json:"DBInstanceStatus"` 81 82 DBInstanceStorage int `json:"DBInstanceStorage"` 83 MaintainStartTime string `json:"MaintainStartTime"` 84 MaintainEndTime string `json:"MaintainEndTime"` 85 StorageEngine string `json:"StorageEngine"` 86 VpcId string `json:"VPCId"` 87 VSwitchId string `json:"VSwitchId"` 88 VpcAuthMode string `json:"VpcAuthMode"` 89 ReplicationFactor string `json:"ReplicationFactor"` 90 } 91 92 var mongoSpec = map[string]struct { 93 VcpuCount int 94 VmemSizeGb int 95 }{} 96 97 func (self *SMongoDB) GetName() string { 98 if len(self.DBInstanceDescription) > 0 { 99 return self.DBInstanceDescription 100 } 101 return self.DBInstanceId 102 } 103 104 func (self *SMongoDB) GetId() string { 105 return self.DBInstanceId 106 } 107 108 func (self *SMongoDB) GetGlobalId() string { 109 return self.DBInstanceId 110 } 111 112 func (self *SMongoDB) GetStatus() string { 113 switch self.DBInstanceStatus { 114 case "Creating": 115 return api.MONGO_DB_STATUS_CREATING 116 case "DBInstanceClassChanging": 117 return api.MONGO_DB_STATUS_CHANGE_CONFIG 118 case "DBInstanceNetTypeChanging", "EngineVersionUpgrading", "GuardSwitching", "HASwitching", "Importing", "ImportingFromOthers", "LinkSwitching", "MinorVersionUpgrading", "NET_CREATING", "NET_DELETING", "NodeCreating", "NodeDeleting", "Restoring", "SSLModifying", "TempDBInstanceCreating", "Transing", "TransingToOthers": 119 return api.MONGO_DB_STATUS_DEPLOY 120 case "Deleting": 121 return api.MONGO_DB_STATUS_DELETING 122 case "Rebooting": 123 return api.MONGO_DB_STATUS_REBOOTING 124 case "Running": 125 return api.MONGO_DB_STATUS_RUNNING 126 default: 127 return strings.ToLower(self.DBInstanceStatus) 128 } 129 } 130 131 func (self *SMongoDB) GetProjectId() string { 132 return self.ResourceGroupId 133 } 134 135 func (self *SMongoDB) Refresh() error { 136 db, err := self.region.GetMongoDB(self.DBInstanceId) 137 if err != nil { 138 return errors.Wrapf(err, "GetMongoDB") 139 } 140 return jsonutils.Update(self, db) 141 } 142 143 func (self *SMongoDB) GetCreatedAt() time.Time { 144 return self.CreationTime 145 } 146 147 func (self *SMongoDB) GetExpiredAt() time.Time { 148 return self.ExpireTime 149 } 150 151 func (self *SMongoDB) GetIpAddr() string { 152 return "" 153 } 154 155 func (self *SMongoDB) GetEngine() string { 156 if len(self.StorageEngine) == 0 { 157 self.Refresh() 158 } 159 return self.StorageEngine 160 } 161 162 func (self *SMongoDB) GetEngineVersion() string { 163 return self.EngineVersion 164 } 165 166 func (self *SMongoDB) GetVpcId() string { 167 if self.NetworkType != "VPC" { 168 return "" 169 } 170 if len(self.VpcId) == 0 { 171 self.Refresh() 172 } 173 return self.VpcId 174 } 175 176 func (self *SMongoDB) GetNetworkId() string { 177 if self.NetworkType != "VPC" { 178 return "" 179 } 180 if len(self.VSwitchId) == 0 { 181 self.Refresh() 182 } 183 return self.VSwitchId 184 } 185 186 func (self *SMongoDB) GetZoneId() string { 187 if !strings.Contains(self.ZoneId, ",") { 188 return self.ZoneId 189 } 190 if index := strings.Index(self.ZoneId, ",") - 1; index > 0 { 191 return fmt.Sprintf("%s-%s", self.region.RegionId, string(self.ZoneId[index])) 192 } 193 return "" 194 } 195 196 func (self *SMongoDB) Delete() error { 197 return self.region.DeleteMongoDB(self.DBInstanceId) 198 } 199 200 func (self *SMongoDB) GetBillingType() string { 201 return convertChargeType(self.ChargeType) 202 } 203 204 func (self *SMongoDB) GetCategory() string { 205 return self.DBInstanceType 206 } 207 208 func (self *SMongoDB) GetDiskSizeMb() int { 209 if self.DBInstanceStorage == 0 { 210 self.Refresh() 211 } 212 return self.DBInstanceStorage * 1024 213 } 214 215 func (self *SMongoDB) GetInstanceType() string { 216 return self.DBInstanceClass 217 } 218 219 func (self *SMongoDB) GetMaintainTime() string { 220 return fmt.Sprintf("%s-%s", self.MaintainStartTime, self.MaintainEndTime) 221 } 222 223 func (self *SMongoDB) GetPort() int { 224 return 3717 225 } 226 227 func (self *SMongoDB) GetReplicationNum() int { 228 if len(self.ReplicationFactor) == 0 { 229 self.Refresh() 230 } 231 num, _ := strconv.Atoi(self.ReplicationFactor) 232 return int(num) 233 } 234 235 func (self *SMongoDB) GetVcpuCount() int { 236 self.region.GetchMongoSkus() 237 sku, ok := self.region.mongoSkus[self.DBInstanceClass] 238 if ok { 239 return sku.CpuCount 240 } 241 return 0 242 } 243 244 func (self *SMongoDB) GetVmemSizeMb() int { 245 self.region.GetchMongoSkus() 246 sku, ok := self.region.mongoSkus[self.DBInstanceClass] 247 if ok { 248 return sku.MemSizeGb * 1024 249 } 250 return 0 251 } 252 253 func (self *SMongoDB) GetIops() int { 254 iops, _ := self.region.GetIops(self.DBInstanceId) 255 return iops 256 } 257 258 func (self *SMongoDB) GetMaxConnections() int { 259 maxConnection, _ := self.region.GetMaxConnections(self.DBInstanceId) 260 return maxConnection 261 } 262 263 func (self *SMongoDB) GetNetworkAddress() string { 264 addr, _ := self.region.GetNetworkAddress(self.DBInstanceId) 265 return addr 266 } 267 268 func (self *SRegion) GetMongoDBsByType(mongoType string) ([]SMongoDB, error) { 269 dbs := []SMongoDB{} 270 for { 271 part, total, err := self.GetMongoDBs(mongoType, 100, len(dbs)/100) 272 if err != nil { 273 return nil, errors.Wrapf(err, "GetMongoDB") 274 } 275 dbs = append(dbs, part...) 276 if len(dbs) >= total { 277 break 278 } 279 } 280 return dbs, nil 281 } 282 283 func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error { 284 return self.region.SetResourceTags(ALIYUN_SERVICE_MONGO_DB, "INSTANCE", self.GetId(), tags, replace) 285 } 286 287 func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) { 288 db, err := self.GetMongoDB(id) 289 if err != nil { 290 return nil, errors.Wrapf(err, "GetMongoDB(%s)", id) 291 } 292 return db, nil 293 } 294 295 func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) { 296 dbs := []SMongoDB{} 297 for _, mongoType := range []string{"sharding", "replicate", "serverless"} { 298 part, err := self.GetMongoDBsByType(mongoType) 299 if err != nil { 300 return nil, err 301 } 302 dbs = append(dbs, part...) 303 } 304 ret := []cloudprovider.ICloudMongoDB{} 305 for i := range dbs { 306 dbs[i].region = self 307 ret = append(ret, &dbs[i]) 308 } 309 return ret, nil 310 } 311 312 func (self *SRegion) GetIops(id string) (int, error) { 313 ret, err := self.GetMongoDBAttribute(id) 314 if err != nil { 315 return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") 316 } 317 if len(ret) == 0 { 318 return 0, errors.Wrapf(err, "ret missing err") 319 } 320 return ret[0].MaxIops, nil 321 } 322 323 func (self *SRegion) GetMaxConnections(id string) (int, error) { 324 ret, err := self.GetMongoDBAttribute(id) 325 if err != nil { 326 return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") 327 } 328 if len(ret) == 0 { 329 return 0, errors.Wrapf(err, "ret missing err") 330 } 331 return ret[0].MaxConnections, nil 332 } 333 334 func (self *SRegion) GetNetworkAddress(id string) (string, error) { 335 ret, err := self.GetMongoDBAttribute(id) 336 if err != nil { 337 return "", errors.Wrapf(err, "DescribeDBInstanceAttribute err") 338 } 339 addrList := make([]string, 0) 340 for _, v := range ret[0].ReplicaSets.ReplicaSet { 341 addrList = append(addrList, v.ConnectionDomain) 342 } 343 addrs := strings.Join(addrList, ",") 344 return addrs, nil 345 } 346 347 func (self *SRegion) GetMongoDBAttribute(id string) ([]SMOngoDBAttribute, error) { 348 params := map[string]string{ 349 "Action": "DescribeDBInstanceAttribute", 350 "DBInstanceId": id, 351 } 352 resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) 353 if err != nil { 354 return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute err") 355 } 356 ret := []SMOngoDBAttribute{} 357 err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") 358 if err != nil { 359 return nil, errors.Wrapf(err, "unmarshal err") 360 } 361 return ret, err 362 } 363 364 func (self *SRegion) GetMongoDBs(mongoType string, pageSize int, pageNum int) ([]SMongoDB, int, error) { 365 if pageSize < 1 || pageSize > 100 { 366 pageSize = 100 367 } 368 if pageNum < 1 { 369 pageNum = 1 370 } 371 372 params := map[string]string{ 373 "PageSize": fmt.Sprintf("%d", pageSize), 374 "PageNumber": fmt.Sprintf("%d", pageNum), 375 } 376 if len(mongoType) > 0 { 377 params["DBInstanceType"] = mongoType 378 } 379 resp, err := self.mongodbRequest("DescribeDBInstances", params) 380 if err != nil { 381 return nil, 0, errors.Wrapf(err, "DescribeDBInstances") 382 } 383 ret := []SMongoDB{} 384 err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") 385 if err != nil { 386 return nil, 0, errors.Wrapf(err, "resp.Unmarshal") 387 } 388 totalCount, _ := resp.Int("TotalCount") 389 return ret, int(totalCount), nil 390 } 391 392 func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) { 393 params := map[string]string{ 394 "DBInstanceId": id, 395 } 396 resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) 397 if err != nil { 398 return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute") 399 } 400 ret := []SMongoDB{} 401 err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") 402 if err != nil { 403 return nil, errors.Wrapf(err, "resp.Unmarshal") 404 } 405 if len(ret) == 1 { 406 ret[0].region = self 407 return &ret[0], nil 408 } 409 return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) 410 } 411 412 func (self *SRegion) DeleteMongoDB(id string) error { 413 params := map[string]string{ 414 "DBInstanceId": id, 415 "ClientToken": utils.GenRequestId(20), 416 } 417 _, err := self.mongodbRequest("DeleteDBInstance", params) 418 return errors.Wrapf(err, "DeleteDBInstance") 419 } 420 421 type SMongoDBAvaibaleResource struct { 422 SupportedDBTypes struct { 423 SupportedDBType []struct { 424 DbType string 425 AvailableZones struct { 426 AvailableZone []struct { 427 ZoneId string 428 RegionId string 429 SupportedEngineVersions struct { 430 SupportedEngineVersion []struct { 431 Version string 432 SupportedEngines struct { 433 SupportedEngine []struct { 434 SupportedNodeTypes struct { 435 SupportedNodeType []struct { 436 NetworkTypes string 437 NodeType string 438 AvailableResources struct { 439 AvailableResource []struct { 440 InstanceClassRemark string 441 InstanceClass string 442 } 443 } 444 } 445 } 446 } 447 } 448 } 449 } 450 } 451 } 452 } 453 } 454 } 455 456 func (self *SRegion) GetchMongoSkus() (map[string]struct { 457 CpuCount int 458 MemSizeGb int 459 }, error) { 460 if len(self.mongoSkus) > 0 { 461 return self.mongoSkus, nil 462 } 463 self.mongoSkus = map[string]struct { 464 CpuCount int 465 MemSizeGb int 466 }{} 467 res, err := self.GetMongoDBAvailableResource() 468 if err != nil { 469 return nil, err 470 } 471 for _, dbType := range res.SupportedDBTypes.SupportedDBType { 472 for _, zone := range dbType.AvailableZones.AvailableZone { 473 for _, version := range zone.SupportedEngineVersions.SupportedEngineVersion { 474 for _, engine := range version.SupportedEngines.SupportedEngine { 475 for _, nodeType := range engine.SupportedNodeTypes.SupportedNodeType { 476 for _, sku := range nodeType.AvailableResources.AvailableResource { 477 _, ok := self.mongoSkus[sku.InstanceClass] 478 if !ok { 479 self.mongoSkus[sku.InstanceClass] = getMongoDBSkuDetails(sku.InstanceClassRemark) 480 } 481 } 482 } 483 } 484 } 485 } 486 } 487 return self.mongoSkus, nil 488 } 489 490 func getMongoDBSkuDetails(remark string) struct { 491 CpuCount int 492 MemSizeGb int 493 } { 494 ret := struct { 495 CpuCount int 496 MemSizeGb int 497 }{} 498 r, _ := regexp.Compile(`(\d{1,3})核(\d{1,3})G+`) 499 result := r.FindSubmatch([]byte(remark)) 500 if len(result) > 2 { 501 cpu, _ := strconv.Atoi(string(result[1])) 502 ret.CpuCount = int(cpu) 503 mem, _ := strconv.Atoi(string(result[2])) 504 ret.MemSizeGb = int(mem) 505 } else { 506 log.Warningf("not match sku remark %s", remark) 507 } 508 return ret 509 } 510 511 func (self *SRegion) GetMongoDBAvailableResource() (*SMongoDBAvaibaleResource, error) { 512 params := map[string]string{} 513 resp, err := self.mongodbRequest("DescribeAvailableResource", params) 514 if err != nil { 515 return nil, errors.Wrapf(err, "DescribeAvailableResource") 516 } 517 ret := &SMongoDBAvaibaleResource{} 518 err = resp.Unmarshal(ret) 519 if err != nil { 520 return nil, errors.Wrapf(err, "resp.Unmarshal") 521 } 522 return ret, nil 523 }