foreman_host_reports 0.0.4 → 1.0.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.
- 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",
|