Merge branch 'check-min-schema-migrate' into 'master'

Ensure we are on a supported version before migrating

See merge request gitlab-org/gitlab-ce!29882
This commit is contained in:
Robert Speicher 2019-06-28 22:25:25 +00:00
commit f291aae877
6 changed files with 99 additions and 1 deletions

View file

@ -244,7 +244,7 @@ migration:path-pg:
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
script:
- bundle exec rake db:migrate VERSION=20170523121229
- bundle exec rake db:migrate
- bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
dependencies:
- setup-test-env

View file

@ -0,0 +1,5 @@
---
title: Added a min schema version check to db:migrate
merge_request: 29882
author:
type: added

View file

@ -85,3 +85,21 @@ eric 37709 0.0 0.0 2518640 7524 s006 S Wed11AM 0:00.79 s
$ kill 87304
$ kill 37709
```
### db:migrate `database version is too old to be migrated` error
Users receive this error when `db:migrate` detects that the current schema version
is older than the `MIN_SCHEMA_VERSION` defined in the `Gitlab::Database` library
module.
Over time we cleanup/combine old migrations in the codebase, so it is not always
possible to migrate GitLab from every previous version.
In some cases you may want to bypass this check. For example, if you were on a version
of GitLab schema later than the `MIN_SCHEMA_VERSION`, and then rolled back the
to an older migration, from before. In this case, in order to migrate forward again,
you should set the `SKIP_SCHEMA_VERSION_CHECK` environment variable.
```sh
bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
```

View file

@ -13,6 +13,11 @@ module Gitlab
# https://dev.mysql.com/doc/refman/5.7/en/datetime.html
MAX_TIMESTAMP_VALUE = Time.at((1 << 31) - 1).freeze
# Minimum schema version from which migrations are supported
# Migrations before this version may have been removed
MIN_SCHEMA_VERSION = 20190506135400
MIN_SCHEMA_GITLAB_VERSION = '11.11.0'
define_histogram :gitlab_database_transaction_seconds do
docstring "Time spent in database transactions, in seconds"
end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
# Configures the database by running migrate, or by loading the schema and seeding if needed
task schema_version_check: :environment do
next if ENV['SKIP_SCHEMA_VERSION_CHECK']
schema_version = ActiveRecord::Migrator.current_version
# Ensure migrations are being run from a supported schema version
# A schema verison of 0 is a fresh db, and should be safe to run migrations
# But a database with existing migrations less than our min version is not
if schema_version > 0 && schema_version < Gitlab::Database::MIN_SCHEMA_VERSION
raise "Your current database version is too old to be migrated. " \
"You should upgrade to GitLab #{Gitlab::Database::MIN_SCHEMA_GITLAB_VERSION} before moving to this version. " \
"Please see https://docs.gitlab.com/ee/policy/maintenance.html#upgrade-recommendations"
end
end
# Ensure the check is a pre-requisite when running db:migrate
Rake::Task["db:migrate"].enhance [:schema_version_check]

View file

@ -0,0 +1,50 @@
# frozen_string_literal: true
require 'spec_helper'
require 'rake'
describe 'schema_version_check rake task' do
include StubENV
before :all do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/migrate/schema_check'
# empty task as env is already loaded
Rake::Task.define_task :environment
end
before do
# Stub out db tasks
allow(ActiveRecord::Tasks::DatabaseTasks).to receive(:migrate).and_return(true)
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(Gitlab::Database::MIN_SCHEMA_VERSION)
# Ensure our check can re-run each time
Rake::Task[:schema_version_check].reenable
end
it 'allows migrations on databases meeting the min schema version requirement' do
expect { run_rake_task('db:migrate') }.not_to raise_error
end
it 'raises an error when schema version is too old to migrate' do
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(25)
expect { run_rake_task('db:migrate') }.to raise_error(RuntimeError, /current database version is too old to be migrated/)
end
it 'skips running validation when passed the skip env variable' do
stub_env('SKIP_SCHEMA_VERSION_CHECK', 'true')
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(25)
expect { run_rake_task('db:migrate') }.not_to raise_error
end
it 'allows migrations on fresh databases' do
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(0)
expect { run_rake_task('db:migrate') }.not_to raise_error
end
def run_rake_task(task_name)
Rake::Task[task_name].reenable
Rake.application.invoke_task task_name
end
end