Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add infrastructure for clearing repository and running seeds #5472

Merged
merged 3 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .dassie/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
MEMCACHED_HOST=memcached
REDIS_PROVIDER=SIDEKIQ_REDIS_URL
SIDEKIQ_REDIS_URL=redis://redis:6379/0
SIDEKIQ_REDIS_URL=redis://redis:6379/0
SEED_DASSIE=true
85 changes: 70 additions & 15 deletions .dassie/db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,77 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
wipe_data = ActiveModel::Type::Boolean.new.cast(ENV.fetch('WIPE_DATA', false))
seed_release_testing = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SEED_RELEASE_TESTING', false))
seed_dassie = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SEED_DASSIE', false))

Hyrax::Engine.load_seed unless ActiveModel::Type::Boolean.new.cast(ENV["SKIP_HYRAX_ENGINE_SEED"])
unless wipe_data || seed_release_testing
puts 'NAME'
puts ' rails db:seed (Hyrax)'
puts
puts 'SYNOPSIS'
puts ' bundle exec rails db:seed [WIPE_DATA=true|false] [SEED_RELEASE_TESTING=true|false] [SEED_DASSIE=true|false]'
puts
puts 'DESCRIPTION'
puts ' Hyrax defined db:seed provides a means to clear repository metadata from the datastore (e.g. Fedora, Postgres) and from Solr.'
puts ' Seeds can be run to pre-populate metadata to help with release testing and local development testing.'
puts
puts ' NOTE: Options can be passed in with the command on the command line or set as ENV variables.'
puts
puts ' The options are as follows:'
puts
puts ' WIPE_DATA'
puts ' USE WITH CAUTION - Deleted data cannot be recovered.'
puts
puts ' When true, it will clear all repository metadata from the datastore (e.g. Fedora, Postgres) and from Solr. It also'
puts ' clears data from the application database that are tightly coupled to repository metadata. See Hyrax::DataMaintenance'
puts ' for more information on what data will be destroyed by this process.'
puts
puts ' The wipe_data process will also restore required repository metadata including collection types and the default admin'
puts ' set. See Hyrax::RequiredDataSeeder for more information on what data will be created by this process.'
puts
puts ' SEED_RELEASE_TESTING'
puts ' When true, it will run the set of seeds for release testing creating a repository metadata and support data, including'
puts ' test users, collection types, collections, and works with and without files. See Hyrax::TestDataSeeder for more information'
puts ' on what data will be created by this process.'
puts
puts ' SEED_DASSIE'
puts ' When true, it will run a minimal set of seeds for dassie test app, including required collection types, default admin set,'
puts ' and test users.'
puts
puts ' ALLOW_RELEASE_SEEDING_IN_PRODUCTION'
puts ' USE WITH EXTERME CAUTION WHEN USED IN PRODUCTION - Deleted data cannot be recovered. Attempts are made to not overwrite'
puts ' existing data, but use in production is not recommended.'
puts
puts ' If this is NOT true, the process will abort when Rails environment is production.'
puts
end

allow_release_seeding_in_production = ActiveModel::Type::Boolean.new.cast(ENV.fetch('ALLOW_RELEASE_SEEDING_IN_PRODUCTION', false))

if Rails.env == 'production' && !allow_release_seeding_in_production
puts "Seeding data for release testing is not for use in production!"
exit
end

if wipe_data
puts '####################################################################################'
puts
puts 'WARNING: You are about to clear all repository metadata from the datastore and solr.'
puts 'Are you sure? [YES|n]'
answer = STDIN.gets.chomp
unless answer == 'YES'
puts ' Aborting!'
puts '####################################################################################'
exit
end

puts "\n== Loading users"
User.where(email: 'admin@example.com').first_or_create do |f|
f.password = 'admin_password'
Hyrax::DataMaintenance.new.destroy_repository_metadata_and_related_data
Hyrax::RequiredDataSeeder.new.generate_seed_data
end

User.where(email: 'basic_user@example.com').first_or_create do |f|
f.password = 'password'
if seed_dassie
Hyrax::RequiredDataSeeder.new.generate_seed_data
Hyrax::TestDataSeeders::UserSeeder.generate_seeds
end

User.where(email: 'another_user@example.com').first_or_create do |f|
f.password = 'password'
if seed_release_testing
Hyrax::TestDataSeeder.new.generate_seed_data
end
29 changes: 29 additions & 0 deletions app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# Collection branding info is tightly coupled to collections. When they are
# removed using wipe!, the associated database entries for collection branding
# also have to be deleted.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
# @todo This destroys branding info in the database. Should it also delete
# related banner and logo files?
class CollectionBrandingDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("CollectionBrandingDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying collection branding...")

Hyrax::CollectionBrandingInfo.destroy_all
logger.info(" collection branding -- DESTROYED")
end
end
end
end
end
26 changes: 26 additions & 0 deletions app/utils/hyrax/data_destroyers/collection_types_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# Collection types are recreated by the release seed data. Clear out here to
# start with a fresh set.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class CollectionTypesDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("CollectionTypesDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying collection types...")

Hyrax::CollectionType.destroy_all
logger.info(" collection types -- DESTROYED")
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# When the default admin set is removed using wipe!, the cache of the default
# admin set id also needs to be deleted.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class DefaultAdminSetIdCacheDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("DefaultAdminSetIdCacheDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying default admin set id cache...")

