foreman_dlm 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/app/controllers/api/v2/dlmlock_events_controller.rb +41 -0
  4. data/app/controllers/api/v2/dlmlocks_controller.rb +10 -4
  5. data/app/controllers/concerns/foreman_dlm/update_checkin_time.rb +21 -0
  6. data/app/controllers/foreman_dlm/application_controller.rb +19 -0
  7. data/app/controllers/foreman_dlm/dlmlocks_controller.rb +73 -0
  8. data/app/helpers/foreman_dlm/dlmlock_helper.rb +31 -0
  9. data/app/jobs/foreman_dlm/refresh_dlmlock_status.rb +17 -0
  10. data/app/models/concerns/foreman_dlm/dlm_facet_host_extensions.rb +13 -0
  11. data/app/models/concerns/foreman_dlm/expirable.rb +35 -0
  12. data/app/models/concerns/foreman_dlm/host_extensions.rb +11 -0
  13. data/app/models/concerns/foreman_dlm/user_extensions.rb +13 -0
  14. data/app/models/foreman_dlm/dlm_facet.rb +7 -0
  15. data/app/models/foreman_dlm/dlmlock.rb +136 -0
  16. data/app/models/foreman_dlm/dlmlock/update.rb +9 -0
  17. data/app/models/foreman_dlm/dlmlock_event.rb +23 -0
  18. data/app/models/host_status/dlmlock_status.rb +44 -0
  19. data/app/models/settings/dlm.rb +20 -0
  20. data/app/views/api/v2/dlmlock_events/index.json.rabl +2 -0
  21. data/app/views/foreman_dlm/api/v2/dlm_facets/base.json.rabl +1 -0
  22. data/app/views/foreman_dlm/api/v2/dlm_facets/base_with_root.json.rabl +3 -0
  23. data/app/views/foreman_dlm/api/v2/dlm_facets/show.json.rabl +3 -0
  24. data/app/views/foreman_dlm/dlmlocks/_details.html.erb +42 -0
  25. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/_list.html.erb +3 -1
  26. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/index.html.erb +0 -0
  27. data/app/views/foreman_dlm/dlmlocks/show.html.erb +10 -0
  28. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/welcome.html.erb +0 -0
  29. data/app/views/hosts/_dlmlocks_tab.html.erb +39 -0
  30. data/config/routes.rb +10 -3
  31. data/contrib/systemd/foreman-dlm-expire-events.service +10 -0
  32. data/contrib/systemd/foreman-dlm-expire-events.timer +8 -0
  33. data/db/migrate/20180627150003_rename_dlmlock_sti_models.rb +9 -0
  34. data/db/migrate/20180704162345_add_dlmlock_events.rb +11 -0
  35. data/db/migrate/20180711090022_add_hosts_fk_to_dlmlocks.rb +5 -0
  36. data/db/migrate/20180711111903_create_dlm_facets.foreman_dlm.rb +10 -0
  37. data/db/migrate/20180713113208_update_permissions_for_scoped_models.rb +13 -0
  38. data/lib/foreman_dlm/engine.rb +43 -7
  39. data/lib/foreman_dlm/version.rb +1 -1
  40. data/lib/tasks/dlmlock_events.rake +19 -0
  41. data/test/controllers/api/v2/dlmlocks_controller_test.rb +32 -11
  42. data/test/controllers/api/v2/dlmlocks_dlmlock_events_controller_test.rb +81 -0
  43. data/test/controllers/api/v2/hosts_controller_test.rb +28 -0
  44. data/test/controllers/foreman_dlm/dlmlocks_test.rb +55 -0
  45. data/test/controllers/hosts_controller_test.rb +12 -0
  46. data/test/factories/dlm_facets.rb +6 -0
  47. data/test/factories/dlmlock.rb +6 -2
  48. data/test/factories/dlmlock_events.rb +13 -0
  49. data/test/factories/host.rb +7 -0
  50. data/test/jobs/refresh_dlmlock_status_test.rb +10 -0
  51. data/test/models/foreman_dlm/dlm_facet_test.rb +13 -0
  52. data/test/models/foreman_dlm/dlmlock_event_test.rb +19 -0
  53. data/test/models/foreman_dlm/dlmlock_test.rb +299 -0
  54. data/test/models/host_managed_test.rb +23 -0
  55. data/test/models/host_status/dlmlock_status_test.rb +49 -0
  56. data/test/models/user_test.rb +5 -0
  57. metadata +63 -15
  58. data/app/controllers/dlmlocks_controller.rb +0 -12
  59. data/app/models/dlmlock.rb +0 -79
  60. data/app/models/dlmlock/update.rb +0 -7
  61. data/app/views/dlmlocks/_details.html.erb +0 -35
  62. data/app/views/dlmlocks/show.html.erb +0 -7
  63. data/test/controllers/dlmlocks_test.rb +0 -24
  64. data/test/models/dlmlock_test.rb +0 -201
