hieracles 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +2 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +5 -0
  7. data/CHANGELOG.md +8 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +22 -0
  10. data/README.md +30 -0
  11. data/Rakefile +14 -0
  12. data/bin/hc +32 -0
  13. data/bin/nodeinfo +41 -0
  14. data/hieracles.gemspec +30 -0
  15. data/lib/hieracles.rb +15 -0
  16. data/lib/hieracles/config.rb +56 -0
  17. data/lib/hieracles/format.rb +58 -0
  18. data/lib/hieracles/formats/console.rb +84 -0
  19. data/lib/hieracles/formats/csv.rb +66 -0
  20. data/lib/hieracles/formats/plain.rb +61 -0
  21. data/lib/hieracles/formats/yaml.rb +36 -0
  22. data/lib/hieracles/help.rb +27 -0
  23. data/lib/hieracles/hiera.rb +27 -0
  24. data/lib/hieracles/node.rb +108 -0
  25. data/lib/hieracles/optparse.rb +63 -0
  26. data/lib/hieracles/utils.rb +59 -0
  27. data/spec/files/config.yml +5 -0
  28. data/spec/files/enc/server.example.com.yaml +7 -0
  29. data/spec/files/enc/server2.example.com.yaml +7 -0
  30. data/spec/files/enc/server3.example.com.yaml +7 -0
  31. data/spec/files/farm_modules/dev.pp +5 -0
  32. data/spec/files/farm_modules/dev2.pp +5 -0
  33. data/spec/files/hiera.yaml +16 -0
  34. data/spec/files/hiera_no_yamlbackend.yaml +16 -0
  35. data/spec/files/hiera_yamlbackend_notfound.yaml +16 -0
  36. data/spec/files/modules/fake_module/manifests/init.pp +3 -0
  37. data/spec/files/modules/fake_module2/manifests/init.pp +3 -0
  38. data/spec/files/modules/fake_module3/manifests/init.pp +3 -0
  39. data/spec/files/params/common/common.yml +2 -0
  40. data/spec/files/params/farm/dev.yaml +1 -0
  41. data/spec/files/params/nodes/server.example.com.yaml +5 -0
  42. data/spec/lib/config_spec.rb +63 -0
  43. data/spec/lib/format_spec.rb +91 -0
  44. data/spec/lib/formats/console_spec.rb +107 -0
  45. data/spec/lib/formats/csv_spec.rb +89 -0
  46. data/spec/lib/formats/plain_spec.rb +94 -0
  47. data/spec/lib/formats/yaml_spec.rb +80 -0
  48. data/spec/lib/help_spec.rb +8 -0
  49. data/spec/lib/hiera_spec.rb +111 -0
  50. data/spec/lib/node_spec.rb +158 -0
  51. data/spec/lib/optparse_spec.rb +65 -0
  52. data/spec/lib/utils_spec.rb +61 -0
  53. data/spec/spec_helper.rb +26 -0
  54. 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
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: MMYNBOKRQNladhirYnmkuJ3DqNSMbJh40
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format Fivemat
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.2.2
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hieracles.gemspec
4
+ gemspec
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