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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a4dda5d22fe6e0fa29b9ce287a9b44f20c2fe3e9
4
- data.tar.gz: 21e5f066edc6cd60249767e8ccd277559d9419d6
3
+ metadata.gz: 4303c4efbf02503a4942b9db6c1396a3f3076a39
4
+ data.tar.gz: 198c1a968a1502b73ce15c0467225e001dff93f8
5
5
  SHA512:
6
- metadata.gz: ab871bf140fd08288bbf39a7be8101c7151823c8eb3249e47e7ed89468399e500111edfc2dc5e108fdae7a557213811afedc5f3e8fb39c310fd27e68c718d187
7
- data.tar.gz: 2d793c5c420b128380d813c92e99bb7c56ff137003a016b2f624eb54e9c2a225172f7a7ae49c40495bbbf98a8342a723347bb3deba7699aaab036268d35b511b
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
- lookup_instance = Jerakia::Launcher.new(request)
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)
@@ -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!(method = :hash) # rubocop:disable Metrics/MethodLength
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 method
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
@@ -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 => key.dup,
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
@@ -3,47 +3,88 @@
3
3
  require 'jerakia/cache'
4
4
  class Jerakia
5
5
  class Datasource
6
- require 'jerakia/response'
6
+ class Instance
7
7
 
8
- attr_reader :response
9
- attr_reader :options
10
- attr_reader :lookup
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
- ## used for verbose logging
27
- def whoami
28
- "datasource=#{@name} lookup=#{@lookup.name}"
29
- end
13
+ attr_reader :options
14
+ attr_reader :request
15
+ attr_reader :response
30
16
 
31
- def option(opt, data = {})
32
- if @options[opt].nil? && data.key?(:default)
33
- @options[opt] = data[:default]
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
- Jerakia.log.debug("[#{whoami}]: options[#{opt}] to #{options[opt]} [#{options[opt].class}]")
37
- if @options[opt].nil?
38
- raise Jerakia::PolicyError, "#{opt} option must be supplied for datasource #{@name} in lookup #{lookup.name}" if data[:mandatory]
39
- else
40
- if data[:type]
41
- if Array(data[:type]).select { |t| @options[opt].is_a?(t) }.empty?
42
- raise Jerakia::PolicyError,
43
- "#{opt} is a #{@options[opt].class} but must be a #{data[:type]} for datasource #{@name} in lookup #{lookup.name}"
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
- module Dummy
3
- def run
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
- class Jerakia::Datasource
4
- module File
5
- attr_reader :file_format
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
- def cache
15
- Jerakia::Cache::File
16
- end
7
+ option(:searchpath, :required => true) { |opt| opt.is_a?(Array) }
17
8
 
18
- def get_file_with_cache(diskname)
19
- if options[:enable_caching]
20
- Jerakia.log.debug("Querying cache for file #{diskname}")
21
- cache.retrieve(diskname)
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
- def list_fragments(prefix, extension)
28
- Dir["#{prefix}.d/*.#{extension}"] if ::File.directory?("#{prefix}.d")
29
- end
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
- def read_from_file(fname)
32
- fpath = []
33
- fpath << options[:docroot] unless fname[0] == '/'
34
- fpath << [fname, lookup.request.namespace]
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
- extension = options[:extension] || @file_format::EXTENSION
37
- diskname_prefix = ::File.join(fpath.flatten).gsub(/\/$/, '').to_s
38
- diskname = "#{diskname_prefix}.#{extension}"
29
+ def cache
30
+ Jerakia::Cache::File
31
+ end
39
32
 
40
- files = [diskname]
41
- files << list_fragments(diskname_prefix, extension)
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
- raw_data = ''
38
+ def get_file(diskname)
39
+ ::File.read(diskname) if ::File.exists?(diskname)
40
+ end
44
41
 
45
- files.flatten.compact.each do |f|
46
- Jerakia.log.debug("read_from_file() #{f}")
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
- raw_data << file_contents if file_contents
68
+ else
69
+ file_content = get_file(f)
49
70
  end
71
+ raw_data << file_contents if file_contents
72
+ end
50
73
 
51
- begin
52
- file_format.convert(raw_data)
53
- rescue Jerakia::FileParseError => e
54
- raise Jerakia::FileParseError, "While parsing #{diskname}: #{e.message}"
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
- def run
59
- #
60
- # Do the lookup
61
-
62
- Jerakia.log.debug("Searching key #{lookup.request.key} from file format #{options[:format]} (#{whoami})")
63
- option :searchpath, :type => Array, :mandatory => true
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