hiera-housekeeper 0.5
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.
- data/lib/hiera/backend/housekeeper_backend.rb +152 -0
- metadata +77 -0
@@ -0,0 +1,152 @@
|
|
1
|
+
### This file is almost exactly the hiera_gpg module by
|
2
|
+
### Craig Dunn (craig@craigdunn.org) (Thanks, mate!)
|
3
|
+
### Hopefully, our additions won't embarrass him.
|
4
|
+
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
class Hiera
|
8
|
+
module Backend
|
9
|
+
class Housekeeper_backend
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
require 'gpgme'
|
13
|
+
@data = Hash.new
|
14
|
+
@cache = Hash.new
|
15
|
+
debug("Loaded housekeeper_backend")
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug (msg)
|
19
|
+
Hiera.debug("[housekeeper_backend]: #{msg}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def warn (msg)
|
23
|
+
Hiera.warn("[housekeeper_backend]: #{msg}")
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def lookup(key, scope, order_override, resolution_type)
|
28
|
+
|
29
|
+
debug("Lookup called, key #{key} resolution type is #{resolution_type}")
|
30
|
+
answer = nil
|
31
|
+
|
32
|
+
# This should compute ~ on both *nix and *doze
|
33
|
+
homes = ["HOME", "HOMEPATH"]
|
34
|
+
real_home = homes.detect { |h| ENV[h] != nil }
|
35
|
+
|
36
|
+
key_dir = Backend.parse_string(Config[:gpg][:key_dir], scope) || "#{ENV[real_home]}/.gnupg"
|
37
|
+
fqdn = Socket.gethostbyname(Socket.gethostname).first
|
38
|
+
housekeeper_server = Backend.parse_string(Config[:housekeeper][:url], scope)
|
39
|
+
housekeeper_keyname = Backend.parse_string(Config[:housekeeper][:keyname], scope) || "puppet"
|
40
|
+
housekeeper_branch = Backend.parse_string(Config[:housekeeper][:branch], scope) || "master"
|
41
|
+
housekeeper_identity = "#{housekeeper_keyname}@#{fqdn}"
|
42
|
+
|
43
|
+
seen_sources = []
|
44
|
+
|
45
|
+
Backend.datasources(scope, order_override) do |source|
|
46
|
+
begin
|
47
|
+
next if seen_sources.include? source
|
48
|
+
uri = URI.parse("http://#{housekeeper_server}:80/file/#{housekeeper_identity}/branches/#{housekeeper_branch}/hieradata/#{source}.gpg")
|
49
|
+
seen_sources.push(source)
|
50
|
+
gpgfile = open(uri).read()
|
51
|
+
rescue OpenURI::HTTPError
|
52
|
+
next
|
53
|
+
end
|
54
|
+
|
55
|
+
unless @data.has_key?(gpgfile) and !stale?(gpgfile)
|
56
|
+
plain = decrypt(gpgfile, key_dir)
|
57
|
+
|
58
|
+
next if !plain
|
59
|
+
next if !plain.kind_of?(String)
|
60
|
+
next if plain.empty?
|
61
|
+
debug("GPG decrypt returned valid data")
|
62
|
+
|
63
|
+
begin
|
64
|
+
@data[gpgfile] = YAML.load(plain)
|
65
|
+
rescue
|
66
|
+
warn("YAML decoding data in #{gpgfile} failed")
|
67
|
+
@data[gpgfile] = {}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
data = @data[gpgfile]
|
72
|
+
next if !data
|
73
|
+
next if data.empty?
|
74
|
+
debug ("Data contains valid YAML")
|
75
|
+
|
76
|
+
next unless data.include?(key)
|
77
|
+
debug ("Key #{key} found in YAML document, Passing answer to hiera")
|
78
|
+
|
79
|
+
parsed_answer = Backend.parse_answer(data[key], scope)
|
80
|
+
|
81
|
+
begin
|
82
|
+
case resolution_type
|
83
|
+
when :array
|
84
|
+
debug("Appending answer array")
|
85
|
+
raise Exception, "Hiera type mismatch: expected Array and got #{parsed_answer.class}" unless parsed_answer.kind_of? Array or parsed_answer.kind_of? String
|
86
|
+
answer ||= []
|
87
|
+
answer << parsed_answer
|
88
|
+
when :hash
|
89
|
+
debug("Merging answer hash")
|
90
|
+
raise Exception, "Hiera type mismatch: expected Hash and got #{parsed_answer.class}" unless parsed_answer.kind_of? Hash
|
91
|
+
answer ||= {}
|
92
|
+
answer = parsed_answer.merge answer
|
93
|
+
else
|
94
|
+
debug("Assigning answer variable")
|
95
|
+
answer = parsed_answer
|
96
|
+
break
|
97
|
+
end
|
98
|
+
rescue NoMethodError
|
99
|
+
raise Exception, "Resolution type is #{resolution_type} but parsed_answer is a #{parsed_answer.class}"
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
return answer
|
104
|
+
end
|
105
|
+
|
106
|
+
def decrypt(cipher, gnupghome)
|
107
|
+
|
108
|
+
gnupghome_backup = ENV["GNUPGHOME"]
|
109
|
+
ENV["GNUPGHOME"] = gnupghome
|
110
|
+
debug("GNUPGHOME is #{ENV['GNUPGHOME']}")
|
111
|
+
|
112
|
+
ctx = GPGME::Ctx.new
|
113
|
+
|
114
|
+
if !ctx.keys.empty?
|
115
|
+
raw = GPGME::Data.new(cipher)
|
116
|
+
txt = GPGME::Data.new
|
117
|
+
|
118
|
+
begin
|
119
|
+
txt = ctx.decrypt(raw)
|
120
|
+
rescue GPGME::Error::DecryptFailed
|
121
|
+
warn("Warning: GPG Decryption failed, check your GPG settings")
|
122
|
+
rescue
|
123
|
+
warn("Warning: General exception decrypting GPG file")
|
124
|
+
ensure
|
125
|
+
ENV["GNUPGHOME"] = gnupghome_backup
|
126
|
+
end
|
127
|
+
|
128
|
+
txt.seek 0
|
129
|
+
result = txt.read
|
130
|
+
|
131
|
+
debug("result is a #{result.class} ctx #{ctx} txt #{txt}")
|
132
|
+
return result
|
133
|
+
else
|
134
|
+
warn("No usable keys found in #{gnupghome}. Check :key_dir value in hiera.yaml is correct")
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def stale?(gpgfile)
|
140
|
+
# NOTE: The mtime change in a file MUST be > 1 second before being
|
141
|
+
# recognized as stale. File mtime changes within 1 second will
|
142
|
+
# not be recognized.
|
143
|
+
stat = File.stat(gpgfile)
|
144
|
+
current = { 'inode' => stat.ino, 'mtime' => stat.mtime, 'size' => stat.size }
|
145
|
+
return false if @cache[gpgfile] == current
|
146
|
+
|
147
|
+
@cache[gpgfile] = current
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hiera-housekeeper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.5'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Neil Houston
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-05-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: hiera
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.2.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: hiera-gpg
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.1.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.1.0
|
46
|
+
description: Hiera backend for fetching encrypted data from housekeeper
|
47
|
+
email: neil.a.houston@gmail.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- lib/hiera/backend/housekeeper_backend.rb
|
53
|
+
homepage: http://github.com/ConnectedHomes/housekeeper
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.8.23
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Housekeeper backend for Hiera
|
77
|
+
test_files: []
|