vault-kv 0.12.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +42 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +29 -0
  5. data/CHANGELOG.md +228 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +362 -0
  8. data/README.md +212 -0
  9. data/Rakefile +6 -0
  10. data/lib/vault.rb +49 -0
  11. data/lib/vault/api.rb +13 -0
  12. data/lib/vault/api/approle.rb +218 -0
  13. data/lib/vault/api/auth.rb +316 -0
  14. data/lib/vault/api/auth_tls.rb +92 -0
  15. data/lib/vault/api/auth_token.rb +242 -0
  16. data/lib/vault/api/help.rb +33 -0
  17. data/lib/vault/api/kv.rb +207 -0
  18. data/lib/vault/api/logical.rb +150 -0
  19. data/lib/vault/api/secret.rb +168 -0
  20. data/lib/vault/api/sys.rb +25 -0
  21. data/lib/vault/api/sys/audit.rb +91 -0
  22. data/lib/vault/api/sys/auth.rb +116 -0
  23. data/lib/vault/api/sys/health.rb +63 -0
  24. data/lib/vault/api/sys/init.rb +83 -0
  25. data/lib/vault/api/sys/leader.rb +48 -0
  26. data/lib/vault/api/sys/lease.rb +49 -0
  27. data/lib/vault/api/sys/mount.rb +103 -0
  28. data/lib/vault/api/sys/policy.rb +92 -0
  29. data/lib/vault/api/sys/seal.rb +81 -0
  30. data/lib/vault/client.rb +447 -0
  31. data/lib/vault/configurable.rb +48 -0
  32. data/lib/vault/defaults.rb +197 -0
  33. data/lib/vault/encode.rb +19 -0
  34. data/lib/vault/errors.rb +72 -0
  35. data/lib/vault/persistent.rb +1158 -0
  36. data/lib/vault/persistent/connection.rb +42 -0
  37. data/lib/vault/persistent/pool.rb +48 -0
  38. data/lib/vault/persistent/timed_stack_multi.rb +70 -0
  39. data/lib/vault/request.rb +43 -0
  40. data/lib/vault/response.rb +89 -0
  41. data/lib/vault/vendor/connection_pool.rb +150 -0
  42. data/lib/vault/vendor/connection_pool/timed_stack.rb +178 -0
  43. data/lib/vault/vendor/connection_pool/version.rb +5 -0
  44. data/lib/vault/version.rb +3 -0
  45. data/vault.gemspec +30 -0
  46. metadata +186 -0
