Merge pull request #13529 from ioito/feat/qx-aws-rds

fix(region): aws rds create
This commit is contained in:
Zexi Li
2022-02-28 15:14:36 +08:00
committed by GitHub
28 changed files with 649 additions and 228 deletions
+3
View File
@@ -160,6 +160,9 @@ type DBInstanceCreateInput struct {
// 从备份中创建新实例
DBInstancebackupId string `json:"dbinstancebackup_id"`
// 多可用区部署
MultiAZ bool `json:"multi_az"`
}
type SDBInstanceChangeConfigInput struct {
+13
View File
@@ -103,6 +103,7 @@ const (
DBINSTANCE_TYPE_ORACLE = "Oracle"
DBINSTANCE_TYPE_PPAS = "PPAS"
DBINSTANCE_TYPE_PERCONA = "Percona"
DBINSTANCE_TYPE_AURORA = "Aurora"
//阿里云实例类型
ALIYUN_DBINSTANCE_CATEGORY_BASIC = "basic" //基础版
@@ -128,6 +129,18 @@ const (
// Azure
AZURE_DBINSTANCE_CATEGORY_BASIC = "basic"
// Aws
// SQLServer
AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION = "Enterprise Edition"
AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION = "Express Edition"
AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION = "Standard Edition"
AWS_DBINSTANCE_CATEGORY_WEB_EDITION = "Web Edition"
// Oracle
AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO = "Standard Edition Two"
AWS_DBINSTANCE_CATEGORY_GENERAL_PURPOSE = "General Purpose"
AWS_DBINSTANCE_CATEGORY_MEMORY_OPTIMIZED = "Memory Optimized"
//阿里云存储类型
ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD = "local_ssd" //本地盘SSD盘
ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD = "cloud_essd" //ESSD云盘
+1
View File
@@ -42,6 +42,7 @@ const (
STATUS_UPDATE_TAGS = "update_tags"
STATUS_UPDATE_TAGS_FAILED = "update_tags_fail"
STATUS_SYNC_STATUS = "sync_status"
STATUS_DELETING = "deleting"
STATUS_DELETE_FAILED = "delete_failed"
STATUS_UNKNOWN = "unknown"
+2
View File
@@ -67,6 +67,8 @@ type SManagedDBInstanceCreateConfig struct {
Username string
ProjectId string
MultiAz bool
BillingCycle *billing.SBillingCycle
Tags map[string]string
+1 -1
View File
@@ -1071,7 +1071,7 @@ func syncDBInstanceSkus(ctx context.Context, userCred mcclient.TokenCredential,
syncResults.Add(DBInstanceSkuManager, result)
msg := result.Result()
log.Infof("SyncDBInstanceSkus for region %s result: %s", localRegion.Name, msg)
log.Infof("sync rds sku for region %s result: %s", localRegion.Name, msg)
if result.IsError() {
return
}
+9 -7
View File
@@ -79,12 +79,13 @@ type SDBInstanceSku struct {
Category string `width:"32" index:"true" nullable:"false" list:"user" create:"optional"`
Engine string `width:"16" index:"true" charset:"ascii" nullable:"false" list:"user" create:"required"`
EngineVersion string `width:"16" index:"true" charset:"ascii" nullable:"false" list:"user" create:"required"`
EngineVersion string `width:"64" index:"true" charset:"ascii" nullable:"false" list:"user" create:"required"`
Zone1 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Zone2 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Zone3 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Zone1 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Zone2 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Zone3 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
MultiAZ tristate.TriState `default:"false" list:"user" create:"optional"`
}
func (manager *SDBInstanceSkuManager) fetchDBInstanceSkus(provider string, region *SCloudregion) ([]SDBInstanceSku, error) {
@@ -543,6 +544,7 @@ func (sku *SDBInstanceSku) syncWithCloudSku(ctx context.Context, userCred mcclie
sku.Status = isku.Status
sku.TPS = isku.TPS
sku.QPS = isku.QPS
sku.MultiAZ = isku.MultiAZ
sku.MaxConnections = isku.MaxConnections
return nil
})
@@ -569,7 +571,7 @@ func SyncRegionDBInstanceSkus(ctx context.Context, userCred mcclient.TokenCreden
return
}
if cnt > 0 {
log.Debugf("SyncDBInstanceSkus synced skus, skip...")
log.Debugf("sync rds sku for %s synced skus, skip...", regionId)
return
}
}
@@ -599,7 +601,7 @@ func SyncRegionDBInstanceSkus(ctx context.Context, userCred mcclient.TokenCreden
}
result := DBInstanceSkuManager.SyncDBInstanceSkus(ctx, userCred, &region, meta)
msg := result.Result()
notes := fmt.Sprintf("SyncDBInstanceSkus for region %s result: %s", region.Name, msg)
notes := fmt.Sprintf("sync rds sku for region %s result: %s", region.Name, msg)
log.Infof(notes)
}
+49 -78
View File
@@ -111,7 +111,7 @@ type SDBInstance struct {
Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 引擎版本
// example: 5.7
EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"`
EngineVersion string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 套餐名称
// example: mysql.x4.large.2c
InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"`
@@ -124,9 +124,9 @@ type SDBInstance struct {
VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
// 外部连接地址
ConnectionStr string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"optional"`
ConnectionStr string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"`
// 内部连接地址
InternalConnectionStr string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"optional"`
InternalConnectionStr string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"`
// 可用区1
Zone1 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
@@ -275,17 +275,13 @@ func (man *SDBInstanceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field
return q, httperrors.ErrNotFound
}
func (manager *SDBInstanceManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
input := api.DBInstanceCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
return nil, errors.Wrapf(err, "data.Unmarshal")
}
func (manager *SDBInstanceManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (api.DBInstanceCreateInput, error) {
var err error
input, err = manager.ValidateCreateData(ctx, userCred, ownerId, query, input)
if err != nil {
return nil, errors.Wrapf(err, "ValidateCreateData")
return input, errors.Wrapf(err, "ValidateCreateData")
}
return input.JSON(input), nil
return input, nil
}
func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (api.DBInstanceCreateInput, error) {
@@ -497,18 +493,12 @@ func (self *SDBInstance) PostCreate(ctx context.Context, userCred mcclient.Token
ids = append(ids, secgroupId)
}
}
resetPassword := true
if input.ResetPassword != nil && !*input.ResetPassword {
resetPassword = false
}
self.StartDBInstanceCreateTask(ctx, userCred, resetPassword, input.Password, "")
self.StartDBInstanceCreateTask(ctx, userCred, jsonutils.Marshal(input))
}
func (self *SDBInstance) StartDBInstanceCreateTask(ctx context.Context, userCred mcclient.TokenCredential, resetPassword bool, password, parentTaskId string) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(password), "password")
params.Add(jsonutils.NewBool(resetPassword), "reset_password")
task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceCreateTask", self, userCred, params, parentTaskId, "", nil)
func (self *SDBInstance) StartDBInstanceCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
params := data.(*jsonutils.JSONDict)
task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceCreateTask", self, userCred, params, "", "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
@@ -785,6 +775,9 @@ func (self *SDBInstance) GetMasterInstance() (*SDBInstance, error) {
}
func (self *SDBInstance) GetIDBInstance() (cloudprovider.ICloudDBInstance, error) {
if len(self.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
}
iregion, err := self.GetIRegion()
if err != nil {
return nil, errors.Wrap(err, "self.GetIRegion")
@@ -899,18 +892,15 @@ func (self *SDBInstance) PerformReboot(ctx context.Context, userCred mcclient.To
//同步RDS实例状态
func (self *SDBInstance) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var openTask = true
count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
if err != nil {
return nil, err
}
if count > 0 {
return nil, httperrors.NewBadRequestError("DBInstance has %d task active, can't sync status", count)
}
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "DBInstanceSyncStatusTask", "")
return self.PerformSync(ctx, userCred, query, data)
}
// 同步RDS状态(弃用)
func (self *SDBInstance) PerformSyncStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return self.PerformSync(ctx, userCred, query, data)
}
// 同步RDS信息
func (self *SDBInstance) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var openTask = true
count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
@@ -921,20 +911,7 @@ func (self *SDBInstance) PerformSync(ctx context.Context, userCred mcclient.Toke
return nil, httperrors.NewBadRequestError("DBInstance has %d task active, can't sync status", count)
}
return nil, self.StartDBInstanceSyncTask(ctx, userCred, jsonutils.NewDict(), "")
}
func (self *SDBInstance) PerformSyncStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var openTask = true
count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
if err != nil {
return nil, err
}
if count > 0 {
return nil, httperrors.NewBadRequestError("DBInstance has %d task active, can't sync status", count)
}
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "DBInstanceSyncStatusTask", "")
return nil, self.StartDBInstanceSyncTask(ctx, userCred, "")
}
func (self *SDBInstance) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
@@ -1136,14 +1113,8 @@ func (self *SDBInstance) StartDBInstanceRebootTask(ctx context.Context, userCred
return nil
}
func (self *SDBInstance) StartDBInstanceSyncTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
self.SetStatus(userCred, api.DBINSTANCE_SYNC_CONFIG, "")
task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceSyncTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
func (self *SDBInstance) StartDBInstanceSyncTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
return StartResourceSyncStatusTask(ctx, userCred, self, "DBInstanceSyncTask", parentTaskId)
}
func (manager *SDBInstanceManager) getDBInstancesByProviderId(providerId string) ([]SDBInstance, error) {
@@ -1600,36 +1571,36 @@ func (self *SDBInstance) SyncAllWithCloudDBInstance(ctx context.Context, userCre
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()
self.VcpuCount = extInstance.GetVcpuCount()
self.VmemSizeMb = extInstance.GetVmemSizeMB()
self.DiskSizeGB = extInstance.GetDiskSizeGB()
self.StorageType = extInstance.GetStorageType()
self.Category = extInstance.GetCategory()
self.Status = extInstance.GetStatus()
self.Port = extInstance.GetPort()
func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudDBInstance) error {
diff, err := db.Update(self, func() error {
self.ExternalId = ext.GetGlobalId()
self.Engine = ext.GetEngine()
self.EngineVersion = ext.GetEngineVersion()
self.InstanceType = ext.GetInstanceType()
self.VcpuCount = ext.GetVcpuCount()
self.VmemSizeMb = ext.GetVmemSizeMB()
self.DiskSizeGB = ext.GetDiskSizeGB()
self.StorageType = ext.GetStorageType()
self.Category = ext.GetCategory()
self.Status = ext.GetStatus()
self.Port = ext.GetPort()
self.ConnectionStr = extInstance.GetConnectionStr()
self.InternalConnectionStr = extInstance.GetInternalConnectionStr()
self.ConnectionStr = ext.GetConnectionStr()
self.InternalConnectionStr = ext.GetInternalConnectionStr()
self.MaintainTime = extInstance.GetMaintainTime()
self.SetZoneIds(extInstance)
self.MaintainTime = ext.GetMaintainTime()
self.SetZoneIds(ext)
if createdAt := extInstance.GetCreatedAt(); !createdAt.IsZero() {
if createdAt := ext.GetCreatedAt(); !createdAt.IsZero() {
self.CreatedAt = createdAt
}
if expiredAt := extInstance.GetExpiredAt(); !expiredAt.IsZero() {
if expiredAt := ext.GetExpiredAt(); !expiredAt.IsZero() {
self.ExpiredAt = expiredAt
}
if len(self.VpcId) == 0 {
if vpcId := extInstance.GetIVpcId(); len(vpcId) > 0 {
if vpcId := ext.GetIVpcId(); len(vpcId) > 0 {
vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("manager_id", provider.Id)
})
@@ -1658,12 +1629,12 @@ func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred m
return errors.Wrap(err, "SyncWithCloudDBInstance.GetProviderFactory")
}
if factory.IsSupportPrepaidResources() && !extInstance.GetExpiredAt().IsZero() {
self.BillingType = extInstance.GetBillingType()
if expired := extInstance.GetExpiredAt(); !expired.IsZero() {
if factory.IsSupportPrepaidResources() && !ext.GetExpiredAt().IsZero() {
self.BillingType = ext.GetBillingType()
if expired := ext.GetExpiredAt(); !expired.IsZero() {
self.ExpiredAt = expired
}
self.AutoRenew = extInstance.IsAutoRenew()
self.AutoRenew = ext.IsAutoRenew()
}
return nil
@@ -1671,7 +1642,7 @@ func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred m
if err != nil {
return err
}
syncVirtualResourceMetadata(ctx, userCred, self, extInstance)
syncVirtualResourceMetadata(ctx, userCred, self, ext)
db.OpsLog.LogSyncUpdate(self, diff, userCred)
if len(diff) > 0 {
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
+2 -5
View File
@@ -19,15 +19,12 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/mcclient"
)
const (
SYNC_STATUS = "sync_status"
)
type IStatusBase interface {
SetStatus(userCred mcclient.TokenCredential, status string, reason string) error
GetStatus() string
@@ -45,7 +42,7 @@ func StartResourceSyncStatusTask(ctx context.Context, userCred mcclient.TokenCre
if err != nil {
return err
}
obj.SetStatus(userCred, SYNC_STATUS, "perform_syncstatus")
obj.SetStatus(userCred, apis.STATUS_SYNC_STATUS, "perform_syncstatus")
task.ScheduleRun(nil)
return nil
}
+62
View File
@@ -42,6 +42,7 @@ import (
"yunion.io/x/onecloud/pkg/util/pinyinutils"
"yunion.io/x/onecloud/pkg/util/rand"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
type SAwsRegionDriver struct {
@@ -98,6 +99,67 @@ func networkCheck(network *models.SNetwork) error {
return nil
}
func (self *SAwsRegionDriver) IsSupportedDBInstance() bool {
return true
}
func (self *SAwsRegionDriver) GetRdsSupportSecgroupCount() int {
return 1
}
func (self *SAwsRegionDriver) ValidateCreateDBInstanceData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input api.DBInstanceCreateInput, skus []models.SDBInstanceSku, network *models.SNetwork) (api.DBInstanceCreateInput, error) {
if len(input.Password) > 0 {
for _, s := range input.Password {
if s == '/' || s == '"' || s == '@' || s == '\'' {
return input, httperrors.NewInputParameterError("aws rds not support password character %s", string(s))
}
}
}
if len(input.Password) == 0 {
for _, s := range seclib2.RandomPassword2(100) {
if s == '/' || s == '"' || s == '@' || s == '\'' {
continue
}
input.Password += string(s)
if len(input.Password) >= 20 {
break
}
}
}
return input, nil
}
func (self *SAwsRegionDriver) ValidateCreateDBInstanceBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceBackupCreateInput) (api.DBInstanceBackupCreateInput, error) {
return input, nil
}
func (self *SAwsRegionDriver) ValidateCreateDBInstanceDatabaseData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceDatabaseCreateInput) (api.DBInstanceDatabaseCreateInput, error) {
return input, httperrors.NewNotSupportedError("aws not support create rds database")
}
func (self *SAwsRegionDriver) ValidateCreateDBInstanceAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceAccountCreateInput) (api.DBInstanceAccountCreateInput, error) {
return input, httperrors.NewNotSupportedError("aws not support create rds account")
}
func (self *SAwsRegionDriver) InitDBInstanceUser(ctx context.Context, instance *models.SDBInstance, task taskman.ITask, desc *cloudprovider.SManagedDBInstanceCreateConfig) error {
user := "admin"
if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL || desc.Category == api.DBINSTANCE_TYPE_POSTGRESQL {
user = "postgres"
}
account := models.SDBInstanceAccount{}
account.DBInstanceId = instance.Id
account.Name = user
account.Status = api.DBINSTANCE_USER_AVAILABLE
account.SetModelManager(models.DBInstanceAccountManager, &account)
err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
if err != nil {
return err
}
return account.SetPassword(desc.Password)
}
func validateAwsLbNetwork(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, requiredMin int) (*jsonutils.JSONDict, error) {
var networkIds []string
if ns, err := data.GetString("network"); err != nil {
+6 -5
View File
@@ -1580,10 +1580,10 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
return nil, errors.Wrap(err, "dbinstance.GetVpc()")
}
params := task.GetParams()
passwd, _ := params.GetString("password")
if len(passwd) == 0 && jsonutils.QueryBoolean(params, "reset_password", true) {
passwd = seclib2.RandomPassword2(12)
input := api.DBInstanceCreateInput{}
task.GetParams().Unmarshal(&input)
if len(input.Password) == 0 && jsonutils.QueryBoolean(task.GetParams(), "reset_password", true) {
input.Password = seclib2.RandomPassword2(12)
}
desc := cloudprovider.SManagedDBInstanceCreateConfig{
Name: dbinstance.Name,
@@ -1597,7 +1597,8 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
EngineVersion: dbinstance.EngineVersion,
Category: dbinstance.Category,
Port: dbinstance.Port,
Password: passwd,
Password: input.Password,
MultiAz: input.MultiAZ,
}
desc.Tags, _ = dbinstance.GetAllUserMetadata()
@@ -80,7 +80,7 @@ func (self *DBInstanceChangeConfigTask) OnDBInstanceChangeConfigComplete(ctx con
Action: notifyclient.ActionChangeConfig,
})
self.SetStage("OnSyncDBInstanceStatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, rds, "DBInstanceSyncStatusTask", self.GetTaskId())
rds.StartDBInstanceSyncTask(ctx, self.UserCred, self.GetTaskId())
}
func (self *DBInstanceChangeConfigTask) OnDBInstanceChangeConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
+1 -1
View File
@@ -76,7 +76,7 @@ func (self *DBInstanceCreateTask) OnCreateDBInstanceComplete(ctx context.Context
rds := obj.(*models.SDBInstance)
logclient.AddActionLogWithStartable(self, rds, logclient.ACT_CREATE, nil, self.UserCred, true)
self.SetStage("OnSyncDBInstanceStatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, rds, "DBInstanceSyncStatusTask", self.GetTaskId())
rds.StartDBInstanceSyncTask(ctx, self.UserCred, self.GetTaskId())
}
func (self *DBInstanceCreateTask) OnCreateDBInstanceCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
@@ -16,6 +16,7 @@ package tasks
import (
"context"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
@@ -71,6 +72,10 @@ func (self *DBInstanceDeleteTask) DeleteDBInstance(ctx context.Context, rds *mod
self.taskFailed(ctx, rds, err)
return
}
err = cloudprovider.WaitDeleted(irds, time.Second*10, time.Minute*50)
if err != nil {
self.taskFailed(ctx, rds, errors.Wrapf(err, "WaitDeleted"))
}
}
self.DeleteDBInstanceComplete(ctx, rds)
@@ -58,7 +58,7 @@ func (self *DBInstanceRemoteUpdateTask) OnInit(ctx context.Context, obj db.IStan
func (self *DBInstanceRemoteUpdateTask) OnRemoteUpdateComplete(ctx context.Context, rds *models.SDBInstance, data jsonutils.JSONObject) {
self.SetStage("OnSyncStatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, rds, "DBInstanceSyncStatusTask", self.GetTaskId())
rds.StartDBInstanceSyncTask(ctx, self.UserCred, self.GetTaskId())
}
func (self *DBInstanceRemoteUpdateTask) OnRemoteUpdateCompleteFailed(ctx context.Context, rds *models.SDBInstance, data jsonutils.JSONObject) {
+1 -1
View File
@@ -88,7 +88,7 @@ func (self *DBInstanceRenewTask) OnInit(ctx context.Context, obj db.IStandaloneM
logclient.AddActionLogWithStartable(self, rds, logclient.ACT_RENEW, map[string]string{"duration": duration}, self.UserCred, true)
self.SetStage("OnSyncstatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, rds, "DBInstanceSyncStatusTask", self.GetTaskId())
rds.StartDBInstanceSyncTask(ctx, self.UserCred, self.GetTaskId())
}
func (self *DBInstanceRenewTask) OnSyncstatusComplete(ctx context.Context, rds *models.SDBInstance, data jsonutils.JSONObject) {
@@ -59,7 +59,7 @@ func (self *DBInstanceSetAutoRenewTask) OnInit(ctx context.Context, obj db.IStan
return
}
self.SetStage("OnDBInstanceSyncComplete", nil)
rds.StartDBInstanceSyncTask(ctx, self.GetUserCred(), nil, "")
rds.StartDBInstanceSyncTask(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *DBInstanceSetAutoRenewTask) OnDBInstanceSyncComplete(ctx context.Context, rds *models.SDBInstance, data jsonutils.JSONObject) {
@@ -65,7 +65,7 @@ func (self *DBInstanceSyncSecgroupsTask) OnSyncSecurityGroupsCompleteFailed(ctx
func (self *DBInstanceSyncSecgroupsTask) OnSyncSecurityGroupsComplete(ctx context.Context, rds *models.SDBInstance, data jsonutils.JSONObject) {
self.SetStage("OnSyncComplete", nil)
rds.StartDBInstanceSyncTask(ctx, self.GetUserCred(), nil, self.GetTaskId())
rds.StartDBInstanceSyncTask(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *DBInstanceSyncSecgroupsTask) OnSyncCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
@@ -1,64 +0,0 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type DBInstanceSyncStatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(DBInstanceSyncStatusTask{})
}
func (self *DBInstanceSyncStatusTask) taskFailed(ctx context.Context, dbinstance *models.SDBInstance, err error) {
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)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionSyncStatus,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *DBInstanceSyncStatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
dbinstance := obj.(*models.SDBInstance)
self.SyncStatusDBInstance(ctx, dbinstance)
}
func (self *DBInstanceSyncStatusTask) SyncStatusDBInstance(ctx context.Context, dbinstance *models.SDBInstance) {
idbinstance, err := dbinstance.GetIDBInstance()
if err != nil {
self.taskFailed(ctx, dbinstance, errors.Wrapf(err, "dbinstance.GetIDBInstance"))
return
}
dbinstance.SyncAllWithCloudDBInstance(ctx, self.UserCred, dbinstance.GetCloudprovider(), idbinstance)
self.SetStageComplete(ctx, nil)
}
+17 -11
View File
@@ -23,6 +23,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -35,27 +36,32 @@ func init() {
taskman.RegisterTask(DBInstanceSyncTask{})
}
func (self *DBInstanceSyncTask) taskFailed(ctx context.Context, dbinstance *models.SDBInstance, err error) {
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_UNKNOWN, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_SYNC_CONF, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_SYNC_CONF, err, self.UserCred, false)
func (self *DBInstanceSyncTask) taskFailed(ctx context.Context, rds *models.SDBInstance, err error) {
rds.SetStatus(self.UserCred, api.DBINSTANCE_UNKNOWN, err.Error())
db.OpsLog.LogEvent(rds, db.ACT_SYNC_STATUS, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, rds, logclient.ACT_SYNC_CONF, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: rds,
Action: notifyclient.ActionSyncStatus,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *DBInstanceSyncTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
dbinstance := obj.(*models.SDBInstance)
self.SyncDBInstance(ctx, dbinstance)
rds := obj.(*models.SDBInstance)
self.SyncDBInstance(ctx, rds)
}
func (self *DBInstanceSyncTask) SyncDBInstance(ctx context.Context, dbinstance *models.SDBInstance) {
idbinstance, err := dbinstance.GetIDBInstance()
func (self *DBInstanceSyncTask) SyncDBInstance(ctx context.Context, rds *models.SDBInstance) {
irds, err := rds.GetIDBInstance()
if err != nil {
self.taskFailed(ctx, dbinstance, errors.Wrapf(err, "dbinstance.GetIDBInstance"))
self.taskFailed(ctx, rds, errors.Wrapf(err, "rds.GetIDBInstance"))
return
}
err = dbinstance.SyncAllWithCloudDBInstance(ctx, self.UserCred, dbinstance.GetCloudprovider(), idbinstance)
err = rds.SyncAllWithCloudDBInstance(ctx, self.UserCred, rds.GetCloudprovider(), irds)
if err != nil {
self.taskFailed(ctx, dbinstance, errors.Wrapf(err, "dbinstance.GetIDBInstance"))
self.taskFailed(ctx, rds, errors.Wrapf(err, "rds.GetIDBInstance"))
return
}
self.SetStageComplete(ctx, nil)
@@ -43,6 +43,7 @@ type DBInstanceCreateOptions struct {
AllowDelete *bool `help:"not lock dbinstance" `
Tags []string `help:"Tags info,prefix with 'user:', eg: user:project=default" json:"-"`
DBInstancebackupId string `help:"create dbinstance from backup" json:"dbinstancebackup_id"`
MultiAz bool `help:"deploy rds with multi az"`
}
func (opts *DBInstanceCreateOptions) Params() (jsonutils.JSONObject, error) {
+1 -1
View File
@@ -505,7 +505,7 @@ func (self *SAwsClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_NETWORK,
cloudprovider.CLOUD_CAPABILITY_LOADBALANCER,
cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX,
cloudprovider.CLOUD_CAPABILITY_RDS,
cloudprovider.CLOUD_CAPABILITY_CACHE + cloudprovider.READ_ONLY_SUFFIX,
cloudprovider.CLOUD_CAPABILITY_NAT + cloudprovider.READ_ONLY_SUFFIX,
cloudprovider.CLOUD_CAPABILITY_EVENT,
+32 -21
View File
@@ -29,7 +29,7 @@ import (
"github.com/aws/aws-sdk-go/aws/request"
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/private/protocol/query"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
xj "github.com/basgys/goxml2json"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -142,37 +142,48 @@ func Build(r *request.Request) {
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.ec2query.UnmarshalError", Fn: UnmarshalError}
type sAwsError struct {
Errors struct {
Type string
Code string
Message string
} `json:"Error"`
RequestID string
}
func (self sAwsError) Error() string {
return jsonutils.Marshal(self).String()
}
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
respErr := &struct {
XMLName xml.Name `xml:"Response"`
Code string `xml:"Errors>Error>Code"`
Message string `xml:"Errors>Error>Message"`
RequestID string `xml:"RequestID"`
}{}
err := xmlutil.UnmarshalXMLError(&respErr, r.HTTPResponse.Body)
result, err := xj.Convert(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
r.Error = errors.Wrapf(err, "xj.Convert")
return
}
if strings.Contains(respErr.Code, "NotFound") {
obj, err := jsonutils.Parse([]byte(result.String()))
if err != nil {
r.Error = errors.Wrapf(err, "jsonutils.Parse")
return
}
respErr := &sAwsError{}
err = obj.Unmarshal(respErr, "ErrorResponse")
if err != nil {
r.Error = errors.Wrapf(err, "obj.Unmarshal")
return
}
if strings.Contains(respErr.Errors.Code, "NotFound") {
r.Error = errors.Wrapf(cloudprovider.ErrNotFound, jsonutils.Marshal(respErr).String())
return
}
r.Error = awserr.NewRequestFailure(
awserr.New(respErr.Code, respErr.Message, nil),
r.HTTPResponse.StatusCode,
respErr.RequestID,
)
r.Error = respErr
return
}
func (self *SAwsClient) request(regionId, serviceName, serviceId, apiVersion string, apiName string, params map[string]string, retval interface{}, assumeRole bool) error {
+316 -8
View File
@@ -15,7 +15,9 @@
package aws
import (
"context"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
@@ -119,6 +121,7 @@ type SDBInstance struct {
type SDBInstances struct {
DBInstances []SDBInstance `xml:"DBInstances>DBInstance"`
Marker string `xml:"Marker"`
}
func (rds *SDBInstance) GetName() string {
@@ -133,14 +136,17 @@ func (rds *SDBInstance) GetGlobalId() string {
return rds.GetId()
}
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/accessing-monitoring.html#Overview.DBInstance.Status
func (rds *SDBInstance) GetStatus() string {
switch rds.DBInstanceStatus {
case "creating":
case "creating", "backing-up":
return api.DBINSTANCE_DEPLOYING
case "available":
return api.DBINSTANCE_RUNNING
case "deleting":
return api.DBINSTANCE_DELETING
case "rebooting":
return api.DBINSTANCE_REBOOTING
default:
log.Errorf("Unknown db instance status: %s", rds.DBInstanceStatus)
return api.DBINSTANCE_UNKNOWN
@@ -159,11 +165,57 @@ func (rds *SDBInstance) GetCreatedAt() time.Time {
return rds.InstanceCreateTime
}
func (rds *SDBInstance) Reboot() error {
return rds.region.RebootDBInstance(rds.DBInstanceIdentifier)
}
func (self *SDBInstance) GetCategory() string {
switch self.Engine {
case "aurora", "aurora-mysql":
return api.DBINSTANCE_TYPE_MYSQL
case "aurora-postgresql":
return api.DBINSTANCE_TYPE_POSTGRESQL
case "oracle-ee", "sqlserver-ee":
return api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION
case "oracle-se2":
return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO
case "sqlserver-se":
return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION
case "sqlserver-ex":
return api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION
case "sqlserver-web":
return api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION
default:
if strings.HasPrefix(self.DBInstanceClass, "db.r") || strings.HasPrefix(self.DBInstanceClass, "db.x") || strings.HasPrefix(self.DBInstanceClass, "db.d") {
return api.AWS_DBINSTANCE_CATEGORY_MEMORY_OPTIMIZED
}
return api.AWS_DBINSTANCE_CATEGORY_GENERAL_PURPOSE
}
}
func (rds *SDBInstance) GetStorageType() string {
return rds.StorageType
}
func (rds *SDBInstance) GetEngine() string {
if strings.Contains(rds.Engine, "aurora") {
return api.DBINSTANCE_TYPE_AURORA
}
if strings.Contains(rds.Engine, "oracle") {
return api.DBINSTANCE_TYPE_ORACLE
}
if strings.Contains(rds.Engine, "sqlserver") {
return api.DBINSTANCE_TYPE_SQLSERVER
}
for k, v := range map[string]string{
"mariadb": api.DBINSTANCE_TYPE_MARIADB,
"mysql": api.DBINSTANCE_TYPE_MYSQL,
"postgres": api.DBINSTANCE_TYPE_POSTGRESQL,
} {
if rds.Engine == k {
return v
}
}
return rds.Engine
}
@@ -175,6 +227,20 @@ func (rds *SDBInstance) GetInstanceType() string {
return rds.DBInstanceClass
}
func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error {
params := map[string]string{
"DBInstanceIdentifier": rds.DBInstanceIdentifier,
"ApplyImmediately": "true",
}
if config.DiskSizeGB > 0 && rds.GetEngine() != api.DBINSTANCE_TYPE_AURORA {
params["AllocatedStorage"] = fmt.Sprintf("%d", config.DiskSizeGB)
}
if len(config.InstanceType) > 0 {
params["DBInstanceClass"] = config.InstanceType
}
return rds.region.rdsRequest("ModifyDBInstance", params, nil)
}
func (rds *SDBInstance) GetVcpuCount() int {
if spec, ok := DBInstanceSpecs[rds.DBInstanceClass]; ok {
return spec.VcpuCount
@@ -210,11 +276,12 @@ func (rds *SDBInstance) Refresh() error {
if err != nil {
return err
}
rds.AwsTags = instance.AwsTags
return jsonutils.Update(rds, instance)
}
func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) {
instances, err := region.GetDBInstances(instanceId)
instances, _, err := region.GetDBInstances(instanceId, "")
if err != nil {
return nil, errors.Wrap(err, "GetDBInstances")
}
@@ -278,6 +345,22 @@ func (rds *SDBInstance) GetConnectionStr() string {
return ""
}
func (rds *SDBInstance) OpenPublicConnection() error {
params := map[string]string{
"DBInstanceIdentifier": rds.DBInstanceIdentifier,
"PubliclyAccessible": "true",
}
return rds.region.rdsRequest("ModifyDBInstance", params, nil)
}
func (rds *SDBInstance) ClosePublicConnection() error {
params := map[string]string{
"DBInstanceIdentifier": rds.DBInstanceIdentifier,
"PubliclyAccessible": "false",
}
return rds.region.rdsRequest("ModifyDBInstance", params, nil)
}
func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) {
parameters, err := rds.region.GetDBInstanceParameters(rds.DBParameterGroups[0].DBParameterGroupName)
if err != nil {
@@ -300,7 +383,37 @@ func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInsta
return idatabases, nil
}
func (region *SRegion) GetDBInstances(instanceId string) ([]SDBInstance, error) {
func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
backups, err := rds.region.GetDBInstanceSnapshots(rds.DBInstanceIdentifier, "")
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudDBInstanceBackup{}
for i := range backups {
backups[i].region = rds.region
ret = append(ret, &backups[i])
}
return ret, nil
}
func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
params := map[string]string{
"DBInstanceIdentifier": rds.DBInstanceIdentifier,
"DBSnapshotIdentifier": conf.Name,
}
ret := struct {
DBSnapshot SDBInstanceSnapshot `xml:"DBSnapshot"`
}{}
err := rds.region.rdsRequest("CreateDBSnapshot", params, &ret)
if err != nil {
return "", err
}
ret.DBSnapshot.region = rds.region
cloudprovider.WaitStatus(&ret.DBSnapshot, api.DBINSTANCE_BACKUP_READY, time.Second*10, time.Hour*2)
return ret.DBSnapshot.GetGlobalId(), nil
}
func (region *SRegion) GetDBInstances(instanceId, marker string) ([]SDBInstance, string, error) {
instances := SDBInstances{}
params := map[string]string{}
idx := 1
@@ -308,28 +421,43 @@ func (region *SRegion) GetDBInstances(instanceId string) ([]SDBInstance, error)
params[fmt.Sprintf("Filters.Filter.%d.Name", idx)] = "dbi-resource-id"
params[fmt.Sprintf("Filters.Filter.%d.Values.Value.1", idx)] = instanceId
}
if len(marker) > 0 {
params["Marker"] = marker
}
err := region.rdsRequest("DescribeDBInstances", params, &instances)
if err != nil {
return nil, errors.Wrap(err, "DescribeDBInstances")
return nil, "", errors.Wrap(err, "DescribeDBInstances")
}
return instances.DBInstances, nil
return instances.DBInstances, instances.Marker, nil
}
func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) {
instances, err := region.GetDBInstances("")
idbinstances := []cloudprovider.ICloudDBInstance{}
instances, marker, err := region.GetDBInstances("", "")
if err != nil {
return nil, errors.Wrap(err, "GetDBInstances")
}
idbinstances := []cloudprovider.ICloudDBInstance{}
for i := 0; i < len(instances); i++ {
instances[i].region = region
idbinstances = append(idbinstances, &instances[i])
}
for len(marker) > 0 {
instances, marker, err = region.GetDBInstances("", marker)
if err != nil {
return nil, errors.Wrap(err, "GetDBInstances")
}
for i := 0; i < len(instances); i++ {
instances[i].region = region
idbinstances = append(idbinstances, &instances[i])
}
}
return idbinstances, nil
}
func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) {
instances, err := self.GetDBInstances(id)
instances, _, err := self.GetDBInstances(id, "")
if err != nil {
return nil, errors.Wrap(err, "GetDBInstances")
}
@@ -345,3 +473,183 @@ func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstan
instances[0].region = self
return &instances[0], nil
}
func (self *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
params := map[string]string{
"DBInstanceClass": desc.InstanceType,
"DBInstanceIdentifier": desc.Name,
"EngineVersion": desc.EngineVersion,
"MasterUsername": "admin",
}
if len(desc.Password) > 0 {
params["MasterUserPassword"] = desc.Password
}
if desc.Engine != api.DBINSTANCE_TYPE_AURORA {
params["StorageType"] = desc.StorageType
params["AllocatedStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB)
for i, sec := range desc.SecgroupIds {
params[fmt.Sprintf("VpcSecurityGroupIds.VpcSecurityGroupId.%d", i+1)] = sec
}
}
if desc.MultiAz {
params["MultiAZ"] = "true"
}
if desc.StorageType == api.STORAGE_IO1_SSD {
params["Iops"] = "3000"
}
switch desc.Engine {
case api.DBINSTANCE_TYPE_MYSQL:
params["Engine"] = "mysql"
case api.DBINSTANCE_TYPE_POSTGRESQL:
params["Engine"] = "postgres"
params["MasterUsername"] = "postgres"
case api.DBINSTANCE_TYPE_MARIADB:
params["Engine"] = "mariadb"
case api.DBINSTANCE_TYPE_SQLSERVER:
params["LicenseModel"] = "license-included"
switch desc.Category {
case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION:
params["Engine"] = "sqlserver-ee"
case api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION:
params["Engine"] = "sqlserver-ex"
params["MultiAZ"] = "false"
case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION:
params["Engine"] = "sqlserver-se"
case api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION:
params["Engine"] = "sqlserver-web"
params["MultiAZ"] = "false"
default:
return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine)
}
case api.DBINSTANCE_TYPE_AURORA:
delete(params, "MultiAZ")
switch desc.Category {
case api.DBINSTANCE_TYPE_MYSQL:
params["Engine"] = "aurora"
if !strings.HasPrefix(desc.EngineVersion, "5.6") {
params["Engine"] = "aurora-mysql"
}
case api.DBINSTANCE_TYPE_POSTGRESQL:
params["Engine"] = "aurora-postgresql"
params["MasterUsername"] = "postgres"
default:
return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine)
}
case api.DBINSTANCE_TYPE_ORACLE:
params["LicenseModel"] = "bring-your-own-license"
switch desc.Category {
case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION:
params["Engine"] = "oracle-ee"
case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO:
params["Engine"] = "oracle-se2"
default:
return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine)
}
}
i := 1
for k, v := range desc.Tags {
params[fmt.Sprintf("Tags.Tag.%d.Key", i)] = k
params[fmt.Sprintf("Tags.Tag.%d.Value", i)] = v
i++
}
result := struct {
DBInstance SDBInstance `xml:"DBInstance"`
}{}
result.DBInstance.region = self
return &result.DBInstance, self.rdsRequest("CreateDBInstance", params, &result)
}
func (self *SDBInstance) Delete() error {
params := map[string]string{
"DBInstanceIdentifier": self.DBInstanceIdentifier,
"SkipFinalSnapshot": "true",
}
return self.region.rdsRequest("DeleteDBInstance", params, nil)
}
func (self *SRegion) RebootDBInstance(id string) error {
params := map[string]string{
"DBInstanceIdentifier": id,
}
return self.rdsRequest("RebootDBInstance", params, nil)
}
func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error {
oldTags, err := self.region.ListRdsResourceTags(self.DBInstanceArn)
if err != nil {
return errors.Wrapf(err, "ListRdsResourceTags")
}
added, removed := map[string]string{}, map[string]string{}
for k, v := range tags {
oldValue, ok := oldTags[k]
if !ok {
added[k] = v
} else if oldValue != v {
removed[k] = oldValue
added[k] = v
}
}
if replace {
for k, v := range oldTags {
newValue, ok := tags[k]
if !ok {
removed[k] = v
} else if v != newValue {
added[k] = newValue
removed[k] = v
}
}
}
if len(removed) > 0 {
err = self.region.RemoveRdsTagsFromResource(self.DBInstanceArn, removed)
if err != nil {
return errors.Wrapf(err, "RemoveRdsTagsFromResource %s", removed)
}
}
if len(added) > 0 {
return self.region.AddRdsTagsToResource(self.DBInstanceArn, added)
}
return nil
}
func (self *SRegion) ListRdsResourceTags(arn string) (map[string]string, error) {
params := map[string]string{
"ResourceName": arn,
}
tags := multicloud.AwsTags{}
err := self.rdsRequest("ListTagsForResource", params, &tags)
if err != nil {
return nil, errors.Wrapf(err, "ListTagsForResource")
}
return tags.GetTags()
}
func (self *SRegion) AddRdsTagsToResource(arn string, tags map[string]string) error {
if len(tags) == 0 {
return nil
}
params := map[string]string{
"ResourceName": arn,
}
i := 1
for k, v := range tags {
params[fmt.Sprintf("Tags.member.%d.Key", i)] = k
params[fmt.Sprintf("Tags.member.%d.Value", i)] = v
}
return self.rdsRequest("AddTagsToResource", params, nil)
}
func (self *SRegion) RemoveRdsTagsFromResource(arn string, tags map[string]string) error {
if len(tags) == 0 {
return nil
}
params := map[string]string{
"ResourceName": arn,
}
i := 1
for k := range tags {
params[fmt.Sprintf("TagKeys.member.%d", i)] = k
}
return self.rdsRequest("RemoveTagsFromResource", params, nil)
}
+39 -8
View File
@@ -20,6 +20,11 @@ type SDBInstanceSpec struct {
}
var DBInstanceSpecs = map[string]SDBInstanceSpec{
"db.m1.small": {VcpuCount: 1, VmemSizeMb: 1.75 * 1024.0},
"db.m1.medium": {VcpuCount: 1, VmemSizeMb: 3.75 * 1024.0},
"db.m1.large": {VcpuCount: 2, VmemSizeMb: 7.5 * 1024},
"db.m1.xlarge": {VcpuCount: 4, VmemSizeMb: 15 * 1024},
"db.t3.micro": {VcpuCount: 2, VmemSizeMb: 1 * 1024},
"db.t3.small": {VcpuCount: 2, VmemSizeMb: 2 * 1024},
"db.t3.medium": {VcpuCount: 2, VmemSizeMb: 4 * 1024},
@@ -34,6 +39,13 @@ var DBInstanceSpecs = map[string]SDBInstanceSpec{
"db.t2.xlarge": {VcpuCount: 4, VmemSizeMb: 4 * 1024},
"db.t2.2xlarge": {VcpuCount: 8, VmemSizeMb: 8 * 1024},
"db.t4g.micro": {VcpuCount: 2, VmemSizeMb: 1 * 1024},
"db.t4g.small": {VcpuCount: 2, VmemSizeMb: 2 * 1024},
"db.t4g.medium": {VcpuCount: 2, VmemSizeMb: 4 * 1024},
"db.t4g.large": {VcpuCount: 2, VmemSizeMb: 8 * 1024},
"db.t4g.xlarge": {VcpuCount: 4, VmemSizeMb: 16 * 1024},
"db.t4g.2xlarge": {VcpuCount: 8, VmemSizeMb: 32 * 1024},
"db.m6g.large": {VcpuCount: 2, VmemSizeMb: 8 * 1024},
"db.m6g.xlarge": {VcpuCount: 4, VmemSizeMb: 16 * 1024},
"db.m6g.2xlarge": {VcpuCount: 8, VmemSizeMb: 32 * 1024},
@@ -42,14 +54,14 @@ var DBInstanceSpecs = map[string]SDBInstanceSpec{
"db.m6g.12xlarge": {VcpuCount: 48, VmemSizeMb: 192 * 1024},
"db.m6g.16xlarge": {VcpuCount: 64, VmemSizeMb: 256 * 1024},
"db.m5.large": {VcpuCount: 2, VmemSizeMb: 8 * 1024},
"db.m5.xlarge": {VcpuCount: 4, VmemSizeMb: 16 * 1024},
"db.m5.2xlarge": {VcpuCount: 8, VmemSizeMb: 32 * 1024},
"db.m5.4xlarge": {VcpuCount: 16, VmemSizeMb: 64 * 1024},
"db.m5.8xlarge": {VcpuCount: 32, VmemSizeMb: 128 * 1024},
"db.m5.12xlarge4": {VcpuCount: 48, VmemSizeMb: 192 * 1024},
"db.m5.16xlarge2": {VcpuCount: 64, VmemSizeMb: 256 * 1024},
"db.m5.24xlarge8": {VcpuCount: 96, VmemSizeMb: 384 * 1024},
"db.m5.large": {VcpuCount: 2, VmemSizeMb: 8 * 1024},
"db.m5.xlarge": {VcpuCount: 4, VmemSizeMb: 16 * 1024},
"db.m5.2xlarge": {VcpuCount: 8, VmemSizeMb: 32 * 1024},
"db.m5.4xlarge": {VcpuCount: 16, VmemSizeMb: 64 * 1024},
"db.m5.8xlarge": {VcpuCount: 32, VmemSizeMb: 128 * 1024},
"db.m5.12xlarge": {VcpuCount: 48, VmemSizeMb: 192 * 1024},
"db.m5.16xlarge": {VcpuCount: 64, VmemSizeMb: 256 * 1024},
"db.m5.24xlarge": {VcpuCount: 96, VmemSizeMb: 384 * 1024},
"db.m5d.large": {VcpuCount: 2, VmemSizeMb: 8 * 1024},
"db.m5d.xlarge": {VcpuCount: 4, VmemSizeMb: 16 * 1024},
@@ -68,6 +80,16 @@ var DBInstanceSpecs = map[string]SDBInstanceSpec{
"db.r6g.12xlarge": {VcpuCount: 48, VmemSizeMb: 384 * 1024},
"db.r6g.16xlarge": {VcpuCount: 64, VmemSizeMb: 512 * 1024},
"db.r6gd.medium": {VcpuCount: 1, VmemSizeMb: 8 * 1024},
"db.r6gd.large": {VcpuCount: 2, VmemSizeMb: 16 * 1024},
"db.r6gd.xlarge": {VcpuCount: 4, VmemSizeMb: 32 * 1024},
"db.r6gd.2xlarge": {VcpuCount: 8, VmemSizeMb: 64 * 1024},
"db.r6gd.4xlarge": {VcpuCount: 16, VmemSizeMb: 128 * 1024},
"db.r6gd.8xlarge": {VcpuCount: 32, VmemSizeMb: 256 * 1024},
"db.r6gd.12xlarge": {VcpuCount: 48, VmemSizeMb: 383 * 1024},
"db.r6gd.16xlarge": {VcpuCount: 64, VmemSizeMb: 512 * 1024},
"db.r6gd.metal": {VcpuCount: 64, VmemSizeMb: 512 * 1024},
"db.r5.large": {VcpuCount: 2, VmemSizeMb: 16 * 1024},
"db.r5.xlarge": {VcpuCount: 4, VmemSizeMb: 32 * 1024},
"db.r5.2xlarge": {VcpuCount: 8, VmemSizeMb: 64 * 1024},
@@ -149,4 +171,13 @@ var DBInstanceSpecs = map[string]SDBInstanceSpec{
"db.r4.4xlarge": {VcpuCount: 16, VmemSizeMb: 122 * 1024},
"db.r4.8xlarge": {VcpuCount: 32, VmemSizeMb: 244 * 1024},
"db.r4.16xlarge": {VcpuCount: 64, VmemSizeMb: 488 * 1024},
"db.x2g.medium": {VcpuCount: 1, VmemSizeMb: 16 * 1024},
"db.x2g.large": {VcpuCount: 2, VmemSizeMb: 32 * 1024},
"db.x2g.xlarge": {VcpuCount: 4, VmemSizeMb: 64 * 1024},
"db.x2g.2xlarge": {VcpuCount: 8, VmemSizeMb: 128 * 1024},
"db.x2g.4xlarge": {VcpuCount: 16, VmemSizeMb: 256 * 1024},
"db.x2g.8xlarge": {VcpuCount: 32, VmemSizeMb: 512 * 1024},
"db.x2g.12xlarge": {VcpuCount: 48, VmemSizeMb: 768 * 1024},
"db.x2g.16xlarge": {VcpuCount: 64, VmemSizeMb: 1024 * 1024},
}
+57 -8
View File
@@ -17,6 +17,7 @@ package aws
import (
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -55,6 +56,7 @@ type SDBInstanceSnapshot struct {
type SDBInstanceSnapshots struct {
Snapshots []SDBInstanceSnapshot `xml:"DBSnapshots>DBSnapshot"`
Marker string `xml:"Marker"`
}
func (snapshot *SDBInstanceSnapshot) GetId() string {
@@ -104,6 +106,14 @@ func (snapshot *SDBInstanceSnapshot) GetStatus() string {
}
}
func (self *SDBInstanceSnapshot) Refresh() error {
snap, err := self.region.GetRdsSnapshot(self.DBSnapshotIdentifier)
if err != nil {
return err
}
return jsonutils.Update(self, snap)
}
func (snapshot *SDBInstanceSnapshot) GetBackupSizeMb() int {
return snapshot.AllocatedStorage * 1024
}
@@ -116,23 +126,62 @@ func (snapshot *SDBInstanceSnapshot) GetDBInstanceId() string {
return snapshot.DbiResourceId
}
func (region *SRegion) GetDBInstanceSnapshots(instanceId string) ([]SDBInstanceSnapshot, error) {
func (self *SDBInstanceSnapshot) Delete() error {
return self.region.DeleteRdsSnapshot(self.DBSnapshotIdentifier)
}
func (self *SRegion) DeleteRdsSnapshot(id string) error {
params := map[string]string{
"DBSnapshotIdentifier": id,
}
return self.rdsRequest("DeleteDBSnapshot", params, nil)
}
func (region *SRegion) GetDBInstanceSnapshots(instanceId, backupId string) ([]SDBInstanceSnapshot, error) {
params := map[string]string{}
if len(instanceId) > 0 {
params["DbiResourceId"] = instanceId
params["DBInstanceIdentifier"] = instanceId
}
if len(backupId) > 0 {
params["DBSnapshotIdentifier"] = backupId
}
ret, marker := []SDBInstanceSnapshot{}, ""
for {
snapshots := SDBInstanceSnapshots{}
params["Marker"] = marker
err := region.rdsRequest("DescribeDBSnapshots", params, &snapshots)
if err != nil {
return nil, errors.Wrap(err, "DescribeDBSnapshots")
}
ret = append(ret, snapshots.Snapshots...)
if len(snapshots.Marker) == 0 {
break
}
marker = snapshots.Marker
}
return ret, nil
}
snapshots := SDBInstanceSnapshots{}
err := region.rdsRequest("DescribeDBSnapshots", params, &snapshots)
func (self *SRegion) GetRdsSnapshot(id string) (*SDBInstanceSnapshot, error) {
if len(id) == 0 {
return nil, cloudprovider.ErrNotFound
}
backups, err := self.GetDBInstanceSnapshots("", id)
if err != nil {
return nil, errors.Wrap(err, "DescribeDBSnapshots")
return nil, err
}
return snapshots.Snapshots, nil
if len(backups) == 1 {
backups[0].region = self
return &backups[0], nil
}
if len(backups) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
}
func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
snapshots, err := region.GetDBInstanceSnapshots("")
snapshots, err := region.GetDBInstanceSnapshots("", "")
if err != nil {
return nil, errors.Wrap(err, "GetDBInstanceSnapshots")
}
+12 -4
View File
@@ -22,15 +22,14 @@ import (
func init() {
type DBInstanceListOptions struct {
Id string
Offset int
Limit int
Marker string
}
shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List rds intances", func(cli *aws.SRegion, args *DBInstanceListOptions) error {
instances, err := cli.GetDBInstances(args.Id)
instances, _, err := cli.GetDBInstances(args.Id, args.Marker)
if err != nil {
return err
}
printList(instances, 0, args.Offset, args.Limit, []string{})
printList(instances, 0, 0, 0, []string{})
return nil
})
@@ -47,4 +46,13 @@ func init() {
return nil
})
shellutils.R(&DBInstanceIdOptions{}, "dbinstance-tags-list", "Show rds intance tags", func(cli *aws.SRegion, args *DBInstanceIdOptions) error {
instance, err := cli.ListRdsResourceTags(args.ID)
if err != nil {
return err
}
printObject(instance)
return nil
})
}
@@ -22,10 +22,11 @@ import (
func init() {
type DBInstanceSnapshotListOptions struct {
DBInstanceId string
Id string
}
shellutils.R(&DBInstanceSnapshotListOptions{}, "dbinstance-snapshot-list", "List rds intance snapshots", func(cli *aws.SRegion, args *DBInstanceSnapshotListOptions) error {
snapshots, err := cli.GetDBInstanceSnapshots(args.DBInstanceId)
snapshots, err := cli.GetDBInstanceSnapshots(args.DBInstanceId, args.Id)
if err != nil {
return err
}
+13
View File
@@ -233,8 +233,15 @@ type SAwsTag struct {
Value string `xml:"value"`
}
type SAwsRdsTag struct {
Key string `xml:"Key"`
Value string `xml:"Value"`
}
type AwsTags struct {
TagSet []SAwsTag `xml:"tagSet>item"`
// rds
TagList []SAwsRdsTag `xml:"TagList>Tag"`
}
func (self AwsTags) GetName() string {
@@ -254,6 +261,12 @@ func (self *AwsTags) GetTags() (map[string]string, error) {
}
ret[tag.Key] = tag.Value
}
for _, tag := range self.TagList {
if strings.ToLower(tag.Key) == "name" || strings.ToLower(tag.Key) == "description" {
continue
}
ret[tag.Key] = tag.Value
}
return ret, nil
}