mongodb.go 15 KB

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