foreman_expire_hosts 6.0.0 → 7.0.2

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +78 -0
  3. data/.rubocop.yml +18 -13
  4. data/.rubocop_todo.yml +11 -31
  5. data/Gemfile +2 -0
  6. data/README.md +1 -0
  7. data/app/controllers/concerns/foreman_expire_hosts/api/v2/hosts_controller_extensions.rb +2 -0
  8. data/app/controllers/concerns/foreman_expire_hosts/host_controller_extensions.rb +20 -15
  9. data/app/helpers/concerns/foreman_expire_hosts/audits_helper_extensions.rb +4 -0
  10. data/app/helpers/concerns/foreman_expire_hosts/hosts_helper_extensions.rb +5 -22
  11. data/app/helpers/expire_hosts_mailer_helper.rb +3 -0
  12. data/app/helpers/foreman_expire_hosts/hosts_helper.rb +16 -0
  13. data/app/mailers/expire_hosts_mailer.rb +3 -0
  14. data/app/models/concerns/foreman_expire_hosts/host_ext.rb +9 -1
  15. data/app/models/host_status/expiration_status.rb +3 -0
  16. data/app/models/setting/expire_hosts.rb +2 -0
  17. data/app/overrides/add_expired_on_field_to_host_form.rb +4 -2
  18. data/app/overrides/add_expired_on_field_to_host_show.rb +5 -3
  19. data/app/overrides/deleted_expired_host_comment_in_audits.rb +8 -6
  20. data/app/services/foreman_expire_hosts/action/base.rb +9 -2
  21. data/app/services/foreman_expire_hosts/action/delete_expired_hosts.rb +3 -0
  22. data/app/services/foreman_expire_hosts/action/stop_expired_hosts.rb +6 -2
  23. data/app/services/foreman_expire_hosts/expiry_edit_authorizer.rb +2 -0
  24. data/app/services/foreman_expire_hosts/notification/base.rb +12 -3
  25. data/app/services/foreman_expire_hosts/notification/deleted_hosts.rb +2 -0
  26. data/app/services/foreman_expire_hosts/notification/expiry_warning.rb +2 -0
  27. data/app/services/foreman_expire_hosts/notification/failed_deleted_hosts.rb +2 -0
  28. data/app/services/foreman_expire_hosts/notification/failed_stopped_hosts.rb +2 -0
  29. data/app/services/foreman_expire_hosts/notification/stopped_hosts.rb +2 -0
  30. data/app/services/foreman_expire_hosts/safe_destroy.rb +7 -5
  31. data/app/services/foreman_expire_hosts/ui_notifications/hosts/base.rb +4 -1
  32. data/app/services/foreman_expire_hosts/ui_notifications/hosts/expiry_warning.rb +2 -0
  33. data/app/services/foreman_expire_hosts/ui_notifications/hosts/stopped_host.rb +2 -0
  34. data/app/views/api/v2/hosts/expiration.json.rabl +2 -0
  35. data/app/views/hosts/_expired_on_field.html.erb +11 -20
  36. data/app/views/hosts/select_multiple_expiration.html.erb +10 -15
  37. data/config/routes.rb +2 -0
  38. data/db/migrate/20150427101516_add_expiry_on_to_hosts.rb +2 -0
  39. data/db/seeds.d/80_expire_hosts_ui_notification.rb +2 -0
  40. data/extra/foreman_expire_hosts.cron +8 -0
  41. data/foreman_expire_hosts.gemspec +10 -3
  42. data/lib/expire_hosts_notifications.rb +3 -0
  43. data/lib/foreman_expire_hosts.rb +2 -0
  44. data/lib/foreman_expire_hosts/engine.rb +22 -10
  45. data/lib/foreman_expire_hosts/version.rb +3 -1
  46. data/lib/tasks/expired_hosts.rake +3 -1
  47. data/test/factories/foreman_expire_hosts_factories.rb +7 -5
  48. data/test/functional/api/v2/hosts_controller_test.rb +3 -1
  49. data/test/functional/concerns/hosts_controller_extensions_test.rb +3 -1
  50. data/test/helpers/hosts_helper_test.rb +5 -0
  51. data/test/lib/expire_hosts_notifications_test.rb +91 -45
  52. data/test/test_plugin_helper.rb +2 -0
  53. data/test/unit/concerns/host_extensions_test.rb +21 -19
  54. data/test/unit/expire_hosts_mailer_test.rb +6 -0
  55. data/test/unit/expiry_edit_authorizer_test.rb +2 -0
  56. data/test/unit/host_status/expiration_status_test.rb +3 -1
  57. data/test/unit/safe_destroy_test.rb +3 -1
  58. metadata +53 -26
  59. data/app/assets/javascripts/foreman_expire_hosts/application.js +0 -3
  60. data/app/assets/javascripts/foreman_expire_hosts/datepicker_for_host_expired_on_field.js +0 -27
  61. data/app/assets/stylesheets/foreman_expire_hosts/application.scss +0 -4
  62. data/app/overrides/add_js_to_host_index.rb +0 -6
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HostStatus
2
4
  class ExpirationStatus < HostStatus::Status
