Merge pull request #6149 from opf/housekeeping/db-version-check

Check version compatibility before running db:migrate
pull/6150/head
ulferts 7 years ago committed by GitHub
commit 62ea19f17f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 60
      lib/open_project/database.rb
  2. 34
      lib/tasks/database.rake

@ -34,6 +34,8 @@ module OpenProject
# syntax differences. # syntax differences.
module Database module Database
class InsufficientVersionError < StandardError; end
# This method returns a hash which maps the identifier of the supported # This method returns a hash which maps the identifier of the supported
# adapter to a regex matching the adapter_name. # adapter to a regex matching the adapter_name.
def self.supported_adapters def self.supported_adapters
@ -43,6 +45,53 @@ module OpenProject
}) })
end end
##
# Get the database system requirements
def self.required_versions
{
postgresql: {
numeric: 90500, # PG_VERSION_NUM
string: '9.5.0',
enforced: true
},
mysql: {
string: '5.6.0',
enforced: false
}
}
end
##
# Check the database version compatibility.
# Raises an +InsufficientVersionError+ when the version is incompatible
def self.check_version!
required = required_versions[name]
current = version
return if version_matches?
message = "Database server version mismatch: Required version is #{required[:string]}, " \
"but current version is #{current}"
if required[:enforced]
raise InsufficientVersionError.new message
else
warn "#{message}. Version is not enforced for this database however, so continuing with this version."
end
end
##
# Return +true+ if the required version is matched by the current connection.
def self.version_matches?
required = required_versions[name]
case name
when :mysql
Gem::Version.new(version) >= Gem::Version.new(required[:string])
when :postgresql
numeric_version >= required[:numeric]
end
end
# Get the raw name of the currently used database adapter. # Get the raw name of the currently used database adapter.
# This string is set by the used adapter gem. # This string is set by the used adapter gem.
def self.adapter_name(connection) def self.adapter_name(connection)
@ -75,11 +124,20 @@ module OpenProject
def self.version(raw = false) def self.version(raw = false)
case name case name
when :mysql when :mysql
version = ActiveRecord::Base.connection.select_value('SELECT VERSION()') ActiveRecord::Base.connection.select_value('SELECT VERSION()')
when :postgresql when :postgresql
version = ActiveRecord::Base.connection.select_value('SELECT version()') version = ActiveRecord::Base.connection.select_value('SELECT version()')
raw ? version : version.match(/\APostgreSQL (\S+)/i)[1] raw ? version : version.match(/\APostgreSQL (\S+)/i)[1]
end end
end end
def self.numeric_version
case name
when :mysql
raise ArgumentError, "Can't get numeric version of MySQL"
when :postgresql
ActiveRecord::Base.connection.select_value('SHOW server_version_num;').to_i
end
end
end end
end end

@ -37,3 +37,37 @@ namespace 'db:sessions' do
ActiveRecord::Base.connection.execute "DELETE FROM #{sessions_table} WHERE updated_at < '#{expiration_time}'" ActiveRecord::Base.connection.execute "DELETE FROM #{sessions_table} WHERE updated_at < '#{expiration_time}'"
end end
end end
namespace 'openproject' do
namespace 'db' do
desc 'Expire old sessions from the sessions table'
task ensure_database_compatibility: [:environment, 'db:load_config'] do
override = ActiveModel::Type::Boolean.new.cast ENV['OPENPROJECT_SKIP_DATABASE_VERSION_CHECK']
if override
warn "Skipping database version check as 'OPENPROJECT_SKIP_DATABASE_VERSION_CHECK' is set. " \
"Incompatibilites and errors may occur."
next
end
##
# Ensure database server version is compatible
override_msg = "If you're sure you want to skip the check, set 'OPENPROJECT_SKIP_DATABASE_VERSION_CHECK' to override"
begin
OpenProject::Database::check_version!
rescue OpenProject::Database::InsufficientVersionError => e
warn "#{e.message}. #{override_msg}"
Kernel.exit(1)
rescue ActiveRecord::ActiveRecordError => e
warn "Failed to perform postgres version check: #{e} - #{e.message}. #{override_msg}"
raise e
end
end
end
end
Rake::Task["db:migrate"].enhance do
Rake::Task["openproject:db:ensure_database_compatibility"].invoke
end

Loading…
Cancel
Save