From b31d0afee764aeed553b276ce161bdf232ff5672 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre <dbalexandre@gmail.com>
Date: Mon, 21 Mar 2022 19:58:12 -0300
Subject: [PATCH] Geo migrations settings are included by default

Changelog: changed
EE: true
---
 config/application.rb                         |  17 +-
 .../lib/gitlab/patch/database_config_spec.rb  | 522 ++++++++++++++++++
 .../patch/legacy_database_config_spec.rb      | 370 -------------
 ..._database_config.rb => database_config.rb} |  41 +-
 ...config_spec.rb => database_config_spec.rb} |   2 +-
 5 files changed, 558 insertions(+), 394 deletions(-)
 create mode 100644 ee/spec/lib/gitlab/patch/database_config_spec.rb
 delete mode 100644 ee/spec/lib/gitlab/patch/legacy_database_config_spec.rb
 rename lib/gitlab/patch/{legacy_database_config.rb => database_config.rb} (60%)
 rename spec/lib/gitlab/patch/{legacy_database_config_spec.rb => database_config_spec.rb} (98%)

diff --git a/config/application.rb b/config/application.rb
index 76541daa9e19d..b07af18d9c929 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -69,18 +69,19 @@ class Application < Rails::Application
     require_dependency Rails.root.join('lib/gitlab/middleware/handle_malformed_strings')
     require_dependency Rails.root.join('lib/gitlab/middleware/rack_multipart_tempfile_factory')
     require_dependency Rails.root.join('lib/gitlab/runtime')
-    require_dependency Rails.root.join('lib/gitlab/patch/legacy_database_config')
+    require_dependency Rails.root.join('lib/gitlab/patch/database_config')
     require_dependency Rails.root.join('lib/gitlab/exceptions_app')
 
     config.exceptions_app = Gitlab::ExceptionsApp.new(Rails.public_path)
 
-    # To be removed in 15.0
-    # This preload is needed to convert legacy `database.yml`
-    # from `production: adapter: postgresql`
-    # into a `production: main: adapter: postgresql`
-    unless Gitlab::Utils.to_boolean(ENV['SKIP_DATABASE_CONFIG_VALIDATION'], default: false)
-      config.class.prepend(::Gitlab::Patch::LegacyDatabaseConfig)
-    end
+    # This preload is required to:
+    #
+    # 1. Convert legacy `database.yml`;
+    # 2. Include Geo post-deployment migrations settings;
+    #
+    # TODO: In 15.0, this preload can be wrapped in a Gitlab.ee block
+    #       since we don't need to convert legacy `database.yml` anymore.
+    config.class.prepend(::Gitlab::Patch::DatabaseConfig)
 
     # Settings in config/environments/* take precedence over those specified here.
     # Application configuration should go into files in config/initializers
