msmg-hiera-templater 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/hiera-templater +67 -0
- data/lib/erb_reflective.rb +23 -0
- data/lib/hiera_template.rb +71 -0
- data/msmg-hiera-templater.gemspec +18 -0
- data/readme.md +111 -0
- metadata +77 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 93f1bedbdcc88d9f3ae602533735b89d35c99b52525536a63b83bc982278541b
|
|
4
|
+
data.tar.gz: d078a5d8fd9adc3c32c2380320cf504fc1f9547524689b2a5624bbfc0eb0d6c4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1d91190aba1abd9d9946d41899e3a0e63a87135ab6f2d388b214e676a0f646fa2d2c2cbd042d2d145a11483b4d941f712c421b3971d6ac895df7b71f87fe26cb
|
|
7
|
+
data.tar.gz: 215c48e206f3ebc32701e12e622f46ae9ab4eb7d4b9b3c9f31db95071ab212ae4ef9b63960270c7ae74dc427dc6ddff3cd36a94f79425817ac1833ae95a8ecfc
|
data/bin/hiera-templater
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require_relative '../lib/hiera_template'
|
|
6
|
+
|
|
7
|
+
args = { config: HieraTemplate::DEFAULT_CONFIG }
|
|
8
|
+
opt_parser = OptionParser.new do |opts|
|
|
9
|
+
opts.banner = <<~USAGE
|
|
10
|
+
Usage: #{File.basename(__FILE__)} [options] <file/folder>
|
|
11
|
+
|
|
12
|
+
Processes a specific .erb template or a folder hierarchy for .erb files.
|
|
13
|
+
Note that only files named with an .erb suffix will be processed and the output file will match the
|
|
14
|
+
name but with the suffix removed.
|
|
15
|
+
|
|
16
|
+
The erb files in the folder must use hiera('key') to retrieve a data item.
|
|
17
|
+
USAGE
|
|
18
|
+
|
|
19
|
+
opts.on('-c CONFIG_FILE', '--config=CONFIG_FILE', String,
|
|
20
|
+
"hiera configuration file (default #{args[:config]})") do |c|
|
|
21
|
+
args[:config] = c
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
opts.on('-r', '--recurse', TrueClass, 'Recurse a specified folder rather than specify a file name') do |n|
|
|
25
|
+
args[:recurse] = n
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
opts.on('-f', '--force', TrueClass, 'Force overwrite if output file exists') do |f|
|
|
29
|
+
args[:overwrite] = f
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
opts.on('-h', '--help', 'Prints this help') do
|
|
33
|
+
puts opts
|
|
34
|
+
exit
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
opt_parser.parse!
|
|
38
|
+
name = ARGV.shift
|
|
39
|
+
unless name && ((File.directory?(name) && args[:recurse]) || (File.exist?(name) && File.extname(name) == '.erb'))
|
|
40
|
+
puts opt_parser.help
|
|
41
|
+
exit 1
|
|
42
|
+
end
|
|
43
|
+
templater = HieraTemplate.new(args[:config])
|
|
44
|
+
|
|
45
|
+
def strip_suffix(file, args)
|
|
46
|
+
new_file = File.join(File.dirname(file), File.basename(file, '.erb'))
|
|
47
|
+
return new_file if args[:overwrite] || !File.exist?(new_file)
|
|
48
|
+
|
|
49
|
+
abort "#{new_file} already exists (based on template #{file})"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def process_file(templater, file, args)
|
|
53
|
+
content = File.read(file)
|
|
54
|
+
output = templater.render(content)
|
|
55
|
+
return unless output.is_a?(String) # Detect custom output
|
|
56
|
+
|
|
57
|
+
out_file = strip_suffix(file, args)
|
|
58
|
+
File.write(out_file, output)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if args[:recurse]
|
|
62
|
+
Dir.glob(File.join(name, '**', '*.erb')) do |file|
|
|
63
|
+
process_file(templater, file, args)
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
process_file(templater, name, args)
|
|
67
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
|
|
5
|
+
# Override some ERB behaviour to make it reflect methods supported
|
|
6
|
+
# by an object that is passed to it
|
|
7
|
+
class ERBReflective < ERB
|
|
8
|
+
# Simply store the object reference passed in
|
|
9
|
+
# then call the superclass behaviour with our binding instead
|
|
10
|
+
def result(other_object)
|
|
11
|
+
@other_object = other_object
|
|
12
|
+
super(binding)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def method_missing(meth, *args, &block)
|
|
16
|
+
super unless respond_to_missing? meth
|
|
17
|
+
@other_object&.send(meth, *args, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def respond_to_missing?(meth)
|
|
21
|
+
@other_object&.respond_to? meth
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'facter'
|
|
5
|
+
require 'hiera'
|
|
6
|
+
|
|
7
|
+
require_relative 'erb_reflective'
|
|
8
|
+
|
|
9
|
+
# Templating handler object used by ERBReflective
|
|
10
|
+
class HieraTemplate
|
|
11
|
+
DEFAULT_CONFIG = '/etc/puppet/hiera.yaml'
|
|
12
|
+
|
|
13
|
+
def initialize(hiera_config = DEFAULT_CONFIG)
|
|
14
|
+
@scope = Facter.to_hash # Time consuming, do it once if possible!
|
|
15
|
+
# Just so we can handle old facter references starting ::
|
|
16
|
+
legacy = @scope.map { |k, v| ["::#{k}", v] }
|
|
17
|
+
@scope.merge!(Hash[legacy])
|
|
18
|
+
@hiera = Hiera.new(config: hiera_config)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Template render
|
|
22
|
+
def render(content)
|
|
23
|
+
@blocks = []
|
|
24
|
+
rendered = ERBReflective.new(content, nil, '-').result(self)
|
|
25
|
+
return rendered unless @blocks.any?
|
|
26
|
+
|
|
27
|
+
# See custom_out
|
|
28
|
+
@blocks.each { |block| block.call(rendered) }
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Methods used by ERBReflective to access hiera data
|
|
33
|
+
# See above, full content is not available until the template is rendered so
|
|
34
|
+
# we only stash the block references that we are given and call it later
|
|
35
|
+
def custom_out(&block)
|
|
36
|
+
raise StandardError, 'custom_out requires a block argument' unless block_given?
|
|
37
|
+
|
|
38
|
+
@blocks << block
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The DSL
|
|
42
|
+
|
|
43
|
+
# If hiera does not exist we will try facter data in scope to unify the API
|
|
44
|
+
def hiera(key, default = nil)
|
|
45
|
+
@hiera.lookup(key, nil, @scope) || @scope.dig(*key.split('.')) || default
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def hiera_hash(key, default = nil)
|
|
49
|
+
@hiera.lookup(key, default, @scope, nil, :hash)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def hiera_array(key, default = nil)
|
|
53
|
+
@hiera.lookup(key, default, @scope, nil, :array)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def mkdir_p(path, owner: nil, group: nil, mode: nil)
|
|
57
|
+
custom_out do |_|
|
|
58
|
+
FileUtils.mkdir_p(path)
|
|
59
|
+
FileUtils.chown_R(owner, group, path) if owner || group
|
|
60
|
+
FileUtils.chmod_R(mode, path) if mode
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def custom_file(path, owner: nil, group: nil, mode: nil)
|
|
65
|
+
custom_out do |content|
|
|
66
|
+
File.write(path, content)
|
|
67
|
+
FileUtils.chown(owner, group, path) if owner || group
|
|
68
|
+
FileUtils.chmod(mode, path) if mode
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = 'msmg-hiera-templater'
|
|
5
|
+
s.version = '0.0.1'
|
|
6
|
+
s.authors = ['Andrew Smith']
|
|
7
|
+
s.email = ['andrew.smith at moneysupermarket.com']
|
|
8
|
+
s.required_ruby_version = '>=2.5'
|
|
9
|
+
s.summary = 'Render ERB templates from heira without requiring puppet'
|
|
10
|
+
s.description = 'MSM pubicly available Ruby'
|
|
11
|
+
s.homepage = 'https://github.com/MSMFG/msmg-hiera-templater'
|
|
12
|
+
s.license = 'Apache-2.0'
|
|
13
|
+
s.files = `git ls-files -z`.split("\x0")
|
|
14
|
+
s.add_runtime_dependency 'facter', ['~>4.2']
|
|
15
|
+
s.add_runtime_dependency 'hiera', ['~>3.7']
|
|
16
|
+
s.bindir = 'bin'
|
|
17
|
+
s.executables << 'hiera-templater'
|
|
18
|
+
end
|
data/readme.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Hiera templater without puppet
|
|
2
|
+
|
|
3
|
+
Requires facter and hiera gems, compatible with latest gems and versions installed on MSM instances.
|
|
4
|
+
|
|
5
|
+
## Background
|
|
6
|
+
|
|
7
|
+
The idea behind this prohect is to allow the power of hiera to be extended to folks that wish to use it
|
|
8
|
+
in scenarios where they don't want to use puppet.
|
|
9
|
+
|
|
10
|
+
## Operation - basics
|
|
11
|
+
|
|
12
|
+
The CLI has only one required option, a file or a path to be parsed, path parsing must be enabled by passing the -r (recursive flag) and
|
|
13
|
+
the CLI will then look for any file suffixed in .erb.
|
|
14
|
+
|
|
15
|
+
In basic mode of operation the templater has a safeguard blocking the overwrite of existing files (possibly from previous runs) unless the
|
|
16
|
+
-f flag (force) is also provided.
|
|
17
|
+
|
|
18
|
+
Syntax as per help
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
andrew.smith@C02Z2A0SLVCG hiera-templater % ruby hiera_templater.rb
|
|
22
|
+
Usage: hiera_templater.rb [options] <file/folder>
|
|
23
|
+
|
|
24
|
+
Processes a specific .erb template or a folder hierarchy for .erb files.
|
|
25
|
+
Note that only files named with an .erb suffix will be processed and the output file will match the
|
|
26
|
+
name but with the suffix removed.
|
|
27
|
+
|
|
28
|
+
The erb files in the folder must use hiera('key') to retrieve a data item.
|
|
29
|
+
-c, --config=CONFIG_FILE hiera configuration file (default /etc/puppet/hiera.yaml)
|
|
30
|
+
-r, --recurse Recurse a specified folder rather than specify a file name
|
|
31
|
+
-f, --force Force overwrite if output file exists
|
|
32
|
+
-h, --help Prints this help
|
|
33
|
+
andrew.smith@C02Z2A0SLVCG hiera-templater %
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
NOTE: In all modes of operation please attempt to utilise the recurse feature to process all your files, do NOT wrap this in another script as you will pay a 0.6 second penalty for each time the Facter library is initialised!!
|
|
37
|
+
|
|
38
|
+
In basic operation the files are delivered to the same folder as the erb template with the erb suffix removed. All template files must have the trailing .erb suffix.
|
|
39
|
+
|
|
40
|
+
ERB templates are processed with one of 3 hiera DSL lookup functions, these are..
|
|
41
|
+
|
|
42
|
+
### hiera(<hey>, \[default\])
|
|
43
|
+
|
|
44
|
+
A key, regardless of type is retrieved, this form will return any type including hash and array and can be given an optional default value for
|
|
45
|
+
values that cannot be found.
|
|
46
|
+
|
|
47
|
+
The hiera function ALSO includes a lookup for facter keys if not found in hiera, neither of the two other lookup functions do this.
|
|
48
|
+
|
|
49
|
+
### hiera_array(<key>, \[default\])
|
|
50
|
+
|
|
51
|
+
Type checked version of the above that will fail if a non array type is found.
|
|
52
|
+
|
|
53
|
+
### hiera_hash(<key>, \[default\])
|
|
54
|
+
|
|
55
|
+
Type checked version of the above that will fail if a non hash type is found.
|
|
56
|
+
|
|
57
|
+
## Operation - More DSL usage
|
|
58
|
+
|
|
59
|
+
If one wishes to output files to a specific folder rather than have then land automatically as placed by the script one can use one of 2 high level DSL
|
|
60
|
+
functions.
|
|
61
|
+
|
|
62
|
+
Noting that as soon as either of these or the more advanced custom_out function is used one is entirely responsible for the output to file, the tool will
|
|
63
|
+
no longer automatically do that for you in these cases.
|
|
64
|
+
|
|
65
|
+
### mkdir_p(\<path\>, \[owner: \<owner\>\], \[group: \<group\>\], \[mode: \<mode\>\]))
|
|
66
|
+
|
|
67
|
+
This DSL function calls custom_out and is a helper to create a folder structure recursively with optional ownership and mode specifications.
|
|
68
|
+
|
|
69
|
+
### custom_file(\<path\>, \[owner: \<owner\>\], \[group: \<group\>\], \[mode: \<mode\>\])
|
|
70
|
+
|
|
71
|
+
This DSL function calls custom_out with a preset block to ensure the output file is written with the path and optionally ownership and mode specified.
|
|
72
|
+
|
|
73
|
+
Note that custom_out blocks are performed in the order specified but following rendering so please ensure that any dependent file strictures are made (mkdir_p) before custome_file is used if it is dependent upon that path.
|
|
74
|
+
|
|
75
|
+
## Operation - Advanced usage
|
|
76
|
+
|
|
77
|
+
The templater implements custom_out as a function which takes a block of Ruby code as a parameter, this block should implement a parameter which will receive the rendered content (whether it uses it or not) and is free to utilise that content for more advanced purposes.
|
|
78
|
+
|
|
79
|
+
## DSL Example
|
|
80
|
+
```
|
|
81
|
+
[root@ip-10-96-3-54 ~]# cat testing/dsl.erb
|
|
82
|
+
[Facter only]
|
|
83
|
+
My IP is: <%= hiera('ipaddress_primary') %>
|
|
84
|
+
|
|
85
|
+
[Something missing]
|
|
86
|
+
Non existant: <%= hiera('clearly::not_existing', 'but has default') %>
|
|
87
|
+
|
|
88
|
+
<% mkdir_p('/tmp/test')
|
|
89
|
+
mkdir_p('/tmp/test2', owner: 'sysadmin', mode: 0500)
|
|
90
|
+
mkdir_p('/tmp/test3', group: 'sysadmin', mode: 0550)
|
|
91
|
+
mkdir_p('/tmp/test4', owner: 'root', group: 'sysadmin', mode: 0750)
|
|
92
|
+
custom_file('/tmp/test4/testfile', owner: 'root', group: 'sysadmin', mode: 0640) -%>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Advanced example
|
|
96
|
+
```
|
|
97
|
+
[root@ip-10-96-3-54 ~]# cat testing/custom_out.erb
|
|
98
|
+
[Facter only]
|
|
99
|
+
My IP is: <%= hiera('ipaddress_primary') %>
|
|
100
|
+
|
|
101
|
+
[Something missing]
|
|
102
|
+
Non existant: <%= hiera('clearly::not_existing', 'but has default') %>
|
|
103
|
+
|
|
104
|
+
<% custom_out do |content|
|
|
105
|
+
File.write('/tmp/footest', content)
|
|
106
|
+
FileUtils.chmod(0640, '/tmp/footest')
|
|
107
|
+
FileUtils.chown('root', 'sysadmin', '/tmp/footest')
|
|
108
|
+
end -%>
|
|
109
|
+
<% custom_out { |content| puts content } -%>
|
|
110
|
+
[root@ip-10-96-3-54 ~]#
|
|
111
|
+
```
|
metadata
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: msmg-hiera-templater
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andrew Smith
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2021-09-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: facter
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: hiera
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.7'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.7'
|
|
41
|
+
description: MSM pubicly available Ruby
|
|
42
|
+
email:
|
|
43
|
+
- andrew.smith at moneysupermarket.com
|
|
44
|
+
executables:
|
|
45
|
+
- hiera-templater
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- bin/hiera-templater
|
|
50
|
+
- lib/erb_reflective.rb
|
|
51
|
+
- lib/hiera_template.rb
|
|
52
|
+
- msmg-hiera-templater.gemspec
|
|
53
|
+
- readme.md
|
|
54
|
+
homepage: https://github.com/MSMFG/msmg-hiera-templater
|
|
55
|
+
licenses:
|
|
56
|
+
- Apache-2.0
|
|
57
|
+
metadata: {}
|
|
58
|
+
post_install_message:
|
|
59
|
+
rdoc_options: []
|
|
60
|
+
require_paths:
|
|
61
|
+
- lib
|
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '2.5'
|
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '0'
|
|
72
|
+
requirements: []
|
|
73
|
+
rubygems_version: 3.1.4
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 4
|
|
76
|
+
summary: Render ERB templates from heira without requiring puppet
|
|
77
|
+
test_files: []
|