3
5
  OK = 0
@@ -15,6 +17,7 @@ module HostStatus
15
17
  return EXPIRED if host.expired_past_grace_period?
16
18
  return IN_GRACE_PERIOD if host.expired?
17
19
  return PENDING if host.pending_expiration?
20
+
18
21
  OK
19
22
  end
20
23
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Setting::ExpireHosts < Setting
2
4
  Setting::BLANK_ATTRS.push('host_expiry_email_recipients')
3
5
 
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Deface::Override.new(
2
4
  :virtual_path => 'hosts/_form',
3
- :name => 'host_form_expired_on_field',
5
+ :name => 'host_form_expired_on_field',
4
6
  :insert_after => 'div#model_name',
5
- :partial => 'hosts/expired_on_field'
7
+ :partial => 'hosts/expired_on_field'
6
8
  )
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Deface::Override.new(
2
- :virtual_path => 'hosts/show',
3
- :name => 'host_expiry_waring_in_show',
4
+ :virtual_path => 'hosts/show',
5
+ :name => 'host_expiry_waring_in_show',
4
6
  :insert_before => '#host-show',
5
- :partial => 'hosts/expired_message.html.erb'
7
+ :partial => 'hosts/expired_message.html.erb'
6
8
  )
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Deface::Override.new(
2
- :virtual_path => 'audits/_list',
3
- :name => 'deleted_expired_host_audit_comment_in_list',
4
+ :virtual_path => 'audits/_list',
5
+ :name => 'deleted_expired_host_audit_comment_in_list',
4
6
  :insert_bottom => 'div.row div.audit-content',
5
- :text => "\n <%= destroyed_expired_host_audit_comment_in_list(audit) %>"
7
+ :text => "\n <%= destroyed_expired_host_audit_comment_in_list(audit) %>"
6
8
  )
7
9
 
8
10
  Deface::Override.new(
9
- :virtual_path => 'audits/show',
10
- :name => 'deleted_expired_host_audit_comment_in_show',
11
+ :virtual_path => 'audits/show',
12
+ :name => 'deleted_expired_host_audit_comment_in_show',
11
13
  :insert_bottom => 'div#tab1 table',
12
- :text => "\n <%= destroyed_expired_host_audit_comment_in_show(@audit) %>"
14
+ :text => "\n <%= destroyed_expired_host_audit_comment_in_show(@audit) %>"
13
15
  )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Action
3
5
  class Base
@@ -17,9 +19,14 @@ module ForemanExpireHosts
17
19
 
18
20
  def process
19
21
  hosts.each do |host|
20
- if action(host)
22
+ result = action(host)
23
+ next if result.nil?
24
+
25
+ if result
26
+ logger.info "Action #{self.class.name} for host #{host.name} was successful."
21
27
  self.successful_hosts << host
22
28
  else
29
+ logger.info "Action #{self.class.name} for host #{host.name} failed."
23
30
  self.failed_hosts << host
24
31
  end
25
32
  end
@@ -51,7 +58,7 @@ module ForemanExpireHosts
51
58
  }
52
59
  end
53
60
 
54
- delegate :logger, :to => :Rails
61
+ delegate :logger, :to => :ForemanExpireHosts
55
62
  end
