lib/longleaf/services/metadata_deserializer.rb in longleaf-0.2.0.pre.1 vs lib/longleaf/services/metadata_deserializer.rb in longleaf-0.3.0

- old
+ new

@@ -7,78 +7,80 @@ module Longleaf # Service which deserializes metadata files into MetadataRecord objects class MetadataDeserializer extend Longleaf::Logging MDF ||= MDFields - + # 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: []) case format when 'yaml' md = from_yaml(file_path, digest_algs) else - raise ArgumentError.new('Invalid deserialization format #{format} specified') + 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) file_size = data.delete(MDFields::FILE_SIZE) last_modified = data.delete(MDFields::LAST_MODIFIED) - + services = md[MDF::SERVICES] service_records = Hash.new - unless services.nil? - services.each do |name, props| - raise Longleaf::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) - run_needed = service_props.delete(MDFields::RUN_NEEDED) - - service_records[name] = ServiceRecord.new( - properties: service_props, - stale_replicas: stale_replicas, - timestamp: timestamp, - run_needed: run_needed) - end + services&.each do |name, props| + raise Longleaf::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) + run_needed = service_props.delete(MDFields::RUN_NEEDED) + + service_records[name] = ServiceRecord.new( + properties: service_props, + stale_replicas: stale_replicas, + timestamp: timestamp, + run_needed: run_needed) end - + MetadataRecord.new(properties: data, - services: service_records, - registered: registered, - deregistered: deregistered, - checksums: checksums, - file_size: file_size, - last_modified: last_modified) + services: service_records, + registered: registered, + deregistered: deregistered, + checksums: checksums, + file_size: file_size, + last_modified: last_modified) end - + # 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) - - YAML.load(contents) + + begin + YAML.safe_load(contents, [], [], true) + rescue => err + raise Longleaf::MetadataError.new("Failed to parse metadata file #{file_path}: #{err.message}") + end end end - + def self.verify_digests(file_path, contents, digest_algs) return if digest_algs.nil? || digest_algs.empty? - + digest_algs.each do |alg| if file_path.respond_to?(:path) path = file_path.path else path = file_path @@ -86,20 +88,20 @@ digest_path = "#{path}.#{alg}" unless File.exist?(digest_path) logger.warn("Missing expected #{alg} digest for #{path}") next end - + digest = DigestHelper::start_digest(alg) result = digest.hexdigest(contents) existing_digest = IO.read(digest_path) - + if result == existing_digest logger.info("Metadata fixity check using algorithm '#{alg}' succeeded for file #{path}") else raise ChecksumMismatchError.new("Metadata digest of type #{alg} did not match the contents of #{path}:" \ - + " expected #{existing_digest}, calculated #{result}") + + " expected #{existing_digest}, calculated #{result}") end end end end -end \ No newline at end of file +end