foreman_dlm 0.1.0 → 2.0.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -6
  3. data/app/controllers/api/v2/dlmlock_events_controller.rb +42 -0
  4. data/app/controllers/api/v2/dlmlocks_controller.rb +31 -16
  5. data/app/controllers/concerns/foreman_dlm/find_host_by_client_cert.rb +7 -13
  6. data/app/controllers/concerns/foreman_dlm/find_host_by_ip.rb +1 -1
  7. data/app/controllers/concerns/foreman_dlm/update_checkin_time.rb +22 -0
  8. data/app/controllers/foreman_dlm/application_controller.rb +19 -0
  9. data/app/controllers/foreman_dlm/dlmlocks_controller.rb +82 -0
  10. data/app/helpers/foreman_dlm/dlmlock_helper.rb +33 -0
  11. data/app/jobs/foreman_dlm/refresh_dlmlock_status.rb +17 -0
  12. data/app/models/concerns/foreman_dlm/dlm_facet_host_extensions.rb +13 -0
  13. data/app/models/concerns/foreman_dlm/expirable.rb +36 -0
  14. data/app/models/concerns/foreman_dlm/host_extensions.rb +21 -2
  15. data/app/models/concerns/foreman_dlm/host_monitoring_extensions.rb +2 -0
  16. data/app/models/concerns/foreman_dlm/user_extensions.rb +13 -0
  17. data/app/models/foreman_dlm/dlm_facet.rb +7 -0
  18. data/app/models/foreman_dlm/dlmlock/update.rb +9 -0
  19. data/app/models/foreman_dlm/dlmlock.rb +137 -0
  20. data/app/models/foreman_dlm/dlmlock_event.rb +23 -0
  21. data/app/models/host_status/dlmlock_status.rb +44 -0
  22. data/app/views/api/v2/dlmlock_events/index.json.rabl +2 -0
  23. data/app/views/api/v2/dlmlocks/show.json.rabl +1 -1
  24. data/app/views/api/v2/errors/precondition_failed.json.rabl +1 -1
  25. data/app/views/foreman_dlm/api/v2/dlm_facets/base.json.rabl +1 -0
  26. data/app/views/foreman_dlm/api/v2/dlm_facets/base_with_root.json.rabl +3 -0
  27. data/app/views/foreman_dlm/api/v2/dlm_facets/show.json.rabl +3 -0
  28. data/app/views/foreman_dlm/dlmlocks/_details.html.erb +42 -0
  29. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/_list.html.erb +3 -1
  30. data/app/views/foreman_dlm/dlmlocks/index.html.erb +2 -0
  31. data/app/views/foreman_dlm/dlmlocks/show.html.erb +10 -0
  32. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/welcome.html.erb +2 -2
  33. data/app/views/hosts/_dlmlocks_tab.html.erb +39 -0
  34. data/config/routes.rb +20 -13
  35. data/contrib/systemd/foreman-dlm-expire-events.service +10 -0
  36. data/contrib/systemd/foreman-dlm-expire-events.timer +8 -0
  37. data/db/migrate/20170824084100_add_dlmlock.foreman_dlm.rb +1 -1
  38. data/db/migrate/20180627150003_rename_dlmlock_sti_models.rb +9 -0
  39. data/db/migrate/20180704162345_add_dlmlock_events.rb +11 -0
  40. data/db/migrate/20180711090022_add_hosts_fk_to_dlmlocks.rb +5 -0
  41. data/db/migrate/20180711111903_create_dlm_facets.foreman_dlm.rb +10 -0
  42. data/db/migrate/20180713113208_update_permissions_for_scoped_models.rb +13 -0
  43. data/lib/foreman_dlm/engine.rb +58 -19
  44. data/lib/foreman_dlm/version.rb +1 -1
  45. data/lib/tasks/dlmlock_events.rake +19 -0
  46. data/lib/tasks/foreman_dlm_tasks.rake +2 -4
  47. data/test/controllers/api/v2/dlmlocks_controller_test.rb +73 -52
  48. data/test/controllers/api/v2/dlmlocks_dlmlock_events_controller_test.rb +81 -0
  49. data/test/controllers/api/v2/hosts_controller_test.rb +28 -0
  50. data/test/controllers/find_host_by_client_cert_test.rb +2 -2
  51. data/test/controllers/foreman_dlm/dlmlocks_test.rb +55 -0
  52. data/test/controllers/hosts_controller_test.rb +12 -0
  53. data/test/factories/dlm_facets.rb +6 -0
  54. data/test/factories/dlmlock.rb +6 -2
  55. data/test/factories/dlmlock_events.rb +13 -0
  56. data/test/factories/host.rb +7 -0
  57. data/test/integration/foreman_dlm/dlmlocks_test.rb +28 -0
  58. data/test/jobs/refresh_dlmlock_status_test.rb +10 -0
  59. data/test/models/foreman_dlm/dlm_facet_test.rb +13 -0
  60. data/test/models/foreman_dlm/dlmlock_event_test.rb +19 -0
  61. data/test/models/foreman_dlm/dlmlock_test.rb +307 -0
  62. data/test/models/host_managed_test.rb +41 -0
  63. data/test/models/host_monitoring_test.rb +1 -1
  64. data/test/models/host_status/dlmlock_status_test.rb +45 -0
  65. data/test/models/user_test.rb +5 -0
  66. data/test/test_plugin_helper.rb +5 -3
  67. metadata +108 -30
  68. data/app/controllers/dlmlocks_controller.rb +0 -13
  69. data/app/models/dlmlock/update.rb +0 -5
  70. data/app/models/dlmlock.rb +0 -79
  71. data/app/views/dlmlocks/_details.html.erb +0 -35
  72. data/app/views/dlmlocks/index.html.erb +0 -2
  73. data/app/views/dlmlocks/show.html.erb +0 -7
  74. data/test/controllers/dlmlocks_test.rb +0 -24
  75. data/test/models/dlmlock_test.rb +0 -201
