Class: Legion::Crypt::LeaseManager
- Inherits:
-
Object
- Object
- Legion::Crypt::LeaseManager
show all
- Includes:
- Logging::Helper, Singleton
- Defined in:
- lib/legion/crypt/lease_manager.rb
Constant Summary
collapse
- RENEWAL_CHECK_INTERVAL =
5
Logging::Helper::CompatLogger
Instance Attribute Summary collapse
Instance Method Summary
collapse
#handle_exception, #log
Constructor Details
Returns a new instance of LeaseManager.
15
16
17
18
19
20
21
22
|
# File 'lib/legion/crypt/lease_manager.rb', line 15
def initialize
@lease_cache = {}
@active_leases = {}
@refs = {}
@running = false
@renewal_thread = nil
@state_mutex = Mutex.new
end
|
Instance Attribute Details
#active_leases ⇒ Object
Returns the value of attribute active_leases.
78
79
80
|
# File 'lib/legion/crypt/lease_manager.rb', line 78
def active_leases
@active_leases
end
|
Instance Method Details
#fetch(name, key) ⇒ Object
65
66
67
68
69
70
71
72
|
# File 'lib/legion/crypt/lease_manager.rb', line 65
def fetch(name, key)
data = @state_mutex.synchronize do
@lease_cache[name.to_sym] || @lease_cache[name.to_s]
end
return nil unless data
data[key.to_sym] || data[key.to_s]
end
|
#fetched_count ⇒ Object
61
62
63
|
# File 'lib/legion/crypt/lease_manager.rb', line 61
def fetched_count
@state_mutex.synchronize { @active_leases.size }
end
|
#lease_data(name) ⇒ Object
74
75
76
|
# File 'lib/legion/crypt/lease_manager.rb', line 74
def lease_data(name)
@state_mutex.synchronize { @lease_cache[name] }
end
|
#push_to_settings(name) ⇒ Object
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
# File 'lib/legion/crypt/lease_manager.rb', line 87
def push_to_settings(name)
refs, data = @state_mutex.synchronize do
r = @refs[name] || @refs[name.to_s] || @refs[name.to_sym]
d = @lease_cache[name] || @lease_cache[name.to_s] || @lease_cache[name.to_sym]
[r&.dup, d&.dup]
end
return if refs.nil? || refs.empty?
return unless data
refs.each do |key, path|
value = data[key.to_sym] || data[key.to_s]
write_setting(path, value)
end
log.info("Lease '#{name}' rotated — updated #{refs.size} settings reference(s)")
end
|
#register_dynamic_lease(name:, path:, response:, settings_refs:) ⇒ Object
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
# File 'lib/legion/crypt/lease_manager.rb', line 127
def register_dynamic_lease(name:, path:, response:, settings_refs:)
register_at_exit_hook
@state_mutex.synchronize do
@lease_cache[name] = response.data || {}
@active_leases[name] = {
lease_id: response.lease_id,
lease_duration: response.lease_duration,
expires_at: Time.now + (response.lease_duration || 0),
fetched_at: Time.now,
renewable: response.renewable?,
path: path
}
end
settings_refs.each do |ref|
register_ref(name, ref[:key], ref[:path])
end
log.info("LeaseManager: registered dynamic lease '#{name}' (path: #{path})")
end
|
#register_ref(name, key, path) ⇒ Object
80
81
82
83
84
85
|
# File 'lib/legion/crypt/lease_manager.rb', line 80
def register_ref(name, key, path)
@state_mutex.synchronize do
@refs[name] ||= {}
@refs[name][key] = path
end
end
|
#reissue_all ⇒ Object
114
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/legion/crypt/lease_manager.rb', line 114
def reissue_all
log.info('LeaseManager: reissue_all — re-issuing all active leases under new token')
lease_names = @state_mutex.synchronize { @active_leases.keys.dup }
lease_names.each do |name|
lease = @state_mutex.synchronize { @active_leases[name]&.dup }
next unless lease && lease[:path]
reissue_lease(name)
end
log.info('LeaseManager: reissue_all complete')
end
|
#reissue_lease(name) ⇒ Object
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
# File 'lib/legion/crypt/lease_manager.rb', line 147
def reissue_lease(name)
lease = @state_mutex.synchronize { @active_leases[name]&.dup }
unless lease && lease[:path]
log.warn("LeaseManager: cannot reissue lease '#{name}' — no path stored for re-read")
return
end
log.info("LeaseManager: reissuing lease '#{name}' from #{lease[:path]}")
response = logical.read(lease[:path])
unless response&.data
log.warn("LeaseManager: reissue for '#{name}' returned no data from #{lease[:path]}")
return
end
updated = @state_mutex.synchronize do
active_lease = @active_leases[name]
next false unless active_lease
@lease_cache[name] = response.data
active_lease.merge!(
lease_id: response.lease_id,
lease_duration: response.lease_duration,
expires_at: Time.now + (response.lease_duration || 0),
fetched_at: Time.now,
renewable: response.renewable?
)
true
end
unless updated
log.warn("LeaseManager: reissue for '#{name}' skipped — lease was removed during reissue (likely shutdown)")
return
end
lease_id_preview = response.lease_id.to_s[0..11]
log.info("LeaseManager: reissued lease '#{name}' " \
"(new_lease_id=#{lease_id_preview}... ttl=#{response.lease_duration}s)")
push_to_settings(name)
trigger_reconnect(name)
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.lease_manager.reissue_lease', lease_name: name)
log.warn("LeaseManager: failed to reissue lease '#{name}': #{e.message}")
end
|
#renewal_thread_alive? ⇒ Boolean
200
201
202
|
# File 'lib/legion/crypt/lease_manager.rb', line 200
def renewal_thread_alive?
@state_mutex.synchronize { @renewal_thread&.alive? || false }
end
|
#reset! ⇒ Object
231
232
233
234
235
236
237
238
239
240
|
# File 'lib/legion/crypt/lease_manager.rb', line 231
def reset!
@state_mutex.synchronize do
@running = false
@lease_cache.clear
@active_leases.clear
@refs.clear
@vault_client = nil
@renewal_thread = nil
end
end
|
#shutdown ⇒ Object
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'lib/legion/crypt/lease_manager.rb', line 204
def shutdown
log.info 'LeaseManager shutdown requested'
stop_renewal_thread
leases = @state_mutex.synchronize { @active_leases.dup }
leases.each do |name, meta|
lease_id = meta[:lease_id]
next if lease_id.nil? || lease_id.empty?
begin
sys.revoke(lease_id)
log.debug("LeaseManager: revoked lease '#{name}' (#{lease_id})")
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.lease_manager.shutdown', lease_name: name)
log.warn("LeaseManager: failed to revoke lease '#{name}' (#{lease_id}): #{e.message}")
end
end
@state_mutex.synchronize do
@lease_cache.clear
@active_leases.clear
@refs.clear
@vault_client = nil
end
log.info 'LeaseManager shutdown complete'
end
|
#start(definitions, vault_client: nil) ⇒ Object
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# File 'lib/legion/crypt/lease_manager.rb', line 24
def start(definitions, vault_client: nil)
@state_mutex.synchronize { @vault_client = vault_client }
return if definitions.nil? || definitions.empty?
register_at_exit_hook
log.info "LeaseManager start requested definitions=#{definitions.size}"
definitions.each do |name, opts|
path = opts['path'] || opts[:path]
next unless path
if lease_valid?(name)
log.debug("LeaseManager: reusing valid cached lease for '#{name}'")
next
end
revoke_expired_lease(name)
begin
log.info("LeaseManager: fetching lease '#{name}' from #{path}")
response = logical.read(path)
unless response
log.warn("LeaseManager: no data at '#{name}' (#{path}) — path may not exist or role not configured")
next
end
log_lease_response(name, response)
cache_lease(name, response, path: path)
log.info("LeaseManager: fetched lease '#{name}' from #{path} " \
"(lease_id=#{response.lease_id.to_s[0..11]}... ttl=#{response.lease_duration}s renewable=#{response.renewable?})")
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.lease_manager.start', lease_name: name, path: path)
log.warn("LeaseManager: failed to fetch lease '#{name}' from #{path}: #{e.message}")
end
end
end
|
#start_renewal_thread ⇒ Object
190
191
192
193
194
195
196
197
198
|
# File 'lib/legion/crypt/lease_manager.rb', line 190
def start_renewal_thread
@state_mutex.synchronize do
return if @renewal_thread&.alive?
@running = true
@renewal_thread = Thread.new { renewal_loop }
end
log.info 'LeaseManager renewal thread started'
end
|
#vault_logical ⇒ Object
Public Vault client accessors used by Crypt for bootstrap/swap operations. Delegates to the configured vault_client or falls back to ::Vault.
106
107
108
|
# File 'lib/legion/crypt/lease_manager.rb', line 106
def vault_logical
logical
end
|
#vault_sys ⇒ Object
110
111
112
|
# File 'lib/legion/crypt/lease_manager.rb', line 110
def vault_sys
sys
end
|