dbinstance.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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 google
  15. import (
  16. "context"
  17. "fmt"
  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/util/billing"
  25. "yunion.io/x/pkg/utils"
  26. billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
  27. api "yunion.io/x/cloudmux/pkg/apis/compute"
  28. "yunion.io/x/cloudmux/pkg/cloudprovider"
  29. "yunion.io/x/cloudmux/pkg/multicloud"
  30. )
  31. var (
  32. EngineVersions = map[string]GoogleSQLVersion{
  33. "MYSQL_5_5": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.5"},
  34. "MYSQL_5_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.6"},
  35. "MYSQL_5_7": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.7"},
  36. "MYSQL_8_0_41": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "8.0"},
  37. "MYSQL_8_0_40": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "8.0"},
  38. "POSTGRES_9_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "9.6"},
  39. "POSTGRES_10": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "10"},
  40. "POSTGRES_11": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "11"},
  41. "POSTGRES_12": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "12"},
  42. "POSTGRES_14": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "14"},
  43. "SQLSERVER_2017_STANDARD": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Standard"},
  44. "SQLSERVER_2017_ENTERPRISE": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Enterprise"},
  45. "SQLSERVER_2017_EXPRESS": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Express"},
  46. "SQLSERVER_2017_WEB": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Web"},
  47. }
  48. InstanceTypes = map[string]GoogleSQLType{
  49. "db-f1-micro": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 614},
  50. "db-g1-small": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1740},
  51. "D0": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 512},
  52. "D1": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1024},
  53. "D2": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 2048},
  54. "D4": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 5120},
  55. "D8": GoogleSQLType{VcpuCount: 2, VmemSizeMb: 10240},
  56. "D16": GoogleSQLType{VcpuCount: 4, VmemSizeMb: 10240},
  57. "D32": GoogleSQLType{VcpuCount: 8, VmemSizeMb: 10240},
  58. }
  59. )
  60. type GoogleSQLType struct {
  61. VcpuCount int
  62. VmemSizeMb int
  63. }
  64. type GoogleSQLVersion struct {
  65. Engine string
  66. Version string
  67. }
  68. type SDBInstanceLocationPreference struct {
  69. Zone string
  70. Kind string
  71. }
  72. type SDBInstanceMaintenanceWindow struct {
  73. Kind string
  74. Hour int
  75. Day int
  76. }
  77. type SDBInstanceBackupConfiguration struct {
  78. StartTime string
  79. Kind string
  80. Enabled bool
  81. BinaryLogEnabled bool
  82. }
  83. type SAuthorizedNetwork struct {
  84. Value string
  85. Kind string
  86. Name string
  87. }
  88. type SDBInstanceSettingIpConfiguration struct {
  89. PrivateNetwork string
  90. AuthorizedNetworks []SAuthorizedNetwork
  91. Ipv4Enabled bool
  92. }
  93. type SDBInstanceSetting struct {
  94. AuthorizedGaeApplications []string
  95. Tier string
  96. Kind string
  97. AvailabilityType string
  98. PricingPlan string
  99. ReplicationType string
  100. ActivationPolicy string
  101. IpConfiguration SDBInstanceSettingIpConfiguration
  102. LocationPreference SDBInstanceLocationPreference
  103. DataDiskType string
  104. MaintenanceWindow SDBInstanceMaintenanceWindow
  105. BackupConfiguration SDBInstanceBackupConfiguration
  106. SettingsVersion string
  107. StorageAutoResizeLimit string
  108. StorageAutoResize bool
  109. DataDiskSizeGb int
  110. DatabaseFlags []SDBInstanceParameter
  111. UserLabels map[string]string
  112. }
  113. type SDBInstanceIpAddress struct {
  114. Type string
  115. IpAddress string
  116. }
  117. type SDBInstanceCaCert struct {
  118. Kind string
  119. CertSerialNumber string
  120. Cert string
  121. CommonName string
  122. Sha1Fingerprint string
  123. Instance string
  124. CreateTime time.Time
  125. ExpirationTime time.Time
  126. }
  127. type SDBInstance struct {
  128. multicloud.SDBInstanceBase
  129. region *SRegion
  130. Kind string
  131. State string
  132. DatabaseVersion string
  133. Settings SDBInstanceSetting
  134. Etag string
  135. MasterInstanceName string
  136. IpAddresses []SDBInstanceIpAddress
  137. ServerCaCert SDBInstanceCaCert
  138. InstanceType string
  139. Project string
  140. ServiceAccountEmailAddress string
  141. BackendType string
  142. SelfLink string
  143. ConnectionName string
  144. Name string
  145. Region string
  146. GceZone string
  147. }
  148. func (region *SRegion) GetDBInstances(maxResults int, pageToken string) ([]SDBInstance, error) {
  149. instances := []SDBInstance{}
  150. params := map[string]string{"filter": "region=" + region.Name}
  151. err := region.RdsList("instances", params, maxResults, pageToken, &instances)
  152. if err != nil {
  153. return nil, errors.Wrap(err, "RdsList")
  154. }
  155. return instances, nil
  156. }
  157. func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) {
  158. instance := SDBInstance{region: region}
  159. err := region.rdsGet(instanceId, &instance)
  160. if err != nil {
  161. return nil, errors.Wrap(err, "RdsGet")
  162. }
  163. return &instance, nil
  164. }
  165. func (rds *SDBInstance) GetName() string {
  166. return rds.Name
  167. }
  168. func (rds *SDBInstance) GetId() string {
  169. return rds.SelfLink
  170. }
  171. func (rds *SDBInstance) GetGlobalId() string {
  172. return strings.TrimPrefix(rds.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION))
  173. }
  174. func (rds *SDBInstance) GetProjectId() string {
  175. return rds.region.GetProjectId()
  176. }
  177. func (rds *SDBInstance) IsEmulated() bool {
  178. return false
  179. }
  180. func (rds *SDBInstance) GetStatus() string {
  181. switch rds.State {
  182. case "RUNNABLE":
  183. return api.DBINSTANCE_RUNNING
  184. case "PENDING_CREATE":
  185. return api.DBINSTANCE_DEPLOYING
  186. case "MAINTENANCE":
  187. return api.DBINSTANCE_MAINTENANCE
  188. case "FAILED":
  189. return api.DBINSTANCE_CREATE_FAILED
  190. case "UNKNOWN_STATE", "SUSPENDED":
  191. return api.DBINSTANCE_UNKNOWN
  192. }
  193. return rds.State
  194. }
  195. func (rds *SDBInstance) GetBillingType() string {
  196. return billing_api.BILLING_TYPE_POSTPAID
  197. }
  198. func (rds *SDBInstance) GetCreatedAt() time.Time {
  199. return rds.ServerCaCert.CreateTime
  200. }
  201. func (rds *SDBInstance) GetExpiredAt() time.Time {
  202. return time.Time{}
  203. }
  204. func (rds *SDBInstance) GetMasterInstanceId() string {
  205. if len(rds.MasterInstanceName) > 0 {
  206. if master := strings.Split(rds.MasterInstanceName, ":"); len(master) == 2 {
  207. return fmt.Sprintf("projects/%s/instances/%s", master[0], master[1])
  208. }
  209. }
  210. return ""
  211. }
  212. func (rds *SDBInstance) GetSecurityGroupId() string {
  213. return ""
  214. }
  215. func (rds *SDBInstance) Refresh() error {
  216. instance, err := rds.region.GetDBInstance(rds.SelfLink)
  217. if err != nil {
  218. return errors.Wrapf(err, "GetDBInstance(%s)", rds.SelfLink)
  219. }
  220. return jsonutils.Update(rds, instance)
  221. }
  222. func (rds *SDBInstance) GetPort() int {
  223. switch rds.GetEngine() {
  224. case api.DBINSTANCE_TYPE_MYSQL:
  225. return 3306
  226. case api.DBINSTANCE_TYPE_POSTGRESQL:
  227. return 5432
  228. case api.DBINSTANCE_TYPE_SQLSERVER:
  229. return 1433
  230. default:
  231. return 0
  232. }
  233. }
  234. func (rds *SDBInstance) GetEngine() string {
  235. if e, ok := EngineVersions[rds.DatabaseVersion]; ok {
  236. return e.Engine
  237. }
  238. if strings.Contains(rds.DatabaseVersion, "MYSQL") {
  239. return api.DBINSTANCE_TYPE_MYSQL
  240. }
  241. if strings.Contains(rds.DatabaseVersion, "POSTGRES") {
  242. return api.DBINSTANCE_TYPE_POSTGRESQL
  243. }
  244. if strings.Contains(rds.DatabaseVersion, "SQLSERVER") {
  245. return api.DBINSTANCE_TYPE_SQLSERVER
  246. }
  247. return rds.DatabaseVersion
  248. }
  249. func (rds *SDBInstance) GetEngineVersion() string {
  250. if e, ok := EngineVersions[rds.DatabaseVersion]; ok {
  251. return e.Version
  252. }
  253. version := strings.TrimPrefix(rds.DatabaseVersion, "MYSQL_")
  254. version = strings.TrimPrefix(version, "POSTGRES_")
  255. version = strings.TrimPrefix(version, "SQLSERVER_")
  256. version = strings.ReplaceAll(version, "_", ".")
  257. return version
  258. }
  259. func (rds *SDBInstance) GetInstanceType() string {
  260. return rds.Settings.Tier
  261. }
  262. func (rds *SDBInstance) GetVcpuCount() int {
  263. if t, ok := InstanceTypes[rds.Settings.Tier]; ok {
  264. return t.VcpuCount
  265. }
  266. numStr := ""
  267. if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") {
  268. numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-standard-")
  269. } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") {
  270. numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-highmem-")
  271. } else {
  272. numStr = strings.TrimPrefix(rds.Settings.Tier, "db-custom-")
  273. numStr = strings.Split(numStr, "-")[0]
  274. }
  275. cpu, _ := strconv.ParseInt(numStr, 10, 32)
  276. return int(cpu)
  277. }
  278. func (rds *SDBInstance) GetVmemSizeMB() int {
  279. if t, ok := InstanceTypes[rds.Settings.Tier]; ok {
  280. return t.VmemSizeMb
  281. }
  282. if strings.HasPrefix(rds.Settings.Tier, "db-custom-") {
  283. info := strings.Split(rds.Settings.Tier, "-")
  284. numStr := info[len(info)-1]
  285. mem, _ := strconv.ParseInt(numStr, 10, 32)
  286. return int(mem)
  287. } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") {
  288. return rds.GetVcpuCount() * 3840
  289. } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") {
  290. return rds.GetVcpuCount() * 3840 * 2
  291. }
  292. return 0
  293. }
  294. func (rds *SDBInstance) GetDiskSizeGB() int {
  295. return rds.Settings.DataDiskSizeGb
  296. }
  297. func (rds *SDBInstance) GetCategory() string {
  298. switch rds.Settings.AvailabilityType {
  299. case "REGIONAL":
  300. return api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL
  301. default:
  302. return api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL
  303. }
  304. }
  305. func (rds *SDBInstance) GetStorageType() string {
  306. return rds.Settings.DataDiskType
  307. }
  308. func (rds *SDBInstance) GetMaintainTime() string {
  309. startTime := (rds.Settings.MaintenanceWindow.Hour + 8) % 24
  310. startDay := (rds.Settings.MaintenanceWindow.Day + 1) % 7
  311. return fmt.Sprintf("%s %02d:00 - %02d:00", time.Weekday(startDay).String(), startTime, startTime+1)
  312. }
  313. func (rds *SDBInstance) GetConnectionStr() string {
  314. for _, ip := range rds.IpAddresses {
  315. if ip.Type == "PRIMARY" {
  316. return ip.IpAddress
  317. }
  318. }
  319. return ""
  320. }
  321. func (rds *SDBInstance) GetInternalConnectionStr() string {
  322. ret := []string{rds.ConnectionName}
  323. for _, ip := range rds.IpAddresses {
  324. if ip.Type == "PRIVATE" {
  325. ret = append(ret, ip.IpAddress)
  326. }
  327. }
  328. return strings.Join(ret, ",")
  329. }
  330. func (rds *SDBInstance) GetZone1Id() string {
  331. zones, err := rds.region.GetIZones()
  332. if err != nil {
  333. log.Errorf("failed to found rds %s zone %s", rds.Name, rds.GceZone)
  334. return ""
  335. }
  336. for _, zone := range zones {
  337. if zone.GetId() == rds.GceZone {
  338. return zone.GetGlobalId()
  339. }
  340. }
  341. return ""
  342. }
  343. func (rds *SDBInstance) GetZone2Id() string {
  344. return ""
  345. }
  346. func (rds *SDBInstance) GetZone3Id() string {
  347. return ""
  348. }
  349. func (rds *SDBInstance) GetIVpcId() string {
  350. return ""
  351. }
  352. func (rds *SDBInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) {
  353. return nil, nil
  354. }
  355. func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) {
  356. ret := []cloudprovider.ICloudDBInstanceParameter{}
  357. for i := range rds.Settings.DatabaseFlags {
  358. rds.Settings.DatabaseFlags[i].rds = rds
  359. ret = append(ret, &rds.Settings.DatabaseFlags[i])
  360. }
  361. return ret, nil
  362. }
  363. func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) {
  364. databases, err := rds.region.GetDBInstanceDatabases(rds.Name)
  365. if err != nil {
  366. return nil, errors.Wrap(err, "GetDBInstanceDatabases")
  367. }
  368. ret := []cloudprovider.ICloudDBInstanceDatabase{}
  369. for i := range databases {
  370. databases[i].rds = rds
  371. ret = append(ret, &databases[i])
  372. }
  373. return ret, nil
  374. }
  375. func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) {
  376. accounts, err := rds.region.GetDBInstanceAccounts(rds.Name)
  377. if err != nil {
  378. return nil, errors.Wrap(err, "GetDBInstanceAccounts")
  379. }
  380. ret := []cloudprovider.ICloudDBInstanceAccount{}
  381. for i := range accounts {
  382. accounts[i].rds = rds
  383. ret = append(ret, &accounts[i])
  384. }
  385. return ret, nil
  386. }
  387. func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
  388. backups, err := rds.region.GetDBInstanceBackups(rds.Name)
  389. if err != nil {
  390. return nil, errors.Wrap(err, "GetDBInstanceBackups")
  391. }
  392. ret := []cloudprovider.ICloudDBInstanceBackup{}
  393. for i := range backups {
  394. backups[i].rds = rds
  395. ret = append(ret, &backups[i])
  396. }
  397. return ret, nil
  398. }
  399. func (region *SRegion) ChangeDBInstanceConfig(instanceId string, diskSizeGb int, instanceType string) error {
  400. rds, err := region.GetDBInstance(instanceId)
  401. if err != nil {
  402. return errors.Wrapf(err, "GetDBInstance(%s)", instanceId)
  403. }
  404. body := map[string]interface{}{}
  405. settings := map[string]interface{}{}
  406. if len(instanceType) > 0 && instanceType != rds.GetInstanceType() {
  407. settings["tier"] = instanceType
  408. }
  409. if diskSizeGb > 0 && diskSizeGb != rds.GetDiskSizeGB() {
  410. settings["dataDiskSizeGb"] = diskSizeGb
  411. }
  412. if len(settings) == 0 {
  413. return nil
  414. }
  415. body["settings"] = settings
  416. return region.rdsPatch(rds.SelfLink, jsonutils.Marshal(body))
  417. }
  418. func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error {
  419. return rds.region.ChangeDBInstanceConfig(rds.SelfLink, config.DiskSizeGB, config.InstanceType)
  420. }
  421. func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error {
  422. return cloudprovider.ErrNotSupported
  423. }
  424. func (region *SRegion) DBInstancePublicConnectionOperation(instanceId string, open bool) error {
  425. ipConfiguration := map[string]interface{}{
  426. "ipv4Enabled": open,
  427. }
  428. if open {
  429. ipConfiguration["authorizedNetworks"] = []map[string]string{
  430. map[string]string{
  431. "name": "White list",
  432. "value": "0.0.0.0/0",
  433. },
  434. }
  435. }
  436. body := map[string]interface{}{
  437. "settings": map[string]interface{}{
  438. "ipConfiguration": ipConfiguration,
  439. },
  440. }
  441. return region.rdsPatch(instanceId, jsonutils.Marshal(body))
  442. }
  443. func (rds *SDBInstance) OpenPublicConnection() error {
  444. return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, true)
  445. }
  446. func (rds *SDBInstance) ClosePublicConnection() error {
  447. return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, false)
  448. }
  449. func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error {
  450. return rds.region.CreateDatabase(rds.SelfLink, conf.Name, conf.CharacterSet)
  451. }
  452. func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error {
  453. return rds.region.CreateDBInstanceAccount(rds.SelfLink, conf.Name, conf.Password, "%")
  454. }
  455. func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
  456. err := rds.region.CreateDBInstanceBackup(rds.SelfLink, conf.Name, conf.Description)
  457. if err != nil {
  458. return "", errors.Wrap(err, "CreateIBackup")
  459. }
  460. return "", nil
  461. }
  462. func (region *SRegion) RecoverFromBackup(instanceName, dest string, backupId string) error {
  463. backup, err := region.GetDBInstanceBackup(backupId)
  464. if err != nil {
  465. return errors.Wrap(err, "GetDBInstanceBackup")
  466. }
  467. body := map[string]interface{}{
  468. "restoreBackupContext": map[string]string{
  469. "backupRunId": backup.Id,
  470. "instanceId": instanceName,
  471. "project": region.client.projectId,
  472. },
  473. }
  474. return region.rdsDo(dest, "restoreBackup", nil, jsonutils.Marshal(body))
  475. }
  476. func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error {
  477. instanceName := rds.Name
  478. if len(conf.OriginDBInstanceExternalId) > 0 {
  479. instance, err := rds.region.GetDBInstance(conf.OriginDBInstanceExternalId)
  480. if err != nil {
  481. return errors.Wrapf(err, "GetInstance(%s)", conf.OriginDBInstanceExternalId)
  482. }
  483. instanceName = instance.Name
  484. }
  485. return rds.region.RecoverFromBackup(instanceName, rds.SelfLink, conf.BackupId)
  486. }
  487. func (rds *SDBInstance) Reboot() error {
  488. return rds.region.rdsDo(rds.SelfLink, "restart", nil, nil)
  489. }
  490. func (rds *SDBInstance) Delete() error {
  491. return rds.region.DeleteDBInstance(rds.SelfLink)
  492. }
  493. func (region *SRegion) DeleteDBInstance(id string) error {
  494. return region.rdsDelete(id)
  495. }
  496. func (region *SRegion) CreateRds(name, engine, databaseVersion, category, instanceType, storageType string, diskSizeGb int, vpcId, zoneId, password string) (*SDBInstance, error) {
  497. settings := map[string]interface{}{
  498. "tier": instanceType,
  499. "storageAutoResize": true,
  500. "dataDiskType": storageType,
  501. "dataDiskSizeGb": diskSizeGb,
  502. }
  503. if utils.IsInStringArray(category, []string{api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL, api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL}) {
  504. settings["availabilityType"] = strings.ToUpper(category)
  505. backupConfiguration := map[string]interface{}{
  506. "enabled": true,
  507. "startTime": "19:00",
  508. }
  509. if engine == api.DBINSTANCE_TYPE_MYSQL {
  510. backupConfiguration["binaryLogEnabled"] = true
  511. }
  512. settings["backupConfiguration"] = backupConfiguration
  513. }
  514. ipConfiguration := map[string]interface{}{
  515. "ipv4Enabled": true,
  516. }
  517. ipConfiguration["authorizedNetworks"] = []map[string]string{
  518. map[string]string{
  519. "name": "White list",
  520. "value": "0.0.0.0/0",
  521. },
  522. }
  523. settings["ipConfiguration"] = ipConfiguration
  524. body := map[string]interface{}{
  525. "databaseVersion": databaseVersion,
  526. "name": name,
  527. "region": region.Name,
  528. "settings": settings,
  529. "backendType": "SECOND_GEN",
  530. "instanceType": "CLOUD_SQL_INSTANCE",
  531. }
  532. if len(zoneId) > 0 {
  533. settings["locationPreference"] = map[string]string{
  534. "zone": zoneId,
  535. }
  536. }
  537. if len(password) > 0 {
  538. body["rootPassword"] = password
  539. }
  540. rds := SDBInstance{region: region}
  541. err := region.rdsInsert("instances", jsonutils.Marshal(body), &rds)
  542. if err != nil {
  543. if e, ok := errors.Cause(err).(*gError); ok && e.ErrorInfo.Code == 409 { //The instance or operation is not in an appropriate state to handle the request
  544. return nil, fmt.Errorf("the name %s is unavailable because it was used recently", name)
  545. }
  546. return nil, errors.Wrap(err, "rdsInsert")
  547. }
  548. return &rds, nil
  549. }
  550. func (region *SRegion) CreateDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (*SDBInstance, error) {
  551. desc.EngineVersion = strings.ToUpper(desc.EngineVersion)
  552. desc.EngineVersion = strings.Replace(desc.EngineVersion, ".", "_", -1)
  553. desc.EngineVersion = strings.Replace(desc.EngineVersion, " ", "_", -1)
  554. if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL {
  555. desc.Engine = "POSTGRES"
  556. }
  557. databaseVersion := fmt.Sprintf("%s_%s", strings.ToUpper(desc.Engine), desc.EngineVersion)
  558. if _, ok := EngineVersions[databaseVersion]; !ok {
  559. return nil, fmt.Errorf("Unsupport %s version %s", desc.Engine, desc.EngineVersion)
  560. }
  561. rds, err := region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, desc.ZoneId, desc.Password)
  562. if err != nil {
  563. return nil, errors.Wrapf(err, "CreateRds")
  564. }
  565. return rds, nil
  566. }
  567. func (self *SDBInstance) GetTags() (map[string]string, error) {
  568. return self.Settings.UserLabels, nil
  569. }
  570. func (self *SDBInstance) GetSysTags() map[string]string {
  571. return nil
  572. }
  573. func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error {
  574. params := map[string]interface{}{
  575. "settings": map[string]interface{}{
  576. "userLabels": tags,
  577. },
  578. }
  579. err := self.region.rdsPatch(self.GetId(), jsonutils.Marshal(params))
  580. return errors.Wrapf(err, "rdsPatch")
  581. }