vault-kv 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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