foreman_host_reports 0.0.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -447
- data/app/controllers/api/v2/host_reports_controller.rb +39 -20
- data/app/controllers/concerns/foreman_host_reports/controller/hosts_controller_extensions.rb +18 -0
- data/app/controllers/concerns/foreman_host_reports/controller/parameters/host_report.rb +1 -1
- data/app/controllers/host_reports_controller.rb +32 -2
- data/app/helpers/concerns/foreman_host_reports/hosts_helper_extensions.rb +25 -0
- data/app/models/concerns/foreman_host_reports/host_extensions.rb +6 -0
- data/app/models/host_report.rb +15 -0
- data/app/models/host_status/host_report_status.rb +185 -0
- data/app/views/api/v2/host_reports/main.json.rabl +1 -2
- data/config/routes.rb +2 -4
- data/db/migrate/20220113064436_rename_status_summaries.rb +12 -0
- data/lib/foreman_host_reports/engine.rb +11 -5
- data/lib/foreman_host_reports/version.rb +1 -1
- data/test/controllers/api/v2/host_reports_controller_test.rb +30 -67
- data/test/factories/foreman_host_reports_factories.rb +13 -5
- data/test/model/host_report_status_test.rb +204 -0
- data/test/test_plugin_helper.rb +4 -2
- data/webpack/__mocks__/foremanReact/components/Pagination/index.js +2 -0
- data/webpack/fills.js +23 -0
- data/webpack/global_index.js +2 -0
- data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/Formatters/statusFormatter.js +3 -4
- data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/StatusCell.js +1 -1
- data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/HostReportsTable.js +2 -10
- data/webpack/src/Router/HostReports/IndexPage/IndexPage.js +0 -1
- data/webpack/src/Router/HostReports/IndexPage/IndexPageActions.js +5 -4
- data/webpack/src/Router/HostReports/IndexPage/IndexPageHelpers.js +1 -1
- data/webpack/src/Router/HostReports/IndexPage/__tests__/HostReportsIndexPage.test.js +3 -4
- data/webpack/src/Router/HostReports/IndexPage/__tests__/__snapshots__/HostReportsIndexPage.test.js.snap +4 -6
- data/webpack/src/Router/HostReports/IndexPage/constants.js +4 -3
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Ansible.js +62 -27
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Components/EmptyLogsRow.js +27 -0
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Components/RawMsgModal.js +41 -0
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/Puppet.js +38 -37
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogs/index.js +10 -3
- data/webpack/src/Router/HostReports/ShowPage/Components/ReportLogsFilter/index.js +56 -65
- data/webpack/src/Router/HostReports/ShowPage/ShowPage.js +34 -8
- data/webpack/src/Router/HostReports/constants.js +2 -0
- data/webpack/src/components/ReportsTab/ReportsTable.js +117 -0
- data/webpack/src/components/ReportsTab/helpers.js +155 -0
- data/webpack/src/components/ReportsTab/index.js +132 -0
- metadata +18 -19
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -4
@@ -1,20 +1,22 @@
|
|
1
1
|
require 'test_plugin_helper'
|
2
2
|
|
3
3
|
class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
4
|
+
let :host_report do
|
5
|
+
as_admin do
|
6
|
+
FactoryBot.create(:host_report)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
let :report_body do
|
10
|
+
read_report('foreman-web.json', URI.parse(host_report.proxy.url).host)
|
11
|
+
end
|
4
12
|
setup do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
Resolv.any_instance.stubs(:getnames).returns([URI.parse(@proxy.url).host])
|
9
|
-
SmartProxy.any_instance.stubs(:with_features).returns([@proxy])
|
13
|
+
Resolv.any_instance.stubs(:getnames).returns([URI.parse(host_report.proxy.url).host])
|
14
|
+
SmartProxy.any_instance.stubs(:with_features).returns([host_report.proxy])
|
15
|
+
SmartProxy.any_instance.stubs(:find_by).returns([host_report.proxy])
|
10
16
|
ProxyAPI::V2::Features.any_instance.stubs(:features).returns({ "reports" => { "state" => "running" } })
|
11
17
|
end
|
12
18
|
|
13
19
|
context 'when user does not have permission to view hosts' do
|
14
|
-
let :host_report do
|
15
|
-
as_admin { FactoryBot.create(:host_report) }
|
16
|
-
end
|
17
|
-
|
18
20
|
setup { setup_user('view', 'host_reports') }
|
19
21
|
|
20
22
|
test 'cannot view any reports' do
|
@@ -34,10 +36,6 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
34
36
|
User.current = users(:one) # use an unprivileged user, not apiadmin
|
35
37
|
end
|
36
38
|
|
37
|
-
def report_body
|
38
|
-
@report_body ||= read_report('foreman-web.json')
|
39
|
-
end
|
40
|
-
|
41
39
|
let :host do
|
42
40
|
as_admin { FactoryBot.create(:host) }
|
43
41
|
end
|
@@ -47,7 +45,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
47
45
|
post :create, params: {
|
48
46
|
host_report: {
|
49
47
|
host: host.name, body: report_body, reported_at: Time.current,
|
50
|
-
|
48
|
+
change: 1, nochange: 2, failure: 3
|
51
49
|
},
|
52
50
|
}, session: set_session_user
|
53
51
|
assert_response :success
|
@@ -65,15 +63,14 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
65
63
|
host_report: {
|
66
64
|
host: host.name, body: report_body, reported_at: Time.current,
|
67
65
|
keywords: %w[HasError HasFailedResource],
|
68
|
-
|
66
|
+
change: 1, nochange: 2, failure: 3
|
69
67
|
},
|
70
68
|
}, session: set_session_user
|
71
69
|
report = ActiveSupport::JSON.decode(@response.body)
|
72
70
|
assert_response :created
|
73
|
-
assert_equal
|
74
|
-
assert_equal
|
75
|
-
assert_equal
|
76
|
-
assert_equal 6, report['other']
|
71
|
+
assert_equal 1, report['change']
|
72
|
+
assert_equal 2, report['nochange']
|
73
|
+
assert_equal 3, report['failure']
|
77
74
|
end
|
78
75
|
|
79
76
|
test 'assign keywords' do
|
@@ -82,7 +79,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
82
79
|
host_report: {
|
83
80
|
host: host.name, body: report_body, reported_at: Time.current,
|
84
81
|
keywords: %w[HasError HasFailedResource],
|
85
|
-
|
82
|
+
change: 1, nochange: 2, failure: 3
|
86
83
|
},
|
87
84
|
}, session: set_session_user
|
88
85
|
report = ActiveSupport::JSON.decode(@response.body)
|
@@ -97,7 +94,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
97
94
|
host_report: {
|
98
95
|
host: host.name, body: report_body, reported_at: Time.current,
|
99
96
|
keywords: %w[HasError HasFailedResource],
|
100
|
-
|
97
|
+
change: 1, nochange: 2, failure: 3
|
101
98
|
},
|
102
99
|
}, session: set_session_user
|
103
100
|
|
@@ -105,7 +102,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
105
102
|
host_report: {
|
106
103
|
host: host.name, body: report_body, reported_at: Time.current,
|
107
104
|
keywords: %w[HasError HasFailedResource],
|
108
|
-
|
105
|
+
change: 1, nochange: 2, failure: 3
|
109
106
|
},
|
110
107
|
}, session: set_session_user
|
111
108
|
end
|
@@ -119,52 +116,23 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
119
116
|
post :create, params: {
|
120
117
|
host_report: {
|
121
118
|
host: host.name, body: report_body, reported_at: Time.current,
|
122
|
-
|
119
|
+
change: 1, nochange: 2, failure: 3
|
123
120
|
},
|
124
121
|
}
|
125
122
|
assert_nil @controller.detected_proxy
|
126
123
|
assert_response :created
|
127
124
|
end
|
128
125
|
|
129
|
-
test 'hosts with a registered smart proxy on should create a report successfully' do
|
130
|
-
Setting[:restrict_registered_smart_proxies] = true
|
131
|
-
Setting[:require_ssl_smart_proxies] = false
|
132
|
-
|
133
|
-
post :create, params: {
|
134
|
-
host_report: {
|
135
|
-
host: host.name, body: report_body, reported_at: Time.current,
|
136
|
-
applied: 5, failed: 1, pending: 1, other: 0
|
137
|
-
},
|
138
|
-
}
|
139
|
-
assert_equal @proxy, @controller.detected_proxy
|
140
|
-
assert_response :created
|
141
|
-
end
|
142
|
-
|
143
|
-
test 'hosts without a registered smart proxy on should not be able to create a report' do
|
144
|
-
Setting[:restrict_registered_smart_proxies] = true
|
145
|
-
Setting[:require_ssl_smart_proxies] = false
|
146
|
-
|
147
|
-
Resolv.any_instance.stubs(:getnames).returns(['another.host'])
|
148
|
-
post :create, params: {
|
149
|
-
host_report: {
|
150
|
-
host: host.name, body: report_body, reported_at: Time.current,
|
151
|
-
applied: 5, failed: 1, pending: 1, other: 0
|
152
|
-
},
|
153
|
-
}
|
154
|
-
assert_response :forbidden
|
155
|
-
end
|
156
|
-
|
157
126
|
test 'hosts with a registered smart proxy and SSL cert should create a report successfully' do
|
158
127
|
Setting[:restrict_registered_smart_proxies] = true
|
159
|
-
Setting[:require_ssl_smart_proxies] = true
|
160
128
|
|
161
129
|
@request.env['HTTPS'] = 'on'
|
162
|
-
@request.env['SSL_CLIENT_S_DN'] =
|
130
|
+
@request.env['SSL_CLIENT_S_DN'] = "CN=#{URI.parse(host_report.proxy.url).host}"
|
163
131
|
@request.env['SSL_CLIENT_VERIFY'] = 'SUCCESS'
|
164
132
|
post :create, params: {
|
165
133
|
host_report: {
|
166
134
|
host: host.name, body: report_body, reported_at: Time.current,
|
167
|
-
|
135
|
+
change: 1, nochange: 2, failure: 3
|
168
136
|
},
|
169
137
|
}
|
170
138
|
assert_response :created
|
@@ -172,15 +140,14 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
172
140
|
|
173
141
|
test 'hosts without a registered smart proxy but with an SSL cert should not be able to create a report' do
|
174
142
|
Setting[:restrict_registered_smart_proxies] = true
|
175
|
-
Setting[:require_ssl_smart_proxies] = true
|
176
143
|
|
177
144
|
@request.env['HTTPS'] = 'on'
|
178
|
-
@request.env['SSL_CLIENT_S_DN'] =
|
145
|
+
@request.env['SSL_CLIENT_S_DN'] = "CN=else.where"
|
179
146
|
@request.env['SSL_CLIENT_VERIFY'] = 'SUCCESS'
|
180
147
|
post :create, params: {
|
181
148
|
host_report: {
|
182
149
|
host: host.name, body: report_body, reported_at: Time.current,
|
183
|
-
|
150
|
+
change: 1, nochange: 2, failure: 3
|
184
151
|
},
|
185
152
|
}
|
186
153
|
assert_response :forbidden
|
@@ -188,7 +155,6 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
188
155
|
|
189
156
|
test 'hosts with an unverified SSL cert should not be able to create a report' do
|
190
157
|
Setting[:restrict_registered_smart_proxies] = true
|
191
|
-
Setting[:require_ssl_smart_proxies] = true
|
192
158
|
|
193
159
|
@request.env['HTTPS'] = 'on'
|
194
160
|
@request.env['SSL_CLIENT_S_DN'] = 'CN=else.where'
|
@@ -196,37 +162,34 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
196
162
|
post :create, params: {
|
197
163
|
host_report: {
|
198
164
|
host: host.name, body: report_body, reported_at: Time.current,
|
199
|
-
|
165
|
+
change: 1, nochange: 2, failure: 3
|
200
166
|
},
|
201
167
|
}
|
202
168
|
assert_response :forbidden
|
203
169
|
end
|
204
170
|
|
205
|
-
test 'when "
|
171
|
+
test 'when "require_ssl" is true, HTTP requests should not be able to create a report' do
|
206
172
|
Setting[:restrict_registered_smart_proxies] = true
|
207
|
-
Setting[:require_ssl_smart_proxies] = true
|
208
173
|
SETTINGS[:require_ssl] = true
|
209
174
|
|
210
175
|
Resolv.any_instance.stubs(:getnames).returns(['else.where'])
|
211
176
|
post :create, params: {
|
212
177
|
host_report: {
|
213
178
|
host: host.name, body: report_body, reported_at: Time.current,
|
214
|
-
|
179
|
+
change: 1, nochange: 2, failure: 3
|
215
180
|
},
|
216
181
|
}
|
217
|
-
assert_response :
|
182
|
+
assert_response :redirect
|
218
183
|
end
|
219
184
|
|
220
|
-
test 'when "
|
221
|
-
# since require_ssl_smart_proxies is only applicable to HTTPS connections, both should be set
|
185
|
+
test 'when "require_ssl" is false, HTTP requests should be able to create reports' do
|
222
186
|
Setting[:restrict_registered_smart_proxies] = true
|
223
|
-
Setting[:require_ssl_smart_proxies] = true
|
224
187
|
SETTINGS[:require_ssl] = false
|
225
188
|
|
226
189
|
post :create, params: {
|
227
190
|
host_report: {
|
228
191
|
host: host.name, body: report_body, reported_at: Time.current,
|
229
|
-
|
192
|
+
change: 1, nochange: 2, failure: 3
|
230
193
|
},
|
231
194
|
}
|
232
195
|
assert_response :created
|
@@ -1,12 +1,20 @@
|
|
1
1
|
FactoryBot.define do
|
2
2
|
factory :host_report do
|
3
3
|
host
|
4
|
+
sequence(:proxy) { |n| FactoryBot.create(:smart_proxy, url: "http://proxy#{n}.example.com", features: [FactoryBot.create(:feature, name: 'Reports')]) }
|
4
5
|
reported_at { Time.now.utc }
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
change { 0 }
|
7
|
+
nochange { 0 }
|
8
|
+
failure { 0 }
|
9
|
+
body { '{}' }
|
10
|
+
end
|
11
|
+
|
12
|
+
trait :puppet_format do
|
13
|
+
format { 'puppet' }
|
14
|
+
end
|
15
|
+
|
16
|
+
trait :ansible_format do
|
17
|
+
format { 'ansible' }
|
10
18
|
end
|
11
19
|
|
12
20
|
trait :with_keyword do
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class HostReportStatusTest < ActiveSupport::TestCase
|
4
|
+
let(:report) { FactoryBot.create(:host_report) }
|
5
|
+
let(:host) { report.host }
|
6
|
+
let(:status) { HostStatus::HostReportStatus.new(host: host).tap(&:refresh) }
|
7
|
+
|
8
|
+
test 'is valid' do
|
9
|
+
assert_valid status
|
10
|
+
end
|
11
|
+
|
12
|
+
test 'last_report defaults to hosts last if nothing was set yet' do
|
13
|
+
assert_equal report, status.last_report
|
14
|
+
end
|
15
|
+
|
16
|
+
test '#last_report returns custom value that was set using writer method' do
|
17
|
+
status.last_report = :something
|
18
|
+
assert_equal :something, status.last_report
|
19
|
+
end
|
20
|
+
|
21
|
+
test '#last_report returns custom value that was set using writer method even for nil' do
|
22
|
+
status.last_report = nil
|
23
|
+
assert_nil status.last_report
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "host with no reports" do
|
27
|
+
let(:host) { FactoryBot.create(:host) }
|
28
|
+
|
29
|
+
test '#no_reports? results in warning only if puppet reports are expected' do
|
30
|
+
refute host.last_report
|
31
|
+
|
32
|
+
status.stubs(:error? => false)
|
33
|
+
status.stubs(:out_of_sync? => false)
|
34
|
+
status.stubs(:no_reports? => true)
|
35
|
+
assert_equal HostStatus::Global::OK, status.to_global
|
36
|
+
|
37
|
+
host.expects(:configuration? => true)
|
38
|
+
assert_equal HostStatus::Global::WARN, status.to_global
|
39
|
+
|
40
|
+
host.expects(:configuration? => false)
|
41
|
+
Setting[:always_show_configuration_status] = true
|
42
|
+
assert_equal HostStatus::Global::WARN, status.to_global
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
test 'status is disabled when reporting is disabled' do
|
47
|
+
host.enabled = false
|
48
|
+
assert_equal HostStatus::HostReportStatus::UNKNOWN, status.refresh
|
49
|
+
end
|
50
|
+
|
51
|
+
test '#out_of_sync? is false when reported_at is unknown' do
|
52
|
+
status.reported_at = nil
|
53
|
+
refute status.out_of_sync?
|
54
|
+
end
|
55
|
+
|
56
|
+
test '#out_of_sync? is false when window is big enough' do
|
57
|
+
original = Setting[:outofsync_interval]
|
58
|
+
Setting[:outofsync_interval] = (Time.now.utc - report.reported_at).to_i / 60 + 1
|
59
|
+
refute status.out_of_sync?
|
60
|
+
Setting[:outofsync_interval] = original
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#out_of_sync?' do
|
64
|
+
let(:report) { FactoryBot.create(:host_report, reported_at: Time.now.utc - 1.year) }
|
65
|
+
|
66
|
+
test '#out_of_sync? is false when out of sync is disabled' do
|
67
|
+
status.stubs(:out_of_sync_disabled?).returns(true)
|
68
|
+
refute status.out_of_sync?
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with last report format' do
|
72
|
+
setup do
|
73
|
+
status.last_report.stubs(:format).returns('Test')
|
74
|
+
end
|
75
|
+
|
76
|
+
test 'is false when formats out of sync is disabled' do
|
77
|
+
stub_outofsync_setting(true)
|
78
|
+
refute status.out_of_sync?
|
79
|
+
end
|
80
|
+
|
81
|
+
test "is true when formats out of sync isn't disbled and it is ouf of sync" do
|
82
|
+
stub_outofsync_setting(false)
|
83
|
+
status.reported_at = '2015-01-01 00:00:00'
|
84
|
+
status.save
|
85
|
+
assert status.out_of_sync?
|
86
|
+
end
|
87
|
+
|
88
|
+
def stub_outofsync_setting(value)
|
89
|
+
Foreman.settings._add('test_out_of_sync_disabled',
|
90
|
+
context: :test,
|
91
|
+
type: :boolean,
|
92
|
+
category: 'Setting',
|
93
|
+
full_name: 'Test out of sync',
|
94
|
+
description: 'description',
|
95
|
+
default: false)
|
96
|
+
Setting[:test_out_of_sync_disabled] = value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
test '#refresh! refreshes the date and persists the record' do
|
102
|
+
status.expects(:refresh)
|
103
|
+
status.refresh!
|
104
|
+
|
105
|
+
assert status.persisted?
|
106
|
+
end
|
107
|
+
|
108
|
+
test '#refresh updates date to reported_at of last report' do
|
109
|
+
status.reported_at = nil
|
110
|
+
status.refresh
|
111
|
+
|
112
|
+
assert_equal report&.reported_at&.to_i, status&.reported_at&.to_i
|
113
|
+
end
|
114
|
+
|
115
|
+
test '#relevant? only for hosts with #configuration? true, or a last report, or setting enabled' do
|
116
|
+
host.expects(:configuration?).returns(true)
|
117
|
+
assert status.relevant?
|
118
|
+
|
119
|
+
host.expects(:configuration?).returns(false)
|
120
|
+
status.expects(:last_report).returns(mock)
|
121
|
+
assert status.relevant?
|
122
|
+
|
123
|
+
host.expects(:configuration?).returns(false)
|
124
|
+
status.expects(:last_report).returns(nil)
|
125
|
+
refute status.relevant?
|
126
|
+
|
127
|
+
host.expects(:configuration?).returns(false)
|
128
|
+
status.expects(:last_report).returns(nil)
|
129
|
+
Setting[:always_show_configuration_status] = true
|
130
|
+
assert status.relevant?
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "host with puppet report" do
|
134
|
+
let(:report) { FactoryBot.create(:host_report, :puppet_format) }
|
135
|
+
|
136
|
+
test 'overwrite puppet_interval as host parameter' do
|
137
|
+
if defined? ForemanPuppet
|
138
|
+
Setting['puppet_interval'] = 25
|
139
|
+
end
|
140
|
+
Setting['outofsync_interval'] = 25
|
141
|
+
status.reported_at = Time.now.utc - 30.minutes
|
142
|
+
assert status.out_of_sync?
|
143
|
+
host.params['puppet_interval'] = 35
|
144
|
+
refute status.out_of_sync?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "host with applied changes" do
|
149
|
+
let(:report) { FactoryBot.create(:host_report, nochange: 0, change: 10, failure: 0) }
|
150
|
+
|
151
|
+
test 'is found via host scoped search' do
|
152
|
+
status.save
|
153
|
+
assert_equal [host], Host.search_for('report_changes > 0')
|
154
|
+
assert_empty Host.search_for('report_changes < 0')
|
155
|
+
assert_empty Host.search_for('report_changes = 0')
|
156
|
+
end
|
157
|
+
|
158
|
+
test 'is found via host report scoped search' do
|
159
|
+
status.save
|
160
|
+
assert_equal [report], HostReport.search_for('changes > 0')
|
161
|
+
assert_equal [report], HostReport.search_for('changed > 0')
|
162
|
+
assert_empty HostReport.search_for('changes < 0')
|
163
|
+
assert_empty HostReport.search_for('changed = 0')
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "host with failures" do
|
168
|
+
let(:report) { FactoryBot.create(:host_report, nochange: 0, change: 0, failure: 10) }
|
169
|
+
|
170
|
+
test 'is found via host scoped search' do
|
171
|
+
status.save
|
172
|
+
assert_equal [host], Host.search_for('report_failures > 0')
|
173
|
+
assert_empty Host.search_for('report_failures < 0')
|
174
|
+
assert_empty Host.search_for('report_failures = 0')
|
175
|
+
end
|
176
|
+
|
177
|
+
test 'is found via host report scoped search' do
|
178
|
+
status.save
|
179
|
+
assert_equal [report], HostReport.search_for('failures > 0')
|
180
|
+
assert_equal [report], HostReport.search_for('failed > 0')
|
181
|
+
assert_empty HostReport.search_for('failures < 0')
|
182
|
+
assert_empty HostReport.search_for('failed = 0')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "host with no changes" do
|
187
|
+
let(:report) { FactoryBot.create(:host_report, nochange: 10, change: 0, failure: 0) }
|
188
|
+
|
189
|
+
test 'is found via host scoped search' do
|
190
|
+
status.save
|
191
|
+
assert_equal [host], Host.search_for('report_nochanges > 0')
|
192
|
+
assert_empty Host.search_for('report_nochanges < 0')
|
193
|
+
assert_empty Host.search_for('report_nochanges = 0')
|
194
|
+
end
|
195
|
+
|
196
|
+
test 'is found via host report scoped search' do
|
197
|
+
status.save
|
198
|
+
assert_equal [report], HostReport.search_for('unchanged > 0')
|
199
|
+
assert_equal [report], HostReport.search_for('nochanges > 0')
|
200
|
+
assert_empty HostReport.search_for('unchanged < 0')
|
201
|
+
assert_empty HostReport.search_for('nochanges = 0')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
data/test/test_plugin_helper.rb
CHANGED
@@ -5,7 +5,9 @@ require 'test_helper'
|
|
5
5
|
FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
|
6
6
|
FactoryBot.reload
|
7
7
|
|
8
|
-
def read_report(file)
|
8
|
+
def read_report(file, override_proxy = "localhost")
|
9
9
|
json = File.expand_path(File.join('..', 'snapshots', file), __FILE__)
|
10
|
-
File.read(json)
|
10
|
+
json = JSON.parse(File.read(json))
|
11
|
+
json["proxy"] = override_proxy
|
12
|
+
json.to_s
|
11
13
|
end
|
data/webpack/fills.js
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
|
3
|
+
import ReportsTab from './src/components/ReportsTab';
|
4
|
+
|
5
|
+
const fills = [
|
6
|
+
{
|
7
|
+
slot: 'host-details-page-tabs',
|
8
|
+
name: 'Reports',
|
9
|
+
component: props => <ReportsTab {...props} />,
|
10
|
+
weight: 450,
|
11
|
+
},
|
12
|
+
];
|
13
|
+
|
14
|
+
export const registerFills = () => {
|
15
|
+
fills.forEach(({ slot, name, component: Component, weight }, index) =>
|
16
|
+
addGlobalFill(
|
17
|
+
slot,
|
18
|
+
name,
|
19
|
+
<Component key={`host-reports-fill-${index}`} />,
|
20
|
+
weight
|
21
|
+
)
|
22
|
+
);
|
23
|
+
};
|
data/webpack/global_index.js
CHANGED
@@ -4,10 +4,9 @@ import StatusCell from '../StatusCell';
|
|
4
4
|
|
5
5
|
const statusFormatter = () => (_, { rowData }) => {
|
6
6
|
const statuses = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
other: rowData.other,
|
7
|
+
change: rowData.change,
|
8
|
+
nochange: rowData.nochange,
|
9
|
+
failure: rowData.failure,
|
11
10
|
};
|
12
11
|
return <StatusCell statuses={statuses} />;
|
13
12
|
};
|
data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/HostReportsTable.js
CHANGED
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
|
4
4
|
import { Table } from 'foremanReact/components/common/table';
|
5
|
-
import Pagination from 'foremanReact/components/Pagination
|
5
|
+
import Pagination from 'foremanReact/components/Pagination';
|
6
6
|
import DefaultEmptyState from 'foremanReact/components/common/EmptyState';
|
7
7
|
import { translate as __ } from 'foremanReact/common/I18n';
|
8
8
|
|
@@ -18,7 +18,6 @@ const HostReportsTable = ({
|
|
18
18
|
pagination,
|
19
19
|
toDelete,
|
20
20
|
onDeleteClick,
|
21
|
-
reloadWithSearch,
|
22
21
|
hostId,
|
23
22
|
}) => {
|
24
23
|
const onDeleteSuccess = () => {
|
@@ -54,13 +53,7 @@ const HostReportsTable = ({
|
|
54
53
|
<React.Fragment>
|
55
54
|
<HostReportDeleteModal toDelete={toDelete} onSuccess={onDeleteSuccess} />
|
56
55
|
{body}
|
57
|
-
<Pagination
|
58
|
-
viewType="list"
|
59
|
-
itemCount={itemCount}
|
60
|
-
pagination={pagination}
|
61
|
-
onChange={fetchAndPush}
|
62
|
-
dropdownButtonId="host-reports-page-pagination-dropdown"
|
63
|
-
/>
|
56
|
+
<Pagination itemCount={itemCount} onChange={fetchAndPush} />
|
64
57
|
</React.Fragment>
|
65
58
|
);
|
66
59
|
};
|
@@ -73,7 +66,6 @@ HostReportsTable.propTypes = {
|
|
73
66
|
sort: PropTypes.object,
|
74
67
|
pagination: PropTypes.object.isRequired,
|
75
68
|
toDelete: PropTypes.object.isRequired,
|
76
|
-
reloadWithSearch: PropTypes.func.isRequired,
|
77
69
|
hostId: PropTypes.string,
|
78
70
|
};
|
79
71
|
|
@@ -11,7 +11,7 @@ import {
|
|
11
11
|
|
12
12
|
export const initializeHostReports = () => dispatch => {
|
13
13
|
const params = getParams();
|
14
|
-
dispatch(fetchHostReports(params));
|
14
|
+
dispatch(fetchHostReports({ per_page: params.perPage, ...params }));
|
15
15
|
if (!history.action === 'POP') {
|
16
16
|
history.replace({
|
17
17
|
pathname: HOST_REPORTS_PATH,
|
@@ -21,7 +21,8 @@ export const initializeHostReports = () => dispatch => {
|
|
21
21
|
};
|
22
22
|
|
23
23
|
export const fetchHostReports = (
|
24
|
-
|
24
|
+
/* eslint-disable-next-line camelcase */
|
25
|
+
{ page, per_page, searchQuery, sort },
|
25
26
|
url = HOST_REPORTS_API_PATH
|
26
27
|
) => async dispatch => {
|
27
28
|
const sortString =
|
@@ -33,7 +34,7 @@ export const fetchHostReports = (
|
|
33
34
|
url,
|
34
35
|
params: {
|
35
36
|
page,
|
36
|
-
per_page
|
37
|
+
per_page,
|
37
38
|
search: searchQuery,
|
38
39
|
order: sortString,
|
39
40
|
},
|
@@ -46,7 +47,7 @@ export const fetchAndPush = (params = {}) => (dispatch, getState) => {
|
|
46
47
|
dispatch(fetchHostReports(query));
|
47
48
|
history.push({
|
48
49
|
pathname: HOST_REPORTS_PATH,
|
49
|
-
search: stringifyParams(query),
|
50
|
+
search: stringifyParams({ perPage: query.per_page, ...query }),
|
50
51
|
});
|
51
52
|
};
|
52
53
|
|
@@ -18,7 +18,7 @@ export const buildQuery = (query, state) => {
|
|
18
18
|
|
19
19
|
return {
|
20
20
|
page: query.page || selectPage(state),
|
21
|
-
|
21
|
+
per_page: query.per_page || selectPerPage(state),
|
22
22
|
searchQuery:
|
23
23
|
query.searchQuery === undefined ? selectSearch(state) : query.searchQuery,
|
24
24
|
...(querySort && { sort: querySort }),
|
@@ -11,7 +11,7 @@ exports[`HostReportsIndexPage redering render with minimal props 1`] = `
|
|
11
11
|
"autocomplete": Object {
|
12
12
|
"id": "searchBar",
|
13
13
|
"searchQuery": "",
|
14
|
-
"url": "host_reports/auto_complete_search",
|
14
|
+
"url": "/host_reports/auto_complete_search",
|
15
15
|
"useKeyShortcuts": true,
|
16
16
|
},
|
17
17
|
"bookmarks": Object {
|
@@ -41,18 +41,16 @@ exports[`HostReportsIndexPage redering render with minimal props 1`] = `
|
|
41
41
|
"perPage": 20,
|
42
42
|
}
|
43
43
|
}
|
44
|
-
reloadWithSearch={[MockFunction]}
|
45
44
|
results={
|
46
45
|
Array [
|
47
46
|
Object {
|
48
|
-
"
|
49
|
-
"
|
47
|
+
"change": 0,
|
48
|
+
"failure": 0,
|
50
49
|
"format": "plain",
|
51
50
|
"hostId": "1",
|
52
51
|
"hostName": "foreman.example.com",
|
53
52
|
"id": "1",
|
54
|
-
"
|
55
|
-
"pending": 0,
|
53
|
+
"nochange": 0,
|
56
54
|
"proxyId": "1",
|
57
55
|
"proxyName": "foreman.example.com",
|
58
56
|
"reportedAt": "2021-01-19T12:34:02.841645028Z",
|