hieracles 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +30 -0
- data/Rakefile +14 -0
- data/bin/hc +32 -0
- data/bin/nodeinfo +41 -0
- data/hieracles.gemspec +30 -0
- data/lib/hieracles.rb +15 -0
- data/lib/hieracles/config.rb +56 -0
- data/lib/hieracles/format.rb +58 -0
- data/lib/hieracles/formats/console.rb +84 -0
- data/lib/hieracles/formats/csv.rb +66 -0
- data/lib/hieracles/formats/plain.rb +61 -0
- data/lib/hieracles/formats/yaml.rb +36 -0
- data/lib/hieracles/help.rb +27 -0
- data/lib/hieracles/hiera.rb +27 -0
- data/lib/hieracles/node.rb +108 -0
- data/lib/hieracles/optparse.rb +63 -0
- data/lib/hieracles/utils.rb +59 -0
- data/spec/files/config.yml +5 -0
- data/spec/files/enc/server.example.com.yaml +7 -0
- data/spec/files/enc/server2.example.com.yaml +7 -0
- data/spec/files/enc/server3.example.com.yaml +7 -0
- data/spec/files/farm_modules/dev.pp +5 -0
- data/spec/files/farm_modules/dev2.pp +5 -0
- data/spec/files/hiera.yaml +16 -0
- data/spec/files/hiera_no_yamlbackend.yaml +16 -0
- data/spec/files/hiera_yamlbackend_notfound.yaml +16 -0
- data/spec/files/modules/fake_module/manifests/init.pp +3 -0
- data/spec/files/modules/fake_module2/manifests/init.pp +3 -0
- data/spec/files/modules/fake_module3/manifests/init.pp +3 -0
- data/spec/files/params/common/common.yml +2 -0
- data/spec/files/params/farm/dev.yaml +1 -0
- data/spec/files/params/nodes/server.example.com.yaml +5 -0
- data/spec/lib/config_spec.rb +63 -0
- data/spec/lib/format_spec.rb +91 -0
- data/spec/lib/formats/console_spec.rb +107 -0
- data/spec/lib/formats/csv_spec.rb +89 -0
- data/spec/lib/formats/plain_spec.rb +94 -0
- data/spec/lib/formats/yaml_spec.rb +80 -0
- data/spec/lib/help_spec.rb +8 -0
- data/spec/lib/hiera_spec.rb +111 -0
- data/spec/lib/node_spec.rb +158 -0
- data/spec/lib/optparse_spec.rb +65 -0
- data/spec/lib/utils_spec.rb +61 -0
- data/spec/spec_helper.rb +26 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b9af763f884a9153607dbc67b10cc0fcd0eb79c8
|
4
|
+
data.tar.gz: 0fc7b717a7a598c3a78245dd18761a11140629cd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 296005bd9070c34848c6f53cdb0e03a4e6b099cf2ac06bc97c5d543a8bf4a89cd40187e7cfd643cb0615867fb9be2d4f8e5618522f9bcb2cd498322d0c9d2281
|
7
|
+
data.tar.gz: 4f251c0dcd1143cffadfc09484af1eaf06af19d671b166d1b49d0b96d4e3ab80804bf20381a9af5b42384e4a79072610caed2e8a83c70ef0aed0b5d1502b28fd
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Hieracles Changelog
|
2
|
+
=======================
|
3
|
+
|
4
|
+
### 0.0.1 - 2015-09-12
|
5
|
+
- first alpha release
|
6
|
+
- added extensive testing using rspec
|
7
|
+
- add more config variables and parameters for fitting various environments
|
8
|
+
- initial transition to Github from internal v0.0.5 Gandi code.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 gandi.net
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Hieracles
|
2
|
+
================
|
3
|
+
|
4
|
+
[![Build Status](https://img.shields.io/travis/Gandi/hieracles.svg)](https://travis-ci.org/Gandi/hieracles)
|
5
|
+
[![Coverage Status](https://img.shields.io/coveralls/Gandi/hieracles.svg)](https://coveralls.io/r/Gandi/hieracles?branch=master)
|
6
|
+
[![Dependency Status](https://img.shields.io/gemnasium/Gandi/hieracles.svg)](https://gemnasium.com/Gandi/hieracles)
|
7
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/Gandi/hieracles.svg)](https://codeclimate.com/github/Gandi/hieracles)
|
8
|
+
|
9
|
+
Hieracles is a command-line tool for analysis and deep examination of [Hiera][hiera] paramaters in a [Puppet][puppet] setup. It's used internally at [Gandi][gandi] and its first incarnation is strongly tied to Gandi puppet architecture. But Hieracles tends to become, in time, a generic Hiera overlay visualisation tool.
|
10
|
+
|
11
|
+
Install
|
12
|
+
-----------
|
13
|
+
At this stage, it's to early to even think about installing anything. The internal code from Gandi is still in progress of transition towards total freedom.
|
14
|
+
|
15
|
+
Authors
|
16
|
+
-----------
|
17
|
+
Hieracles original code is writen by [@mose](https://github.com/mose).
|
18
|
+
|
19
|
+
License
|
20
|
+
-----------
|
21
|
+
Hieracles is available under MIT license. See [LICENSE](./LICENSE) file for more details
|
22
|
+
|
23
|
+
Copyright
|
24
|
+
------------
|
25
|
+
copyright (c) 2015 Gandi http://gandi.net
|
26
|
+
|
27
|
+
|
28
|
+
[puppet]: https://github.com/puppetlabs/puppet
|
29
|
+
[hiera]: https://github.com/puppetlabs/hiera
|
30
|
+
[gandi]: https://gandi.net
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'launch rspec tests'
|
7
|
+
task :spec do
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
9
|
+
t.rspec_opts = ['-c', '-f Fivemat', '-r ./spec/spec_helper.rb']
|
10
|
+
t.pattern = 'spec/lib/**/*_spec.rb'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
task default: :spec
|
data/bin/hc
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'hieracles'
|
6
|
+
|
7
|
+
opt = Hieracles::Optparse.new(ARGV)
|
8
|
+
|
9
|
+
fqdn = opt.payload[0]
|
10
|
+
command = opt.payload[1]
|
11
|
+
args = opt.payload[2..-1]
|
12
|
+
|
13
|
+
unless fqdn && command
|
14
|
+
puts Hieracles::Help.usage
|
15
|
+
exit(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
if Hieracles::Format.method_defined? command
|
19
|
+
node = Hieracles::Node.new fqdn, opt.options
|
20
|
+
begin
|
21
|
+
formatter = Object.const_get("Hieracles::Formats::#{Hieracles::Config.format}")
|
22
|
+
rescue
|
23
|
+
puts " Unknown format #{Hieracles::Config.format}"
|
24
|
+
exit(1)
|
25
|
+
end
|
26
|
+
dispatch = formatter.new node
|
27
|
+
puts dispatch.send(command.to_sym, args)
|
28
|
+
else
|
29
|
+
puts " Unknown command: #{command}"
|
30
|
+
Hieracles::Help.usage
|
31
|
+
exit(1)
|
32
|
+
end
|
data/bin/nodeinfo
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This is a cgi script intended to be installed on
|
3
|
+
# puppetmasters v2.6 and v2.7
|
4
|
+
|
5
|
+
require 'mysql'
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
cgi = CGI.new
|
9
|
+
|
10
|
+
if cgi['q'].empty?
|
11
|
+
puts "Content-type: text/plain\n\n"
|
12
|
+
puts "KO"
|
13
|
+
exit(0)
|
14
|
+
end
|
15
|
+
|
16
|
+
DB_HOST = 'localhost'
|
17
|
+
DB_USER = ''
|
18
|
+
DB_PASS = ''
|
19
|
+
DB_FIELDS = %w(farm site country)
|
20
|
+
|
21
|
+
fqdn = cgi['q'].gsub(/[^-_0-9a-zA-z\.]/, '')
|
22
|
+
QUERY = "select #{DB_FIELDS.join(', ')} from node left join datacenter dc on node.site=dc.datacenter where nodename='#{fqdn}';"
|
23
|
+
DB = "puppet"
|
24
|
+
|
25
|
+
|
26
|
+
begin
|
27
|
+
puts "Content-type: text/plain\n\n"
|
28
|
+
con = Mysql.new DB_HOST, DB_USER, DB_PASS
|
29
|
+
rs = con.query "use " + DB
|
30
|
+
rs = con.query QUERY
|
31
|
+
rs.each do |r|
|
32
|
+
puts r.join(',')
|
33
|
+
end
|
34
|
+
|
35
|
+
rescue Mysql::Error => e
|
36
|
+
puts e.errno
|
37
|
+
puts e.error
|
38
|
+
|
39
|
+
ensure
|
40
|
+
con.close if con
|
41
|
+
end
|
data/hieracles.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "hieracles"
|
7
|
+
spec.version = File.read(File.expand_path('../CHANGELOG.md', __FILE__))[/([0-9]+\.[0-9]+\.[0-9]+)/]
|
8
|
+
spec.authors = ["mose"]
|
9
|
+
spec.email = ["mose@gandi.net"]
|
10
|
+
spec.summary = %q{CLI tool for Hiera parameters visualisation.}
|
11
|
+
spec.description = %q{CLI tool for Hiera parameters visualisation and analysis.}
|
12
|
+
spec.homepage = "https://github.com/Gandi/hieracles"
|
13
|
+
spec.metadata = { "changelog" => "https://github.com/Gandi/hieracles/blob/master/CHANGELOG.md" }
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
#spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.executables = ['hc']
|
19
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency 'rspec', "~> 3.0"
|
25
|
+
spec.add_development_dependency 'fivemat'
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
spec.add_development_dependency 'simplecov'
|
28
|
+
spec.add_development_dependency 'rubocop'
|
29
|
+
|
30
|
+
end
|
data/lib/hieracles.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'hieracles/optparse'
|
2
|
+
require 'hieracles/config'
|
3
|
+
require 'hieracles/hiera'
|
4
|
+
require 'hieracles/utils'
|
5
|
+
require 'hieracles/help'
|
6
|
+
require 'hieracles/node'
|
7
|
+
require 'hieracles/format'
|
8
|
+
require 'hieracles/formats/csv'
|
9
|
+
require 'hieracles/formats/yaml'
|
10
|
+
require 'hieracles/formats/plain'
|
11
|
+
require 'hieracles/formats/console'
|
12
|
+
|
13
|
+
# https://github.com/Gandi/hieracles
|
14
|
+
module Hieracles
|
15
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Hieracles
|
4
|
+
# configuration singleton
|
5
|
+
module Config
|
6
|
+
extend self
|
7
|
+
|
8
|
+
attr_reader :extraparams, :server, :classpath,
|
9
|
+
:modulepath, :hierafile, :basepath, :encpath, :format
|
10
|
+
|
11
|
+
def load(options)
|
12
|
+
@optionfile = options[:config] || defaultconfig
|
13
|
+
@extraparams = extract_params(options[:params])
|
14
|
+
initconfig(@optionfile) unless File.exist? @optionfile
|
15
|
+
values = YAML.load_file(@optionfile)
|
16
|
+
@server = values['server']
|
17
|
+
@classpath = values['classpath']
|
18
|
+
@modulepath = values['modulepath'] || 'modules'
|
19
|
+
@encpath = options[:encpath] || values['encpath'] || 'enc'
|
20
|
+
@basepath = File.expand_path(options[:basepath] || values['basepath'] || '.')
|
21
|
+
@hierafile = options[:hierafile] || values['hierafile'] || 'hiera.yaml'
|
22
|
+
@format = (options[:format] || values['format'] || 'console').capitalize
|
23
|
+
end
|
24
|
+
|
25
|
+
def initconfig(file)
|
26
|
+
FileUtils.mkdir_p(File.dirname(file))
|
27
|
+
File.open(file, 'w') do |f|
|
28
|
+
f.puts '---'
|
29
|
+
f.puts '# uncomment if you use the CGI method for discovery'
|
30
|
+
f.puts '# server: puppetserver.example.com'
|
31
|
+
f.puts 'classpath: manifests/classes/%s.pp'
|
32
|
+
f.puts 'modulepath: modules'
|
33
|
+
f.puts 'encpath: enc'
|
34
|
+
f.puts 'hierafile: hiera.yaml'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def defaultconfig
|
39
|
+
File.join(ENV['HOME'], '.config', 'hieracles', 'config.yml')
|
40
|
+
end
|
41
|
+
|
42
|
+
# str is like: something=xxx;another=yyy
|
43
|
+
def extract_params(str)
|
44
|
+
return {} unless str
|
45
|
+
str.split(';').reduce({}) do |a, k|
|
46
|
+
a["#{k[/^[^=]*/]}".to_sym] = k[/[^=]*$/]
|
47
|
+
a
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def path(what)
|
52
|
+
File.join(@basepath, send(what.to_sym))
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Hieracles
|
2
|
+
class Format
|
3
|
+
def initialize(node)
|
4
|
+
@node = node
|
5
|
+
end
|
6
|
+
|
7
|
+
def info(_)
|
8
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
def files(_)
|
12
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
def paths(_)
|
16
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def params(args)
|
20
|
+
show_params(true, args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def allparams(args)
|
24
|
+
show_params(false, args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def show_params(without_common, args)
|
28
|
+
filter = args[0]
|
29
|
+
output = build_head(without_common)
|
30
|
+
@node.params(without_common).each do |k, v|
|
31
|
+
output << build_params_line(k, v, filter)
|
32
|
+
end
|
33
|
+
output
|
34
|
+
end
|
35
|
+
|
36
|
+
def modules(args)
|
37
|
+
output = ''
|
38
|
+
@node.modules.each do |k, v|
|
39
|
+
output << build_modules_line(k, v)
|
40
|
+
end
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def build_head(without_common)
|
47
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_params_line(key, value, filter)
|
51
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_modules_line(key, value)
|
55
|
+
"#{__callee__} not implemented, please inherit from the Hieracles::Format class to implement a format.\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Hieracles
|
2
|
+
module Formats
|
3
|
+
# format accepting colors
|
4
|
+
# for display in the terminal
|
5
|
+
class Console < Hieracles::Format
|
6
|
+
include Hieracles::Utils
|
7
|
+
|
8
|
+
COLORS = [
|
9
|
+
"\e[31m%s\e[0m",
|
10
|
+
"\e[32m%s\e[0m",
|
11
|
+
"\e[33m%s\e[0m",
|
12
|
+
"\e[34m%s\e[0m",
|
13
|
+
"\e[35m%s\e[0m",
|
14
|
+
"\e[36m%s\e[0m",
|
15
|
+
"\e[37m%s\e[0m",
|
16
|
+
"\e[38m%s\e[0m",
|
17
|
+
"\e[97m%s\e[0m"
|
18
|
+
]
|
19
|
+
|
20
|
+
def initialize(node)
|
21
|
+
@colors = {}
|
22
|
+
super(node)
|
23
|
+
end
|
24
|
+
|
25
|
+
def info(_)
|
26
|
+
back = ''
|
27
|
+
length = max_key_length(@node.info) + 2
|
28
|
+
title = format(COLORS[8], "%-#{length}s")
|
29
|
+
@node.info.each do |k, v|
|
30
|
+
back << format("#{title} %s\n", k, v)
|
31
|
+
end
|
32
|
+
back
|
33
|
+
end
|
34
|
+
|
35
|
+
def files(_)
|
36
|
+
@node.files.join("\n") + "\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
def paths(_)
|
40
|
+
@node.paths.join("\n") + "\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_head(without_common)
|
44
|
+
output = ''
|
45
|
+
@node.files(without_common).each_with_index do |f, i|
|
46
|
+
output << format("#{COLORS[i]}\n", "[#{i}] #{f}")
|
47
|
+
@colors[f] = i
|
48
|
+
end
|
49
|
+
"#{output}\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_params_line(key, value, filter)
|
53
|
+
output = ''
|
54
|
+
if !filter || Regexp.new(filter).match(key)
|
55
|
+
first = value.shift
|
56
|
+
filecolor_index = @colors[first[:file]]
|
57
|
+
filecolor = COLORS[filecolor_index]
|
58
|
+
output << format("#{filecolor} #{COLORS[5]} %s\n",
|
59
|
+
"[#{filecolor_index}]",
|
60
|
+
key,
|
61
|
+
first[:value].to_s.gsub('%', '%%')
|
62
|
+
)
|
63
|
+
while value.count > 0
|
64
|
+
overriden = value.shift
|
65
|
+
filecolor_index = @colors[overriden[:file]]
|
66
|
+
output << format(" #{COLORS[8]}\n",
|
67
|
+
"[#{filecolor_index}] #{key} #{overriden[:value]}"
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
output
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_modules_line(key, value)
|
75
|
+
length = max_key_length(@node.modules) + 3
|
76
|
+
value_color = '%s'
|
77
|
+
value_color = COLORS[0] if /not found/i.match value
|
78
|
+
value_color = COLORS[2] if /\(duplicate\)/i.match value
|
79
|
+
format("%-#{length}s #{value_color}\n", key, value)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|