foreman_monitoring 0.0.3 → 0.1.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 (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
@@ -6,7 +6,7 @@ module HostStatus
6
6
  UNKNOWN = 3
7
7
 
8
8
  def relevant?(_options = {})
9
- host_not_in_build? && host_known_in_monitoring?
9
+ host_not_in_build? && host.monitored? && host_known_in_monitoring?
10
10
  end
11
11
 
12
12
  def to_status(_options = {})
@@ -59,6 +59,10 @@ module HostStatus
59
59
  host.monitoring_results.any?
60
60
  end
61
61
 
62
+ def host_monitored?
63
+ host.monitored?
64
+ end
65
+
62
66
  def should_affect_global_status?
63
67
  Setting[:monitoring_affect_global_status]
64
68
  end
@@ -1,16 +1,33 @@
1
1
  class Setting
2
2
  class Monitoring < ::Setting
3
+
4
+ def self.default_settings
5
+ [
6
+ set('monitoring_affect_global_status',
7
+ _("Monitoring status will affect a host's global status when enabled"),
8
+ true, N_('Monitoring status should affect global status')),
9
+ set('monitoring_create_action',
10
+ _("What action should be taken when a host is created"),
11
+ 'create', N_('Host Create Action'), nil, {:collection => Proc.new {::Monitoring::CREATE_ACTIONS} }),
12
+ set('monitoring_delete_action',
13
+ _("What action should be taken when a host is deleted"),
14
+ 'delete', N_('Host Delete Action'), nil, {:collection => Proc.new {::Monitoring::DELETE_ACTIONS} })
15
+ ]
16
+ end
17
+
3
18
  def self.load_defaults
4
19
  # Check the table exists
5
20
  return unless super
6
21
 
7
- Setting.transaction do
8
- [
9
- set('monitoring_affect_global_status',
10
- _("Monitoring status will affect a host's global status when enabled"),
11
- true, N_('Monitoring status should affect global status'))
12
- ].compact.each { |s| create! s.update(:category => 'Setting::Monitoring') }
22
+ self.transaction do
23
+ default_settings.each { |s| self.create! s.update(:category => "Setting::Monitoring")}
13
24
  end
25
+
26
+ true
27
+ end
28
+
29
+ def self.humanized_category
30
+ N_('Monitoring')
14
31
  end
15
32
  end
16
33
  end
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => 'hosts/select_multiple_power_state',
2
+ :name => 'add_host_multiple_power_set_downtime_checkbox',
3
+ :insert_before => "erb[silent]:contains('end')",
4
+ :partial => 'hosts/host_downtime_checkbox'
5
+ )
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => 'hosts/show',
2
+ :name => 'add_monitoring_set_downtime_modal',
3
+ :insert_after => 'div#review_before_build',
4
+ :partial => 'hosts/set_host_downtime'
5
+ )
@@ -1,13 +1,66 @@
1
1
  class Monitoring
2
+ CREATE_ACTIONS = {
3
+ 'none' => _('None'),
4
+ 'create' => _('Create Host Object')
5
+ }.freeze
6
+
7
+ DELETE_ACTIONS = {
8
+ 'none' => _('None'),
9
+ 'delete' => _('Delete Host Object'),
10
+ 'downtime' => _('Set Downtime for Host')
11
+ }.freeze
12
+
2
13
  delegate :logger, :to => :Rails
3
14
  attr_reader :proxy, :proxy_api
4
15
 
5
- def initialize
6
- @proxy = SmartProxy.with_features('Monitoring').first
16
+ def self.create_action?(action)
17
+ Setting[:monitoring_create_action] == action.to_s
18
+ end
19
+
20
+ def self.delete_action?(action)
21
+ Setting[:monitoring_delete_action] == action.to_s
22
+ end
23
+
24
+ def initialize(opts)
25
+ @proxy = opts.fetch(:monitoring_proxy)
7
26
  @proxy_api = ProxyAPI::Monitoring.new(:url => proxy.url)
8
27
  end
9
28
 
10
29
  def set_downtime_host(host, options = {})
