useAnalyticsBucketAssociatedEntities.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import {
  3. getAnalyticsBucketPublicationName,
  4. getAnalyticsBucketS3KeyName,
  5. getAnalyticsBucketsDestinationName,
  6. } from './AnalyticsBucketDetails.utils'
  7. import { useAnalyticsBucketWrapperInstance } from './useAnalyticsBucketWrapperInstance'
  8. import { useFDWDeleteMutation } from '@/data/fdw/fdw-delete-mutation'
  9. import { useDeleteDestinationPipelineMutation } from '@/data/replication/delete-destination-pipeline-mutation'
  10. import { useReplicationDestinationsQuery } from '@/data/replication/destinations-query'
  11. import { useReplicationPipelinesQuery } from '@/data/replication/pipelines-query'
  12. import { useDeletePublicationMutation } from '@/data/replication/publication-delete-mutation'
  13. import { useReplicationPublicationsQuery } from '@/data/replication/publications-query'
  14. import { useReplicationSourcesQuery } from '@/data/replication/sources-query'
  15. import { useS3AccessKeyDeleteMutation } from '@/data/storage/s3-access-key-delete-mutation'
  16. import { useStorageCredentialsQuery } from '@/data/storage/s3-access-key-query'
  17. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  18. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  19. /**
  20. * Returns all the data that's associated to a specified analytics bucket (e.g publications, S3 keys, etc)
  21. * Used for cleaning up analytics bucket after deletion
  22. */
  23. export const useAnalyticsBucketAssociatedEntities = (
  24. { projectRef, bucketId }: { projectRef?: string; bucketId?: string },
  25. options: { enabled: boolean } = { enabled: true }
  26. ) => {
  27. const { can: canReadS3Credentials } = useAsyncCheckPermissions(
  28. PermissionAction.STORAGE_ADMIN_READ,
  29. '*'
  30. )
  31. const {
  32. data: icebergWrapper,
  33. meta: icebergWrapperMeta,
  34. isLoading: isLoadingWrapperInstance,
  35. } = useAnalyticsBucketWrapperInstance({ bucketId }, { enabled: options.enabled })
  36. const { data: s3AccessKeys } = useStorageCredentialsQuery(
  37. { projectRef },
  38. { enabled: canReadS3Credentials && options.enabled }
  39. )
  40. const s3AccessKey = (s3AccessKeys?.data ?? []).find(
  41. (x) => x.description === getAnalyticsBucketS3KeyName(bucketId ?? '')
  42. )
  43. const { data: sourcesData } = useReplicationSourcesQuery(
  44. { projectRef },
  45. { enabled: options.enabled }
  46. )
  47. const sourceId = sourcesData?.sources.find((s) => s.name === projectRef)?.id
  48. const { data: publications = [] } = useReplicationPublicationsQuery(
  49. { projectRef, sourceId },
  50. { enabled: options.enabled }
  51. )
  52. const publication = publications.find(
  53. (p) => p.name === getAnalyticsBucketPublicationName(bucketId ?? '')
  54. )
  55. const { data: destinationsData } = useReplicationDestinationsQuery({ projectRef })
  56. const destinations = destinationsData?.destinations ?? []
  57. const destination = destinations.find(
  58. (x) => x.name === getAnalyticsBucketsDestinationName(bucketId ?? '')
  59. )
  60. const { data: pipelines } = useReplicationPipelinesQuery({ projectRef })
  61. const pipeline = pipelines?.pipelines.find((x) => x.config.publication_name === publication?.name)
  62. return {
  63. icebergWrapper,
  64. icebergWrapperMeta,
  65. s3AccessKey,
  66. sourceId,
  67. publication,
  68. pipeline,
  69. destination,
  70. isLoadingWrapperInstance,
  71. }
  72. }
  73. export const useAnalyticsBucketDeleteCleanUp = ({
  74. projectRef,
  75. bucketId,
  76. }: {
  77. projectRef?: string
  78. bucketId?: string
  79. }) => {
  80. const { data: project } = useSelectedProjectQuery()
  81. const {
  82. icebergWrapper,
  83. icebergWrapperMeta,
  84. s3AccessKey,
  85. publication,
  86. sourceId,
  87. pipeline,
  88. destination,
  89. } = useAnalyticsBucketAssociatedEntities({ projectRef, bucketId: bucketId })
  90. // Default error handlers from all mutations will be silenced
  91. const { mutateAsync: deleteFDW, isPending: isDeletingWrapper } = useFDWDeleteMutation({
  92. onError: () => {},
  93. })
  94. const { mutateAsync: deleteS3AccessKey, isPending: isDeletingKey } = useS3AccessKeyDeleteMutation(
  95. { onError: () => {} }
  96. )
  97. const { mutateAsync: deletePublication, isPending: isDeletingPublication } =
  98. useDeletePublicationMutation({ onError: () => {} })
  99. const { mutateAsync: deletePipeline, isPending: isDeletingPipeline } =
  100. useDeleteDestinationPipelineMutation({ onError: () => {} })
  101. const isDeleting =
  102. isDeletingWrapper || isDeletingKey || isDeletingPublication || isDeletingPipeline
  103. const mutateAsync = async () => {
  104. const connectionString = project?.connectionString
  105. if (!!icebergWrapper && !!icebergWrapperMeta) {
  106. try {
  107. await deleteFDW({
  108. projectRef,
  109. connectionString,
  110. wrapper: icebergWrapper,
  111. wrapperMeta: icebergWrapperMeta,
  112. })
  113. } catch (error: any) {
  114. console.error(`Failed to delete iceberg wrapper for ${bucketId}:`, error.message)
  115. }
  116. } else {
  117. console.warn(`Unable to find and delete iceberg wrapper for ${bucketId}`)
  118. }
  119. if (!!s3AccessKey) {
  120. try {
  121. await deleteS3AccessKey({ projectRef, id: s3AccessKey.id })
  122. } catch (error: any) {
  123. console.error(`Failed to delete S3 access key for: ${bucketId}`, error.message)
  124. }
  125. } else {
  126. console.warn(`Unable to find and delete corresponding S3 access key for ${bucketId}`)
  127. }
  128. if (!!pipeline && !!destination) {
  129. try {
  130. await deletePipeline({
  131. projectRef,
  132. destinationId: destination?.id,
  133. pipelineId: pipeline.id,
  134. })
  135. } catch (error: any) {
  136. console.error(`Failed to delete replication pipeline for: ${bucketId}`, error.message)
  137. }
  138. } else {
  139. console.warn(`Unable to find and delete replication pipeline for ${bucketId}`)
  140. }
  141. if (!!publication && !!sourceId) {
  142. try {
  143. await deletePublication({ projectRef, sourceId, publicationName: publication.name })
  144. } catch (error: any) {
  145. console.error(`Failed to delete replication publication for: ${bucketId}`, error.message)
  146. }
  147. } else {
  148. console.warn(`Unable to find and delete replication publication for ${bucketId}`)
  149. }
  150. }
  151. return { mutateAsync, isPending: isDeleting }
  152. }