jerakia 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jerakia.rb +4 -5
- data/lib/jerakia/answer.rb +33 -3
- data/lib/jerakia/cli.rb +3 -1
- data/lib/jerakia/cli/lookup.rb +3 -3
- data/lib/jerakia/cli/secret.rb +58 -0
- data/lib/jerakia/datasource.rb +73 -32
- data/lib/jerakia/datasource/dummy.rb +6 -10
- data/lib/jerakia/datasource/file.rb +77 -63
- data/lib/jerakia/datasource/file/json.rb +9 -11
- data/lib/jerakia/datasource/file/yaml.rb +12 -14
- data/lib/jerakia/dsl/lookup.rb +15 -17
- data/lib/jerakia/dsl/policy.rb +11 -8
- data/lib/jerakia/encryption.rb +60 -0
- data/lib/jerakia/encryption/vault.rb +168 -0
- data/lib/jerakia/error.rb +10 -0
- data/lib/jerakia/launcher.rb +18 -6
- data/lib/jerakia/log.rb +2 -18
- data/lib/jerakia/lookup.rb +0 -24
- data/lib/jerakia/policy.rb +31 -58
- data/lib/jerakia/response/filter.rb +2 -1
- data/lib/jerakia/response/filter/encryption.rb +21 -38
- data/lib/jerakia/schema.rb +3 -3
- data/lib/jerakia/util/http.rb +51 -0
- data/lib/jerakia/version.rb +1 -1
- metadata +6 -7
- data/lib/hiera/backend/jerakia_backend.rb +0 -59
- data/lib/jerakia/datasource/file_new.rb +0 -82
- data/lib/jerakia/policy/registry.rb +0 -23
- data/lib/puppet/indirector/data_binding/jerakia.rb +0 -33
- data/lib/puppet/indirector/data_binding/jerakia_rest.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4303c4efbf02503a4942b9db6c1396a3f3076a39
|
4
|
+
data.tar.gz: 198c1a968a1502b73ce15c0467225e001dff93f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8ab25c31d6044d86ba469d5f33c043152e269a4a22f52f991b3edfe8950012e0ec3889cf77c80e8ce4047af154176a438914d4f3bdcd7e72a86b9ab730cc826
|
7
|
+
data.tar.gz: ab5dd6838aec464f3a053d227ee71ed3180cbd79d0c592ba4b490023501882e8467b94b302f6c2176e2e4c052ced0fa1685ac602bf6c56c0719c848c34c512be
|
data/lib/jerakia.rb
CHANGED
@@ -15,6 +15,7 @@ class Jerakia
|
|
15
15
|
require 'jerakia/error'
|
16
16
|
|
17
17
|
attr_reader :options
|
18
|
+
attr_reader :launcher
|
18
19
|
|
19
20
|
class << self
|
20
21
|
attr_reader :config
|
@@ -26,6 +27,7 @@ class Jerakia
|
|
26
27
|
|
27
28
|
def initialize(options = {})
|
28
29
|
@options = options
|
30
|
+
@policies = {}
|
29
31
|
|
30
32
|
load_config
|
31
33
|
load_log_handler
|
@@ -36,14 +38,11 @@ class Jerakia
|
|
36
38
|
|
37
39
|
log.debug('Jerakia initialized')
|
38
40
|
Jerakia.log.verbose("Jerakia started. Version #{Jerakia::VERSION}")
|
41
|
+
@launcher = Jerakia::Launcher.new
|
39
42
|
end
|
40
43
|
|
41
44
|
def lookup(request)
|
42
|
-
|
43
|
-
lookup_instance.invoke_from_file
|
44
|
-
lookup_instance.answer
|
45
|
-
rescue Jerakia::Error => e
|
46
|
-
Jerakia.fatal(e.message, e)
|
45
|
+
launcher.policies[request.policy.to_sym].run(request)
|
47
46
|
end
|
48
47
|
|
49
48
|
def self.fatal(msg, e)
|
data/lib/jerakia/answer.rb
CHANGED
@@ -4,9 +4,12 @@ class Jerakia
|
|
4
4
|
|
5
5
|
attr_accessor :payload
|
6
6
|
attr_accessor :datatype
|
7
|
+
attr_reader :merge_strategy
|
7
8
|
attr_reader :lookup_type
|
8
9
|
|
9
|
-
def initialize(lookup_type = :first)
|
10
|
+
def initialize(lookup_type = :first, merge_strategy = :array)
|
11
|
+
@lookup_type = lookup_type
|
12
|
+
@merge_strategy = merge_strategy
|
10
13
|
case lookup_type
|
11
14
|
when :first
|
12
15
|
@payload = nil
|
@@ -16,17 +19,44 @@ class Jerakia
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
22
|
+
def process_response(response_entries)
|
23
|
+
response_entries.flatten.each do |res|
|
24
|
+
case lookup_type
|
25
|
+
when :first
|
26
|
+
@payload = res[:value]
|
27
|
+
@datatype = res[:datatype]
|
28
|
+
Jerakia.log.debug("Registered answer as #{payload}")
|
29
|
+
break
|
30
|
+
when :cascade
|
31
|
+
@payload << res[:value]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
consolidate
|
35
|
+
end
|
36
|
+
|
37
|
+
def consolidate
|
38
|
+
if lookup_type == :cascade && payload.is_a?(Array)
|
39
|
+
case merge_strategy
|
40
|
+
when :array
|
41
|
+
flatten_payload!
|
42
|
+
when :hash, :deep_hash
|
43
|
+
merge_payload!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
19
49
|
def flatten_payload!
|
20
50
|
@payload.flatten!
|
21
51
|
end
|
22
52
|
|
23
53
|
# TODO: consolidate this into less lines
|
24
54
|
#
|
25
|
-
def merge_payload!
|
55
|
+
def merge_payload! # rubocop:disable Metrics/MethodLength
|
26
56
|
payload_hash = {}
|
27
57
|
@payload.each do |p|
|
28
58
|
next unless p.is_a?(Hash)
|
29
|
-
case
|
59
|
+
case merge_strategy
|
30
60
|
when :hash
|
31
61
|
payload_hash = p.merge(payload_hash)
|
32
62
|
when :deep_hash
|
data/lib/jerakia/cli.rb
CHANGED
@@ -5,13 +5,15 @@ require 'yaml'
|
|
5
5
|
require 'jerakia/cli/server'
|
6
6
|
require 'jerakia/cli/token'
|
7
7
|
require 'jerakia/cli/lookup'
|
8
|
-
|
8
|
+
require 'jerakia/cli/secret'
|
9
9
|
|
10
10
|
class Jerakia
|
11
11
|
class CLI < Thor
|
12
12
|
include Jerakia::CLI::Server
|
13
13
|
include Jerakia::CLI::Lookup
|
14
14
|
include Jerakia::CLI::Token
|
15
|
+
include Jerakia::CLI::Secret
|
16
|
+
|
15
17
|
|
16
18
|
desc 'version', 'Version information'
|
17
19
|
def version
|
data/lib/jerakia/cli/lookup.rb
CHANGED
@@ -66,13 +66,13 @@ class Jerakia
|
|
66
66
|
efault: 'json',
|
67
67
|
desc: 'Output format, yaml or json'
|
68
68
|
|
69
|
-
def lookup(key)
|
69
|
+
def lookup(key=nil)
|
70
70
|
# Thor by default now returns a frozen options hash so we
|
71
71
|
# need to dup this here to prevent problems later with
|
72
72
|
# modifying the request object
|
73
73
|
#
|
74
74
|
options_copy = options.dup
|
75
|
-
|
75
|
+
key_copy = key.nil? ? key : key.dup
|
76
76
|
case true
|
77
77
|
when options[:verbose]
|
78
78
|
loglevel = 'verbose'
|
@@ -91,7 +91,7 @@ class Jerakia
|
|
91
91
|
:loglevel => loglevel,
|
92
92
|
:trace => options[:trace])
|
93
93
|
req = Jerakia::Request.new(
|
94
|
-
:key =>
|
94
|
+
:key => key_copy,
|
95
95
|
:namespace => options_copy[:namespace].split(/::/),
|
96
96
|
:policy => options_copy[:policy].to_sym,
|
97
97
|
:lookup_type => options_copy[:type].to_sym,
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'jerakia/encryption'
|
2
|
+
require 'jerakia'
|
3
|
+
|
4
|
+
class Jerakia
|
5
|
+
class CLI < Thor
|
6
|
+
module Secret
|
7
|
+
class Secret < Thor
|
8
|
+
|
9
|
+
Jerakia.new
|
10
|
+
@provider = Jerakia::Encryption.new
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :provider
|
14
|
+
end
|
15
|
+
|
16
|
+
no_commands do
|
17
|
+
def provider
|
18
|
+
self.class.provider
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if @provider.features?(:decrypt)
|
23
|
+
desc 'decrypt <encrypted value>', 'Decrypt an encrypted value'
|
24
|
+
def decrypt(encrypted)
|
25
|
+
begin
|
26
|
+
plaintext = provider.decrypt(encrypted)
|
27
|
+
rescue Jerakia::EncryptionError => e
|
28
|
+
puts e.message
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
puts plaintext
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if @provider.features?(:encrypt)
|
36
|
+
desc 'encrypt <string>', 'Encrypt a plain text string'
|
37
|
+
def encrypt(plaintext)
|
38
|
+
begin
|
39
|
+
encrypted = provider.encrypt(plaintext)
|
40
|
+
rescue Jerakia::EncryptionError => e
|
41
|
+
puts e.message
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
puts encrypted
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.included(thor)
|
50
|
+
thor.class_eval do
|
51
|
+
info = Secret.provider.loaded? ? "" : "(No encryption provider configured!)"
|
52
|
+
desc 'secret [SUBCOMMAND] <options>', "Manage encrypted secrets #{info}"
|
53
|
+
subcommand 'secret', Secret
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/jerakia/datasource.rb
CHANGED
@@ -3,47 +3,88 @@
|
|
3
3
|
require 'jerakia/cache'
|
4
4
|
class Jerakia
|
5
5
|
class Datasource
|
6
|
-
|
6
|
+
class Instance
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
attr_reader :name
|
12
|
-
|
13
|
-
def initialize(name, lookup, opts)
|
14
|
-
@response = Jerakia::Response.new(lookup)
|
15
|
-
@options = opts
|
16
|
-
@lookup = lookup
|
17
|
-
@name = name
|
18
|
-
begin
|
19
|
-
require "jerakia/datasource/#{name}"
|
20
|
-
eval "extend Jerakia::Datasource::#{name.capitalize}"
|
21
|
-
rescue LoadError => e
|
22
|
-
raise Jerakia::Error, "Cannot load datasource #{name} in lookup #{lookup.name}, #{e.message}"
|
8
|
+
class << self
|
9
|
+
attr_reader :features
|
10
|
+
attr_accessor :options
|
23
11
|
end
|
24
|
-
end
|
25
12
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
13
|
+
attr_reader :options
|
14
|
+
attr_reader :request
|
15
|
+
attr_reader :response
|
30
16
|
|
31
|
-
|
32
|
-
|
33
|
-
@
|
17
|
+
def initialize(lookup, opts)
|
18
|
+
self.class.validate_options(opts)
|
19
|
+
@response = Jerakia::Response.new(lookup)
|
20
|
+
@options = opts
|
21
|
+
@request = lookup.request
|
22
|
+
@features = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def answer(data=nil)
|
26
|
+
if block_given?
|
27
|
+
while @response.want?
|
28
|
+
yield @response
|
29
|
+
end
|
30
|
+
else
|
31
|
+
@response.submit(data) if response.want? and not data.nil?
|
32
|
+
end
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
def self.feature(name)
|
36
|
+
@features << name.to_sym unless @features.include?(name.to_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def features?(name)
|
40
|
+
@features.include?(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.option(name, arguments = {}, &block)
|
44
|
+
self.options={} if self.options.nil?
|
45
|
+
@options[name] = Proc.new do |opt|
|
46
|
+
if arguments[:default]
|
47
|
+
opt = arguments[:default] if opt.nil?
|
48
|
+
end
|
49
|
+
if arguments[:required]
|
50
|
+
raise Jerakia::DatasourceArgumentError, "Must specify #{name} parameter" if opt.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
if block_given?
|
54
|
+
unless opt.nil?
|
55
|
+
raise Jerakia::DatasourceArgumentError, "Validation failed for #{name}" unless yield opt
|
56
|
+
end
|
44
57
|
end
|
58
|
+
opt
|
45
59
|
end
|
46
60
|
end
|
61
|
+
def self.validate_options(args)
|
62
|
+
options.keys.each do |k|
|
63
|
+
options[k].call(args[k])
|
64
|
+
end
|
65
|
+
|
66
|
+
args.keys.each do |k|
|
67
|
+
raise Jerakia::DatasourceArgumentError, "Unknown option #{k}" unless options.keys.include?(k)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
require 'jerakia/response'
|
73
|
+
|
74
|
+
def self.load_datasource(name)
|
75
|
+
require "jerakia/datasource/#{name.to_s}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.class_of(name)
|
79
|
+
return eval "Jerakia::Datasource::#{name.to_s.capitalize}"
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def self.run(lookup)
|
84
|
+
options = lookup.datasource[:opts]
|
85
|
+
datasource = class_of(lookup.datasource[:name]).new(lookup, options)
|
86
|
+
datasource.lookup
|
87
|
+
return datasource.response
|
47
88
|
end
|
48
89
|
end
|
49
90
|
end
|
@@ -1,12 +1,8 @@
|
|
1
|
-
class Jerakia::Datasource
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# Do the lookup
|
6
|
-
|
7
|
-
Jerakia.log.debug("Searching key #{lookup.request.key} in dummy datasource")
|
8
|
-
option :return, :type => [String, Hash, Array], :default => 'Returned data'
|
9
|
-
response.submit options[:return]
|
10
|
-
end
|
1
|
+
class Jerakia::Datasource::Dummy < Jerakia::Datasource::Instance
|
2
|
+
option :return, :default => 'Returned data'
|
3
|
+
def lookup
|
4
|
+
answer options[:return]
|
11
5
|
end
|
12
6
|
end
|
7
|
+
|
8
|
+
|
@@ -1,81 +1,95 @@
|
|
1
1
|
require 'jerakia/cache/file'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def load_format_handler
|
8
|
-
format = options[:format] || :yaml
|
9
|
-
class_name = format.to_s.capitalize
|
10
|
-
require "jerakia/datasource/file/#{format}"
|
11
|
-
@file_format = eval "Jerakia::Datasource::File::#{class_name}"
|
12
|
-
end
|
3
|
+
#Jerakia::Datasource.define(:file) do
|
4
|
+
#
|
5
|
+
class Jerakia::Datasource::File < Jerakia::Datasource::Instance
|
13
6
|
|
14
|
-
|
15
|
-
Jerakia::Cache::File
|
16
|
-
end
|
7
|
+
option(:searchpath, :required => true) { |opt| opt.is_a?(Array) }
|
17
8
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
::File.read(diskname) if ::File.exists?(diskname)
|
24
|
-
end
|
25
|
-
end
|
9
|
+
option :format, :default => :yaml
|
10
|
+
option :docroot, :default => '/var/lib/jerakia/data'
|
11
|
+
option :extention
|
12
|
+
option :enable_caching, :default => true
|
26
13
|
|
27
|
-
|
28
|
-
|
29
|
-
|
14
|
+
def load_format_handler
|
15
|
+
format = options[:format]
|
16
|
+
require "jerakia/datasource/file/#{format.to_s}"
|
17
|
+
eval "extend Jerakia::Datasource::File::#{format.to_s.capitalize}"
|
18
|
+
end
|
30
19
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
20
|
+
def format_handler
|
21
|
+
format = options[:format]
|
22
|
+
eval "Jerakia::Datasource::File::#{format.to_s.capitalize}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def extension
|
26
|
+
options[:extension] || format_handler::EXTENSION
|
27
|
+
end
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
def cache
|
30
|
+
Jerakia::Cache::File
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
|
33
|
+
def get_file_with_cache(diskname)
|
34
|
+
Jerakia.log.debug("Querying cache for file #{diskname}")
|
35
|
+
cache.retrieve(diskname)
|
36
|
+
end
|
42
37
|
|
43
|
-
|
38
|
+
def get_file(diskname)
|
39
|
+
::File.read(diskname) if ::File.exists?(diskname)
|
40
|
+
end
|
44
41
|
|
45
|
-
|
46
|
-
|
42
|
+
def list_fragments(prefix, extension)
|
43
|
+
Dir["#{prefix}.d/*.#{extension}"] if ::File.directory?("#{prefix}.d")
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_from_file(fname)
|
47
|
+
docroot = options[:docroot]
|
48
|
+
namespace = request.namespace
|
49
|
+
cached = options[:enable_caching]
|
50
|
+
|
51
|
+
fpath = []
|
52
|
+
fpath << docroot unless fname[0] == '/'
|
53
|
+
fpath << [fname, namespace]
|
54
|
+
|
55
|
+
diskname_prefix = ::File.join(fpath.flatten).gsub(/\/$/, '').to_s
|
56
|
+
diskname = "#{diskname_prefix}.#{extension}"
|
57
|
+
|
58
|
+
files = [diskname]
|
59
|
+
files << list_fragments(diskname_prefix, extension)
|
60
|
+
|
61
|
+
raw_data = ''
|
62
|
+
|
63
|
+
files.flatten.compact.each do |f|
|
64
|
+
Jerakia.log.debug("read_from_file() #{f}")
|
65
|
+
file_contents = get_file_with_cache(f)
|
66
|
+
if cached
|
47
67
|
file_contents = get_file_with_cache(f)
|
48
|
-
|
68
|
+
else
|
69
|
+
file_content = get_file(f)
|
49
70
|
end
|
71
|
+
raw_data << file_contents if file_contents
|
72
|
+
end
|
50
73
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
74
|
+
begin
|
75
|
+
convert(raw_data)
|
76
|
+
rescue Jerakia::FileParseError => e
|
77
|
+
raise Jerakia::FileParseError, "While parsing #{diskname}: #{e.message}"
|
56
78
|
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def lookup
|
82
|
+
Jerakia.log.debug("Searching key #{request.key} from file format #{options[:format]}")
|
83
|
+
|
84
|
+
load_format_handler
|
85
|
+
paths=options[:searchpath].flatten
|
57
86
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
option :format, :type => Symbol, :default => :yaml
|
65
|
-
option :docroot, :type => String, :default => '/etc/jerakia/data'
|
66
|
-
option :extension, :type => String
|
67
|
-
|
68
|
-
load_format_handler
|
69
|
-
|
70
|
-
options[:searchpath].flatten.each do |path|
|
71
|
-
Jerakia.log.debug("Attempting to load data from #{path}")
|
72
|
-
return unless response.want?
|
73
|
-
data = read_from_file(path)
|
74
|
-
Jerakia.log.debug("Datasource provided #{data} looking for key #{lookup.request.key}")
|
75
|
-
unless data[lookup.request.key].nil?
|
76
|
-
Jerakia.log.debug("Found data #{data[lookup.request.key]}")
|
77
|
-
response.submit data[lookup.request.key]
|
78
|
-
end
|
87
|
+
answer do |response|
|
88
|
+
path = paths.shift
|
89
|
+
break unless path
|
90
|
+
data = read_from_file(path)
|
91
|
+
unless data[request.key].nil?
|
92
|
+
response.submit data[request.key]
|
79
93
|
end
|
80
94
|
end
|
81
95
|
end
|