Commit 06349b8f authored by Michael Kozono's avatar Michael Kozono

Merge branch...

Merge branch '348357-deprecate-custom-rake-geo-db-rake-tasks-in-favor-of-built-in-tasks-rake-db-geo' into 'master'

Deprecate custom geo:db:* rake tasks in favor of built-in tasks

See merge request gitlab-org/gitlab!77269
parents 4c24d8aa 40a48618
# frozen_string_literal: true
module Gitlab
module Geo
module DatabaseTasks
extend self
DATABASE_CONFIG = 'config/database.yml'
GEO_DATABASE_CONFIG = 'config/database_geo.yml'
GEO_DB_DIR = 'ee/db/geo'
def method_missing(method_name, *args, &block)
with_geo_db do
ActiveRecord::Tasks::DatabaseTasks.public_send(method_name, *args, &block) # rubocop:disable GitlabSecurity/PublicSend
end
end
def respond_to_missing?(method_name, include_private = false)
ActiveRecord::Tasks::DatabaseTasks.respond_to?(method_name) || super
end
def rollback
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
with_geo_db do
migration_context.rollback(step)
end
end
def version
with_geo_db do
ActiveRecord::Migrator.current_version
end
end
def dump_schema_after_migration?
with_geo_db do
!!ActiveRecord::Base.dump_schema_after_migration
end
end
def pending_migrations
with_geo_db do
migration_context.open.pending_migrations
end
end
def migration_context
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
end
def abort_if_no_geo_config!
@geo_config_exists ||= File.exist?(Rails.root.join(GEO_DATABASE_CONFIG)) # rubocop:disable Gitlab/ModuleWithInstanceVariables
unless @geo_config_exists # rubocop:disable Gitlab/ModuleWithInstanceVariables
abort("Failed to open #{GEO_DATABASE_CONFIG}. Consult the documentation on how to set up GitLab Geo.")
end
end
module Schema
extend self
def dump
require 'active_record/schema_dumper'
Gitlab::Geo::DatabaseTasks.with_geo_db do
ActiveRecord::Tasks::DatabaseTasks.dump_schema(Gitlab::Geo::DatabaseTasks.db_config)
end
end
end
module Migrate
extend self
def up
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
raise 'VERSION is required' unless version
Gitlab::Geo::DatabaseTasks.with_geo_db do
Gitlab::Geo::DatabaseTasks.migration_context.run(:up, version)
end
end
def down
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
raise 'VERSION is required - To go down one migration, run db:rollback' unless version
Gitlab::Geo::DatabaseTasks.with_geo_db do
Gitlab::Geo::DatabaseTasks.migration_context.run(:down, version)
end
end
def status
Gitlab::Geo::DatabaseTasks.with_geo_db do
unless ActiveRecord::SchemaMigration.table_exists?
abort 'Schema migrations table does not exist yet.'
end
db_list = ActiveRecord::SchemaMigration.normalized_versions
file_list =
ActiveRecord::Migrator.migrations_paths.flat_map do |path|
# match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
Dir.foreach(path).grep(/^(\d{3,})_(.+)\.rb$/) do
version = ActiveRecord::SchemaMigration.normalize_migration_number(Regexp.last_match(1))
status = db_list.delete(version) ? 'up' : 'down'
[status, version, Regexp.last_match(2).humanize]
end
end
db_list.map! do |version|
['up', version, '********** NO FILE **********']
end
# output
puts "\ndatabase: #{ActiveRecord::Base.connection_db_config.database}\n\n"
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
puts "-" * 50
(db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
end
puts
end
end
end
module Test
extend self
def load
Gitlab::Geo::DatabaseTasks.with_geo_db do
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
ActiveRecord::Schema.verbose = false
ActiveRecord::Tasks::DatabaseTasks.load_schema(ActiveRecord::Base.configurations.configs_for(env_name: 'test').first, :sql, ENV['SCHEMA'])
ensure
if should_reconnect
ActiveRecord::Base.establish_connection(Gitlab::Geo::DatabaseTasks.db_config) # rubocop: disable Database/EstablishConnection
end
end
end
def purge
Gitlab::Geo::DatabaseTasks.with_geo_db do
ActiveRecord::Tasks::DatabaseTasks.purge(ActiveRecord::Base.configurations.configs_for(env_name: 'test').first)
end
end
end
def geo_settings
{
database_config: YAML.load_file(GEO_DATABASE_CONFIG),
db_dir: GEO_DB_DIR,
migrations_paths: geo_migrations_paths,
schema_migrations_path: geo_schema_migrations_path,
seed_loader: SeedLoader.new
}
end
def geo_migrations_paths
migrations_paths = [geo_migrate_path]
migrations_paths << geo_post_migration_path unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
migrations_paths
end
def geo_migrate_path
Rails.root.join(GEO_DB_DIR, 'migrate')
end
def geo_post_migration_path
Rails.root.join(GEO_DB_DIR, 'post_migrate')
end
def geo_schema_migrations_path
Rails.root.join(GEO_DB_DIR, 'schema_migrations').to_s
end
def with_geo_db
abort_if_no_geo_config!
original_settings = {
database_config: ActiveRecord::Tasks::DatabaseTasks.database_configuration&.dup || YAML.load_file(DATABASE_CONFIG),
db_dir: ActiveRecord::Tasks::DatabaseTasks.db_dir,
migrations_paths: ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
seed_loader: ActiveRecord::Tasks::DatabaseTasks.seed_loader,
schema_migrations_path: Gitlab::Database::SchemaMigrations::Context.default_schema_migrations_path
}
set_db_env(geo_settings)
yield
ensure
set_db_env(original_settings)
end
def db_config
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).first
end
def set_db_env(settings)
ActiveRecord::Tasks::DatabaseTasks.database_configuration = settings[:database_config]
ActiveRecord::Tasks::DatabaseTasks.db_dir = settings[:db_dir]
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = settings[:migrations_paths]
ActiveRecord::Tasks::DatabaseTasks.seed_loader = settings[:seed_loader]
ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
Gitlab::Database::SchemaMigrations::Context.default_schema_migrations_path = settings[:schema_migrations_path]
ActiveRecord::Base.establish_connection(db_config) # rubocop: disable Database/EstablishConnection
end
class SeedLoader
def load_seed
load(File.join(GEO_DB_DIR, 'seeds.rb'))
end
end
end
end
end
This diff is collapsed.
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Geo::DatabaseTasks, :reestablished_active_record_base do
let(:schema_file) { Rails.root.join('tmp', 'tests', 'geo_structure.sql').to_s }
subject { described_class }
before do
stub_env('SCHEMA', schema_file) # schema will be dumped to this file
end
after do
FileUtils.rm_rf(schema_file)
end
[:drop_current, :create_current, :migrate, :load_seed, :load_schema_current].each do |method_name|
it "defines the missing method #{method_name}" do
is_expected.to respond_to(method_name)
end
it "forwards method #{method_name} to ActiveRecord::Tasks::DatabaseTasks" do
expect(ActiveRecord::Tasks::DatabaseTasks).to receive(method_name)
subject.public_send(method_name)
end
end
describe '.rollback' do
context 'ENV["STEP"] not set' do
it 'calls ActiveRecord::MigrationContext.rollback with step 1' do
expect_next_instance_of(ActiveRecord::MigrationContext) do |migration_context|
expect(migration_context).to receive(:rollback).with(1)
end
subject.rollback
end
end
end
describe '.version' do
it 'returns a Number' do
expect(subject.version).to be_an(Integer)
end
end
describe '.dump_schema_after_migration?' do
it 'returns a true value' do
expect(subject.dump_schema_after_migration?).to be_truthy
end
end
describe '.pending_migrations' do
it 'returns an array' do
expect(subject.pending_migrations).to be_an(Array)
end
end
describe described_class::Schema do
describe '.dump' do
it 'calls ActiveRecord::Tasks::DatabaseTasks.dump_schema' do
expect(ActiveRecord::Tasks::DatabaseTasks).to receive(:dump_schema)
subject.dump
end
end
end
describe described_class::Migrate do
describe '.up' do
it 'requires ENV["VERSION"] to be set' do
stub_env('VERSION', nil)
expect { subject.up }.to raise_error(/VERSION is required/)
end
it 'calls ActiveRecord::Migrator.run' do
stub_env('VERSION', '19700101120000')
expect_next_instance_of(ActiveRecord::MigrationContext) do |migration_context|
expect(migration_context).to receive(:run).with(:up, any_args)
end
subject.up
end
end
describe '.down' do
it 'requires ENV["VERSION"] to be set' do
stub_env('VERSION', nil)
expect { subject.down }.to raise_error(/VERSION is required/)
end
it 'calls ActiveRecord::Migrator.run' do
stub_env('VERSION', '19700101120000')
expect_next_instance_of(ActiveRecord::MigrationContext) do |migration_context|
expect(migration_context).to receive(:run).with(:down, any_args)
end
subject.down
end
end
describe '.status' do
it 'outputs "database: gitlabhq_geo_test"' do
expect(ActiveRecord::SchemaMigration).to receive(:normalized_versions).and_return([])
expect { subject.status }.to output(/database: gitlabhq_geo_test/).to_stdout
end
end
end
describe described_class::Test do
describe '.load' do
it 'calls ActiveRecord::Tasks::DatabaseTasks.load_schema' do
expect(ActiveRecord::Tasks::DatabaseTasks).to receive(:load_schema)
subject.load
end
end
describe '.purge' do
it 'calls ActiveRecord::Tasks::DatabaseTasks.purge' do
expect(ActiveRecord::Tasks::DatabaseTasks).to receive(:purge)
subject.purge
end
end
end
end
......@@ -22,7 +22,7 @@ module EE
override :migrations_paths
def migrations_paths
if geo_migration?
::Gitlab::Geo::DatabaseTasks.geo_migrations_paths
geo_db_config.configuration_hash[:migrations_paths]
else
super
end
......@@ -54,5 +54,9 @@ module EE
def geo_migration?
self.class.metadata[:geo]
end
def geo_db_config
Geo::TrackingBase.connection_db_config
end
end
end
......@@ -16,216 +16,40 @@ RSpec.describe 'geo rake tasks', :geo, :silence_stdout do
stub_licensed_features(geo: true)
end
it 'Gitlab:Geo::DatabaseTasks responds to all methods used in Geo rake tasks' do
%i[
drop_current
create_current
migrate
rollback
version
load_schema_current
load_seed
dump_schema_after_migration?
pending_migrations
].each do |method|
expect(Gitlab::Geo::DatabaseTasks).to respond_to(method)
end
end
it 'Gitlab::Geo::GeoTasks responds to all methods used in Geo rake tasks' do
%i[
set_primary_geo_node
update_primary_geo_node_url
].each do |method|
expect(Gitlab::Geo::GeoTasks).to respond_to(method)
end
end
it 'Gitlab::Geo::DatabaseTasks::Migrate responds to all methods used in Geo rake tasks' do
%i[up down status].each do |method|
expect(Gitlab::Geo::DatabaseTasks::Migrate).to respond_to(method)
end
end
it 'Gitlab::Geo::DatabaseTasks::Test responds to all methods used in Geo rake tasks' do
%i[load purge].each do |method|
expect(Gitlab::Geo::DatabaseTasks::Test).to respond_to(method)
end
end
it 'Gitlab::Geo::DatabaseTasks::Schema responds to .dump method used in Geo rake tasks' do
expect(Gitlab::Geo::DatabaseTasks::Schema).to respond_to(:dump)
end
describe 'geo:db:drop' do
it 'drops the current database' do
expect(Gitlab::Geo::DatabaseTasks).to receive(:drop_current)
run_rake_task('geo:db:drop')
end
end
describe 'geo:db:create' do
it 'creates a Geo tracking database' do
expect(Gitlab::Geo::DatabaseTasks).to receive(:create_current)
run_rake_task('geo:db:create')
end
end
describe 'geo:db:migrate' do
it 'migrates a Geo tracking database' do
expect(Gitlab::Geo::DatabaseTasks).to receive(:migrate)
expect(Rake::Task['geo:db:_dump']).to receive(:invoke)
run_rake_task('geo:db:migrate')
end
end
describe 'geo:db:rollback' do
it 'rolls back a Geo tracking database' do
expect(Gitlab::Geo::DatabaseTasks).to receive(:rollback)
expect(Rake::Task['geo:db:_dump']).to receive(:invoke)
run_rake_task('geo:db:rollback')
end
end
describe 'geo:db:version' do
it 'retrieves current schema version number' do
expect(Gitlab::Geo::DatabaseTasks).to receive(:version)
run_rake_task('geo:db:version')
end
end
describe 'geo:db:reset' do
it 'drops, recreates database, and loads seeds' do
expect(Rake::Task['geo:db:drop']).to receive(:invoke)
expect(Rake::Task['geo:db:create']).to receive(:invoke)
expect(Rake::Task['geo:db:setup']).to receive(:invoke)
run_rake_task('geo:db:reset')
end
end
describe 'geo:db:seed' do
it 'loads seed data' do
allow(Rake::Task['geo:db:abort_if_pending_migrations']).to receive(:invoke).and_return(false)
expect(Gitlab::Geo::DatabaseTasks).to receive(:load_seed)
run_rake_task('geo:db:seed')
end
end
describe 'geo:db:_dump' do
it 'dumps the schema' do
allow(Gitlab::Geo::DatabaseTasks).to receive(:dump_schema_after_migration?).and_return(true)
expect(Rake::Task['geo:db:schema:dump']).to receive(:invoke)
run_rake_task('geo:db:_dump')
end
end
describe 'geo:db:abort_if_pending_migrations' do
it 'raises an error if there are pending migrations' do
pending_migration = double('pending migration', version: 12, name: 'Test')
allow(Gitlab::Geo::DatabaseTasks).to receive(:pending_migrations).and_return([pending_migration])
expect { run_rake_task('geo:db:abort_if_pending_migrations') }.to raise_error(%{Run `rake geo:db:migrate` to update your database then try again.})
end
end
describe 'geo:db:schema_load' do
it 'loads schema file into database' do
allow(ENV).to receive(:[]).with('SCHEMA')
expect(Gitlab::Geo::DatabaseTasks).to receive(:load_schema_current).with(:sql, ENV['SCHEMA'])
run_rake_task('geo:db:schema:load')
end
end
describe 'geo:db:schema_dump' do
it 'creates a clean structure.sql file', :reestablished_active_record_base do
expect(Gitlab::Geo::DatabaseTasks::Schema).to receive(:dump)
expect(Rake::Task['gitlab:db:clean_structure_sql']).to receive(:invoke)
run_rake_task('geo:db:schema:dump')
end
end
describe 'geo:db:migrate:up' do
it 'runs up method for given migration' do
expect(Gitlab::Geo::DatabaseTasks::Migrate).to receive(:up)
expect(Rake::Task['geo:db:_dump']).to receive(:invoke)
run_rake_task('geo:db:migrate:up')
end
end
describe 'geo:db:migrate:down' do
it 'runs down method for given migration' do
expect(Gitlab::Geo::DatabaseTasks::Migrate).to receive(:down)
expect(Rake::Task['geo:db:_dump']).to receive(:invoke)
run_rake_task('geo:db:migrate:down')
end
end
describe 'geo:db:migrate:redo' do
context 'without env var set' do
it 'does not run migrations' do
expect(Rake::Task['geo:db:migrate:down']).not_to receive(:invoke)
expect(Rake::Task['geo:db:rollback']).to receive(:invoke)
run_rake_task('geo:db:migrate:redo')
end
end
context 'with env var set' do
it 'does run migrations' do
allow(ENV).to receive(:[]).with('VERSION').and_return(1)
expect(Rake::Task['geo:db:migrate:down']).to receive(:invoke)
expect(Rake::Task['geo:db:rollback']).not_to receive(:invoke)
run_rake_task('geo:db:migrate:redo')
context 'custom geo:db:* rake tasks' do
using RSpec::Parameterized::TableSyntax
where(:deprecated_task, :task_to_invoke) do
'geo:db:create' | 'db:create:geo'
'geo:db:drop' | 'db:drop:geo'
'geo:db:migrate' | 'db:migrate:geo'
'geo:db:migrate:down' | 'db:migrate:down:geo'
'geo:db:migrate:redo' | 'db:migrate:redo:geo'
'geo:db:migrate:status' | 'db:migrate:status:geo'
'geo:db:migrate:up' | 'db:migrate:up:geo'
'geo:db:reset' | 'db:reset:geo'
'geo:db:rollback' | 'db:rollback:geo'
'geo:db:schema:dump' | 'db:schema:dump:geo'
'geo:db:schema:load' | 'db:schema:load:geo'
'geo:db:seed' | 'db:seed:geo'
'geo:db:setup' | 'db:setup:geo'
'geo:db:test:load' | 'db:test:load:geo'
'geo:db:test:prepare' | 'db:test:prepare:geo'
'geo:db:test:purge' | 'db:test:purge:geo'
'geo:db:version' | 'db:version:geo'
end
with_them do
it "logs a deprecated message and invokes the Rails built-in task" do
expect(Rake::Task[task_to_invoke]).to receive(:invoke).and_return(true)
expect { run_rake_task(deprecated_task) }
.to output("DEPRECATION WARNING: Using `bin/rails #{deprecated_task}` is deprecated and will be removed in Gitlab 15.0. Please run `bin/rails #{task_to_invoke}` instead.\n")
.to_stdout
end
end
end
describe 'geo:db:migrate:status' do
it 'displays migration status' do
expect(Gitlab::Geo::DatabaseTasks::Migrate).to receive(:status)
run_rake_task('geo:db:migrate:status')
end
end
describe 'geo:db:test:prepare' do
it 'check for pending migrations and load schema in test environment' do
expect(Rake::Task['geo:db:test:load']).to receive(:invoke)
run_rake_task('geo:db:test:prepare')
end
end
describe 'geo:db:test:load' do
it 'recreates database in test environment' do
expect(Gitlab::Geo::DatabaseTasks::Test).to receive(:load)
expect(Gitlab::Geo::DatabaseTasks::Test).to receive(:purge)
run_rake_task('geo:db:test:load')
end
end
describe 'geo:db:test:purge' do
it 'empties database in test environment' do
expect(Gitlab::Geo::DatabaseTasks::Test).to receive(:purge)
run_rake_task('geo:db:test:purge')
end
end
describe 'geo:set_primary_node' do
before do
stub_config_setting(url: 'https://example.com:1234/relative_part')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment