From eb6d93d2835e8932fcbcab50ff5b632f2eb41ea9 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Sat, 20 Jan 2024 14:27:47 -0600 Subject: [PATCH] support for hiera datadir --- .../plugins/check_ghostbuster_hiera_files.rb | 27 +++++++++--- spec/fixtures/hiera.yaml | 6 +++ .../plugins/ghostbuster_hiera_files_spec.rb | 44 ++++++++++++++----- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/puppet-lint/plugins/check_ghostbuster_hiera_files.rb b/lib/puppet-lint/plugins/check_ghostbuster_hiera_files.rb index 7503851..1660bdc 100644 --- a/lib/puppet-lint/plugins/check_ghostbuster_hiera_files.rb +++ b/lib/puppet-lint/plugins/check_ghostbuster_hiera_files.rb @@ -13,13 +13,26 @@ def load_data(path, content) end PuppetLint.new_check(:ghostbuster_hiera_files) do + def hiera + @hiera ||= YAML.load_file(ENV['HIERA_YAML_PATH'] || '/etc/puppetlabs/code/hiera.yaml') + end + + def default_datadir + (hiera.dig('defaults', 'datadir') || 'hieradata') + end + + def path_in_datadirs?(path) + @data_dirs ||= hiera['hierarchy'].map { |h| (h['datadir'] || default_datadir).chomp('/') }.uniq + return path.match?(%{\./#{Regexp.union(@data_dirs)}/}) + end + def regexprs - hiera_yaml_file = ENV['HIERA_YAML_PATH'] || '/etc/puppetlabs/code/hiera.yaml' - hiera = YAML.load_file(hiera_yaml_file) regs = {} hiera['hierarchy'].each do |hierarchy| + path_datadir = Regexp.escape((hierarchy['datadir'] || default_datadir).chomp('/')) ([*hierarchy['path']] + [*hierarchy['paths']]).each do |level| - regex = level.gsub(/%\{(::)?(trusted|server_facts|facts)\.[^\}]+\}/, '(.+)').gsub(/%\{[^\}]+\}/, '.+') + level = File.join(path_datadir, level) + regex = Regexp.new(level.gsub(/%\{(::)?(trusted|server_facts|facts)\.[^\}]+\}/, '(.+)').gsub(/%\{[^\}]+\}/, '.+')) facts = level.match(regex).captures.map { |f| f[/%{(::)?(trusted|server_facts|facts)\.(.+)}/, 3] } regs[regex] = facts end @@ -28,14 +41,14 @@ def regexprs end def check - return if path.match(%r{./hieradata/.*\.yaml}).nil? + return unless path_in_datadirs? path puppetdb = PuppetGhostbuster::PuppetDB.new - _path = path.gsub('./hieradata/', '') regexprs.each do |k, v| - m = _path.match(Regexp.new(k)) + m = path.match(k) next if m.nil? + return if m.captures.size == 0 if m.captures.size > 1 @@ -68,7 +81,7 @@ def check end notify :warning, { - message: "Hiera File #{_path} seems unused", + message: "Hiera File #{path} seems unused", line: 1, column: 1, } diff --git a/spec/fixtures/hiera.yaml b/spec/fixtures/hiera.yaml index 7d32a83..214f10e 100644 --- a/spec/fixtures/hiera.yaml +++ b/spec/fixtures/hiera.yaml @@ -1,6 +1,12 @@ --- version: 5 +defaults: + datadir: data hierarchy: + - name: "Some other location" + datadir: private/ + path: "nodes/%{trusted.certname}.eyaml" + - name: "Per-node data (yaml version)" path: "nodes/%{trusted.certname}.yaml" diff --git a/spec/puppet-lint/plugins/ghostbuster_hiera_files_spec.rb b/spec/puppet-lint/plugins/ghostbuster_hiera_files_spec.rb index 6d3a688..8e10ebf 100644 --- a/spec/puppet-lint/plugins/ghostbuster_hiera_files_spec.rb +++ b/spec/puppet-lint/plugins/ghostbuster_hiera_files_spec.rb @@ -9,19 +9,19 @@ context 'with fix disabled' do context 'when a certname file is NOT used' do - let(:path) { './hieradata/nodes/foo.example.com.yaml' } + let(:path) { './data/nodes/foo.example.com.yaml' } it 'detects one problem' do expect(problems.size).to eq(1) end it 'creates a warning' do - expect(problems).to contain_warning('Hiera File nodes/foo.example.com.yaml seems unused') + expect(problems).to contain_warning("Hiera File #{path} seems unused") end end context 'when a certname file is used' do - let(:path) { './hieradata/nodes/bar.example.com.yaml' } + let(:path) { './data/nodes/bar.example.com.yaml' } it 'does not detect any problem' do expect(problems.size).to eq(0) @@ -29,19 +29,19 @@ end context 'when an environment file is NOT used' do - let(:path) { './hieradata/environment/foo.yaml' } + let(:path) { './data/environment/foo.yaml' } it 'detects one problem' do expect(problems.size).to eq(1) end it 'creates a warning' do - expect(problems).to contain_warning('Hiera File environment/foo.yaml seems unused') + expect(problems).to contain_warning("Hiera File #{path} seems unused") end end context 'when an environment file is used' do - let(:path) { './hieradata/environment/production.yaml' } + let(:path) { './data/environment/production.yaml' } it 'does not detect any problem' do expect(problems.size).to eq(0) @@ -49,31 +49,55 @@ end context 'when an fact is NOT used' do - let(:path) { './hieradata/virtual/false.yaml' } + let(:path) { './data/virtual/false.yaml' } it 'detects one problem' do expect(problems.size).to eq(1) end it 'creates a warning' do - expect(problems).to contain_warning('Hiera File virtual/false.yaml seems unused') + expect(problems).to contain_warning("Hiera File #{path} seems unused") end end context 'when an fact file is used' do - let(:path) { './hieradata/virtual/true.yaml' } + let(:path) { './data/virtual/true.yaml' } it 'does not detect any problem' do expect(problems.size).to eq(0) end end + context 'when an fact file is used with wrong extension' do + let(:path) { './data/virtual/true.eyaml' } + + it 'detects one problem' do + expect(problems.size).to eq(1) + end + + it 'creates a warning' do + expect(problems).to contain_warning("Hiera File #{path} seems unused") + end + end + context 'when using a variable in hierarchy' do - let(:path) { './hieradata/domain/example.com.yaml' } + let(:path) { './data/domain/example.com.yaml' } it 'does not detect any problem' do expect(problems.size).to eq(0) end end + + context 'when hierarchy datadir is NOT default and NOT used' do + let(:path) { './private/nodes/privates.example.com.eyaml' } + + it 'detects one problem' do + expect(problems.size).to eq(1) + end + + it 'creates a warning' do + expect(problems).to contain_warning("Hiera File #{path} seems unused") + end + end end end