jerakia 1.2.1 → 2.0.0
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.
- 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
|