foreman_monitoring 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -1
  3. data/app/controllers/api/v2/monitoring_results_controller.rb +8 -0
  4. data/app/controllers/concerns/foreman_monitoring/hosts_controller_extensions.rb +140 -0
  5. data/app/helpers/concerns/foreman_monitoring/hosts_helper_ext.rb +35 -11
  6. data/app/lib/proxy_api/monitoring.rb +35 -0
  7. data/app/models/concerns/foreman_monitoring/host_extensions.rb +48 -8
  8. data/app/models/concerns/foreman_monitoring/hostgroup_extensions.rb +15 -0
  9. data/app/models/concerns/orchestration/monitoring.rb +105 -0
  10. data/app/models/host_status/monitoring_status.rb +5 -1
  11. data/app/models/setting/monitoring.rb +23 -6
  12. data/app/overrides/add_host_multiple_power_set_downtime_checkbox.rb +5 -0
  13. data/app/overrides/add_host_set_downtime_modal.rb +5 -0
  14. data/app/services/monitoring.rb +56 -3
  15. data/app/views/hosts/_downtime_fields.html.erb +3 -0
  16. data/app/views/hosts/_host_downtime_checkbox.html.erb +8 -0
  17. data/app/views/hosts/_set_host_downtime.html.erb +20 -0
  18. data/app/views/hosts/select_multiple_downtime.html.erb +5 -0
  19. data/app/views/hosts/select_multiple_monitoring_proxy.html.erb +5 -0
  20. data/app/views/monitoring_results/_host_tab.html.erb +2 -0
  21. data/app/views/monitoring_results/_host_tab_pane.html.erb +2 -0
  22. data/config/routes.rb +16 -0
  23. data/db/migrate/20161220201510_add_monitoring_proxy_id_to_host_and_hostgroup.rb +11 -0
  24. data/lib/foreman_monitoring/engine.rb +35 -3
  25. data/lib/foreman_monitoring/version.rb +1 -1
  26. data/test/factories/host.rb +6 -0
  27. data/test/functional/hosts_controller_test.rb +190 -0
  28. data/test/lib/proxy_api/monitoring_test.rb +30 -0
  29. data/test/test_plugin_helper.rb +4 -0
  30. data/test/unit/host_status/monitoring_status_test.rb +7 -2
  31. data/test/unit/host_test.rb +111 -5
  32. data/test/unit/monitoring_test.rb +9 -3
  33. metadata +19 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 64c6df30e7204048fc85d7ce4e6de17ba28d14c5
4
- data.tar.gz: 3e14672d74d600a9e05aff1a92846b804c07aa0b
3
+ metadata.gz: 3d9186b9fa48b695bea2617e3c589b22d0df22bd
4
+ data.tar.gz: f3dd5db766d37990e59d09ffdf9881a830abc134
5
5
  SHA512:
6
- metadata.gz: 8e37b4565ae23bc25f9319ce81737751eb95cf1ebe11840aad9499cbacf37445447eb784d6c95a8022702effc2cf751748ee109b41f621960daf8a245d88eb52
7
- data.tar.gz: ceb07dd17ccef4baf8311faa60afbfb8ad03a73c2b842eb7fb9dcfeb1865de4feebb9448292cc1e5c46f43f76db08c877a0484c56d63b53ee4d20e3c6c6e7b7a
6
+ metadata.gz: 25700b1a96cebf6cfb1e829b54dfef9f6fd6f934ffbbd1e8a9fa753ee9e51f0a406c478c0bdba8e8cd2b46bbeaf5ae3d2be0a06da9524ea77740b8e042e32f61
7
+ data.tar.gz: 1f714e3081f6adeb50b7f01f30c6855dc237f3613210993719fc0f0d97ed34828190f58c784e9ac93a6afb6c54d2049c1bd5b82f7e76d088553b3af7ae8f1479
data/README.md CHANGED
@@ -1,14 +1,41 @@
1
1
  # Foreman Monitoring Plugin
2
2
 
3
3
  This is a Foreman plugin for monitoring system integration.