@@ -0,0 +1,9 @@
1
+ module ForemanDlm
2
+ class Dlmlock
3
+ class Update < Dlmlock
4
+ def humanized_type
5
+ _('Update Lock')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module ForemanDlm
2
+ class DlmlockEvent < ApplicationRecord
3
+ include Authorizable
4
+ include Expirable
5
+
6
+ TYPES = %w[release acquire enable disable fail].freeze
7
+ validates :event_type, inclusion: { in: TYPES }
8
+
9
+ def self.humanize_class_name
10
+ N_('Distributed Lock Event')
11
+ end
12
+
13
+ belongs_to_host
14
+ belongs_to :dlmlock, inverse_of: :dlmlock_events, class_name: 'ForemanDlm::Dlmlock'
15
+ belongs_to :user, inverse_of: :dlmlock_events
16
+
17
+ scoped_search on: :event_type, complete_value: true
18
+
19
+ def humanized_type
20
+ _('Dlmlock Event')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ module HostStatus
2
+ class DlmlockStatus < Status
3
+ OK = 0
4
+ STALE = 1
5
+
6
+ def self.status_name
7
+ N_('Distributed Lock')
8
+ end
9
+
10
+ def to_label(_options = {})
11
+ case to_status
12
+ when OK
13
+ N_('Ok')
14
+ when STALE
15
+ N_('Stale')
16
+ else
17
+ N_('Unknown')
18
+ end
19
+ end
20
+
21
+ def to_global(_options = {})
22
+ case to_status
23
+ when OK
24
+ HostStatus::Global::OK
25
+ else
26
+ HostStatus::Global::ERROR
27
+ end
28
+ end
29
+
30
+ def to_status(_options = {})
31
+ ok? ? OK : STALE
32
+ end
33
+
34
+ def relevant?(_options = {})
35
+ host.dlmlocks.any?
36
+ end
37
+
38
+ private
39
+
40
+ def ok?
41
+ host.dlmlocks.stale.empty?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ class Setting
2
+ class Dlm < ::Setting
3
+ def self.load_defaults
4
+ return unless ActiveRecord::Base.connection.table_exists?('settings')
5
+ return unless super
6
+
7
+ Setting.transaction do
8
+ [
9
+ set('dlm_stale_time', N_('Number of hours after which locked Distributed Lock is stale'), 4, N_('Distributed Lock stale time'))
10
+ ].compact.each { |s| Setting::General.create s.update(category: 'Setting::General') }
11
+ end
12
+
13
+ true
14
+ end
15
+
16
+ def self.humanized_category
17
+ N_('Distributed Locks')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,2 @@
1
+ collection @events
2
+ attributes :id, :event_type, :created_at, :updated_at
@@ -0,0 +1 @@
1
+ attributes :id, :last_checkin_at
@@ -0,0 +1,3 @@
1
+ child :dlm_facet => :dlm_facet_attributes do |_dlm_facet|
2
+ extends 'foreman_dlm/api/v2/dlm_facets/base'
3
+ end
@@ -0,0 +1,3 @@
1
+ child :dlm_facet => :dlm_facet_attributes do
2
+ extends 'foreman_dlm/api/v2/dlm_facets/base'
3
+ end
@@ -0,0 +1,42 @@
1
+ <% if authorizer.can?(:view_dlmlock_events) %>
2
+ <table class="<%= table_css_classes('table-fixed') %>">
3
+ <thead>
4
+ <tr>
5
+ <th><%= _("Host") %></th>
6
+ <th><%= _("User") %></th>
7
+ <th><%= _("Type") %></th>
8
+ <th><%= _("Timestamp") %></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% @dlmlock.dlmlock_events.includes(:user).reorder(created_at: :desc).each do |event| %>
13
+
14
+ <tr>
15
+ <td>
16
+ <% if event.host %>
17
+ <%= link_to_if_authorized(event.host.name, hash_for_host_path(:id => event.host)) %>
18
+ <% end %>
19
+ </td>
20
+
21
+ <td>
22
+ <% if event.user %>
23
+ <% if event.user.hidden? %>
24
+ <em><%= event.user.name %></em>
25
+ <% else %>
26
+ <%= link_to_if_authorized(event.user.name, hash_for_edit_user_path(event.user)) %>
27
+ <% end %>
28
+ <% end %>
29
+ </td>
30
+
31
+ <td>
32
+ <%= _(event.event_type.humanize) %>
33
+ </td>
34
+
35
+ <td>
36
+ <%= event.created_at %>
37
+ </td>
38
+ </tr>
39
+ <% end %>
40
+ </tbody>
41
+ </table>
42
+ <% end %>
@@ -5,6 +5,7 @@
5
5
  <th><%= sort :host, :as => _("Owner") %></th>
