Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Hiera overrides #273

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/puppet-strings/hiera.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module PuppetStrings
module Hiera
require_relative 'hiera/hierarchy_data_path'
require_relative 'hiera/data'

def self.load_config
PuppetStrings::Hiera::Data.new('hiera.yaml')
end
end
end
95 changes: 95 additions & 0 deletions lib/puppet-strings/hiera/data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true

module PuppetStrings::Hiera
class Data
attr_reader :config_path, :data_paths

def initialize(config_path)
@config_path = config_path
@data_paths = []

load_config
end

def files
@files ||= begin
result = {}

data_paths.each do |dp|
dp.matches.each do |file, interpolations|
unless result.key?(file)
result[file] = interpolations
end
end
end

result
end
end

# @return [Hash[String, Hash[String, Any]]]
# Full variable (class::var) -> filename: value
def overrides
@overrides ||= begin
overrides = {}

files.each_key do |file|
data = YAML.load(File.read(file))
data.each do |key, value|
overrides[key] ||= {}
overrides[key][file] = value
end
end

overrides
end
end

# @return [Hash[String, Hash[String, Any]]]
# variable -> filename: value
def for_class(class_name)
result = {}
overrides.each do |key, value|
override_class_name, _, variable = key.rpartition('::')
if override_class_name == class_name
result[variable] = value
end
end
result
end

def to_s
config_path
end

private

def load_config
return unless File.exist?(config_path)

config = YAML.load(File.read(config_path))

unless config['version'] == 5
raise "Unsupported version '#{config['version']}'"
end

hierarchy = config['hierarchy']
return unless hierarchy

hierarchy.each do |level|
data_hash = level['data_hash'] || config['defaults']['data_hash']
next unless data_hash == 'yaml_data'

datadir = level['datadir'] || config['defaults']['datadir']

if level['path']
data_paths << PuppetStrings::Hiera::HierarchyDataPath.new(datadir, level['path'])
elsif level['paths']
level['paths'].each do |path|
data_paths << PuppetStrings::Hiera::HierarchyDataPath.new(datadir, path)
end
end
end
end
end
end
63 changes: 63 additions & 0 deletions lib/puppet-strings/hiera/hierarchy_data_path.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

module PuppetStrings::Hiera
class HierarchyDataPath
attr_reader :datadir, :path, :regex, :mapping

def initialize(datadir, path)
@datadir = datadir
@path = path
@regex, @mapping = HierarchyDataPath.path2regex(path)
end

def matches
result = {}

Dir.chdir(datadir) do
Dir['**'].each do |entry|
next unless File.file?(entry)

regex.match(entry) do |match|
full_path = File.join(datadir, entry)
interpolations = {}

mapping.each do |name, interpolation|
interpolations[interpolation] = match.named_captures[name]
end

result[full_path] = interpolations
end
end
end

result
end

def self.path2regex(path)
mapping = {}

intermediate_result = path

# First pass - intermediate replacements
path.scan(/%{[^}]+}/).each_with_index do |interpolation, i|
replacement = "X_INTERPOLATION_#{i}_X"
mapping[replacement] = interpolation[2..-2]
intermediate_result = intermediate_result.sub(interpolation, replacement)
end

# Second pass - escape any special chars
escaped = Regexp.escape(intermediate_result)

# Third pass - replacement intermediates with regex
mapping.each_key do |replacement|
escaped = escaped.sub(replacement, "(?<#{replacement}>.+)")
end

[Regexp.new(escaped), mapping]
end

def to_s
File.join(datadir, path)
end
end
end
12 changes: 12 additions & 0 deletions lib/puppet-strings/markdown/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ def defaults
@registry[:defaults] unless @registry[:defaults].nil?
end

# Overrides from Hiera
#
# Hiera overrides only apply to classes. Each entry is a tuple of the
# filename it's defined in, a mapping of interpolations that were applied
# in the filename and the value inside the file.
#
# @return [Array[Tuple[String, Hash[String, String], Any]]]
# Any overrides from Hiera.
def hiera_overrides
[]
end

# @return [Hash] information needed for the table of contents
def toc_info
{
Expand Down
18 changes: 18 additions & 0 deletions lib/puppet-strings/markdown/puppet_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ def initialize(registry)
super(registry, 'class')
end

def hiera_overrides
@hiera_overrides ||= begin
hiera = PuppetStrings::Hiera.load_config
overrides = hiera.for_class(name)

result = {}

overrides.each do |variable, files|
result[variable] = files.map do |filename, value|
interpolations = hiera.files[filename]
[filename, interpolations, value]
end
end

result
end
end

def render
super(@template)
end
Expand Down
13 changes: 13 additions & 0 deletions lib/puppet-strings/markdown/templates/classes_and_defines.erb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ Options:
<% if defaults && defaults[param[:name]] -%>
Default value: `<%= defaults[param[:name]] %>`

<% end -%>
<% if hiera_overrides[param[:name]] -%>
<details>
<summary>Hiera overrides in a detailed table</summary>

| Filename | Interpolations | Value |
|----------|----------------|-------|
<% hiera_overrides[param[:name]].each do |filename, interpolations, value| -%>
| `<%= filename %>` | <%= interpolations.map { |i, v| "`#{i}`: `#{v}`" }.join("<br>") %> | `<%= value %>` |
<% end -%>

</details>

<% end -%>
<% end -%>
<% end -%>
1 change: 1 addition & 0 deletions lib/puppet-strings/yard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module PuppetStrings::Yard
require 'puppet-strings/yard/handlers'
require 'puppet-strings/yard/tags'
require 'puppet-strings/yard/parsers'
require 'puppet-strings/hiera'
require 'puppet-strings/monkey_patches/display_object_command'

# Sets up YARD for use with puppet-strings.
Expand Down
1 change: 1 addition & 0 deletions lib/puppet-strings/yard/code_objects/class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def to_hash
hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
hash[:defaults] = defaults unless defaults.nil? || defaults.empty?
#hash[:hiera_overrides] = hiera_overrides if hiera_overrides.any?
hash[:source] = source unless source.nil? || source.empty?
hash
end
Expand Down