jerakia 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e7a0ffdcc717ef8705465da1d89d701353e31a4d
4
+ data.tar.gz: a40d224bb84863097b2b1e4d877aa5b8bfbed9c7
5
+ SHA512:
6
+ metadata.gz: a1e2f422baea90e6bc37df8bd5ed1b9717b41a3968b4eb44ad50dfa80eb1defdc11461da6f57e749fd074d4a986a9f135ea9ddee6797fcd9a73ef14dcca0e9b5
7
+ data.tar.gz: a6f211698de9b7286b674e76285f9720bc7c50a70f5bb9d9d121610592fae36ecf5d0bb858fdaf54ea7268d3108f93f322514a5f4cefbe8d963b02ac9c61d931
data/bin/jerakia ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'jerakia'
4
+ require 'json'
5
+ require 'optparse'
6
+
7
+ options = {
8
+ :policy => "default",
9
+ :config => "/etc/jerakia/jerakia.yml",
10
+ :scope => nil,
11
+ :key => nil,
12
+ :merge => "array",
13
+ :lookup_type => "first",
14
+ :namespace => nil,
15
+ :metadata => {},
16
+ }
17
+
18
+ OptionParser.new do |opts|
19
+
20
+ opts.on("--config CONFIG","-c","Config file") do |c|
21
+ options[:config] = c
22
+ end
23
+
24
+ opts.on("--key KEY", "-k", "Lookup key") do |k|
25
+ options[:key] = k
26
+ end
27
+
28
+ opts.on("--policy POLICY", "-p", "Policy") do |p|
29
+ options[:policy] = p.to_sym
30
+ end
31
+
32
+ opts.on("--namespace NAMESPACE", "-n", "Namespace") do |n|
33
+ options[:namespace] = n.split(/::/)
34
+ end
35
+
36
+ opts.on("--type TYPE", "-t", "Lookup type") do |t|
37
+ options[:lookup_type] = t.to_sym
38
+ end
39
+
40
+ opts.on("--scope SCOPE", "-s", "Scope handler") do |s|
41
+ options[:scope] = s.to_sym
42
+ end
43
+
44
+ opts.on("--merge MERGE", "-m", "Merge type") do |m|
45
+ options[:merge] = m.to_sym
46
+ end
47
+ end.parse!
48
+
49
+ unless ARGV.empty?
50
+ ARGV.each do |arg|
51
+ meta=arg.split(':')
52
+ options[:metadata][meta[0]] = meta[1]
53
+ end
54
+ end
55
+
56
+
57
+
58
+ jac = Jerakia.new({:config => options[:config]})
59
+ req = Jerakia::Request.new(
60
+ :key => options[:key],
61
+ :namespace => options[:namespace],
62
+ :policy => options[:policy].to_sym,
63
+ :lookup_type => options[:lookup_type].to_sym,
64
+ :merge => options[:merge].to_sym,
65
+ :loglevel => 'debug',
66
+ :metadata => options[:metadata]
67
+ )
68
+
69
+
70
+ answer = jac.lookup(req)
71
+ puts answer.payload.to_json
@@ -0,0 +1,67 @@
1
+ class Hiera
2
+ module Backend
3
+ class Jerakia_backend
4
+
5
+ def initialize
6
+ require 'jerakia'
7
+ @config = Config[:jerakia] || {}
8
+ @policy = @config[:policy] || 'default'
9
+ @jerakia = ::Jerakia.new(Config[:jerakia] || {})
10
+ Jerakia.log.debug("[hiera] hiera backend loaded with policy #{@policy}")
11
+
12
+ end
13
+
14
+
15
+ def lookup(key, scope, order_override, resolution_type)
16
+
17
+
18
+ lookup_type = :first
19
+ merge_type = :none
20
+
21
+ case resolution_type
22
+ when :array
23
+ lookup_type = :cascade
24
+ merge_type = :array
25
+ when :hash
26
+ lookup_type = :cascade
27
+ merge_type = :hash
28
+ end
29
+
30
+ namespace = []
31
+
32
+ if key.include?('::')
33
+ lookup_key = key.split('::')
34
+ namespace << lookup_key.shift
35
+ key = lookup_key.join('::')
36
+ end
37
+
38
+ Jerakia.log.debug("[hiera] backend invoked for key #{key} using namespace #{namespace}")
39
+
40
+ metadata={}
41
+ if scope.is_a?(Hash)
42
+ metadata=scope
43
+ else
44
+ metadata = scope.real.to_hash
45
+ end
46
+
47
+
48
+ request = Jerakia::Request.new(
49
+ :key => key,
50
+ :namespace => namespace,
51
+ :policy => @policy,
52
+ :lookup_type => lookup_type,
53
+ :merge => merge_type,
54
+ :metadata => metadata,
55
+ )
56
+
57
+ answer = @jerakia.lookup(request)
58
+ answer.payload
59
+
60
+
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+
@@ -0,0 +1,36 @@
1
+ class Jerakia::Answer
2
+
3
+ attr_accessor :payload
4
+ attr_accessor :datatype
5
+ attr_reader :lookup_type
6
+
7
+ def initialize(lookup_type = :first)
8
+ case lookup_type
9
+ when :first
10
+ @payload=nil
11
+ when :cascade
12
+ @payload=[]
13
+ @datatype="array"
14
+ end
15
+ end
16
+
17
+ def flatten_payload!
18
+ @payload.flatten!
19
+ end
20
+
21
+ def merge_payload!
22
+ payload_hash={}
23
+ @payload.each do |p|
24
+ if p.is_a?(Hash)
25
+ payload_hash.merge!(p)
26
+ end
27
+ end
28
+ @payload=payload_hash
29
+ set_data_type
30
+ end
31
+
32
+ def set_data_type
33
+ @data_type=@payload.class.to_s.downcase
34
+ end
35
+ end
36
+
@@ -0,0 +1,24 @@
1
+ #
2
+ # Very primitive form of cache - but we'll make this smarter
3
+ #
4
+ #
5
+ class Jerakia::Cache
6
+
7
+ def initialize
8
+ @@bucket = {}
9
+ end
10
+
11
+ def bucket_add(index,data)
12
+ @@bucket[index] = data
13
+ data
14
+ end
15
+
16
+ def in_bucket?(index)
17
+ @@bucket.has_key?(index)
18
+ end
19
+
20
+ def bucket
21
+ @@bucket
22
+ end
23
+ end
24
+
@@ -0,0 +1,25 @@
1
+ class Jerakia::Config
2
+
3
+ require 'yaml'
4
+ attr_reader :policydir
5
+ attr_reader :server_url
6
+
7
+ def initialize(config='/etc/jerakia/jerakia.yml')
8
+ unless File.exists?(config)
9
+ Jerakia.crit("Config file #{config} not found")
10
+ end
11
+ rawdata=File.read(config)
12
+ ymldata=YAML.load(rawdata)
13
+ @policydir=ymldata['policydir']
14
+ @server_url=ymldata['server_url']
15
+ @configdata=ymldata
16
+ end
17
+
18
+ def [](key)
19
+ @configdata[key.to_s]
20
+ end
21
+
22
+
23
+ end
24
+
25
+
@@ -0,0 +1,9 @@
1
+ class Jerakia::Datamodel < Jerakia
2
+
3
+
4
+ def initialize
5
+ @@namespace = {}
6
+ end
7
+
8
+ end
9
+
@@ -0,0 +1,17 @@
1
+ class Jerakia::Datasource
2
+ module Dummy
3
+
4
+ def run
5
+ #
6
+ # Do the lookup
7
+
8
+ Jerakia.log.debug("Searching key #{lookup.request.key} in dummy datasource")
9
+ option :return, { :type => String, :default => "Returned data" }
10
+ response.submit options[:return]
11
+
12
+
13
+
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,17 @@
1
+ class Jerakia::Datasource
2
+ module File
3
+ class Yaml
4
+ class << self
5
+ require 'yaml'
6
+ def import_file(fname, extension='yml')
7
+ diskfile="#{fname}.#{extension}"
8
+ Jerakia.log.debug("scanning file #{diskfile}")
9
+ return {} unless ::File.exists?(diskfile)
10
+ data=::File.read(diskfile)
11
+ YAML.load(data)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,65 @@
1
+ class Jerakia::Datasource
2
+ module File
3
+
4
+ attr_reader :file_format
5
+ def load_format_handler
6
+ format = options[:format] || :yaml
7
+ class_name=format.to_s.capitalize
8
+ require "jerakia/datasource/file/#{format.to_s}"
9
+ @file_format = eval "Jerakia::Datasource::File::#{class_name}"
10
+ end
11
+
12
+ def read_from_file(fname)
13
+ fpath = []
14
+ fpath << options[:docroot] unless fname[0] == '/'
15
+ fpath << [ fname, lookup.request.namespace ]
16
+ diskname = ::File.join(fpath.flatten).gsub(/\/$/, '')
17
+
18
+ Jerakia.log.debug("read_from_file() #{fname} using diskname #{diskname}")
19
+
20
+ import_args=[]
21
+ import_args << diskname
22
+ import_args << options[:extension] if options[:extension]
23
+
24
+ cache_index={ :diskname => diskname, :format => options[:format] }
25
+ if options[:enable_caching]
26
+ if in_bucket?(cache_index)
27
+ Jerakia.log.debug("returning cached data #{bucket[cache_index]}")
28
+ bucket[cache_index]
29
+ else
30
+ Jerakia.log.debug("adding to cache #{@file_format.import_file(*import_args)}")
31
+ bucket_add(cache_index,@file_format.import_file(*import_args))
32
+ end
33
+ else
34
+ @file_format.import_file(*import_args)
35
+ end
36
+ end
37
+
38
+
39
+ def run
40
+ #
41
+ # Do the lookup
42
+
43
+ Jerakia.log.debug("Searching key #{lookup.request.key} from file format #{options[:format]} (#{whoami})")
44
+ option :searchpath, { :type => Array, :mandatory => true }
45
+ option :format, { :type => Symbol, :default => :yaml }
46
+ option :docroot, { :type => String, :default => "/etc/jerakia/data" }
47
+ option :extension, { :type => String }
48
+
49
+ load_format_handler
50
+
51
+ options[:searchpath].each do |path|
52
+ Jerakia.log.debug("Attempting to load data from #{path}")
53
+ return unless response.want?
54
+ data=read_from_file(path)
55
+ Jerakia.log.debug("Datasource provided #{data} looking for key #{lookup.request.key}")
56
+ if data[lookup.request.key]
57
+ Jerakia.log.debug("Found data #{data[lookup.request.key]}")
58
+ response.submit data[lookup.request.key]
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+
@@ -0,0 +1,39 @@
1
+ require 'jerakia/cache'
2
+ class Jerakia::Datasource < Jerakia::Cache
3
+
4
+ require 'jerakia/response'
5
+ attr_reader :response
6
+ attr_reader :options
7
+ attr_reader :lookup
8
+
9
+ def initialize(name, lookup, opts)
10
+ @response = Jerakia::Response.new(lookup)
11
+ @options = opts
12
+ @lookup = lookup
13
+ @name = name
14
+ require "jerakia/datasource/#{name.to_s}"
15
+ # rescue loaderrer
16
+ eval "extend Jerakia::Datasource::#{name.to_s.capitalize}"
17
+ end
18
+
19
+
20
+ ## used for verbose logging
21
+ def whoami
22
+ "datasource=#{@name} lookup=#{@lookup.name}"
23
+ end
24
+
25
+ def option(opt, data={})
26
+ @options[opt] ||= data[:default] || nil
27
+ Jerakia.log.debug("[#{whoami}]: options[#{opt}] to #{options[opt]} [#{options[opt].class}]")
28
+ if @options[opt].nil?
29
+ Jerakia.crit "#{opt} must be configured in #{whoami}" if data[:mandatory]
30
+ else
31
+ if data[:type]
32
+ Jerakia.crit "#{opt} must be a #{data[:type].to_s} in #{whoami}" unless @options[opt].is_a?(data[:type])
33
+ end
34
+ end
35
+ end
36
+
37
+
38
+ end
39
+
@@ -0,0 +1,34 @@
1
+ # Here we take a request object and read in the policy file
2
+ # which is evalulated in this instance
3
+ #
4
+ class Jerakia::Launcher
5
+
6
+ attr_reader :request
7
+ attr_reader :answer
8
+ def initialize(req)
9
+ @@request = req
10
+ invoke
11
+ end
12
+
13
+ def invoke
14
+ policy_name=request.policy.to_s
15
+ Jerakia.log.info "Invoked lookup for #{@@request.key} using policy #{policy_name}"
16
+ filename=File.join(Jerakia.config.policydir, "#{policy_name}.rb")
17
+ policydata=Jerakia.filecache(filename)
18
+ instance_eval policydata
19
+ end
20
+
21
+ def request
22
+ @@request
23
+ end
24
+
25
+
26
+ def policy(name, opts={}, &block)
27
+ policy = Jerakia::Policy.new(name, opts, &block)
28
+ policy.fire!
29
+ @answer = policy.answer
30
+ end
31
+ end
32
+
33
+
34
+
@@ -0,0 +1,52 @@
1
+ class Jerakia::Log < Jerakia
2
+
3
+ require 'logger'
4
+ def initialize(level=:info)
5
+ @@logfile ||= config[:logfile] || '/var/log/jerakia.log'
6
+ @@logger ||= Logger.new(@@logfile)
7
+ @@level ||= level
8
+ case @@level
9
+ when :info
10
+ @@logger.level = Logger::INFO
11
+ when :debug
12
+ @@logger.level = Logger::DEBUG
13
+ end
14
+ end
15
+
16
+ def info(msg)
17
+ @@logger.info msg
18
+ end
19
+
20
+ def debug(msg)
21
+ @@logger.debug msg
22
+ end
23
+
24
+ def error(msg)
25
+ @@logger.error msg
26
+ end
27
+
28
+ def fatal(msg)
29
+ @@logger.fatal msg
30
+ end
31
+
32
+ # def self.fatal(msg)
33
+ # self.new.fatal msg
34
+ # end
35
+ #
36
+ # def self.error(msg)
37
+ # self.new.error msg
38
+ # end
39
+ #
40
+ def self.debug(msg)
41
+ self.new.debug msg
42
+ end
43
+ #
44
+ ## def self.info(msg)
45
+ # puts @@logger
46
+ # self.new.info msg
47
+ # end
48
+
49
+
50
+
51
+ end
52
+
@@ -0,0 +1,92 @@
1
+ class Jerakia::Lookup
2
+ require 'jerakia/datasource'
3
+ require 'jerakia/scope'
4
+ require 'jerakia/plugins/lookup/hiera_compat'
5
+ require 'jerakia/plugins/lookup/confine'
6
+
7
+ attr_accessor :request
8
+ attr_reader :datasource
9
+ attr_reader :valid
10
+ attr_reader :lookuptype
11
+ attr_reader :scope_object
12
+ attr_reader :output_filters
13
+ attr_reader :name
14
+ attr_reader :proceed
15
+
16
+ def initialize(name,req,scope,&block)
17
+
18
+ @name=name
19
+ @request=req
20
+ @valid=true
21
+ @scope_object=scope
22
+ @output_filters=[]
23
+ @proceed=true
24
+ extend Jerakia::Lookup::Plugin
25
+ instance_eval &block
26
+
27
+ end
28
+
29
+ def datasource(source, opts={})
30
+ @datasource = Jerakia::Datasource.new(source, self, opts)
31
+ end
32
+
33
+ # If set, Jerakia will pass each Jerakia::Response object
34
+ # to an output filter plugin
35
+ #
36
+
37
+ def scope
38
+ @scope_object.value
39
+ end
40
+
41
+
42
+ def output_filter(name,opts={})
43
+ @output_filters << { :name => name, :opts => opts }
44
+ end
45
+
46
+ def proceed?
47
+ @proceed
48
+ end
49
+
50
+ ## lookup function: stop
51
+ # Enabling stop sets @proceed to false, which will cause Jerakia
52
+ # *not* to load any more lookups in the policy if this lookup is
53
+ # deemed as valid. If the lookup is invalidated than Jerakia *will*
54
+ # progress to the next lookup. This is useful in conjuction with
55
+ # the confine plugin where we want to segregate some lookups but
56
+ # not worry about excluding from later lookups
57
+ #
58
+ def stop
59
+ @proceed = false
60
+ end
61
+
62
+ ## lookup function: continue
63
+ # Will cause Jerakia to continue to the next lookup in the policy
64
+ # which is the default behaviour
65
+ #
66
+ def continue
67
+ @proceed = true
68
+ end
69
+
70
+ ## lookup function: invalidate
71
+ # Setting invalidate will mean this lookup will be skipped in the policy
72
+ #
73
+ def invalidate
74
+ @valid=false
75
+ end
76
+
77
+ def valid?
78
+ return @valid
79
+ end
80
+
81
+ def run
82
+ @datasource.run
83
+ response=@datasource.response
84
+ @output_filters.each do |filter|
85
+ response.filter! filter[:name], filter[:opts]
86
+ end
87
+ return response
88
+ end
89
+
90
+
91
+ end
92
+
@@ -0,0 +1,20 @@
1
+ class Jerakia::Lookup
2
+ module Plugin
3
+
4
+ def confine(key=nil,match)
5
+ if key
6
+ invalidate unless key[Regexp.new(match)] == key
7
+ else
8
+ invalidate
9
+ end
10
+ end
11
+
12
+ def exclude(key=nil,match)
13
+ if key
14
+ invalidate if key[Regexp.new(match)] == key
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+
@@ -0,0 +1,26 @@
1
+ # This plugin reformats the lookup key according to a puppet's
2
+ # Hiera system, so instead of looking up <key> in <path>/<namespace>.yml
3
+ # we lookup <namespace>::<key> in <path>.yml
4
+ #
5
+ # This is a useful plugin for people wanting to test drive Jerakia
6
+ # but maintain an existing hiera filesystem layout and naming convention
7
+ # within the source data.
8
+ #
9
+ class Jerakia::Lookup
10
+ module Plugin
11
+ def hiera_compat
12
+ request.key.prepend("#{request.namespace.join('::')}::")
13
+ request.namespace=[]
14
+ end
15
+
16
+ def calling_module
17
+ if request.namespace.length > 0
18
+ request.namespace[0]
19
+ else
20
+ Jerakia.log.error("hiera_compat plugin tried to use calling_module but there is no namespace declared. Ensure that calling_module is called before hiera_compat in the policy")
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+
@@ -0,0 +1,65 @@
1
+ require 'jerakia/launcher'
2
+
3
+ class Jerakia::Policy < Jerakia::Launcher
4
+ require 'jerakia/answer'
5
+
6
+ attr_accessor :lookups
7
+ attr_reader :routes
8
+ attr_reader :answer
9
+ attr_reader :scope
10
+ attr_reader :lookup_proceed
11
+
12
+ def initialize(name, opts, &block)
13
+ @lookups=[]
14
+ @routes={}
15
+ @answer=Jerakia::Answer.new(request.lookup_type)
16
+ @scope=Jerakia::Scope.new
17
+ @lookup_proceed = true
18
+ begin
19
+ instance_eval &block
20
+ rescue => e
21
+ Jerakia.fatal "Error processing policy file", e
22
+ end
23
+ end
24
+
25
+ def clone_request
26
+ Marshal.load(Marshal.dump(request))
27
+ end
28
+
29
+
30
+ def lookup(name,opts={},&block)
31
+ # We specifically clone the request object to allow plugins to modify the
32
+ # request payload for the scope of this lookup only.
33
+ #
34
+ lookup = Jerakia::Lookup.new(name,clone_request,scope,&block)
35
+ Jerakia.log.debug("Proceed to next lookup #{lookup.proceed?}")
36
+
37
+ @lookups << lookup if lookup.valid? and @lookup_proceed
38
+ @lookup_proceed = false if !lookup.proceed? and lookup.valid?
39
+
40
+ end
41
+
42
+ def fire!
43
+ @lookups.each do |l|
44
+ responses = l.run
45
+ responses.entries.each do |res|
46
+ case request.lookup_type
47
+ when :first
48
+ @answer.payload ||= res[:value]
49
+ @answer.datatype ||= res[:datatype]
50
+ when :cascade
51
+ @answer.payload << res[:value]
52
+ end
53
+ end
54
+
55
+ if request.lookup_type == :cascade && @answer.payload.is_a?(Array) && request.merge == :array
56
+ @answer.flatten_payload!
57
+ end
58
+ if request.lookup_type == :cascade && @answer.payload.is_a?(Array) && request.merge == :hash
59
+ @answer.merge_payload!
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+
@@ -0,0 +1,21 @@
1
+ class Jerakia::Request
2
+
3
+ attr_accessor :key
4
+ attr_accessor :namespace
5
+ attr_accessor :merge
6
+ attr_accessor :policy
7
+ attr_accessor :metadata
8
+ attr_accessor :lookup_type
9
+ attr_accessor :scope
10
+
11
+ def initialize(opts={})
12
+ @key = opts[:key] || ''
13
+ @namespace = opts[:namespace] || []
14
+ @merge = opts[:merge] || false
15
+ @policy = opts[:policy] || 'default'
16
+ @metadata = opts[:metadata] || {}
17
+ @lookup_type = opts[:lookup_type] || :first
18
+ @scope = opts[:scope] || nil
19
+ end
20
+
21
+ end