6
6
  <th><%= sort :type, :as => _("Type") %></th>
7
7
  <th><%= sort :enabled, :as => _("Enabled") %></th>
8
+ <th class="col-md-2"><%= _('Actions') %></th>
8
9
  </tr>
9
10
  </thead>
10
11
  <tbody>
@@ -12,7 +13,7 @@
12
13
  <tr class="<%= lock.enabled? ? '' : 'warning' %>">
13
14
  <td>
14
15
  <%= icon_text(dlmlock_status_icon_class(lock),
15
- link_to_if_authorized(lock.name, hash_for_dlmlock_path(:id => lock)),
16
+ link_to_if_authorized(lock.name, hash_for_foreman_dlm_dlmlock_path(:id => lock)),
16
17
  kind: 'fa',
17
18
  class: "#{dlmlock_status_icon_color_class(lock)} fa-lg")
18
19
  %>
@@ -38,6 +39,7 @@
38
39
  <%= icon_text('toggle-off', 'Disabled', {kind: 'fa', class: 'center fa-lg', title: _('Disabled')}) %>
39
40
  <% end %>
40
41
  </td>
42
+ <td><%= action_buttons(*dlmlock_actions(lock, authorizer)) %></td>
41
43
  </tr>
42
44
  <% end %>
43
45
  </tbody>
@@ -0,0 +1,10 @@
1
+ <% title @dlmlock.name %>
2
+ <% breadcrumbs(
3
+ resource_url: api_dlmlocks_path
4
+ ) if respond_to?(:breadcrumbs) # Requires Foreman >= 1.18 %>
5
+
6
+ <%= title_actions link_to(_('Back'), foreman_dlm_dlmlocks_path, :class => 'btn btn-default'),
7
+ ((link_to(_("Host details"), @dlmlock.host, :class => 'btn btn-default') if @dlmlock.host.present?))
8
+ %>
9
+
10
+ <%= render 'details' %>
@@ -0,0 +1,39 @@
1
+ <% if @host.dlmlocks.any? %>
2
+ <%= alert class: 'alert-info',
3
+ header: '',
4
+ text: n_(
5
+ 'This host holds %s lock.',
6
+ 'This host holds %s locks.',
7
+ @host.dlmlocks.count
8
+ ) % @host.dlmlocks.count
9
+ %>
10
+ <% end %>
11
+
12
+ <table class="<%= table_css_classes %> table-fixed">
13
+ <thead>
14
+ <tr>
15
+ <th colspan="2"><%= _('Locks') %></th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ <tr>
20
+ <td><%= _('Last checkin') %></td>
21
+ <td><%= @host.dlm_facet && @host.dlm_facet.last_checkin_at ? date_time_relative(@host.dlm_facet.last_checkin_at) : _('N/A') %></td>
22
+ </tr>
23
+ <tr>
24
+ <td><%= _('Holds Locks') %></td>
25
+ <td>
26
+ <% if @host.dlmlocks.any? %>
27
+ <% @host.dlmlocks.authorized(:view_dlmlocks).each do |lock| %>
28
+ <%= link_to_if_authorized(lock.name, hash_for_foreman_dlm_dlmlock_path(lock)) %>
29
+ <span class="label label-<%= lock.updated_at > 6.hours.ago ? 'info' : 'warning' %>">
30
+ <%= _('acquired') %> <%= date_time_relative_value(lock.updated_at) %>
31
+ </span>
32
+ <% end %>
33
+ <% else %>
34
+ <%= _('None') %>
35
+ <% end %>
36
+ </td>
37
+ </tr>
38
+ </tbody>
39
+ </table>
@@ -6,6 +6,8 @@ Rails.application.routes.draw do
6
6
  :constraints => ApiConstraints.new(:version => 2, :default => true) do
7
7
  constraints(id: /[^\/]+/) do