4
+ It allows to manage hosts and downtimes and to display status
5
+ information from the monitoring solution.
6
+
7
+ It requires the Smart Proxy plugin [monitoring](https://github.com/theforeman/smart_proxy_monitoring)
8
+ for communication with the monitoring system. See its documentation
9
+ for supported monitoring solutions and detailed configuration instructions.
4
10
 
5
11
  # Installation
6
12
 
7
13
  See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
8
- for how to install Foreman plugins
14
+ for how to install Foreman plugins.
15
+
16
+ The gem name is `foreman_monitoring`.
17
+
18
+ RPM users can install the `tfm-rubygem-foreman_monitoring` package.
19
+
20
+ This plug-in has not been packaged for Debian, yet.
9
21
 
10
22
  # Usage
11
23
 
24
+ For managing a host in the monitoring solution a Smart Proxy providing
25
+ the `monitoring` feature has to be assigned. This can be done during
26
+ provisioning or as a bulk action from the host overview.
27
+
28
+ You can configure the default action which will be done during host
29
+ provisioning and deprovisioning. Provisioning allows to create a monitoring
30
+ object or take no action while deprovisioing allows to delete the monitoring
31
+ object, set a downtime or take no action. For rebuild it will by default
32
+ set a downtime.
33
+
34
+ The plugin will show you the monitoring status as a sub-status and a detail
35
+ panel. You can configure if the sub-status should affect the global status.
36
+
37
+ Furthermore it allows to individually set a downtime at the host detail view
38
+ or as a bulk action from the host overview.
12
39
 
13
40
  ## Contributing
14
41
 
@@ -6,6 +6,14 @@ module Api
6
6
 
7
7
  add_smart_proxy_filters :create, :features => 'Monitoring'
8
8
 
9
+ api :POST, '/monitoring_results', N_('Import monitoring result')
10
+ param :host, String, :desc => N_('FQDN of the host that the results are for'), :required => true
11
+ param :service, String, :desc => N_('Name of the service the results belong to'), :required => true
12
+ param :timestamp, String, :desc => N_('Timestamp of the results')
13
+ param :acknowledged, [true, false], :desc => N_('Is the result acknowledged?')
14
+ param :downtime, [true, false], :desc => N_('Is the result in downtime?')
15
+ param :result, [0, 1, 2, 3], :desc => N_('State of the monitoring result (0 -> ok, 1 -> warning, 2 -> critical, 3 -> unknown)')
16
+
9
17
  def create
10
18
  begin
11
19
  MonitoringResult.import(monitoring_result_params.with_indifferent_access)
@@ -0,0 +1,140 @@
1
+ module ForemanMonitoring
2
+ module HostsControllerExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :find_resource_with_monitoring, :only => [:downtime]
7
+ before_action :find_multiple_with_monitoring, :only => [:select_multiple_downtime, :update_multiple_downtime,
8
+ :select_multiple_monitoring_proxy, :update_multiple_monitoring_proxy]
9
+ before_action :validate_host_downtime_params, :only => [:downtime]
10
+ before_action :validate_hosts_downtime_params, :only => [:update_multiple_downtime]
11
+ before_action :validate_multiple_monitoring_proxy, :only => :update_multiple_monitoring_proxy
12
+
13
+ alias_method :find_resource_with_monitoring, :find_resource
14
+ alias_method :find_multiple_with_monitoring, :find_multiple
15
+ alias_method_chain :update_multiple_power_state, :monitoring
16
+ end
17
+
18
+ def downtime
19
+ unless @host.downtime_host(downtime_options)
20
+ process_error(:redirect => host_path, :error_msg => @host.errors.full_messages.to_sentence)
21
+ return false
22
+ end
23
+ process_success :success_msg => _('Created downtime for %s') % (@host), :success_redirect => :back
24
+ end
25
+
26
+ def select_multiple_downtime
27
+ end
28
+
29
+ def update_multiple_downtime
30
+ failed_hosts = {}
31
+
32
+ @hosts.each do |host|
33
+ unless host.monitored?
34
+ failed_hosts[host.name] = _('is not monitored')
35
+ next
36
+ end
37
+ begin
38
+ unless host.downtime_host(downtime_options)
39
+ error_message = host.errors.full_messages.to_sentence
40
+ failed_hosts[host.name] = error_message
41
+ logger.error "Failed to set a host downtime for #{host}: #{error_message}"
42
+ end
43
+ rescue => error
44
+ failed_hosts[host.name] = error
45
+ Foreman::Logging.exception(_('Failed to set a host downtime for %s.') % host, error)
46
+ end
47
+ end
48
+
49
+ if failed_hosts.empty?
50
+ notice _('A downtime was set for the selected hosts.')
51
+ else
52
+ error n_('A downtime clould not be set for host: %s.',
53
+ 'A downtime could not be set for hosts: %s.',
54
+ failed_hosts.count) % failed_hosts.map { |h, err| "#{h} (#{err})" }.to_sentence
55
+ end
56
+ redirect_back_or_to hosts_path
57
+ end
58
+
59
+ def validate_multiple_monitoring_proxy
60
+ validate_multiple_proxy(select_multiple_monitoring_proxy_hosts_path)
61
+ end
62
+
63
+ def select_multiple_monitoring_proxy
64
+ end
65
+
66
+ def update_multiple_monitoring_proxy
67
+ update_multiple_proxy(_('Monitoring'), :monitoring_proxy=)
68
+ end
69
+
70
+ def update_multiple_power_state_with_monitoring
71
+ options = {
72
+ :comment => 'Power state changed in Foreman',
73
+ :author => "Foreman User #{User.current}",
74
+ :start_time => DateTime.now.to_time.to_i,
75
+ :end_time => DateTime.now.advance(:minutes => 30).to_time.to_i
76
+ }
77
+ if User.current.allowed_to?(:controller => :hosts, :action => :select_multiple_downtime) && params[:power][:set_downtime]
78
+ @hosts.each do |host|
79
+ unless host.monitored?
80
+ logger.debug "Not setting a downtime for #{host} as it is not monitored."
81
+ next
82
+ end
83
+ if host.downtime_host(options)
84
+ logger.debug "Set a host downtime for #{host}."
85
+ else
86
+ logger.error "Failed to set a host downtime for #{host}: #{host.errors.full_messages.to_sentence}"
87
+ end
88
+ end
89
+ end
90
+ update_multiple_power_state_without_monitoring
91
+ end
92
+
93
+ private
94
+
95
+ def downtime_options
96
+ {
97
+ :comment => params[:downtime][:comment],
98
+ :author => "Foreman User #{User.current}",
99
+ :start_time => DateTime.parse(params[:downtime][:starttime]).to_time.to_i,
100
+ :end_time => DateTime.parse(params[:downtime][:endtime]).to_time.to_i
101
+ }
102
+ end
103
+
104
+ def validate_host_downtime_params
105
+ validate_downtime_params(host_path)
106
+ end
107
+
108
+ def validate_hosts_downtime_params
109
+ validate_downtime_params(hosts_path)
110
+ end
111
+
112
+ def validate_downtime_params(redirect_url)
113
+ if params[:downtime].blank? || (params[:downtime][:comment]).blank?
114
+ process_error(:redirect => redirect_url, :error_msg => 'No comment for downtime set!')
115
+ return false
116
+ end
117
+ if (params[:downtime][:starttime]).blank? || (params[:downtime][:endtime]).blank?
118
+ process_error(:redirect => redirect_url, :error_msg => 'No start/endtime for downtime!')
119
+ return false
120
+ end
121
+ begin
122
+ DateTime.parse(params[:downtime][:starttime])
123
+ DateTime.parse(params[:downtime][:endtime])
124
+ rescue ArgumentError
125
+ process_error(:redirect => redirect_url, :error_msg => 'Invalid start/endtime for downtime!')
126
+ return false
127
+ end
128
+ end
129
+
130
+ def action_permission
131
+ case params[:action]
132
+ when 'downtime', 'select_multiple_downtime', 'update_multiple_downtime',
133
+ 'select_multiple_monitoring_proxy', 'update_multiple_monitoring_proxy'
134
+ :downtime
135
+ else
136
+ super
137
+ end
138
+ end
139
+ end
140
+ end
@@ -2,18 +2,35 @@ module ForemanMonitoring
2
2
  module HostsHelperExt
3
3
  extend ActiveSupport::Concern
4
4
 
5
- # included do
6
- # alias_method_chain :host_title_actions, :monitoring
7
- # end
5
+ included do
6
+ alias_method_chain :host_title_actions, :monitoring
7
+ alias_method_chain :multiple_actions, :monitoring
8
+ end
9
+
10
+ def multiple_actions_with_monitoring
11
+ return multiple_actions_without_monitoring unless authorized_for(:controller => :hosts, :action => :select_multiple_downtime)
12
+ multiple_actions_without_monitoring + [[_('Set downtime'), select_multiple_downtime_hosts_path], [_('Change Monitoring Proxy'), select_multiple_monitoring_proxy_hosts_path]]
13
+ end
8
14
 
9
- # def host_title_actions_with_monitoring(host)
10
- # title_actions(
11
- # button_group(
12
- # link_to(_('Monitoring'), monitoring_show_host_path(host), :target => '_blank', :class => 'btn btn-default')
13
- # )
14
- # )
15
- # host_title_actions_without_monitoring(host)
16
- # end
15
+ def host_title_actions_with_monitoring(host)
16
+ title_actions(
17
+ button_group(
18
+ display_link_if_authorized(_('Downtime'),
19
+ hash_for_host_path(:id => host).merge(:auth_object => host,
20
+ :permission => :manage_host_downtimes,
21
+ :anchor => 'set_host_downtime'),
22
+ :class => 'btn btn-default',
23
+ :disabled => !host.monitored?,
24
+ :title => _('Set a downtime for this host'),
25
+ :id => 'host-downtime',
26
+ :data => { :toggle => 'modal',
27
+ :target => '#set_host_downtime'
28
+ }
29
+ )
30
+ )
31
+ )
32
+ host_title_actions_without_monitoring(host)
33
+ end
17
34
 
18
35
  def host_monitoring_result_icon_class(result)
19
36
  icon_class = case result
@@ -42,5 +59,12 @@ module ForemanMonitoring
42
59
  'status-question'
43
60
  end
44
61
  end
62
+
63
+ def datetime_f(f, attr, options = {})
64
+ field(f, attr, options) do
65
+ addClass options, 'form-control'
66
+ f.datetime_local_field attr, options
67
+ end
68
+ end
45
69
  end
46
70
  end
@@ -10,5 +10,40 @@ module ProxyAPI
10
10
  rescue => e
11
11
  raise ProxyException.new(url, e, N_('Unable to set downtime for %s') % host)
12
12
  end
13
+
14
+ def remove_host_downtime(host, args = {})
15
+ parse(delete("downtime/host/#{host}?#{args.to_query}"))
16
+ rescue => e
17
+ raise ProxyException.new(url, e, N_('Unable to remove downtime for %s') % host)
18
+ end
19
+
20
+ def create_host(host, attributes = {})
21
+ parse(put({:attributes => attributes}, "host/#{host}"))
22
+ rescue => e
23
+ raise ProxyException.new(url, e, N_('Unable to create monitoring host object for %s') % host)
24
+ end
25
+
26
+ def update_host(host, attributes = {})
27
+ parse(post({:attributes => attributes}, "host/#{host}"))
28
+ rescue => e
29
+ raise ProxyException.new(url, e, N_('Unable to update monitoring host object for %s') % host)
30
+ end
31
+
32
+ def delete_host(host)
33
+ raise Foreman::Exception.new('Missing hostname.') if host.blank?
34
+ parse(delete("host/#{host}"))
35
+ rescue RestClient::ResourceNotFound
36
+ true
37
+ rescue => e
38
+ raise ProxyException.new(url, e, N_('Unable to delete monitoring host object for %s') % host)
39
+ end
40
+
41
+ def query_host(host)
42
+ parse(get("host/#{host}"))
43
+ rescue RestClient::ResourceNotFound
44
+ nil
45
+ rescue => e
46
+ raise ProxyException.new(url, e, N_('Unable to query monitoring host object for %s') % host)
47
+ end
13
48
  end
14
49
  end
@@ -2,10 +2,14 @@ module ForemanMonitoring
2
2
  module HostExtensions
3
3
  extend ActiveSupport::Concern
4
4
  included do
5
- before_destroy :downtime_host_destroy
5
+ include Orchestration::Monitoring
6
+
6
7
  after_build :downtime_host_build
7
8
 
8
- has_many :monitoring_results, :foreign_key => 'host_id'
9
+ alias_method_chain :smart_proxy_ids, :monitoring_proxy
10
+ alias_method_chain :hostgroup_inherited_attributes, :monitoring
11
+
12
+ has_many :monitoring_results, :dependent => :destroy, :foreign_key => 'host_id'
9
13
  end
10
14
 
11
15
  def monitoring_status(options = {})
@@ -24,19 +28,55 @@ module ForemanMonitoring
24
28
  downtime_host(:comment => _('Host rebuilt in Foreman'))
25
29
  end
26
30
 
27
- def downtime_host_destroy
28
- downtime_host(:comment => _('Host deleted in Foreman'))
29
- end
30
-
31
31
  def downtime_host(options)
32
- return unless monitoring_results.any?
32
+ return unless monitored?
33
33
  begin
34
- monitoring = Monitoring.new
35
34
  monitoring.set_downtime_host(self, options)
36
35
  rescue ProxyAPI::ProxyException => e
37
36
  errors.add(:base, _("Error setting downtime: '%s'") % e.message)
38
37
  end
39
38
  errors.empty?
40
39
  end
40
+
41
+ def monitored?
42
+ monitoring_proxy.present?
43
+ end
44
+
45
+ def hostgroup_inherited_attributes_with_monitoring
46
+ hostgroup_inherited_attributes_without_monitoring + ['monitoring_proxy_id']
47
+ end
48
+
49
+ def smart_proxy_ids_with_monitoring_proxy
50
+ ids = smart_proxy_ids_without_monitoring_proxy
51
+ [monitoring_proxy, hostgroup.try(:monitoring_proxy)].compact.each do |proxy|
52
+ ids << proxy.id
53
+ end
54
+ ids
55
+ end
56
+
57
+ def monitoring_attributes
58
+ {
59
+ :ip => ip,
60
+ :ip6 => ip6,
61
+ :architecture => architecture.try(:name),
62
+ :os => operatingsystem.try(:to_label),
63
+ :osfamily => operatingsystem.try(:family),
64
+ :virtual => provider != 'BareMetal',
65
+ :provider => provider,
66
+ :compute_resource => compute_resource.try(:to_label),
67
+ :hostgroup => hostgroup.try(:to_label),
68
+ :organization => organization.try(:name),
69
+ :location => organization.try(:name),
70
+ :comment => comment,
71
+ :environment => environment.try(:to_s),
72
+ :owner_name => owner.try(:name)
73
+ }
74
+ end
75
+
76
+ private
77
+
78
+ def monitoring
79
+ Monitoring.new(:monitoring_proxy => monitoring_proxy)
80
+ end
41
81
  end
42
82
  end
@@ -0,0 +1,15 @@
1
+ module ForemanMonitoring
2
+ module HostgroupExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ def monitoring_proxy
6
+ return super unless ancestry.present?
7
+ SmartProxy.find_by_id(inherited_monitoring_proxy_id)
8
+ end
9
+
10
+ def inherited_monitoring_proxy_id
11
+ return monitoring_proxy_id unless ancestry.present?
12
+ self[:monitoring_proxy_id] || self.class.sort_by_ancestry(ancestors.where('monitoring_proxy_id is not NULL')).last.try(:monitoring_proxy_id)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,105 @@
1
+ module Orchestration::Monitoring
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ after_validation :queue_monitoring
6
+ before_destroy :queue_monitoring_destroy
7
+ end
8
+
9
+ protected
10
+
11
+ def queue_monitoring
12
+ return unless monitored? && errors.empty?
13
+ clear_monitoring_object
14
+ !monitoring_object.has_key?(:attrs) ? queue_monitoring_create : queue_monitoring_update
15
+ end
16
+
17
+ def queue_monitoring_create
18
+ queue.create(:name => _("Create monitoring object for %s") % self, :priority => 20,
19
+ :action => [self, :setMonitoring]) if ::Monitoring.create_action?(:create)
20
+ end
21
+
22
+ def queue_monitoring_update
23
+ return unless monitoring_update_required?(monitoring_object[:attrs], monitoring_attributes)
24
+ Rails.logger.debug("Detected a change to the monitoring object is required.")
25
+ queue.create(:name => _("Monitoring update for %s") % old, :priority => 2,
26
+ :action => [self, :setMonitoringUpdate]) if ::Monitoring.create_action?(:create)
27
+ end
28
+
29
+ def queue_monitoring_destroy
30
+ return unless monitored? && errors.empty?
31
+ queue.create(:name => _("Removing monitoring object for %s") % self, :priority => 2,
32
+ :action => [self, :delMonitoring]) if ::Monitoring.delete_action?(:delete)
33
+ queue.create(:name => _("Set monitoring downtime for %s") % self, :priority => 2,
34
+ :action => [self, :setMonitoringDowntime]) if ::Monitoring.delete_action?(:downtime)
35
+ end
36
+
37
+ def setMonitoring
38
+ Rails.logger.info "Adding Monitoring object for #{name}"
39
+ monitoring.create_host(self)
40
+ rescue => e
41
+ failure _("Failed to create a monitoring object %{name}: %{message}\n ") % { :name => name, :message => e.message }, e
42
+ end
43
+
44
+ def delMonitoring
45
+ Rails.logger.info "Deleting Monitoring object for #{name}"
46
+ monitoring.delete_host(self)
47
+ rescue => e
48
+ failure _("Failed to delete a monitoring object %{name}: %{message}\n ") % { :name => name, :message => e.message }, e
49
+ end
50
+
51
+ def setMonitoringUpdate
52
+ Rails.logger.info "Updating Monitoring object for #{name}"
53
+ monitoring.update_host(self)
54
+ rescue => e
55
+ failure _("Failed to update a monitoring object %{name}: %{message}\n ") % { :name => name, :message => e.message }, e
56
+ end
57
+
58
+ def delMonitoringUpdate; end
59
+
60
+ def setMonitoringDowntime
61
+ Rails.logger.info "Setting Monitoring downtime for #{name}"
62
+ monitoring.set_downtime_host(self, monitoring_downtime_defaults)
63
+ rescue => e
64
+ failure _("Failed to set a monitoring downtime for %{name}: %{message}\n ") % { :name => name, :message => e.message }, e
65
+ end
66
+
67
+ def delMonitoringDowntime
68
+ Rails.logger.info "Deleting Monitoring downtime for #{name}"
69
+ monitoring.del_downtime_host(self, monitoring_downtime_defaults)
70
+ rescue => e
71
+ failure _("Failed to set a monitoring downtime for %{name}: %{message}\n ") % { :name => name, :message => e.message }, e
72
+ end
73
+
74
+ def monitoring_object
75
+ @monitoring_object || monitoring.query_host(self)
76
+ end
77
+
78
+ def clear_monitoring_object
79
+ @monitoring_object = nil
80
+ true
81
+ end
82
+
83
+ private
84
+
85
+ def monitoring_downtime_defaults
86
+ {
87
+ :comment => _('Host deleted in Foreman')
88
+ }
89
+ end
90
+
91
+ def monitoring_update_required?(actual_attrs, desired_attrs)
92
+ return true if actual_attrs.deep_symbolize_keys.keys != desired_attrs.deep_symbolize_keys.keys
93
+ actual_attrs.deep_symbolize_keys.merge(desired_attrs.deep_symbolize_keys) do |k, actual_v, desired_v|
94
+ if actual_v.is_a?(Hash) && desired_v.is_a?(Hash)
95
+ return true if monitoring_update_required?(actual_v, desired_v)
96
+ elsif actual_v.to_s != desired_v.to_s
97
+ Rails.logger.debug "Scheduling monitoring host object update because #{k} changed it's value from '#{actual_v}' (#{actual_v.class}) to '#{desired_v}' (#{desired_v.class})"
98
+ return true
99
+ end
100
+ desired_v
101
+ end
102
+ Rails.logger.debug "No monitoring update required."
103
+ false
104
+ end
105
+ end