Hyrax::DefaultAdministrativeSet.destroy_all
logger.info(" default admin set id cache -- DESTROYED")
end
end
end
end
end
27 changes: 27 additions & 0 deletions app/utils/hyrax/data_destroyers/featured_works_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# Featured works are tightly coupled to works in the repository. When they
# are removed using wipe!, the associated database entries for featured
# works also need to be deleted.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class FeaturedWorksDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("FeaturedWorksDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying featured works...")

FeaturedWork.destroy_all
logger.info(" featured works -- DESTROYED")
end
end
end
end
end
30 changes: 30 additions & 0 deletions app/utils/hyrax/data_destroyers/permission_templates_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# PermissionTemplates are tightly coupled to admin sets and collections.
# When they are removed using wipe!, the associated database entries for
# permission templates also have to be deleted.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class PermissionTemplatesDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("PermissionTemplatesDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying permission templates...")

Hyrax::PermissionTemplateAccess.destroy_all
logger.info(" permission templates access -- DESTROYED")

Hyrax::PermissionTemplate.destroy_all
logger.info(" permission templates -- DESTROYED")
end
end
end
end
end
42 changes: 42 additions & 0 deletions app/utils/hyrax/data_destroyers/repository_metadata_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# Clear all repository metadata from the datastore (e.g. Fedora, Postgres)
# and from Solr.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
# @note When using Wings adapter, which wraps ActiveFedora, the persister wipe!
# method clears both Fedora and Solr. Optionally, an index_adapter may also
# be set to use Valkyrie to write to a second Solr core. If the Hyrax index
# adapter is the NullIndexingAdapter, that means that Valkyrie is not being
# used to index the repository metadata and does not need to be cleared using
# the Hyrax index adapter.
#
# When using other Valkyrie persistence adapters, wipe! only clears the repository
# metadata from the datastore (e.g. ORM table in Postgres). The index adapter
# is used to clear metadata from Solr.
#
class RepositoryMetadataDestroyer
class << self
attr_accessor :logger

def destroy_metadata(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("RepositoryMetadataDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying all repository metadata...")

unless Hyrax.index_adapter.is_a? Valkyrie::Indexing::NullIndexingAdapter
conn = Hyrax.index_adapter.connection
conn.delete_by_query('*:*', params: { 'softCommit' => true })
end
Hyrax.persister.wipe!

logger.info(" repository metadata -- DESTROYED")
end
end
end
end
end
33 changes: 33 additions & 0 deletions app/utils/hyrax/data_destroyers/stats_destroyer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true
module Hyrax
module DataDestroyers
# Stats are tightly coupled to works and files in the repository. When they
# are removed using wipe!, the associated database entries for stats also
# need to be deleted.
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class StatsDestroyer
class << self
attr_accessor :logger

def destroy_data(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("StatsDataDestroyer is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger

logger.info("Destroying stats...")

FileDownloadStat.destroy_all
logger.info(" file download stats -- DESTROYED")

FileViewStat.destroy_all
logger.info(" file view stats -- DESTROYED")

WorkViewStat.destroy_all
logger.info(" work view stats -- DESTROYED")
end
end
end
end
end
51 changes: 51 additions & 0 deletions app/utils/hyrax/data_maintenance.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

module Hyrax
##
# These methods created for use in rake tasks and db/seeds.rb They can be used to:
# * clear repository metadata and related data and files
# * clear temporary files
# * clear logs
#
# @note WARNING: DO NOT USE IN PRODUCTION! The methods in this class are destructive.
# Data can not be recovered.
#
class DataMaintenance
attr_accessor :logger, :allow_destruction_in_production

def initialize(logger: Logger.new(STDOUT), allow_destruction_in_production: false)
raise("Destruction of data is not for use in production!") if Rails.env.production? && !allow_destruction_in_production
@logger = logger
@allow_destruction_in_production = allow_destruction_in_production
end

# Clear repository metadata and related data
# * clear repository metadata from the datastore (e.g. Fedora, Postgres) and from Solr
# * clear targeted application data that is tightly coupled to repository metadata
# * delete files that are tightly coupled to repository metadata
def destroy_repository_metadata_and_related_data
Hyrax::DataDestroyers::RepositoryMetadataDestroyer.destroy_metadata(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::StatsDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::FeaturedWorksDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::PermissionTemplatesDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::CollectionBrandingDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::DefaultAdminSetIdCacheDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
Hyrax::DataDestroyers::CollectionTypesDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)

# TODO: Stubbed until RepositoryFilesDestroyer is written
# Hyrax::DataDestroyers::RepositoryFilesDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
end

# @todo write code to clear out log files
def destroy_log_files
# Stubbed until LogFilesDestroyer is written
# Hyrax::DataDestroyers::LogFilesDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
end

# @todo write code to delete tmp files
def destroy_tmp_files
# Stubbed until TmpFilesDestroyer is written
# Hyrax::DataDestroyers::TmpFilesDestroyer.destroy_data(logger: logger, allow_destruction_in_production: allow_destruction_in_production)
end
end
end
21 changes: 21 additions & 0 deletions app/utils/hyrax/required_data_seeder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Hyrax
# This class was created for use in rake tasks and db/seeds.rb. It generates
# required repository metadata including Admin Set and User collection types and
# the default admin set.
#
# Seeders of required data are non-destructive. If the data already exists,
# it will not be replaced.
class RequiredDataSeeder
attr_accessor :logger

def initialize(logger: Logger.new(STDOUT))
@logger = logger
end

def generate_seed_data
Hyrax::RequiredDataSeeders::CollectionTypeSeeder.generate_seeds(logger: logger)
Hyrax::RequiredDataSeeders::CollectionSeeder.generate_seeds(logger: logger)
end
end
end
Loading