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.
@@ -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: []