foreman_leapp 0.0.6 → 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.
- checksums.yaml +4 -4
- data/README.md +11 -20
- data/app/controllers/api/v2/concerns/api_authorizer.rb +27 -0
- data/app/controllers/api/v2/preupgrade_reports_controller.rb +21 -2
- data/app/controllers/preupgrade_reports_controller.rb +11 -1
- data/app/lib/actions/preupgrade_job.rb +2 -1
- data/app/models/preupgrade_report.rb +1 -0
- data/app/models/preupgrade_report_entry.rb +1 -0
- data/app/views/api/v2/preupgrade_report_entries/base.json.rabl +1 -1
- data/app/views/api/v2/preupgrade_reports/job_invocation.json.rabl +3 -0
- data/app/views/foreman_leapp/job_templates/check.erb +14 -0
- data/app/views/foreman_leapp/job_templates/preupgrade.erb +3 -1
- data/app/views/foreman_leapp/job_templates/remediation.erb +11 -0
- data/app/views/foreman_leapp/job_templates/upgrade.erb +6 -5
- data/config/routes.rb +2 -1
- data/db/migrate/20200429080939_report_entries_flags.rb +5 -0
- data/lib/foreman_leapp/engine.rb +4 -1
- data/lib/foreman_leapp/version.rb +1 -1
- data/package.json +3 -2
- data/test/functional/api/v2/preupgrade_reports_controller_test.rb +89 -6
- data/test/functional/preupgrade_reports_controller_test.rb +27 -4
- data/webpack/__mocks__/foremanReact/common/I18n.js +1 -1
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +1 -0
- data/webpack/components/PreupgradeReports/PreupgradeReports.js +104 -21
- data/webpack/components/PreupgradeReports/PreupgradeReportsActions.js +1 -1
- data/webpack/components/PreupgradeReports/PreupgradeReportsHelpers.js +132 -15
- data/webpack/components/PreupgradeReports/PreupgradeReportsReducer.js +2 -0
- data/webpack/components/PreupgradeReports/PreupgradeReportsSelectors.js +10 -0
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.fixtures.js +45 -7
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.test.js +17 -1
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsHelpers.test.js +43 -3
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReports.test.js.snap +82 -134
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsHelpers.test.js.snap +409 -2
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsReducer.test.js.snap +21 -1
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsSelectors.test.js.snap +17 -1
- data/webpack/components/PreupgradeReports/components/EntriesFilter.js +121 -0
- data/webpack/components/PreupgradeReports/components/EntriesFilter.scss +3 -0
- data/webpack/components/PreupgradeReports/components/EntriesFilter.test.js +30 -0
- data/webpack/components/PreupgradeReports/components/{FixAllButton.js → FixSelectedButton.js} +6 -8
- data/webpack/components/PreupgradeReports/components/FixSelectedButton.test.js +15 -0
- data/webpack/components/PreupgradeReports/components/NoReports.js +35 -0
- data/webpack/components/PreupgradeReports/components/NoReports.test.js +15 -0
- data/webpack/components/PreupgradeReports/components/UpgradeAllButton.js +29 -0
- data/webpack/components/PreupgradeReports/components/{FixAllButton.test.js → UpgradeAllButton.test.js} +3 -4
- data/webpack/components/PreupgradeReports/components/__snapshots__/EntriesFilter.test.js.snap +330 -0
- data/webpack/components/PreupgradeReports/components/__snapshots__/{FixAllButton.test.js.snap → FixSelectedButton.test.js.snap} +9 -3
- data/webpack/components/PreupgradeReports/components/__snapshots__/NoReports.test.js.snap +19 -0
- data/webpack/components/PreupgradeReports/components/__snapshots__/UpgradeAllButton.test.js.snap +29 -0
- data/webpack/components/PreupgradeReports/index.js +22 -4
- data/webpack/components/PreupgradeReportsList/PreupgradeReportList.scss +37 -0
- data/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js +16 -0
- data/webpack/components/PreupgradeReportsList/__tests__/__snapshots__/PreupgradeReportsList.test.js.snap +38 -0
- data/webpack/components/PreupgradeReportsList/components/InfoItem.js +1 -1
- data/webpack/components/PreupgradeReportsList/components/InhibitorInfoItem.js +33 -0
- data/webpack/components/PreupgradeReportsList/components/PreupgradeReportEntry.js +19 -9
- data/webpack/components/PreupgradeReportsList/components/PreupgradeReportsListHeader.js +56 -0
- data/webpack/components/PreupgradeReportsList/components/SortableHeaderItem.js +50 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/InhibitorInfoItem.test.js +27 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.test.js +2 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportsListHeader.test.js +14 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/SortableHeaderItem.test.js +29 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/InhibitorInfoItem.test.js.snap +32 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportEntry.test.js.snap +23 -17
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportsListHeader.test.js.snap +113 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/SortableHeaderItem.test.js.snap +36 -0
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/helpers.test.js.snap +4 -10
- data/webpack/components/PreupgradeReportsList/components/__tests__/helpers.test.js +0 -2
- data/webpack/components/PreupgradeReportsList/components/foreman_leapp.scss +7 -1
- data/webpack/components/PreupgradeReportsList/components/helpers.js +47 -19
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-critical.svg +61 -0
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-high.svg +61 -0
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-low.svg +62 -0
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-med.svg +62 -0
- data/webpack/components/PreupgradeReportsList/index.js +28 -3
- metadata +34 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 133a054cb6f2f0aab562ef7c0e5863e844ede2a3124a738594c03033a06225d6
|
|
4
|
+
data.tar.gz: ed23743e31e2a42dcf9c5ddaebae7b2ebe38ac8c46cff49cdd4856df07091fc2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca1b768b4c623e9b1d679b0bb67b8bdc882ba74041bf386b81bbb647c186669564fd155f3a1ab8d8df1ff7141535efc044d843c6cd81ae08beba1bf550ad1738
|
|
7
|
+
data.tar.gz: fe21fa9458002c0ae272d6b2738a8abf758b8434a8aad5c31fbf04e3da79ac230a2ab91a6b37a3d3041560f67c249012ec0a035ee2b0d28320fd53e1de45d752
|
data/README.md
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
# ForemanLeapp
|
|
2
2
|
|
|
3
|
-
This plugin allows to run inplace upgrades for
|
|
4
|
-
For more information about
|
|
5
|
-
[developer docs](https://leapp.readthedocs.io/en/latest/).
|
|
3
|
+
This plugin allows to run inplace upgrades for RHEL 7 hosts in Foreman using Leapp tool.
|
|
4
|
+
For more information about Leapp tool check [github](https://github.com/oamg/leapp) or [developer docs](https://leapp.readthedocs.io/en/latest/).
|
|
6
5
|
|
|
7
6
|
## Installation
|
|
8
7
|
|
|
9
|
-
See [
|
|
10
|
-
for how to install Foreman plugins
|
|
8
|
+
See [Plugins Manual](https://www.theforeman.org/plugins/#2.Installation) for how to install Foreman plugins.
|
|
11
9
|
|
|
12
10
|
## Usage
|
|
13
11
|
|
|
14
|
-
The plugin will add
|
|
15
|
-
|
|
12
|
+
The plugin will add following jobs:
|
|
13
|
+
- Run preupgrade via Leapp
|
|
14
|
+
- Remediation plan
|
|
15
|
+
- Run upgrade via Leapp
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- to fetch a specific preupgrade report - GET http://FOREMAN_URL:FOREMAN_PORT/api/v2/preupgrade_reports/REPORT_ID.
|
|
22
|
-
- to fetch all reports for specific job invocation - GET http://FOREMAN_URL:FOREMAN_PORT/api/v2/aggregation/JOB_INVOCATION_ID.
|
|
23
|
-
- to fetch last preupgrade report per host - GET http://FOREMAN_URL:FOREMAN_PORT/api/v2/preupgrade_reports/hosts/HOST_NAME_OR_ID/last.
|
|
24
|
-
|
|
25
|
-
## TODO
|
|
26
|
-
|
|
27
|
-
- Unit tests
|
|
28
|
-
- Automate rubocop checks
|
|
29
|
-
- Frontend (either from scratch or adapt the react/patternfly/typescript one for cockpit upgrades)
|
|
17
|
+
## Api
|
|
18
|
+
- `GET /api/preupgrade_reports` List Preupgrade reports
|
|
19
|
+
- `GET /api/preupgrade_reports/:id` Show Preupgrade report
|
|
20
|
+
- `GET /api/job_invocations/:id/preupgrade_reports` List Preupgrade reports for Job invocation
|
|
30
21
|
|
|
31
22
|
## Contributing
|
|
32
23
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ApiAuthorizer
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
before_action :hosts_permission
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def hosts_permission
|
|
13
|
+
return if User.current.can?('view_hosts')
|
|
14
|
+
|
|
15
|
+
render_error 'access_denied', status: :forbidden,
|
|
16
|
+
locals: { details: _('Missing one of the required permissions: view_hosts'),
|
|
17
|
+
missing_permissions: 'view_hosts' }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def resource_scope(_options = {})
|
|
21
|
+
@resource_scope ||= begin
|
|
22
|
+
scope = PreupgradeReport.joins(:host).merge(Host.authorized(:view_hosts, Host))
|
|
23
|
+
scope = scope.where(job_invocation_id: params[:id]) if action_name == 'job_invocation'
|
|
24
|
+
scope
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
module Api
|
|
4
4
|
module V2
|
|
5
5
|
class PreupgradeReportsController < ::Api::V2::BaseController
|
|
6
|
-
|
|
6
|
+
include ApiAuthorizer
|
|
7
|
+
|
|
8
|
+
layout 'api/v2/layouts/index_layout', except: %i[show]
|
|
7
9
|
|
|
8
10
|
api :GET, '/preupgrade_reports/', N_('List Preupgrade reports')
|
|
9
11
|
param_group :search_and_pagination, ::Api::V2::BaseController
|
|
@@ -13,7 +15,24 @@ module Api
|
|
|
13
15
|
|
|
14
16
|
api :GET, '/preupgrade_reports/:id', N_('Show Preupgrade report')
|
|
15
17
|
param :id, :identifier, required: true
|
|
16
|
-
def show
|
|
18
|
+
def show
|
|
19
|
+
@preupgrade_report = resource_scope.find(params[:id])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
api :GET, '/job_invocations/:id/preupgrade_reports', N_('List Preupgrade reports for Job invocation')
|
|
23
|
+
param :id, :identifier, required: true
|
|
24
|
+
def job_invocation
|
|
25
|
+
@preupgrade_reports = resource_scope_for_index.where(job_invocation_id: params[:id])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# By overriding path_to_authenticate we can require REX's permission view_job_invocations
|
|
31
|
+
def path_to_authenticate
|
|
32
|
+
params['action'] = 'show' if params['action'] == 'job_invocation'
|
|
33
|
+
Foreman::AccessControl.normalize_path_hash params.slice(:action, :id, :user_id)
|
|
34
|
+
.merge({ controller: 'api/v2/job_invocations' })
|
|
35
|
+
end
|
|
17
36
|
end
|
|
18
37
|
end
|
|
19
38
|
end
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class PreupgradeReportsController < ::Api::V2::BaseController
|
|
4
|
+
include ApiAuthorizer
|
|
5
|
+
|
|
4
6
|
def index
|
|
5
|
-
@preupgrade_reports = resource_scope.search_for(*search_options)
|
|
7
|
+
@preupgrade_reports = resource_scope.includes(:preupgrade_report_entries).search_for(*search_options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
# By overriding :path_to_authenticate we can require REX's :view_job_invocations permission
|
|
13
|
+
def path_to_authenticate
|
|
14
|
+
Foreman::AccessControl.normalize_path_hash params.slice(:action, :id, :user_id)
|
|
15
|
+
.merge({ controller: 'job_invocations' })
|
|
6
16
|
end
|
|
7
17
|
end
|
|
@@ -8,7 +8,8 @@ module Actions
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def plan(job_invocation, host, *_args)
|
|
11
|
-
return unless ::Helpers::JobHelper.correct_feature?(job_invocation, 'leapp_preupgrade')
|
|
11
|
+
return unless ::Helpers::JobHelper.correct_feature?(job_invocation, 'leapp_preupgrade') ||
|
|
12
|
+
::Helpers::JobHelper.correct_feature?(job_invocation, 'leapp_remediation_plan')
|
|
12
13
|
|
|
13
14
|
plan_self(host_id: host.id, job_invocation_id: job_invocation.id)
|
|
14
15
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
name: Check Leapp
|
|
3
|
+
description_format: 'Check if Leapp package is installed.'
|
|
4
|
+
kind: job_template
|
|
5
|
+
job_category: Leapp
|
|
6
|
+
provider_type: SSH
|
|
7
|
+
snippet: true
|
|
8
|
+
%>
|
|
9
|
+
|
|
10
|
+
if ! command -v leapp > /dev/null
|
|
11
|
+
then
|
|
12
|
+
echo "Leapp is not installed."
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
@@ -7,8 +7,10 @@ provider_type: SSH
|
|
|
7
7
|
feature: leapp_preupgrade
|
|
8
8
|
%>
|
|
9
9
|
|
|
10
|
+
<%= render_template 'Check Leapp' %>
|
|
11
|
+
|
|
10
12
|
leapp preupgrade
|
|
11
|
-
[ $? -eq 0 ] || exit 1
|
|
12
13
|
|
|
13
14
|
echo "===leap_upgrade_report_start==="
|
|
14
15
|
cat /var/log/leapp/leapp-report.json
|
|
16
|
+
rm -f /var/log/leapp/leapp-report.json
|
|
@@ -12,6 +12,17 @@ template_inputs:
|
|
|
12
12
|
input_type: user
|
|
13
13
|
value_type: plain
|
|
14
14
|
description: List of remediation ids
|
|
15
|
+
- name: run_preupgrade
|
|
16
|
+
description: Run preupgrade check again when remediation entries are fixed.
|
|
17
|
+
input_type: user
|
|
18
|
+
required: true
|
|
19
|
+
options: "true\nfalse"
|
|
20
|
+
default: "true"
|
|
15
21
|
%>
|
|
16
22
|
|
|
23
|
+
<%= render_template 'Check Leapp' %>
|
|
24
|
+
|
|
17
25
|
<%= build_remediation_plan(input('remediation_ids').split(','), @host) %>
|
|
26
|
+
<% if input('run_preupgrade') == 'true' %>
|
|
27
|
+
<%= render_template 'Run preupgrade via Leapp' %>
|
|
28
|
+
<% end %>
|
|
@@ -6,18 +6,19 @@ description_format: 'Upgrade RHEL 7 host'
|
|
|
6
6
|
provider_type: Ansible
|
|
7
7
|
feature: leapp_upgrade
|
|
8
8
|
template_inputs:
|
|
9
|
-
- name:
|
|
10
|
-
description:
|
|
9
|
+
- name: Reboot
|
|
10
|
+
description: Reboot the host automaticaly to continue with the upgrade
|
|
11
11
|
input_type: user
|
|
12
|
-
required:
|
|
13
|
-
|
|
12
|
+
required: true
|
|
13
|
+
default: "true"
|
|
14
|
+
options: "true\nfalse"
|
|
14
15
|
%>
|
|
15
16
|
---
|
|
16
17
|
- hosts: all
|
|
17
18
|
tasks:
|
|
18
19
|
- name: Run Leapp Upgrade
|
|
19
20
|
command: leapp upgrade
|
|
20
|
-
<% if input('
|
|
21
|
+
<% if input('Reboot') == "true" %>
|
|
21
22
|
- name: Reboot the machine
|
|
22
23
|
reboot:
|
|
23
24
|
reboot_timeout: 1800
|
data/config/routes.rb
CHANGED
|
@@ -4,8 +4,9 @@ Rails.application.routes.draw do
|
|
|
4
4
|
resources :preupgrade_reports, :only => %i[index]
|
|
5
5
|
|
|
6
6
|
namespace :api, defaults: { format: 'json' } do
|
|
7
|
-
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2'}, apiv: /v2/, constraints: ApiConstraints.new( version: 2, default: true) do
|
|
7
|
+
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v2/, constraints: ApiConstraints.new( version: 2, default: true) do
|
|
8
8
|
resources :preupgrade_reports, only: %i[index show]
|
|
9
|
+
get 'job_invocations/:id/preupgrade_reports', to: 'preupgrade_reports#job_invocation'
|
|
9
10
|
end
|
|
10
11
|
end
|
|
11
12
|
end
|
data/lib/foreman_leapp/engine.rb
CHANGED
|
@@ -33,7 +33,10 @@ module ForemanLeapp
|
|
|
33
33
|
partial: 'job_invocations/leapp_preupgrade_report',
|
|
34
34
|
name: _('Leapp preupgrade report'),
|
|
35
35
|
id: 'leapp_preupgrade_report',
|
|
36
|
-
onlyif: proc { |subject|
|
|
36
|
+
onlyif: proc { |subject|
|
|
37
|
+
::Helpers::JobHelper.correct_feature?(subject, 'leapp_preupgrade') ||
|
|
38
|
+
::Helpers::JobHelper.correct_feature?(subject, 'leapp_remediation_plan')
|
|
39
|
+
}
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
end
|
data/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "tfm-lint --plugin -d /webpack",
|
|
8
8
|
"link-leapp-js": "./script/link_leapp_js.sh",
|
|
9
|
-
"test": "tfm-test --plugin",
|
|
9
|
+
"test": "tfm-test --plugin --config jest.config.js",
|
|
10
10
|
"test:watch": "tfm-test --plugin --watchAll",
|
|
11
11
|
"test:current": "tfm-test --plugin --watch",
|
|
12
12
|
"publish-coverage": "tfm-publish-coverage",
|
|
@@ -32,10 +32,11 @@
|
|
|
32
32
|
"@theforeman/builder": "^4.2.1",
|
|
33
33
|
"@theforeman/eslint-plugin-foreman": "4.2.1",
|
|
34
34
|
"@theforeman/stories": "^4.2.1",
|
|
35
|
-
"@theforeman/vendor-dev": "^4.2.1",
|
|
36
35
|
"@theforeman/test": "^4.2.1",
|
|
36
|
+
"@theforeman/vendor-dev": "^4.2.1",
|
|
37
37
|
"babel-eslint": "^10.0.0",
|
|
38
38
|
"eslint": "^6.8.0",
|
|
39
|
+
"jest-svg-transformer": "^1.0.0",
|
|
39
40
|
"prettier": "^1.19.1"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
@@ -7,24 +7,107 @@ module Api
|
|
|
7
7
|
class PreupgradeReportsControllerTest < ActionController::TestCase
|
|
8
8
|
setup do
|
|
9
9
|
@host = FactoryBot.create(:host)
|
|
10
|
-
@
|
|
10
|
+
@job_invocation = FactoryBot.create(:job_invocation)
|
|
11
|
+
@report = FactoryBot.create(:preupgrade_report, host: @host, job_invocation: @job_invocation)
|
|
11
12
|
@entry = FactoryBot.create(:preupgrade_report_entry, host: @host, preupgrade_report: @report)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
test 'should get index' do
|
|
15
|
-
get :index
|
|
15
|
+
test 'should get :index' do
|
|
16
|
+
get :index
|
|
16
17
|
assert_response :success
|
|
17
|
-
assert_not_empty
|
|
18
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
test 'should get
|
|
21
|
+
test 'should get :show' do
|
|
21
22
|
get :show, params: { id: @report.id }
|
|
22
23
|
assert_response :success
|
|
23
24
|
|
|
24
|
-
response =
|
|
25
|
+
response = JSON.parse(@response.body)
|
|
25
26
|
assert_equal response['id'], @report.id
|
|
26
27
|
assert_not_empty response['preupgrade_report_entries']
|
|
27
28
|
end
|
|
29
|
+
|
|
30
|
+
test 'should get :job_invocation' do
|
|
31
|
+
get :job_invocation, params: { id: @job_invocation.id }
|
|
32
|
+
assert_response :success
|
|
33
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'with permissions' do
|
|
37
|
+
setup do
|
|
38
|
+
@user = FactoryBot.create(:user, admin: false)
|
|
39
|
+
setup_user('view', 'job_invocations', nil, @user)
|
|
40
|
+
setup_user('view', 'hosts', nil, @user)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test 'should get :index' do
|
|
44
|
+
get :index, session: set_session_user(@user)
|
|
45
|
+
assert_response :success
|
|
46
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
test 'should get :show' do
|
|
50
|
+
get :show, params: { id: @report.id }, session: set_session_user(@user)
|
|
51
|
+
assert_response :success
|
|
52
|
+
assert_equal @report.id, JSON.parse(@response.body)['id']
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
test 'should get :job_invocation' do
|
|
56
|
+
get :job_invocation, params: { id: @job_invocation.id }, session: set_session_user(@user)
|
|
57
|
+
assert_response :success
|
|
58
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'without :view_job_invocations' do
|
|
63
|
+
setup do
|
|
64
|
+
@user = FactoryBot.create(:user, admin: false)
|
|
65
|
+
setup_user('view', 'hosts', nil, @user)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test 'should not get :index' do
|
|
69
|
+
get :index, session: set_session_user(@user)
|
|
70
|
+
assert_response :forbidden
|
|
71
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
test 'should not get :show' do
|
|
75
|
+
get :show, params: { id: @report.id }, session: set_session_user(@user)
|
|
76
|
+
assert_response :forbidden
|
|
77
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
test 'should not get :job_invocation' do
|
|
81
|
+
get :job_invocation, params: { id: @job_invocation.id }, session: set_session_user(@user)
|
|
82
|
+
assert_response :forbidden
|
|
83
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'without :view_hosts' do
|
|
88
|
+
setup do
|
|
89
|
+
@user = FactoryBot.create(:user, admin: false)
|
|
90
|
+
setup_user('view', 'job_invocations', nil, @user)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
test 'should not get :index' do
|
|
94
|
+
get :index, session: set_session_user(@user)
|
|
95
|
+
assert_response :forbidden
|
|
96
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
test 'should not get :job_invocation' do
|
|
100
|
+
get :show, params: { id: @report.id }, session: set_session_user(@user)
|
|
101
|
+
assert_response :forbidden
|
|
102
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
test 'should not get :job_invocation' do
|
|
106
|
+
get :job_invocation, params: { id: @job_invocation.id }, session: set_session_user(@user)
|
|
107
|
+
assert_response :forbidden
|
|
108
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
|
|
109
|
+
end
|
|
110
|
+
end
|
|
28
111
|
end
|
|
29
112
|
end
|
|
30
113
|
end
|
|
@@ -4,13 +4,36 @@ require 'test_plugin_helper'
|
|
|
4
4
|
|
|
5
5
|
class PreupgradeReportsControllerTest < ActionController::TestCase
|
|
6
6
|
setup do
|
|
7
|
+
@user = FactoryBot.create(:user, admin: false)
|
|
7
8
|
@host = FactoryBot.create :host
|
|
8
9
|
FactoryBot.create :preupgrade_report, host: @host
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
test 'should get index' do
|
|
12
|
-
get :index
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
test 'should get :index' do
|
|
13
|
+
get :index
|
|
14
|
+
assert_response :success
|
|
15
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
test 'should get :index with :view_job_invocations & :view_hosts' do
|
|
19
|
+
setup_user 'view', 'job_invocations', nil, @user
|
|
20
|
+
setup_user 'view', 'hosts', nil, @user
|
|
21
|
+
get :index, session: set_session_user(@user)
|
|
22
|
+
assert_response :success
|
|
23
|
+
assert_not_empty JSON.parse(@response.body)['results']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
test 'should not get :index without :view_job_invocations' do
|
|
27
|
+
setup_user 'view', 'hosts', nil, @user
|
|
28
|
+
get :index, session: set_session_user(@user)
|
|
29
|
+
assert_response :forbidden
|
|
30
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test 'should not get :index without :view_hosts' do
|
|
34
|
+
setup_user 'view', 'job_invocations', nil, @user
|
|
35
|
+
get :index, session: set_session_user(@user)
|
|
36
|
+
assert_response :forbidden
|
|
37
|
+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
|
|
15
38
|
end
|
|
16
39
|
end
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const translate =
|
|
1
|
+
export const translate = val => val;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const EmptyStatePattern = () => jest.fn();
|
|
@@ -1,24 +1,118 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import MessageBox from 'foremanReact/components/common/MessageBox';
|
|
3
3
|
import { LoadingState, Row } from 'patternfly-react';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
|
|
6
6
|
import PreupgradeReportsList from '../PreupgradeReportsList';
|
|
7
|
-
import
|
|
7
|
+
import UpgradeAllButton from './components/UpgradeAllButton';
|
|
8
|
+
import EntriesFilter from './components/EntriesFilter';
|
|
9
|
+
import FixSelectedButton from './components/FixSelectedButton';
|
|
8
10
|
|
|
9
11
|
import {
|
|
10
12
|
flattenEntries,
|
|
11
13
|
isEmpty,
|
|
12
14
|
anyEntriesFixable,
|
|
15
|
+
filterEntries,
|
|
16
|
+
idsForInvocationFromEntries,
|
|
17
|
+
sortEntries,
|
|
18
|
+
fixableEntries,
|
|
13
19
|
} from './PreupgradeReportsHelpers';
|
|
14
20
|
|
|
21
|
+
import NoReports from './components/NoReports';
|
|
22
|
+
|
|
15
23
|
const PreupgradeReports = ({
|
|
16
24
|
preupgradeReports,
|
|
17
|
-
loading,
|
|
18
|
-
error,
|
|
19
25
|
csrfToken,
|
|
20
26
|
newJobInvocationUrl,
|
|
21
27
|
}) => {
|
|
28
|
+
const [filterType, setFilterType] = useState('title');
|
|
29
|
+
const [filterValue, setFilterValue] = useState('');
|
|
30
|
+
const [checked, setChecked] = useState([]);
|
|
31
|
+
const [sort, setSort] = useState({ attribute: '', order: 'desc' });
|
|
32
|
+
|
|
33
|
+
const onFilterValueChange = value => {
|
|
34
|
+
setFilterValue(value);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const onFilterValueClear = () => setFilterValue('');
|
|
38
|
+
|
|
39
|
+
const onFilterTypeChange = value => {
|
|
40
|
+
onFilterValueClear();
|
|
41
|
+
setFilterType(value);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const isSelected = entry => checked.some(item => item.id === entry.id);
|
|
45
|
+
|
|
46
|
+
const anySelected = checked.length > 0;
|
|
47
|
+
|
|
48
|
+
const toggleSelected = (entry, isEntrySelected) => {
|
|
49
|
+
if (isEntrySelected) {
|
|
50
|
+
setChecked(checked.filter(item => item.id !== entry.id));
|
|
51
|
+
} else {
|
|
52
|
+
setChecked([entry, ...checked]);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const toggleSelectAll = () => {
|
|
57
|
+
const allFixable = fixableEntries(preupgradeReports);
|
|
58
|
+
|
|
59
|
+
if (checked.length === allFixable.length) {
|
|
60
|
+
setChecked([]);
|
|
61
|
+
} else {
|
|
62
|
+
setChecked(allFixable);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const changeSort = value => {
|
|
67
|
+
setSort({ ...sort, ...value });
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<React.Fragment>
|
|
72
|
+
<Row>
|
|
73
|
+
<div className="col-md-8">
|
|
74
|
+
<EntriesFilter
|
|
75
|
+
filterType={filterType}
|
|
76
|
+
onFilterTypeChange={onFilterTypeChange}
|
|
77
|
+
filterValue={filterValue}
|
|
78
|
+
onFilterValueChange={onFilterValueChange}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
<div className="col-md-4">
|
|
82
|
+
<div className="btn-toolbar pull-right">
|
|
83
|
+
<FixSelectedButton
|
|
84
|
+
postUrl={newJobInvocationUrl}
|
|
85
|
+
disabled={!anyEntriesFixable(preupgradeReports) || !anySelected}
|
|
86
|
+
csrfToken={csrfToken}
|
|
87
|
+
ids={idsForInvocationFromEntries(checked)}
|
|
88
|
+
/>
|
|
89
|
+
<UpgradeAllButton
|
|
90
|
+
postUrl={newJobInvocationUrl}
|
|
91
|
+
csrfToken={csrfToken}
|
|
92
|
+
preupgradeReports={preupgradeReports}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</Row>
|
|
97
|
+
<PreupgradeReportsList
|
|
98
|
+
allEntries={filterEntries(
|
|
99
|
+
filterType,
|
|
100
|
+
filterValue,
|
|
101
|
+
sortEntries(flattenEntries(preupgradeReports), sort)
|
|
102
|
+
)}
|
|
103
|
+
isSelected={isSelected}
|
|
104
|
+
toggleSelected={toggleSelected}
|
|
105
|
+
sort={sort}
|
|
106
|
+
changeSort={changeSort}
|
|
107
|
+
toggleSelectAll={toggleSelectAll}
|
|
108
|
+
/>
|
|
109
|
+
</React.Fragment>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const withLoadingState = Component => props => {
|
|
114
|
+
const { error, loading, preupgradeReports, reportsExpected } = props;
|
|
115
|
+
|
|
22
116
|
if (!isEmpty(error)) {
|
|
23
117
|
return (
|
|
24
118
|
<MessageBox
|
|
@@ -31,30 +125,19 @@ const PreupgradeReports = ({
|
|
|
31
125
|
|
|
32
126
|
return (
|
|
33
127
|
<LoadingState loading={loading}>
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
postUrl={newJobInvocationUrl}
|
|
40
|
-
disabled={!anyEntriesFixable(preupgradeReports)}
|
|
41
|
-
csrfToken={csrfToken}
|
|
42
|
-
preupgradeReports={preupgradeReports}
|
|
43
|
-
/>
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
</Row>
|
|
47
|
-
<PreupgradeReportsList allEntries={flattenEntries(preupgradeReports)} />
|
|
128
|
+
{preupgradeReports.length > 0 ? (
|
|
129
|
+
<Component {...props} />
|
|
130
|
+
) : (
|
|
131
|
+
<NoReports reportsExpected={reportsExpected} />
|
|
132
|
+
)}
|
|
48
133
|
</LoadingState>
|
|
49
134
|
);
|
|
50
135
|
};
|
|
51
136
|
|
|
52
137
|
PreupgradeReports.propTypes = {
|
|
53
138
|
preupgradeReports: PropTypes.array.isRequired,
|
|
54
|
-
loading: PropTypes.bool.isRequired,
|
|
55
|
-
error: PropTypes.object.isRequired,
|
|
56
139
|
csrfToken: PropTypes.string.isRequired,
|
|
57
140
|
newJobInvocationUrl: PropTypes.string.isRequired,
|
|
58
141
|
};
|
|
59
142
|
|
|
60
|
-
export default PreupgradeReports;
|
|
143
|
+
export default withLoadingState(PreupgradeReports);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
PREUPGRADE_REPORTS_FAILURE,
|
|
8
8
|
} from '../../consts';
|
|
9
9
|
|
|
10
|
-
export const
|
|
10
|
+
export const getPreupgradeReportsAction = url => async dispatch => {
|
|
11
11
|
dispatch({ type: PREUPGRADE_REPORTS_REQUEST });
|
|
12
12
|
|
|
13
13
|
try {
|