blob: 849afaddec6fbc3e50b61963f6364de92e757157 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# frozen_string_literal: true
module Terraform
class RemoteStateHandler < BaseService
StateLockedError = Class.new(StandardError)
StateDeletedError = Class.new(StandardError)
UnauthorizedError = Class.new(StandardError)
def find_with_lock
retrieve_with_lock(find_only: true) do |state|
yield state if block_given?
end
end
def handle_with_lock
raise UnauthorizedError unless can_modify_state?
retrieve_with_lock do |state|
raise StateLockedError unless lock_matches?(state)
yield state if block_given?
state.save! unless state.destroyed?
end
nil
end
def lock!
raise ArgumentError if params[:lock_id].blank?
raise UnauthorizedError unless can_modify_state?
retrieve_with_lock do |state|
raise StateLockedError if state.locked?
state.lock_xid = params[:lock_id]
state.locked_by_user = current_user
state.locked_at = Time.current
state.save!
end
end
def unlock!
raise UnauthorizedError unless can_modify_state?
retrieve_with_lock do |state|
# force-unlock does not pass ID, so we ignore it if it is missing
raise StateLockedError unless params[:lock_id].nil? || lock_matches?(state)
state.lock_xid = nil
state.locked_by_user = nil
state.locked_at = nil
state.save!
end
end
private
def retrieve_with_lock(find_only: false)
create_or_find!(find_only: find_only).tap { |state| state.with_lock { yield state } }
end
def create_or_find!(find_only:)
raise ArgumentError unless params[:name].present?
find_params = { project: project, name: params[:name] }
state = if find_only
find_state!(find_params)
else
Terraform::State.create_or_find_by(find_params)
end
raise StateDeletedError if state.deleted_at?
state
end
def lock_matches?(state)
return true if state.lock_xid.nil? && params[:lock_id].nil?
ActiveSupport::SecurityUtils
.secure_compare(state.lock_xid.to_s, params[:lock_id].to_s)
end
def can_modify_state?
current_user.can?(:admin_terraform_state, project)
end
def find_state(find_params)
Terraform::State.find_by(find_params) # rubocop: disable CodeReuse/ActiveRecord
end
def find_state!(find_params)
find_state(find_params) || raise(ActiveRecord::RecordNotFound, "Couldn't find state")
end
end
end
|