11
- proxy_api.create_host_downtime(host.fqdn, { :author => 'Foreman', :comment => 'triggered by Foreman' }.merge(options))
30
+ proxy_api.create_host_downtime(host.fqdn, default_downtime_options.merge(options))
31
+ end
32
+
33
+ def del_downtime_host(host, options = {})
34
+ proxy_api.remove_host_downtime(host.fqdn, default_downtime_options.merge(options))
35
+ end
36
+
37
+ def create_host(host)
38
+ proxy_api.create_host(host.fqdn, host.monitoring_attributes)
39
+ end
40
+
41
+ def update_host(host)
42
+ proxy_api.update_host(host.fqdn, host.monitoring_attributes)
43
+ end
44
+
45
+ def delete_host(host)
46
+ # We cannot use host.fqdn here as that is delegated to primary interface that does not exist anymore
47
+ proxy_api.delete_host(host.name)
48
+ end
49
+
50
+ def query_host(host)
51
+ result = proxy_api.query_host(host.name)
52
+ return {} unless result
53
+ {
54
+ :attrs => result
55
+ }
56
+ end
57
+
58
+ private
59
+
60
+ def default_downtime_options
61
+ {
62
+ :author => 'Foreman',
63
+ :comment => 'triggered by Foreman'
64
+ }
12
65
  end
13
66
  end
@@ -0,0 +1,3 @@
1
+ <%= text_f f, :comment, :size => "col-md-5", :label => _('Comment'), :help_inline => _('Short description that explains why the downtime was set.'), :required => true %>
2
+ <%= datetime_f f, :starttime, :size => "col-md-5", :label => _('Starttime'), :help_inline => _('Time when the downtime should start.'), :value => DateTime.now.strftime("%Y-%m-%dT%H:%M"), :required => true %>
3
+ <%= datetime_f f, :endtime, :size => "col-md-5", :label => _('Endtime'), :help_inline => _('Time when the downtime should end.'), :value => DateTime.now.advance(:hours => 2).strftime("%Y-%m-%dT%H:%M"), :required => true %>
@@ -0,0 +1,8 @@
1
+ <% if authorized_for(:controller => :hosts, :action => :select_multiple_downtime) %>
2
+ <%= checkbox_f f, :set_downtime, {
3
+ :label_size => 'col-md-6',
4
+ :help_inline => _('Set a downtime for this host')
5
+ },
6
+ 'true',
7
+ 'false' %>
8
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <div id="set_host_downtime" class="modal fade hide">
2
+ <div class="modal-dialog">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <%= alert_close('modal') %>
6
+ <h4 class="modal-title"><%= _('Set host downtime for %s') % @host %></h4>
7
+ </div>
8
+ <div class="modal-body">
9
+ <%= form_for :downtime,
10
+ :method => :put,
11
+ :url => hash_for_downtime_host_path(:id => @host).merge(:auth_object => @host, :permission => 'build_hosts') do |f| %>
12
+ <%= render :partial => 'downtime_fields', :locals => { :f => f } %>
13
+ <div class="modal-footer">
14
+ <%= modal_close %>
15
+ <%= f.submit(_("Set downtime"), :class => "btn btn-success submit") %>
16
+ </div>
17
+ <% end %>
18
+ </div>
19
+ </div>
20
+ </div>
@@ -0,0 +1,5 @@
1
+ <%= render 'selected_hosts', :hosts => @hosts %>
2
+
3
+ <%= form_for :downtime, :url => update_multiple_downtime_hosts_path(:host_ids => params[:host_ids]) do |f| %>
4
+ <%= render :partial => 'downtime_fields', :locals => { :f => f } %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <%= render 'selected_hosts', :hosts => @hosts %>
2
+
3
+ <%= form_for :proxy, :url => update_multiple_monitoring_proxy_hosts_path(:host_ids => params[:host_ids]) do |f| %>
4
+ <%= multiple_proxy_select(f, 'Monitoring') %>
5
+ <% end %>
@@ -1 +1,3 @@
1
+ <%- if authorized_for(:permission => 'view_monitoring_results', :auth_object => @host) && @host.monitored? -%>
1
2
  <li><a href="#monitoring" data-toggle="tab"><%= _("Monitoring") %></a></li>