56
63
  end
57
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Action
3
5
  class DeleteExpiredHosts < Base
@@ -8,6 +10,7 @@ module ForemanExpireHosts
8
10
  end
9
11
 
10
12
  def action(host)
13
+ logger.info "Destroying expired host #{host}."
11
14
  SafeDestroy.new(host).destroy!
12
15
  end
13
16
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Action
3
5
  class StopExpiredHosts < Base
@@ -8,8 +10,10 @@ module ForemanExpireHosts
8
10
  end
9
11
 
10
12
  def action(host)
11
- return true unless host.supports_power_and_running?
12
- logger.info "Powering down expired host in grace period #{host}"
13
+ return false unless host.supports_power?
14
+ return unless host.power.ready?
15
+
16
+ logger.info "Powering down expired host in grace period #{host}."
13
17
  host.power.stop
14
18
  rescue StandardError
15
19
  false
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  class ExpiryEditAuthorizer
3
5
  attr_accessor :user, :hosts
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class Base
@@ -24,22 +26,27 @@ module ForemanExpireHosts
24
26
  end
25
27
 
26
28
  def deliver_mail_notification(recipient, hosts)
29
+ return true if hosts.empty?
30
+
31
+ logger.info "Deliving mail notification '#{humanized_name}' for hosts #{hosts.to_sentence} to #{recipient}."
32
+
27
33
  build_mail_notification(recipient, hosts).deliver_now
28
- rescue SocketError, Net::SMTPError => error
34
+ rescue SocketError, Net::SMTPError => e
29
35
  message = _('Failed to deliver %{notification_name} for Hosts %{hosts}') % {
30
36
  :notification_name => humanized_name,
31
37
  :hosts => hosts.map(&:name).to_sentence
32
38
  }
33
- Foreman::Logging.exception(message, error)
39
+ Foreman::Logging.exception(message, e)
34
40
  end
35
41
 
36
42
  def deliver_ui_notifications
37
43
  all_hosts.each do |host|
44
+ logger.info "Deliving UI notification '#{humanized_name}' for host '#{host}'."
38
45
  build_ui_notification(host).deliver!
39
46
  end
40
47
  end
41
48
 
42
- delegate :logger, :to => :Rails
49
+ delegate :logger, :to => :ForemanExpireHosts
43
50
 
44
51
  def humanized_name
45
52
  _('Notification')
@@ -59,11 +66,13 @@ module ForemanExpireHosts
59
66
  return global_recipients if global_recipients.present?
60
67
  return [User.anonymous_admin] if host.owner.blank?
61
68
  return [host.owner] if host.owner_type == 'User'
69
+
62
70
  host.owner.all_users
63
71
  end
64
72
 
65
73
  def additional_recipients
66
74
  return [] if Setting[:host_expiry_email_recipients].nil?
75
+
67
76
  Setting[:host_expiry_email_recipients].split(',').compact.map(&:strip)
68
77
  end
69
78
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class DeletedHosts < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class ExpiryWarning < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class FailedDeletedHosts < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class FailedStoppedHosts < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module Notification
3
5
  class StoppedHosts < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  class SafeDestroy
3
5
  # See http://projects.theforeman.org/issues/14702 for reasoning.
@@ -13,18 +15,18 @@ module ForemanExpireHosts
13
15
  # See https://community.theforeman.org/t/how-to-properly-destroy-a-content-host/8621
14
16
  # for reasoning.
15
17
  if subject.is_a?(Host::Base) && with_katello?
16
- Katello::RegistrationManager.unregister_host(host)
18
+ Katello::RegistrationManager.unregister_host(subject)
17
19
  else
18
20
  subject.destroy!
19
21
  end
20
- rescue ActiveRecord::RecordNotDestroyed => invalid
22
+ rescue ActiveRecord::RecordNotDestroyed => e
21
23
  message = _('Failed to delete %{class_name} %{subject}: %{message} - Errors: %{errors}') % {
22
24
  :class_name => subject.class.name,
23
25
  :subject => subject,
24
- :message => invalid.message,
25
- :errors => invalid.record.errors.full_messages.to_sentence
26
+ :message => e.message,
27
+ :errors => e.record.errors.full_messages.to_sentence
26
28
  }