@@ -0,0 +1,42 @@
1
+ ##
2
+ # A Net::HTTP connection wrapper that holds extra information for managing the
3
+ # connection's lifetime.
4
+
5
+ module Vault
6
+ class PersistentHTTP::Connection # :nodoc:
7
+
8
+ attr_accessor :http
9
+
10
+ attr_accessor :last_use
11
+
12
+ attr_accessor :requests
13
+
14
+ attr_accessor :ssl_generation
15
+
16
+ def initialize http_class, http_args, ssl_generation
17
+ @http = http_class.new(*http_args)
18
+ @ssl_generation = ssl_generation
19
+
20
+ reset
21
+ end
22
+
23
+ def finish
24
+ @http.finish
25
+ rescue IOError
26
+ ensure
27
+ reset
28
+ end
29
+
30
+ def reset
31
+ @last_use = PersistentHTTP::EPOCH
32
+ @requests = 0
33
+ end
34
+
35
+ def ressl ssl_generation
36
+ @ssl_generation = ssl_generation
37
+
38
+ finish
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,48 @@
1
+ module Vault
2
+ class PersistentHTTP::Pool < Vault::ConnectionPool # :nodoc:
3
+
4
+ attr_reader :available # :nodoc:
5
+ attr_reader :key # :nodoc:
6
+
7
+ def initialize(options = {}, &block)
8
+ super
9
+
10
+ @available = PersistentHTTP::TimedStackMulti.new(@size, &block)
11
+ @key = :"current-#{@available.object_id}"
12
+ end
13
+
14
+ def checkin net_http_args
15
+ stack = Thread.current[@key][net_http_args]
16
+
17
+ raise ConnectionPool::Error, 'no connections are checked out' if
18
+ stack.empty?
19
+
20
+ conn = stack.pop
21
+
22
+ if stack.empty?
23
+ @available.push conn, connection_args: net_http_args
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ def checkout net_http_args
30
+ stacks = Thread.current[@key] ||= Hash.new { |h, k| h[k] = [] }
31
+ stack = stacks[net_http_args]
32
+
33
+ if stack.empty? then
34
+ conn = @available.pop connection_args: net_http_args
35
+ else
36
+ conn = stack.last
37
+ end
38
+
39
+ stack.push conn
40
+
41
+ conn
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ require_relative 'timed_stack_multi'
48
+
@@ -0,0 +1,70 @@
1
+ module Vault
2
+ class PersistentHTTP::TimedStackMulti < ConnectionPool::TimedStack # :nodoc:
3
+
4
+ def initialize(size = 0, &block)
5
+ super
6
+
7
+ @enqueued = 0
8
+ @ques = Hash.new { |h, k| h[k] = [] }
9
+ @lru = {}
10
+ @key = :"connection_args-#{object_id}"
11
+ end
12
+
13
+ def empty?
14
+ (@created - @enqueued) >= @max
15
+ end
16
+
17
+ def length
18
+ @max - @created + @enqueued
19
+ end
20
+
21
+ private
22
+
23
+ def connection_stored? options = {} # :nodoc:
24
+ !@ques[options[:connection_args]].empty?
25
+ end
26
+
27
+ def fetch_connection options = {} # :nodoc:
28
+ connection_args = options[:connection_args]
29
+
30
+ @enqueued -= 1
31
+ lru_update connection_args
32
+ @ques[connection_args].pop
33
+ end
34
+
35
+ def lru_update connection_args # :nodoc:
36
+ @lru.delete connection_args
37
+ @lru[connection_args] = true
38
+ end
39
+
40
+ def shutdown_connections # :nodoc:
41
+ @ques.each_key do |key|
42
+ super connection_args: key
43
+ end
44
+ end
45
+
46
+ def store_connection obj, options = {} # :nodoc:
47
+ @ques[options[:connection_args]].push obj
48
+ @enqueued += 1
49
+ end
50
+
51
+ def try_create options = {} # :nodoc:
52
+ connection_args = options[:connection_args]
53
+
54
+ if @created >= @max && @enqueued >= 1
55
+ oldest, = @lru.first
56
+ @lru.delete oldest
57
+ @ques[oldest].pop
58
+
59
+ @created -= 1
60
+ end
61
+
62
+ if @created < @max
63
+ @created += 1
64
+ lru_update connection_args
65
+ return @create_block.call(connection_args)
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,43 @@
1
+ module Vault
2
+ class Request
3
+ attr_reader :client
4
+
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # @return [String]
10
+ def to_s
11
+ "#<#{self.class.name}>"
12
+ end
13
+
14
+ # @return [String]
15
+ def inspect
16
+ "#<#{self.class.name}:0x#{"%x" % (self.object_id << 1)}>"
17
+ end
18
+
19
+ private
20
+
21
+ include EncodePath
22
+
23
+ # Removes the given header fields from options and returns the result. This
24
+ # modifies the given options in place.
25
+ #
26
+ # @param [Hash] options
27
+ #
28
+ # @return [Hash]
29
+ def extract_headers!(options = {})
30
+ extract = {
31
+ wrap_ttl: Vault::Client::WRAP_TTL_HEADER,
32
+ }
33
+
34
+ {}.tap do |h|
35
+ extract.each do |k,v|
36
+ if options[k]
37
+ h[v] = options.delete(k)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ module Vault
2
+ class Response
3
+ # Defines a new field. This is designed to be used by the subclass as a
4
+ # mini-DSL.
5
+ #
6
+ # @example Default
7
+ # field :data
8
+ #
9
+ # @example With a mutator
10
+ # field :present, as: :present?
11
+ #
12
+ # @param n [Symbol] the name of the field
13
+ # @option opts [Symbol] :as alias for method name
14
+ #
15
+ # @!visibility private
16
+ def self.field(n, opts = {})
17
+ self.fields[n] = opts
18
+
19
+ if opts[:as].nil?
20
+ attr_reader n
21
+ else
22
+ define_method(opts[:as]) do
23
+ instance_variable_get(:"@#{n}")
24
+ end
25
+ end
26
+ end
27
+
28
+ # Returns the list of fields defined on this subclass.
29
+ # @!visibility private
30
+ def self.fields
31
+ @fields ||= {}
32
+ end
33
+
34
+ # Decodes the given object (usually a Hash) into an instance of this class.
35
+ #
36
+ # @param object [Hash<Symbol, Object>]
37
+ def self.decode(object)
38
+ self.new(object)
39
+ end
40
+
41
+ def initialize(opts = {})
42
+ # Initialize all fields as nil to start
43
+ self.class.fields.each do |k, _|
44
+ instance_variable_set(:"@#{k}", nil)
45
+ end
46
+
47
+ # For each supplied option, set the instance variable if it was defined
48
+ # as a field.
49
+ opts.each do |k, v|
50
+ if self.class.fields.key?(k)
51
+ opts = self.class.fields[k]
52
+
53
+ if (m = opts[:load]) && !v.nil?
54
+ v = m.call(v)
55
+ end
56
+
57
+ if opts[:freeze]
58
+ v = v.freeze
59
+ end
60
+
61
+ instance_variable_set(:"@#{k}", v)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Create a hash-bashed representation of this response.
67
+ #
68
+ # @return [Hash]
69
+ def to_h
70
+ self.class.fields.inject({}) do |h, (k, opts)|
71
+ if opts[:as].nil?
72
+ h[k] = self.public_send(k)
73
+ else
74
+ h[k] = self.public_send(opts[:as])
75
+ end
76
+
77
+ if !h[k].nil? && !h[k].is_a?(Array) && h[k].respond_to?(:to_h)
78
+ h[k] = h[k].to_h
79
+ end
80
+
81
+ h
82
+ end
83
+ end
84
+
85
+ def ==(other)
86
+ self.to_h == other.to_h
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,150 @@
1
+ require_relative 'connection_pool/version'
2
+ require_relative 'connection_pool/timed_stack'
3
+
4
+
5
+ # Generic connection pool class for e.g. sharing a limited number of network connections
6
+ # among many threads. Note: Connections are lazily created.
7
+ #
8
+ # Example usage with block (faster):
9
+ #
10
+ # @pool = ConnectionPool.new { Redis.new }
11
+ #
12
+ # @pool.with do |redis|
13
+ # redis.lpop('my-list') if redis.llen('my-list') > 0
14
+ # end
15
+ #
16
+ # Using optional timeout override (for that single invocation)
17
+ #
18
+ # @pool.with(:timeout => 2.0) do |redis|
19
+ # redis.lpop('my-list') if redis.llen('my-list') > 0
20
+ # end
21
+ #
22
+ # Example usage replacing an existing connection (slower):
23
+ #
24
+ # $redis = ConnectionPool.wrap { Redis.new }
25
+ #
26
+ # def do_work
27
+ # $redis.lpop('my-list') if $redis.llen('my-list') > 0
28
+ # end
29
+ #
30
+ # Accepts the following options:
31
+ # - :size - number of connections to pool, defaults to 5
32
+ # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
33
+ #
34
+ module Vault
35
+ class ConnectionPool
36
+ DEFAULTS = {size: 5, timeout: 5}
37
+
38
+ class Error < RuntimeError
39
+ end
40
+
41
+ def self.wrap(options, &block)
42
+ Wrapper.new(options, &block)
43
+ end
44
+
45
+ def initialize(options = {}, &block)
46
+ raise ArgumentError, 'Connection pool requires a block' unless block
47
+
48
+ options = DEFAULTS.merge(options)
49
+
50
+ @size = options.fetch(:size)
51
+ @timeout = options.fetch(:timeout)
52
+
53
+ @available = TimedStack.new(@size, &block)
54
+ @key = :"current-#{@available.object_id}"
55
+ end
56
+
57
+ if Thread.respond_to?(:handle_interrupt)
58
+
59
+ # MRI
60
+ def with(options = {})
61
+ Thread.handle_interrupt(Exception => :never) do
62
+ conn = checkout(options)
63
+ begin
64
+ Thread.handle_interrupt(Exception => :immediate) do
65
+ yield conn
66
+ end
67
+ ensure
68
+ checkin
69
+ end
70
+ end
71
+ end
72
+
73
+ else
74
+
75
+ # jruby 1.7.x
76
+ def with(options = {})
77
+ conn = checkout(options)
78
+ begin
79
+ yield conn
80
+ ensure
81
+ checkin
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ def checkout(options = {})
88
+ conn = if stack.empty?
89
+ timeout = options[:timeout] || @timeout
90
+ @available.pop(timeout: timeout)
91
+ else
92
+ stack.last
93
+ end
94
+
95
+ stack.push conn
96
+ conn
97
+ end
98
+
99
+ def checkin
100
+ conn = pop_connection # mutates stack, must be on its own line
101
+ @available.push(conn) if stack.empty?
102
+
103
+ nil
104
+ end
105
+
106
+ def shutdown(&block)
107
+ @available.shutdown(&block)
108
+ end
109
+
110
+ private
111
+
112
+ def pop_connection
113
+ if stack.empty?
114
+ raise ConnectionPool::Error, 'no connections are checked out'
115
+ else
116
+ stack.pop
117
+ end
118
+ end
119
+
120
+ def stack
121
+ ::Thread.current[@key] ||= []
122
+ end
123
+
124
+ class Wrapper < ::BasicObject
125
+ METHODS = [:with, :pool_shutdown]
126
+
127
+ def initialize(options = {}, &block)
128
+ @pool = ::ConnectionPool.new(options, &block)
129
+ end
130
+
131
+ def with(&block)
132
+ @pool.with(&block)
133
+ end
134
+
135
+ def pool_shutdown(&block)
136
+ @pool.shutdown(&block)
137
+ end
138
+
139
+ def respond_to?(id, *args)
140
+ METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
141
+ end
142
+
143
+ def method_missing(name, *args, &block)
144
+ with do |connection|
145
+ connection.send(name, *args, &block)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end