(orgID string, mutate func(*configstore.ManagedWarehouse) error)
| 352 | } |
| 353 | |
| 354 | func (s *gormAPIStore) DeleteOrg(name string) (bool, error) { |
| 355 | returnRows := int64(0) |
| 356 | err := s.db().Transaction(func(tx *gorm.DB) error { |
| 357 | if err := configstore.LockOrgConnectionAdmissionTx(tx, name); err != nil { |
| 358 | return err |
| 359 | } |
| 360 | |
| 361 | // Deleting an org while a managed warehouse row is in a non-terminal |
| 362 | // state would leak the Duckling CR + AWS infra behind it, so those |
| 363 | // still block deletion. But deprovisioning does NOT remove the |
| 364 | // warehouse row — the provisioner tears the infra down and leaves the |
| 365 | // row in the terminal "deleted" state (controller.go reconcileDeleting). |
| 366 | // A "deleted" row means the infra is gone, so cascade it away here and |
| 367 | // let the org (and its unique database_name) be released. Without this, |
| 368 | // a fully deprovisioned org could never be deleted and its |
| 369 | // database_name would be squatted forever. |
| 370 | var liveWarehouses int64 |
| 371 | if err := tx.Model(&configstore.ManagedWarehouse{}). |
| 372 | Where("org_id = ? AND state <> ?", name, configstore.ManagedWarehouseStateDeleted). |
| 373 | Count(&liveWarehouses).Error; err != nil { |
| 374 | return err |
| 375 | } |
| 376 | if liveWarehouses > 0 { |
| 377 | return errWarehouseStillExists |
| 378 | } |
| 379 | if err := tx.Where("org_id = ?", name).Delete(&configstore.ManagedWarehouse{}).Error; err != nil { |
| 380 | return err |
| 381 | } |
| 382 | if err := tx.Where("org_id = ?", name).Delete(&configstore.OrgUser{}).Error; err != nil { |
| 383 | return err |
| 384 | } |
| 385 | // Org deletion is the lifecycle boundary for otherwise durable grant |
| 386 | // audit rows. Retaining them could reactivate an old secret if this org |
| 387 | // name were created again. |
| 388 | if err := tx.Where("org_id = ?", name).Delete(&configstore.ServiceGrant{}).Error; err != nil { |
| 389 | return err |
| 390 | } |
| 391 | result := tx.Where("name = ?", name).Delete(&configstore.Org{}) |
| 392 | if result.Error != nil { |
| 393 | return result.Error |
| 394 | } |
| 395 | returnRows = result.RowsAffected |
| 396 | return nil |
| 397 | }) |
| 398 | if err != nil { |
| 399 | return false, err |
| 400 | } |
| 401 | return returnRows > 0, nil |
| 402 | } |
| 403 | |
| 404 | // errOrgTeamExists distinguishes the (org, team) primary-key conflict from |
| 405 | // the schema-name conflict on the admin create endpoint — the admin surface |
| 406 | // never overwrites an existing row (that's the internal provisioning |
nothing calls this directly
no test coverage detected