27
- Foreman::Logging.exception(message, invalid)
29
+ Foreman::Logging.exception(message, e)
28
30
  false
29
31
  end
30
32
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module UINotifications
3
5
  module Hosts
@@ -6,6 +8,7 @@ module ForemanExpireHosts
6
8
 
7
9
  def create
8
10
  return add_notification unless find_notification
11
+
9
12
  redeliver! if redeliver?
10
13
  find_notification
11
14
  end
@@ -45,7 +48,7 @@ module ForemanExpireHosts
45
48
 
46
49
  def redeliver!
47
50
  recipients = find_notification.notification_recipients
48
- recipients.update_all(seen: false) # rubocop:disable Rails/SkipsModelValidations
51
+ recipients.update_all(seen: false)
49
52
  recipients.pluck(:user_id).each do |user_id|
50
53
  ::UINotifications::CacheHandler.new(user_id).clear
51
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module UINotifications
3
5
  module Hosts
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanExpireHosts
2
4
  module UINotifications
3
5
  module Hosts
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  attributes :expired_on
@@ -1,22 +1,13 @@
1
- <% if @host.can_modify_expiry_date? %>
2
- <%= stylesheet 'foreman_expire_hosts/application' %>
3
- <%= javascript 'foreman_expire_hosts/application' %>
4
- <% end %>
5
1
  <%= datepicker_f f, :expired_on,
6
- :value => @host.expired_on.try(:strftime, '%d/%m/%Y'),
7
- :data => { provide: @host.can_modify_expiry_date? ? 'datepicker' : 'readonly',
8
- orientation: 'top left',
9
- date_autoclose: true,
10
- date_clear_btn: true,
11
- date_format: 'dd/mm/yyyy',
12
- date_start_date: Date.tomorrow.strftime('%d/%m/%Y'),
13
- date_today_highlight: true
14
- },
15
- :autocomplete => false,
16
- :placeholder => 'dd/mm/yyyy',
17
- :help_block => ('<span class="pficon-warning-triangle-o"></span> '.html_safe + _('You are not allowed to change the expiry date of this host.') unless @host.can_modify_expiry_date?),
18
- :readonly => !@host.can_modify_expiry_date?,
19
- :help_inline => popover('Auto Expiry', _('Host will be deleted automatically on given expiry date.') + '<br>'.html_safe +
20
- _('Leave blank to keep the host until deleted manually')),
21
- :onfocus => 'append_shortcuts()'
2
+ {
3
+ :label => _('Expires on'),
4
+ :autocomplete => false,
5
+ :include_blank => true,
6
+ :use_month_numbers => false,
7
+ :start_year => Date.today.year,
8
+ :help_block => ('<span class="pficon-warning-triangle-o"></span> '.html_safe + _('You are not allowed to change the expiry date of this host.') unless @host.can_modify_expiry_date?),
9
+ :disabled => !@host.can_modify_expiry_date?,
10
+ :help_inline => popover('Auto Expiry', _('Expired hosts will be deleted automatically after the grace period has passed.') + '<br>'.html_safe +
11
+ _('If you do not want this host to expire and do not want it to be deleted automatically, do not specify an expiry date.'))
12
+ }
22
13
  %>
@@ -1,23 +1,18 @@
1
- <%= stylesheet 'foreman_expire_hosts/application' %>
2
- <%= javascript 'foreman_expire_hosts/application' %>
3
1
  <%= render 'selected_hosts', :hosts => @hosts %>
4
2
 
5
3
  <%= form_for :host, :url => update_multiple_expiration_hosts_path(:host_ids => params[:host_ids]) do |f| %>
6
4
 
7
- <%= _('Host will be deleted automatically on given expired date. Leave blank to clear expiration date.') %>
5
+ <%= _('Hosts will be deleted automatically on the given expiry date. Leave blank to clear expiration date.') %>
8
6
 
9
7
  <%= datepicker_f f, :expired_on,
