/usr/bin/hiera is in ruby-hiera 1.3.0-1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | #!/usr/bin/env ruby
# CLI client for Hiera.
#
# To lookup the 'release' key for a node given Puppet YAML facts:
#
# $ hiera release 'rel/%{location}' --yaml some.node.yaml
#
# If the node yaml had a location fact the default would match that
# else you can supply scope values on the command line
#
# $ hiera release 'rel/%{location}' location=dc2 --yaml some.node.yaml
# Bundler and rubygems maintain a set of directories from which to
# load gems. If Bundler is loaded, let it determine what can be
# loaded. If it's not loaded, then use rubygems. But do this before
# loading any hiera code, so that our gem loading system is sane.
if not defined? ::Bundler
begin
require 'rubygems'
rescue LoadError
end
end
require 'hiera'
require 'hiera/util'
require 'optparse'
require 'pp'
options = {
:default => nil,
:config => File.join(Hiera::Util.config_dir, 'hiera.yaml'),
:scope => {},
:key => nil,
:verbose => false,
:resolution_type => :priority
}
# Loads the scope from YAML or JSON files
def load_scope(source, type=:yaml)
case type
when :mcollective
begin
require 'mcollective'
include MCollective::RPC
util = rpcclient("rpcutil")
util.progress = false
nodestats = util.custom_request("inventory", {}, source, {"identity" => source}).first
raise "Failed to retrieve facts for node #{source}: #{nodestats[:statusmsg]}" unless nodestats[:statuscode] == 0
scope = nodestats[:data][:facts]
rescue Exception => e
STDERR.puts "MCollective lookup failed: #{e.class}: #{e}"
exit 1
end
when :yaml
raise "Cannot find scope #{type} file #{source}" unless File.exist?(source)
require 'yaml'
# Attempt to load puppet in case we're going to be fed
# Puppet yaml files
begin
require 'puppet'
rescue
end
scope = YAML.load_file(source)
# Puppet makes dumb yaml files that do not promote data reuse.
scope = scope.values if scope.is_a?(Puppet::Node::Facts)
when :json
raise "Cannot find scope #{type} file #{source}" unless File.exist?(source)
require 'json'
scope = JSON.load(File.read(source))
when :inventory_service
# For this to work the machine running the hiera command needs access to
# /facts REST endpoint on your inventory server. This access is
# controlled in auth.conf and identification is by the certname of the
# machine running hiera commands.
#
# Another caveat is that if your inventory server isn't at the short dns
# name of 'puppet' you will need to set the inventory_sever option in
# your puppet.conf. Set it in either the master or main sections. It
# is fine to have the inventory_server option set even if the config
# doesn't have the fact_terminus set to rest.
begin
require 'puppet/util/run_mode'
$puppet_application_mode = Puppet::Util::RunMode[:master]
require 'puppet'
Puppet.settings.parse
Puppet::Node::Facts.indirection.terminus_class = :rest
scope = YAML.load(Puppet::Node::Facts.indirection.find(source).to_yaml)
# Puppet makes dumb yaml files that do not promote data reuse.
scope = scope.values if scope.is_a?(Puppet::Node::Facts)
rescue Exception => e
STDERR.puts "Puppet inventory service lookup failed: #{e.class}: #{e}"
exit 1
end
else
raise "Don't know how to load data type #{type}"
end
raise "Scope from #{type} file #{source} should be a Hash" unless scope.is_a?(Hash)
scope
end
OptionParser.new do |opts|
opts.banner = "Usage: hiera [options] key [default value] [variable='text'...]\n\nThe default value will be used if no value is found for the key. Scope variables\nwill be interpolated into %{variable} placeholders in the hierarchy and in\nreturned values.\n\n"
opts.on("--version", "-V", "Version information") do
puts Hiera.version
exit
end
opts.on("--debug", "-d", "Show debugging information") do
options[:verbose] = true
end
opts.on("--array", "-a", "Return all values as an array") do
options[:resolution_type] = :array
end
opts.on("--hash", "-h", "Return all values as a hash") do
options[:resolution_type] = :hash
end
opts.on("--config CONFIG", "-c", "Configuration file") do |v|
if File.exist?(v)
options[:config] = v
else
STDERR.puts "Cannot find config file: #{v}"
exit 1
end
end
opts.on("--json SCOPE", "-j", "JSON format file to load scope from") do |v|
begin
options[:scope] = load_scope(v, :json)
rescue Exception => e
STDERR.puts "Could not load JSON scope: #{e.class}: #{e}"
exit 1
end
end
opts.on("--yaml SCOPE", "-y", "YAML format file to load scope from") do |v|
begin
options[:scope] = load_scope(v)
rescue Exception => e
STDERR.puts "Could not load YAML scope: #{e.class}: #{e}"
exit 1
end
end
opts.on("--mcollective IDENTITY", "-m", "Use facts from a node (via mcollective) as scope") do |v|
begin
options[:scope] = load_scope(v, :mcollective)
rescue Exception => e
STDERR.puts "Could not load MCollective scope: #{e.class}: #{e}"
exit 1
end
end
opts.on("--inventory_service IDENTITY", "-i", "Use facts from a node (via Puppet's inventory service) as scope") do |v|
begin
options[:scope] = load_scope(v, :inventory_service)
rescue Exception => e
STDERR.puts "Could not load Puppet inventory service scope: #{e.class}: #{e}"
exit 1
end
end
end.parse!
# arguments can be:
#
# key default var=val another=val
#
# The var=val's assign scope
unless ARGV.empty?
options[:key] = ARGV.delete_at(0)
ARGV.each do |arg|
if arg =~ /^(.+?)=(.+?)$/
options[:scope][$1] = $2
else
unless options[:default]
options[:default] = arg.dup
else
STDERR.puts "Don't know how to parse scope argument: #{arg}"
end
end
end
else
STDERR.puts "Please supply a data item to look up"
exit 1
end
begin
hiera = Hiera.new(:config => options[:config])
rescue Exception => e
if options[:verbose]
raise
else
STDERR.puts "Failed to start Hiera: #{e.class}: #{e}"
exit 1
end
end
unless options[:verbose]
Hiera.logger = "noop"
end
ans = hiera.lookup(options[:key], options[:default], options[:scope], nil, options[:resolution_type])
if ans.is_a?(String)
puts ans
else
pp ans
end
|