8
8
  resources :dlmlocks, only: [:index, :show, :update, :destroy] do
9
+ resources :dlmlock_events, only: [:index]
10
+
9
11
  get :lock, on: :member, action: :show, controller: 'dlmlocks'
10
12
  put :lock, on: :member, action: :acquire, controller: 'dlmlocks'
11
13
  delete :lock, on: :member, action: :release, controller: 'dlmlocks'
@@ -15,10 +17,15 @@ Rails.application.routes.draw do
15
17
  end
16
18
  end
17
19
 
18
- scope '/foreman_dlm' do
19
- resources :dlmlocks, only: [:index, :show] do
20
+ namespace :foreman_dlm do
21
+ resources :dlmlocks, only: [:index, :show, :destroy] do
20
22
  collection do
21
- get 'auto_complete_search'
23
+ get :auto_complete_search
24
+ end
25
+ member do
26
+ put :enable
27
+ put :disable
28
+ put :release
22
29
  end
23
30
  end
24
31
  end
@@ -0,0 +1,10 @@
1
+ [Unit]
2
+ Description=Clean up expired Foreman DLM events
3
+ Documentation=https://github.com/dm-drogeriemarkt/foreman_dlm/blob/master/README.md
4
+ Requires=network.target
5
+
6
+ [Service]
7
+ Type=oneshot
8
+ EnvironmentFile=-/etc/sysconfig/foreman_dlm
9
+ ExecStart=/sbin/foreman-rake dlmlocks:expire
10
+ TimeoutSec=30m
@@ -0,0 +1,8 @@
1
+ [Unit]
2
+ Description=Run foreman-dlm-expire-events.service nightly
3
+
4
+ [Timer]
5
+ OnCalendar=*-*-* 02:00:00
6
+
7
+ [Install]
8
+ WantedBy=timers.target
@@ -0,0 +1,9 @@
1
+ class RenameDlmlockStiModels < ActiveRecord::Migration[5.1]
2
+ def up
3
+ execute "UPDATE dlmlocks set type='ForemanDlm::Dlmlock::Update' where type='Dlmlock::Update';"
4
+ end
5
+
6
+ def down
7
+ execute "UPDATE dlmlocks set type='Dlmlock::Update' where type='ForemanDlm::Dlmlock::Update';"
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class AddDlmlockEvents < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :dlmlock_events do |t|
4
+ t.integer :dlmlock_id, index: true, null: false
5
+ t.string :event_type, index: true
6
+ t.integer :host_id, index: true
7
+ t.integer :user_id
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class AddHostsFkToDlmlocks < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_foreign_key :dlmlocks, :hosts
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ class CreateDlmFacets < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :dlm_facets do |t|
4
+ t.references :host, null: false, foreign_key: true, index: true, unique: true
5
+ t.column :last_checkin_at, :datetime
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ class UpdatePermissionsForScopedModels < ActiveRecord::Migration[5.1]
2
+ class FakePermission < ApplicationRecord
3
+ self.table_name = 'permissions'
4
+ end
5
+
6
+ def up
7
+ FakePermission.where(resource_type: 'Dlmlock').update_all(resource_type: 'ForemanDlm::Dlmlock')
8
+ end
9
+
10
+ def down
11
+ FakePermission.where(resource_type: 'ForemanDlm::Dlmlock').update_all(resource_type: 'Dlmlock')
12
+ end
13
+ end
@@ -4,6 +4,15 @@ module ForemanDlm
4
4
 
5
5
  config.autoload_paths += Dir["#{config.root}/app/controllers/concerns"]
6
6
  config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
7
+ config.autoload_paths += Dir["#{config.root}/app/jobs"]
8
+
9
+ initializer 'foreman_dlm.load_default_settings', before: :load_config_initializers do
10
+ require_dependency File.expand_path('../../app/models/settings/dlm.rb', __dir__) if begin
11
+ Setting.table_exists?
12
+ rescue StandardError
13
+ (false)
14
+ end
15
+ end
7
16
 
8
17
  # Add any db migrations
9
18
  initializer 'foreman_dlm.load_app_instance_data' do |app|
@@ -21,32 +30,57 @@ module ForemanDlm
21
30
  # Add permissions
22
31
  security_block :foreman_dlm do
23
32
  permission :view_dlmlocks, {
24
- :dlmlocks => [:index, :show, :auto_complete_search],
33
+ :'foreman_dlm/dlmlocks' => [:index, :show, :auto_complete_search],
25
34
  :'api/v2/dlmlocks' => [:index, :show]
26
- }, :resource_type => 'Dlmlock'
35
+ }, :resource_type => 'ForemanDlm::Dlmlock'
27
36
 
