Skip to content

Commit

Permalink
When moab not found on disk, looks for it. If found, updates catalog.
Browse files Browse the repository at this point in the history
closes #1139
  • Loading branch information
justinlittman committed Dec 17, 2019
1 parent d87a8ac commit e7fef50
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 61 deletions.
13 changes: 12 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,23 @@ Layout/EmptyLineAfterGuardClause:
Layout/SpaceAroundEqualsInParameterDefault:
Enabled: false

Metrics/AbcSize:
Exclude:
- 'app/services/preserved_object_handler.rb'

Metrics/BlockLength:
Exclude:
- 'app/services/preserved_object_handler.rb' # FIXME check_existence shameless green
- '**/*.rake'
- 'spec/**/*'

Metrics/ClassLength:
Exclude:
- 'app/services/preserved_object_handler.rb'

Metrics/CyclomaticComplexity:
Exclude:
- 'app/services/preserved_object_handler.rb'

# because this isn't 1994
Metrics/LineLength:
Max: 150
Expand Down
18 changes: 4 additions & 14 deletions app/lib/audit/catalog_to_moab.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,13 @@ def check_catalog_version
end

unless online_moab_found?
transaction_ok = ActiveRecordUtils.with_transaction_and_rescue(results) do
update_status('online_moab_not_found')
complete_moab.save!
end
results.remove_db_updated_results unless transaction_ok
handle_missing_moab

# Check if it moved to another location
MoabMovedHandler.new(complete_moab, results).check_and_handle_moved_moab

results.add_result(AuditResults::MOAB_NOT_FOUND,
db_created_at: complete_moab.created_at.iso8601,
db_updated_at: complete_moab.updated_at.iso8601)
return results.report_results(logger)
end

return results.report_results(logger) unless can_validate_current_comp_moab_status?

compare_version_and_take_action
Expand All @@ -50,11 +45,6 @@ def storage_location
complete_moab.moab_storage_root.storage_location
end

def online_moab_found?
return true if moab
false
end

# compare the catalog version to the actual Moab; update the catalog version if the Moab is newer
# report results (and return them)
def compare_version_and_take_action
Expand Down
8 changes: 6 additions & 2 deletions app/services/audit_results.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class AuditResults
DB_OBJ_ALREADY_EXISTS = :db_obj_already_exists
DB_OBJ_DOES_NOT_EXIST = :db_obj_does_not_exist
CM_STATUS_CHANGED = :cm_status_changed
CM_STORAGE_ROOT_CHANGED = :cm_storage_root_changed
UNEXPECTED_VERSION = :unexpected_version
INVALID_MOAB = :invalid_moab
CM_PO_VERSION_MISMATCH = :cm_po_version_mismatch
Expand Down Expand Up @@ -53,6 +54,7 @@ class AuditResults
DB_OBJ_ALREADY_EXISTS => "%{addl} db object already exists",
DB_OBJ_DOES_NOT_EXIST => "%{addl} db object does not exist",
CM_STATUS_CHANGED => "CompleteMoab status changed from %{old_status} to %{new_status}",
CM_STORAGE_ROOT_CHANGED => "CompleteMoab storage root changed from %{old_storage_root} to %{new_storage_root}",
UNEXPECTED_VERSION => "actual version (%{actual_version}) has unexpected relationship to %{db_obj_name} db version (%{db_obj_version}); ERROR!",
INVALID_MOAB => "Invalid Moab, validation errors: %{addl}",
CM_PO_VERSION_MISMATCH => "CompleteMoab online Moab version %{cm_version} does not match PreservedObject current_version %{po_version}",
Expand Down Expand Up @@ -99,6 +101,7 @@ class AuditResults
].freeze