diff --git a/ee/spec/lib/gitlab/patch/database_config_spec.rb b/ee/spec/lib/gitlab/patch/database_config_spec.rb
new file mode 100644
index 0000000000000..5095a20d4b69c
--- /dev/null
+++ b/ee/spec/lib/gitlab/patch/database_config_spec.rb
@@ -0,0 +1,522 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Patch::DatabaseConfig do
+  describe '#load_geo_database_yaml' do
+    let(:configuration) { Rails::Application::Configuration.new(Rails.root) }
+
+    context 'when config/database_geo.yml does not exist' do
+      before do
+        allow(File).to receive(:exist?).and_call_original
+        allow(File).to receive(:exist?).with(Rails.root.join("config/database_geo.yml")).and_return(false)
+      end
+
+      it 'returns an empty hash' do
+        expect(configuration.load_geo_database_yaml).to eq({})
+      end
+    end
+
+    context 'when config/database_geo.yml exists' do
+      shared_examples 'hash containing geo: connection name' do
+        it 'returns a hash containing geo:' do
+          expect(configuration.load_geo_database_yaml).to match(
+            "production" => { "geo" => a_hash_including("adapter") },
+            "development" => { "geo" => a_hash_including("adapter" => "postgresql") },
+            "test" => { "geo" => a_hash_including("adapter" => "postgresql") }
+          )
+        end
+      end
+
+      before do
+        allow(Pathname)
+          .to receive(:new)
+          .and_call_original
+
+        allow(Pathname)
+          .to receive(:new).with(Rails.root.join('config/database_geo.yml'))
+          .and_return(instance_double('Pathname', read: database_geo_yml))
+      end
+
+      context 'when config/database_geo.yml use a new syntax' do
+        let(:database_geo_yml) do
+          <<-EOS
+            production:
+              geo:
+                adapter: postgresql
+                encoding: unicode
+                database: gitlabhq_geo_production
+                username: git
+                password: "secure password"
+                host: localhost
+
+            development:
+              geo:
+                adapter: postgresql
+                encoding: unicode
+                database: gitlabhq_geo_development
+                username: postgres
+                password: "secure password"
+                host: localhost
+                variables:
+                  statement_timeout: 15s
+
+            test: &test
+              geo:
+                adapter: postgresql
+                encoding: unicode
+                database: gitlabhq_geo_test
+                username: postgres
+                password:
+                host: localhost
+                prepared_statements: false
+                variables:
+                  statement_timeout: 15s
+          EOS
+        end
+
+        include_examples 'hash containing geo: connection name'
+      end
+
+      context 'when config/database_geo.yml use a legacy syntax' do
+        let(:database_geo_yml) do
+          <<-EOS
+            production:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_geo_production
+              username: git
+              password: "secure password"
+              host: localhost
+
+            development:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_geo_development
+              username: postgres
+              password: "secure password"
+              host: localhost
+              variables:
+                statement_timeout: 15s
+
+            test: &test
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_geo_test
+              username: postgres
+              password:
+              host: localhost
+              prepared_statements: false
+              variables:
+                statement_timeout: 15s
+          EOS
+        end
+
+        include_examples 'hash containing geo: connection name'
+      end
+    end
+  end
+
+  describe '#database_configuration' do
+    let(:configuration) { Rails::Application::Configuration.new(Rails.root) }
+
+    before do
+      # The `AS::ConfigurationFile` calls `read` in `def initialize`
+      # thus we cannot use `allow_next_instance_of`
+      # rubocop:disable RSpec/AnyInstanceOf
+      allow_any_instance_of(ActiveSupport::ConfigurationFile)
+        .to receive(:read).with(Rails.root.join('config/database.yml')).and_return(database_yml)
+      # rubocop:enable RSpec/AnyInstanceOf
+    end
+
+    shared_examples 'hash containing main: connection name' do
+      it 'returns a hash containing only main:' do
+        database_configuration = configuration.database_configuration
+
+        expect(database_configuration).to match(
+          "production" => { "main" => a_hash_including("adapter") },
+          "development" => { "main" => a_hash_including("adapter" => "postgresql") },
+          "test" => { "main" => a_hash_including("adapter" => "postgresql") }
+        )
+      end
+    end
+
+    shared_examples 'hash containing both main: and geo: connection names' do
+      it 'returns a hash containing both main: and geo:' do
+        database_configuration = configuration.database_configuration
+
+        expect(database_configuration).to match(
+          "production" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter", "migrations_paths" => ["ee/db/geo/migrate", "ee/db/geo/post_migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") },
+          "development" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql", "migrations_paths" => ["ee/db/geo/migrate", "ee/db/geo/post_migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") },
+          "test" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql", "migrations_paths" => ["ee/db/geo/migrate", "ee/db/geo/post_migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") }
+        )
+      end
+
+      context 'when SKIP_POST_DEPLOYMENT_MIGRATIONS environment variable set' do
+        before do
+          stub_env('SKIP_POST_DEPLOYMENT_MIGRATIONS', 'true')
+        end
+
+        it 'does not include Geo post deployment migrations path' do
+          database_configuration = configuration.database_configuration
+
+          expect(database_configuration).to match(
+            "production" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter", "migrations_paths" => ["ee/db/geo/migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") },
+            "development" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql", "migrations_paths" => ["ee/db/geo/migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") },
+            "test" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql", "migrations_paths" => ["ee/db/geo/migrate"], "schema_migrations_path" => "ee/db/geo/schema_migrations") }
+          )
+        end
+      end
+    end
+
+    context 'when config/database_geo.yml does not exist' do
+      before do
+        allow(File).to receive(:exist?).and_call_original
+        allow(File).to receive(:exist?).with(Rails.root.join("config/database_geo.yml")).and_return(false)
+      end
+
+      context 'when config/database.yml use a new syntax' do
+        context 'and does not contain Geo settings' do
+          let(:database_yml) do
+            <<-EOS
+              production:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+
+              development:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+
+              test: &test
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+            EOS
+          end
+
+          include_examples 'hash containing main: connection name'
+        end
+
+        context 'contains Geo settings' do
+          let(:database_yml) do
+            <<-EOS
+              production:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+
+              development:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+
+              test: &test
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+            EOS
+          end
+
+          include_examples 'hash containing both main: and geo: connection names'
+        end
+      end
+
+      context 'when config/database.yml use a legacy syntax' do
+        let(:database_yml) do
+          <<-EOS
+            production:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_production
+              username: git
+              password: "secure password"
+              host: localhost
+
+            development:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_development
+              username: postgres
+              password: "secure password"
+              host: localhost
+              variables:
+                statement_timeout: 15s
+
+            test: &test
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_test
+              username: postgres
+              password:
+              host: localhost
+              prepared_statements: false
+              variables:
+                statement_timeout: 15s
+          EOS
+        end
+
+        include_examples 'hash containing main: connection name'
+
+        it 'configuration is legacy' do
+          configuration.database_configuration
+
+          expect(configuration.uses_legacy_database_config).to eq(true)
+        end
+      end
+    end
+
+    context 'when config/database_geo.yml exists' do
+      let(:database_geo_yml) do
+        <<-EOS
+          production:
+            adapter: postgresql
+            encoding: unicode
+            database: gitlabhq_geo_production
+            username: git
+            password: "secure password"
+            host: localhost
+
+          development:
+            adapter: postgresql
+            encoding: unicode
+            database: gitlabhq_geo_development
+            username: postgres
+            password: "secure password"
+            host: localhost
+
+          staging:
+            adapter: postgresql
+            encoding: unicode
+            database: gitlabhq_geo_staging
+            username: git
+            password: "secure password"
+            host: localhost
+
+          test: &test
+            adapter: postgresql
+            encoding: unicode
+            database: gitlabhq_geo_test
+            username: postgres
+            password:
+            host: localhost
+        EOS
+      end
+
+      before do
+        # The `AS::ConfigurationFile` calls `read` in `def initialize`
+        # thus we cannot use `allow_next_instance_of`
+        # rubocop:disable RSpec/AnyInstanceOf
+        allow_any_instance_of(ActiveSupport::ConfigurationFile)
+          .to receive(:read).with(Rails.root.join('config/database_geo.yml')).and_return(database_geo_yml)
+        # rubocop:enable RSpec/AnyInstanceOf
+      end
+
+      context 'when config/database.yml use a new syntax' do
+        context 'and does not contain Geo setting' do
+          let(:database_yml) do
+            <<-EOS
+              production:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+
+              development:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+
+              test: &test
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+            EOS
+          end
+
+          include_examples 'hash containing both main: and geo: connection names'
+        end
+
+        context 'contains Geo setting' do
+          let(:database_yml) do
+            <<-EOS
+              production:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_production
+                  username: git
+                  password: "secure password"
+                  host: localhost
+
+              development:
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_development
+                  username: postgres
+                  password: "secure password"
+                  host: localhost
+                  variables:
+                    statement_timeout: 15s
+
+              test: &test
+                main:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+                geo:
+                  adapter: postgresql
+                  encoding: unicode
+                  database: gitlabhq_geo_test
+                  username: postgres
+                  password:
+                  host: localhost
+                  prepared_statements: false
+                  variables:
+                    statement_timeout: 15s
+            EOS
+          end
+
+          include_examples 'hash containing both main: and geo: connection names'
+        end
+      end
+
+      context 'when config/database.yml use a legacy syntax' do
+        let(:database_yml) do
+          <<-EOS
+            production:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_production
+              username: git
+              password: "secure password"
+              host: localhost
+
+            development:
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_development
+              username: postgres
+              password: "secure password"
+              host: localhost
+              variables:
+                statement_timeout: 15s
+
+            test: &test
+              adapter: postgresql
+              encoding: unicode
+              database: gitlabhq_test
+              username: postgres
+              password:
+              host: localhost
+              prepared_statements: false
+              variables:
+                statement_timeout: 15s
+          EOS
+        end
+
+        include_examples 'hash containing both main: and geo: connection names'
+      end
+    end
+  end
+end
diff --git a/ee/spec/lib/gitlab/patch/legacy_database_config_spec.rb b/ee/spec/lib/gitlab/patch/legacy_database_config_spec.rb
deleted file mode 100644
index e8bba0e1d5b6a..0000000000000
--- a/ee/spec/lib/gitlab/patch/legacy_database_config_spec.rb
+++ /dev/null
@@ -1,370 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Patch::LegacyDatabaseConfig do
-  describe '#load_geo_database_yaml' do
-    let(:configuration) { Rails::Application::Configuration.new(Rails.root) }
-
-    context 'when config/database_geo.yml does not exist' do
-      before do
-        allow(File).to receive(:exist?).and_call_original
-        allow(File).to receive(:exist?).with(Rails.root.join("config/database_geo.yml")).and_return(false)
-      end
-
-      it 'returns an empty hash' do
-        expect(configuration.load_geo_database_yaml).to eq({})
-      end
-    end
-
-    context 'when config/database_geo.yml exists' do
-      shared_examples 'hash containing geo: connection name' do
-        it 'returns a hash containing geo:' do
-          expect(configuration.load_geo_database_yaml).to match(
-            "production" => { "geo" => a_hash_including("adapter") },
-            "development" => { "geo" => a_hash_including("adapter" => "postgresql") },
-            "test" => { "geo" => a_hash_including("adapter" => "postgresql") }
-          )
-        end
-      end
-
-      before do
-        allow(Pathname)
-          .to receive(:new)
-          .and_call_original
-
-        allow(Pathname)
-          .to receive(:new).with(Rails.root.join('config/database_geo.yml'))
-          .and_return(double(read: database_geo_yml))
-      end
-
-      context 'when config/database_geo.yml use a new syntax' do
-        let(:database_geo_yml) do
-          <<-EOS
-            production:
-              geo:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_geo_production
-                username: git
-                password: "secure password"
-                host: localhost
-
-            development:
-              geo:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_geo_development
-                username: postgres
-                password: "secure password"
-                host: localhost
-                variables:
-                  statement_timeout: 15s
-
-            test: &test
-              geo:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_geo_test
-                username: postgres
-                password:
-                host: localhost
-                prepared_statements: false
-                variables:
-                  statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing geo: connection name'
-      end
-
-      context 'when config/database_geo.yml use a legacy syntax' do
-        let(:database_geo_yml) do
-          <<-EOS
-            production:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_geo_production
-              username: git
-              password: "secure password"
-              host: localhost
-
-            development:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_geo_development
-              username: postgres
-              password: "secure password"
-              host: localhost
-              variables:
-                statement_timeout: 15s
-
-            test: &test
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_geo_test
-              username: postgres
-              password:
-              host: localhost
-              prepared_statements: false
-              variables:
-                statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing geo: connection name'
-      end
-    end
-  end
-
-  describe '#database_configuration' do
-    let(:configuration) { Rails::Application::Configuration.new(Rails.root) }
-
-    before do
-      # The `AS::ConfigurationFile` calls `read` in `def initialize`
-      # thus we cannot use `allow_next_instance_of`
-      # rubocop:disable RSpec/AnyInstanceOf
-      allow_any_instance_of(ActiveSupport::ConfigurationFile)
-        .to receive(:read).with(Rails.root.join('config/database.yml')).and_return(database_yml)
-      # rubocop:enable RSpec/AnyInstanceOf
-    end
-
-    context 'when config/database_geo.yml does not exist' do
-      shared_examples 'hash containing main: connection name' do
-        it 'returns a hash containing only main:' do
-          database_configuration = configuration.database_configuration
-
-          expect(database_configuration).to match(
-            "production" => { "main" => a_hash_including("adapter") },
-            "development" => { "main" => a_hash_including("adapter" => "postgresql") },
-            "test" => { "main" => a_hash_including("adapter" => "postgresql") }
-          )
-        end
-      end
-
-      before do
-        allow(File).to receive(:exist?).and_call_original
-        allow(File).to receive(:exist?).with(Rails.root.join("config/database_geo.yml")).and_return(false)
-      end
-
-      context 'when config/database.yml use a new syntax' do
-        let(:database_yml) do
-          <<-EOS
-            production:
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_production
-                username: git
-                password: "secure password"
-                host: localhost
-
-            development:
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_development
-                username: postgres
-                password: "secure password"
-                host: localhost
-                variables:
-                  statement_timeout: 15s
-
-            test: &test
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_test
-                username: postgres
-                password:
-                host: localhost
-                prepared_statements: false
-                variables:
-                  statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing main: connection name'
-      end
-
-      context 'when config/database.yml use a legacy syntax' do
-        let(:database_yml) do
-          <<-EOS
-            production:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_production
-              username: git
-              password: "secure password"
-              host: localhost
-
-            development:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_development
-              username: postgres
-              password: "secure password"
-              host: localhost
-              variables:
-                statement_timeout: 15s
-
-            test: &test
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_test
-              username: postgres
-              password:
-              host: localhost
-              prepared_statements: false
-              variables:
-                statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing main: connection name'
-
-        it 'configuration is legacy' do
-          configuration.database_configuration
-
-          expect(configuration.uses_legacy_database_config).to eq(true)
-        end
-      end
-    end
-
-    context 'when config/database_geo.yml exists' do
-      let(:database_geo_yml) do
-        <<-EOS
-          production:
-            adapter: postgresql
-            encoding: unicode
-            database: gitlabhq_geo_production
-            username: git
-            password: "secure password"
-            host: localhost
-
-          development:
-            adapter: postgresql
-            encoding: unicode
-            database: gitlabhq_geo_development
-            username: postgres
-            password: "secure password"
-            host: localhost
-
-          staging:
-            adapter: postgresql
-            encoding: unicode
-            database: gitlabhq_geo_staging
-            username: git
-            password: "secure password"
-            host: localhost
-
-          test: &test
-            adapter: postgresql
-            encoding: unicode
-            database: gitlabhq_geo_test
-            username: postgres
-            password:
-            host: localhost
-        EOS
-      end
-
-      shared_examples 'hash containing both main: and geo: connection names' do
-        it 'returns a hash containing both main: and geo:' do
-          database_configuration = configuration.database_configuration
-
-          expect(database_configuration).to match(
-            "production" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter") },
-            "development" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql") },
-            "test" => { "main" => a_hash_including("adapter"), "geo" => a_hash_including("adapter" => "postgresql") }
-          )
-        end
-      end
-
-      before do
-        # The `AS::ConfigurationFile` calls `read` in `def initialize`
-        # thus we cannot use `allow_next_instance_of`
-        # rubocop:disable RSpec/AnyInstanceOf
-        allow_any_instance_of(ActiveSupport::ConfigurationFile)
-          .to receive(:read).with(Rails.root.join('config/database_geo.yml')).and_return(database_geo_yml)
-        # rubocop:enable RSpec/AnyInstanceOf
-      end
-
-      context 'when config/database.yml use a new syntax' do
-        let(:database_yml) do
-          <<-EOS
-            production:
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_production
-                username: git
-                password: "secure password"
-                host: localhost
-
-            development:
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_development
-                username: postgres
-                password: "secure password"
-                host: localhost
-                variables:
-                  statement_timeout: 15s
-
-            test: &test
-              main:
-                adapter: postgresql
-                encoding: unicode
-                database: gitlabhq_test
-                username: postgres
-                password:
-                host: localhost
-                prepared_statements: false
-                variables:
-                  statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing both main: and geo: connection names'
-      end
-
-      context 'when config/database.yml use a legacy syntax' do
-        let(:database_yml) do
-          <<-EOS
-            production:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_production
-              username: git
-              password: "secure password"
-              host: localhost
-
-            development:
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_development
-              username: postgres
-              password: "secure password"
-              host: localhost
-              variables:
-                statement_timeout: 15s
-
-            test: &test
-              adapter: postgresql
-              encoding: unicode
-              database: gitlabhq_test
-              username: postgres
-              password:
-              host: localhost
-              prepared_statements: false
-              variables:
-                statement_timeout: 15s
-          EOS
-        end
-
-        include_examples 'hash containing both main: and geo: connection names'
-      end
-    end
-  end
-end
diff --git a/lib/gitlab/patch/legacy_database_config.rb b/lib/gitlab/patch/database_config.rb
similarity index 60%
rename from lib/gitlab/patch/legacy_database_config.rb
rename to lib/gitlab/patch/database_config.rb
index 6040f737c75f7..702e8d404b128 100644
--- a/lib/gitlab/patch/legacy_database_config.rb
+++ b/lib/gitlab/patch/database_config.rb
@@ -28,7 +28,7 @@
 
 module Gitlab
   module Patch
