app/services/foreman_seeder.rb
require 'digest'
class ForemanSeeder
FOREMAN_INTERNAL_KEY = 'database_seed'.freeze
ADVISORY_LOCK = 'database_seed'.freeze
attr_reader :seeds
class << self
attr_accessor :is_seeding
end
def initialize
@seeds = (foreman_seeds + plugin_seeds).sort_by { |seed| seed.split("/").last }
@hashed_files = @seeds + templates
end
def foreman_seeds
Dir.glob(Rails.root + 'db/seeds.d/*.rb')
end
def plugin_seeds
Foreman::Plugin.registered_plugins.collect do |name, plugin|
Dir.glob(plugin.engine.root + 'db/seeds.d/*.rb') if plugin.engine
end.flatten.compact
end
def templates
SeedHelper.report_templates + SeedHelper.provisioning_templates + SeedHelper.partition_tables_templates
end
def hash
hashes = @hashed_files.collect { |seed| Digest::SHA256.file(seed).base64digest }
Digest::SHA256.base64digest(hashes.join)
end
def execute
Foreman::AdvisoryLockManager.with_transaction_lock(ADVISORY_LOCK) do
# if we had to wait for the lock it is likely that the seeding has already been done, no need to seed again
return unless hash_changed?
self.class.is_seeding = true
begin
@seeds.each do |seed|
Rails.logger.info("Seeding #{seed}") unless Rails.env.test?
admin = User.unscoped.find_by_login(User::ANONYMOUS_ADMIN)
# anonymous admin does not exist until some of seed step creates it, therefore we use it only when it exists
if admin.present?
User.as_anonymous_admin do
load seed
end
else
load seed
end
end
ensure
self.class.is_seeding = false
end
save_hash
Rails.logger.info("All seed files executed") unless Rails.env.test?
end
end
def save_hash
ForemanInternal.find_or_create_by(key: FOREMAN_INTERNAL_KEY).update_attribute(:value, hash)
end
def old_hash
ForemanInternal.find_or_create_by(key: FOREMAN_INTERNAL_KEY).value
end
def hash_changed?
old_hash != hash
end
end