10
- :value => (Date.today + 14).strftime('%d/%m/%Y'),
11
- :data => { provide: 'datepicker',
12
- orientation: 'top left',
13
- date_autoclose: true,
14
- date_clear_btn: true,
15
- date_format: 'dd/mm/yyyy',
16
- date_start_date: Date.tomorrow.strftime('%d/%m/%Y'),
17
- date_today_highlight: true
18
- },
19
- :autocomplete => false,
20
- :placeholder => 'dd/mm/yyyy',
21
- :onfocus => 'append_shortcuts()'
8
+ {
9
+ :autocomplete => false,
10
+ :include_blank => true,
11
+ :use_month_numbers => false,
12
+ :start_year => Date.today.year
13
+ },
14
+ {
15
+ :onchange => 'tfm.hosts.table.toggleMultipleOkButton(this);'
16
+ }
22
17
  %>
23
18
  <% end %>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Foreman::Application.routes.draw do
2
4
  post 'expired_hosts/select_multiple_expiration' => 'hosts#select_multiple_expiration', as: 'select_multiple_expiration_hosts'
3
5
  post 'expired_hosts/update_multiple_expiration' => 'hosts#update_multiple_expiration', as: 'update_multiple_expiration_hosts'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AddExpiryOnToHosts < ActiveRecord::Migration[4.2]
2
4
  def change
3
5
  add_column :hosts, :expired_on, :date unless column_exists? :hosts, :expired_on
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  [
2
4
  {
3
5
  group: _('Hosts'),
@@ -0,0 +1,8 @@
1
+ SHELL=/bin/sh
2
+ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
3
+
4
+ RAILS_ENV=production
5
+ FOREMAN_HOME=/usr/share/foreman
6
+
7
+ # Send out notifications about expired hosts
8
+ 45 7 * * * foreman /usr/sbin/foreman-rake expired_hosts:deliver_notifications >>/var/log/foreman/expired_hosts.log 2>&1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path('lib/foreman_expire_hosts/version', __dir__)
2
4
  require 'date'
3
5
 
@@ -8,7 +10,10 @@ Gem::Specification.new do |s|
8
10
  s.authors = ['Nagarjuna Rachaneni', 'Timo Goebel']
9
11
  s.email = ['nn.nagarjuna@gmail.com', 'mail@timogoebel.name']
10
12
  s.summary = 'Foreman plugin for limiting host lifetime'
11
- s.description = 'This Plugin will add new column expired_on to hosts to limit the lifetime of a host.'
13
+ s.description = <<~DESC
14
+ A Foreman plugin that allows hosts to expire at a configurable date.
15
+ Hosts will be shut down and automatically deleted after a grace period.
16
+ DESC
12
17
  s.homepage = 'https://github.com/theforeman/foreman_expire_hosts'
13
18
  s.licenses = ['GPL-3.0']
14
19
 
@@ -18,9 +23,11 @@ Gem::Specification.new do |s|
18
23
 
19
24
  s.require_paths = ['lib']
20
25
 
21
- s.add_dependency 'bootstrap-datepicker-rails'
22
26
  s.add_dependency 'deface'
23
27
 
24
28
  s.add_development_dependency 'rdoc'
25
- s.add_development_dependency 'rubocop', '0.54.0'
29
+ s.add_development_dependency 'rubocop', '~> 0.80.0'
30
+ s.add_development_dependency 'rubocop-minitest', '~> 0.7.0'
31
+ s.add_development_dependency 'rubocop-performance', '~> 1.5.2'
32
+ s.add_development_dependency 'rubocop-rails', '~> 2.4.2'
26
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExpireHostsNotifications
2
4
  class << self
3
5
  def delete_expired_hosts
@@ -10,6 +12,7 @@ module ExpireHostsNotifications
10
12
 
11
13
  def deliver_expiry_warning_notification(num = 1) # notify1_days_before_expiry
12
14
  return unless [1, 2].include?(num)
15
+
13
16
  days_before_expiry = Setting["notify#{num}_days_before_host_expiry"].to_i
14
17
  expiry_date = (Date.today + days_before_expiry)
15
18
  notifiable_hosts = Host.with_expire_date(expiry_date).preload(:owner)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'foreman_expire_hosts/engine'
2
4
  module ForemanExpireHosts
3
5
  end