-    module LegacyDatabaseConfig
+    module DatabaseConfig
       extend ActiveSupport::Concern
 
       prepended do
@@ -73,23 +73,34 @@ def database_configuration
         @uses_legacy_database_config = false # rubocop:disable Gitlab/ModuleWithInstanceVariables
 
         super.to_h do |env, configs|
-          # This check is taken from Rails where the transformation
-          # of a flat database.yml is done into `primary:`
-          # https://github.com/rails/rails/blob/v6.1.4/activerecord/lib/active_record/database_configurations.rb#L169
-          if configs.is_a?(Hash) && !configs.all? { |_, v| v.is_a?(Hash) }
-            configs = { "main" => configs }
-
-            @uses_legacy_database_config = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
+          # TODO: To be removed in 15.0. See https://gitlab.com/gitlab-org/gitlab/-/issues/338182
+          # This preload is needed to convert legacy `database.yml`
+          # from `production: adapter: postgresql`
+          # into a `production: main: adapter: postgresql`
+          unless Gitlab::Utils.to_boolean(ENV['SKIP_DATABASE_CONFIG_VALIDATION'], default: false)
+            # This check is taken from Rails where the transformation
+            # of a flat database.yml is done into `primary:`
+            # https://github.com/rails/rails/blob/v6.1.4/activerecord/lib/active_record/database_configurations.rb#L169
+            if configs.is_a?(Hash) && !configs.all? { |_, v| v.is_a?(Hash) }
+              configs = { "main" => configs }
+
+              @uses_legacy_database_config = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
+            end
           end
 