3
+ <%- end -%>
@@ -1,3 +1,4 @@
1
+ <%- if authorized_for(:permission => 'view_monitoring_results', :auth_object => @host) && @host.monitored? -%>
1
2
  <div class="tab-pane" id="monitoring">
2
3
  <% if @host.monitoring_results.any? %>
3
4
  <table class="table table-bordered table-striped">
@@ -23,3 +24,4 @@
23
24
  <div class="alert alert-success"> <%= _('No monitoring results for this host') %> </div>
24
25
  <% end %>
25
26
  </div>
27
+ <%- end -%>
data/config/routes.rb CHANGED
@@ -7,4 +7,20 @@ Rails.application.routes.draw do
7
7
  resources :monitoring_results, :only => [:create]
8
8
  end
9
9
  end
10
+
11
+ scope '/monitoring' do
12
+ constraints(:id => %r{[^\/]+}) do
13
+ resources :hosts, :only => [] do
14
+ member do
15
+ put 'downtime'
16
+ end
17
+ collection do
18
+ post :select_multiple_downtime
19
+ post :update_multiple_downtime
20
+ post :select_multiple_monitoring_proxy
21
+ post :update_multiple_monitoring_proxy
22
+ end
23
+ end
24
+ end
25
+ end
10
26
  end
@@ -0,0 +1,11 @@
1
+ class AddMonitoringProxyIdToHostAndHostgroup < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :hosts, :monitoring_proxy_id, :integer
4
+ add_column :hostgroups, :monitoring_proxy_id, :integer
5
+ end
6
+
7
+ def self.down
8
+ remove_column :hosts, :monitoring_proxy_id
9
+ remove_column :hostgroups, :monitoring_proxy_id
10
+ end
11
+ end
@@ -30,15 +30,47 @@ module ForemanMonitoring
30
30
 
31
31
  initializer 'foreman_monitoring.register_plugin', :before => :finisher_hook do |_app|
32
32
  Foreman::Plugin.register :foreman_monitoring do
33
- requires_foreman '>= 1.11'
33
+ requires_foreman '>= 1.15'
34
+
35
+ apipie_documented_controllers ["#{ForemanMonitoring::Engine.root}/app/controllers/api/v2/*.rb"]
36
+
37
+ security_block :foreman_monitoring do
38
+ permission :view_monitoring_results,
39
+ {},
40
+ :resource_type => 'Host'
41
+ permission :manage_host_downtimes,
42
+ { :hosts => [:downtime, :select_multiple_downtime, :update_multiple_downtime] },
43
+ :resource_type => 'Host'
44
+ permission :upload_monitoring_results,
45
+ :'api/v2/monitoring_results' => [:create]
46
+ end
47
+
48
+ role 'Monitoring viewer', [:view_monitoring_results]
49
+ role 'Monitoring manager', [:view_monitoring_results, :manage_host_downtimes, :upload_monitoring_results]
50
+
34
51
  register_custom_status HostStatus::MonitoringStatus
52
+
53
+ add_controller_action_scope(HostsController, :index) { |base_scope| base_scope.includes(:monitoring_results) }
54
+
55
+ monitoring_proxy_options = {
56
+ :feature => 'Monitoring',
57
+ :label => N_('Monitoring Proxy'),
58
+ :description => N_('Monitoring Proxy to use to manage monitoring of this host'),
59
+ :api_description => N_('ID of Monitoring Proxy to use to manage monitoring of this host')
60
+ }
61
+
62
+ # add monitoring smart proxy to hosts and hostgroups
63
+ smart_proxy_for Host::Managed, :monitoring_proxy, monitoring_proxy_options
64
+ smart_proxy_for Hostgroup, :monitoring_proxy, monitoring_proxy_options
35
65
  end
36
66
  end
37
67
 
38
68
  config.to_prepare do
39
69
  begin
40
- Host::Managed.send :include, ForemanMonitoring::HostExtensions
41
- HostsHelper.send(:include, ForemanMonitoring::HostsHelperExt)
70
+ ::Host::Managed.send :include, ForemanMonitoring::HostExtensions
71
+ ::Hostgroup.send :include, ForemanMonitoring::HostgroupExtensions
72
+ ::HostsHelper.send(:include, ForemanMonitoring::HostsHelperExt)
73
+ ::HostsController.send :include, ForemanMonitoring::HostsControllerExtensions
42
74
  rescue => e
