foreman_expire_hosts 6.0.0 → 7.0.2

Sign up to get free protection for your applications and to get access to all the features.
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