lib/longleaf/services/metadata_deserializer.rb in longleaf-0.3.0 vs lib/longleaf/services/metadata_deserializer.rb in longleaf-1.0.0

- old
+ new

@@ -1,8 +1,9 @@ require 'yaml' require 'longleaf/models/metadata_record' require 'longleaf/models/md_fields' +require 'longleaf/services/metadata_validator' require 'longleaf/errors' require 'longleaf/logging' module Longleaf # Service which deserializes metadata files into MetadataRecord objects @@ -13,21 +14,19 @@ # Deserialize a file into a MetadataRecord object # # @param file_path [String] path of the file to read. Required. # @param format [String] format the file is stored in. Default is 'yaml'. def self.deserialize(file_path:, format: 'yaml', digest_algs: []) + file_path = file_path.path if file_path.is_a?(File) + case format when 'yaml' md = from_yaml(file_path, digest_algs) else raise ArgumentError.new("Invalid deserialization format #{format} specified") end - if !md || !md.is_a?(Hash) || !md.key?(MDF::DATA) || !md.key?(MDF::SERVICES) - raise Longleaf::MetadataError.new("Invalid metadata file, did not contain data or services fields: #{file_path}") - end - data = Hash.new.merge(md[MDF::DATA]) # Extract reserved properties for submission as separate parameters registered = data.delete(MDFields::REGISTERED_TIMESTAMP) deregistered = data.delete(MDFields::DEREGISTERED_TIMESTAMP) checksums = data.delete(MDFields::CHECKSUMS) @@ -35,11 +34,11 @@ last_modified = data.delete(MDFields::LAST_MODIFIED) services = md[MDF::SERVICES] service_records = Hash.new services&.each do |name, props| - raise Longleaf::MetadataError.new("Value of service #{name} must be a hash") unless props.class == Hash + raise MetadataError.new("Value of service #{name} must be a hash") unless props.class == Hash service_props = Hash.new.merge(props) stale_replicas = service_props.delete(MDFields::STALE_REPLICAS) timestamp = service_props.delete(MDFields::SERVICE_TIMESTAMP) @@ -64,15 +63,48 @@ # Load configuration a yaml encoded configuration file def self.from_yaml(file_path, digest_algs) File.open(file_path, 'r:bom|utf-8') do |f| contents = f.read - verify_digests(file_path, contents, digest_algs) + checksum_error = nil + begin + verify_digests(file_path, contents, digest_algs) + rescue ChecksumMismatchError => err + # Hold onto the checksum error, in case we can identify the underlying cause + checksum_error = err + end begin - YAML.safe_load(contents, [], [], true) - rescue => err - raise Longleaf::MetadataError.new("Failed to parse metadata file #{file_path}: #{err.message}") + md = nil + begin + md = YAML.safe_load(contents, [], [], true) + rescue => err + raise MetadataError.new("Failed to parse metadata file #{file_path}: #{err.message}") + end + + validation_result = MetadataValidator.new(md).validate_config + if !validation_result.valid? + if checksum_error.nil? + raise MetadataError.new("Invalid metadata file #{file_path.to_s}:\n#{validation_result.errors.join("\n")}") + else + raise MetadataError.new(validation_result.errors.join("\n")) + end + end + + # Either return the valid metadata, or raise the checksum error as is + if checksum_error.nil? + md + else + raise checksum_error + end + rescue MetadataError => err + if checksum_error.nil? + raise err + else + # Add underlying cause from the metadata error to the checksum mismatch error + msg = checksum_error.message + "\nWith related issue(s):\n#{err.message}" + raise ChecksumMismatchError.new(msg) + end end end end def self.verify_digests(file_path, contents, digest_algs)