dbinstances.go 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "net"
  20. "strings"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/tristate"
  27. "yunion.io/x/pkg/util/billing"
  28. "yunion.io/x/pkg/util/compare"
  29. "yunion.io/x/pkg/util/netutils"
  30. "yunion.io/x/pkg/util/rbacscope"
  31. "yunion.io/x/pkg/utils"
  32. "yunion.io/x/sqlchemy"
  33. "yunion.io/x/onecloud/pkg/apis"
  34. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  35. api "yunion.io/x/onecloud/pkg/apis/compute"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  39. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  40. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  41. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  42. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  43. "yunion.io/x/onecloud/pkg/compute/options"
  44. "yunion.io/x/onecloud/pkg/httperrors"
  45. "yunion.io/x/onecloud/pkg/mcclient"
  46. "yunion.io/x/onecloud/pkg/util/logclient"
  47. "yunion.io/x/onecloud/pkg/util/rbacutils"
  48. "yunion.io/x/onecloud/pkg/util/seclib2"
  49. "yunion.io/x/onecloud/pkg/util/stringutils2"
  50. )
  51. // +onecloud:swagger-gen-model-singular=dbinstance
  52. // +onecloud:swagger-gen-model-plural=dbinstances
  53. type SDBInstanceManager struct {
  54. db.SVirtualResourceBaseManager
  55. db.SExternalizedResourceBaseManager
  56. SDeletePreventableResourceBaseManager
  57. SCloudregionResourceBaseManager
  58. SManagedResourceBaseManager
  59. SVpcResourceBaseManager
  60. }
  61. var DBInstanceManager *SDBInstanceManager
  62. func init() {
  63. DBInstanceManager = &SDBInstanceManager{
  64. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  65. SDBInstance{},
  66. "dbinstances_tbl",
  67. "dbinstance",
  68. "dbinstances",
  69. ),
  70. }
  71. DBInstanceManager.SetVirtualObject(DBInstanceManager)
  72. notifyclient.AddNotifyDBHookResources(DBInstanceManager.KeywordPlural())
  73. }
  74. type SDBInstance struct {
  75. db.SVirtualResourceBase
  76. db.SExternalizedResourceBase
  77. SManagedResourceBase
  78. SBillingResourceBase
  79. SCloudregionResourceBase
  80. SDeletePreventableResourceBase
  81. // 主实例Id
  82. MasterInstanceId string `width:"128" charset:"ascii" list:"user" create:"optional"`
  83. // CPU数量
  84. // example: 1
  85. VcpuCount int `nullable:"false" default:"1" list:"user" create:"optional"`
  86. // 内存大小
  87. // example: 1024
  88. VmemSizeMb int `nullable:"false" list:"user" create:"required"`
  89. // 存储类型
  90. // example: local_ssd
  91. StorageType string `nullable:"false" list:"user" create:"required"`
  92. // 存储大小
  93. // example: 10240
  94. DiskSizeGB int `nullable:"false" list:"user" create:"required"`
  95. // 已使用的存储大小
  96. DiskSizeUsedMB int `nullable:"false" list:"user"`
  97. // 端口
  98. // example: 3306
  99. Port int `nullable:"false" list:"user" create:"optional"`
  100. // 实例类型
  101. // example: ha
  102. Category string `nullable:"false" list:"user" create:"optional"`
  103. // 最大连接数
  104. Iops int `nullable:"true" list:"user" create:"optional"`
  105. // 引擎
  106. // example: MySQL
  107. Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"`
  108. // 引擎版本
  109. // example: 5.7
  110. EngineVersion string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"required"`
  111. // 套餐名称
  112. // example: mysql.x4.large.2c
  113. InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"`
  114. // 维护时间
  115. MaintainTime string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  116. // 虚拟私有网络Id
  117. // example: ed20d84e-3158-41b1-870c-1725e412e8b6
  118. VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
  119. // 外部连接地址
  120. ConnectionStr string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  121. // 内部连接地址
  122. InternalConnectionStr string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  123. // 可用区1
  124. Zone1 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
  125. // 可用区2
  126. Zone2 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
  127. // 可用区3
  128. Zone3 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
  129. // 从备份创建新实例
  130. DBInstancebackupId string `width:"36" name:"dbinstancebackup_id" charset:"ascii" nullable:"false" create:"optional"`
  131. }
  132. func (manager *SDBInstanceManager) GetContextManagers() [][]db.IModelManager {
  133. return [][]db.IModelManager{
  134. {CloudregionManager},
  135. }
  136. }
  137. // RDS实例列表
  138. func (man *SDBInstanceManager) ListItemFilter(
  139. ctx context.Context,
  140. q *sqlchemy.SQuery,
  141. userCred mcclient.TokenCredential,
  142. query api.DBInstanceListInput,
  143. ) (*sqlchemy.SQuery, error) {
  144. var err error
  145. q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
  146. if err != nil {
  147. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
  148. }
  149. q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  150. if err != nil {
  151. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  152. }
  153. q, err = man.SDeletePreventableResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DeletePreventableResourceBaseListInput)
  154. if err != nil {
  155. return nil, errors.Wrap(err, "SDeletePreventableResourceBaseManager.ListItemFilter")
  156. }
  157. q, err = man.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  158. if err != nil {
  159. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  160. }
  161. q, err = man.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
  162. if err != nil {
  163. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  164. }
  165. q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
  166. if err != nil {
  167. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
  168. }
  169. if len(query.SecgroupId) > 0 {
  170. _, err = validators.ValidateModel(ctx, userCred, SecurityGroupManager, &query.SecgroupId)
  171. if err != nil {
  172. return nil, err
  173. }
  174. sq := DBInstanceSecgroupManager.Query("dbinstance_id").Equals("secgroup_id", query.SecgroupId)
  175. q = q.In("id", sq.SubQuery())
  176. }
  177. if len(query.ZoneId) > 0 {
  178. zoneObj, err := ZoneManager.FetchByIdOrName(ctx, userCred, query.ZoneId)
  179. if err != nil {
  180. if errors.Cause(err) == sql.ErrNoRows {
  181. return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), query.ZoneId)
  182. } else {
  183. return nil, errors.Wrap(err, "ZoneManager.FetchByIdOrName")
  184. }
  185. }
  186. q = q.Filter(sqlchemy.OR(
  187. sqlchemy.Equals(q.Field("zone1"), zoneObj.GetId()),
  188. sqlchemy.Equals(q.Field("zone2"), zoneObj.GetId()),
  189. sqlchemy.Equals(q.Field("zone3"), zoneObj.GetId()),
  190. ))
  191. }
  192. if len(query.MasterInstance) > 0 {
  193. instObj, err := DBInstanceManager.FetchByIdOrName(ctx, userCred, query.MasterInstance)
  194. if err != nil {
  195. if errors.Cause(err) == sql.ErrNoRows {
  196. return nil, httperrors.NewResourceNotFoundError2(DBInstanceManager.Keyword(), query.MasterInstance)
  197. } else {
  198. return nil, errors.Wrap(err, "DBInstanceManager.FetchByIdOrName")
  199. }
  200. }
  201. q = q.Equals("master_instance_id", instObj.GetId())
  202. }
  203. if query.VcpuCount > 0 {
  204. q = q.Equals("vcpu_count", query.VcpuCount)
  205. }
  206. if query.VmemSizeMb > 0 {
  207. q = q.Equals("vmem_size_mb", query.VmemSizeMb)
  208. }
  209. if len(query.StorageType) > 0 {
  210. q = q.Equals("storage_type", query.StorageType)
  211. }
  212. if len(query.Category) > 0 {
  213. q = q.Equals("category", query.Category)
  214. }
  215. if len(query.Engine) > 0 {
  216. q = q.Equals("engine", query.Engine)
  217. }
  218. if len(query.EngineVersion) > 0 {
  219. q = q.Equals("engine_version", query.EngineVersion)
  220. }
  221. if len(query.InstanceType) > 0 {
  222. q = q.Equals("instance_type", query.InstanceType)
  223. }
  224. if len(query.IpAddr) > 0 {
  225. dn := DBInstanceNetworkManager.Query("dbinstance_id")
  226. conditions := []sqlchemy.ICondition{}
  227. for _, ipAddr := range query.IpAddr {
  228. if len(ipAddr) == 0 {
  229. continue
  230. }
  231. condition := sqlchemy.Contains(dn.Field("ip_addr"), ipAddr)
  232. conditions = append(conditions, condition)
  233. }
  234. if len(conditions) > 0 {
  235. dn = dn.Filter(sqlchemy.OR(conditions...))
  236. }
  237. q = q.Filter(sqlchemy.In(q.Field("id"), dn.SubQuery()))
  238. }
  239. return q, nil
  240. }
  241. func (man *SDBInstanceManager) OrderByExtraFields(
  242. ctx context.Context,
  243. q *sqlchemy.SQuery,
  244. userCred mcclient.TokenCredential,
  245. query api.DBInstanceListInput,
  246. ) (*sqlchemy.SQuery, error) {
  247. q, err := man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
  248. if err != nil {
  249. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
  250. }
  251. q, err = man.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
  252. if err != nil {
  253. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
  254. }
  255. q, err = man.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  256. if err != nil {
  257. return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
  258. }
  259. q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
  260. if err != nil {
  261. return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
  262. }
  263. return q, nil
  264. }
  265. func (man *SDBInstanceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  266. q, err := man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  267. if err == nil {
  268. return q, nil
  269. }
  270. q, err = man.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
  271. if err == nil {
  272. return q, nil
  273. }
  274. q, err = man.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  275. if err == nil {
  276. return q, nil
  277. }
  278. q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  279. if err == nil {
  280. return q, nil
  281. }
  282. return q, httperrors.ErrNotFound
  283. }
  284. func (manager *SDBInstanceManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  285. var err error
  286. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  287. if err == nil {
  288. return q, nil
  289. }
  290. return q, httperrors.ErrNotFound
  291. }
  292. func (manager *SDBInstanceManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (api.DBInstanceCreateInput, error) {
  293. var err error
  294. input, err = manager.ValidateCreateData(ctx, userCred, ownerId, query, input)
  295. if err != nil {
  296. return input, errors.Wrapf(err, "ValidateCreateData")
  297. }
  298. return input, nil
  299. }
  300. func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (api.DBInstanceCreateInput, error) {
  301. if len(input.DBInstancebackupId) > 0 {
  302. _backup, err := validators.ValidateModel(ctx, userCred, DBInstanceBackupManager, &input.DBInstancebackupId)
  303. if err != nil {
  304. return input, err
  305. }
  306. backup := _backup.(*SDBInstanceBackup)
  307. err = backup.fillRdsConfig(&input)
  308. if err != nil {
  309. return input, err
  310. }
  311. }
  312. for _, v := range map[string]*string{"zone1": &input.Zone1, "zone2": &input.Zone2, "zone3": &input.Zone3} {
  313. if len(*v) > 0 {
  314. _, err := validators.ValidateModel(ctx, userCred, ZoneManager, v)
  315. if err != nil {
  316. return input, err
  317. }
  318. }
  319. }
  320. if len(input.Password) > 0 {
  321. err := seclib2.ValidatePassword(input.Password)
  322. if err != nil {
  323. return input, err
  324. }
  325. }
  326. var vpc *SVpc
  327. var network *SNetwork
  328. if len(input.NetworkId) > 0 {
  329. _network, err := validators.ValidateModel(ctx, userCred, NetworkManager, &input.NetworkId)
  330. if err != nil {
  331. return input, err
  332. }
  333. network = _network.(*SNetwork)
  334. if len(input.Address) > 0 {
  335. ip := net.ParseIP(input.Address).To4()
  336. if ip == nil {
  337. return input, httperrors.NewInputParameterError("invalid address: %s", input.Address)
  338. }
  339. addr, _ := netutils.NewIPV4Addr(input.Address)
  340. if !network.IsAddressInRange(addr) {
  341. return input, httperrors.NewInputParameterError("Ip %s not in network %s(%s) range", input.Address, network.Name, network.Id)
  342. }
  343. }
  344. vpc, _ = network.GetVpc()
  345. } else if len(input.VpcId) > 0 {
  346. _vpc, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcId)
  347. if err != nil {
  348. return input, err
  349. }
  350. vpc = _vpc.(*SVpc)
  351. } else {
  352. return input, httperrors.NewMissingParameterError("vpc_id")
  353. }
  354. input.VpcId = vpc.Id
  355. input.ManagerId = vpc.ManagerId
  356. cloudprovider := vpc.GetCloudprovider()
  357. if cloudprovider == nil {
  358. return input, httperrors.NewGeneralError(fmt.Errorf("failed to get vpc %s(%s) cloudprovider", vpc.Name, vpc.Id))
  359. }
  360. if !cloudprovider.IsAvailable() {
  361. return input, httperrors.NewInputParameterError("cloudprovider %s(%s) is not available", cloudprovider.Name, cloudprovider.Id)
  362. }
  363. region, err := vpc.GetRegion()
  364. if err != nil {
  365. return input, err
  366. }
  367. input.CloudregionId = region.Id
  368. if len(input.Duration) > 0 {
  369. billingCycle, err := billing.ParseBillingCycle(input.Duration)
  370. if err != nil {
  371. return input, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
  372. }
  373. if !utils.IsInStringArray(string(input.BillingType), []string{string(billing_api.BILLING_TYPE_PREPAID), string(billing_api.BILLING_TYPE_POSTPAID)}) {
  374. input.BillingType = billing_api.BILLING_TYPE_PREPAID
  375. }
  376. if input.BillingType == billing_api.BILLING_TYPE_PREPAID {
  377. if !region.GetDriver().IsSupportedBillingCycle(billingCycle, man.KeywordPlural()) {
  378. return input, httperrors.NewInputParameterError("unsupported duration %s", input.Duration)
  379. }
  380. }
  381. input.BillingCycle = billingCycle.String()
  382. if input.BillingType == billing_api.BILLING_TYPE_POSTPAID {
  383. input.ReleaseAt = billingCycle.EndAt(time.Now())
  384. }
  385. }
  386. for k, v := range map[string]string{
  387. "engine": input.Engine,
  388. "engine_version": input.EngineVersion,
  389. "category": input.Category,
  390. "storage_type": input.StorageType,
  391. } {
  392. if len(v) == 0 {
  393. return input, httperrors.NewMissingParameterError(k)
  394. }
  395. }
  396. info := getDBInstanceInfo(region, nil)
  397. if info == nil {
  398. return input, httperrors.NewNotSupportedError("cloudregion %s not support create rds", region.Name)
  399. }
  400. versionsInfo, ok := info[input.Engine]
  401. if !ok {
  402. return input, httperrors.NewNotSupportedError("cloudregion %s not support create %s rds", region.Name, input.Engine)
  403. }
  404. categoryInfo, ok := versionsInfo[input.EngineVersion]
  405. if !ok {
  406. return input, httperrors.NewNotSupportedError("cloudregion %s not support create %s rds", region.Name, input.EngineVersion)
  407. }
  408. storageInfo, ok := categoryInfo[input.Category]
  409. if !ok {
  410. return input, httperrors.NewNotSupportedError("cloudregion %s not support create %s rds", region.Name, input.Category)
  411. }
  412. if !utils.IsInStringArray(input.StorageType, storageInfo) {
  413. return input, httperrors.NewNotSupportedError("cloudregion %s not support create %s rds", region.Name, input.StorageType)
  414. }
  415. if len(input.InstanceType) == 0 && (input.VcpuCount == 0 || input.VmemSizeMb == 0) {
  416. return input, httperrors.NewMissingParameterError("Missing instance_type or vcpu_count, vmem_size_mb parameters")
  417. }
  418. instance := SDBInstance{}
  419. jsonutils.Update(&instance, input)
  420. skus, err := instance.GetAvailableDBInstanceSkus(false)
  421. if err != nil {
  422. return input, httperrors.NewGeneralError(err)
  423. }
  424. if len(skus) == 0 {
  425. return input, httperrors.NewInputParameterError("not match any dbinstance sku")
  426. }
  427. if len(input.InstanceType) > 0 { //设置下cpu和内存的大小
  428. input.VcpuCount = skus[0].VcpuCount
  429. input.VmemSizeMb = skus[0].VmemSizeMb
  430. }
  431. input.VirtualResourceCreateInput, err = man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  432. if err != nil {
  433. return input, err
  434. }
  435. driver := region.GetDriver()
  436. secCount := driver.GetRdsSupportSecgroupCount()
  437. if secCount == 0 && len(input.SecgroupIds) > 0 {
  438. return input, httperrors.NewNotSupportedError("%s rds not support secgroup", driver.GetProvider())
  439. }
  440. if len(input.SecgroupIds) > secCount {
  441. return input, httperrors.NewNotSupportedError("%s rds Support up to %d security groups", driver.GetProvider(), secCount)
  442. }
  443. for i := range input.SecgroupIds {
  444. _, err := validators.ValidateModel(ctx, userCred, SecurityGroupManager, &input.SecgroupIds[i])
  445. if err != nil {
  446. return input, err
  447. }
  448. }
  449. input, err = driver.ValidateCreateDBInstanceData(ctx, userCred, ownerId, input, skus, network)
  450. if err != nil {
  451. return input, err
  452. }
  453. quotaKeys := fetchRegionalQuotaKeys(rbacscope.ScopeProject, ownerId, region, cloudprovider)
  454. pendingUsage := SRegionQuota{Rds: 1}
  455. pendingUsage.SetKeys(quotaKeys)
  456. if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
  457. return input, httperrors.NewOutOfQuotaError("%s", err)
  458. }
  459. return input, nil
  460. }
  461. func (self *SDBInstance) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  462. self.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  463. pendingUsage := SRegionQuota{Rds: 1}
  464. pendingUsage.SetKeys(self.GetQuotaKeys())
  465. err := quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  466. if err != nil {
  467. log.Errorf("CancelPendingUsage error %s", err)
  468. }
  469. input := api.DBInstanceCreateInput{}
  470. data.Unmarshal(&input)
  471. if len(input.NetworkId) > 0 {
  472. err := DBInstanceNetworkManager.newNetwork(ctx, userCred, self.Id, input.NetworkId, input.Address)
  473. if err != nil {
  474. log.Errorf("DBInstanceNetworkManager.Insert")
  475. }
  476. }
  477. ids := []string{}
  478. for _, secgroupId := range input.SecgroupIds {
  479. if !utils.IsInStringArray(secgroupId, ids) {
  480. err := self.assignSecgroup(ctx, userCred, secgroupId)
  481. if err != nil {
  482. log.Errorf("assignSecgroup")
  483. }
  484. ids = append(ids, secgroupId)
  485. }
  486. }
  487. self.StartDBInstanceCreateTask(ctx, userCred, jsonutils.Marshal(input))
  488. }
  489. func (self *SDBInstance) StartDBInstanceCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
  490. params := data.(*jsonutils.JSONDict)
  491. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceCreateTask", self, userCred, params, "", "", nil)
  492. if err != nil {
  493. return errors.Wrapf(err, "NewTask")
  494. }
  495. self.SetStatus(ctx, userCred, api.DBINSTANCE_DEPLOYING, "")
  496. task.ScheduleRun(nil)
  497. return nil
  498. }
  499. func (manager *SDBInstanceManager) FetchCustomizeColumns(
  500. ctx context.Context,
  501. userCred mcclient.TokenCredential,
  502. query jsonutils.JSONObject,
  503. objs []interface{},
  504. fields stringutils2.SSortedStrings,
  505. isList bool,
  506. ) []api.DBInstanceDetails {
  507. rows := make([]api.DBInstanceDetails, len(objs))
  508. virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  509. manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  510. regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  511. rdsIds := make([]string, len(rows))
  512. vpcIds := make([]string, len(rows))
  513. zone1Ids := make([]string, len(rows))
  514. zone2Ids := make([]string, len(rows))
  515. zone3Ids := make([]string, len(rows))
  516. for i := range rows {
  517. rows[i] = api.DBInstanceDetails{
  518. VirtualResourceDetails: virtRows[i],
  519. ManagedResourceInfo: manRows[i],
  520. CloudregionResourceInfo: regRows[i],
  521. }
  522. instance := objs[i].(*SDBInstance)
  523. rdsIds[i] = instance.Id
  524. vpcIds[i] = instance.VpcId
  525. zone1Ids[i] = instance.Zone1
  526. zone2Ids[i] = instance.Zone2
  527. zone3Ids[i] = instance.Zone3
  528. }
  529. vpcs := make(map[string]SVpc)
  530. err := db.FetchStandaloneObjectsByIds(VpcManager, vpcIds, &vpcs)
  531. if err != nil {
  532. log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err)
  533. return rows
  534. }
  535. for i := range rows {
  536. if vpc, ok := vpcs[vpcIds[i]]; ok {
  537. rows[i].Vpc = vpc.Name
  538. rows[i].VpcExtId = vpc.ExternalId
  539. }
  540. }
  541. q := SecurityGroupManager.Query()
  542. ownerId, queryScope, err, _ := db.FetchCheckQueryOwnerScope(ctx, userCred, query, SecurityGroupManager, policy.PolicyActionList, true)
  543. if err != nil {
  544. log.Errorf("FetchCheckQueryOwnerScope error: %v", err)
  545. return rows
  546. }
  547. secgroups := SecurityGroupManager.FilterByOwner(ctx, q, SecurityGroupManager, userCred, ownerId, queryScope).SubQuery()
  548. rdssecgroups := DBInstanceSecgroupManager.Query().SubQuery()
  549. secQ := rdssecgroups.Query(rdssecgroups.Field("dbinstance_id"), rdssecgroups.Field("secgroup_id"), secgroups.Field("name").Label("secgroup_name")).Join(secgroups, sqlchemy.Equals(rdssecgroups.Field("secgroup_id"), secgroups.Field("id"))).Filter(sqlchemy.In(rdssecgroups.Field("dbinstance_id"), rdsIds))
  550. type sRdsSecgroupInfo struct {
  551. DBInstanceId string `json:"dbinstance_id"`
  552. SecgroupName string
  553. SecgroupId string
  554. }
  555. rsgs := []sRdsSecgroupInfo{}
  556. err = secQ.All(&rsgs)
  557. if err != nil {
  558. log.Errorf("secQ.All error: %v", err)
  559. return rows
  560. }
  561. ret := make(map[string][]apis.StandaloneShortDesc)
  562. for i := range rsgs {
  563. rsg, ok := ret[rsgs[i].DBInstanceId]
  564. if !ok {
  565. rsg = make([]apis.StandaloneShortDesc, 0)
  566. }
  567. rsg = append(rsg, apis.StandaloneShortDesc{
  568. Id: rsgs[i].SecgroupId,
  569. Name: rsgs[i].SecgroupName,
  570. })
  571. ret[rsgs[i].DBInstanceId] = rsg
  572. }
  573. zone1, err := db.FetchIdNameMap2(ZoneManager, zone1Ids)
  574. if err != nil {
  575. return rows
  576. }
  577. zone2, err := db.FetchIdNameMap2(ZoneManager, zone2Ids)
  578. if err != nil {
  579. return rows
  580. }
  581. zone3, err := db.FetchIdNameMap2(ZoneManager, zone3Ids)
  582. if err != nil {
  583. return rows
  584. }
  585. networks := NetworkManager.Query().SubQuery()
  586. rdsnetworks := DBInstanceNetworkManager.Query().SubQuery()
  587. nQ := rdsnetworks.Query(
  588. rdsnetworks.Field("dbinstance_id"),
  589. rdsnetworks.Field("network_id"),
  590. rdsnetworks.Field("ip_addr"),
  591. networks.Field("name").Label("network_name"),
  592. ).Join(networks, sqlchemy.Equals(rdsnetworks.Field("network_id"), networks.Field("id"))).
  593. Filter(sqlchemy.In(rdsnetworks.Field("dbinstance_id"), rdsIds))
  594. type sRdsNetworkInfo struct {
  595. DBInstanceId string `json:"dbinstance_id"`
  596. NetworkName string
  597. NetworkId string
  598. IpAddr string
  599. }
  600. rns := []sRdsNetworkInfo{}
  601. err = nQ.All(&rns)
  602. if err != nil {
  603. return rows
  604. }
  605. rdsNetworks := map[string][]string{}
  606. rdsIpAddrs := map[string][]string{}
  607. for i := range rns {
  608. _, ok := rdsNetworks[rns[i].DBInstanceId]
  609. if !ok {
  610. rdsNetworks[rns[i].DBInstanceId] = []string{}
  611. }
  612. rdsNetworks[rns[i].DBInstanceId] = append(rdsNetworks[rns[i].DBInstanceId], rns[i].NetworkName)
  613. _, ok = rdsIpAddrs[rns[i].DBInstanceId]
  614. if !ok {
  615. rdsIpAddrs[rns[i].DBInstanceId] = []string{}
  616. }
  617. rdsIpAddrs[rns[i].DBInstanceId] = append(rdsIpAddrs[rns[i].DBInstanceId], rns[i].IpAddr)
  618. }
  619. for i := range rows {
  620. rows[i].Zone1Name = zone1[zone1Ids[i]]
  621. rows[i].Zone2Name = zone2[zone2Ids[i]]
  622. rows[i].Zone3Name = zone3[zone3Ids[i]]
  623. rows[i].Secgroups, _ = ret[rdsIds[i]]
  624. networks, ok := rdsNetworks[rdsIds[i]]
  625. if ok {
  626. rows[i].Network = strings.Join(networks, ",")
  627. }
  628. ipAddrs, ok := rdsIpAddrs[rdsIds[i]]
  629. if ok {
  630. rows[i].IpAddrs = strings.Join(ipAddrs, ",")
  631. }
  632. }
  633. q = DBInstanceDatabaseManager.Query().In("dbinstance_id", rdsIds)
  634. databases := []SDBInstanceDatabase{}
  635. err = db.FetchModelObjects(DBInstanceDatabaseManager, q, &databases)
  636. if err != nil {
  637. return rows
  638. }
  639. databaseMap := map[string][]apis.IdNameDetails{}
  640. for i := range databases {
  641. _, ok := databaseMap[databases[i].DBInstanceId]
  642. if !ok {
  643. databaseMap[databases[i].DBInstanceId] = []apis.IdNameDetails{}
  644. }
  645. databaseMap[databases[i].DBInstanceId] = append(databaseMap[databases[i].DBInstanceId], apis.IdNameDetails{
  646. Id: databases[i].Id,
  647. Name: databases[i].Name,
  648. })
  649. }
  650. for i := range rows {
  651. rows[i].Databases, _ = databaseMap[rdsIds[i]]
  652. }
  653. return rows
  654. }
  655. func (self *SDBInstance) GetVpc() (*SVpc, error) {
  656. vpc, err := VpcManager.FetchById(self.VpcId)
  657. if err != nil {
  658. return nil, err
  659. }
  660. return vpc.(*SVpc), nil
  661. }
  662. type sDBInstanceZone struct {
  663. Id string
  664. Name string
  665. }
  666. func fetchDBInstanceZones(rdsIds []string) map[string][]sDBInstanceZone {
  667. instances := DBInstanceManager.Query().SubQuery()
  668. zones := ZoneManager.Query().SubQuery()
  669. result := map[string][]sDBInstanceZone{}
  670. for _, zone := range []string{"zone1", "zone2", "zone3"} {
  671. zoneInfo := []struct {
  672. InstanceId string
  673. Id string
  674. Name string
  675. }{}
  676. q := zones.Query(instances.Field("id").Label("instance_id"), zones.Field("id"), zones.Field("name"))
  677. q = q.Join(instances, sqlchemy.Equals(zones.Field("id"), instances.Field(zone)))
  678. q = q.Filter(sqlchemy.In(instances.Field("id"), rdsIds))
  679. q = q.Filter(sqlchemy.NOT(sqlchemy.IsNullOrEmpty(instances.Field(zone))))
  680. err := q.All(&zoneInfo)
  681. if err != nil {
  682. return nil
  683. }
  684. for _, _zone := range zoneInfo {
  685. if _, ok := result[_zone.InstanceId]; !ok {
  686. result[_zone.InstanceId] = []sDBInstanceZone{}
  687. }
  688. result[_zone.InstanceId] = append(result[_zone.InstanceId], sDBInstanceZone{
  689. Id: fmt.Sprintf("%s_name", zone),
  690. Name: _zone.Name,
  691. })
  692. }
  693. }
  694. return result
  695. }
  696. func (self *SDBInstance) getSecgroupsByExternalIds(externalIds []string) ([]SSecurityGroup, error) {
  697. q := SecurityGroupManager.Query().In("external_id", externalIds).Equals("manager_id", self.ManagerId)
  698. secgroups := []SSecurityGroup{}
  699. err := db.FetchModelObjects(SecurityGroupManager, q, &secgroups)
  700. if err != nil {
  701. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  702. }
  703. return secgroups, nil
  704. }
  705. func (self *SDBInstance) GetSecgroups() ([]SSecurityGroup, error) {
  706. sq := DBInstanceSecgroupManager.Query("secgroup_id").Equals("dbinstance_id", self.Id).SubQuery()
  707. q := SecurityGroupManager.Query().In("id", sq)
  708. secgroups := []SSecurityGroup{}
  709. err := db.FetchModelObjects(SecurityGroupManager, q, &secgroups)
  710. if err != nil {
  711. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  712. }
  713. return secgroups, nil
  714. }
  715. func (self *SDBInstance) GetDBInstanceSecgroups() ([]SDBInstanceSecgroup, error) {
  716. q := DBInstanceSecgroupManager.Query().Equals("dbinstance_id", self.Id)
  717. secgroups := []SDBInstanceSecgroup{}
  718. err := db.FetchModelObjects(DBInstanceSecgroupManager, q, &secgroups)
  719. if err != nil {
  720. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  721. }
  722. return secgroups, nil
  723. }
  724. func (self *SDBInstance) RevokeSecgroup(ctx context.Context, userCred mcclient.TokenCredential, id string) error {
  725. secgroups, err := self.GetDBInstanceSecgroups()
  726. if err != nil {
  727. return errors.Wrapf(err, "GetDBInstanceSecgroups")
  728. }
  729. for i := range secgroups {
  730. if secgroups[i].SecgroupId == id {
  731. err = secgroups[i].Detach(ctx, userCred)
  732. if err != nil {
  733. return errors.Wrapf(err, "secgroups.Detach %d", secgroups[i].RowId)
  734. }
  735. }
  736. }
  737. return nil
  738. }
  739. func (self *SDBInstance) AssignSecgroup(ctx context.Context, userCred mcclient.TokenCredential, id string) error {
  740. secgroups, err := self.GetDBInstanceSecgroups()
  741. if err != nil {
  742. return errors.Wrapf(err, "GetDBInstanceSecgroups")
  743. }
  744. for i := range secgroups {
  745. if secgroups[i].SecgroupId == id {
  746. return fmt.Errorf("secgroup %s already assign rds %s(%s)", id, self.Name, self.Id)
  747. }
  748. }
  749. return self.assignSecgroup(ctx, userCred, id)
  750. }
  751. func (self *SDBInstance) assignSecgroup(ctx context.Context, userCred mcclient.TokenCredential, id string) error {
  752. ds := &SDBInstanceSecgroup{}
  753. ds.DBInstanceId = self.Id
  754. ds.SecgroupId = id
  755. ds.SetModelManager(DBInstanceSecgroupManager, ds)
  756. return DBInstanceSecgroupManager.TableSpec().Insert(ctx, ds)
  757. }
  758. func (self *SDBInstance) GetMasterInstance() (*SDBInstance, error) {
  759. instance, err := DBInstanceManager.FetchById(self.MasterInstanceId)
  760. if err != nil {
  761. return nil, err
  762. }
  763. return instance.(*SDBInstance), nil
  764. }
  765. func (self *SDBInstance) GetIDBInstance(ctx context.Context) (cloudprovider.ICloudDBInstance, error) {
  766. if len(self.ExternalId) == 0 {
  767. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  768. }
  769. iregion, err := self.GetIRegion(ctx)
  770. if err != nil {
  771. return nil, errors.Wrap(err, "self.GetIRegion")
  772. }
  773. iRds, err := iregion.GetIDBInstanceById(self.ExternalId)
  774. if err != nil {
  775. return nil, errors.Wrapf(err, "GetIDBInstanceById(%s)", self.ExternalId)
  776. }
  777. return iRds, nil
  778. }
  779. func (self *SDBInstance) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
  780. backups, err := self.GetDBInstanceBackups()
  781. if err != nil {
  782. return nil, httperrors.NewGeneralError(fmt.Errorf("failed get backups: %v", err))
  783. }
  784. for i := range backups {
  785. _, err := backups[i].PerformChangeOwner(ctx, userCred, query, input)
  786. if err != nil {
  787. return nil, err
  788. }
  789. }
  790. return self.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input)
  791. }
  792. func (self *SDBInstance) PerformRecovery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SDBInstanceRecoveryConfigInput) (jsonutils.JSONObject, error) {
  793. if !utils.IsInStringArray(self.Status, []string{api.DBINSTANCE_RUNNING}) {
  794. return nil, httperrors.NewInvalidStatusError("Cannot do recovery dbinstance in status %s required status %s", self.Status, api.DBINSTANCE_RUNNING)
  795. }
  796. _backup, err := DBInstanceBackupManager.FetchByIdOrName(ctx, userCred, input.DBInstancebackupId)
  797. if err != nil {
  798. if errors.Cause(err) == sql.ErrNoRows {
  799. return nil, httperrors.NewResourceNotFoundError2("dbinstancebackup", input.DBInstancebackupId)
  800. }
  801. return nil, httperrors.NewGeneralError(err)
  802. }
  803. input.DBInstancebackupId = _backup.GetId()
  804. databases, err := self.GetDBInstanceDatabases()
  805. if err != nil {
  806. return nil, err
  807. }
  808. dbDatabases := []string{}
  809. for _, database := range databases {
  810. dbDatabases = append(dbDatabases, database.Name)
  811. }
  812. backup := _backup.(*SDBInstanceBackup)
  813. for src, dest := range input.Databases {
  814. if len(dest) == 0 {
  815. dest = src
  816. }
  817. if strings.Index(backup.DBNames, src) < 0 {
  818. return nil, httperrors.NewInputParameterError("backup %s(%s) not contain database %s", backup.Name, backup.Id, src)
  819. }
  820. if utils.IsInStringArray(dest, dbDatabases) {
  821. return nil, httperrors.NewConflictError("conflict database %s for instance %s(%s)", dest, self.Name, self.Id)
  822. }
  823. input.Databases[src] = dest
  824. }
  825. if backup.ManagerId != self.ManagerId {
  826. return nil, httperrors.NewInputParameterError("back and instance not in same cloudaccount")
  827. }
  828. if backup.CloudregionId != self.CloudregionId {
  829. return nil, httperrors.NewInputParameterError("backup and instance not in same cloudregion")
  830. }
  831. if len(backup.Engine) > 0 && backup.Engine != self.Engine {
  832. return nil, httperrors.NewInputParameterError("can not recover data from diff rds engine")
  833. }
  834. driver, err := self.GetRegionDriver()
  835. if err != nil {
  836. return nil, httperrors.NewGeneralError(err)
  837. }
  838. err = driver.ValidateDBInstanceRecovery(ctx, userCred, self, backup, input)
  839. if err != nil {
  840. return nil, err
  841. }
  842. return nil, self.StartDBInstanceRecoveryTask(ctx, userCred, input.JSON(input), "")
  843. }
  844. func (self *SDBInstance) StartDBInstanceRecoveryTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  845. self.SetStatus(ctx, userCred, api.DBINSTANCE_RESTORING, "")
  846. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceRecoveryTask", self, userCred, params, parentTaskId, "", nil)
  847. if err != nil {
  848. return err
  849. }
  850. task.ScheduleRun(nil)
  851. return nil
  852. }
  853. func (self *SDBInstance) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  854. params := jsonutils.NewDict()
  855. params.Set("purge", jsonutils.JSONTrue)
  856. return nil, self.StartDBInstanceDeleteTask(ctx, userCred, params, "")
  857. }
  858. func (self *SDBInstance) PerformReboot(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  859. if !utils.IsInStringArray(self.Status, []string{api.DBINSTANCE_RUNNING, api.DBINSTANCE_REBOOT_FAILED}) {
  860. return nil, httperrors.NewInvalidStatusError("Cannot do reboot dbinstance in status %s", self.Status)
  861. }
  862. return nil, self.StartDBInstanceRebootTask(ctx, userCred, jsonutils.NewDict(), "")
  863. }
  864. // 同步RDS实例状态
  865. func (self *SDBInstance) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  866. return self.PerformSync(ctx, userCred, query, data)
  867. }
  868. // 同步RDS状态(弃用)
  869. func (self *SDBInstance) PerformSyncStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  870. return self.PerformSync(ctx, userCred, query, data)
  871. }
  872. // 同步RDS信息
  873. func (self *SDBInstance) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  874. var openTask = true
  875. count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  876. if err != nil {
  877. return nil, err
  878. }
  879. if count > 0 {
  880. return nil, httperrors.NewBadRequestError("DBInstance has %d task active, can't sync status", count)
  881. }
  882. return nil, self.StartDBInstanceSyncTask(ctx, userCred, "")
  883. }
  884. func (self *SDBInstance) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  885. if !utils.IsInStringArray(self.Status, []string{api.DBINSTANCE_RUNNING}) {
  886. return nil, httperrors.NewInvalidStatusError("Cannot do renew dbinstance in status %s required status %s", self.Status, api.DBINSTANCE_RUNNING)
  887. }
  888. durationStr := jsonutils.GetAnyString(data, []string{"duration"})
  889. if len(durationStr) == 0 {
  890. return nil, httperrors.NewInputParameterError("missong duration")
  891. }
  892. bc, err := billing.ParseBillingCycle(durationStr)
  893. if err != nil {
  894. return nil, httperrors.NewInputParameterError("invalid duration %s: %s", durationStr, err)
  895. }
  896. region, err := self.GetRegion()
  897. if err != nil {
  898. return nil, err
  899. }
  900. if !region.GetDriver().IsSupportedBillingCycle(bc, DBInstanceManager.KeywordPlural()) {
  901. return nil, httperrors.NewInputParameterError("unsupported duration %s", durationStr)
  902. }
  903. return nil, self.StartDBInstanceRenewTask(ctx, userCred, durationStr, "")
  904. }
  905. func (self *SDBInstance) SetAutoRenew(autoRenew bool) error {
  906. _, err := db.Update(self, func() error {
  907. self.AutoRenew = autoRenew
  908. return nil
  909. })
  910. return err
  911. }
  912. // 设置自动续费
  913. // 要求RDS状态为running
  914. // 要求RDS计费类型为包年包月(预付费)
  915. func (self *SDBInstance) PerformSetAutoRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DBInstanceAutoRenewInput) (jsonutils.JSONObject, error) {
  916. if !utils.IsInStringArray(self.Status, []string{api.DBINSTANCE_RUNNING}) {
  917. return nil, httperrors.NewUnsupportOperationError("The dbinstance status need be %s, current is %s", api.DBINSTANCE_RUNNING, self.Status)
  918. }
  919. if self.BillingType != billing_api.BILLING_TYPE_PREPAID {
  920. return nil, httperrors.NewUnsupportOperationError("Only %s dbinstance support this operation", billing_api.BILLING_TYPE_PREPAID)
  921. }
  922. if self.AutoRenew == input.AutoRenew {
  923. return nil, nil
  924. }
  925. driver, err := self.GetRegionDriver()
  926. if err != nil {
  927. return nil, errors.Wrapf(err, "GetRegionDriver")
  928. }
  929. if !driver.IsSupportedDBInstanceAutoRenew() {
  930. err := self.SetAutoRenew(input.AutoRenew)
  931. if err != nil {
  932. return nil, httperrors.NewGeneralError(err)
  933. }
  934. logclient.AddSimpleActionLog(self, logclient.ACT_SET_AUTO_RENEW, jsonutils.Marshal(input), userCred, true)
  935. return nil, nil
  936. }
  937. return nil, self.StartSetAutoRenewTask(ctx, userCred, input.AutoRenew, "")
  938. }
  939. func (self *SDBInstance) StartSetAutoRenewTask(ctx context.Context, userCred mcclient.TokenCredential, autoRenew bool, parentTaskId string) error {
  940. data := jsonutils.NewDict()
  941. data.Set("auto_renew", jsonutils.NewBool(autoRenew))
  942. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceSetAutoRenewTask", self, userCred, data, parentTaskId, "", nil)
  943. if err != nil {
  944. return errors.Wrap(err, "NewTask")
  945. }
  946. self.SetStatus(ctx, userCred, api.DBINSTANCE_SET_AUTO_RENEW, "")
  947. task.ScheduleRun(nil)
  948. return nil
  949. }
  950. func (self *SDBInstance) PerformPublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  951. open := jsonutils.QueryBoolean(data, "open", true)
  952. if open && len(self.ConnectionStr) > 0 {
  953. return nil, httperrors.NewInputParameterError("DBInstance has opened the outer network connection")
  954. }
  955. if !open && len(self.ConnectionStr) == 0 {
  956. return nil, httperrors.NewInputParameterError("The extranet connection is not open")
  957. }
  958. region, err := self.GetRegion()
  959. if err != nil {
  960. return nil, err
  961. }
  962. if !region.GetDriver().IsSupportDBInstancePublicConnection() {
  963. return nil, httperrors.NewInputParameterError("%s not support this operation", region.Provider)
  964. }
  965. return nil, self.StartDBInstancePublicConnectionTask(ctx, userCred, "", open)
  966. }
  967. func (self *SDBInstance) StartDBInstancePublicConnectionTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, open bool) error {
  968. self.SetStatus(ctx, userCred, api.DBINSTANCE_DEPLOYING, "")
  969. params := jsonutils.NewDict()
  970. params.Add(jsonutils.NewBool(open), "open")
  971. task, err := taskman.TaskManager.NewTask(ctx, "DBInstancePublicConnectionTask", self, userCred, params, parentTaskId, "", nil)
  972. if err != nil {
  973. return err
  974. }
  975. task.ScheduleRun(nil)
  976. return nil
  977. }
  978. func (self *SDBInstance) PerformChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SDBInstanceChangeConfigInput) (jsonutils.JSONObject, error) {
  979. if !utils.IsInStringArray(self.Status, []string{api.DBINSTANCE_RUNNING}) {
  980. return nil, httperrors.NewInputParameterError("Cannot change config in status %s", self.Status)
  981. }
  982. if input.DiskSizeGB != 0 && input.DiskSizeGB < self.DiskSizeGB {
  983. return nil, httperrors.NewUnsupportOperationError("DBInstance Disk cannot be thrink")
  984. }
  985. if input.DiskSizeGB == self.DiskSizeGB && input.InstanceType == self.InstanceType {
  986. return nil, nil
  987. }
  988. return nil, self.StartDBInstanceChangeConfig(ctx, userCred, jsonutils.Marshal(input).(*jsonutils.JSONDict), "")
  989. }
  990. func (self *SDBInstance) StartDBInstanceChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
  991. self.SetStatus(ctx, userCred, api.DBINSTANCE_CHANGE_CONFIG, "")
  992. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceChangeConfigTask", self, userCred, data, parentTaskId, "", nil)
  993. if err != nil {
  994. return err
  995. }
  996. task.ScheduleRun(nil)
  997. return nil
  998. }
  999. func (self *SDBInstance) StartDBInstanceRenewTask(ctx context.Context, userCred mcclient.TokenCredential, duration string, parentTaskId string) error {
  1000. self.SetStatus(ctx, userCred, api.DBINSTANCE_RENEWING, "")
  1001. params := jsonutils.NewDict()
  1002. params.Set("duration", jsonutils.NewString(duration))
  1003. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceRenewTask", self, userCred, params, parentTaskId, "", nil)
  1004. if err != nil {
  1005. return err
  1006. }
  1007. task.ScheduleRun(nil)
  1008. return nil
  1009. }
  1010. func (self *SDBInstance) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  1011. desc := self.SVirtualResourceBase.GetShortDesc(ctx)
  1012. region, _ := self.GetRegion()
  1013. provider := self.GetCloudprovider()
  1014. ipAddr := func() string {
  1015. rdsNetwrok := SDBInstanceNetwork{}
  1016. err := DBInstanceNetworkManager.Query("ip_addr").Equals("dbinstance_id", self.Id).IsNotNull("ip_addr").IsNotEmpty("ip_addr").First(&rdsNetwrok)
  1017. if err != nil {
  1018. return ""
  1019. }
  1020. return rdsNetwrok.IpAddr
  1021. }()
  1022. info := MakeCloudProviderInfo(region, nil, provider)
  1023. desc.Set("engine", jsonutils.NewString(self.Engine))
  1024. desc.Set("storage_type", jsonutils.NewString(self.StorageType))
  1025. desc.Set("instance_type", jsonutils.NewString(self.InstanceType))
  1026. desc.Set("vcpu_count", jsonutils.NewInt(int64(self.VcpuCount)))
  1027. desc.Set("vmem_size_mb", jsonutils.NewInt(int64(self.VmemSizeMb)))
  1028. desc.Set("disk_size_gb", jsonutils.NewInt(int64(self.DiskSizeGB)))
  1029. desc.Set("iops", jsonutils.NewInt(int64(self.Iops)))
  1030. desc.Set("ip_addr", jsonutils.NewString(ipAddr))
  1031. desc.Update(jsonutils.Marshal(&info))
  1032. return desc
  1033. }
  1034. func (self *SDBInstance) StartDBInstanceDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
  1035. self.SetStatus(ctx, userCred, api.DBINSTANCE_DELETING, "")
  1036. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceDeleteTask", self, userCred, data, parentTaskId, "", nil)
  1037. if err != nil {
  1038. return err
  1039. }
  1040. task.ScheduleRun(nil)
  1041. return nil
  1042. }
  1043. func (self *SDBInstance) StartDBInstanceRebootTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
  1044. self.SetStatus(ctx, userCred, api.DBINSTANCE_REBOOTING, "")
  1045. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceRebootTask", self, userCred, data, parentTaskId, "", nil)
  1046. if err != nil {
  1047. return err
  1048. }
  1049. task.ScheduleRun(nil)
  1050. return nil
  1051. }
  1052. func (self *SDBInstance) StartDBInstanceSyncTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  1053. return StartResourceSyncStatusTask(ctx, userCred, self, "DBInstanceSyncTask", parentTaskId)
  1054. }
  1055. func (manager *SDBInstanceManager) getDBInstancesByProviderId(providerId string) ([]SDBInstance, error) {
  1056. instances := []SDBInstance{}
  1057. err := fetchByManagerId(manager, providerId, &instances)
  1058. if err != nil {
  1059. return nil, errors.Wrapf(err, "getDBInstancesByProviderId.fetchByManagerId")
  1060. }
  1061. return instances, nil
  1062. }
  1063. func (self *SDBInstance) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  1064. params := jsonutils.NewDict()
  1065. params.Set("keep_backup", jsonutils.NewBool(jsonutils.QueryBoolean(data, "keep_backup", false)))
  1066. return self.StartDBInstanceDeleteTask(ctx, userCred, params, "")
  1067. }
  1068. func (self *SDBInstance) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1069. log.Infof("dbinstance delete do nothing")
  1070. return nil
  1071. }
  1072. func (self *SDBInstance) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1073. return self.purge(ctx, userCred)
  1074. }
  1075. func (self *SDBInstance) GetDBInstanceParameters() ([]SDBInstanceParameter, error) {
  1076. params := []SDBInstanceParameter{}
  1077. q := DBInstanceParameterManager.Query().Equals("dbinstance_id", self.Id)
  1078. err := db.FetchModelObjects(DBInstanceParameterManager, q, &params)
  1079. if err != nil {
  1080. return nil, errors.Wrapf(err, "GetDBInstanceParameters.FetchModelObjects for instance %s", self.Id)
  1081. }
  1082. return params, nil
  1083. }
  1084. func (self *SDBInstance) GetDBInstanceBackup(name string) (*SDBInstanceBackup, error) {
  1085. q := DBInstanceBackupManager.Query().Equals("dbinstance_id", self.Id)
  1086. q = q.Filter(
  1087. sqlchemy.OR(
  1088. sqlchemy.Equals(q.Field("name"), name),
  1089. sqlchemy.Equals(q.Field("id"), name),
  1090. ),
  1091. )
  1092. count, err := q.CountWithError()
  1093. if err != nil {
  1094. return nil, err
  1095. }
  1096. if count > 1 {
  1097. return nil, fmt.Errorf("Duplicate %d backup %s for dbinstance %s(%s)", count, name, self.Name, self.Id)
  1098. }
  1099. if count == 0 {
  1100. return nil, fmt.Errorf("Failed to found backup %s for dbinstance %s(%s)", name, self.Name, self.Id)
  1101. }
  1102. backup := &SDBInstanceBackup{}
  1103. backup.SetModelManager(DBInstanceBackupManager, backup)
  1104. return backup, q.First(backup)
  1105. }
  1106. func (self *SDBInstance) GetDBInstanceDatabase(name string) (*SDBInstanceDatabase, error) {
  1107. q := DBInstanceDatabaseManager.Query().Equals("dbinstance_id", self.Id)
  1108. q = q.Filter(
  1109. sqlchemy.OR(
  1110. sqlchemy.Equals(q.Field("name"), name),
  1111. sqlchemy.Equals(q.Field("id"), name),
  1112. ),
  1113. )
  1114. count, err := q.CountWithError()
  1115. if err != nil {
  1116. return nil, err
  1117. }
  1118. if count > 1 {
  1119. return nil, fmt.Errorf("Duplicate %d database %s for dbinstance %s(%s)", count, name, self.Name, self.Id)
  1120. }
  1121. if count == 0 {
  1122. return nil, fmt.Errorf("Failed to found database %s for dbinstance %s(%s)", name, self.Name, self.Id)
  1123. }
  1124. database := &SDBInstanceDatabase{}
  1125. database.SetModelManager(DBInstanceDatabaseManager, database)
  1126. return database, q.First(database)
  1127. }
  1128. func (self *SDBInstance) GetDBInstanceDatabases() ([]SDBInstanceDatabase, error) {
  1129. databases := []SDBInstanceDatabase{}
  1130. q := DBInstanceDatabaseManager.Query().Equals("dbinstance_id", self.Id)
  1131. err := db.FetchModelObjects(DBInstanceDatabaseManager, q, &databases)
  1132. if err != nil {
  1133. return nil, errors.Wrapf(err, "GetDBInstanceDatabases.FetchModelObjects for instance %s", self.Id)
  1134. }
  1135. return databases, nil
  1136. }
  1137. func (self *SDBInstance) GetDBInstanceAccount(name string) (*SDBInstanceAccount, error) {
  1138. q := DBInstanceAccountManager.Query().Equals("dbinstance_id", self.Id)
  1139. q = q.Filter(
  1140. sqlchemy.OR(
  1141. sqlchemy.Equals(q.Field("name"), name),
  1142. sqlchemy.Equals(q.Field("id"), name),
  1143. ),
  1144. )
  1145. count, err := q.CountWithError()
  1146. if err != nil {
  1147. return nil, err
  1148. }
  1149. if count > 1 {
  1150. return nil, fmt.Errorf("Duplicate %d account %s for dbinstance %s(%s)", count, name, self.Name, self.Id)
  1151. }
  1152. if count == 0 {
  1153. return nil, fmt.Errorf("Failed to found account %s for dbinstance %s(%s)", name, self.Name, self.Id)
  1154. }
  1155. account := &SDBInstanceAccount{}
  1156. account.SetModelManager(DBInstanceAccountManager, account)
  1157. return account, q.First(account)
  1158. }
  1159. func (self *SDBInstance) GetDBInstanceAccounts() ([]SDBInstanceAccount, error) {
  1160. accounts := []SDBInstanceAccount{}
  1161. q := DBInstanceAccountManager.Query().Equals("dbinstance_id", self.Id)
  1162. err := db.FetchModelObjects(DBInstanceAccountManager, q, &accounts)
  1163. if err != nil {
  1164. return nil, errors.Wrapf(err, "GetDBInstanceAccounts.FetchModelObjects for instance %s", self.Id)
  1165. }
  1166. return accounts, nil
  1167. }
  1168. func (self *SDBInstance) GetDBInstancePrivilege(account, database string) (*SDBInstancePrivilege, error) {
  1169. instances := DBInstanceManager.Query().SubQuery()
  1170. accounts := DBInstanceAccountManager.Query().SubQuery()
  1171. databases := DBInstanceDatabaseManager.Query().SubQuery()
  1172. q := DBInstancePrivilegeManager.Query()
  1173. q = q.Join(accounts, sqlchemy.Equals(accounts.Field("id"), q.Field("dbinstanceaccount_id"))).
  1174. Join(databases, sqlchemy.Equals(databases.Field("id"), q.Field("dbinstancedatabase_id"))).
  1175. Join(instances, sqlchemy.AND(sqlchemy.Equals(instances.Field("id"), accounts.Field("dbinstance_id")), sqlchemy.Equals(instances.Field("id"), databases.Field("dbinstance_id"))))
  1176. q = q.Filter(
  1177. sqlchemy.AND(
  1178. sqlchemy.OR(
  1179. sqlchemy.Equals(accounts.Field("id"), account),
  1180. sqlchemy.Equals(accounts.Field("name"), account),
  1181. ),
  1182. sqlchemy.OR(
  1183. sqlchemy.Equals(databases.Field("id"), database),
  1184. sqlchemy.Equals(databases.Field("name"), database),
  1185. ),
  1186. ),
  1187. )
  1188. count, err := q.CountWithError()
  1189. if err != nil {
  1190. return nil, err
  1191. }
  1192. if count > 1 {
  1193. return nil, sqlchemy.ErrDuplicateEntry
  1194. }
  1195. if count == 0 {
  1196. return nil, sql.ErrNoRows
  1197. }
  1198. privilege := &SDBInstancePrivilege{}
  1199. privilege.SetModelManager(DBInstancePrivilegeManager, privilege)
  1200. err = q.First(privilege)
  1201. if err != nil {
  1202. return nil, errors.Wrap(err, "q.First()")
  1203. }
  1204. return privilege, nil
  1205. }
  1206. func (self *SDBInstance) GetDBInstanceBackupByMode(mode string) ([]SDBInstanceBackup, error) {
  1207. backups := []SDBInstanceBackup{}
  1208. q := DBInstanceBackupManager.Query().Equals("dbinstance_id", self.Id)
  1209. switch mode {
  1210. case api.BACKUP_MODE_MANUAL, api.BACKUP_MODE_AUTOMATED:
  1211. q = q.Equals("backup_mode", mode)
  1212. }
  1213. err := db.FetchModelObjects(DBInstanceBackupManager, q, &backups)
  1214. if err != nil {
  1215. return nil, errors.Wrap(err, "GetDBInstanceBackups.FetchModelObjects")
  1216. }
  1217. return backups, nil
  1218. }
  1219. func (self *SDBInstance) GetDBInstanceBackups() ([]SDBInstanceBackup, error) {
  1220. return self.GetDBInstanceBackupByMode("")
  1221. }
  1222. func (self *SDBInstance) GetDBDatabases() ([]SDBInstanceDatabase, error) {
  1223. databases := []SDBInstanceDatabase{}
  1224. q := DBInstanceDatabaseManager.Query().Equals("dbinstance_id", self.Id)
  1225. err := db.FetchModelObjects(DBInstanceDatabaseManager, q, &databases)
  1226. if err != nil {
  1227. return nil, errors.Wrap(err, "GetDBDatabases.FetchModelObjects")
  1228. }
  1229. return databases, nil
  1230. }
  1231. func (self *SDBInstance) GetDBParameters() ([]SDBInstanceParameter, error) {
  1232. parameters := []SDBInstanceParameter{}
  1233. q := DBInstanceParameterManager.Query().Equals("dbinstance_id", self.Id)
  1234. err := db.FetchModelObjects(DBInstanceParameterManager, q, &parameters)
  1235. if err != nil {
  1236. return nil, errors.Wrap(err, "GetDBParameters.FetchModelObjects")
  1237. }
  1238. return parameters, nil
  1239. }
  1240. func (self *SDBInstance) GetDBNetworks() ([]SDBInstanceNetwork, error) {
  1241. q := DBInstanceNetworkManager.Query().Equals("dbinstance_id", self.Id)
  1242. networks := []SDBInstanceNetwork{}
  1243. err := db.FetchModelObjects(DBInstanceNetworkManager, q, &networks)
  1244. if err != nil {
  1245. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1246. }
  1247. return networks, nil
  1248. }
  1249. func (manager *SDBInstanceManager) SyncDBInstanceMasterId(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, cloudDBInstances []cloudprovider.ICloudDBInstance) {
  1250. for _, instance := range cloudDBInstances {
  1251. masterId := instance.GetMasterInstanceId()
  1252. if len(masterId) > 0 {
  1253. master, err := db.FetchByExternalIdAndManagerId(manager, masterId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1254. return q.Equals("manager_id", provider.Id)
  1255. })
  1256. if err != nil {
  1257. log.Errorf("failed to found master dbinstance by externalId: %s error: %v", masterId, err)
  1258. continue
  1259. }
  1260. slave, err := db.FetchByExternalIdAndManagerId(manager, instance.GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1261. return q.Equals("manager_id", provider.Id)
  1262. })
  1263. if err != nil {
  1264. log.Errorf("failed to found local dbinstance by externalId %s error: %v", instance.GetGlobalId(), err)
  1265. continue
  1266. }
  1267. localInstance := slave.(*SDBInstance)
  1268. _, err = db.Update(localInstance, func() error {
  1269. localInstance.MasterInstanceId = master.GetId()
  1270. return nil
  1271. })
  1272. if err != nil {
  1273. log.Errorf("failed to update dbinstance %s(%s) master instanceId error: %v", localInstance.Name, localInstance.Id, err)
  1274. }
  1275. }
  1276. }
  1277. }
  1278. func (manager *SDBInstanceManager) SyncDBInstances(
  1279. ctx context.Context,
  1280. userCred mcclient.TokenCredential,
  1281. syncOwnerId mcclient.IIdentityProvider,
  1282. provider *SCloudprovider,
  1283. region *SCloudregion,
  1284. cloudDBInstances []cloudprovider.ICloudDBInstance,
  1285. xor bool,
  1286. ) ([]SDBInstance, []cloudprovider.ICloudDBInstance, compare.SyncResult) {
  1287. lockman.LockRawObject(ctx, "dbinstances", fmt.Sprintf("%s-%s", provider.Id, region.Id))
  1288. defer lockman.ReleaseRawObject(ctx, "dbinstances", fmt.Sprintf("%s-%s", provider.Id, region.Id))
  1289. localDBInstances := []SDBInstance{}
  1290. remoteDBInstances := []cloudprovider.ICloudDBInstance{}
  1291. syncResult := compare.SyncResult{}
  1292. dbInstances, err := region.GetDBInstances(provider)
  1293. if err != nil {
  1294. syncResult.Error(err)
  1295. return nil, nil, syncResult
  1296. }
  1297. for i := range dbInstances {
  1298. if taskman.TaskManager.IsInTask(&dbInstances[i]) {
  1299. syncResult.Error(fmt.Errorf("dbInstance %s(%s)in task", dbInstances[i].Name, dbInstances[i].Id))
  1300. return nil, nil, syncResult
  1301. }
  1302. }
  1303. removed := make([]SDBInstance, 0)
  1304. commondb := make([]SDBInstance, 0)
  1305. commonext := make([]cloudprovider.ICloudDBInstance, 0)
  1306. added := make([]cloudprovider.ICloudDBInstance, 0)
  1307. if err := compare.CompareSets(dbInstances, cloudDBInstances, &removed, &commondb, &commonext, &added); err != nil {
  1308. syncResult.Error(err)
  1309. return nil, nil, syncResult
  1310. }
  1311. for i := 0; i < len(removed); i++ {
  1312. err := removed[i].syncRemoveCloudDBInstance(ctx, userCred)
  1313. if err != nil {
  1314. syncResult.DeleteError(err)
  1315. } else {
  1316. syncResult.Delete()
  1317. }
  1318. }
  1319. if !xor {
  1320. for i := 0; i < len(commondb); i++ {
  1321. err := commondb[i].SyncWithCloudDBInstance(ctx, userCred, provider, commonext[i])
  1322. if err != nil {
  1323. syncResult.UpdateError(err)
  1324. continue
  1325. }
  1326. localDBInstances = append(localDBInstances, commondb[i])
  1327. remoteDBInstances = append(remoteDBInstances, commonext[i])
  1328. syncResult.Update()
  1329. }
  1330. }
  1331. for i := 0; i < len(added); i++ {
  1332. instance, err := manager.newFromCloudDBInstance(ctx, userCred, syncOwnerId, provider, region, added[i])
  1333. if err != nil {
  1334. syncResult.AddError(err)
  1335. continue
  1336. }
  1337. localDBInstances = append(localDBInstances, *instance)
  1338. remoteDBInstances = append(remoteDBInstances, added[i])
  1339. syncResult.Add()
  1340. }
  1341. return localDBInstances, remoteDBInstances, syncResult
  1342. }
  1343. func (self *SDBInstance) syncRemoveCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential) error {
  1344. err := self.RealDelete(ctx, userCred)
  1345. if err != nil {
  1346. return err
  1347. }
  1348. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1349. Obj: self,
  1350. Action: notifyclient.ActionSyncDelete,
  1351. })
  1352. return nil
  1353. }
  1354. func (self *SDBInstance) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  1355. if self.DisableDelete.IsTrue() {
  1356. return httperrors.NewInvalidStatusError("DBInstance is locked, cannot delete")
  1357. }
  1358. return self.SStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
  1359. }
  1360. func (self *SDBInstance) GetDBInstanceSkuQuery(skipZoneCheck bool) *sqlchemy.SQuery {
  1361. q := DBInstanceSkuManager.Query().Equals("storage_type", self.StorageType).Equals("category", self.Category).
  1362. Equals("cloudregion_id", self.CloudregionId).Equals("engine", self.Engine).Equals("engine_version", self.EngineVersion)
  1363. if !skipZoneCheck {
  1364. for k, v := range map[string]string{"zone1": self.Zone1, "zone2": self.Zone2, "zone3": self.Zone3} {
  1365. if len(v) > 0 {
  1366. q = q.Equals(k, v)
  1367. }
  1368. }
  1369. }
  1370. if len(self.InstanceType) > 0 {
  1371. q = q.Equals("name", self.InstanceType)
  1372. } else {
  1373. q = q.Equals("vcpu_count", self.VcpuCount).Equals("vmem_size_mb", self.VmemSizeMb)
  1374. }
  1375. return q
  1376. }
  1377. func (self *SDBInstance) GetAvailableDBInstanceSkus(skipZoneCheck bool) ([]SDBInstanceSku, error) {
  1378. skus := []SDBInstanceSku{}
  1379. q := self.GetDBInstanceSkuQuery(skipZoneCheck).Equals("status", api.DBINSTANCE_SKU_AVAILABLE)
  1380. err := db.FetchModelObjects(DBInstanceSkuManager, q, &skus)
  1381. if err != nil {
  1382. return nil, err
  1383. }
  1384. return skus, nil
  1385. }
  1386. func (self *SDBInstance) GetDBInstanceSkus(skipZoneCheck bool) ([]SDBInstanceSku, error) {
  1387. skus := []SDBInstanceSku{}
  1388. q := self.GetDBInstanceSkuQuery(skipZoneCheck)
  1389. err := db.FetchModelObjects(DBInstanceSkuManager, q, &skus)
  1390. if err != nil {
  1391. return nil, err
  1392. }
  1393. return skus, nil
  1394. }
  1395. func (self *SDBInstance) GetAvailableInstanceTypes() ([]cloudprovider.SInstanceType, error) {
  1396. instanceTypes := []cloudprovider.SInstanceType{}
  1397. skus, err := self.GetAvailableDBInstanceSkus(false)
  1398. if err != nil {
  1399. return nil, errors.Wrap(err, "self.GetAvailableDBInstanceSkus")
  1400. }
  1401. for _, sku := range skus {
  1402. instanceType := cloudprovider.SInstanceType{}
  1403. instanceType.InstanceType = sku.Name
  1404. instanceType.SZoneInfo, _ = sku.GetZoneInfo()
  1405. instanceTypes = append(instanceTypes, instanceType)
  1406. }
  1407. return instanceTypes, nil
  1408. }
  1409. func (self *SDBInstance) setZoneInfo() error {
  1410. sku := SDBInstanceSku{}
  1411. q := self.GetDBInstanceSkuQuery(false)
  1412. count, err := q.CountWithError()
  1413. if err != nil {
  1414. return errors.Wrapf(err, "q.CountWithError")
  1415. }
  1416. if count == 0 {
  1417. return fmt.Errorf("failed to fetch any sku for dbinstance %s(%s)", self.Name, self.Id)
  1418. }
  1419. if count > 1 {
  1420. return fmt.Errorf("fetch %d skus for dbinstance %s(%s)", count, self.Name, self.Id)
  1421. }
  1422. err = q.First(&sku)
  1423. if err != nil {
  1424. return errors.Wrap(err, "q.First()")
  1425. }
  1426. self.Zone1 = sku.Zone1
  1427. self.Zone2 = sku.Zone2
  1428. self.Zone3 = sku.Zone3
  1429. return nil
  1430. }
  1431. func (self *SDBInstance) SetZoneInfo(ctx context.Context, userCred mcclient.TokenCredential) error {
  1432. _, err := db.UpdateWithLock(ctx, self, func() error {
  1433. return self.setZoneInfo()
  1434. })
  1435. return err
  1436. }
  1437. func (self *SDBInstance) SetZoneIds(extInstance cloudprovider.ICloudDBInstance) error {
  1438. region, err := self.GetRegion()
  1439. if err != nil {
  1440. return err
  1441. }
  1442. zones, err := region.GetZones()
  1443. if err != nil {
  1444. return errors.Wrapf(err, "GetZones")
  1445. }
  1446. var setZoneId = func(input string, output *string) {
  1447. *output = input
  1448. for _, zone := range zones {
  1449. if strings.HasSuffix(zone.ExternalId, input) {
  1450. *output = zone.Id
  1451. break
  1452. }
  1453. }
  1454. }
  1455. zone1 := extInstance.GetZone1Id()
  1456. if len(zone1) > 0 {
  1457. setZoneId(zone1, &self.Zone1)
  1458. }
  1459. zone2 := extInstance.GetZone2Id()
  1460. if len(zone2) > 0 {
  1461. setZoneId(zone2, &self.Zone2)
  1462. }
  1463. zone3 := extInstance.GetZone3Id()
  1464. if len(zone3) > 0 {
  1465. setZoneId(zone3, &self.Zone3)
  1466. }
  1467. return nil
  1468. }
  1469. func (self *SDBInstance) SyncAllWithCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extInstance cloudprovider.ICloudDBInstance) error {
  1470. err := self.SyncWithCloudDBInstance(ctx, userCred, provider, extInstance)
  1471. if err != nil {
  1472. return errors.Wrapf(err, "SyncWithCloudDBInstance")
  1473. }
  1474. syncDBInstanceResource(ctx, userCred, SSyncResultSet{}, self, extInstance, &SSyncRange{})
  1475. return nil
  1476. }
  1477. func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudDBInstance) error {
  1478. diff, err := db.Update(self, func() error {
  1479. if options.Options.EnableSyncName {
  1480. newName, _ := db.GenerateAlterName(self, ext.GetName())
  1481. if len(newName) > 0 {
  1482. self.Name = newName
  1483. }
  1484. }
  1485. self.ExternalId = ext.GetGlobalId()
  1486. self.Engine = ext.GetEngine()
  1487. self.EngineVersion = ext.GetEngineVersion()
  1488. self.InstanceType = ext.GetInstanceType()
  1489. cpu := ext.GetVcpuCount()
  1490. mem := ext.GetVmemSizeMB()
  1491. if (cpu == 0 || mem == 0) && len(self.InstanceType) > 0 {
  1492. skus, _ := self.GetAvailableDBInstanceSkus(true)
  1493. for _, sku := range skus {
  1494. cpu, mem = sku.VcpuCount, sku.VmemSizeMb
  1495. break
  1496. }
  1497. }
  1498. if cpu > 0 {
  1499. self.VcpuCount = cpu
  1500. }
  1501. if mem > 0 {
  1502. self.VmemSizeMb = mem
  1503. }
  1504. self.DiskSizeGB = ext.GetDiskSizeGB()
  1505. self.DiskSizeUsedMB = ext.GetDiskSizeUsedMB()
  1506. self.StorageType = ext.GetStorageType()
  1507. self.Category = ext.GetCategory()
  1508. self.Status = ext.GetStatus()
  1509. self.Port = ext.GetPort()
  1510. if len(ext.GetDescription()) > 0 {
  1511. self.Description = ext.GetDescription()
  1512. }
  1513. if iops := ext.GetIops(); iops > 0 {
  1514. self.Iops = iops
  1515. }
  1516. self.ConnectionStr = ext.GetConnectionStr()
  1517. self.InternalConnectionStr = ext.GetInternalConnectionStr()
  1518. self.MaintainTime = ext.GetMaintainTime()
  1519. self.SetZoneIds(ext)
  1520. if createdAt := ext.GetCreatedAt(); !createdAt.IsZero() {
  1521. self.CreatedAt = createdAt
  1522. }
  1523. if vpcId := ext.GetIVpcId(); len(vpcId) > 0 {
  1524. self.VpcId = vpcId
  1525. vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1526. return q.Equals("manager_id", provider.Id)
  1527. })
  1528. if err != nil {
  1529. log.Errorf("FetchVpcId(%s) error: %v", vpcId, err)
  1530. } else {
  1531. self.VpcId = vpc.GetId()
  1532. }
  1533. }
  1534. self.BillingType = billing_api.TBillingType(ext.GetBillingType())
  1535. self.ExpiredAt = time.Time{}
  1536. self.AutoRenew = false
  1537. if self.BillingType == billing_api.BILLING_TYPE_PREPAID {
  1538. self.AutoRenew = ext.IsAutoRenew()
  1539. self.ExpiredAt = ext.GetExpiredAt()
  1540. }
  1541. return nil
  1542. })
  1543. if err != nil {
  1544. return err
  1545. }
  1546. if account := self.GetCloudaccount(); account != nil {
  1547. syncVirtualResourceMetadata(ctx, userCred, self, ext, account.ReadOnly)
  1548. }
  1549. SyncCloudProject(ctx, userCred, self, provider.GetOwnerId(), ext, provider)
  1550. db.OpsLog.LogSyncUpdate(self, diff, userCred)
  1551. if len(diff) > 0 {
  1552. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1553. Obj: self,
  1554. Action: notifyclient.ActionSyncUpdate,
  1555. })
  1556. }
  1557. return nil
  1558. }
  1559. func (self *SDBInstance) GetSlaveDBInstances() ([]SDBInstance, error) {
  1560. dbinstances := []SDBInstance{}
  1561. q := DBInstanceManager.Query().Equals("master_instance_id", self.Id)
  1562. return dbinstances, db.FetchModelObjects(DBInstanceManager, q, &dbinstances)
  1563. }
  1564. func (manager *SDBInstanceManager) newFromCloudDBInstance(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, provider *SCloudprovider, region *SCloudregion, extInstance cloudprovider.ICloudDBInstance) (*SDBInstance, error) {
  1565. instance := SDBInstance{}
  1566. instance.SetModelManager(manager, &instance)
  1567. instance.ExternalId = extInstance.GetGlobalId()
  1568. instance.CloudregionId = region.Id
  1569. instance.ManagerId = provider.Id
  1570. instance.IsEmulated = extInstance.IsEmulated()
  1571. instance.Status = extInstance.GetStatus()
  1572. instance.Port = extInstance.GetPort()
  1573. instance.Iops = extInstance.GetIops()
  1574. instance.Engine = extInstance.GetEngine()
  1575. instance.EngineVersion = extInstance.GetEngineVersion()
  1576. instance.InstanceType = extInstance.GetInstanceType()
  1577. instance.Category = extInstance.GetCategory()
  1578. instance.VcpuCount = extInstance.GetVcpuCount()
  1579. instance.VmemSizeMb = extInstance.GetVmemSizeMB()
  1580. instance.DiskSizeGB = extInstance.GetDiskSizeGB()
  1581. instance.DiskSizeUsedMB = extInstance.GetDiskSizeUsedMB()
  1582. instance.ConnectionStr = extInstance.GetConnectionStr()
  1583. instance.StorageType = extInstance.GetStorageType()
  1584. instance.InternalConnectionStr = extInstance.GetInternalConnectionStr()
  1585. instance.Description = extInstance.GetDescription()
  1586. instance.MaintainTime = extInstance.GetMaintainTime()
  1587. instance.SetZoneIds(extInstance)
  1588. if vpcId := extInstance.GetIVpcId(); len(vpcId) > 0 {
  1589. instance.VpcId = vpcId
  1590. vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1591. return q.Equals("manager_id", provider.Id)
  1592. })
  1593. if err != nil {
  1594. log.Errorf("FetchVpcId(%s) error: %v", vpcId, err)
  1595. } else {
  1596. instance.VpcId = vpc.GetId()
  1597. }
  1598. }
  1599. if createdAt := extInstance.GetCreatedAt(); !createdAt.IsZero() {
  1600. instance.CreatedAt = createdAt
  1601. }
  1602. instance.BillingType = billing_api.TBillingType(extInstance.GetBillingType())
  1603. instance.AutoRenew = false
  1604. instance.ExpiredAt = time.Time{}
  1605. if instance.BillingType == billing_api.BILLING_TYPE_PREPAID {
  1606. instance.AutoRenew = extInstance.IsAutoRenew()
  1607. instance.ExpiredAt = extInstance.GetExpiredAt()
  1608. }
  1609. err := func() error {
  1610. lockman.LockRawObject(ctx, manager.Keyword(), "name")
  1611. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
  1612. var err error
  1613. instance.Name, err = db.GenerateName(ctx, manager, ownerId, extInstance.GetName())
  1614. if err != nil {
  1615. return errors.Wrapf(err, "db.GenerateName")
  1616. }
  1617. return manager.TableSpec().Insert(ctx, &instance)
  1618. }()
  1619. if err != nil {
  1620. return nil, errors.Wrapf(err, "newFromCloudDBInstance.Insert")
  1621. }
  1622. syncVirtualResourceMetadata(ctx, userCred, &instance, extInstance, false)
  1623. SyncCloudProject(ctx, userCred, &instance, provider.GetOwnerId(), extInstance, provider)
  1624. db.OpsLog.LogEvent(&instance, db.ACT_CREATE, instance.GetShortDesc(ctx), userCred)
  1625. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1626. Obj: &instance,
  1627. Action: notifyclient.ActionSyncCreate,
  1628. })
  1629. return &instance, nil
  1630. }
  1631. type SRdsCountStat struct {
  1632. TotalRdsCount int
  1633. TotalCpuCount int
  1634. TotalMemSizeMb int
  1635. TotalDiskSizeGb int
  1636. TotalDiskSizeUsedMb int
  1637. DiskUsedRate float64
  1638. }
  1639. func (man *SDBInstanceManager) TotalCount(
  1640. ctx context.Context,
  1641. scope rbacscope.TRbacScope,
  1642. ownerId mcclient.IIdentityProvider,
  1643. rangeObjs []db.IStandaloneModel,
  1644. providers []string, brands []string, cloudEnv string,
  1645. policyResult rbacutils.SPolicyResult,
  1646. ) (SRdsCountStat, error) {
  1647. dbq := man.Query()
  1648. dbq = scopeOwnerIdFilter(dbq, scope, ownerId)
  1649. dbq = CloudProviderFilter(dbq, dbq.Field("manager_id"), providers, brands, cloudEnv)
  1650. dbq = RangeObjectsFilter(dbq, rangeObjs, dbq.Field("cloudregion_id"), nil, dbq.Field("manager_id"), nil, nil)
  1651. dbq = db.ObjectIdQueryWithPolicyResult(ctx, dbq, man, policyResult)
  1652. sq := dbq.SubQuery()
  1653. q := sq.Query(sqlchemy.COUNT("total_rds_count"),
  1654. sqlchemy.SUM("total_cpu_count", sq.Field("vcpu_count")),
  1655. sqlchemy.SUM("total_mem_size_mb", sq.Field("vmem_size_mb")),
  1656. sqlchemy.SUM("total_disk_size_gb", sq.Field("disk_size_gb")),
  1657. sqlchemy.SUM("total_disk_size_used_mb", sq.Field("disk_size_used_mb")),
  1658. )
  1659. stat := SRdsCountStat{}
  1660. row := q.Row()
  1661. err := q.Row2Struct(row, &stat)
  1662. if stat.TotalDiskSizeGb > 0 {
  1663. stat.DiskUsedRate = float64(stat.TotalDiskSizeUsedMb) / float64(stat.TotalDiskSizeGb) / 1024
  1664. }
  1665. return stat, err
  1666. }
  1667. func (self *SDBInstance) GetQuotaKeys() quotas.IQuotaKeys {
  1668. region, _ := self.GetRegion()
  1669. return fetchRegionalQuotaKeys(
  1670. rbacscope.ScopeProject,
  1671. self.GetOwnerId(),
  1672. region,
  1673. self.GetCloudprovider(),
  1674. )
  1675. }
  1676. func (dbinstance *SDBInstance) GetUsages() []db.IUsage {
  1677. if dbinstance.PendingDeleted || dbinstance.Deleted {
  1678. return nil
  1679. }
  1680. usage := SRegionQuota{Rds: 1}
  1681. keys := dbinstance.GetQuotaKeys()
  1682. usage.SetKeys(keys)
  1683. return []db.IUsage{
  1684. &usage,
  1685. }
  1686. }
  1687. func (self *SDBInstance) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  1688. region, err := self.GetRegion()
  1689. if err != nil {
  1690. return nil, err
  1691. }
  1692. provider, err := self.GetDriver(ctx)
  1693. if err != nil {
  1694. return nil, errors.Wrap(err, "self.GetDriver")
  1695. }
  1696. return provider.GetIRegionById(region.GetExternalId())
  1697. }
  1698. func (manager *SDBInstanceManager) ListItemExportKeys(ctx context.Context,
  1699. q *sqlchemy.SQuery,
  1700. userCred mcclient.TokenCredential,
  1701. keys stringutils2.SSortedStrings,
  1702. ) (*sqlchemy.SQuery, error) {
  1703. var err error
  1704. q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1705. if err != nil {
  1706. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
  1707. }
  1708. if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
  1709. q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1710. if err != nil {
  1711. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
  1712. }
  1713. }
  1714. if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
  1715. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1716. if err != nil {
  1717. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  1718. }
  1719. }
  1720. if keys.Contains("vpc") {
  1721. q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"vpc"}))
  1722. if err != nil {
  1723. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys")
  1724. }
  1725. }
  1726. return q, nil
  1727. }
  1728. func (manager *SDBInstanceManager) getExpiredPostpaids() []SDBInstance {
  1729. q := ListExpiredPostpaidResources(manager.Query(), options.Options.ExpiredPrepaidMaxCleanBatchSize)
  1730. q = q.IsFalse("pending_deleted")
  1731. dbs := make([]SDBInstance, 0)
  1732. err := db.FetchModelObjects(DBInstanceManager, q, &dbs)
  1733. if err != nil {
  1734. log.Errorf("fetch dbinstances error %s", err)
  1735. return nil
  1736. }
  1737. return dbs
  1738. }
  1739. func (cache *SDBInstance) SetDisableDelete(userCred mcclient.TokenCredential, val bool) error {
  1740. diff, err := db.Update(cache, func() error {
  1741. if val {
  1742. cache.DisableDelete = tristate.True
  1743. } else {
  1744. cache.DisableDelete = tristate.False
  1745. }
  1746. return nil
  1747. })
  1748. if err != nil {
  1749. return err
  1750. }
  1751. db.OpsLog.LogEvent(cache, db.ACT_UPDATE, diff, userCred)
  1752. logclient.AddSimpleActionLog(cache, logclient.ACT_UPDATE, diff, userCred, true)
  1753. return err
  1754. }
  1755. func (self *SDBInstance) doExternalSync(ctx context.Context, userCred mcclient.TokenCredential) error {
  1756. provider := self.GetCloudprovider()
  1757. if provider != nil {
  1758. return fmt.Errorf("no cloud provider???")
  1759. }
  1760. iregion, err := self.GetIRegion(ctx)
  1761. if err != nil || iregion == nil {
  1762. return fmt.Errorf("no cloud region??? %s", err)
  1763. }
  1764. idbs, err := iregion.GetIDBInstanceById(self.ExternalId)
  1765. if err != nil {
  1766. return err
  1767. }
  1768. return self.SyncWithCloudDBInstance(ctx, userCred, provider, idbs)
  1769. }
  1770. func (manager *SDBInstanceManager) DeleteExpiredPostpaids(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  1771. dbs := manager.getExpiredPostpaids()
  1772. if dbs == nil {
  1773. return
  1774. }
  1775. for i := 0; i < len(dbs); i += 1 {
  1776. if len(dbs[i].ExternalId) > 0 {
  1777. err := dbs[i].doExternalSync(ctx, userCred)
  1778. if err == nil && dbs[i].IsValidPostPaid() {
  1779. continue
  1780. }
  1781. }
  1782. dbs[i].SetDisableDelete(userCred, false)
  1783. dbs[i].StartDBInstanceDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
  1784. }
  1785. }
  1786. func (self *SDBInstance) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
  1787. if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
  1788. return nil, httperrors.NewBadRequestError("dbinstance billing type is %s", self.BillingType)
  1789. }
  1790. releaseAt, err := input.GetReleaseAt()
  1791. if err != nil {
  1792. return nil, err
  1793. }
  1794. err = SaveReleaseAt(ctx, self, userCred, releaseAt)
  1795. if err != nil {
  1796. return nil, err
  1797. }
  1798. return nil, err
  1799. }
  1800. func (self *SDBInstance) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1801. err := SaveReleaseAt(ctx, self, userCred, time.Time{})
  1802. if err != nil {
  1803. return nil, err
  1804. }
  1805. return nil, nil
  1806. }
  1807. func (self *SDBInstance) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DBInstanceRemoteUpdateInput) (jsonutils.JSONObject, error) {
  1808. err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "")
  1809. if err != nil {
  1810. return nil, errors.Wrap(err, "StartRemoteUpdateTask")
  1811. }
  1812. return nil, nil
  1813. }
  1814. func (self *SDBInstance) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
  1815. data := jsonutils.NewDict()
  1816. if replaceTags {
  1817. data.Add(jsonutils.JSONTrue, "replace_tags")
  1818. }
  1819. if task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil); err != nil {
  1820. log.Errorln(err)
  1821. return errors.Wrap(err, "Start ElasticcacheRemoteUpdateTask")
  1822. } else {
  1823. self.SetStatus(ctx, userCred, api.DBINSTANCE_UPDATE_TAGS, "StartRemoteUpdateTask")
  1824. task.ScheduleRun(nil)
  1825. }
  1826. return nil
  1827. }
  1828. func (self *SDBInstance) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  1829. if len(self.ExternalId) == 0 || options.Options.KeepTagLocalization {
  1830. return
  1831. }
  1832. if account := self.GetCloudaccount(); account != nil && account.ReadOnly {
  1833. return
  1834. }
  1835. err := self.StartRemoteUpdateTask(ctx, userCred, true, "")
  1836. if err != nil {
  1837. log.Errorf("StartRemoteUpdateTask fail: %s", err)
  1838. }
  1839. }
  1840. func (self *SDBInstance) PerformSetSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DBInstanceSetSecgroupInput) (jsonutils.JSONObject, error) {
  1841. if self.Status != api.DBINSTANCE_RUNNING {
  1842. return nil, httperrors.NewInvalidStatusError("this operation requires rds state to be %s", api.DBINSTANCE_RUNNING)
  1843. }
  1844. if len(input.SecgroupIds) == 0 {
  1845. return nil, httperrors.NewMissingParameterError("secgroup_ids")
  1846. }
  1847. for i := range input.SecgroupIds {
  1848. _, err := validators.ValidateModel(ctx, userCred, SecurityGroupManager, &input.SecgroupIds[i])
  1849. if err != nil {
  1850. return nil, err
  1851. }
  1852. }
  1853. driver, err := self.GetRegionDriver()
  1854. if err != nil {
  1855. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetRegionDriver"))
  1856. }
  1857. max := driver.GetRdsSupportSecgroupCount()
  1858. if len(input.SecgroupIds) > max {
  1859. return nil, httperrors.NewUnsupportOperationError("%s supported secgroup count is %d", driver.GetProvider(), max)
  1860. }
  1861. secgroups, err := self.GetSecgroups()
  1862. if err != nil {
  1863. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetSecgroups"))
  1864. }
  1865. secMaps := map[string]bool{}
  1866. for i := range secgroups {
  1867. if !utils.IsInStringArray(secgroups[i].Id, input.SecgroupIds) {
  1868. err := self.RevokeSecgroup(ctx, userCred, secgroups[i].Id)
  1869. if err != nil {
  1870. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "RevokeSecgroup(%s)", secgroups[i].Id))
  1871. }
  1872. }
  1873. secMaps[secgroups[i].Id] = true
  1874. }
  1875. for _, id := range input.SecgroupIds {
  1876. if _, ok := secMaps[id]; !ok {
  1877. err = self.AssignSecgroup(ctx, userCred, id)
  1878. if err != nil {
  1879. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "AssignSecgroup(%s)", id))
  1880. }
  1881. }
  1882. }
  1883. return nil, self.StartSyncSecgroupsTask(ctx, userCred, "")
  1884. }
  1885. func (self *SDBInstance) StartSyncSecgroupsTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  1886. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceSyncSecgroupsTask", self, userCred, nil, parentTaskId, "", nil)
  1887. if err != nil {
  1888. return errors.Wrap(err, "NewTask")
  1889. }
  1890. self.SetStatus(ctx, userCred, api.DBINSTANCE_DEPLOYING, "sync secgroups")
  1891. task.ScheduleRun(nil)
  1892. return nil
  1893. }
  1894. func (manager *SDBInstanceManager) GetExpiredModels(advanceDay int) ([]IBillingModel, error) {
  1895. return fetchExpiredModels(manager, advanceDay)
  1896. }
  1897. func (self *SDBInstance) GetExpiredAt() time.Time {
  1898. return self.ExpiredAt
  1899. }
  1900. func (db *SDBInstance) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  1901. db.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
  1902. if len(db.ExternalId) > 0 && (data.Contains("name") || data.Contains("description")) {
  1903. err := db.StartRemoteUpdateTask(ctx, userCred, false, "")
  1904. if err != nil {
  1905. log.Errorf("StartRemoteUpdateTask fail: %s", err)
  1906. }
  1907. }
  1908. }