43
75
  Rails.logger.warn "ForemanMonitoring: skipping engine hook (#{e})"
44
76
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanMonitoring
2
- VERSION = '0.0.3'.freeze
2
+ VERSION = '0.1.0'.freeze
3
3
  end
@@ -1,5 +1,11 @@
1
1
  FactoryGirl.modify do
2
2
  factory :host do
3
+ trait :with_monitoring do
4
+ monitoring_proxy do
5
+ FactoryGirl.create(:smart_proxy, :monitoring)
6
+ end
7
+ end
8
+
3
9
  trait :with_monitoring_results do
4
10
  transient do
5
11
  monitoring_result_count 20
@@ -0,0 +1,190 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class HostsControllerExtensionsTest < ActionController::TestCase
4
+ tests ::HostsController
5
+ setup do
6
+ User.current = users(:admin)
7
+ disable_monitoring_orchestration
8
+ @host = FactoryGirl.create(:host, :managed)
9
+ end
10
+
11
+ context 'when setting a host downtime' do
12
+ setup do
13
+ @request.env['HTTP_REFERER'] = host_path(:id => @host)
14
+ end
15
+
16
+ test 'the flash should inform it' do
17
+ Host::Managed.any_instance.stubs(:downtime_host).returns(true)
18
+ put :downtime, {
19
+ :id => @host.name,
20
+ :downtime => {
21
+ :comment => 'Maintenance work.',
22
+ :starttime => DateTime.now,
23
+ :endtime => DateTime.now
24
+ }
25
+ }, set_session_user
26
+ assert_response :found
27
+ assert_redirected_to host_path(:id => @host)
28
+ assert_nil flash[:error]
29
+ assert_not_nil flash[:notice]
30
+ assert_equal "Created downtime for #{@host}", flash[:notice]
31
+ end
32
+
33
+ test 'with missing comment param the flash should inform it' do
34
+ put :downtime, { :id => @host.name }, set_session_user
35
+ assert_response :found
36
+ assert_redirected_to host_path(:id => @host)
37
+ assert_not_nil flash[:error]
38
+ assert_equal 'No comment for downtime set!', flash[:error]
39
+ end
40
+
41
+ test 'with missing date params the flash should inform it' do
42
+ put :downtime, { :id => @host.name, :downtime => { :comment => 'Maintenance work.' } }, set_session_user
43
+ assert_response :found
44
+ assert_redirected_to host_path(:id => @host)
45
+ assert_not_nil flash[:error]
46
+ assert_equal 'No start/endtime for downtime!', flash[:error]
47
+ end
48
+
49
+ test 'with invalid starttime the flash should inform it' do
50
+ put :downtime, {
51
+ :id => @host.name,
52
+ :downtime => {
53
+ :comment => 'Maintenance work.',
54
+ :starttime => 'invalid',
55
+ :endtime => 'invalid' }
56
+ }, set_session_user
57
+ assert_response :found
58
+ assert_redirected_to host_path(:id => @host)
59
+ assert_not_nil flash[:error]
60
+ assert_equal 'Invalid start/endtime for downtime!', flash[:error]
61
+ end
62
+ end
63
+
64
+ describe 'setting a downtime on multiple hosts' do
65
+ before do
66
+ @hosts = FactoryGirl.create_list(:host, 2, :with_monitoring)
67
+ @request.env['HTTP_REFERER'] = hosts_path
68
+ end
69
+
70
+ test 'show a host selection' do
71
+ host_ids = @hosts.map(&:id)
72
+ xhr :post, :select_multiple_downtime, {:host_ids => host_ids}, set_session_user
73
+ assert_response :success
74
+ assert response.body =~ /#{@hosts.first.name}.*#{@hosts.last.name}/m
75
+ end
76
+
77
+ test 'should set a downtime' do
78
+ Host::Managed.any_instance.expects(:downtime_host).twice.returns(true)
79
+ params = {
80
+ :host_ids => @hosts.map(&:id),
81
+ :downtime => {
82
+ :comment => 'Maintenance work.',
83
+ :starttime => DateTime.now,
84
+ :endtime => DateTime.now
85
+ }
86
+ }
87
+
88
+ post :update_multiple_downtime, params,
89
+ set_session_user
90
+
91
+ assert_response :found
92
+ assert_redirected_to hosts_path
93
+ assert_nil flash[:error]
94
+ assert_not_nil flash[:notice]
95
+ assert_equal 'A downtime was set for the selected hosts.', flash[:notice]
96
+ end
97
+ end
98
+
99
+ describe 'changing the power state on multiple hosts' do
100
+ before do
101
+ @hosts = FactoryGirl.create_list(:host, 2, :with_monitoring)
102
+ @request.env['HTTP_REFERER'] = hosts_path
103
+
104
+ power_mock = mock('power')
105
+ power_mock.expects(:poweroff).twice
106
+ Host::Managed.any_instance.stubs(:power).returns(power_mock)
107
+ Host::Managed.any_instance.stubs(:supports_power?).returns(true)
108
+ end
109
+
110
+ test 'should set a downtime if selected' do
111
+ Host::Managed.any_instance.expects(:downtime_host).twice.returns(true)
112
+ params = {
113
+ :host_ids => @hosts.map(&:id),
114
+ :power => {
115
+ :action => 'poweroff',
116
+ :set_downtime => true
117
+ }
118
+ }
119
+
120
+ post :update_multiple_power_state, params,
121
+ set_session_user
122
+
123
+ assert_response :found
124
+ assert_redirected_to hosts_path
125
+ assert_nil flash[:error]
126
+ assert_not_nil flash[:notice]
127
+ assert_equal 'The power state of the selected hosts will be set to poweroff', flash[:notice]
128
+ end
129
+
130
+ test 'should not set a downtime if not selected' do
131
+ Host::Managed.any_instance.expects(:downtime_host).never
132
+ params = {
133
+ :host_ids => @hosts.map(&:id),
134
+ :power => {
135
+ :action => 'poweroff',
136
+ :set_downtime => false
137
+ }
138
+ }
139
+
140
+ post :update_multiple_power_state, params,
141
+ set_session_user
142
+
143
+ assert_response :found
144
+ assert_redirected_to hosts_path
145
+ assert_nil flash[:error]
146
+ assert_not_nil flash[:notice]
147
+ assert_equal 'The power state of the selected hosts will be set to poweroff', flash[:notice]
148
+ end
149
+ end
150
+
151
+ describe 'changing the monitoring proxy of multiple hosts' do
152
+ let(:hosts) { FactoryGirl.create_list(:host, 2, :with_monitoring) }
153
+ let(:monitoring_proxy) { FactoryGirl.create(:smart_proxy, :monitoring, :organizations => [hosts.first.organization], :locations => [hosts.first.location]) }
154
+ before do
155
+ @request.env['HTTP_REFERER'] = hosts_path
156
+ end
157
+
158
+ test 'show a host selection' do
159
+ host_ids = hosts.map(&:id)
160
+ xhr :post, :select_multiple_monitoring_proxy, {:host_ids => host_ids}, set_session_user
161
+ assert_response :success
162
+ assert response.body =~ /#{hosts.first.name}.*#{hosts.last.name}/m
163
+ end
164
+
165
+ test 'should change the proxy' do
166
+ hosts.each do |host|
167
+ refute_equal monitoring_proxy, host.monitoring_proxy
168
+ end
169
+
170
+ params = {
171
+ :host_ids => hosts.map(&:id),
172
+ :proxy => { :proxy_id => monitoring_proxy.id }
173
+ }
174
+
175
+ post :update_multiple_monitoring_proxy, params,
176
+ set_session_user
177
+
178
+ assert_response :found
179
+ assert_redirected_to hosts_path
180
+ assert_nil flash[:error]
181
+ assert_equal "The Monitoring proxy of the selected hosts was set to #{monitoring_proxy.name}.", flash[:notice]
182
+
183
+ hosts.each do |host|
184
+ as_admin do
185
+ assert_equal monitoring_proxy, host.reload.monitoring_proxy
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end