dbinstance_databases.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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. "yunion.io/x/cloudmux/pkg/cloudprovider"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/compare"
  23. "yunion.io/x/pkg/util/rbacscope"
  24. "yunion.io/x/sqlchemy"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  29. "yunion.io/x/onecloud/pkg/httperrors"
  30. "yunion.io/x/onecloud/pkg/mcclient"
  31. "yunion.io/x/onecloud/pkg/util/stringutils2"
  32. )
  33. // +onecloud:swagger-gen-model-singular=dbinstancedatabase
  34. // +onecloud:swagger-gen-model-plural=dbinstancedatabases
  35. type SDBInstanceDatabaseManager struct {
  36. db.SStatusStandaloneResourceBaseManager
  37. db.SExternalizedResourceBaseManager
  38. SDBInstanceResourceBaseManager
  39. }
  40. var DBInstanceDatabaseManager *SDBInstanceDatabaseManager
  41. func init() {
  42. DBInstanceDatabaseManager = &SDBInstanceDatabaseManager{
  43. SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
  44. SDBInstanceDatabase{},
  45. "dbinstancedatabases_tbl",
  46. "dbinstancedatabase",
  47. "dbinstancedatabases",
  48. ),
  49. }
  50. DBInstanceDatabaseManager.SetVirtualObject(DBInstanceDatabaseManager)
  51. }
  52. type SDBInstanceDatabase struct {
  53. db.SStatusStandaloneResourceBase
  54. db.SExternalizedResourceBase
  55. SDBInstanceResourceBase `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"`
  56. // 字符集
  57. // example: utf-8
  58. CharacterSet string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"character_set"`
  59. // RDS实例Id
  60. // example: 7d07e867-37d1-4754-865d-80f88ad0f982
  61. // DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"`
  62. }
  63. func (manager *SDBInstanceDatabaseManager) GetContextManagers() [][]db.IModelManager {
  64. return [][]db.IModelManager{
  65. {DBInstanceManager},
  66. }
  67. }
  68. func (manager *SDBInstanceDatabaseManager) ResourceScope() rbacscope.TRbacScope {
  69. return rbacscope.ScopeProject
  70. }
  71. func (self *SDBInstanceDatabase) GetOwnerId() mcclient.IIdentityProvider {
  72. instance, err := self.GetDBInstance()
  73. if err != nil {
  74. log.Errorf("failed to get instance for database %s(%s)", self.Name, self.Id)
  75. return nil
  76. }
  77. return instance.GetOwnerId()
  78. }
  79. func (manager *SDBInstanceDatabaseManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
  80. dbinstanceId, _ := data.GetString("dbinstance_id")
  81. if len(dbinstanceId) > 0 {
  82. instance, err := db.FetchById(DBInstanceManager, dbinstanceId)
  83. if err != nil {
  84. return nil, errors.Wrapf(err, "db.FetchById(DBInstanceManager, %s)", dbinstanceId)
  85. }
  86. return instance.(*SDBInstance).GetOwnerId(), nil
  87. }
  88. return db.FetchProjectInfo(ctx, data)
  89. }
  90. func (manager *SDBInstanceDatabaseManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  91. if owner != nil {
  92. sq := DBInstanceManager.Query("id")
  93. switch scope {
  94. case rbacscope.ScopeProject:
  95. sq = sq.Equals("tenant_id", owner.GetProjectId())
  96. return q.In("dbinstance_id", sq.SubQuery())
  97. case rbacscope.ScopeDomain:
  98. sq = sq.Equals("domain_id", owner.GetProjectDomainId())
  99. return q.In("dbinstance_id", sq.SubQuery())
  100. }
  101. }
  102. return q
  103. }
  104. func (self *SDBInstanceDatabase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DBInstanceDatabaseUpdateInput) (api.DBInstanceDatabaseUpdateInput, error) {
  105. var err error
  106. input.StatusStandaloneResourceBaseUpdateInput, err = self.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput)
  107. if err != nil {
  108. return input, errors.Wrapf(err, "SStatusStandaloneResourceBase.ValidateUpdateData")
  109. }
  110. if len(input.Name) > 0 && input.Name != self.Name {
  111. return input, httperrors.NewForbiddenError("not allow update rds database name")
  112. }
  113. return input, nil
  114. }
  115. // RDS数据库列表
  116. func (manager *SDBInstanceDatabaseManager) ListItemFilter(
  117. ctx context.Context,
  118. q *sqlchemy.SQuery,
  119. userCred mcclient.TokenCredential,
  120. query api.DBInstanceDatabaseListInput,
  121. ) (*sqlchemy.SQuery, error) {
  122. q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  123. if err != nil {
  124. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
  125. }
  126. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  127. if err != nil {
  128. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  129. }
  130. q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DBInstanceFilterListInput)
  131. if err != nil {
  132. return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter")
  133. }
  134. if len(query.CharacterSet) > 0 {
  135. q = q.In("character_set", query.CharacterSet)
  136. }
  137. return q, nil
  138. }
  139. func (manager *SDBInstanceDatabaseManager) OrderByExtraFields(
  140. ctx context.Context,
  141. q *sqlchemy.SQuery,
  142. userCred mcclient.TokenCredential,
  143. query api.DBInstanceDatabaseListInput,
  144. ) (*sqlchemy.SQuery, error) {
  145. var err error
  146. q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  147. if err != nil {
  148. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
  149. }
  150. q, err = manager.SDBInstanceResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DBInstanceFilterListInput)
  151. if err != nil {
  152. return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.OrderByExtraFields")
  153. }
  154. return q, nil
  155. }
  156. func (manager *SDBInstanceDatabaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  157. var err error
  158. q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  159. if err == nil {
  160. return q, nil
  161. }
  162. q, err = manager.SDBInstanceResourceBaseManager.QueryDistinctExtraField(q, field)
  163. if err == nil {
  164. return q, nil
  165. }
  166. return q, httperrors.ErrNotFound
  167. }
  168. func (self *SDBInstanceDatabase) GetUniqValues() jsonutils.JSONObject {
  169. return jsonutils.Marshal(map[string]string{"dbinstance_id": self.DBInstanceId})
  170. }
  171. func (manager *SDBInstanceDatabaseManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
  172. dbinstanceId, _ := data.GetString("dbinstance_id")
  173. return jsonutils.Marshal(map[string]string{"dbinstance_id": dbinstanceId})
  174. }
  175. func (manager *SDBInstanceDatabaseManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
  176. dbinstanceId, _ := values.GetString("dbinstance_id")
  177. if len(dbinstanceId) > 0 {
  178. q = q.Equals("dbinstance_id", dbinstanceId)
  179. }
  180. return q
  181. }
  182. func (manager *SDBInstanceDatabaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceDatabaseCreateInput) (*jsonutils.JSONDict, error) {
  183. for _, instance := range []string{input.DBInstance, input.DBInstanceId} {
  184. if len(instance) > 0 {
  185. input.DBInstance = instance
  186. break
  187. }
  188. }
  189. if len(input.DBInstance) == 0 {
  190. return nil, httperrors.NewMissingParameterError("dbinstance")
  191. }
  192. _instance, err := DBInstanceManager.FetchByIdOrName(ctx, userCred, input.DBInstance)
  193. if err != nil {
  194. if err == sql.ErrNoRows {
  195. return nil, httperrors.NewResourceNotFoundError("failed to found dbinstance %s", input.DBInstance)
  196. }
  197. return nil, httperrors.NewGeneralError(errors.Wrap(err, "DBInstanceManager.FetchByIdOrName"))
  198. }
  199. instance := _instance.(*SDBInstance)
  200. input.DBInstanceId = instance.Id
  201. if instance.Status != api.DBINSTANCE_RUNNING {
  202. return nil, httperrors.NewInputParameterError("DBInstance %s(%s) status is %s require status is %s", instance.Name, instance.Id, instance.Status, api.DBINSTANCE_RUNNING)
  203. }
  204. region, err := instance.GetRegion()
  205. if err != nil {
  206. return nil, err
  207. }
  208. for i, _account := range input.Accounts {
  209. account, err := instance.GetDBInstanceAccount(_account.Account)
  210. if err != nil {
  211. return nil, httperrors.NewInputParameterError("failed to found dbinstance %s(%s) account %s: %v", instance.Name, instance.Id, _account.Account, err)
  212. }
  213. input.Accounts[i].DBInstanceaccountId = account.Id
  214. }
  215. input, err = region.GetDriver().ValidateCreateDBInstanceDatabaseData(ctx, userCred, ownerId, instance, input)
  216. if err != nil {
  217. return nil, err
  218. }
  219. input.StatusStandaloneResourceCreateInput, err = manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput)
  220. if err != nil {
  221. return nil, err
  222. }
  223. return input.JSON(input), nil
  224. }
  225. func (self *SDBInstanceDatabase) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  226. self.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  227. self.StartDBInstanceDatabaseCreateTask(ctx, userCred, data.(*jsonutils.JSONDict), "")
  228. }
  229. func (self *SDBInstanceDatabase) StartDBInstanceDatabaseCreateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  230. self.SetStatus(ctx, userCred, api.DBINSTANCE_DATABASE_CREATING, "")
  231. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceDatabaseCreateTask", self, userCred, params, parentTaskId, "", nil)
  232. if err != nil {
  233. return errors.Wrap(err, "NewTask")
  234. }
  235. task.ScheduleRun(nil)
  236. return nil
  237. }
  238. func (self *SDBInstanceDatabase) GetDBInstancePrivileges() ([]SDBInstancePrivilege, error) {
  239. privileges := []SDBInstancePrivilege{}
  240. q := DBInstancePrivilegeManager.Query().Equals("dbinstancedatabase_id", self.Id)
  241. err := db.FetchModelObjects(DBInstancePrivilegeManager, q, &privileges)
  242. if err != nil {
  243. return nil, err
  244. }
  245. return privileges, nil
  246. }
  247. func (self *SDBInstanceDatabase) GetDBInstance() (*SDBInstance, error) {
  248. instance, err := DBInstanceManager.FetchById(self.DBInstanceId)
  249. if err != nil {
  250. return nil, err
  251. }
  252. return instance.(*SDBInstance), nil
  253. }
  254. func (manager *SDBInstanceDatabaseManager) FetchCustomizeColumns(
  255. ctx context.Context,
  256. userCred mcclient.TokenCredential,
  257. query jsonutils.JSONObject,
  258. objs []interface{},
  259. fields stringutils2.SSortedStrings,
  260. isList bool,
  261. ) []api.DBInstancedatabaseDetails {
  262. rows := make([]api.DBInstancedatabaseDetails, len(objs))
  263. stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  264. dbRows := manager.SDBInstanceResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  265. dbinstanceIds := make([]string, len(objs))
  266. for i := range rows {
  267. rows[i] = api.DBInstancedatabaseDetails{
  268. StatusStandaloneResourceDetails: stdRows[i],
  269. DBInstanceResourceInfo: dbRows[i],
  270. }
  271. database := objs[i].(*SDBInstanceDatabase)
  272. rows[i], _ = database.getMoreDetails(ctx, userCred, rows[i])
  273. dbinstanceIds[i] = database.DBInstanceId
  274. }
  275. dbinstances := make(map[string]SDBInstance)
  276. err := db.FetchStandaloneObjectsByIds(DBInstanceManager, dbinstanceIds, &dbinstances)
  277. if err != nil {
  278. log.Errorf("FetchStandaloneObjectsByIds fail: %v", err)
  279. return rows
  280. }
  281. virObjs := make([]interface{}, len(objs))
  282. for i := range rows {
  283. if dbinstance, ok := dbinstances[dbinstanceIds[i]]; ok {
  284. virObjs[i] = &dbinstance
  285. rows[i].ProjectId = dbinstance.ProjectId
  286. }
  287. }
  288. projRows := DBInstanceManager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, virObjs, fields, isList)
  289. for i := range rows {
  290. rows[i].ProjectizedResourceInfo = projRows[i]
  291. }
  292. return rows
  293. }
  294. func (self *SDBInstanceDatabase) getPrivilegesDetails() ([]api.DBInstancePrivilege, error) {
  295. out := []api.DBInstancePrivilege{}
  296. privileges, err := self.GetDBInstancePrivileges()
  297. if err != nil {
  298. return out, errors.Wrap(err, "GetDBInstancePrivileges")
  299. }
  300. for _, privilege := range privileges {
  301. detail, err := privilege.GetPrivilege()
  302. if err != nil {
  303. return nil, errors.Wrap(err, "GetDetailedJson")
  304. }
  305. out = append(out, detail)
  306. }
  307. return out, nil
  308. }
  309. func (self *SDBInstanceDatabase) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, out api.DBInstancedatabaseDetails) (api.DBInstancedatabaseDetails, error) {
  310. privileges, err := self.getPrivilegesDetails()
  311. if err != nil {
  312. return out, err
  313. }
  314. out.DBInstanceprivileges = privileges
  315. return out, nil
  316. }
  317. func (manager *SDBInstanceDatabaseManager) SyncDBInstanceDatabases(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, cloudDatabases []cloudprovider.ICloudDBInstanceDatabase) compare.SyncResult {
  318. lockman.LockRawObject(ctx, "dbinstance-databases", instance.Id)
  319. defer lockman.ReleaseRawObject(ctx, "dbinstance-databases", instance.Id)
  320. result := compare.SyncResult{}
  321. dbDatabases, err := instance.GetDBInstanceDatabases()
  322. if err != nil {
  323. result.Error(err)
  324. return result
  325. }
  326. removed := make([]SDBInstanceDatabase, 0)
  327. commondb := make([]SDBInstanceDatabase, 0)
  328. commonext := make([]cloudprovider.ICloudDBInstanceDatabase, 0)
  329. added := make([]cloudprovider.ICloudDBInstanceDatabase, 0)
  330. if err := compare.CompareSets(dbDatabases, cloudDatabases, &removed, &commondb, &commonext, &added); err != nil {
  331. result.Error(err)
  332. return result
  333. }
  334. for i := 0; i < len(removed); i++ {
  335. err := removed[i].RealDelete(ctx, userCred)
  336. if err != nil {
  337. result.DeleteError(err)
  338. } else {
  339. result.Delete()
  340. }
  341. }
  342. for i := 0; i < len(commondb); i++ {
  343. err := commondb[i].SyncWithCloudDBInstanceDatabase(ctx, userCred, instance, commonext[i])
  344. if err != nil {
  345. result.UpdateError(err)
  346. } else {
  347. result.Update()
  348. }
  349. }
  350. for i := 0; i < len(added); i++ {
  351. err = manager.newFromCloudDBInstanceDatabase(ctx, userCred, instance, added[i])
  352. if err != nil {
  353. result.AddError(err)
  354. } else {
  355. result.Add()
  356. }
  357. }
  358. return result
  359. }
  360. func (self *SDBInstanceDatabase) SyncWithCloudDBInstanceDatabase(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, extDatabase cloudprovider.ICloudDBInstanceDatabase) error {
  361. _, err := db.UpdateWithLock(ctx, self, func() error {
  362. self.Status = extDatabase.GetStatus()
  363. self.Name = extDatabase.GetName()
  364. self.CharacterSet = extDatabase.GetCharacterSet()
  365. return nil
  366. })
  367. if err != nil {
  368. return errors.Wrapf(err, "SyncWithCloudDBInstanceDatabase.UpdateWithLock")
  369. }
  370. return nil
  371. }
  372. func (manager *SDBInstanceDatabaseManager) newFromCloudDBInstanceDatabase(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, extDatabase cloudprovider.ICloudDBInstanceDatabase) error {
  373. lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
  374. defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
  375. database := SDBInstanceDatabase{}
  376. database.SetModelManager(manager, &database)
  377. database.Name = extDatabase.GetName()
  378. database.DBInstanceId = instance.Id
  379. database.Status = extDatabase.GetStatus()
  380. database.CharacterSet = extDatabase.GetCharacterSet()
  381. database.ExternalId = extDatabase.GetGlobalId()
  382. err := manager.TableSpec().Insert(ctx, &database)
  383. if err != nil {
  384. return errors.Wrapf(err, "newFromCloudDBInstanceDatabase.Insert")
  385. }
  386. return nil
  387. }
  388. func (self *SDBInstanceDatabase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  389. log.Infof("dbinstance database delete do nothing")
  390. return nil
  391. }
  392. func (self *SDBInstanceDatabase) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  393. return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
  394. }
  395. func (self *SDBInstanceDatabase) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  396. return self.StartDBInstanceDatabaseDeleteTask(ctx, userCred, "")
  397. }
  398. func (self *SDBInstanceDatabase) StartDBInstanceDatabaseDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  399. self.SetStatus(ctx, userCred, api.DBINSTANCE_DATABASE_DELETING, "")
  400. task, err := taskman.TaskManager.NewTask(ctx, "DBInstanceDatabaseDeleteTask", self, userCred, nil, parentTaskId, "", nil)
  401. if err != nil {
  402. return err
  403. }
  404. task.ScheduleRun(nil)
  405. return nil
  406. }
  407. func (manager *SDBInstanceDatabaseManager) ListItemExportKeys(ctx context.Context,
  408. q *sqlchemy.SQuery,
  409. userCred mcclient.TokenCredential,
  410. keys stringutils2.SSortedStrings,
  411. ) (*sqlchemy.SQuery, error) {
  412. var err error
  413. q, err = manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  414. if err != nil {
  415. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
  416. }
  417. if keys.ContainsAny(manager.SDBInstanceResourceBaseManager.GetExportKeys()...) {
  418. q, err = manager.SDBInstanceResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  419. if err != nil {
  420. return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemExportKeys")
  421. }
  422. }
  423. return q, nil
  424. }
  425. func (manager *SDBInstanceDatabaseManager) InitializeData() error {
  426. sq := DBInstanceManager.Query("id")
  427. q := manager.Query().NotIn("dbinstance_id", sq.SubQuery())
  428. databases := []SDBInstanceDatabase{}
  429. err := db.FetchModelObjects(manager, q, &databases)
  430. if err != nil {
  431. return errors.Wrapf(err, "db.FetchModelObjects")
  432. }
  433. for i := range databases {
  434. err = databases[i].RealDelete(context.Background(), nil)
  435. if err != nil {
  436. return errors.Wrapf(err, "purge %s", databases[i].Id)
  437. }
  438. }
  439. log.Debugf("SDBInstanceDatabaseManager cleaned %d dirty data.", len(databases))
  440. return nil
  441. }