feature: add qcloud rds support

This commit is contained in:
Qu Xuan
2020-09-27 17:10:18 +08:00
parent fc15772ab6
commit f776054187
52 changed files with 2968 additions and 486 deletions
+4 -35
View File
@@ -15,44 +15,13 @@
package compute
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type DBInstanceSkuListOption struct {
options.BaseListOptions
Engine string
EngineVersion string
Category string
StorageType string
Cloudregion string
}
R(&DBInstanceSkuListOption{}, "dbinstance-sku-list", "List dbinstance skus", func(s *mcclient.ClientSession, args *DBInstanceSkuListOption) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
result, err := modules.DBInstanceSkus.List(s, params)
if err != nil {
return err
}
printList(result, modules.DBInstanceSkus.GetColumns(s))
return nil
})
type DBInstanceSkuIdOption struct {
ID string `help:"DBInstance Id or name"`
}
R(&DBInstanceSkuIdOption{}, "dbinstance-sku-show", "Show dbinstance sku details", func(s *mcclient.ClientSession, args *DBInstanceSkuIdOption) error {
result, err := modules.DBInstanceSkus.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
cmd := shell.NewResourceCmd(&modules.DBInstanceSkus).WithKeyword("dbinstance-sku")
cmd.List(&options.DBInstanceSkuListOption{})
cmd.Show(&options.DBInstanceSkuIdOption{})
}
+11 -20
View File
@@ -107,19 +107,10 @@ type DBInstanceCreateInput struct {
//
// | 平台 | 支持类型 | 说明 |
// | ----- | ------ | --- |
// | 华为云 |ha, single, replica| |
// | 阿里云 |basic, high_availability, always_on, finance||
// | Google |Zonal, Regional | |
// 翻译:
// basic: 基础版
// high_availability: 高可用
// always_on: 集群版
// finance: 金融版, 三节点
// ha: 高可用
// single: 单机
// replica: 只读
// Zonal: 单区域
// Regional: 区域级
// | 华为云 |ha, single, replica| ha: 高可用, single: 单机, replica: 只读|
// | 阿里云 |basic, high_availability, always_on, finance|basic: 基础版, high_availability: 高可用, always_on: 集群版, finance: 金融版, 三节点|
// | Google |Zonal, Regional | Zonal: 单区域, Regional: 区域级|
// | 腾讯云 |fe, ha, basic | ha: 高可用, basic: 基础版, fe: 金融版|
// required: true
Category string `json:"category"`
@@ -127,13 +118,12 @@ type DBInstanceCreateInput struct {
//
//
//
// | 平台 | 支持类型 |
// | 华为云 |SSD, SAS, SATA|
// | 阿里云 |local_ssd, cloud_essd, cloud_ssd|
// | Google |PD_SSD, PD_HDD|
// 翻译:
// PD_SSD: SSD
// PD_HDD: HDD
// | 平台 | 支持类型 | 说明 |
// | ----- | ------ | --- |
// | 华为云 |SSD, SAS, SATA| |
// | 阿里云 |local_ssd, cloud_essd, cloud_ssd| |
// | Google |PD_SSD, PD_HDD| PD_SSD: SSD, PD_HDD: HDD|
// | 腾讯云 |cloud_ssd, local_ssd| |
// required: true
StorageType string `json:"storage_type"`
@@ -146,6 +136,7 @@ type DBInstanceCreateInput struct {
// 阿里云不需要此参数
// 华为云会默认创建一个用户,若不传此参数, 则为随机密码
// 谷歌云会默认创建一个用户,若不传此参数, 则为随机密码
// 腾讯云会默认创建一个用户,若不传此参数, 则为随机密码
Password string `json:"password"`
// 是否不设置初始密码
+1
View File
@@ -48,6 +48,7 @@ type DBInstanceAccountCreateInput struct {
// | ---- |------- |
// | Aliyun |MySQL, MariaBD, SQLServer |
// | 华为云 |MySQL, MariaBD |
// | 腾讯云 |MySQL |
// required: true
// 阿里云SQL Server 2017集群版不支持创建账号
// 实例状态必须是运行中
+27
View File
@@ -16,6 +16,7 @@ package compute
const (
//实例状态
DBINSTANCE_INIT = "init" //初始化
DBINSTANCE_DEPLOYING = "deploying" //部署中
DBINSTANCE_RUNNING = "running" //运行中
DBINSTANCE_REBOOTING = "rebooting" //重启中
@@ -99,6 +100,11 @@ const (
ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON = "always_on" //集群版
ALIYUN_DBINSTANCE_CATEGORY_FINANCE = "finance" //金融版
//腾讯云实例类型
QCLOUD_DBINSTANCE_CATEGORY_BASIC = "basic" //基础版
QCLOUD_DBINSTANCE_CATEGORY_HA = "ha" //高可用
QCLOUD_DBINSTANCE_CATEGORY_FINANCE = "fe" //金融版
//华为云实例类型
HUAWEI_DBINSTANCE_CATEGORY_HA = "ha" //主备
HUAWEI_DBINSTANCE_CATEGORY_SINGLE = "single" //单机
@@ -118,6 +124,11 @@ const (
HUAWEI_DBINSTANCE_STORAGE_TYPE_ULTRAHIGHPRO = "ULTRAHIGHPRO"
HUAWEI_DBINSTANCE_STORAGE_TYPE_COMMON = "COMMON"
HUAWEI_DBINSTANCE_STORAGE_TYPE_HIGH = "HIGH"
//腾讯云
QCLOUD_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD = "local_ssd" //本地盘SSD盘
QCLOUD_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD = "cloud_ssd" //SSD云盘
)
var (
@@ -128,4 +139,20 @@ var (
ALIYUN_SQL_SERVER_DENY_KEYWORD []string = []string{
"root", " admin", " eagleye", " master", " aurora", " sa", " sysadmin", " administrator", " mssqld", " public", " securityadmin", " serveradmin", " setupadmin", " processadmin", " diskadmin", " dbcreator", " bulkadmin", " tempdb", " msdb", " model", " distribution", " mssqlsystemresource", " guest", " add", " except", " percent", " all", " exec", " plan", " alter", " execute", " precision", " and", " exists", " primary", " any", " exit", " print", " as", " fetch", " proc", " asc", " file", " procedure", " authorization", " fillfactor", " public", " backup", " for", " raiserror", " begin", " foreign", " read", " between", " freetext", " readtext", " break", " freetexttable", " reconfigure", " browse", " from", " references", " bulk", " full", " replication", " by", " function", " restore", " cascade", " goto", " restrict", " case", " grant", " return", " check", " group", " revoke", " checkpoint", " having", " right", " close", " holdlock", " rollback", " clustered", " identity", " rowcount", " coalesce", " identity_insert", " rowguidcol", " collate", " identitycol", " rule", " column", " if", " save", " commit", " in", " schema", " compute", " index", " select", " constraint", " inner", " session_user", " contains", " insert", " set", " containstable", " intersect", " setuser", " continue", " into", " shutdown", " convert", " is", " some", " create", " join", " statistics", " cross", " key", " system_user", " current", " kill", " table", " current_date", " left", " textsize", " current_time", " like", " then", " current_timestamp", " lineno", " to", " current_user", " load", " top", " cursor", " national", " tran", " database", " nocheck", " transaction", " dbcc", " nonclustered", " trigger", " deallocate", " not", " truncate", " declare", " null", " tsequal", " default", " nullif", " union", " delete", " of", " unique", " deny", " off", " update", " desc", " offsets", " updatetext", " disk", " on", " use", " distinct", " open", " user", " distributed", " opendatasource", " values", " double", " openquery", " varying", " drop", " openrowset", " view", " dummy", " openxml", " waitfor", " dump", " option", " when", " else", " or", " where", " end", " order", " while", " errlvl", " outer", " with", " escape", " over", " writetext", " galaxy",
}
RW_PRIVILEGE_SET = []string{
"SELECT", "INSERT", "UPDATE", "DELETE", "CREATE",
"DROP", "REFERENCES", "INDEX", "ALTER", "CREATE TEMPORARY TABLES",
"LOCK TABLES", "EXECUTE", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE",
"ALTER ROUTINE", "EVENT", "TRIGGER", "PROCESS", "REPLICATION SLAVE",
"REPLICATION CLIENT",
}
R_PRIVILEGE_SET = []string{"SELECT", "LOCK TABLES", "SHOW VIEW", "PROCESS", "REPLICATION SLAVE", "REPLICATION CLIENT"}
QCLOUD_RW_PRIVILEGE_SET = []string{
"SELECT", "INSERT", "UPDATE", "DELETE", "CREATE",
"DROP", "REFERENCES", "INDEX", "ALTER", "CREATE TEMPORARY TABLES",
"LOCK TABLES", "EXECUTE", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE",
"ALTER ROUTINE", "EVENT", "TRIGGER",
}
QCLOUD_R_PRIVILEGE_SET = []string{"SELECT", "LOCK TABLES", "SHOW VIEW"}
)
+1
View File
@@ -44,6 +44,7 @@ type DBInstanceDatabaseCreateInput struct {
// | ---- |------- |
// | Aliyun |MySQL, MariaBD, SQLServer |
// | 华为云 |MySQL, MariaBD |
// | 腾讯云 | |
// required: true
// 阿里云SQL Server 2017集群版不支持创建数据库
// 阿里云只读实例不支持创建数据库
+1
View File
@@ -16,4 +16,5 @@ package compute
const (
DBINSTANCE_SKU_AVAILABLE = "available"
DBINSTANCE_SKU_SOLDOUT = "soldout"
)
+15 -7
View File
@@ -26,19 +26,24 @@ type SExtraIp struct {
URL string
}
type SZoneInfo struct {
Zone1 string
Zone2 string
Zone3 string
ZoneId string
}
type SInstanceType struct {
InstanceType string
ZoneIds []string
SZoneInfo
}
type SManagedDBInstanceCreateConfig struct {
Name string
Description string
StorageType string
DiskSizeGB int
SInstanceType
Name string
Description string
StorageType string
DiskSizeGB int
InstanceType string
InstanceTypes []SInstanceType
VcpuCount int
VmemSizeMb int
VpcId string
@@ -61,6 +66,8 @@ type SManagedDBInstanceChangeConfig struct {
DiskSizeGB int
StorageType string
InstanceType string
VcpuCount int
VmemSizeMb int
}
type SDBInstanceDatabaseCreateConfig struct {
@@ -77,6 +84,7 @@ type SDBInstancePrivilege struct {
type SDBInstanceAccountCreateConfig struct {
Name string
Host string
Description string
Password string
}
+3 -1
View File
@@ -833,7 +833,9 @@ type ICloudDBInstanceDatabase interface {
}
type ICloudDBInstanceAccount interface {
ICloudResource
GetName() string
GetStatus() string
GetHost() string
GetIDBInstanceAccountPrivileges() ([]ICloudDBInstanceAccountPrivilege, error)
+49 -36
View File
@@ -813,24 +813,38 @@ func syncRegionDBInstances(ctx context.Context, userCred mcclient.TokenCredentia
return
}
syncDBInstanceNetwork(ctx, userCred, syncResults, &localInstances[i], remoteInstances[i])
syncDBInstanceParameters(ctx, userCred, syncResults, &localInstances[i], remoteInstances[i])
syncDBInstanceDatabases(ctx, userCred, syncResults, &localInstances[i], remoteInstances[i])
syncDBInstanceAccounts(ctx, userCred, syncResults, &localInstances[i], remoteInstances[i])
syncDBInstanceResource(ctx, userCred, syncResults, &localInstances[i], remoteInstances[i])
}()
}
}
func syncDBInstanceNetwork(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) {
func syncDBInstanceResource(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) {
err := syncDBInstanceNetwork(ctx, userCred, syncResults, localInstance, remoteInstance)
if err != nil {
log.Errorf("syncDBInstanceNetwork error: %v", err)
}
err = syncDBInstanceParameters(ctx, userCred, syncResults, localInstance, remoteInstance)
if err != nil {
log.Errorf("syncDBInstanceParameters error: %v", err)
}
err = syncDBInstanceDatabases(ctx, userCred, syncResults, localInstance, remoteInstance)
if err != nil {
log.Errorf("syncDBInstanceParameters error: %v", err)
}
err = syncDBInstanceAccounts(ctx, userCred, syncResults, localInstance, remoteInstance)
if err != nil {
log.Errorf("syncDBInstanceAccounts: %v", err)
}
}
func syncDBInstanceNetwork(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) error {
network, err := remoteInstance.GetDBNetwork()
if err != nil {
msg := fmt.Sprintf("GetDBNetwork for dbinstance %s failed %s", remoteInstance.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetDBNetwork")
}
if network == nil {
return
return nil
}
result := DBInstanceNetworkManager.SyncDBInstanceNetwork(ctx, userCred, localInstance, network)
@@ -839,16 +853,15 @@ func syncDBInstanceNetwork(ctx context.Context, userCred mcclient.TokenCredentia
msg := result.Result()
log.Infof("SyncDBInstanceNetwork for dbinstance %s result: %s", localInstance.Name, msg)
if result.IsError() {
return
return result.AllError()
}
return nil
}
func syncDBInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) {
func syncDBInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) error {
parameters, err := remoteInstance.GetIDBInstanceParameters()
if err != nil {
msg := fmt.Sprintf("GetIDBInstanceParameters for dbinstance %s failed %s", remoteInstance.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetIDBInstanceParameters")
}
result := DBInstanceParameterManager.SyncDBInstanceParameters(ctx, userCred, localInstance, parameters)
@@ -857,16 +870,15 @@ func syncDBInstanceParameters(ctx context.Context, userCred mcclient.TokenCreden
msg := result.Result()
log.Infof("SyncDBInstanceParameters for dbinstance %s result: %s", localInstance.Name, msg)
if result.IsError() {
return
return result.AllError()
}
return nil
}
func syncRegionDBInstanceBackups(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
func syncRegionDBInstanceBackups(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) error {
backups, err := remoteRegion.GetIDBInstanceBackups()
if err != nil {
msg := fmt.Sprintf("GetIDBInstanceBackups for dbinstance %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetIDBInstanceBackups")
}
result := DBInstanceBackupManager.SyncDBInstanceBackups(ctx, userCred, provider, nil, localRegion, backups)
@@ -875,17 +887,16 @@ func syncRegionDBInstanceBackups(ctx context.Context, userCred mcclient.TokenCre
msg := result.Result()
log.Infof("SyncDBInstanceBackups for region %s result: %s", localRegion.Name, msg)
if result.IsError() {
return
return result.AllError()
}
return nil
}
func syncDBInstanceDatabases(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) {
func syncDBInstanceDatabases(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) error {
databases, err := remoteInstance.GetIDBInstanceDatabases()
if err != nil {
msg := fmt.Sprintf("GetIDBInstanceDatabases for dbinstance %s failed %s", remoteInstance.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetIDBInstanceDatabases")
}
result := DBInstanceDatabaseManager.SyncDBInstanceDatabases(ctx, userCred, localInstance, databases)
@@ -894,16 +905,15 @@ func syncDBInstanceDatabases(ctx context.Context, userCred mcclient.TokenCredent
msg := result.Result()
log.Infof("SyncDBInstanceDatabases for dbinstance %s result: %s", localInstance.Name, msg)
if result.IsError() {
return
return result.AllError()
}
return nil
}
func syncDBInstanceAccounts(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) {
func syncDBInstanceAccounts(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localInstance *SDBInstance, remoteInstance cloudprovider.ICloudDBInstance) error {
accounts, err := remoteInstance.GetIDBInstanceAccounts()
if err != nil {
msg := fmt.Sprintf("GetIDBInstanceAccounts for dbinstance %s failed %s", remoteInstance.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetIDBInstanceAccounts")
}
localAccounts, remoteAccounts, result := DBInstanceAccountManager.SyncDBInstanceAccounts(ctx, userCred, localInstance, accounts)
@@ -912,7 +922,7 @@ func syncDBInstanceAccounts(ctx context.Context, userCred mcclient.TokenCredenti
msg := result.Result()
log.Infof("SyncDBInstanceAccounts for dbinstance %s result: %s", localInstance.Name, msg)
if result.IsError() {
return
return result.AllError()
}
for i := 0; i < len(localAccounts); i++ {
@@ -924,18 +934,20 @@ func syncDBInstanceAccounts(ctx context.Context, userCred mcclient.TokenCredenti
return
}
syncDBInstanceAccountPrivileges(ctx, userCred, syncResults, &localAccounts[i], remoteAccounts[i])
err = syncDBInstanceAccountPrivileges(ctx, userCred, syncResults, &localAccounts[i], remoteAccounts[i])
if err != nil {
log.Errorf("syncDBInstanceAccountPrivileges error: %v", err)
}
}()
}
return nil
}
func syncDBInstanceAccountPrivileges(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localAccount *SDBInstanceAccount, remoteAccount cloudprovider.ICloudDBInstanceAccount) {
func syncDBInstanceAccountPrivileges(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, localAccount *SDBInstanceAccount, remoteAccount cloudprovider.ICloudDBInstanceAccount) error {
privileges, err := remoteAccount.GetIDBInstanceAccountPrivileges()
if err != nil {
msg := fmt.Sprintf("GetIDBInstanceAccountPrivileges for dbinstance account %s failed %s", remoteAccount.GetName(), err)
log.Errorf(msg)
return
return errors.Wrapf(err, "GetIDBInstanceAccountPrivileges for %s(%s)", localAccount.Name, localAccount.Id)
}
result := DBInstancePrivilegeManager.SyncDBInstanceAccountPrivileges(ctx, userCred, localAccount, privileges)
@@ -944,8 +956,9 @@ func syncDBInstanceAccountPrivileges(ctx context.Context, userCred mcclient.Toke
msg := result.Result()
log.Infof("SyncDBInstanceAccountPrivileges for account %s result: %s", localAccount.Name, msg)
if result.IsError() {
return
return result.AllError()
}
return nil
}
func syncRegionSnapshots(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
+62 -52
View File
@@ -17,6 +17,7 @@ package models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -39,7 +40,6 @@ import (
type SDBInstanceAccountManager struct {
db.SStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SDBInstanceResourceBaseManager
}
@@ -59,15 +59,13 @@ func init() {
type SDBInstanceAccount struct {
db.SStatusStandaloneResourceBase
db.SExternalizedResourceBase
Host string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"optional" default:"%"`
SDBInstanceResourceBase `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"`
// 数据库密码
Secret string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"optional"`
// RDS实例Id
// DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"`
}
func (manager *SDBInstanceAccountManager) GetContextManagers() [][]db.IModelManager {
@@ -224,10 +222,6 @@ func (manager *SDBInstanceAccountManager) ListItemFilter(
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DBInstanceFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter")
@@ -264,19 +258,33 @@ func (manager *SDBInstanceAccountManager) QueryDistinctExtraField(q *sqlchemy.SQ
return q, httperrors.ErrNotFound
}
type sRdsAccount struct {
Name string
DBInstanceId string `json:"dbinstance_id"`
Host string
}
func (self *SDBInstanceAccount) GetUniqValues() jsonutils.JSONObject {
return jsonutils.Marshal(map[string]string{"dbinstance_id": self.DBInstanceId})
return jsonutils.Marshal(sRdsAccount{Name: self.Name, DBInstanceId: self.DBInstanceId, Host: self.Host})
}
func (manager *SDBInstanceAccountManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
dbinstanceId, _ := data.GetString("dbinstance_id")
return jsonutils.Marshal(map[string]string{"dbinstance_id": dbinstanceId})
info := sRdsAccount{}
data.Unmarshal(&info)
return jsonutils.Marshal(info)
}
func (manager *SDBInstanceAccountManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
dbinstanceId, _ := values.GetString("dbinstance_id")
if len(dbinstanceId) > 0 {
q = q.Equals("dbinstance_id", dbinstanceId)
info := sRdsAccount{}
values.Unmarshal(&info)
if len(info.DBInstanceId) > 0 {
q = q.Equals("dbinstance_id", info.DBInstanceId)
}
if len(info.Name) > 0 {
q = q.Equals("name", info.Name)
}
if len(info.Host) > 0 {
q = q.Equals("host", info.Host)
}
return q
}
@@ -612,54 +620,57 @@ func (manager *SDBInstanceAccountManager) SyncDBInstanceAccounts(ctx context.Con
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, instance.GetOwnerId()))
result := compare.SyncResult{}
localAccounts := []SDBInstanceAccount{}
remoteAccounts := []cloudprovider.ICloudDBInstanceAccount{}
dbAccounts, err := instance.GetDBInstanceAccounts()
if err != nil {
result.Error(err)
return nil, nil, result
}
localAccounts := []SDBInstanceAccount{}
remoteAccounts := []cloudprovider.ICloudDBInstanceAccount{}
removed := make([]SDBInstanceAccount, 0)
commondb := make([]SDBInstanceAccount, 0)
commonext := make([]cloudprovider.ICloudDBInstanceAccount, 0)
added := make([]cloudprovider.ICloudDBInstanceAccount, 0)
if err := compare.CompareSets(dbAccounts, cloudAccounts, &removed, &commondb, &commonext, &added); err != nil {
result.Error(err)
return nil, nil, result
accountMaps := map[string]SDBInstanceAccount{}
for i := range dbAccounts {
accountMaps[fmt.Sprintf("%s:%s", dbAccounts[i].Name, dbAccounts[i].Host)] = dbAccounts[i]
}
remoteMaps := map[string]cloudprovider.ICloudDBInstanceAccount{}
for i := range cloudAccounts {
remoteMaps[fmt.Sprintf("%s:%s", cloudAccounts[i].GetName(), cloudAccounts[i].GetHost())] = cloudAccounts[i]
}
for i := 0; i < len(removed); i++ {
err := removed[i].Purge(ctx, userCred)
for key, account := range remoteMaps {
local, ok := accountMaps[key]
if !ok {
_account, err := manager.newFromCloudDBInstanceAccount(ctx, userCred, instance, account)
if err != nil {
result.AddError(err)
continue
}
result.Add()
remoteAccounts = append(remoteAccounts, account)
localAccounts = append(localAccounts, *_account)
continue
}
err = local.SyncWithCloudDBInstanceAccount(ctx, userCred, instance, account)
if err != nil {
result.DeleteError(err)
} else {
result.UpdateError(err)
continue
}
result.Update()
remoteAccounts = append(remoteAccounts, account)
localAccounts = append(localAccounts, local)
}
for key, account := range accountMaps {
_, ok := remoteMaps[key]
if !ok {
err := account.Purge(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
}
for i := 0; i < len(commondb); i++ {
err := commondb[i].SyncWithCloudDBInstanceAccount(ctx, userCred, instance, commonext[i])
if err != nil {
result.UpdateError(err)
} else {
result.Update()
localAccounts = append(localAccounts, commondb[i])
remoteAccounts = append(remoteAccounts, commonext[i])
}
}
for i := 0; i < len(added); i++ {
account, err := manager.newFromCloudDBInstanceAccount(ctx, userCred, instance, added[i])
if err != nil {
result.AddError(err)
} else {
localAccounts = append(localAccounts, *account)
remoteAccounts = append(remoteAccounts, added[i])
result.Add()
}
}
return localAccounts, remoteAccounts, result
}
@@ -684,7 +695,6 @@ func (manager *SDBInstanceAccountManager) newFromCloudDBInstanceAccount(ctx cont
account.Name = extAccount.GetName()
account.DBInstanceId = instance.Id
account.Status = extAccount.GetStatus()
account.ExternalId = extAccount.GetGlobalId()
err := manager.TableSpec().Insert(ctx, &account)
if err != nil {
+25
View File
@@ -369,6 +369,30 @@ func (backup *SDBInstanceBackup) GetIRegion() (cloudprovider.ICloudRegion, error
}
func (backup *SDBInstanceBackup) GetIDBInstanceBackup() (cloudprovider.ICloudDBInstanceBackup, error) {
if len(backup.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
}
if len(backup.DBInstanceId) > 0 {
rds, err := backup.GetDBInstance()
if err != nil {
return nil, errors.Wrapf(err, "GetDBInstance")
}
iRds, err := rds.GetIDBInstance()
if err != nil {
return nil, errors.Wrapf(err, "GetIDBInstance")
}
backups, err := iRds.GetIDBInstanceBackups()
if err != nil {
return nil, errors.Wrapf(err, "GetIDBInstanceBackups")
}
for i := range backups {
if backups[i].GetGlobalId() == backup.ExternalId {
return backups[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "externalId: %s", backup.ExternalId)
}
iRegion, err := backup.GetIRegion()
if err != nil {
return nil, errors.Wrap(err, "backup.GetIRegion")
@@ -432,6 +456,7 @@ func (self *SDBInstanceBackup) SyncWithCloudDBInstanceBackup(
provider *SCloudprovider,
) error {
_, err := db.UpdateWithLock(ctx, self, func() error {
self.ExternalId = extBackup.GetGlobalId()
self.Status = extBackup.GetStatus()
self.StartTime = extBackup.GetStartTime()
self.EndTime = extBackup.GetEndTime()
+25
View File
@@ -30,6 +30,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
@@ -628,3 +629,27 @@ func (manager *SDBInstanceSkuManager) ListItemExportKeys(ctx context.Context,
return q, nil
}
func (self *SDBInstanceSku) GetZoneInfo() (cloudprovider.SZoneInfo, error) {
zoneInfo := cloudprovider.SZoneInfo{ZoneId: self.ZoneId}
region := self.GetRegion()
if region == nil {
return zoneInfo, fmt.Errorf("empyt region for rds sku %s(%s)", self.Name, self.Id)
}
var cloudZoneId = func(id string) (string, error) {
if len(id) == 0 {
return "", nil
}
_zone, err := ZoneManager.FetchById(id)
if err != nil {
log.Errorf("ZoneManager.FetchById(%s) error: %v", id, err)
return "", errors.Wrapf(err, "ZoneManager.FetchById(%s)", id)
}
zone := _zone.(*SZone)
return strings.TrimPrefix(zone.ExternalId, region.ExternalId+"/"), nil
}
zoneInfo.Zone1, _ = cloudZoneId(self.Zone1)
zoneInfo.Zone2, _ = cloudZoneId(self.Zone2)
zoneInfo.Zone3, _ = cloudZoneId(self.Zone3)
return zoneInfo, nil
}
+22 -15
View File
@@ -111,7 +111,7 @@ type SDBInstance struct {
EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 套餐名称
// example: mysql.x4.large.2c
InstanceType string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"optional"`
InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"`
// 维护时间
MaintainTime string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"optional"`
@@ -666,7 +666,11 @@ func (self *SDBInstance) GetIDBInstance() (cloudprovider.ICloudDBInstance, error
if err != nil {
return nil, errors.Wrap(err, "self.GetIRegion")
}
return iregion.GetIDBInstanceById(self.ExternalId)
iRds, err := iregion.GetIDBInstanceById(self.ExternalId)
if err != nil {
return nil, errors.Wrapf(err, "GetIDBInstanceById(%s)", self.ExternalId)
}
return iRds, nil
}
func (self *SDBInstance) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
@@ -1413,26 +1417,19 @@ func (self *SDBInstance) GetAvailableZoneIds() ([]string, error) {
}
func (self *SDBInstance) GetAvailableInstanceTypes() ([]cloudprovider.SInstanceType, error) {
instanceTypes := map[string]cloudprovider.SInstanceType{}
instanceTypes := []cloudprovider.SInstanceType{}
skus, err := self.GetAvailableDBInstanceSkus()
if err != nil {
return nil, errors.Wrap(err, "self.GetAvailableDBInstanceSkus")
}
for _, sku := range skus {
if instanceType, ok := instanceTypes[sku.Name]; !ok {
instanceTypes[sku.Name] = cloudprovider.SInstanceType{InstanceType: sku.Name, ZoneIds: []string{sku.ZoneId}}
} else if !utils.IsInStringArray(sku.ZoneId, instanceType.ZoneIds) {
instanceType.ZoneIds = append(instanceType.ZoneIds, sku.ZoneId)
}
instanceType := cloudprovider.SInstanceType{}
instanceType.InstanceType = sku.Name
instanceType.SZoneInfo, _ = sku.GetZoneInfo()
instanceTypes = append(instanceTypes, instanceType)
}
result := []cloudprovider.SInstanceType{}
for _, instanceType := range instanceTypes {
result = append(result, instanceType)
}
return result, nil
return instanceTypes, nil
}
func (self *SDBInstance) setZoneInfo() error {
@@ -1491,8 +1488,18 @@ func (self *SDBInstance) SetZoneIds(extInstance cloudprovider.ICloudDBInstance)
}
}
func (self *SDBInstance) SyncAllWithCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extInstance cloudprovider.ICloudDBInstance) error {
err := self.SyncWithCloudDBInstance(ctx, userCred, provider, extInstance)
if err != nil {
return errors.Wrapf(err, "SyncWithCloudDBInstance")
}
syncDBInstanceResource(ctx, userCred, SSyncResultSet{}, self, extInstance)
return nil
}
func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extInstance cloudprovider.ICloudDBInstance) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
self.ExternalId = extInstance.GetGlobalId()
self.Engine = extInstance.GetEngine()
self.EngineVersion = extInstance.GetEngineVersion()
self.InstanceType = extInstance.GetInstanceType()
-1
View File
@@ -219,7 +219,6 @@ func (self *SGoogleRegionDriver) InitDBInstanceUser(ctx context.Context, instanc
account.DBInstanceId = instance.Id
account.Name = user
account.Status = api.DBINSTANCE_USER_AVAILABLE
account.ExternalId = user
account.SetModelManager(models.DBInstanceAccountManager, &account)
err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
if err != nil {
-1
View File
@@ -2187,7 +2187,6 @@ func (self *SHuaWeiRegionDriver) InitDBInstanceUser(ctx context.Context, instanc
account.DBInstanceId = instance.Id
account.Name = user
account.Status = api.DBINSTANCE_USER_AVAILABLE
account.ExternalId = user
account.SetModelManager(models.DBInstanceAccountManager, &account)
err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
if err != nil {
+77 -81
View File
@@ -1610,7 +1610,6 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
Description: dbinstance.Description,
StorageType: dbinstance.StorageType,
DiskSizeGB: dbinstance.DiskSizeGB,
InstanceType: dbinstance.InstanceType,
VcpuCount: dbinstance.VcpuCount,
VmemSizeMb: dbinstance.VmemSizeMb,
VpcId: vpc.ExternalId,
@@ -1629,12 +1628,6 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
log.Errorf("failed to sync project %s for create %s rds %s error: %v", dbinstance.ProjectId, _cloudprovider.Provider, dbinstance.Name, err)
}
if len(dbinstance.InstanceType) > 0 {
desc.ZoneIds, _ = dbinstance.GetAvailableZoneIds()
} else {
desc.InstanceTypes, _ = dbinstance.GetAvailableInstanceTypes()
}
region := dbinstance.GetRegion()
err = region.GetDriver().InitDBInstanceUser(ctx, dbinstance, task, &desc)
@@ -1673,49 +1666,46 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
desc.MasterInstanceId = master.ExternalId
}
log.Debugf("create dbinstance params: %s", jsonutils.Marshal(desc).String())
idbinstance, err := iregion.CreateIDBInstance(&desc)
if idbinstance != nil { //避免创建失败后,删除本地的未能同步删除云上失败的RDS
db.SetExternalId(dbinstance, userCred, idbinstance.GetGlobalId())
}
instanceTypes, err := dbinstance.GetAvailableInstanceTypes()
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "GetAvailableInstanceTypes")
}
if len(instanceTypes) == 0 {
return nil, fmt.Errorf("no avaiable sku for create")
}
err = cloudprovider.WaitStatus(idbinstance, api.DBINSTANCE_RUNNING, time.Second*5, time.Hour*1)
var createFunc = func() (cloudprovider.ICloudDBInstance, error) {
errMsgs := []string{}
for i := range instanceTypes {
desc.SInstanceType = instanceTypes[i]
log.Debugf("create dbinstance params: %s", jsonutils.Marshal(desc).String())
iRds, err := iregion.CreateIDBInstance(&desc)
if err != nil {
errMsgs = append(errMsgs, err.Error())
continue
}
return iRds, nil
}
if len(errMsgs) > 0 {
return nil, fmt.Errorf(strings.Join(errMsgs, "\n"))
}
return nil, fmt.Errorf("no avaiable skus %s(%dC%d) for create", dbinstance.InstanceType, desc.VcpuCount, desc.VmemSizeMb)
}
iRds, err := createFunc()
if err != nil {
return nil, errors.Wrapf(err, "create")
}
err = cloudprovider.WaitStatus(iRds, api.DBINSTANCE_RUNNING, time.Second*5, time.Hour*1)
if err != nil {
log.Errorf("timeout for waiting dbinstance running error: %v", err)
}
dbinstance.SyncWithCloudDBInstance(ctx, userCred, dbinstance.GetCloudprovider(), idbinstance)
network, err := idbinstance.GetDBNetwork()
err = dbinstance.SyncAllWithCloudDBInstance(ctx, userCred, dbinstance.GetCloudprovider(), iRds)
if err != nil {
log.Errorf("failed to get get network for dbinstance %s(%s) error: %v", dbinstance.Name, dbinstance.Id, err)
} else {
models.DBInstanceNetworkManager.SyncDBInstanceNetwork(ctx, userCred, dbinstance, network)
}
parameters, err := idbinstance.GetIDBInstanceParameters()
if err != nil {
log.Errorf("failed to get parameters for dbinstance %s(%s) error: %v", dbinstance.Name, dbinstance.Id, err)
} else {
models.DBInstanceParameterManager.SyncDBInstanceParameters(ctx, userCred, dbinstance, parameters)
}
backups, err := idbinstance.GetIDBInstanceBackups()
if err != nil {
log.Errorf("failed to get backups for dbinstance %s(%s) error: %v", dbinstance.Name, dbinstance.Id, err)
} else {
models.DBInstanceBackupManager.SyncDBInstanceBackups(ctx, userCred, dbinstance.GetCloudprovider(), dbinstance, dbinstance.GetRegion(), backups)
}
databases, err := idbinstance.GetIDBInstanceDatabases()
if err != nil {
log.Errorf("failed to get databases for databases %s(%s) error: %v", dbinstance.Name, dbinstance.Id, err)
} else {
models.DBInstanceDatabaseManager.SyncDBInstanceDatabases(ctx, userCred, dbinstance, databases)
log.Errorf("SyncAllWithCloudDBInstance error: %v", err)
}
return nil, nil
@@ -2223,37 +2213,36 @@ func (self *SManagedVirtualizationRegionDriver) RequestChangeDBInstanceConfig(ct
instance.StorageType = input.StorageType
}
conf := &cloudprovider.SManagedDBInstanceChangeConfig{
conf := cloudprovider.SManagedDBInstanceChangeConfig{
DiskSizeGB: input.DiskSizeGB,
StorageType: instance.StorageType,
}
instanceTypes := []string{}
opts := []cloudprovider.SManagedDBInstanceChangeConfig{}
if len(input.InstanceType) > 0 {
conf.InstanceType = input.InstanceType
} else if input.VCpuCount == 0 && input.VmemSizeMb == 0 {
conf.InstanceType = instance.InstanceType
} else {
instance.InstanceType = ""
if len(input.InstanceType) > 0 || input.VCpuCount > 0 || input.VmemSizeMb > 0 {
instance.InstanceType = input.InstanceType
if input.VCpuCount > 0 {
instance.VcpuCount = input.VCpuCount
}
if input.VmemSizeMb > 0 {
instance.VmemSizeMb = input.VmemSizeMb
}
skus, err := instance.GetDBInstanceSkus()
if err != nil {
return nil, errors.Wrap(err, "instance.GetDBInstanceSkus")
}
for _, sku := range skus {
instanceTypes = append(instanceTypes, sku.Name)
for i := range skus {
conf.InstanceType = skus[i].Name
conf.VcpuCount = skus[i].VcpuCount
conf.VmemSizeMb = skus[i].VmemSizeMb
opts = append(opts, conf)
}
}
if len(conf.InstanceType) == 0 && len(instanceTypes) == 0 {
return nil, fmt.Errorf("No available dbinstance sku for change config")
} else {
conf.InstanceType = instance.InstanceType
conf.VcpuCount = instance.VcpuCount
conf.VmemSizeMb = instance.VmemSizeMb
opts = append(opts, conf)
}
iRds, err := instance.GetIDBInstance()
@@ -2261,29 +2250,38 @@ func (self *SManagedVirtualizationRegionDriver) RequestChangeDBInstanceConfig(ct
return nil, errors.Wrap(err, "instance.GetIDBInstance")
}
log.Infof("change config: %s", jsonutils.Marshal(conf).String())
if len(conf.InstanceType) > 0 {
err = iRds.ChangeConfig(ctx, conf)
if err != nil {
return nil, errors.Wrapf(err, "iRds.ChangeConfig(%s)", conf.InstanceType)
}
} else {
for _, instanceType := range instanceTypes {
conf.InstanceType = instanceType
log.Infof("try change instance type to %s", instance.InstanceType)
err = iRds.ChangeConfig(ctx, conf)
var changeConfig = func() error {
errMsgs := []string{}
for i := range opts {
log.Infof("change config: %s", jsonutils.Marshal(opts[i]).String())
err = iRds.ChangeConfig(ctx, &opts[i])
if err != nil {
log.Warningf("change failed: %v try another", err)
errMsgs = append(errMsgs, err.Error())
continue
}
return nil
}
return nil, fmt.Errorf("no available dbinstance sku to change")
if len(errMsgs) > 0 {
return fmt.Errorf(strings.Join(errMsgs, "\n"))
}
return fmt.Errorf("no available dbinstance sku to change")
}
err = changeConfig()
if err != nil {
return nil, err
}
err = cloudprovider.WaitStatus(iRds, api.DBINSTANCE_RUNNING, time.Second*10, time.Minute*40)
if err != nil {
log.Errorf("failed to wait rds %s(%s) status running", instance.Name, instance.Id)
return nil, errors.Wrapf(err, "cloudprovider.WaitStatus")
}
err = iRds.Refresh()
if err != nil {
return nil, errors.Wrapf(err, "iRds.Refresh")
}
_, err = db.Update(instance, func() error {
instance.InstanceType = iRds.GetInstanceType()
instance.Category = iRds.GetCategory()
@@ -2308,11 +2306,6 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstanceBackup(ct
return nil, errors.Wrap(err, "instance.GetIDBInstance")
}
iRegion, err := backup.GetIRegion()
if err != nil {
return nil, errors.Wrap(err, "backup.GetIRegion")
}
desc := &cloudprovider.SDBInstanceBackupCreateConfig{
Name: backup.Name,
}
@@ -2326,11 +2319,14 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstanceBackup(ct
return nil, errors.Wrap(err, "iRds.CreateBackup")
}
db.SetExternalId(backup, userCred, backupId)
iBackup, err := iRegion.GetIDBInstanceBackupById(backupId)
err = db.SetExternalId(backup, userCred, backupId)
if err != nil {
return nil, errors.Wrapf(err, "iRegion.GetIDBInstanceBackupById(%s)", backupId)
return nil, errors.Wrapf(err, "db.SetExternalId")
}
iBackup, err := backup.GetIDBInstanceBackup()
if err != nil {
return nil, errors.Wrapf(err, "backup.GetIDBInstanceBackup")
}
_, err = db.Update(backup, func() error {
+54
View File
@@ -1358,3 +1358,57 @@ func (self *SQcloudRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con
})
return nil
}
func (self *SQcloudRegionDriver) InitDBInstanceUser(ctx context.Context, instance *models.SDBInstance, task taskman.ITask, desc *cloudprovider.SManagedDBInstanceCreateConfig) error {
user := "root"
account := models.SDBInstanceAccount{}
account.DBInstanceId = instance.Id
account.Name = user
account.Host = "%"
if instance.Engine == api.DBINSTANCE_TYPE_MYSQL && instance.Category == api.QCLOUD_DBINSTANCE_CATEGORY_BASIC {
account.Host = "localhost"
}
account.Status = api.DBINSTANCE_USER_AVAILABLE
account.SetModelManager(models.DBInstanceAccountManager, &account)
err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
if err != nil {
return errors.Wrapf(err, "Insert")
}
return account.SetPassword(desc.Password)
}
func (self *SQcloudRegionDriver) IsSupportedDBInstance() bool {
return true
}
func (self *SQcloudRegionDriver) IsDBInstanceNeedSecgroup() bool {
return true
}
func (self *SQcloudRegionDriver) ValidateCreateDBInstanceBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceBackupCreateInput) (api.DBInstanceBackupCreateInput, error) {
switch instance.Engine {
case api.DBINSTANCE_TYPE_MYSQL:
if instance.Category == api.QCLOUD_DBINSTANCE_CATEGORY_BASIC {
return input, httperrors.NewNotSupportedError("Qcloud Basic MySQL instance not support create backup")
}
}
return input, nil
}
func (self *SQcloudRegionDriver) ValidateCreateDBInstanceAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceAccountCreateInput) (api.DBInstanceAccountCreateInput, error) {
return input, nil
}
func (self *SQcloudRegionDriver) ValidateCreateDBInstanceDatabaseData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceDatabaseCreateInput) (api.DBInstanceDatabaseCreateInput, error) {
return input, httperrors.NewNotSupportedError("Not support create Qcloud databases")
}
func (self *SQcloudRegionDriver) ValidateDBInstanceAccountPrivilege(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, account string, privilege string) error {
switch privilege {
case api.DATABASE_PRIVILEGE_RW:
case api.DATABASE_PRIVILEGE_R:
default:
return httperrors.NewInputParameterError("Unknown privilege %s", privilege)
}
return nil
}
@@ -64,6 +64,7 @@ func (self *DBInstanceAccountCreateTask) CreateDBInstanceAccount(ctx context.Con
desc := &cloudprovider.SDBInstanceAccountCreateConfig{
Name: account.Name,
Host: account.Host,
}
desc.Password, _ = account.GetPassword()
@@ -85,7 +86,7 @@ func (self *DBInstanceAccountCreateTask) CreateDBInstanceAccount(ctx context.Con
var iAccount cloudprovider.ICloudDBInstanceAccount = nil
for i := range iAccounts {
if iAccounts[i].GetName() == account.Name {
if iAccounts[i].GetName() == account.Name && iAccounts[i].GetHost() == account.Host {
iAccount = iAccounts[i]
break
}
@@ -100,7 +101,7 @@ func (self *DBInstanceAccountCreateTask) CreateDBInstanceAccount(ctx context.Con
return
}
db.SetExternalId(account, self.UserCred, iAccount.GetGlobalId())
//db.SetExternalId(account, self.UserCred, iAccount.GetGlobalId())
input := api.DBInstanceAccountCreateInput{}
self.GetParams().Unmarshal(&input)
@@ -66,7 +66,7 @@ func (self *DBInstanceAccountRevokePrivilegeTask) OnInit(ctx context.Context, ob
var iAccount cloudprovider.ICloudDBInstanceAccount = nil
for _, ac := range accounts {
if ac.GetName() == account.Name {
if ac.GetName() == account.Name && ac.GetHost() == account.Host {
iAccount = ac
break
}
@@ -49,15 +49,9 @@ func (self *DBInstanceBackupDeleteTask) OnInit(ctx context.Context, obj db.IStan
}
func (self *DBInstanceBackupDeleteTask) DeleteDBInstanceBackup(ctx context.Context, backup *models.SDBInstanceBackup) {
iRegion, err := backup.GetIRegion()
if err != nil {
self.taskFailed(ctx, backup, errors.Wrap(err, "backup.GetIRegion"))
return
}
iBackup, err := iRegion.GetIDBInstanceBackupById(backup.ExternalId)
if err != nil && err != cloudprovider.ErrNotFound {
self.taskFailed(ctx, backup, errors.Wrap(err, "iRegion.GetIDBInstanceBackupById"))
iBackup, err := backup.GetIDBInstanceBackup()
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
self.taskFailed(ctx, backup, errors.Wrap(err, "backup.GetIDBInstanceBackup"))
return
}
+1 -31
View File
@@ -19,7 +19,6 @@ import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -40,7 +39,7 @@ func (self *DBInstanceCreateTask) taskFailed(ctx context.Context, dbinstance *mo
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_CREATE_FAILED, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_CREATE, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_CREATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.Marshal(err))
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *DBInstanceCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
@@ -62,35 +61,6 @@ func (self *DBInstanceCreateTask) OnCreateDBInstanceComplete(ctx context.Context
dbinstance := obj.(*models.SDBInstance)
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_CREATE, nil, self.UserCred, true)
accounts, err := dbinstance.GetDBInstanceAccounts()
if err != nil {
log.Errorf("failed to get dbinstance %s account error: %v", dbinstance.Name, err)
}
if len(accounts) > 0 {
iRds, err := dbinstance.GetIDBInstance()
if err != nil {
log.Errorf("failed to found dbinstance %s error: %v", dbinstance.Name, err)
} else {
iAccounts, err := iRds.GetIDBInstanceAccounts()
if err != nil {
log.Errorf("failed to get accounts from cloud dbinstance %s error: %v", dbinstance.Name, err)
}
externalIds := map[string]string{}
for _, iAccount := range iAccounts {
externalIds[iAccount.GetName()] = iAccount.GetGlobalId()
}
for i := range accounts {
externalId, ok := externalIds[accounts[i].Name]
if !ok {
log.Errorf("failed to get dbinstance account %s from cloud dbinstance for set externalId", accounts[i].Name)
} else {
db.SetExternalId(&accounts[i], self.UserCred, externalId)
}
}
}
}
self.SetStage("OnSyncDBInstanceStatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, dbinstance, "DBInstanceSyncStatusTask", self.GetTaskId())
}
@@ -48,7 +48,7 @@ func (self *DBInstancePublicConnectionTask) getAction() string {
func (self *DBInstancePublicConnectionTask) taskFailed(ctx context.Context, dbinstance *models.SDBInstance, err error) {
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_FAILE, err.Error())
logclient.AddActionLogWithStartable(self, dbinstance, self.getAction(), err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.Marshal(err))
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *DBInstancePublicConnectionTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
@@ -63,7 +63,9 @@ func (self *DBInstancePublicConnectionTask) DBInstancePublicConnectionOperation(
return
}
if isOpen, _ := self.GetParams().Bool("open"); isOpen {
isOpen := jsonutils.QueryBoolean(self.GetParams(), "open", false)
if isOpen {
err = idbinstance.OpenPublicConnection()
} else {
err = idbinstance.ClosePublicConnection()
@@ -73,14 +75,27 @@ func (self *DBInstancePublicConnectionTask) DBInstancePublicConnectionOperation(
return
}
err = cloudprovider.WaitStatus(idbinstance, api.DBINSTANCE_RUNNING, 10*time.Second, time.Minute*30)
connectionStr := ""
err = cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) {
iRds, err := instance.GetIDBInstance()
if err != nil {
return false, errors.Wrapf(err, "GetIDBInstance")
}
connectionStr = iRds.GetConnectionStr()
if (isOpen && len(connectionStr) > 0) || (!isOpen && len(connectionStr) == 0) {
return true, nil
}
return false, nil
})
if err != nil {
self.taskFailed(ctx, instance, errors.Wrap(err, "cloudprovider.WaitStatus"))
self.taskFailed(ctx, instance, errors.Wrapf(err, "cloudprovider.Wait"))
return
}
_, err = db.Update(instance, func() error {
instance.ConnectionStr = idbinstance.GetConnectionStr()
instance.ConnectionStr = connectionStr
return nil
})
@@ -39,7 +39,7 @@ func (self *DBInstanceSyncStatusTask) taskFailed(ctx context.Context, dbinstance
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_UNKNOWN, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_SYNC_STATUS, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.Marshal(err))
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *DBInstanceSyncStatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
+1 -1
View File
@@ -53,7 +53,7 @@ func (self *DBInstanceSyncTask) SyncDBInstance(ctx context.Context, dbinstance *
self.taskFailed(ctx, dbinstance, errors.Wrapf(err, "dbinstance.GetIDBInstance"))
return
}
err = dbinstance.SyncWithCloudDBInstance(ctx, self.UserCred, dbinstance.GetCloudprovider(), idbinstance)
err = dbinstance.SyncAllWithCloudDBInstance(ctx, self.UserCred, dbinstance.GetCloudprovider(), idbinstance)
if err != nil {
self.taskFailed(ctx, dbinstance, errors.Wrapf(err, "dbinstance.GetIDBInstance"))
return
+1 -1
View File
@@ -26,7 +26,7 @@ var (
func init() {
DBInstanceSkus = DBInstanceSkusManager{NewComputeManager("dbinstance_sku", "dbinstance_skus",
[]string{"Id", "Name", "Engine", "Engine_Version", "Category", "Storage_Type", "Status", "Enabled"},
[]string{},
[]string{})}
registerCompute(&DBInstanceSkus)
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package options
import "yunion.io/x/jsonutils"
type DBInstanceSkuListOption struct {
BaseListOptions
Engine string
EngineVersion string
Category string
StorageType string
Cloudregion string
VcpuCount *int
VmemSizeMb *int
}
func (opts *DBInstanceSkuListOption) Params() (jsonutils.JSONObject, error) {
return ListStructToParams(opts)
}
type DBInstanceSkuIdOption struct {
ID string `help:"DBInstance Id or name"`
}
func (opts *DBInstanceSkuIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
func (opts *DBInstanceSkuIdOption) GetId() string {
return opts.ID
}
+6 -39
View File
@@ -604,17 +604,18 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
"RegionId": region.RegionId,
"Engine": desc.Engine,
"EngineVersion": desc.EngineVersion,
"DBInstanceClass": desc.InstanceType,
"DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB),
"DBInstanceNetType": "Intranet",
"PayType": "Postpaid",
"SecurityIPList": "0.0.0.0/0",
"DBInstanceDescription": desc.Name,
"ClientToken": utils.GenRequestId(20),
"InstanceNetworkType": "VPC",
"VPCId": desc.VpcId,
"VSwitchId": desc.NetworkId,
"DBInstanceStorageType": desc.StorageType,
"DBInstanceClass": desc.InstanceType,
"ZoneId": desc.ZoneId,
"ClientToken": utils.GenRequestId(20),
}
switch desc.Category {
case api.ALIYUN_DBINSTANCE_CATEGORY_HA:
@@ -651,43 +652,9 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
params["DBInstanceId"] = desc.MasterInstanceId
}
var err error
var resp jsonutils.JSONObject
if len(desc.InstanceType) > 0 {
params["DBInstanceClass"] = desc.InstanceType
for _, zoneId := range desc.ZoneIds {
params["ZoneId"] = zoneId
resp, err = region.rdsRequest(action, params)
if err == nil {
break
}
}
if len(desc.ZoneIds) == 0 {
resp, err = region.rdsRequest(action, params)
}
if err != nil {
return nil, errors.Wrapf(err, "region.rdsRequest.%s", action)
}
} else {
for _, spec := range desc.InstanceTypes {
params["DBInstanceClass"] = spec.InstanceType
for _, zoneId := range spec.ZoneIds {
params["ZoneId"] = zoneId
resp, err = region.rdsRequest(action, params)
if err == nil {
break
}
}
if err == nil {
break
}
}
if err != nil {
return nil, errors.Wrapf(err, "region.rdsRequest.%s", action)
}
if resp == nil {
return nil, fmt.Errorf("dbinstance type %dC%dMB not avaiable", desc.VcpuCount, desc.VmemSizeMb)
}
resp, err := region.rdsRequest(action, params)
if err != nil {
return nil, errors.Wrapf(err, "rdsRequest")
}
instanceId, err := resp.GetString("DBInstanceId")
if err != nil {
@@ -41,14 +41,6 @@ type SDBInstanceAccount struct {
PrivExceeded string
}
func (account *SDBInstanceAccount) GetId() string {
return account.AccountName
}
func (account *SDBInstanceAccount) GetGlobalId() string {
return account.AccountName
}
func (account *SDBInstanceAccount) GetName() string {
return account.AccountName
}
@@ -29,7 +29,7 @@ type SDatabasePrivilege struct {
}
func (privilege *SDatabasePrivilege) GetGlobalId() string {
return fmt.Sprintf("%s/%s", privilege.account.GetGlobalId(), privilege.DBName)
return fmt.Sprintf("%s/%s", privilege.account.GetName(), privilege.DBName)
}
func (privilege *SDatabasePrivilege) GetPrivilege() string {
-13
View File
@@ -15,7 +15,6 @@
package aws
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/multicloud"
)
@@ -26,18 +25,6 @@ type SDBInstanceAccount struct {
AccountName string
}
func (account *SDBInstanceAccount) GetId() string {
return account.AccountName
}
func (account *SDBInstanceAccount) GetGlobalId() string {
return account.AccountName
}
func (account *SDBInstanceAccount) GetName() string {
return account.AccountName
}
func (account *SDBInstanceAccount) GetStatus() string {
return api.DBINSTANCE_USER_AVAILABLE
}
+9 -1
View File
@@ -30,11 +30,11 @@ package multicloud
import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SDBInstanceAccountBase struct {
SResourceBase
}
func (account *SDBInstanceAccountBase) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) {
@@ -45,6 +45,14 @@ func (account *SDBInstanceAccountBase) Delete() error {
return errors.Wrapf(cloudprovider.ErrNotImplemented, "Delete")
}
func (account *SDBInstanceAccountBase) GetHost() string {
return "%"
}
func (account *SDBInstanceAccountBase) GetStatus() string {
return api.DBINSTANCE_USER_AVAILABLE
}
func (account *SDBInstanceAccountBase) ResetPassword(password string) error {
return errors.Wrapf(cloudprovider.ErrNotImplemented, "ResetPassword")
}
+3 -39
View File
@@ -625,45 +625,9 @@ func (region *SRegion) CreateDBInstance(desc *cloudprovider.SManagedDBInstanceCr
if _, ok := EngineVersions[databaseVersion]; !ok {
return nil, fmt.Errorf("Unsupport %s version %s", desc.Engine, desc.EngineVersion)
}
var err error
var rds *SDBInstance = nil
if len(desc.InstanceType) > 0 {
if len(desc.ZoneIds) == 0 {
desc.ZoneIds = append(desc.ZoneIds, "")
}
for _, zoneId := range desc.ZoneIds {
rds, err = region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, zoneId, desc.Password)
if err == nil {
break
} else {
log.Errorf("failed to create dbinstance %s at %s error: %v", desc.Name, zoneId, err)
}
}
if err != nil {
return nil, errors.Wrap(err, "CreateRds")
}
} else if len(desc.InstanceTypes) > 0 {
for _, spec := range desc.InstanceTypes {
if len(spec.ZoneIds) == 0 {
desc.ZoneIds = append(desc.ZoneIds, "")
}
for _, zoneId := range spec.ZoneIds {
rds, err = region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, zoneId, desc.Password)
if err == nil {
break
} else {
log.Errorf("failed to create dbinstance %s at %s error: %v", desc.Name, zoneId, err)
}
}
if err == nil {
break
}
}
if err != nil {
return nil, errors.Wrap(err, "CreateRds")
}
} else {
return nil, fmt.Errorf("Missing instance type info")
rds, err := region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, desc.ZoneId, desc.Password)
if err != nil {
return nil, errors.Wrapf(err, "CreateRds")
}
return rds, nil
}
+4 -19
View File
@@ -21,8 +21,8 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SSqlserverUserDetails struct {
@@ -30,6 +30,7 @@ type SSqlserverUserDetails struct {
}
type SDBInstanceAccount struct {
multicloud.SDBInstanceAccountBase
rds *SDBInstance
Kind string
@@ -71,30 +72,14 @@ func (account *SDBInstanceAccount) Delete() error {
return account.rds.region.DeleteDBInstanceAccount(account.rds.Name, account.Name, account.Host)
}
func (account *SDBInstanceAccount) GetGlobalId() string {
return account.Name
}
func (account *SDBInstanceAccount) GetId() string {
return account.SelfLink
}
func (account *SDBInstanceAccount) GetMetadata() *jsonutils.JSONDict {
return nil
func (account *SDBInstanceAccount) GetHost() string {
return account.Host
}
func (account *SDBInstanceAccount) GetName() string {
return account.Name
}
func (account *SDBInstanceAccount) GetStatus() string {
return api.DBINSTANCE_USER_AVAILABLE
}
func (account *SDBInstanceAccount) IsEmulated() bool {
return false
}
func (account *SDBInstanceAccount) Refresh() error {
_account, err := account.rds.region.GetDBInstanceAccount(account.SelfLink)
if err != nil {
+5 -46
View File
@@ -469,17 +469,7 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
"replication_mode": "sync",
}
}
if len(desc.ZoneIds) == 0 {
for _, masterZoneId := range zoneIds {
for _, slaveZoneId := range zoneIds {
desc.ZoneIds = append(desc.ZoneIds, fmt.Sprintf("%s,%s", masterZoneId, slaveZoneId))
}
}
}
case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE:
if len(desc.ZoneIds) == 0 {
desc.ZoneIds = zoneIds
}
case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA:
}
@@ -497,42 +487,11 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
"is_auto_renew": false,
}
}
var resp jsonutils.JSONObject = nil
if len(desc.InstanceType) > 0 {
params["flavor_ref"] = desc.InstanceType
for _, zoneId := range desc.ZoneIds {
params["availability_zone"] = zoneId
resp, err = region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
if err == nil {
break
}
}
if err != nil {
log.Debugf("params: %s", jsonutils.Marshal(params).PrettyString())
return nil, errors.Wrap(err, "DBInstance.Create")
}
} else {
for _, spec := range desc.InstanceTypes {
params["flavor_ref"] = spec.InstanceType
for _, zoneId := range spec.ZoneIds {
params["availability_zone"] = zoneId
resp, err = region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
if err == nil {
break
}
}
if err == nil {
break
}
}
if err != nil {
log.Debugf("params: %s", jsonutils.Marshal(params).PrettyString())
return nil, errors.Wrap(err, "region.ecsClient.DBInstance.Create")
}
if resp == nil {
return nil, fmt.Errorf("dbinstance type %dC%dMB not avaiable", desc.VcpuCount, desc.VmemSizeMb)
}
params["flavor_ref"] = desc.InstanceType
params["availability_zone"] = desc.ZoneId
resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
if err != nil {
return nil, errors.Wrapf(err, "Create")
}
instance := &SDBInstance{region: region}
@@ -30,15 +30,6 @@ type SDBInstanceAccount struct {
Name string
}
func (account *SDBInstanceAccount) GetId() string {
return account.Name
}
func (account *SDBInstanceAccount) GetGlobalId() string {
return account.Name
}
func (account *SDBInstanceAccount) GetName() string {
return account.Name
}
@@ -51,10 +42,6 @@ func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string
return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil)
}
func (account *SDBInstanceAccount) GetStatus() string {
return api.DBINSTANCE_USER_AVAILABLE
}
func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) {
privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name)
if err != nil {
@@ -28,7 +28,7 @@ type SDatabasePrivilege struct {
}
func (privilege *SDatabasePrivilege) GetGlobalId() string {
return fmt.Sprintf("%s/%s", privilege.account.GetGlobalId(), privilege.Name)
return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name)
}
func (privilege *SDatabasePrivilege) GetPrivilege() string {
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"strings"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) {
ret := []cloudprovider.ICloudDBInstance{}
mysql := []SMySQLInstance{}
for {
part, total, err := self.ListMySQLInstances([]string{}, len(mysql), 50)
if err != nil {
return nil, errors.Wrapf(err, "ListMySQLInstances")
}
mysql = append(mysql, part...)
if len(mysql) >= total {
break
}
}
for i := range mysql {
mysql[i].region = self
ret = append(ret, &mysql[i])
}
return ret, nil
}
func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) {
if strings.HasPrefix(id, "cdb-") {
return self.GetMySQLInstanceById(id)
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) CreateIDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
switch opts.Engine {
case api.DBINSTANCE_TYPE_MYSQL:
rds, err := self.CreateMySQLDBInstance(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateMySQLDBInstance")
}
return rds, nil
}
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "For %s", opts.Engine)
}
+16
View File
@@ -41,6 +41,22 @@ clb.tencentcloudapi.com
clb.ap-shanghai-fsi.tencentcloudapi.com
clb.ap-shenzhen-fsi.tencentcloudapi.com
cdb.tencentcloudapi.com
cdb.ap-shanghai-fsi.tencentcloudapi.com
cdb.ap-shenzhen-fsi.tencentcloudapi.com
mariadb.tencentcloudapi.com
mariadb.ap-shanghai-fsi.tencentcloudapi.com
mariadb.ap-shenzhen-fsi.tencentcloudapi.com
postgres.tencentcloudapi.com
postgres.ap-shanghai-fsi.tencentcloudapi.com
postgres.ap-shenzhen-fsi.tencentcloudapi.com
sqlserver.tencentcloudapi.com
sqlserver.ap-shanghai-fsi.tencentcloudapi.com
sqlserver.ap-shenzhen-fsi.tencentcloudapi.com
lb.api.qcloud.com
wss.api.qcloud.com
cns.api.qcloud.com
+66 -6
View File
@@ -46,11 +46,15 @@ const (
QCLOUD_DEFAULT_REGION = "ap-beijing"
QCLOUD_API_VERSION = "2017-03-12"
QCLOUD_CLB_API_VERSION = "2018-03-17"
QCLOUD_BILLING_API_VERSION = "2018-07-09"
QCLOUD_AUDIT_API_VERSION = "2019-03-19"
QCLOUD_CAM_API_VERSION = "2019-01-16"
QCLOUD_API_VERSION = "2017-03-12"
QCLOUD_CLB_API_VERSION = "2018-03-17"
QCLOUD_BILLING_API_VERSION = "2018-07-09"
QCLOUD_AUDIT_API_VERSION = "2019-03-19"
QCLOUD_CAM_API_VERSION = "2019-01-16"
QCLOUD_CDB_API_VERSION = "2017-03-20"
QCLOUD_MARIADB_API_VERSION = "2017-03-12"
QCLOUD_POSTGRES_API_VERSION = "2017-03-12"
QCLOUD_SQLSERVER_API_VERSION = "2018-03-28"
)
type QcloudClientConfig struct {
@@ -167,6 +171,30 @@ func lbRequest(client *common.Client, apiName string, params map[string]string,
return _phpJsonRequest(client, &lbJsonResponse{}, domain, "/v2/index.php", "", apiName, params, debug)
}
// cdb
func cdbRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
domain := apiDomain("cdb", params)
return _jsonRequest(client, domain, QCLOUD_CDB_API_VERSION, apiName, params, debug, true)
}
// mariadb
func mariadbRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
domain := apiDomain("mariadb", params)
return _jsonRequest(client, domain, QCLOUD_MARIADB_API_VERSION, apiName, params, debug, true)
}
// postgres
func postgresRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
domain := apiDomain("postgres", params)
return _jsonRequest(client, domain, QCLOUD_POSTGRES_API_VERSION, apiName, params, debug, true)
}
// sqlserver
func sqlserverRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
domain := apiDomain("sqlserver", params)
return _jsonRequest(client, domain, QCLOUD_SQLSERVER_API_VERSION, apiName, params, debug, true)
}
// ssl 证书服务
func wssRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
domain := "wss.api.qcloud.com"
@@ -514,6 +542,38 @@ func (client *SQcloudClient) lbRequest(apiName string, params map[string]string)
return lbRequest(cli, apiName, params, client.debug)
}
func (client *SQcloudClient) cdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return cdbRequest(cli, apiName, params, client.debug)
}
func (client *SQcloudClient) mariadbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return mariadbRequest(cli, apiName, params, client.debug)
}
func (client *SQcloudClient) postgresRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return postgresRequest(cli, apiName, params, client.debug)
}
func (client *SQcloudClient) sqlserverRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
return nil, err
}
return sqlserverRequest(cli, apiName, params, client.debug)
}
func (client *SQcloudClient) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := client.getDefaultClient()
if err != nil {
@@ -830,7 +890,7 @@ func (self *SQcloudClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_NETWORK,
cloudprovider.CLOUD_CAPABILITY_LOADBALANCER,
cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
// cloudprovider.CLOUD_CAPABILITY_RDS,
cloudprovider.CLOUD_CAPABILITY_RDS,
// cloudprovider.CLOUD_CAPABILITY_CACHE,
cloudprovider.CLOUD_CAPABILITY_EVENT,
cloudprovider.CLOUD_CAPABILITY_CLOUDID,
+137
View File
@@ -0,0 +1,137 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
var (
SUPPORTED_ENGINE_VERSION = []string{"5.7", "10.0", "10.1"}
)
type SaleZoneInfo struct {
Zone string
ZoneId string
ZoneName string
}
type SAvailableChoice struct {
MasterZone SaleZoneInfo
SlaveZones []SaleZoneInfo
}
type SRegionSaleInfo struct {
AvailableChoice []SAvailableChoice
Region string
RegionId string
RegionName string
ZoneList []SaleZoneInfo
}
func (self *SRegion) DescribeSaleInfo() ([]SRegionSaleInfo, error) {
resp, err := self.mariadbRequest("DescribeSaleInfo", map[string]string{})
if err != nil {
return nil, errors.Wrapf(err, "DescribeSaleInfo")
}
saleInfo := []SRegionSaleInfo{}
err = resp.Unmarshal(&saleInfo, "RegionList")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return saleInfo, nil
}
type SInstanceSpec struct {
Cpu int
Machine string
MaxStorage int
Memory int
MinStorage int
NodeCount int
Pid int
Qps int
SuitInfo string
}
type SInstanceSpecs struct {
Machine string
SpecInfos []SInstanceSpec
}
func (self *SRegion) DescribeDBInstanceSpecs() ([]SInstanceSpecs, error) {
resp, err := self.mariadbRequest("DescribeDBInstanceSpecs", map[string]string{})
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBInstanceSpecs")
}
specs := []SInstanceSpecs{}
err = resp.Unmarshal(&specs, "Specs")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return specs, nil
}
func (self *SRegion) ListMariadbSkus() ([]SDBInstanceSku, error) {
skus := []SDBInstanceSku{}
saleRegions, err := self.DescribeSaleInfo()
if err != nil {
return nil, errors.Wrapf(err, "DescribeSaleInfo")
}
for _, saleRegion := range saleRegions {
if saleRegion.Region == self.Region {
specs, err := self.DescribeDBInstanceSpecs()
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBInstanceSpecs")
}
for _, spec := range specs {
for _, info := range spec.SpecInfos {
sku := SDBInstanceSku{
Region: self.Region,
Engine: api.DBINSTANCE_TYPE_MARIADB,
Cpu: info.Cpu,
StorageMax: info.MaxStorage,
StorageMin: info.MinStorage,
StorageStep: 10,
MemoryMb: info.Memory * 1024,
Qps: info.Qps,
Description: info.SuitInfo,
Category: "标准版",
Status: api.DBINSTANCE_SKU_AVAILABLE,
}
if info.NodeCount == 3 {
sku.Category = "金融版"
}
for _, engineVersion := range SUPPORTED_ENGINE_VERSION {
sku.EngineVersion = engineVersion
sku.Zone2 = ""
for _, zone := range saleRegion.AvailableChoice {
sku.Zone1 = zone.MasterZone.Zone
for _, slaveZone := range zone.SlaveZones {
sku.Zone2 = slaveZone.Zone
skus = append(skus, sku)
}
}
}
}
}
}
}
return skus, nil
}
+811
View File
@@ -0,0 +1,811 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"context"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/timeutils"
"yunion.io/x/pkg/utils"
billingapi "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SlaveInstanceInfo struct {
Region string
Vip string
VpcId int
Vport int
Zone string
}
type SlaveInfo struct {
First SlaveInstanceInfo
Second SlaveInstanceInfo
}
type SDrInfo struct {
Status int
Zone string
InstanceId string
Region string
SyncStatus string
InstanceName string
InstanceType string
}
type SMasterInfo struct {
Region string
RegionId int
ZoneId int
Zone string
InstanceId string
ResourceId string
Status int
InstanceName string
InstanceType int
TaskStatus int
Memory int
Volume int
DeviceType string
Qps int
VpcId int
SubnetId int
ExClusterId string
ExClusterName string
}
type SRoGroup struct {
RoGroupMode string
RoGroupId string
RoGroupName string
RoOfflineDelay int
RoMaxDelayTime int
MinRoInGroup int
WeightMode string
Weight int
// RoInstances
Vip string
Vport int
UniqVpcId string
UniqSubnetId string
RoGroupRegion string
RoGroupZone string
}
type SRoVipInfo struct {
RoVipStatus int
RoSubnetId int
RoVpcId int
RoVport int
RoVip string
}
type SMySQLInstance struct {
region *SRegion
multicloud.SDBInstanceBase
AutoRenew int
CdbError int
Cpu int
CreateTime time.Time
DeadlineTime string
DeployGroupId string
DeployMode int
DeviceClass string
DeviceType string
DrInfo []SDrInfo
EngineVersion string
ExClusterId string
HourFeeStatus int
InitFlag int
InstanceId string
InstanceName string
InstanceType int
IsolateTime string
MasterInfo SMasterInfo
Memory int
OfflineTime string
PayType int
PhysicalId string
ProjectId int
ProtectMode string
Qps int
Region string
RegionId string
ResourceId string
RoGroups []SRoGroup
RoVipInfo SRoVipInfo
SecurityGroupIds []string
SlaveInfo SlaveInfo
Status int
SubnetId int
//TagList": null,
TaskStatus int
UniqSubnetId string
UniqVpcId string
Vip string
Volume int
VpcId int
Vport int
WanDomain string
WanPort int
WanStatus int
Zone string
ZoneId int
ZoneName string
}
func (self *SMySQLInstance) GetId() string {
return self.InstanceId
}
func (self *SMySQLInstance) GetGlobalId() string {
return self.InstanceId
}
func (self *SMySQLInstance) GetName() string {
if len(self.InstanceName) > 0 {
return self.InstanceName
}
return self.InstanceId
}
func (self *SMySQLInstance) GetDiskSizeGB() int {
return self.Volume
}
func (self *SMySQLInstance) GetEngine() string {
return api.DBINSTANCE_TYPE_MYSQL
}
func (self *SMySQLInstance) GetEngineVersion() string {
return self.EngineVersion
}
func (self *SMySQLInstance) GetIVpcId() string {
return self.UniqVpcId
}
func (self *SMySQLInstance) Refresh() error {
rds, err := self.region.GetMySQLInstanceById(self.InstanceId)
if err != nil {
return errors.Wrapf(err, "GetMySQLInstanceById(%s)", self.InstanceId)
}
return jsonutils.Update(self, rds)
}
func (self *SMySQLInstance) GetInstanceType() string {
return fmt.Sprintf("%d核%dMB", self.Cpu, self.Memory)
}
func (self *SMySQLInstance) GetMaintainTime() string {
timeWindow, err := self.region.DescribeMySQLTimeWindow(self.InstanceId)
if err != nil {
log.Errorf("DescribeMySQLTimeWindow %s error: %v", self.InstanceId, err)
return ""
}
return timeWindow.String()
}
func (self *SMySQLInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) {
return &cloudprovider.SDBInstanceNetwork{NetworkId: self.UniqSubnetId, IP: self.Vip}, nil
}
func (self *SMySQLInstance) GetConnectionStr() string {
if self.WanStatus == 1 {
return fmt.Sprintf("%s:%d", self.WanDomain, self.WanPort)
}
return ""
}
func (self *SMySQLInstance) GetInternalConnectionStr() string {
return fmt.Sprintf("%s:%d", self.Vip, self.Vport)
}
func (self *SMySQLInstance) Reboot() error {
return self.region.RebootMySQLInstance(self.InstanceId)
}
func (self *SMySQLInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedDBInstanceChangeConfig) error {
return self.region.UpgradeMySQLDBInstance(self.InstanceId, opts.VmemSizeMb, opts.DiskSizeGB)
}
func (self *SMySQLInstance) GetMasterInstanceId() string {
return self.MasterInfo.InstanceId
}
func (self *SMySQLInstance) GetSecurityGroupId() string {
if len(self.SecurityGroupIds) > 0 {
return self.SecurityGroupIds[0]
}
if self.DeviceType == "BASIC" {
return ""
}
secgroups, err := self.region.DescribeMySQLDBSecurityGroups(self.InstanceId)
if err != nil {
log.Errorf("failed to get instance %s security group info %v", self.InstanceId, err)
return ""
}
if len(secgroups) > 0 {
return secgroups[0].SecurityGroupId
}
return ""
}
func (self *SMySQLInstance) Renew(bc billing.SBillingCycle) error {
month := bc.GetMonths()
return self.region.RenewMySQLDBInstance(self.InstanceId, month)
}
func (self *SMySQLInstance) OpenPublicConnection() error {
if self.WanStatus == 0 {
return self.region.OpenMySQLWanService(self.InstanceId)
}
return nil
}
func (self *SMySQLInstance) ClosePublicConnection() error {
if self.WanStatus == 1 {
return self.region.CloseMySQLWanService(self.InstanceId)
}
return nil
}
func (self *SMySQLInstance) GetPort() int {
return self.Vport
}
func (self *SMySQLInstance) GetStatus() string {
if self.InitFlag == 0 {
return api.DBINSTANCE_INIT
}
switch self.TaskStatus {
case 0:
switch self.Status {
case 0:
return api.DBINSTANCE_DEPLOYING
case 1:
return api.DBINSTANCE_RUNNING
case 4, 5:
return api.DBINSTANCE_DELETING
}
case 1:
case 2: //数据导入中
return api.DBINSTANCE_IMPORTING
case 3, 4: //开放关闭外网地址
return api.DBINSTANCE_DEPLOYING
case 10:
return api.DBINSTANCE_REBOOTING
case 12:
return api.DBINSTANCE_MIGRATING
default:
return api.DBINSTANCE_DEPLOYING
}
return api.DBINSTANCE_UNKNOWN
}
func (self *SMySQLInstance) GetCategory() string {
return strings.ToLower(self.DeviceType)
}
func (self *SMySQLInstance) GetStorageType() string {
switch self.DeviceType {
case "BASIC":
return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD
default:
return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD
}
}
func (self *SMySQLInstance) GetCreatedAt() time.Time {
// 2019-12-25 09:00:43 #非UTC时间
return self.CreateTime.Add(time.Hour * -8)
}
func (self *SMySQLInstance) GetBillingType() string {
if self.PayType == 0 {
return billingapi.BILLING_TYPE_PREPAID
}
return billingapi.BILLING_TYPE_POSTPAID
}
func (self *SMySQLInstance) SetAutoRenew(autoRenew bool) error {
return self.region.ModifyMySQLAutoRenewFlag([]string{self.InstanceId}, autoRenew)
}
func (self *SMySQLInstance) IsAutoRenew() bool {
return self.AutoRenew == 1
}
func (self *SMySQLInstance) GetExpiredAt() time.Time {
t, _ := timeutils.ParseTimeStr(self.DeadlineTime)
if t.IsZero() {
return t
}
return t.Add(time.Hour * -8)
}
func (self *SMySQLInstance) GetVcpuCount() int {
return self.Cpu
}
func (self *SMySQLInstance) GetVmemSizeMB() int {
return self.Memory
}
func (self *SMySQLInstance) GetZone1Id() string {
return self.Zone
}
func (self *SMySQLInstance) GetZone2Id() string {
return self.SlaveInfo.First.Zone
}
func (self *SMySQLInstance) GetZone3Id() string {
return self.SlaveInfo.Second.Zone
}
func (self *SMySQLInstance) GetProjectId() string {
return fmt.Sprintf("%d", self.ProjectId)
}
func (self *SMySQLInstance) Delete() error {
err := self.region.IsolateMySQLDBInstance(self.InstanceId)
if err != nil {
return errors.Wrapf(err, "IsolateMySQLDBInstance")
}
return self.region.OfflineIsolatedMySQLInstances([]string{self.InstanceId})
}
func (self *SRegion) ListMySQLInstances(ids []string, offset, limit int) ([]SMySQLInstance, int, error) {
if limit < 1 || limit > 50 {
limit = 50
}
params := map[string]string{
"Offset": fmt.Sprintf("%d", offset),
"Limit": fmt.Sprintf("%d", limit),
}
for idx, id := range ids {
params[fmt.Sprintf("InstanceIds.%d", idx)] = id
}
resp, err := self.cdbRequest("DescribeDBInstances", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeDBInstances")
}
items := []SMySQLInstance{}
err = resp.Unmarshal(&items, "Items")
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
total, _ := resp.Float("TotalCount")
return items, int(total), nil
}
type SAsyncRequestResult struct {
Info string
Status string
}
func (self *SRegion) DescribeMySQLAsyncRequestInfo(id string) (*SAsyncRequestResult, error) {
resp, err := self.cdbRequest("DescribeAsyncRequestInfo", map[string]string{"AsyncRequestId": id})
if err != nil {
return nil, errors.Wrapf(err, "DescribeAsyncRequestInfo")
}
result := SAsyncRequestResult{}
err = resp.Unmarshal(&result)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return &result, nil
}
func (self *SRegion) waitAsyncAction(action string, resId, asyncRequestId string) error {
if len(asyncRequestId) == 0 {
return errors.Error("Missing AsyncRequestId")
}
return cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) {
result, err := self.DescribeMySQLAsyncRequestInfo(asyncRequestId)
if err != nil {
return false, errors.Wrapf(err, action)
}
log.Debugf("task %s(%s) for mysql instance %s status: %s", action, asyncRequestId, resId, result.Status)
switch result.Status {
case "FAILED", "KILLED", "REMOVED", "PAUSED":
return true, errors.Errorf(result.Info)
case "SUCCESS":
return true, nil
default:
return false, nil
}
})
}
func (self *SRegion) RebootMySQLInstance(id string) error {
resp, err := self.cdbRequest("RestartDBInstances", map[string]string{"InstanceIds.0": id})
if err != nil {
return errors.Wrapf(err, "RestartDBInstances")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("RestartDBInstances", id, asyncRequestId)
}
func (self *SRegion) DescribeMySQLDBInstanceInfo(id string) (*SMySQLInstance, error) {
resp, err := self.cdbRequest("DescribeDBInstanceInfo", map[string]string{"InstanceId": id})
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBInstanceInfo")
}
result := SMySQLInstance{region: self}
err = resp.Unmarshal(&result)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return &result, nil
}
func (self *SRegion) RenewMySQLDBInstance(id string, month int) error {
params := map[string]string{
"InstanceId": id,
"TimeSpan": fmt.Sprintf("%d", month),
}
_, err := self.cdbRequest("RenewDBInstance", params)
if err != nil {
return errors.Wrapf(err, "RenewDBInstance")
}
return nil
}
func (self *SRegion) OfflineIsolatedMySQLInstances(ids []string) error {
params := map[string]string{}
for idx, id := range ids {
params[fmt.Sprintf("InstanceIds.%d", idx)] = id
}
_, err := self.cdbRequest("OfflineIsolatedInstances", params)
if err != nil {
return errors.Wrapf(err, "OfflineIsolatedInstances")
}
return nil
}
func (self *SRegion) ReleaseIsolatedMySQLDBInstances(ids []string) error {
params := map[string]string{}
for idx, id := range ids {
params[fmt.Sprintf("InstanceIds.%d", idx)] = id
}
resp, err := self.cdbRequest("ReleaseIsolatedDBInstances", params)
if err != nil {
return errors.Wrapf(err, "ReleaseIsolatedDBInstances")
}
result := []struct {
InstanceId string
Code int
Message string
}{}
err = resp.Unmarshal(&result, "Items")
if err != nil {
return errors.Wrapf(err, "resp.Unmarshal")
}
msg := []string{}
for i := range result {
if result[i].Code != 0 {
msg = append(msg, fmt.Sprintf("instance %s release isolate error: %s", result[i].InstanceId, result[i].Message))
}
}
if len(msg) > 0 {
return errors.Error(strings.Join(msg, " "))
}
return cloudprovider.Wait(time.Second, time.Minute*10, func() (bool, error) {
instances, _, err := self.ListMySQLInstances(ids, 0, len(ids))
if err != nil {
return false, errors.Wrapf(err, "ListMySQLInstances")
}
for i := range instances {
if instances[i].Status == 4 || instances[i].Status == 5 {
log.Debugf("mysql instance %s(%s) current be isolate", instances[i].InstanceName, instances[i].InstanceId)
return false, nil
}
}
return true, nil
})
}
func (self *SRegion) IsolateMySQLDBInstance(id string) error {
params := map[string]string{"InstanceId": id}
resp, err := self.cdbRequest("IsolateDBInstance", params)
if err != nil {
return errors.Wrapf(err, "IsolateDBInstance")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
if len(asyncRequestId) > 0 {
return self.waitAsyncAction("IsolateDBInstance", id, asyncRequestId)
}
return cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) {
instances, _, err := self.ListMySQLInstances([]string{id}, 0, 1)
if err != nil {
return false, errors.Wrapf(err, "ListMySQLInstances(%s)", id)
}
statusMap := map[int]string{0: "创建中", 1: "运行中", 4: "隔离中", 5: "已隔离"}
for _, rds := range instances {
status, _ := statusMap[rds.Status]
log.Debugf("instance %s(%s) status %d(%s)", rds.InstanceName, rds.InstanceId, rds.Status, status)
if rds.Status != 5 {
return false, nil
}
}
return true, nil
})
}
func (self *SRegion) CloseMySQLWanService(id string) error {
params := map[string]string{"InstanceId": id}
resp, err := self.cdbRequest("CloseWanService", params)
if err != nil {
return errors.Wrapf(err, "CloseWanService")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("CloseWanService", id, asyncRequestId)
}
func (self *SRegion) OpenMySQLWanService(id string) error {
params := map[string]string{"InstanceId": id}
resp, err := self.cdbRequest("OpenWanService", params)
if err != nil {
return errors.Wrapf(err, "OpenWanService")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("OpenWanService", id, asyncRequestId)
}
func (self *SRegion) InitMySQLDBInstances(ids []string, password string, parameters map[string]string, vport int) error {
params := map[string]string{"NewPassword": password}
for idx, id := range ids {
params[fmt.Sprintf("InstanceIds.%d", idx)] = id
}
i := 0
for k, v := range parameters {
params[fmt.Sprintf("Parameters.%d.name", i)] = k
params[fmt.Sprintf("Parameters.%d.value", i)] = v
i++
}
if vport >= 1024 && vport <= 65535 {
params["Vport"] = fmt.Sprintf("%d", vport)
}
resp, err := self.cdbRequest("InitDBInstances", params)
if err != nil {
return errors.Wrapf(err, "InitDBInstances")
}
asyncRequestIds := []string{}
err = resp.Unmarshal(&asyncRequestIds, "AsyncRequestIds")
if err != nil {
return errors.Wrapf(err, "resp.Unmarshal")
}
for idx, requestId := range asyncRequestIds {
err = self.waitAsyncAction("InitDBInstances", fmt.Sprintf("%d", idx), requestId)
if err != nil {
return err
}
}
return nil
}
func (self *SRegion) UpgradeMySQLDBInstance(id string, memoryMb int, volumeGb int) error {
params := map[string]string{
"InstanceId": id,
"Memory": fmt.Sprintf("%d", memoryMb),
"Volume": fmt.Sprintf("%d", volumeGb),
}
resp, err := self.cdbRequest("UpgradeDBInstance", params)
if err != nil {
return errors.Wrapf(err, "UpgradeDBInstance")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("UpgradeDBInstance", id, asyncRequestId)
}
func (self *SRegion) ModifyMySQLAutoRenewFlag(ids []string, autoRenew bool) error {
params := map[string]string{}
for idx, id := range ids {
params[fmt.Sprintf("InstanceIds.%d", idx)] = id
}
params["AutoRenew"] = fmt.Sprintf("%d", autoRenew)
_, err := self.cdbRequest("ModifyAutoRenewFlag", params)
return err
}
type SMaintenanceTime struct {
Monday []string
Tuesday []string
Wednesday []string
Thursday []string
Friday []string
Saturday []string
Sunday []string
}
func (w SMaintenanceTime) String() string {
windows := []string{}
for k, v := range map[string][]string{
"Monday": w.Monday,
"Tuesday": w.Tuesday,
"Wednesday": w.Wednesday,
"Thursday": w.Thursday,
"Friday": w.Friday,
"Saturday": w.Saturday,
"Sunday": w.Sunday,
} {
if len(v) > 0 {
windows = append(windows, fmt.Sprintf("%s: %s", k, strings.Join(v, " ")))
}
}
return strings.Join(windows, "\n")
}
func (self *SRegion) DescribeMySQLTimeWindow(id string) (*SMaintenanceTime, error) {
params := map[string]string{"InstanceId": id}
resp, err := self.cdbRequest("DescribeTimeWindow", params)
if err != nil {
return nil, errors.Wrapf(err, "DescribeTimeWindow")
}
timeWindow := &SMaintenanceTime{}
err = resp.Unmarshal(timeWindow)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return timeWindow, nil
}
type SDBSecgroup struct {
ProjectId int
CreateTime time.Time
SecurityGroupId string
SecurityGroupName string
SecurityGroupRemark string
}
func (self *SRegion) DescribeMySQLDBSecurityGroups(instanceId string) ([]SDBSecgroup, error) {
params := map[string]string{
"InstanceId": instanceId,
}
resp, err := self.cdbRequest("DescribeDBSecurityGroups", params)
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBSecurityGroups")
}
result := []SDBSecgroup{}
err = resp.Unmarshal(&result, "Groups")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return result, nil
}
func (self *SRegion) CreateMySQLDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (*SMySQLInstance, error) {
params := map[string]string{
"InstanceName": opts.Name,
"GoodsNum": "1",
"Memory": fmt.Sprintf("%d", opts.VmemSizeMb),
"Volume": fmt.Sprintf("%d", opts.DiskSizeGB),
"EngineVersion": opts.EngineVersion,
}
if len(opts.VpcId) > 0 {
params["UniqVpcId"] = opts.VpcId
}
if len(opts.NetworkId) > 0 {
params["UniqSubnetId"] = opts.NetworkId
}
if len(opts.ProjectId) > 0 {
params["ProjectId"] = opts.ProjectId
}
if opts.Port > 1024 && opts.Port < 65535 {
params["Port"] = fmt.Sprintf("%d", opts.Port)
}
if len(opts.Password) > 0 {
params["Password"] = opts.Password
}
if len(opts.SecgroupId) > 0 {
params["SecurityGroup.0"] = opts.SecgroupId
}
action := "CreateDBInstanceHour"
if opts.BillingCycle != nil {
params["Period"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths())
action = "CreateDBInstance"
}
switch opts.Category {
case api.QCLOUD_DBINSTANCE_CATEGORY_HA, api.QCLOUD_DBINSTANCE_CATEGORY_BASIC:
params["DeviceType"] = strings.ToUpper(opts.Category)
case api.QCLOUD_DBINSTANCE_CATEGORY_FINANCE:
params["DeviceType"] = "HA"
params["ProtectMode"] = "2"
}
if len(opts.Zone1) > 0 {
params["Zone"] = opts.Zone1
}
if len(opts.Zone2) > 0 {
params["SlaveZone"] = opts.Zone2
}
if len(opts.Zone3) > 0 {
params["BackupZone"] = opts.Zone3
}
params["ClientToken"] = utils.GenRequestId(20)
resp, err := self.cdbRequest(action, params)
if err != nil {
return nil, errors.Wrapf(err, "cdbRequest")
}
instanceIds := []string{}
err = resp.Unmarshal(&instanceIds, "InstanceIds")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
if len(instanceIds) == 0 {
return nil, fmt.Errorf("%s not return InstanceIds", action)
}
err = cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) {
instances, _, err := self.ListMySQLInstances(instanceIds, 0, 1)
if err != nil {
return false, errors.Wrapf(err, "ListMySQLInstances(%s)", instanceIds)
}
for _, rds := range instances {
log.Debugf("instance %s(%s) task status: %d", rds.InstanceName, rds.InstanceId, rds.TaskStatus)
if rds.TaskStatus == 1 {
return false, nil
}
}
return true, nil
})
if err != nil {
return nil, errors.Wrapf(err, "cloudprovider.Wait After create")
}
return self.GetMySQLInstanceById(instanceIds[0])
}
func (self *SRegion) GetMySQLInstanceById(id string) (*SMySQLInstance, error) {
part, total, err := self.ListMySQLInstances([]string{id}, 0, 20)
if err != nil {
return nil, errors.Wrapf(err, "ListMySQLInstances")
}
if total > 1 {
return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "id: [%s]", id)
}
if total < 1 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
}
part[0].region = self
return &part[0], nil
}
func (self *SMySQLInstance) CreateDatabase(opts *cloudprovider.SDBInstanceDatabaseCreateConfig) error {
return cloudprovider.ErrNotSupported
}
func (self *SMySQLInstance) CreateAccount(opts *cloudprovider.SDBInstanceAccountCreateConfig) error {
return self.region.CreateMySQLAccount(self.InstanceId, opts)
}
func (self *SMySQLInstance) CreateIBackup(opts *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
tables := map[string]string{}
for _, d := range opts.Databases {
tables[d] = ""
}
return self.region.CreateMySQLBackup(self.InstanceId, tables)
}
+367
View File
@@ -0,0 +1,367 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"fmt"
"strings"
"gopkg.in/fatih/set.v0"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SMySQLInstanceAccount struct {
multicloud.SDBInstanceAccountBase
rds *SMySQLInstance
Notes string
Host string
User string
ModifyTime string
ModifyPasswordTime string
CreateTime string
}
func (self *SMySQLInstanceAccount) GetName() string {
return self.User
}
func (self *SMySQLInstanceAccount) GetHost() string {
return self.Host
}
func (self *SMySQLInstanceAccount) ResetPassword(password string) error {
return self.rds.region.ModifyMySQLAccountPassword(self.rds.InstanceId, password, map[string]string{self.User: self.Host})
}
func (self *SMySQLInstanceAccount) Delete() error {
return self.rds.region.DeleteMySQLAccounts(self.rds.InstanceId, map[string]string{self.User: self.Host})
}
type sPrivilege struct {
Database string
Privilege string
User string
Host string
}
func (p sPrivilege) GetGlobalId() string {
return fmt.Sprintf("%s-%s-%s-%s", p.User, p.Host, p.Database, p.Privilege)
}
func (p sPrivilege) GetDBName() string {
return p.Database
}
func (p sPrivilege) GetPrivilege() string {
return p.Privilege
}
func (self *SRegion) GrantAccountPrivilege(instanceId, user, host, database, privilege string) error {
privileges := []string{}
switch privilege {
case api.DATABASE_PRIVILEGE_RW:
privileges = api.QCLOUD_RW_PRIVILEGE_SET
case api.DATABASE_PRIVILEGE_R:
privileges = api.QCLOUD_R_PRIVILEGE_SET
default:
return fmt.Errorf("unknow privilege %s", privilege)
}
priv, err := self.DescribeAccountPrivileges(instanceId, user, host)
if err != nil {
return errors.Wrapf(err, "DescribeAccountPrivileges")
}
params := map[string]string{
"InstanceId": instanceId,
"Accounts.0.User": user,
"Accounts.0.Host": host,
}
for i, p := range priv.GlobalPrivileges {
params[fmt.Sprintf("GlobalPrivileges.%d", i)] = p
}
find := false
for i, p := range priv.DatabasePrivileges {
params[fmt.Sprintf("DatabasePrivileges.%d.Database", i)] = p.Database
if database == p.Database {
p.Privileges = privileges
find = true
}
for j, v := range p.Privileges {
params[fmt.Sprintf("DatabasePrivileges.%d.Privileges.%d", i, j)] = v
}
}
if !find {
params[fmt.Sprintf("DatabasePrivileges.%d.Database", len(priv.DatabasePrivileges))] = database
for j, v := range privileges {
params[fmt.Sprintf("DatabasePrivileges.%d.Privileges.%d", len(priv.DatabasePrivileges), j)] = v
}
}
for i, p := range priv.TablePrivileges {
params[fmt.Sprintf("TablePrivileges.%d.Database", i)] = p.Database
params[fmt.Sprintf("TablePrivileges.%d.Table", i)] = p.Table
for j, v := range p.Privileges {
params[fmt.Sprintf("TablePrivileges.%d.Privileges.%d", i, j)] = v
}
}
for i, p := range priv.ColumnPrivileges {
params[fmt.Sprintf("ColumnPrivileges.%d.Database", i)] = p.Database
params[fmt.Sprintf("ColumnPrivileges.%d.Table", i)] = p.Table
params[fmt.Sprintf("ColumnPrivileges.%d.Column", i)] = p.Column
for j, v := range p.Privileges {
params[fmt.Sprintf("ColumnPrivileges.%d.Privileges.%d", i, j)] = v
}
}
resp, err := self.cdbRequest("ModifyAccountPrivileges", params)
if err != nil {
return errors.Wrapf(err, "ModifyAccountPrivileges")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("ModifyAccountPrivileges", instanceId, asyncRequestId)
}
func (self *SRegion) RevokeAccountPrivilege(instanceId, user, host, database string) error {
priv, err := self.DescribeAccountPrivileges(instanceId, user, host)
if err != nil {
return errors.Wrapf(err, "DescribeAccountPrivileges")
}
params := map[string]string{
"InstanceId": instanceId,
"Accounts.0.User": user,
"Accounts.0.Host": host,
}
for i, p := range priv.GlobalPrivileges {
params[fmt.Sprintf("GlobalPrivileges.%d", i)] = p
}
idx := 0
for _, p := range priv.DatabasePrivileges {
if p.Database == database {
continue
}
params[fmt.Sprintf("DatabasePrivileges.%d.Database", idx)] = p.Database
for i, v := range p.Privileges {
params[fmt.Sprintf("DatabasePrivileges.%d.Privileges.%d", idx, i)] = v
}
}
for i, p := range priv.TablePrivileges {
params[fmt.Sprintf("TablePrivileges.%d.Database", i)] = p.Database
params[fmt.Sprintf("TablePrivileges.%d.Table", i)] = p.Table
for j, v := range p.Privileges {
params[fmt.Sprintf("TablePrivileges.%d.Privileges.%d", i, j)] = v
}
}
for i, p := range priv.ColumnPrivileges {
params[fmt.Sprintf("ColumnPrivileges.%d.Database", i)] = p.Database
params[fmt.Sprintf("ColumnPrivileges.%d.Table", i)] = p.Table
params[fmt.Sprintf("ColumnPrivileges.%d.Column", i)] = p.Column
for j, v := range p.Privileges {
params[fmt.Sprintf("ColumnPrivileges.%d.Privileges.%d", i, j)] = v
}
}
resp, err := self.cdbRequest("ModifyAccountPrivileges", params)
if err != nil {
return errors.Wrapf(err, "ModifyAccountPrivileges")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("ModifyAccountPrivileges", instanceId, asyncRequestId)
}
func (self *SMySQLInstanceAccount) GrantPrivilege(database, privilege string) error {
return self.rds.region.GrantAccountPrivilege(self.rds.InstanceId, self.User, self.Host, database, privilege)
}
func (self *SMySQLInstanceAccount) RevokePrivilege(database string) error {
return self.rds.region.RevokeAccountPrivilege(self.rds.InstanceId, self.User, self.Host, database)
}
func (self *SMySQLInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) {
if utils.IsInStringArray(self.User, []string{"mysql.infoschema", "mysql.session", "mysql.sys"}) {
return []cloudprovider.ICloudDBInstanceAccountPrivilege{}, nil
}
priv, err := self.rds.region.DescribeAccountPrivileges(self.rds.InstanceId, self.User, self.Host)
if err != nil {
return nil, errors.Wrapf(err, "DescribeAccountPrivileges")
}
ret := []cloudprovider.ICloudDBInstanceAccountPrivilege{}
rwSet := set.New(set.ThreadSafe)
for _, p := range api.QCLOUD_RW_PRIVILEGE_SET {
rwSet.Add(p)
}
rSet := set.New(set.ThreadSafe)
for _, p := range api.QCLOUD_R_PRIVILEGE_SET {
rSet.Add(p)
}
for _, p := range priv.DatabasePrivileges {
pSet := set.New(set.ThreadSafe)
for _, v := range p.Privileges {
pSet.Add(v)
}
priv := strings.Join(p.Privileges, ",")
if pSet.IsEqual(rSet) {
priv = api.DATABASE_PRIVILEGE_R
} else if pSet.IsEqual(rwSet) {
priv = api.DATABASE_PRIVILEGE_RW
}
privilege := &sPrivilege{
Database: p.Database,
User: self.User,
Host: self.Host,
Privilege: priv,
}
ret = append(ret, privilege)
}
return ret, nil
}
func (self *SRegion) ModifyMySQLAccountPassword(instanceId string, password string, users map[string]string) error {
params := map[string]string{
"InstanceId": instanceId,
"NewPassword": password,
}
idx := 0
for user, host := range users {
params[fmt.Sprintf("Accounts.%d.user", idx)] = user
params[fmt.Sprintf("Accounts.%d.host", idx)] = host
idx++
}
resp, err := self.cdbRequest("ModifyAccountPassword", params)
if err != nil {
return errors.Wrapf(err, "ModifyAccountPassword")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("ModifyAccountPassword", instanceId, asyncRequestId)
}
func (self *SRegion) DeleteMySQLAccounts(instanceId string, users map[string]string) error {
params := map[string]string{
"InstanceId": instanceId,
}
idx := 0
for user, host := range users {
params[fmt.Sprintf("Accounts.%d.user", idx)] = user
params[fmt.Sprintf("Accounts.%d.host", idx)] = host
idx++
}
resp, err := self.cdbRequest("DeleteAccounts", params)
if err != nil {
return errors.Wrapf(err, "DeleteAccounts")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("DeleteAccounts", instanceId, asyncRequestId)
}
func (self *SRegion) DescribeMySQLAccounts(instanceId string, offset, limit int) ([]SMySQLInstanceAccount, int, error) {
if limit < 1 || limit > 100 {
limit = 100
}
params := map[string]string{
"InstanceId": instanceId,
"Offset": fmt.Sprintf("%d", offset),
"Limit": fmt.Sprintf("%d", limit),
}
resp, err := self.cdbRequest("DescribeAccounts", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeAccounts")
}
ret := []SMySQLInstanceAccount{}
err = resp.Unmarshal(&ret, "Items")
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
totalCount, _ := resp.Float("TotalCount")
return ret, int(totalCount), nil
}
func (self *SMySQLInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) {
ret := []cloudprovider.ICloudDBInstanceAccount{}
for {
part, total, err := self.region.DescribeMySQLAccounts(self.InstanceId, len(ret), 100)
if err != nil {
return nil, errors.Wrapf(err, "DescribeMySQLAccounts")
}
for i := range part {
part[i].rds = self
ret = append(ret, &part[i])
}
if len(ret) >= total {
break
}
}
return ret, nil
}
func (self *SRegion) CreateMySQLAccount(instanceId string, opts *cloudprovider.SDBInstanceAccountCreateConfig) error {
params := map[string]string{
"InstanceId": instanceId,
"Password": opts.Password,
"Accounts.0.User": opts.Name,
"Accounts.0.Host": opts.Host,
"Description": opts.Description,
}
resp, err := self.cdbRequest("CreateAccounts", params)
if err != nil {
return errors.Wrapf(err, "CreateAccounts")
}
asyncRequestId, _ := resp.GetString("AsyncRequestId")
return self.waitAsyncAction("CreateAccounts", instanceId, asyncRequestId)
}
type SDatabasePrivilege struct {
Privileges []string
Database string
}
type STablePrivilege struct {
Database string
Table string
Privileges []string
}
type SColumnPrivilege struct {
Database string
Table string
Column string
Privileges []string
}
type SAccountPrivilege struct {
GlobalPrivileges []string
DatabasePrivileges []SDatabasePrivilege
TablePrivileges []STablePrivilege
ColumnPrivileges []SColumnPrivilege
}
func (self *SRegion) DescribeAccountPrivileges(instanceId string, user, host string) (*SAccountPrivilege, error) {
params := map[string]string{
"InstanceId": instanceId,
"User": user,
"Host": host,
}
resp, err := self.cdbRequest("DescribeAccountPrivileges", params)
if err != nil {
return nil, errors.Wrapf(err, "DescribeAccountPrivileges")
}
priv := &SAccountPrivilege{}
err = resp.Unmarshal(priv)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return priv, nil
}
+240
View File
@@ -0,0 +1,240 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"fmt"
"time"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/timeutils"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SMySQLInstanceBackup struct {
multicloud.SDBInstanceBackupBase
rds *SMySQLInstance
Name string
Size int
Date string
IntranetUrl string
InternetUrl string
Type string
BackupId int
Status string
FinishTime string
Creator string
StartTime string
Method string
Way string
}
func (self *SMySQLInstanceBackup) GetId() string {
return fmt.Sprintf("%d", self.BackupId)
}
func (self *SMySQLInstanceBackup) GetGlobalId() string {
return self.GetId()
}
func (self *SMySQLInstanceBackup) GetName() string {
if len(self.Name) > 0 {
return self.Name
}
return self.GetId()
}
func (self *SMySQLInstanceBackup) GetEngine() string {
return api.DBINSTANCE_TYPE_MYSQL
}
func (self *SMySQLInstanceBackup) GetStatus() string {
switch self.Status {
case "SUCCESS":
return api.DBINSTANCE_BACKUP_READY
case "FAILED":
return api.DBINSTANCE_BACKUP_CREATE_FAILED
case "RUNNING":
return api.DBINSTANCE_BACKUP_CREATING
default:
return api.DBINSTANCE_BACKUP_UNKNOWN
}
}
func (self *SMySQLInstanceBackup) GetEngineVersion() string {
return self.rds.EngineVersion
}
func (self *SMySQLInstanceBackup) GetDBInstanceId() string {
return self.rds.InstanceId
}
func (self *SMySQLInstanceBackup) GetStartTime() time.Time {
start, err := timeutils.ParseTimeStr(self.StartTime)
if err != nil {
return time.Time{}
}
return start.Add(time.Hour * -8)
}
func (self *SMySQLInstanceBackup) GetEndTime() time.Time {
end, err := timeutils.ParseTimeStr(self.FinishTime)
if err != nil {
return time.Time{}
}
return end.Add(time.Hour * -8)
}
func (self *SMySQLInstanceBackup) GetBackupSizeMb() int {
return self.Size / 1024 / 1024
}
func (self *SMySQLInstanceBackup) GetDBNames() string {
return ""
}
func (self *SMySQLInstanceBackup) GetBackupMode() string {
if self.Way == "manual" {
return api.BACKUP_MODE_MANUAL
}
return api.BACKUP_MODE_AUTOMATED
}
func (self *SMySQLInstanceBackup) Delete() error {
return self.rds.region.DeleteBackup(self.rds.InstanceId, fmt.Sprintf("%d", self.BackupId))
}
func (self *SMySQLInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
backups := []cloudprovider.ICloudDBInstanceBackup{}
for {
part, total, err := self.region.DescribeMySQLBackups(self.InstanceId, len(backups), 100)
if err != nil {
return nil, errors.Wrapf(err, "DescribeMySQLBackups")
}
for i := range part {
part[i].rds = self
backups = append(backups, &part[i])
}
if len(backups) >= total {
break
}
}
return backups, nil
}
func (self *SRegion) DescribeMySQLBackups(instanceId string, offset, limit int) ([]SMySQLInstanceBackup, int, error) {
if limit < 1 || limit > 100 {
limit = 100
}
params := map[string]string{
"Offset": fmt.Sprintf("%d", offset),
"Limit": fmt.Sprintf("%d", limit),
}
if len(instanceId) > 0 {
params["InstanceId"] = instanceId
}
resp, err := self.cdbRequest("DescribeBackups", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeBackups")
}
backups := []SMySQLInstanceBackup{}
err = resp.Unmarshal(&backups, "Items")
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
totalCount, _ := resp.Float("TotalCount")
return backups, int(totalCount), nil
}
func (self *SRegion) DeleteBackup(instanceId, id string) error {
params := map[string]string{
"InstanceId": instanceId,
"BackupId": id,
}
_, err := self.cdbRequest("DeleteBackup", params)
if err != nil {
return errors.Wrapf(err, "DeleteBackup")
}
return nil
}
func (self *SRegion) GetMySQLInstanceBackup(instanceId, backupId string) (*SMySQLInstanceBackup, error) {
backups := []SMySQLInstanceBackup{}
for {
part, total, err := self.DescribeMySQLBackups(instanceId, len(backups), 100)
if err != nil {
return nil, errors.Wrapf(err, "DescribeMySQLBackups")
}
for i := range part {
if fmt.Sprintf("%d", part[i].BackupId) == backupId {
return &part[i], nil
}
}
backups = append(backups, part...)
if len(backups) >= total {
break
}
}
return nil, fmt.Errorf("failed to found rds %s backup %s", instanceId, backupId)
}
func (self *SRegion) waitMySQLBackupReady(instanceId, backupId string) error {
return cloudprovider.Wait(time.Second*20, time.Minute*30, func() (bool, error) {
backup, err := self.GetMySQLInstanceBackup(instanceId, backupId)
if err != nil {
return false, errors.Wrapf(err, "GetMySQLInstanceBackup")
}
log.Infof("backup %s for instance %s status %s", backup.GetName(), instanceId, backup.Status)
if utils.IsInStringArray(backup.Status, []string{"FAILED", "SUCCESS"}) {
return true, nil
}
return false, nil
})
}
func (self *SRegion) CreateMySQLBackup(instanceId string, tables map[string]string) (string, error) {
params := map[string]string{
"InstanceId": instanceId,
"BackupMethod": "physical",
}
if len(tables) > 0 {
params["BackupMethod"] = "logical"
idx := 0
for db, table := range tables {
params[fmt.Sprintf("BackupDBTableList.%d.Db", idx)] = db
if len(table) > 0 {
params[fmt.Sprintf("BackupDBTableList.%d.Table", idx)] = table
}
idx++
}
}
resp, err := self.cdbRequest("CreateBackup", params)
if err != nil {
return "", errors.Wrapf(err, "CreateBackup")
}
_backupId, _ := resp.Float("BackupId")
backupId := fmt.Sprintf("%d", int(_backupId))
err = self.waitMySQLBackupReady(instanceId, backupId)
if err != nil {
return "", errors.Wrapf(err, "waitBackupReady")
}
return backupId, nil
}
@@ -0,0 +1,97 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"fmt"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SMySQLInstanceDatabase struct {
rds *SMySQLInstance
multicloud.SResourceBase
CharacterSet string
DatabaseName string
}
func (self *SMySQLInstanceDatabase) GetStatus() string {
return api.DBINSTANCE_DATABASE_RUNNING
}
func (self *SMySQLInstanceDatabase) GetId() string {
return self.DatabaseName
}
func (self *SMySQLInstanceDatabase) GetName() string {
return self.DatabaseName
}
func (self *SMySQLInstanceDatabase) GetGlobalId() string {
return self.DatabaseName
}
func (self *SMySQLInstanceDatabase) GetCharacterSet() string {
return self.CharacterSet
}
func (self *SMySQLInstanceDatabase) Delete() error {
return cloudprovider.ErrNotSupported
}
func (self *SRegion) DescribeMySQLDatabases(instanceId string, offset, limit int) ([]SMySQLInstanceDatabase, int, error) {
if limit < 1 || limit > 100 {
limit = 100
}
params := map[string]string{
"Offset": fmt.Sprintf("%d", offset),
"Limit": fmt.Sprintf("%d", limit),
"InstanceId": instanceId,
}
resp, err := self.cdbRequest("DescribeDatabases", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeDatabases")
}
databases := []SMySQLInstanceDatabase{}
err = resp.Unmarshal(&databases, "DatabaseList")
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
totalCount, _ := resp.Float("TotalCount")
return databases, int(totalCount), nil
}
func (rds *SMySQLInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) {
ret := []cloudprovider.ICloudDBInstanceDatabase{}
for {
part, total, err := rds.region.DescribeMySQLDatabases(rds.InstanceId, len(ret), 100)
if err != nil {
return nil, errors.Wrapf(err, "DescribeMySQLDatabases")
}
for i := range part {
part[i].rds = rds
ret = append(ret, &part[i])
}
if len(ret) >= total {
break
}
}
return ret, nil
}
+183
View File
@@ -0,0 +1,183 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SellTypeConfig struct {
Device string
Type string
CdbType string
Memory int
Cpu int
VolumeMin int
VolumeMax int
VolumeStep int
Connection int
Qps int
Iops int
Info string
Status string
Tag string
}
type SSellType struct {
TypeName string
EngineVersion []string
Configs []SellTypeConfig
}
type SZoneConf struct {
DeployMode []int
MasterZone []string
SlaveZone []string
BackupZone []string
}
type SZoneSellConf struct {
Status int
ZoneName string
IsCustom bool
IsSupportDr bool
IsSupportVpc bool
HourInstanceSaleMaxNum int
IsDefaultZone bool
IsBm bool
PayType []string
ProtectMode string
Zone string
SellType []SSellType
ZoneConf SZoneConf
DrZone []string
IsSupportRemoteRo bool
}
type SRegionSellConf struct {
RegionName string
Area string
IsDefaultRegion bool
Region string
ZonesConf []SZoneSellConf
}
func (self *SRegion) DescribeDBZoneConfig() ([]SRegionSellConf, error) {
resp, err := self.cdbRequest("DescribeDBZoneConfig", map[string]string{})
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBZoneConfig")
}
skus := []SRegionSellConf{}
err = resp.Unmarshal(&skus, "Items")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return skus, nil
}
type SDBInstanceSku struct {
Region string
Engine string
EngineVersion string
Category string
Iops int
Qps int
MaxConnection int
Cpu int
MemoryMb int
StorageType string
StorageMin int
StorageMax int
StorageStep int
Status string
Description string
Zone1 string
Zone2 string
Zone3 string
}
func (self *SRegion) ListMysqlSkus() ([]SDBInstanceSku, error) {
conf, err := self.DescribeDBZoneConfig()
if err != nil {
return nil, errors.Wrapf(err, "DescribeDBZoneConfig")
}
skus := []SDBInstanceSku{}
for _, item := range conf {
if item.Region != self.Region {
continue
}
sku := SDBInstanceSku{
Region: self.Region,
Engine: api.DBINSTANCE_TYPE_MYSQL,
Status: api.DBINSTANCE_SKU_SOLDOUT,
}
for _, zone := range item.ZonesConf {
//0-未上线;1-上线;2-开放;3-停售;4-不展示
if zone.Status == 0 || zone.Status == 4 {
continue
}
if zone.Status == 1 || zone.Status == 2 {
sku.Status = api.DBINSTANCE_SKU_AVAILABLE
}
if zone.IsBm { // 跳过黑石
continue
}
for _, sellType := range zone.SellType {
for _, sellConf := range sellType.Configs {
sku.Cpu = sellConf.Cpu
sku.MemoryMb = sellConf.Memory
sku.Iops = sellConf.Iops
sku.MaxConnection = sellConf.Connection
sku.Qps = sellConf.Qps
sku.StorageMin = sellConf.VolumeMin
sku.StorageMax = sellConf.VolumeMax
sku.StorageStep = sellConf.VolumeStep
sku.Zone1 = zone.Zone
for _, engineVersion := range sellType.EngineVersion {
sku.EngineVersion = engineVersion
sku.Category = sellConf.Type
sku.Zone2, sku.Zone3 = "", ""
sku.StorageType = api.STORAGE_LOCAL_SSD
switch sellConf.Type {
case "高可用版":
for _, zone2 := range zone.ZoneConf.SlaveZone {
sku.Zone2 = zone2
skus = append(skus, sku)
}
if utils.IsInStringArray(engineVersion, []string{"5.6", "5.7", "8.0"}) {
sku.Category = "金融版"
for _, zone2 := range zone.ZoneConf.SlaveZone {
sku.Zone2 = zone2
sku.Zone3 = zone2
skus = append(skus, sku)
}
}
case "基础版":
sku.StorageType = api.STORAGE_CLOUD_SSD
skus = append(skus, sku)
default:
log.Errorf("unknow %s", sellConf.Type)
}
}
}
}
}
}
return skus, nil
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SpecItemInfoList struct {
SpecCode string
Version string
VersionName string
Cpu int
Memory int
MaxStorage int
MinStorage int
Qps int
Pid int
Type string
}
type SpecInfoList struct {
Region string
Zone string
SpecItemInfoList []SpecItemInfoList
}
func (self *SRegion) DescribeProductConfig() ([]SpecInfoList, error) {
resp, err := self.postgresRequest("DescribeProductConfig", map[string]string{})
if err != nil {
return nil, errors.Wrapf(err, "DescribeProductConfig")
}
products := []SpecInfoList{}
err = resp.Unmarshal(&products, "SpecInfoList")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return products, nil
}
func (self *SRegion) ListPostgreSQLSkus() ([]SDBInstanceSku, error) {
skus := []SDBInstanceSku{}
products, err := self.DescribeProductConfig()
if err != nil {
return nil, errors.Wrapf(err, "DescribeProductConfig")
}
for _, product := range products {
sku := SDBInstanceSku{
Region: self.Region,
Zone1: product.Zone,
Engine: api.DBINSTANCE_TYPE_POSTGRESQL,
Status: api.DBINSTANCE_SKU_AVAILABLE,
Category: "双机高可用",
}
for _, spec := range product.SpecItemInfoList {
sku.EngineVersion = spec.Version
sku.Qps = spec.Qps
sku.Cpu = spec.Cpu
sku.MemoryMb = spec.Memory * 1024
sku.StorageMax = spec.MaxStorage
sku.StorageMin = spec.MinStorage
sku.StorageStep = 10
skus = append(skus, sku)
}
}
return skus, nil
}
@@ -0,0 +1,76 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SqlServerSpecInfoList struct {
Cpu int
MachineType string
MachineTypeName string
MaxStorage int
Memory int
MinStorage int
PayModeStatus string
Pid int
PostPid []int
Qps int
RoPid int
SpecId int
SuitInfo string
Version string
VersionName string
}
func (self *SRegion) DescribeSqlServerProductConfig(zoneId string) ([]SqlServerSpecInfoList, error) {
resp, err := self.sqlserverRequest("DescribeProductConfig", map[string]string{"Zone": zoneId})
if err != nil {
return nil, errors.Wrapf(err, "DescribeProductConfig")
}
specs := []SqlServerSpecInfoList{}
err = resp.Unmarshal(&specs, "SpecInfoList")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return specs, nil
}
func (self *SRegion) ListSQLServerSkus() ([]SDBInstanceSku, error) {
zones, err := self.GetIZones()
if err != nil {
return nil, errors.Wrapf(err, "GetIZones")
}
skus := []SDBInstanceSku{}
for _, zone := range zones {
products, err := self.DescribeSqlServerProductConfig(zone.GetId())
if err != nil {
return nil, errors.Wrapf(err, "DescribeSqlServerProductConfig")
}
for _, product := range products {
sku := SDBInstanceSku{
Region: self.Region,
Zone1: zone.GetId(),
Engine: api.DBINSTANCE_TYPE_SQLSERVER,
EngineVersion: product.Version,
}
skus = append(skus, sku)
}
}
return skus, nil
}
+20
View File
@@ -674,6 +674,26 @@ func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonut
return self.client.lbRequest(apiName, params)
}
func (self *SRegion) cdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
params["Region"] = self.Region
return self.client.cdbRequest(apiName, params)
}
func (self *SRegion) mariadbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
params["Region"] = self.Region
return self.client.mariadbRequest(apiName, params)
}
func (self *SRegion) postgresRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
params["Region"] = self.Region
return self.client.postgresRequest(apiName, params)
}
func (self *SRegion) sqlserverRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
params["Region"] = self.Region
return self.client.sqlserverRequest(apiName, params)
}
func (self *SRegion) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
return self.client.wssRequest(apiName, params)
}
@@ -0,0 +1,60 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"github.com/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type MariadbRegionListOptions struct {
}
shellutils.R(&MariadbRegionListOptions{}, "mariadb-region-list", "List mariadb region list", func(cli *qcloud.SRegion, args *MariadbRegionListOptions) error {
regions, err := cli.DescribeSaleInfo()
if err != nil {
return errors.Wrapf(err, "DescribeSaleInfo")
}
printList(regions, 0, 0, 0, nil)
return nil
})
type MariadbSpecListOptions struct {
}
shellutils.R(&MariadbSpecListOptions{}, "mariadb-spec-list", "List mariadb specs", func(cli *qcloud.SRegion, args *MariadbSpecListOptions) error {
specs, err := cli.DescribeDBInstanceSpecs()
if err != nil {
return errors.Wrapf(err, "DescribeDBInstanceSpecs")
}
printList(specs, 0, 0, 0, nil)
return nil
})
type MariadbSkuListOptions struct {
}
shellutils.R(&MariadbSkuListOptions{}, "mariadb-sku-list", "List mariadb skus", func(cli *qcloud.SRegion, args *MariadbSkuListOptions) error {
skus, err := cli.ListMariadbSkus()
if err != nil {
return errors.Wrapf(err, "ListMariadbSkus")
}
printList(skus, 0, 0, 0, nil)
return nil
})
}
+171
View File
@@ -0,0 +1,171 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type MysqlSkuListOptions struct {
}
shellutils.R(&MysqlSkuListOptions{}, "mysql-sku-list", "List mysql instance types", func(cli *qcloud.SRegion, args *MysqlSkuListOptions) error {
skus, err := cli.ListMysqlSkus()
if err != nil {
return errors.Wrapf(err, "ListMysqlSkus")
}
printList(skus, 0, 0, 0, nil)
return nil
})
type MysqlInstanceListOptions struct {
Ids []string
Offset int
Limit int
}
shellutils.R(&MysqlInstanceListOptions{}, "mysql-instance-list", "List mysql instance", func(cli *qcloud.SRegion, args *MysqlInstanceListOptions) error {
result, _, err := cli.ListMySQLInstances(args.Ids, args.Offset, args.Limit)
if err != nil {
return errors.Wrapf(err, "ListMySQLInstances")
}
printList(result, 0, 0, 0, nil)
return nil
})
type MySQLInstanceIdOptions struct {
ID string
}
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-reboot", "Reboot mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
return cli.RebootMySQLInstance(args.ID)
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-isolate", "Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
return cli.IsolateMySQLDBInstance(args.ID)
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-offline-isolate", "Offline Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
return cli.OfflineIsolatedMySQLInstances([]string{args.ID})
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-release-isolate", "Release Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
return cli.ReleaseIsolatedMySQLDBInstances([]string{args.ID})
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-secgroup-list", "List mysql instance secgroups", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
secgroups, err := cli.DescribeMySQLDBSecurityGroups(args.ID)
if err != nil {
return err
}
printList(secgroups, 0, 0, 0, nil)
return nil
})
type MySQLInstanceDBListOptions struct {
MySQLInstanceIdOptions
Offset int
Limit int
}
shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-database-list", "List mysql instance database", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error {
databases, totalCount, err := cli.DescribeMySQLDatabases(args.ID, args.Offset, args.Limit)
if err != nil {
return err
}
printList(databases, 0, 0, 0, nil)
fmt.Println("TotalCount: ", totalCount)
return nil
})
shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-account-list", "List mysql instance accounts", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error {
accounts, totalCount, err := cli.DescribeMySQLAccounts(args.ID, args.Offset, args.Limit)
if err != nil {
return err
}
printList(accounts, 0, 0, 0, nil)
fmt.Println("TotalCount: ", totalCount)
return nil
})
shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-backup-list", "List mysql instance backups", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error {
backups, totalCount, err := cli.DescribeMySQLBackups(args.ID, args.Offset, args.Limit)
if err != nil {
return err
}
printList(backups, 0, 0, 0, nil)
fmt.Println("TotalCount: ", totalCount)
return nil
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-show", "Show mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
result, err := cli.DescribeMySQLDBInstanceInfo(args.ID)
if err != nil {
return err
}
printObject(result)
return nil
})
type MySQLRenewOptions struct {
MySQLInstanceIdOptions
MONTH int `choices:"1|2|3|4|5|6|7|8|9|10|11|12|24|36"`
}
shellutils.R(&MySQLRenewOptions{}, "mysql-instance-renew", "Renew mysql instance", func(cli *qcloud.SRegion, args *MySQLRenewOptions) error {
return cli.RenewMySQLDBInstance(args.ID, args.MONTH)
})
shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-backup-create", "Create mysql instance backup", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error {
backup, err := cli.CreateMySQLBackup(args.ID, nil)
if err != nil {
return err
}
printObject(backup)
return nil
})
type RestAccountPasswordOptions struct {
INSTANCE_ID string
PASSWORD string
USER string
Host string `default:"%"`
}
shellutils.R(&RestAccountPasswordOptions{}, "mysql-account-reset-password", "Reset mysql account password", func(cli *qcloud.SRegion, args *RestAccountPasswordOptions) error {
return cli.ModifyMySQLAccountPassword(args.INSTANCE_ID, args.PASSWORD, map[string]string{args.USER: args.Host})
})
type MySQLAccountPrivilegeShowOptions struct {
INSTANCE_ID string
USER string
Host string `default:"%"`
}
shellutils.R(&MySQLAccountPrivilegeShowOptions{}, "mysql-account-privilege-show", "Show account privileges", func(cli *qcloud.SRegion, args *MySQLAccountPrivilegeShowOptions) error {
result, err := cli.DescribeAccountPrivileges(args.INSTANCE_ID, args.USER, args.Host)
if err != nil {
return err
}
printObject(result)
return nil
})
}
@@ -0,0 +1,48 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type PostgreSQLProductListOptions struct {
}
shellutils.R(&PostgreSQLProductListOptions{}, "postgre-product-list", "List postgre sql products", func(cli *qcloud.SRegion, args *PostgreSQLProductListOptions) error {
products, err := cli.DescribeProductConfig()
if err != nil {
return errors.Wrapf(err, "DescribeProductConfig")
}
printList(products, 0, 0, 0, nil)
return nil
})
type SPostgreSQLSkuListOptions struct {
}
shellutils.R(&SPostgreSQLSkuListOptions{}, "postgre-sku-list", "List postgre sql skus", func(cli *qcloud.SRegion, args *SPostgreSQLSkuListOptions) error {
skus, err := cli.ListPostgreSQLSkus()
if err != nil {
return errors.Wrapf(err, "ListPostgreSQLSkus")
}
printList(skus, 0, 0, 0, nil)
return nil
})
}
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SQLServerSQLProductListOptions struct {
ZONE string
}
shellutils.R(&SQLServerSQLProductListOptions{}, "sqlserver-product-list", "List sql server products", func(cli *qcloud.SRegion, args *SQLServerSQLProductListOptions) error {
products, err := cli.DescribeSqlServerProductConfig(args.ZONE)
if err != nil {
return errors.Wrapf(err, "DescribeProductConfig")
}
printList(products, 0, 0, 0, nil)
return nil
})
type SSQLServerSQLSkuListOptions struct {
}
shellutils.R(&SSQLServerSQLSkuListOptions{}, "sqlserver-sku-list", "List sqlserver skus", func(cli *qcloud.SRegion, args *SSQLServerSQLSkuListOptions) error {
skus, err := cli.ListSQLServerSkus()
if err != nil {
return errors.Wrapf(err, "ListSQLServerSkus")
}
printList(skus, 0, 0, 0, nil)
return nil
})
}