From bd44d0558fbfdfed42e12d0b3196f34f215dd93e Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 28 May 2025 14:45:11 -0400 Subject: [PATCH] Delete old multitenancy migration script --- script/migrate-to-multi-tenant | 271 --------------------------------- 1 file changed, 271 deletions(-) delete mode 100755 script/migrate-to-multi-tenant diff --git a/script/migrate-to-multi-tenant b/script/migrate-to-multi-tenant deleted file mode 100755 index 79db5c0e0..000000000 --- a/script/migrate-to-multi-tenant +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env ruby - -require_relative "../config/environment" - -class EnactTenanting - CURRENT_DOMAIN = "https://fizzy.37signals.com" - TENANTED_DOMAIN = Rails.env.local? ? "http://%{tenant}.fizzy.localhost:3006" : "https://%{tenant}.fizzy.37signals.com" - - PROJECT_MAPPING = { - 693169841 => "37s", # Writebook improvements - 693169850 => "37s", # Fizzy: Issues - 693169853 => "37s", # Fizzy: 💡 IDEAS - 693169858 => "37s", # Know It All: 💡 IDEAS - 693169859 => "37s", # Cycle 1: BC4 Client access for templates - 693169860 => "37s", # Know It All: Issues - 693169862 => "37s", # Active Record Tenanting - 693169863 => "37s", # Cycle 1: BC4 Hilltop View - 693169865 => "37s", # [BC iOS] Search refactor - 693169867 => "37s", # File icons refactor - 693169870 => "37s", # HEY Preload Replies - 693169872 => "37s", # [BC4 Android] Search Refactor - 693169873 => "37s", # BC4 - 693169874 => "37s", # [HEY] ContentFilter pipeline rewrite - 693169875 => "37s", # [Hey Calendar Android] Search - 693169876 => "37s", # [HEY Calendar iOS] Search - 693169877 => "37s", # [BC4] Turbo for comment and answer forms - - 693169842 => "dev", # Foobar - 693169843 => "dev", # Test - 693169851 => "dev", # Kevin - 693169861 => "dev", # Testing space - 693169869 => "dev", # Flower ideas - 693169871 => "dev", # Mike's TODOs - - 693169856 => "qa" # QA Exploration - } - - TENANTS = PROJECT_MAPPING.values.uniq - - attr_reader :creation_counter, :update_counter - - def initialize - @creation_counter = {} - @update_counter = {} - end - - def up - setup - destroy_tenants - - safety_check - - copy_accounts_et_al - copy_buckets_et_al - copy_bubbles_et_al - copy_filters - copy_active_storage - - cross_check - - update_action_text_urls - - pp [ "updated:", update_counter ] - - hardlink_active_storage - end - - def setup - ApplicationRecord.connects_to shards: { untenanted: { reading: :primary_original } } - end - - def with_original_db(&block) - ApplicationRecord.connected_to(role: :reading, shard: :untenanted, &block) - end - - def safety_check - buckets = with_original_db { Bucket.all.to_a } - - unless buckets.map(&:id).sort == PROJECT_MAPPING.keys.sort - unknown_buckets = buckets.map(&:id) - PROJECT_MAPPING.keys - missing_buckets = PROJECT_MAPPING.keys - buckets.map(&:id) - - raise "Surprising buckets. unknown #{unknown_buckets.inspect}, missing #{missing_buckets.inspect}" - end - end - - def copy_accounts_et_al - account = with_original_db { Account.first } - users = with_original_db { User.all.to_a } - workflows = with_original_db { account.workflows.to_a } - workflow_stages = with_original_db { workflows.flat_map(&:stages) } - tags = with_original_db { account.tags.to_a } - - TENANTS.each do |tenant| - ApplicationRecord.with_tenant(tenant) do - Account.create! name: tenant, id: account.id - - upsert_all users - upsert_all workflows - upsert_all workflow_stages - upsert_all tags - end - end - end - - def copy_buckets_et_al - PROJECT_MAPPING.each do |bucket_id, tenant| - bucket = with_original_db { Bucket.where(id: bucket_id).first } - accesses = with_original_db { bucket.accesses.to_a } - subscriptions = with_original_db { bucket.subscriptions.to_a } - - ApplicationRecord.with_tenant(tenant) do - upsert_all bucket - upsert_all accesses - upsert_all subscriptions - end - end - end - - def copy_bubbles_et_al - PROJECT_MAPPING.each do |bucket_id, tenant| - bubbles = with_original_db { Bucket.find(bucket_id).bubbles.to_a } - assignments = with_original_db { bubbles.flat_map(&:assignments) } - pops = with_original_db { bubbles.filter_map(&:pop) } - notifications = with_original_db { bubbles.flat_map(&:notifications) } - events = with_original_db { bubbles.flat_map(&:events) } - taggings = with_original_db { bubbles.flat_map(&:taggings) } - watches = with_original_db { bubbles.flat_map(&:watches) } - messages = with_original_db { bubbles.flat_map(&:messages) } - messageables = with_original_db { messages.filter_map(&:messageable) } - comments = messageables.select { _1.is_a?(Comment) } - markdowns = with_original_db { comments.map(&:markdown_body) } - reactions = with_original_db { comments.flat_map(&:reactions) } - - ApplicationRecord.with_tenant(tenant) do - upsert_all bubbles - upsert_all assignments - upsert_all pops - upsert_all taggings - upsert_all watches - messageables.group_by(&:class).each do |klass, klass_messageables| - upsert_all klass_messageables - end - upsert_all markdowns - upsert_all reactions - upsert_all messages - upsert_all events - upsert_all notifications - end - end - end - - def copy_filters - creation_counter["Filter"] = 0 - TENANTS.each do |tenant| - buckets = ApplicationRecord.with_tenant(tenant) { Bucket.all.to_a } - - filters = with_original_db do - Filter.all.filter_map do |filter| # hah no pun intended - next unless filter.buckets.empty? || buckets.any? { |b| filter.buckets.include?(b) } - - filter.attributes.merge(filter.as_params) - end - end - - ApplicationRecord.with_tenant(tenant) do - filters.each do |attr| - Filter.create! attr - end - end - creation_counter["Filter"] += filters.length - end - end - - def copy_active_storage - attachments = with_original_db { ActiveStorage::Attachment.all.to_a } - blobs = with_original_db { ActiveStorage::Blob.all.to_a } - - TENANTS.each do |tenant| - ApplicationRecord.with_tenant(tenant) do - upsert_all blobs - upsert_all attachments - end - end - end - - def destroy_tenants - TENANTS.each do |tenant| - ApplicationRecord.destroy_tenant(tenant) - end - FileUtils.rm_rf "storage/tenants" - end - - def cross_check - pp [ "created:", creation_counter ] - - with_original_db do - assert_count User, User.count * TENANTS.length - assert_count Workflow, Workflow.count * TENANTS.length - assert_count Workflow::Stage, Workflow::Stage.count * TENANTS.length - assert_count Tag, Tag.count * TENANTS.length - - assert_count Bucket, Bucket.count - assert_count Access, Access.count - assert_count Subscription, Subscription.count - - assert_count Bubble, Bubble.count - assert_count Assignment, Assignment.count - assert_count Pop, Pop.count - assert_count EventSummary, EventSummary.count - assert_count Comment, Comment.count - assert_count Reaction, Reaction.count - assert_count Message, Message.count - assert_count Tagging, Tagging.count - assert_count Watch, Watch.count - - assert_count Event, Event.count - assert_count Notification, Notification.count - - assert_count ActiveStorage::Attachment, ActiveStorage::Attachment.count * TENANTS.length - assert_count ActiveStorage::Blob, ActiveStorage::Blob.count * TENANTS.length - - raise "Filter count is off" unless creation_counter["Filter"] >= Filter.count - end - end - - def update_action_text_urls - raise "No more markdown" - end - - def hardlink_active_storage - files = Dir.glob("storage/files/*/*/*").map { _1.split("/")[2..].join("/") } - - TENANTS.each do |tenant| - ApplicationRecord.with_tenant(tenant) do - destdir = ActiveStorage::Blob.service.root - - files.each do |file| - FileUtils.mkdir_p File.join(destdir, File.dirname(file)) - FileUtils.ln File.join("storage/files", file), File.join(destdir, file) - end - end - end - end - - def upsert_all(originals) - originals = Array(originals) - return if originals.empty? - - klass = originals.first.class - - result = klass.upsert_all(originals.collect(&:attributes)) - raise "Error upserting" unless result.rows.length == originals.length - - creation_counter[klass.name] ||= 0 - creation_counter[klass.name] += originals.length - - nil - end - - def assert_count(klass, expected) - actual = creation_counter[klass.name] - unless actual == expected - raise "#{klass} count is off: expected #{expected}, got #{actual}" - end - end -end - -EnactTenanting.new.up - -exit 0