-          if Gitlab.ee? && File.exist?(Rails.root.join("config/database_geo.yml"))
-            migrations_paths = ["ee/db/geo/migrate"]
-            migrations_paths << "ee/db/geo/post_migrate" unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
+          if Gitlab.ee?
+            if !configs.key?("geo") && File.exist?(Rails.root.join("config/database_geo.yml"))
+              configs["geo"] = Rails.application.config_for(:database_geo).stringify_keys
+            end
+
+            if configs.key?("geo")
+              migrations_paths = Array(configs["geo"]["migrations_paths"])
+              migrations_paths << "ee/db/geo/migrate" if migrations_paths.empty?
+              migrations_paths << "ee/db/geo/post_migrate" unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
 
-            configs["geo"] =
-              Rails.application.config_for(:database_geo)
-                .merge(migrations_paths: migrations_paths, schema_migrations_path: "ee/db/geo/schema_migrations")
-                .stringify_keys
+              configs["geo"]["migrations_paths"] = migrations_paths.uniq
+              configs["geo"]["schema_migrations_path"] = "ee/db/geo/schema_migrations" if configs["geo"]["schema_migrations_path"].blank?
+            end
           end
 
           [env, configs]
diff --git a/spec/lib/gitlab/patch/legacy_database_config_spec.rb b/spec/lib/gitlab/patch/database_config_spec.rb
similarity index 98%
rename from spec/lib/gitlab/patch/legacy_database_config_spec.rb
rename to spec/lib/gitlab/patch/database_config_spec.rb
index b87e16f31ae07..d6f36ab86d500 100644
--- a/spec/lib/gitlab/patch/legacy_database_config_spec.rb
+++ b/spec/lib/gitlab/patch/database_config_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Gitlab::Patch::LegacyDatabaseConfig do
+RSpec.describe Gitlab::Patch::DatabaseConfig do
   it 'module is included' do
     expect(Rails::Application::Configuration).to include(described_class)
   end
-- 
GitLab