hiera_explain 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 590bb159ecb68d039aaaf5d853ad42058480a1b8
4
+ data.tar.gz: 916b60c7bbffee5b014f634fc652fe07e9fc2136
5
+ SHA512:
6
+ metadata.gz: 68019f8c76a2b4efc04777ef43ddac3ea23c0e16cca1eba58654de2cfbffb36cdbf80df592b16c8057f01e36a0eb29931b10bbda26f7a40194305ed095a226f4
7
+ data.tar.gz: b5a5dc1c0a417efa43345db4af7244020e84073e3d065321ce5e843727ade6b560a4aa1773bd6ba290aa2ea585ae0f4572e61922db5c9d19acb5341e8603a9ec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Hiera Explain
2
+
3
+ Hiera is sometimes inscrutable. Its data retrieval model can be surprising in
4
+ its simplicity. It's common for people to struggle with how to format data in
5
+ their Hiera datasources and retrieve it properly.
6
+
7
+ This tool is designed to help demystify Hiera. When you invoke `hiera_explain`,
8
+ it will use whatever scope you provide to evaluate the `hiera.yaml` file and
9
+ print it out exactly as Hiera will interpret it. What is scope? That's merely
10
+ the collection of facts or other variables provided for Hiera to use.
11
+
12
+ ## Usage
13
+
14
+ The examples here will use this sample `hiera.yaml` configuration file:
15
+
16
+ ```yaml
17
+ ---
18
+ :backends:
19
+ - yaml
20
+ - json
21
+
22
+ :yaml:
23
+ :datadir: /etc/puppetlabs/code/hieradata
24
+
25
+ :json:
26
+ :datadir: /etc/puppetlabs/code/hieradata
27
+
28
+ :hierarchy:
29
+ - "%{clientcert}"
30
+ - overrides
31
+ - "environments/%{environment}/hieradata/%{osfamily}"
32
+ - "environments/%{environment}/hieradata/%{clientcert}"
33
+ - "environments/%{environment}/hieradata/defaults"
34
+ - classroom
35
+ - tuning
36
+ - common
37
+ - defaults
38
+ ```
39
+
40
+ When you invoke `hiera_explain`, it will first show you each `datadir` expanded
41
+ out with any variables Hiera can interpolate. Then it will evaluate and display
42
+ the hierarchy, as Hiera would interpret it.
43
+
44
+ ```
45
+ root@master:~ # hiera_explain
46
+ Backend data directories:
47
+ * yaml: /etc/puppetlabs/code/hieradata
48
+ * json: /etc/puppetlabs/code/hieradata
49
+
50
+ Expanded hierarchy:
51
+ * master.puppetlabs.vm
52
+ * overrides
53
+ * environments/production/hieradata/RedHat
54
+ * environments/production/hieradata/master.puppetlabs.vm
55
+ * environments/production/hieradata/defaults
56
+ * classroom
57
+ * tuning
58
+ * common
59
+ * defaults
60
+ ```
61
+
62
+ Next it will show you the exact file paths that Hiera will look in as it's
63
+ resolving the keys you're looking up. It will indicate which files exist with a
64
+ checked box and with color coding.
65
+
66
+ ```
67
+ File lookup order:
68
+ [X] /etc/puppetlabs/code/hieradata/master.puppetlabs.vm.yaml
69
+ [ ] /etc/puppetlabs/code/hieradata/overrides.yaml
70
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/RedHat.yaml
71
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/master.puppetlabs.vm.yaml
72
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/defaults.yaml
73
+ [X] /etc/puppetlabs/code/hieradata/classroom.yaml
74
+ [ ] /etc/puppetlabs/code/hieradata/tuning.yaml
75
+ [ ] /etc/puppetlabs/code/hieradata/common.yaml
76
+ [X] /etc/puppetlabs/code/hieradata/defaults.yaml
77
+ [ ] /etc/puppetlabs/code/hieradata/master.puppetlabs.vm.json
78
+ [X] /etc/puppetlabs/code/hieradata/overrides.json
79
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/RedHat.json
80
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/master.puppetlabs.vm.json
81
+ [ ] /etc/puppetlabs/code/hieradata/environments/production/hieradata/defaults.json
82
+ [ ] /etc/puppetlabs/code/hieradata/classroom.json
83
+ [ ] /etc/puppetlabs/code/hieradata/tuning.json
84
+ [ ] /etc/puppetlabs/code/hieradata/common.json
85
+ [ ] /etc/puppetlabs/code/hieradata/defaults.json
86
+ ```
87
+
88
+ Finally, it will actually dump out *all data* available for you to look up with
89
+ Hiera functions in your Puppet code. It is also color coded, and and will indicate
90
+ which values are unable to be resolved with `hiera_hash()`.
91
+
92
+ ```
93
+ Priority lookup results:
94
+ * hiera('foo') => bar
95
+ * hiera('message') => This is a sample variable that came from a Hiera datasource
96
+ * hiera('hashies') => {"key"=>"value"}
97
+ * hiera('puppet_enterprise::profile::console::rbac_session_timeout') => 4320
98
+ * hiera('puppet_enterprise::profile::puppetdb::listen_address') => 0.0.0.0
99
+ * hiera('pe_repo::base_path') =>
100
+
101
+ Array lookup results:
102
+ * hiera_array('pe_repo::base_path') => [nil, "https://master.puppetlabs.vm:8140/packages/classroom"]
103
+ * hiera_array('puppet_enterprise::profile::console::rbac_session_timeout') => [4320]
104
+ * hiera_array('puppet_enterprise::profile::puppetdb::listen_address') => ["0.0.0.0"]
105
+ * hiera_array('message') => ["This is a sample variable that came from a Hiera datasource", "this comes from json"]
106
+ * hiera_array('foo') => ["bar"]
107
+ * hiera_array('hashies') => [{"key"=>"value"}]
108
+
109
+ Hash lookup results:
110
+ * hiera_hash('pe_repo::base_path') => No hash datatype in ["master.puppetlabs.vm.yaml", "classroom.yaml"]
111
+ * hiera_hash('puppet_enterprise::profile::console::rbac_session_timeout') => No hash datatype in ["classroom.yaml"]
112
+ * hiera_hash('puppet_enterprise::profile::puppetdb::listen_address') => No hash datatype in ["classroom.yaml"]
113
+ * hiera_hash('message') => No hash datatype in ["defaults.yaml", "overrides.json"]
114
+ * hiera_hash('foo') => No hash datatype in ["overrides.json"]
115
+ * hiera_hash('hashies') => {"key"=>"value"}
116
+ ```
117
+
118
+ ![Screenshot](screenshot.png)
119
+
120
+ ### Options
121
+
122
+ `hiera_explain` can use scope from a variety of sources. You can pass a JSON or
123
+ YAML file containing a full dump of facts, or you can retrieve those using
124
+ MCollective or PuppetDB. You can pass in as many sources of scope data as you like.
125
+
126
+ ```
127
+ root@master:~ # hiera_explain -h
128
+
129
+ Usage : hiera_explain [--json PATH] [--yaml PATH] [--mcollective IDENTITY] [--puppetdb IDENTITY].
130
+
131
+ -j, --json PATH Load scope from a JSON file.
132
+ -y, --yaml PATH Load scope from a YAML file.
133
+ -m, --mcollective IDENTITY Use MCollective to retrieve scope for an identity.
134
+ -p, --puppetdb IDENTITY Use PuppetDB to retrieve scope for an identity.
135
+ -i, --inventory IDENTITY Use Puppet's inventory service to retrieve scope (deprecated!)
136
+ -n, --no-color Disable console colors.
137
+ -d, --debug Display debugging messages
138
+
139
+ -h, --help Displays this help
140
+ ```
141
+
142
+ You can even override facts one at a time on the command line.
143
+
144
+ ```
145
+ root@master:~ # hiera_explain -p master.puppetlabs.vm clientcert=foo.bar.baz
146
+ Backend data directories:
147
+ * yaml: /etc/puppetlabs/code/hieradata
148
+ * json: /etc/puppetlabs/code/hieradata
149
+
150
+ Expanded hierarchy:
151
+ * foo.bar.baz
152
+ * overrides
153
+ * environments/production/hieradata/RedHat
154
+ * environments/production/hieradata/foo.bar.baz
155
+ * environments/production/hieradata/defaults
156
+ * classroom
157
+ * tuning
158
+ * common
159
+ * defaults
160
+ ```
161
+
162
+ ### Adding supported backends.
163
+
164
+ A standard Hiera backend won't provide the data we need to look up all available
165
+ data. I've added support for `yaml`, `json`, and `eyaml` backend out-of-the-box,
166
+ but it's fairly easy to add support for your own backend.
167
+
168
+ Simply provide a monkeypatching class like the following. It should return a
169
+ hash of Hiera data, given a path.
170
+
171
+ ```ruby
172
+ class HieraExplain::Datasource
173
+
174
+ # marshall is a data serialization format for Ruby. There does not exist
175
+ # a Hiera backend for using it, nor should there be as it's a binary format.
176
+ # But if there were, this would make hiera_explain understand it.
177
+ def self.marshall(path)
178
+ Marshal::load(File.read(path))
179
+ end
180
+
181
+ end
182
+ ```
183
+
184
+ The filename and the method it provides *must* be the same as the name for your
185
+ backend.
186
+
187
+ ```
188
+ root@master:modules # $ tree marshall
189
+ marshall
190
+ └── lib
191
+ ├── hiera
192
+ │   └── backends
193
+ │   └── marshall_backend.rb
194
+ └── hiera_explain
195
+ └── datasource
196
+ └── marshall.rb
197
+ ```
198
+
199
+ ## Disclaimer
200
+
201
+ This is early in development, although the script this is based on has been used
202
+ in the classroom for quite a while now.
203
+
204
+ Contact
205
+ -------
206
+
207
+ binford2k@gmail.com
data/bin/hiera_explain ADDED
@@ -0,0 +1,153 @@
1
+ #! /opt/puppetlabs/puppet/bin/ruby
2
+ require 'hiera'
3
+ require 'puppet'
4
+ require 'colorize'
5
+ require 'optparse'
6
+
7
+ require 'hiera_explain'
8
+ require 'hiera_explain/scope'
9
+ require 'hiera_explain/datasource'
10
+
11
+ begin
12
+ Puppet.initialize_settings
13
+ rescue => e
14
+ Puppet.settings.parse
15
+ end
16
+
17
+ hiera = Hiera.new(:config => Puppet.settings[:hiera_config])
18
+ scope = HieraExplain::Scope.new()
19
+ optparse = OptionParser.new { |opts|
20
+ opts.banner = "Usage : hiera_explain [--json PATH] [--yaml PATH] [--mcollective IDENTITY] [--puppetdb IDENTITY].
21
+
22
+ "
23
+
24
+ opts.on("-j PATH", "--json PATH", "Load scope from a JSON file.") do |arg|
25
+ scope.load_scope(arg, :json)
26
+ end
27
+
28
+ opts.on("-y PATH", "--yaml PATH", "Load scope from a YAML file.") do |arg|
29
+ scope.load_scope(arg, :yaml)
30
+ end
31
+
32
+ opts.on("-m IDENTITY", "--mcollective IDENTITY", "Use MCollective to retrieve scope for an identity.") do |arg|
33
+ scope.load_scope(arg, :mcollective)
34
+ end
35
+
36
+ opts.on("-p IDENTITY", "--puppetdb IDENTITY", "Use PuppetDB to retrieve scope for an identity.") do |arg|
37
+ scope.load_scope(arg, :puppetdb)
38
+ end
39
+
40
+ opts.on("-i IDENTITY", "--inventory IDENTITY", "Use Puppet's inventory service to retrieve scope #{'(deprecated!)'.yellow}") do |arg|
41
+ if Gem::Version.new(Puppet.version) > Gem::Version.new('4')
42
+ puts "WARNING: Many great apologies, but I fear that the inventory service has been deprecated.".red
43
+ exit 1
44
+ end
45
+ scope.load_scope(arg, :inventory_service)
46
+ end
47
+
48
+ opts.on("-n", "--no-color", "Disable console colors.") do
49
+ String.disable_colorization = true
50
+ end
51
+
52
+ opts.on("-d", "--debug", "Display debugging messages") do
53
+ loglevel = Logger::DEBUG
54
+ end
55
+
56
+ opts.separator('')
57
+
58
+ opts.on("-h", "--help", "Displays this help") do
59
+ puts
60
+ puts opts
61
+ puts
62
+ exit
63
+ end
64
+ }
65
+ optparse.parse!
66
+
67
+ # Default to the curren't node's MCO's fact cache
68
+ scope.load_scope("/etc/puppetlabs/mcollective/facts.yaml", :yaml) if scope.empty?
69
+ scope['environment'] ||= 'production'
70
+
71
+ # data buckets
72
+ priority_lookup = {}
73
+ array_lookup = {}
74
+ hash_lookup = {}
75
+ hash_errors = {}
76
+
77
+ # Cribbed from Hiera source to ensure we're parsing the same way.
78
+ unless ARGV.empty?
79
+ ARGV.each do |arg|
80
+ if arg =~ /^(.+?)=(.+?)$/
81
+ scope[$1] = $2
82
+ else
83
+ STDERR.puts "Don't know how to parse scope argument: #{arg}"
84
+ end
85
+ end
86
+ end
87
+
88
+ puts 'Backend data directories:'
89
+ Hiera::Config[:backends].each do |backend|
90
+ puts " * #{backend}: #{Hiera::Backend.datadir(backend, scope)}"
91
+ end
92
+ puts
93
+
94
+ puts 'Expanded hierarchy:'
95
+ Hiera::Backend.datasources(scope) do |datasource|
96
+ puts " * #{datasource}"
97
+ end
98
+ puts
99
+
100
+ puts 'File lookup order:'
101
+ Hiera::Config[:backends].each do |backend|
102
+ datadir = Hiera::Backend.datadir(backend, scope)
103
+ next unless datadir
104
+
105
+ Hiera::Backend.datasources(scope) do |source|
106
+ path = File.join(datadir, "#{source}.#{backend}")
107
+
108
+ unless File.exists?(path)
109
+ puts " [ ] #{path}".red
110
+
111
+ else
112
+ puts " [X] #{path}".green
113
+
114
+ data = HieraExplain.load_datasource(backend, path)
115
+ priority_lookup = data.merge(priority_lookup)
116
+
117
+ data.each do |key, value|
118
+ array_lookup[key] ||= Array.new
119
+ array_lookup[key] << value
120
+
121
+ hash_lookup[key] ||= Hash.new
122
+ if (value.class == Hash)
123
+ hash_lookup[key].merge!(value)
124
+ else
125
+ hash_errors[key] ||= Array.new
126
+ hash_errors[key] << "#{source}.#{backend}"
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+ end
134
+ puts
135
+
136
+ puts 'Priority lookup results:'
137
+ priority_lookup.each { |key, value| puts " * hiera('#{key}') => #{value.to_s.green}" }
138
+ puts
139
+
140
+ puts 'Array lookup results:'
141
+ array_lookup.each { |key, value| puts " * hiera_array('#{key}') => #{value.inspect.green}" }
142
+ puts
143
+
144
+ puts 'Hash lookup results:'
145
+ hash_lookup.each do |key, value|
146
+ print " * hiera_hash('#{key}') => "
147
+ if(hash_errors.has_key? key)
148
+ puts "No hash datatype in #{hash_errors[key].inspect}".red
149
+ else
150
+ puts value.inspect.green
151
+ end
152
+ end
153
+ puts
@@ -0,0 +1,20 @@
1
+ class HieraExplain
2
+
3
+ def self.load_datasource(backend, path)
4
+ return {} unless File.exists? path
5
+
6
+ begin
7
+ require "hiera_explain/datasource/#{backend}"
8
+ rescue LoadError => e
9
+ end
10
+
11
+ begin
12
+ return HieraExplain::Datasource.send(backend.to_s, path)
13
+ rescue => e
14
+ puts "The #{backend} backend has a malformed datasource at #{path}"
15
+ data = {}
16
+ end
17
+
18
+ data
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ class HieraExplain::Datasource
2
+
3
+ def self.yaml(path)
4
+ require 'yaml'
5
+ YAML.load_file(path)
6
+ end
7
+
8
+ def self.json(path)
9
+ require 'json'
10
+ JSON.parse(File.read(path))
11
+ end
12
+
13
+ def self.eyaml(path)
14
+ require 'yaml'
15
+ data = YAML.load_file(path)
16
+ data.each do |key, value|
17
+ data[key] = '<<encrypted>>' if data =~ /.*ENC\[.*?\]/
18
+ end
19
+ data
20
+ end
21
+
22
+ end
@@ -0,0 +1,10 @@
1
+ class HieraExplain::Datasource
2
+
3
+ # marshall is a data serialization format for Ruby. There does not exist
4
+ # a Hiera backend for using it, nor should there be as it's a binary format.
5
+ # But if there were, this would make hiera_explain understand it.
6
+ def self.marshall(path)
7
+ Marshal::load(File.read(path))
8
+ end
9
+
10
+ end
@@ -0,0 +1,116 @@
1
+ require 'rubygems'
2
+
3
+ class HieraExplain::Scope
4
+ attr_accessor :scope
5
+
6
+ def initialize()
7
+ @scope = {}
8
+ end
9
+
10
+ def empty?
11
+ @scope.empty?
12
+ end
13
+
14
+ def include?(key)
15
+ @scope.include?(key)
16
+ end
17
+
18
+ def [](key)
19
+ @scope[key]
20
+ end
21
+
22
+ def []=(key, value)
23
+ @scope[key] = value
24
+ end
25
+
26
+ # Loads the scope from YAML or JSON files
27
+ def load_scope(source, type=:yaml)
28
+ case type
29
+ when :mcollective
30
+ begin
31
+ require 'mcollective'
32
+
33
+ util = MCollective::RPC::Client.new('rpcutil',
34
+ :configfile => MCollective::Util.config_file_for_user,
35
+ :options => MCollective::Util.default_options,
36
+ )
37
+ util.progress = false
38
+ nodestats = util.custom_request("inventory", {}, source, {"identity" => source}).first
39
+
40
+ raise "Failed to retrieve facts for node #{source}: #{nodestats[:statusmsg]}" unless nodestats[:statuscode] == 0
41
+
42
+ scope = nodestats[:data][:facts]
43
+ rescue Exception => e
44
+ STDERR.puts "MCollective lookup failed: #{e.class}: #{e}"
45
+ exit 1
46
+ end
47
+
48
+ when :yaml
49
+ raise "Cannot find scope #{type} file #{source}" unless File.exist?(source)
50
+
51
+ require 'yaml'
52
+
53
+ # Attempt to load puppet in case we're going to be fed
54
+ # Puppet yaml files
55
+ begin
56
+ require 'puppet'
57
+ rescue
58
+ end
59
+
60
+ scope = YAML.load_file(source)
61
+
62
+ when :json
63
+ raise "Cannot find scope #{type} file #{source}" unless File.exist?(source)
64
+
65
+ require 'json'
66
+
67
+ scope = JSON.load(File.read(source))
68
+
69
+ when :puppetdb
70
+ require 'puppet'
71
+ begin
72
+ Puppet.initialize_settings unless Puppet.settings.global_defaults_initialized?
73
+ Puppet::Node::Facts.indirection.terminus_class = :puppetdb
74
+ scope = YAML.load(Puppet::Node::Facts.indirection.find(source).to_yaml)
75
+ rescue Exception => e
76
+ STDERR.puts "PuppetDB fact lookup failed: #{e.class}: #{e}"
77
+ exit 1
78
+ end
79
+
80
+ when :inventory_service
81
+ # For this to work the machine running the hiera command needs access to
82
+ # /facts REST endpoint on your inventory server. This access is
83
+ # controlled in auth.conf and identification is by the certname of the
84
+ # machine running hiera commands.
85
+ #
86
+ # Another caveat is that if your inventory server isn't at the short dns
87
+ # name of 'puppet' you will need to set the inventory_sever option in
88
+ # your puppet.conf. Set it in either the master or main sections. It
89
+ # is fine to have the inventory_server option set even if the config
90
+ # doesn't have the fact_terminus set to rest.
91
+ begin
92
+ require 'puppet/util/run_mode'
93
+ $puppet_application_mode = Puppet::Util::RunMode[:master]
94
+ # require 'puppet'
95
+ # Puppet.settings.parse
96
+ Puppet::Node::Facts.indirection.terminus_class = :rest
97
+ scope = YAML.load(Puppet::Node::Facts.indirection.find(source).to_yaml)
98
+ # Puppet makes dumb yaml files that do not promote data reuse.
99
+ scope = scope.values if scope.is_a?(Puppet::Node::Facts)
100
+ rescue Exception => e
101
+ STDERR.puts "Puppet inventory service lookup failed: #{e.class}: #{e}"
102
+ puts e.backtrace
103
+ exit 1
104
+ end
105
+ else
106
+ raise "Don't know how to load data type #{type}"
107
+ end
108
+
109
+ # Puppet makes dumb yaml files that do not promote data reuse.
110
+ scope = scope.values if scope.is_a?(Puppet::Node::Facts)
111
+ raise "Scope from #{type} file #{source} should be a Hash" unless scope.is_a?(Hash)
112
+
113
+ @scope.merge! scope
114
+ end
115
+
116
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hiera_explain
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Ford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: puppet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hiera
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: colorize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: |2
56
+ Hiera lookups have always been hard for people to understand. This tool will
57
+ display the entire lookup hierarchy, including filenames, exactly as Hiera will
58
+ interpret them and in the order that Hiera will resolve them.
59
+
60
+ Then it will display all the data which can be retrieved from Hiera, given the
61
+ node scope being used.
62
+ email: binford2k@gmail.com
63
+ executables:
64
+ - hiera_explain
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - README.md
69
+ - LICENSE
70
+ - bin/hiera_explain
71
+ - lib/hiera_explain/datasource/marshall.rb
72
+ - lib/hiera_explain/datasource.rb
73
+ - lib/hiera_explain/scope.rb
74
+ - lib/hiera_explain.rb
75
+ homepage: https://github.com/binford2k/hiera_explain
76
+ licenses:
77
+ - Apache 2.0
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.0.14.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Provides an explanation of how Hiera retrieves data.
99
+ test_files: []