diff --git a/lib/custom_facts/util/normalization.rb b/lib/custom_facts/util/normalization.rb index 8725a2aff..74b7f86f5 100644 --- a/lib/custom_facts/util/normalization.rb +++ b/lib/custom_facts/util/normalization.rb @@ -16,7 +16,7 @@ class NormalizationError < StandardError; end # @return [void] def normalize(value) case value - when Integer, Float, TrueClass, FalseClass, NilClass, Symbol + when Integer, Float, TrueClass, FalseClass, NilClass, Symbol, Date value when String normalize_string(value) diff --git a/lib/custom_facts/util/parser.rb b/lib/custom_facts/util/parser.rb index 4c5093cbd..22f7c2bc4 100644 --- a/lib/custom_facts/util/parser.rb +++ b/lib/custom_facts/util/parser.rb @@ -4,7 +4,6 @@ # facts such as scripts, text, json and yaml files. # # Parsers must subclass this class and provide their own #results method. -require 'yaml' module LegacyFacter module Util @@ -93,9 +92,18 @@ def self.parse(output) end end + # This regex was taken from Psych and adapted + # https://github.com/ruby/psych/blob/d2deaa9adfc88fc0b870df022a434d6431277d08/lib/psych/scalar_scanner.rb#L9 + # It is used to detect Time in YAML, but we use it to wrap time objects in quotes to be treated as strings. + TIME = + /(\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?\s*$)/.freeze + class YamlParser < Base def parse_results - YAML.safe_load(content) + # Add quotes to Yaml time + cont = content.gsub(TIME, '"\1"') + + YAML.safe_load(cont, [Date]) end end diff --git a/spec/custom_facts/util/parser_spec.rb b/spec/custom_facts/util/parser_spec.rb index 25f7799a9..5255823ba 100755 --- a/spec/custom_facts/util/parser_spec.rb +++ b/spec/custom_facts/util/parser_spec.rb @@ -267,4 +267,42 @@ def expects_to_parse_powershell(cmd, result) expect(LegacyFacter::Util::Parser.parser_for('this.is.not.valid').results).to be nil end end + + describe LegacyFacter::Util::Parser::YamlParser do + let(:yaml_parser) { LegacyFacter::Util::Parser::YamlParser.new(nil, yaml_content) } + + describe '#parse_results' do + context 'when yaml contains Time formatted fields' do + context 'when time zone is present' do + let(:yaml_content) { load_fixture('external_fact_yaml').read } + + it 'treats it as a string' do + expected_result = { 'testsfact' => { 'time' => '2020-04-28 01:44:08.148119000 +01:01' } } + + expect(yaml_parser.parse_results).to eq(expected_result) + end + end + + context 'when time zone is missing' do + let(:yaml_content) { load_fixture('external_fact_yaml_no_zone').read } + + it 'is interpreted as a string' do + expected_result = { 'testsfact' => { 'time' => '2020-04-28 01:44:08.148119000' } } + + expect(yaml_parser.parse_results).to eq(expected_result) + end + end + end + + context 'when yaml contains Date formatted fields' do + let(:yaml_content) { load_fixture('external_fact_yaml_date').read } + + it 'loads date' do + expected_result = { 'testsfact' => { 'date' => Date.parse('2020-04-28') } } + + expect(yaml_parser.parse_results).to eq(expected_result) + end + end + end + end end diff --git a/spec/fixtures/external_fact_yaml b/spec/fixtures/external_fact_yaml new file mode 100644 index 000000000..6bd841152 --- /dev/null +++ b/spec/fixtures/external_fact_yaml @@ -0,0 +1,3 @@ +--- +testsfact: + time: 2020-04-28 01:44:08.148119000 +01:01 \ No newline at end of file diff --git a/spec/fixtures/external_fact_yaml_date b/spec/fixtures/external_fact_yaml_date new file mode 100644 index 000000000..3745e6afe --- /dev/null +++ b/spec/fixtures/external_fact_yaml_date @@ -0,0 +1,3 @@ +--- +testsfact: + date: 2020-04-28 \ No newline at end of file diff --git a/spec/fixtures/external_fact_yaml_no_zone b/spec/fixtures/external_fact_yaml_no_zone new file mode 100644 index 000000000..68eed3513 --- /dev/null +++ b/spec/fixtures/external_fact_yaml_no_zone @@ -0,0 +1,3 @@ +--- +testsfact: + time: 2020-04-28 01:44:08.148119000 \ No newline at end of file