Class: DataParser

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet-check/data_parser.rb

Overview

executes diagnostics on data files

Class Method Summary collapse

Class Method Details

.hiera(data) ⇒ Object

checks hieradata



125
126
127
128
129
130
131
132
133
134
# File 'lib/puppet-check/data_parser.rb', line 125

def self.hiera(data)
  warnings = []
  data.each do |key, value|
    # check for nil values in the data (nil keys are fine)
    if (value.is_a?(Hash) && value.values.any?(&:nil?)) || (value.class.to_s == 'NilClass')
      warnings.push("Value(s) missing in key '#{key}'.")
    end
  end
  warnings
end

.json(files) ⇒ Object

checks json (.json)



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/puppet-check/data_parser.rb', line 28

def self.json(files)
  require 'json'

  files.each do |file|
    # check json syntax
    begin
      parsed = JSON.parse(File.read(file))
    rescue JSON::ParserError => err
      PuppetCheck.error_files.push("#{file}:\n#{err.to_s.lines.first.strip}")
    else
      warnings = []

      # check metadata.json
      if File.basename(file) == 'metadata.json'
        # metadata-json-lint has issues and is essentially no longer maintained, so here is an improved and leaner version of it
        require 'spdx-licenses'

        # check for errors
        errors = []

        # check for required keys
        %w(name version author license summary source dependencies).each do |key|
          errors.push("Required field '#{key}' not found.") unless parsed.key?(key)
        end

        # check for duplicate dependencies and requirements, and that both are an array of hashes if they exist
        %w(requirements dependencies).each do |key|
          next unless parsed.key?(key)
          next errors.push("Field '#{key}' is not an array of hashes.") unless (parsed[key].is_a? Array) && (parsed[key].empty? || (parsed[key][0].is_a? Hash))

          names = []
          parsed[key].each do |req_dep|
            name = req_dep['name']
            errors.push("Duplicate #{key} on #{name}.") if names.include?(name)
            names << name
          end
        end

        # check for deprecated fields
        %w(types checksum).each do |key|
          errors.push("Deprecated field '#{key}' found.") if parsed.key?(key)
        end

        # check for summary under 144 character
        errors.push('Summary exceeds 144 characters.') if parsed.key?('summary') && parsed['summary'].size > 144

        next PuppetCheck.error_files.push("#{file}:\n#{errors.join("\n")}") unless errors.empty?

        # check for warnings
        # check for operatingsystem_support hash array
        if parsed.key?('operatingsystem_support')
          # check if operatingsystem_support array is actually empty
          if !(parsed['operatingsystem_support'].is_a? Array) || parsed['operatingsystem_support'].empty? || (!parsed['operatingsystem_support'].empty? && !(parsed['operatingsystem_support'][0].is_a? Hash))
            warnings.push('Recommended field \'operatingsystem\' not found.')
            warnings.push('Recommended field \'operatingsystemrelease\' not found.')
          else
            # check for operatingsystem string
            if parsed['operatingsystem_support'][0].key?('operatingsystem')
              warnings.push('Field \'operatingsystem\' is not a string.') unless parsed['operatingsystem_support'][0]['operatingsystem'].is_a? String
            else
              warnings.push('Recommended field \'operatingsystem\' not found.')
            end
            # check for operatingsystemrelease string array
            if parsed['operatingsystem_support'][0].key?('operatingsystemrelease')
              warnings.push('Field \'operatingsystemrelease\' is not a string array.') unless parsed['operatingsystem_support'][0]['operatingsystemrelease'][0].is_a? String
            else
              warnings.push('Recommended field \'operatingsystemrelease\' not found.')
            end
          end
        else
          warnings.push('Recommended field \'operatingsystem_support\' not found.')
        end

        # check for requirement and dependency upper bounds
        %w(requirements dependencies).each do |key|
          next if parsed[key].empty?
          parsed[key].each do |req_dep|
            warnings.push("'#{req_dep['name']}' is missing an upper bound.") unless req_dep['version_requirement'].include?('<')
          end
        end

        # check for spdx license (rubygems/util/licenses for rubygems >= 2.5 in the far future)
        if parsed.key?('license') && !SpdxLicenses.exist?(parsed['license']) && parsed['license'] !~ /[pP]roprietary/
          warnings.push("License identifier '#{parsed['license']}' is not in the SPDX list: http://spdx.org/licenses/")
        end
      # assume this is hieradata
      else
        # perform some rudimentary hiera checks if data exists
        warnings = hiera(parsed) unless parsed.class.to_s == 'NilClass'
      end
      next PuppetCheck.warning_files.push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
      PuppetCheck.clean_files.push(file.to_s)
    end
  end
end

.yaml(files) ⇒ Object

checks yaml (.yaml/.yml)



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/puppet-check/data_parser.rb', line 6

def self.yaml(files)
  require 'yaml'

  files.each do |file|
    # check yaml syntax
    begin
      parsed = YAML.load_file(file)
    rescue StandardError => err
      PuppetCheck.error_files.push("#{file}:\n#{err.to_s.gsub("(#{file}): ", '')}")
    else
      warnings = []

      # perform some rudimentary hiera checks if data exists and is hieradata
      warnings = hiera(parsed) unless (parsed.class.to_s == 'NilClass') || (file == 'hiera.yaml')

      next PuppetCheck.warning_files.push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
      PuppetCheck.clean_files.push(file.to_s)
    end
  end
end