@@ -1,79 +0,0 @@
1
- class Dlmlock < ActiveRecord::Base
2
- include Authorizable
3
-
4
- def self.humanize_class_name
5
- N_('Distributed Lock')
6
- end
7
-
8
- belongs_to_host
9
- audited
10
-
11
- validates :name, presence: true, uniqueness: true
12
-
13
- scoped_search :on => :name, :complete_value => true, :default_order => true
14
- scoped_search :relation => :host, :on => :name, :complete_value => true, :rename => :host
15
- scoped_search :on => :type, :complete_value => true, :default_order => true
16
- scoped_search :on => :enabled, :complete_value => { :true => true, :false => false }, :only_explicit => true
17
-
18
- attr_accessor :old
19
-
20
- def acquire!(host)
21
- atomic_update(nil, host)
22
- end
23
-
24
- def release!(host)
25
- atomic_update(host, nil)
26
- end
27
-
28
- def locked_by?(host)
29
- self.host == host
30
- end
31
- alias_method :acquired_by?, :locked_by?
32
-
33
- def disabled?
34
- !enabled?
35
- end
36
-
37
- def locked?
38
- host.present?
39
- end
40
- alias_method :taken?, :locked?
41
-
42
- def humanized_type
43
- _('Generic Lock')
44
- end
45
-
46
- private
47
-
48
- def atomic_update(old_host, new_host)
49
- changes = {
50
- host_id: new_host.try(:id)
51
- }
52
- self.old = dup
53
- num_updated = self.class.where(
54
- id: id,
55
- host_id: [new_host.try(:id), old_host.try(:id)],
56
- enabled: true
57
- ).update_all(changes.merge(updated_at: DateTime.now))
58
- if num_updated > 0
59
- reload
60
- process_host_change(old_host, new_host, changes)
61
- return self
62
- end
63
- false
64
- end
65
-
66
- def process_host_change(old_host, new_host, changes)
67
- return if host.try(:id) == old.host.try(:id)
68
- write_audit(action: 'update', audited_changes: changes)
69
- run_callback(old_host, :unlock) if old.host
70
- run_callback(new_host, :lock) if host
71
- end
72
-
73
- def run_callback(h, callback)
74
- h.run_callbacks callback do
75
- logger.debug { "custom hook after_#{callback} on #{h} will be executed if defined." }
76
- true
77
- end
78
- end
79
- end
@@ -1,35 +0,0 @@
1
- <table class="<%= table_css_classes('table-fixed') %>">
2
- <thead>
3
- <tr>
4
- <th><%= _("Owner") %></th>
5
- <th><%= _("Initiator") %></th>
6
- <th><%= _("Timestamp") %></th>
7
- <th><%= _("Enabled") %></th>
8
- </tr>
9
- </thead>
10
- <tbody>
11
- <% @dlmlock.audits.includes(:user).reorder(created_at: :desc).each do |audit| %>
12
- <% revision = audit.revision %>
13
- <tr>
14
- <td>
15
- <% if revision.host.present? %>
16
- <%= link_to_if_authorized(revision.host.name, hash_for_host_path(:id => revision.host)) %>
17
- <% end %>
18
- </td>
19
- <td>
20
- <% if audit.user.hidden? %>
21
- <em><%= audit.user.name %></em>
22
- <% else %>
23
- <%= link_to_if_authorized(audit.user.name, hash_for_edit_user_path(audit.user)) %>
24
- <% end %>
25
- </td>
26
- <td>
27
- <%= audit.created_at %>
28
- </td>
29
- <td>
30
- <%= revision.enabled? %>
31
- </td>
32
- </tr>
33
- <% end %>
34
- </tbody>
35
- </table>
@@ -1,2 +0,0 @@
1
- <% title _("Locks") %>
2
- <%= render :partial => 'list' %>
@@ -1,7 +0,0 @@
1
- <% title "#{@dlmlock.name} "%>
2
-
3
- <%= title_actions link_to(_('Back'), :back, :class => 'btn btn-default'),
4
- ((link_to(_("Host details"), @dlmlock.host, :class => 'btn btn-default') if @dlmlock.host.present?))
5
- %>
6
-
7
- <%= render 'details' %>
@@ -1,24 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class DlmlocksControllerTest < ActionController::TestCase
4
- test '#index' do
5
- FactoryBot.create(:dlmlock)
6
- get :index, {}, set_session_user
7
- assert_response :success
8
- assert_not_nil assigns('dlmlocks')
9
- assert_template 'index'
10
- end
11
-
12
- test '#index with no lock shows welcome page' do
13
- get :index, {}, set_session_user
14
- assert_response :success
15
- assert_template 'welcome'
16
- end
17
-
18
- test '#show' do
19
- dlmlock = FactoryBot.create(:dlmlock)
20
- get :show, { :id => dlmlock.id }, set_session_user
21
- assert_response :success
22
- assert_template 'show'
23
- end
24
- end
@@ -1,201 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class DlmlockTest < ActiveSupport::TestCase
4
- setup do
5
- User.current = users(:admin)
6
- end
7
-
8
- subject { FactoryBot.create(:dlmlock) }
9
- should validate_presence_of(:name)
10
- should validate_uniqueness_of(:name)
11
-
12
- let(:host1) { FactoryBot.create(:host, :managed) }
13
- let(:host2) { FactoryBot.create(:host, :managed) }
14
-
15
- class HostWithCallbacks < ::Host::Managed
16
- attr_accessor :callbacks
17
-
18
- def initialize(*attributes, &block)
19
- super
20
- @callbacks = []
21
- end
22
-
23
- after_lock :callback1
24
- after_unlock :callback2
25
-
26
- def callback1
27
- Rails.logger.debug "callback1 executed for #{self} (#{self.class})"
28
- callbacks << 'callback1'
29
- end
30
-
31
- def callback2
32
- Rails.logger.debug "callback2 executed for #{self} (#{self.class})"
33
- callbacks << 'callback2'
34
- end
35
- end
36
-
37
- let(:host1_with_callbacks) { HostWithCallbacks.create(:name => 'test1.example.com') }
38
- let(:host2_with_callbacks) { HostWithCallbacks.create(:name => 'test2.example.com') }
39
-
40
- context 'a free and enabled DLM lock' do
41
- let(:dlmlock) { FactoryBot.create(:dlmlock) }
42
-
43
- test 'should be enabled and unlocked' do
44
- assert_equal true, dlmlock.enabled?
45
- assert_equal false, dlmlock.disabled?
46
- assert_equal false, dlmlock.locked?
47
- assert_equal false, dlmlock.taken?
48
- end
49
-
50
- test 'can be acquired' do
51
- assert_nil dlmlock.host
52
- assert dlmlock.acquire!(host1)
53
- assert_equal host1, dlmlock.reload.host
54
- end
55
-
56
- test 'can be released' do
57
- assert_nil dlmlock.host
58
- assert dlmlock.release!(host1)
59
- assert_nil dlmlock.reload.host
60
- end
61
-
62
- test 'records audit change on acquisition by owner' do
63
- assert_difference "Audit.where(auditable_type: 'Dlmlock').count" do
64
- assert dlmlock.acquire!(host1)
65
- end
66
- audit_record = dlmlock.audits.last
67
- assert_equal 'update', audit_record.action
68
- assert_equal({:host_id => host1.id}, audit_record.audited_changes)
69
- end
70
-
71
- test 'records no audit change on release' do
72
- assert_no_difference "Audit.where(auditable_type: 'Dlmlock').count" do
73
- assert dlmlock.release!(host1)
74
- end
75
- end
76
-
77
- test 'triggers after_lock callback' do
78
- host = HostWithCallbacks.new
79
- host.name = 'test.example.com'
80
- host.save
81
- assert dlmlock.acquire!(host)
82
- assert_equal ['callback1'], host.callbacks
83
- end
84
- end
85
-
86
- context 'a free and disabled DLM lock' do
87
- let(:dlmlock) { FactoryBot.create(:dlmlock, :enabled => false) }
88
-
89
- test 'should be disabled and unlocked' do
90
- assert_equal false, dlmlock.enabled?
91
- assert_equal true, dlmlock.disabled?
92
- assert_equal false, dlmlock.locked?
93
- assert_equal false, dlmlock.taken?
94
- end
95
-
96
- test 'can not be acquired' do
97
- assert_nil dlmlock.host
98
- assert_equal false, dlmlock.acquire!(host1)
99
- assert_nil dlmlock.reload.host
100
- end
101
-
102
- test 'can not be released' do
103
- assert_nil dlmlock.host
104
- assert_equal false, dlmlock.release!(host1)
105
- assert_nil dlmlock.reload.host
106
- end
107
-
108
- test 'triggers no callbacks' do
109
- host = HostWithCallbacks.new
110
- host.name = 'test.example.com'
111
- host.save
112
- assert_equal false, dlmlock.release!(host)
113
- assert_equal [], host.callbacks
114
- end
115
- end
116
-
117
- context 'an acquired DLM lock' do
118
- let(:dlmlock) { FactoryBot.create(:dlmlock, :host => host1) }
119
-
120
- test 'should be enabled and locked' do
121
- assert_equal true, dlmlock.enabled?
122
- assert_equal false, dlmlock.disabled?
123
- assert_equal true, dlmlock.locked?
124
- assert_equal true, dlmlock.taken?
125
- assert_equal true, dlmlock.locked_by?(host1)
126
- assert_equal true, dlmlock.acquired_by?(host1)
127
- end
128
-
129
- test 'can be acquired by owner' do
130
- assert_equal host1, dlmlock.host
131
- assert dlmlock.acquire!(host1)
132
- assert_equal host1, dlmlock.reload.host
133
- end
134
-
135
- test 'can not be acquired by other host' do
136
- assert_equal host1, dlmlock.host
137
- assert_equal false, dlmlock.acquire!(host2)
138
- assert_equal host1, dlmlock.reload.host
139
- end
140
-
141
- test 'can be released by owner' do
142
- assert_equal host1, dlmlock.host
143
- assert dlmlock.release!(host1)
144
- assert_nil dlmlock.reload.host
145
- end
146
-
147
- test 'can not be released by other host' do
148
- assert_equal host1, dlmlock.host
149
- assert_equal false, dlmlock.release!(host2)
150
- assert_equal host1, dlmlock.reload.host
151
- end
152
-
153
- test 'records audit change on release by owner' do
154
- assert_difference "Audit.where(auditable_type: 'Dlmlock').count" do
155
- assert dlmlock.release!(host1)
156
- end
157
- audit_record = dlmlock.audits.last
158
- assert_equal 'update', audit_record.action
159
- assert_equal({:host_id => nil}, audit_record.audited_changes)
160
- end
161
-
162
- test 'records no audit change on acquisition by owner' do
163
- assert_no_difference "Audit.where(auditable_type: 'Dlmlock').count" do
164
- assert dlmlock.acquire!(host1)
165
- end
166
- end
167
-
168
- test 'triggers after_unlock callback on release by owner' do
169
- host = HostWithCallbacks.new
170
- host.name = 'test.example.com'
171
- host.save
172
- dlmlock.host = host
173
- dlmlock.save
174
- assert dlmlock.release!(host)
175
- assert_equal ['callback2'], host.callbacks
176
- end
177
-
178
- test 'triggers no callbacks on release attempt by other host' do
179
- assert host1_with_callbacks
180
- assert host2_with_callbacks
181
- dlmlock.update(:host => host1_with_callbacks)
182
- assert_equal false, dlmlock.release!(host2_with_callbacks)
183
- assert_equal [], host1_with_callbacks.callbacks
184
- assert_equal [], host2_with_callbacks.callbacks
185
- end
186
-
187
- test 'triggers no callbacks on acquiry attempt by owner' do
188
- assert host1_with_callbacks
189
- dlmlock.update(:host => host1_with_callbacks)
190
- assert dlmlock.acquire!(host1_with_callbacks)
191
- assert_equal [], host1_with_callbacks.callbacks
192
- end
193
- end
194
-
195
- context 'scoped search' do
196
- test 'can be searched by name' do
197
- dlmlock = FactoryBot.create(:dlmlock)
198
- assert_equal Dlmlock::Update.find(dlmlock.id), Dlmlock.search_for("name ~ #{dlmlock.name}").first
199
- end
200
- end
201
- end