28
37
  permission :create_dlmlocks, {
29
38
  :'api/v2/dlmlocks' => [:create]
30
- }, :resource_type => 'Dlmlock'
39
+ }, :resource_type => 'ForemanDlm::Dlmlock'
31
40
 
32
41
  permission :edit_dlmlocks, {
42
+ :'foreman_dlm/dlmlocks' => [:release, :enable, :disable],
33
43
  :'api/v2/dlmlocks' => [:update, :acquire, :release]
34
- }, :resource_type => 'Dlmlock'
44
+ }, :resource_type => 'ForemanDlm::Dlmlock'
35
45
 
36
46
  permission :destroy_dlmlocks, {
47
+ :'foreman_dlm/dlmlocks' => [:destroy],
37
48
  :'api/v2/dlmlocks' => [:destroy]
38
- }, :resource_type => 'Dlmlock'
49
+ }, :resource_type => 'ForemanDlm::Dlmlock'
50
+
51
+ permission :view_dlmlock_events, {
52
+ :'api/v2/dlmlock_events' => [:index]
53
+ }, :resource_type => 'ForemanDlm::DlmlockEvent'
39
54
  end
40
55
 
41
56
  # Add a new role called 'Distributed Lock Manager' if it doesn't exist
42
- role 'Distributed Lock Manager', [:view_dlmlocks, :create_dlmlocks, :edit_dlmlocks, :destroy_dlmlocks]
57
+ role 'Distributed Lock Manager', [:view_dlmlocks,
58
+ :create_dlmlocks,
59
+ :edit_dlmlocks,
60
+ :destroy_dlmlocks,
61
+ :view_dlmlock_events]
43
62
 
44
63
  # add menu entry
45
64
  menu :top_menu, :distributed_locks,
46
- url_hash: { controller: :dlmlocks, action: :index },
65
+ url_hash: { controller: :'foreman_dlm/dlmlocks', action: :index },
47
66
  caption: N_('Distributed Locks'),
48
67
  parent: :monitor_menu,
49
68
  after: :audits
69
+
70
+ # Dlm Facet
71
+ register_facet(ForemanDlm::DlmFacet, :dlm_facet) do
72
+ api_view list: 'foreman_dlm/api/v2/dlm_facets/base_with_root', single: 'foreman_dlm/api/v2/dlm_facets/show'
73
+ end
74
+
75
+ register_custom_status HostStatus::DlmlockStatus
76
+
77
+ # extend host show page
78
+ extend_page('hosts/show') do |context|
79
+ context.add_pagelet :main_tabs,
80
+ :name => N_('Locks'),
81
+ :partial => 'hosts/dlmlocks_tab',
82
+ :onlyif => proc { |host| host.dlm_facet }
83
+ end
50
84
  end
51
85
  end
52
86
 
@@ -54,6 +88,8 @@ module ForemanDlm
54
88
  config.to_prepare do
55
89
  begin
56
90
  Host::Managed.send(:include, ForemanDlm::HostExtensions)
91
+ User.send(:include, ForemanDlm::UserExtensions)
92
+ Host::Managed.send(:include, ForemanDlm::DlmFacetHostExtensions)
57
93
 
58
94
  Host::Managed.send(:include, ForemanDlm::HostMonitoringExtensions) if ForemanDlm.with_monitoring?
59
95
  rescue StandardError => e
@@ -1,3 +1,3 @@
1
1
  module ForemanDlm
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -0,0 +1,19 @@
1
+ desc <<-TASK_DESCRIPTION
2
+ Expire lock events automatically
3
+
4
+ Available conditions:
5
+ * days => number of days to keep reports (defaults to 14)
6
+ * batch_size => number of records deleted in single SQL transaction (defaults to 1k)
7
+ * sleep_time => delay in seconds between batches (defaults to 0.2)
8
+
9
+ TASK_DESCRIPTION
10
+
11
+ namespace :dlmlocks do
12
+ task expire: :environment do
13
+ created_before = ENV['days'].to_i.days if ENV['days']
14
+ batch_size = ENV['batch_size'].to_i if ENV['batch_size']
15
+ sleep_time = ENV['sleep_time'].to_f if ENV['sleep_time']
16
+
17
+ ForemanDlm::DlmlockEvent.expire(created_before: created_before, batch_size: batch_size, sleep_time: sleep_time)
18
+ end
19
+ end