HONEYBADGER_REPORT_CODES = [
CM_STORAGE_ROOT_CHANGED,
MOAB_FILE_CHECKSUM_MISMATCH,
ZIP_PART_NOT_FOUND,
ZIP_PART_CHECKSUM_MISMATCH,
Expand All @@ -109,14 +112,15 @@ class AuditResults

DB_UPDATED_CODES = [
CREATED_NEW_OBJECT,
CM_STATUS_CHANGED
CM_STATUS_CHANGED,
CM_STORAGE_ROOT_CHANGED
].freeze

def self.logger_severity_level(result_code)
case result_code
when DB_OBJ_DOES_NOT_EXIST, ZIP_PARTS_NOT_CREATED, ZIP_PARTS_NOT_ALL_REPLICATED
Logger::WARN
when VERSION_MATCHES, ACTUAL_VERS_GT_DB_OBJ, CREATED_NEW_OBJECT, CM_STATUS_CHANGED, MOAB_CHECKSUM_VALID
when VERSION_MATCHES, ACTUAL_VERS_GT_DB_OBJ, CREATED_NEW_OBJECT, CM_STATUS_CHANGED, CM_STORAGE_ROOT_CHANGED, MOAB_CHECKSUM_VALID
Logger::INFO
else
Logger::ERROR
Expand Down
68 changes: 68 additions & 0 deletions app/services/moab_moved_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

##
# Service for handling a Moab that has moved
class MoabMovedHandler
attr_reader :complete_moab, :results

def initialize(complete_moab, results)
@complete_moab = complete_moab
@results = results
end

def check_and_handle_moved_moab
update_moab_storage_root if moved_moab.exist?
end

private

def moved_moab
@moved_moab ||= Moab::StorageServices.find_storage_object(complete_moab.preserved_object.druid)
end

def validation_errors?
object_validator = Stanford::StorageObjectValidator.new(moved_moab)
object_validator.validation_errors(Settings.moab.allow_content_subdirs).any?
end

def storage_root
@storage_root ||= MoabStorageRoot.find_by!(storage_location: File.join(moved_moab.storage_root.to_path, Settings.moab.storage_trunk))
end

def update_status_ok
complete_moab.status = 'ok'
return unless complete_moab.status_changed?

results.add_result(
AuditResults::CM_STATUS_CHANGED, old_status: complete_moab.status_was, new_status: complete_moab.status
)
end

def update_storage_root
old_storage_root = complete_moab.moab_storage_root
complete_moab.moab_storage_root = storage_root
results.add_result(
AuditResults::CM_STORAGE_ROOT_CHANGED, old_storage_root: old_storage_root.storage_location,
new_storage_root: complete_moab.moab_storage_root.storage_location
)
end

def update_moab_storage_root
version = nil
transaction_ok = ActiveRecordUtils.with_transaction_and_rescue(results) do
version = complete_moab.version
end
results.remove_db_updated_results unless transaction_ok
# Ensures Moab at the current location matches the catalog in all ways (e.g. version, full validation) except for disk location
return if moved_moab.current_version_id != version
return if validation_errors?

# Update the disk location in the catalog
transaction_ok = ActiveRecordUtils.with_transaction_and_rescue(results) do
update_storage_root
update_status_ok
complete_moab.save!
end
results.remove_db_updated_results unless transaction_ok
end
end
17 changes: 17 additions & 0 deletions app/services/moab_validation_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def moab
@moab ||= Moab::StorageObject.new(druid, object_dir)
end

def online_moab_found?
return true if moab&.exist?
false
end

def can_validate_checksums?
false
end
Expand Down Expand Up @@ -90,4 +95,16 @@ def set_status_as_seen_on_disk(found_expected_version)
update_status('validity_unknown')
end
end

def handle_missing_moab
transaction_ok = ActiveRecordUtils.with_transaction_and_rescue(results) do
results.add_result(AuditResults::MOAB_NOT_FOUND,
db_created_at: complete_moab.created_at.iso8601,
db_updated_at: complete_moab.updated_at.iso8601)

update_status('online_moab_not_found')
complete_moab.save!
end
results.remove_db_updated_results unless transaction_ok
end
end
96 changes: 63 additions & 33 deletions app/services/preserved_object_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# inspired by http://www.thegreatcodeadventure.com/smarter-rails-services-with-active-record-modules/
class PreservedObjectHandler
include ::MoabValidationHandler
# include ::MoabMovedHandler
include ActiveModel::Validations

validates :druid, presence: true, format: { with: DruidTools::Druid.pattern }
Expand Down Expand Up @@ -71,45 +72,74 @@ def check_existence

if invalid?
results.add_result(AuditResults::INVALID_ARGUMENTS, errors.full_messages)
elsif PreservedObject.exists?(druid: druid)
Rails.logger.debug "check_existence #{druid} called"
transaction_ok = with_active_record_transaction_and_rescue do
raise_rollback_if_cm_po_version_mismatch

return results.report_results unless can_validate_current_comp_moab_status?

if incoming_version == comp_moab.version
set_status_as_seen_on_disk(true) unless comp_moab.status == 'ok'
results.add_result(AuditResults::VERSION_MATCHES, 'CompleteMoab')
elsif incoming_version > comp_moab.version
set_status_as_seen_on_disk(true) unless comp_moab.status == 'ok'
results.add_result(AuditResults::ACTUAL_VERS_GT_DB_OBJ, db_obj_name: 'CompleteMoab', db_obj_version: comp_moab.version)
if moab_validation_errors.empty?
comp_moab.upd_audstamps_version_size(ran_moab_validation?, incoming_version, incoming_size)
pres_object.current_version = incoming_version
pres_object.save!
else
update_status('invalid_moab')
end
else # incoming_version < comp_moab.version
set_status_as_seen_on_disk(false)
results.add_result(AuditResults::ACTUAL_VERS_LT_DB_OBJ, db_obj_name: 'CompleteMoab', db_obj_version: comp_moab.version)
return results.report_results
end

return results.report_results unless check_preserved_object_db_obj_exists && check_moab_db_obj_exists

unless online_moab_found?
handle_missing_moab

# Check if it moved to another location
MoabMovedHandler.new(comp_moab, results).check_and_handle_moved_moab
return results.report_results
end

Rails.logger.debug "check_existence #{druid} called"

transaction_ok = with_active_record_transaction_and_rescue do
raise_rollback_if_cm_po_version_mismatch

return results.report_results unless can_validate_current_comp_moab_status?

if incoming_version == comp_moab.version
# Error thrown if comp_moab not found for this storage root and caught by with_active_record_transaction_and_rescue
set_status_as_seen_on_disk(true) unless comp_moab.status == 'ok'
results.add_result(AuditResults::VERSION_MATCHES, 'CompleteMoab')
elsif incoming_version > comp_moab.version
set_status_as_seen_on_disk(true) unless comp_moab.status == 'ok'
results.add_result(AuditResults::ACTUAL_VERS_GT_DB_OBJ, db_obj_name: 'CompleteMoab', db_obj_version: comp_moab.version)
if moab_validation_errors.empty?
comp_moab.upd_audstamps_version_size(ran_moab_validation?, incoming_version, incoming_size)
pres_object.current_version = incoming_version
pres_object.save!
else
update_status('invalid_moab')
end
comp_moab.update_audit_timestamps(ran_moab_validation?, true)
comp_moab.save!
end
results.remove_db_updated_results unless transaction_ok
else
results.add_result(AuditResults::DB_OBJ_DOES_NOT_EXIST, 'PreservedObject')
if moab_validation_errors.empty?
create_db_objects('validity_unknown')
else
create_db_objects('invalid_moab')
else # incoming_version < comp_moab.version
set_status_as_seen_on_disk(false)
results.add_result(AuditResults::ACTUAL_VERS_LT_DB_OBJ, db_obj_name: 'CompleteMoab', db_obj_version: comp_moab.version)
end
comp_moab.update_audit_timestamps(ran_moab_validation?, true)
comp_moab.save!
end
results.remove_db_updated_results unless transaction_ok
results.report_results
end

def check_preserved_object_db_obj_exists
with_active_record_transaction_and_rescue do
# If it doesn't exist, error will be caught and DB_OBJ_DOES_NOT_EXIST added to results
pres_object
return true
end
if moab_validation_errors.empty?
create_db_objects('validity_unknown')
else
create_db_objects('invalid_moab')
end
false
end

def check_moab_db_obj_exists
with_active_record_transaction_and_rescue do
# If it doesn't exist, error will be caught and DB_OBJ_DOES_NOT_EXIST added to results
comp_moab
return true
end
false
end

def confirm_version
results.check_name = 'confirm_version'
if invalid?
Expand Down
Loading

0 comments on commit e7fef50

Please sign in to comment.