foreman_wreckingball 3.0.1 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/app/assets/javascripts/foreman_wreckingball/modal.js +26 -18
  4. data/app/assets/javascripts/foreman_wreckingball/status_hosts_table.js +81 -0
  5. data/app/assets/javascripts/foreman_wreckingball/status_managed_hosts_dashboard.js +14 -0
  6. data/app/assets/javascripts/foreman_wreckingball/status_row.js +17 -0
  7. data/app/assets/stylesheets/foreman_wreckingball/status_hosts_table.css.scss +13 -0
  8. data/app/assets/stylesheets/foreman_wreckingball/status_managed_hosts_dashboard.css.scss +8 -0
  9. data/app/controllers/foreman_wreckingball/hosts_controller.rb +143 -43
  10. data/app/helpers/concerns/foreman_wreckingball/hosts_helper_extensions.rb +0 -15
  11. data/app/helpers/foreman_wreckingball/statuses_helper.rb +21 -0
  12. data/app/lib/actions/foreman_wreckingball/bulk_remediate.rb +27 -0
  13. data/app/lib/actions/foreman_wreckingball/host/remediate_hardware_version.rb +63 -0
  14. data/app/lib/actions/foreman_wreckingball/host/remediate_spectre_v2.rb +58 -0
  15. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/mock.rb +13 -0
  16. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/real.rb +7 -0
  17. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/server.rb +14 -0
  18. data/app/models/concerns/foreman_wreckingball/host_extensions.rb +10 -20
  19. data/app/models/concerns/foreman_wreckingball/host_status_extensions.rb +13 -0
  20. data/app/models/concerns/foreman_wreckingball/user_extensions.rb +12 -0
  21. data/app/models/concerns/foreman_wreckingball/usergroup_extensions.rb +18 -0
  22. data/app/models/concerns/foreman_wreckingball/vmware_facet_host_extensions.rb +10 -0
  23. data/app/models/foreman_wreckingball/cpu_hot_add_status.rb +8 -0
  24. data/app/models/foreman_wreckingball/hardware_version_status.rb +70 -0
  25. data/app/models/foreman_wreckingball/operatingsystem_status.rb +8 -0
  26. data/app/models/foreman_wreckingball/spectre_v2_status.rb +19 -3
  27. data/app/models/foreman_wreckingball/tools_status.rb +9 -1
  28. data/app/models/foreman_wreckingball/vmware_facet.rb +9 -4
  29. data/app/models/foreman_wreckingball/vmware_hypervisor_facet.rb +4 -7
  30. data/app/models/setting/wreckingball.rb +22 -0
  31. data/app/services/foreman_wreckingball/vmware_cluster_importer.rb +7 -7
  32. data/app/services/foreman_wreckingball/vmware_hypervisor_importer.rb +17 -4
  33. data/app/views/foreman_wreckingball/hosts/_hosts.json.rabl +35 -0
  34. data/app/views/foreman_wreckingball/hosts/_status_dashboard_content.erb +13 -23
  35. data/app/views/foreman_wreckingball/hosts/_status_managed_hosts_dashboard_cards.html.erb +16 -0
  36. data/app/views/foreman_wreckingball/hosts/_status_managed_hosts_dashboard_cards_card.html.erb +11 -0
  37. data/app/views/foreman_wreckingball/hosts/_status_row.html.erb +16 -55
  38. data/app/views/foreman_wreckingball/hosts/_status_row_actions.html.erb +22 -0
  39. data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table.html.erb +24 -0
  40. data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table_actions.html.erb +9 -0
  41. data/app/views/foreman_wreckingball/hosts/schedule_remediate.html.erb +44 -26
  42. data/app/views/foreman_wreckingball/hosts/status_dashboard.html.erb +9 -6
  43. data/app/views/foreman_wreckingball/hosts/status_hosts.json.rabl +13 -0
  44. data/app/views/foreman_wreckingball/hosts/status_managed_hosts_dashboard.html.erb +142 -0
  45. data/config/environments/production.rb +7 -0
  46. data/config/routes.rb +4 -4
  47. data/db/migrate/20181020174609_add_power_state_to_vmware_facets.rb +7 -0
  48. data/db/migrate/20181021111543_add_indexes_to_vmware_hypervisor_facets.rb +8 -0
  49. data/lib/foreman_wreckingball/engine.rb +71 -23
  50. data/lib/foreman_wreckingball/version.rb +1 -1
  51. data/lib/tasks/foreman_vmware_checks_tasks.rake +1 -1
  52. data/test/actions/foreman_wreckingball/bulk_remediate_test.rb +31 -0
  53. data/test/actions/foreman_wreckingball/host/refresh_vmware_facet_test.rb +5 -4
  54. data/test/actions/foreman_wreckingball/host/remediate_hardware_version_test.rb +63 -0
  55. data/test/actions/foreman_wreckingball/host/remediate_spectre_v2_test.rb +62 -0
  56. data/test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb +4 -2
  57. data/test/controllers/foreman_wreckingball/hosts_controller_test.rb +278 -39
  58. data/test/factories/compute_resource.rb +6 -1
  59. data/test/factories/foreman_wreckingball_factories.rb +166 -115
  60. data/test/factories/host.rb +16 -0
  61. data/test/factories/task.rb +17 -0
  62. data/test/helpers/foreman_wreckingball/status_helper.rb +10 -0
  63. data/test/integration/hosts_status_dashboard_test.rb +50 -0
  64. data/test/integration/hosts_status_managed_hosts_test.rb +105 -0
  65. data/test/integration_test_plugin_helper.rb +13 -0
  66. data/test/models/foreman_wreckingball/hardware_version_status_test.rb +88 -0
  67. data/test/models/foreman_wreckingball/tools_status_test.rb +5 -2
  68. data/test/models/foreman_wreckingball/vmware_facet_test.rb +27 -6
  69. data/test/models/host_status_test.rb +22 -0
  70. data/test/models/host_test.rb +64 -4
  71. data/test/models/usergroup_test.rb +25 -0
  72. data/test/test_plugin_helper.rb +19 -0
  73. data/test/unit/foreman_wreckingball/vmware_cluster_importer_test.rb +17 -2
  74. data/test/unit/foreman_wreckingball/vmware_hypervisor_importer_test.rb +11 -0
  75. metadata +55 -8
  76. data/app/services/foreman_wreckingball/debris_collector.rb +0 -249
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d61b28b92f7f4ed29367841c4bec7b80ea38cc4610daf6e4ec78f1181ac8b5c9
4
- data.tar.gz: 89f264e68c658e9135a07f761584f23e51b543ba8264bb4a0ead2aef132449b5
3
+ metadata.gz: 5386e48704b4c0837fd34063239ead1bda9c7e2dd72cc60d82c15ac60334fea2
4
+ data.tar.gz: 4ed751665783de1efb8e25534cc32324f287c4611aa579d031873078b53ff7d1
5
5
  SHA512:
6
- metadata.gz: 0e24c4e6c7ad4cd4eb6bb6f6e66a18712bc090fb41f60d0b639448b9763aad0655aa49a4f80206b036b25fc70d9acae8319a5d027becb8f43d6a26263152232a
7
- data.tar.gz: 76271354a6bd79fd6263bca07ffdc8cba779b1be3ad9744f0675bc5b80c4498c214c473d2b7825af3af5f73d0f20def793bceeffcecfd784f8e0d78f2e6c8a20
6
+ metadata.gz: 2d6df272535f83e43c0889bce9655beb8b01f522269a85ebfbb7e5a6f1d332c407632e295234e12e7dc826897e8cc7eda587a322a57d265b3239ebbda54b4d4f
7
+ data.tar.gz: 3aea63d70aa6895ba153fdf32c370127ca8ee8a2b22ceb9099b4c8ded6fca3b8315561e4cd78854ec1977b6df73d7dee7e54e5943237de496dfaf1eebec179bd
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ForemanWreckingball
2
2
 
3
+ [<img src="https://opensourcelogos.aws.dmtech.cloud/dmTECH_opensource_logo%401x.svg" height="21" width="130">](https://www.dmtech.de/)
4
+
3
5
  This is a plugin for Foreman that adds several VMware related status checks to your Hosts in Foreman. For performance reasons, these checks are only run periodically.
4
6
 
5
7
  ## Compatibility
@@ -23,7 +25,7 @@ Fork and send a Pull Request. Thanks!
23
25
 
24
26
  ## Copyright
25
27
 
26
- Copyright (c) 2018 dm-drogerie markt GmbH & Co. KG https://dm.de
28
+ Copyright (c) 2018 dmTECH GmbH, [dmtech.de](https://www.dmtech.de/)
27
29
 
28
30
  This program is free software: you can redistribute it and/or modify
29
31
  it under the terms of the GNU General Public License as published by
@@ -9,29 +9,38 @@ function submit_modal_form() {
9
9
  $('#confirmation-modal').modal('hide');
10
10
  }
11
11
 
12
- function show_modal(element, url) {
13
- if (!url) {
14
- url = $(element).attr('href');
15
- }
16
- var title = $(element).attr('data-title');
17
- if (title) {
18
- $('#confirmation-modal .modal-title').text(title);
19
- }
12
+ function show_modal(element) {
13
+ if ($(element).attr('disabled')) { return; }
14
+
15
+ const url = $(element).attr('href');
16
+ const title = $(element).data('title');
17
+ const hostAssociation = $(element).data('host-association');
18
+
19
+ if (title) { $('#confirmation-modal .modal-title').text(title); }
20
+
20
21
  $('#confirmation-modal .modal-body')
21
22
  .empty()
22
23
  .append('<div class="modal-spinner spinner spinner-lg"></div>');
23
24
  $('#confirmation-modal').modal();
24
- $('#confirmation-modal .modal-body').load(url + ' #content',
25
- function(response, status, xhr) {
26
- $('#confirmation-modal .form-actions').remove();
27
25
 
28
- var submit_button = $('#confirmation-modal button[data-action="submit"]');
29
- if ($(element).attr('data-submit-class')) {
30
- submit_button.attr('class', 'btn ' + $(element).attr('data-submit-class'));
31
- } else {
32
- submit_button.attr('class', 'btn btn-primary');
33
- }
26
+ let params;
27
+ if (!!hostAssociation) {
28
+ params = Object.assign({}, { host_association: hostAssociation },
29
+ !!$(element).data('owned-only') ? { owned_only: true } : null);
30
+ } else if($(element).data('status-id')) {
31
+ params = { status_ids: [$(element).data('status-id')] };
32
+ } else {
33
+ const statusIds = $(element).closest('.status-row')
34
+ .find(':checkbox[name="status-id"]:checked')
35
+ .map((_, e) => { return e.value; })
36
+ .toArray();
37
+ params = { status_ids: statusIds };
38
+ }
34
39
 
40
+ $('#confirmation-modal .modal-body').load(`${url}?${$.param(params)} #content`,
41
+ (response, status, xhr) => {
42
+ $('#confirmation-modal .form-actions').remove();
43
+ $('#confirmation-modal button[data-action="submit"]').attr('class', 'btn btn-primary');
35
44
  $('#confirmation-modal a[rel="popover"]').popover();
36
45
 
37
46
  trigger_form_selector_binds('schedule_remediate_form', url);
@@ -39,4 +48,3 @@ function show_modal(element, url) {
39
48
  });
40
49
  return false;
41
50
  }
42
-
@@ -0,0 +1,81 @@
1
+ $(document).ready(() => {
2
+ $.fn.dataTable.ext.errMode = 'none';
3
+ $('.status-row.list-group-item').one('click', function() {
4
+ $(this).find('table.status-hosts').each((_index, element) => {
5
+ $(element).dataTable({
6
+ searching: false,
7
+ ordering: false,
8
+ bLengthChange: false,
9
+ lengthMenu: [100],
10
+ processing: true,
11
+ serverSide: true,
12
+ columnDefs: [
13
+ { className: 'ellipsis', targets: [1, 2, 3, 4] },
14
+ { width: '10px', targets: 0 }
15
+ ],
16
+ ajax: {
17
+ url: $(element).data('hosts-url'),
18
+ type: 'GET',
19
+ data: (_, oSettings) => {
20
+ const { _iDisplayStart: start, _iDisplayLength: perPage } = oSettings;
21
+ const page = (start / perPage) + 1;
22
+ return {
23
+ page: page || 1,
24
+ per_page: perPage
25
+ };
26
+ },
27
+ dataSrc: (json) => {
28
+ return json.data.map((e) => {
29
+ let row = [
30
+ `<input name='status-id' type='checkbox' value='${e.status.id}' data-remediate='${!!e.remediate}' >`,
31
+ `<a href="${e.path}">${e.name}</a>`,
32
+ `<span class="${e.status.icon_class}"></span><span class="${e.status.status_class}">${e.status.label}</span>`,
33
+ (e.owner || {}).name || '',
34
+ (e.environment || {}).name || ''
35
+ ];
36
+ if(e.remediate) {
37
+ row.push(`
38
+ <span class="btn btn-sm btn-default">
39
+ <a data-title="${e.remediate.title}"
40
+ data-id="aid_wreckingball_hosts_${e.name}_schedule_remediate"
41
+ data-status-id="${e.status.id}"
42
+ onclick="show_modal(this); return false;"
43
+ href="${e.remediate.path}">
44
+ ${e.remediate.label}
45
+ </a>
46
+ </span>`);
47
+ } else {
48
+ row.push(null);
49
+ }
50
+ return row;
51
+ });
52
+ }
53
+ }
54
+ });
55
+ $(element).on('error.dt', (_, settings) => {
56
+ $(settings.nTable).closest('.status-hosts-container').addClass('ajax-error');
57
+ });
58
+ $(element).on('page.dt', () => {
59
+ $selectAll.prop('checked', false).change();
60
+ $remediateSelected.attr('disabled', true);
61
+ });
62
+
63
+ const $selectAll = $(this).find(':checkbox[name="select-all"]');
64
+ const $remediateSelected = $(this).find('a.remediate-selected');
65
+
66
+ $selectAll.prop('checked', false);
67
+
68
+ $selectAll.change(() => {
69
+ const $selectHost = $(this).find(':checkbox[name="status-id"]');
70
+ $selectHost.prop('checked', $selectAll.is(':checked'));
71
+ $remediateSelected.attr('disabled', !$selectAll.is(':checked'));
72
+ });
73
+
74
+ $(this).on('change', ':checkbox[name=status-id]', () => {
75
+ const isAnyHostChecked = $(this).find(':checkbox[name="status-id"]').is(':checked');
76
+ $selectAll.prop('checked', isAnyHostChecked);
77
+ $remediateSelected.attr('disabled', !isAnyHostChecked);
78
+ });
79
+ });
80
+ });
81
+ });
@@ -0,0 +1,14 @@
1
+ $(document).ready(() => {
2
+ $('table#missing_vms').add('table#wrong_hosts').add('table#more_than_one_hosts')
3
+ .DataTable({
4
+ bLengthChange: true,
5
+ lengthMenu: [20, 50, 100],
6
+ order: [[ 0, 'desc' ]],
7
+ columnDefs: [
8
+ {
9
+ 'targets': 'no-sort',
10
+ 'orderable': false,
11
+ }
12
+ ]
13
+ });
14
+ });
@@ -0,0 +1,17 @@
1
+ $(document).ready(() => {
2
+ // click the list-view heading then expand a row
3
+ $('.list-group-item-header').click(function(event) {
4
+ if(!$(event.target).is('button, a, input, .fa-ellipsis-v')) {
5
+ $(this).find('.fa-angle-right').toggleClass('fa-angle-down')
6
+ .end().parent().toggleClass('list-view-pf-expand-active')
7
+ .find('.list-group-item-container').toggleClass('hidden');
8
+ }
9
+ });
10
+
11
+ // click the close button, hide the expand row and remove the active status
12
+ $('.list-group-item-container .close').click(function() {
13
+ $(this).parent().addClass('hidden')
14
+ .parent().removeClass('list-view-pf-expand-active')
15
+ .find('.fa-angle-right').removeClass('fa-angle-down');
16
+ });
17
+ });
@@ -0,0 +1,13 @@
1
+ div.status-hosts-container div.alert-danger {
2
+ display: none;
3
+ }
4
+
5
+ div.status-hosts-container.ajax-error div.alert-danger {
6
+ margin-top: 25px;
7
+ display: block;
8
+ }
9
+
10
+ div.status-hosts-container.ajax-error div.dataTables_wrapper,
11
+ div.status-hosts-container.ajax-error p {
12
+ display: none;
13
+ }
@@ -0,0 +1,8 @@
1
+ .status-managed-hosts-dashboard-cards {
2
+ .card-pf.card-pf-accented.card-pf-aggregate-status {
3
+ min-height: 100px;
4
+ .card-pf-title {
5
+ min-height: 30px;
6
+ }
7
+ }
8
+ }
@@ -3,45 +3,125 @@
3
3
  module ForemanWreckingball
4
4
  class HostsController < ::HostsController
5
5
  include ::ForemanTasks::Concerns::Parameters::Triggering
6
- before_action :find_resource, :only => [:submit_remediate, :schedule_remediate]
7
- before_action :find_status, :only => [:submit_remediate, :schedule_remediate]
6
+ include ::HostsHelper
7
+ include ::AuthorizeHelper
8
+
9
+ AJAX_REQUESTS = [:status_hosts].freeze
10
+ before_action :ajax_request, :only => AJAX_REQUESTS
11
+ before_action :find_statuses, :only => [:schedule_remediate, :submit_remediate]
8
12
 
9
13
  def status_dashboard
10
- statuses = [
11
- ToolsStatus,
12
- OperatingsystemStatus,
13
- CpuHotAddStatus,
14
- SpectreV2Status
15
- ]
16
-
17
- @newest_data = Host.authorized(:view_hosts, Host).joins(:vmware_facet).maximum('vmware_facets.updated_at')
18
-
19
- @data = statuses.map do |status|
20
- host_association = status.host_association
21
- hosts = Host.authorized(:view_hosts, Host)
22
- .joins(host_association)
23
- .includes(host_association)
24
- .joins(:vmware_facet)
25
- .includes(host_association => :host)
26
- .includes(:environment)
27
- .preload(:owner)
28
- .order(:name)
14
+ @newest_data = Host.authorized(:view_hosts).joins(:vmware_facet).maximum('vmware_facets.updated_at')
15
+ host_ids = Host.authorized(:view_hosts)
16
+ .try { |query| params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
17
+ .pluck(:id)
18
+
19
+ @data = HostStatus.wreckingball_statuses.map do |status|
20
+ counter = status.where(host_id: host_ids)
21
+ .select(:status)
22
+ .group(:status)
23
+ .count
24
+ .transform_keys { |key| status.to_global(key) }
25
+
29
26
  {
30
27
  name: status.status_name,
31
- hosts: hosts,
32
28
  description: status.description,
33
- host_association: host_association,
34
- supports_remediate: status.supports_remediate?
29
+ host_association: status.host_association,
30
+ supports_remediate: status.supports_remediate?,
31
+ counter: {
32
+ ok: counter[HostStatus::Global::OK] || 0,
33
+ warning: counter[HostStatus::Global::WARN] || 0,
34
+ critical: counter[HostStatus::Global::ERROR] || 0
35
+ }
35
36
  }
36
37
  end
37
38
  end
38
39
 
40
+ def status_managed_hosts_dashboard
41
+ vmware_compute_resources = Foreman::Model::Vmware.unscoped.all
42
+
43
+ @errors = {}
44
+
45
+ # NOTE The call to ComputeResource#vms may slow things down
46
+ vms_by_compute_resource_id = vmware_compute_resources.each_with_object({}) do |cr, memo|
47
+ memo[cr.id] = cr.vms.all
48
+ rescue StandardError => e
49
+ @errors[cr.name] = e.message
50
+ Foreman::Logging.exception("Failed to load VMs from compute resource #{cr.name}", e)
51
+ end
52
+
53
+ # Get all VM UUIDs found in any of the compute resources
54
+ all_vm_uuids = vms_by_compute_resource_id.values.flatten.group_by(&:id).keys
55
+
56
+ # Map all VM UUIDs to all compute resources that have access to this VM
57
+ @vm_compute_resource_mapping = all_vm_uuids.each_with_object({}) do |uuid, obj|
58
+ cr_ids = vms_by_compute_resource_id.select { |_cr_id, vms| vms.find { |vm| vm.id == uuid } }.keys
59
+ obj[uuid] = vmware_compute_resources.select { |cr| cr_ids.include?(cr.id) }
60
+ end
61
+
62
+ @missing_hosts = []
63
+ @wrong_hosts = []
64
+ @more_than_one_hosts = []
65
+
66
+ Host::Managed.authorized(:view_hosts, Host)
67
+ .includes(:compute_resource)
68
+ .where(compute_resource: vmware_compute_resources)
69
+ .try { |query| params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
70
+ .each do |host|
71
+
72
+ compute_resources = @vm_compute_resource_mapping[host.uuid]
73
+
74
+ if compute_resources.empty?
75
+ # VM is not found on any compute resource, vSphere does not have the vm uuid
76
+ @missing_hosts << host
77
+ elsif compute_resources.count > 1
78
+ # The vm uuid is found on more than one compute resource
79
+ @more_than_one_hosts << host
80
+ elsif host.compute_resource_id != compute_resources.first.id
81
+ # The host is associated to a wrong compute resource
82
+ @wrong_hosts << host
83
+ end
84
+ end
85
+
86
+ @compute_resource_authorizer = Authorizer.new(User.current, collection: vmware_compute_resources)
87
+ @host_authorizer = Authorizer.new(User.current)
88
+ end
89
+
90
+ # ajax method
91
+ def status_hosts
92
+ @status = HostStatus.find_wreckingball_status_by_host_association(params.fetch(:status))
93
+
94
+ all_hosts = Host.authorized(:view_hosts, Host)
95
+ .joins(@status.host_association)
96
+ .try { |query| params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
97
+ .includes(@status.host_association, :vmware_facet, :environment)
98
+ .where.not('host_status.status': @status.global_ok_list)
99
+ .preload(:owner)
100
+ .order(:name)
101
+
102
+ @count = all_hosts.size
103
+ @hosts = all_hosts.paginate(page: params.fetch(:page, 1), per_page: params.fetch(:per_page, 100))
104
+
105
+ respond_to do |format|
106
+ format.json do
107
+ Rabl::Renderer.json(@hosts, 'foreman_wreckingball/hosts/status_hosts',
108
+ view_path: "#{ForemanWreckingball::Engine.root}/app/views",
109
+ scope: self)
110
+ end
111
+ end
112
+ end
113
+
39
114
  def refresh_status_dashboard
40
- flash[:success] = _('Refresh Compute Resource data task was successfully scheduled.')
41
- task = User.as_anonymous_admin do
42
- ::ForemanTasks.async_task(::Actions::ForemanWreckingball::Vmware::ScheduleVmwareSync)
115
+ if ForemanTasks::Task.active.where(label: ::Actions::ForemanWreckingball::Vmware::ScheduleVmwareSync.to_s).empty?
116
+ flash[:success] = _('Refresh Compute Resource data task was successfully scheduled.')
117
+ task = User.as_anonymous_admin do
118
+ ::ForemanTasks.async_task(::Actions::ForemanWreckingball::Vmware::ScheduleVmwareSync)
119
+ end
120
+ redirect_to(foreman_tasks_task_path(task.id))
121
+ else
122
+ flash[:warning] = _('Refresh Compute Resource data task is already running. Please wait for the running task to finish.')
123
+ redirect_to status_dashboard_hosts_path
43
124
  end
44
- redirect_to(foreman_tasks_task_path(task.id))
45
125
  end
46
126
 
47
127
  def schedule_remediate
@@ -49,20 +129,21 @@ module ForemanWreckingball
49
129
  end
50
130
 
51
131
  def submit_remediate
52
- raise Foreman::Exception, 'VMware Status can not be remediated.' unless @status.class.respond_to?(:supports_remediate?) && @status.class.supports_remediate?
53
- task = User.as_anonymous_admin do
54
- triggering = ::ForemanTasks::Triggering.new_from_params(triggering_params)
55
- if triggering.future?
56
- triggering.parse_start_at!
57
- triggering.parse_start_before!
58
- else
59
- triggering.start_at ||= Time.zone.now
60
- end
132
+ return not_found unless @statuses.any?
61
133
 
62
- triggering.trigger(@status.class.remediate_action, @host)
134
+ triggering = ::ForemanTasks::Triggering.new_from_params(triggering_params)
135
+ if triggering.future?
136
+ triggering.parse_start_at!
137
+ triggering.parse_start_before!
138
+ else
139
+ triggering.start_at ||= Time.zone.now
63
140
  end
64
- flash[:success] = _('Remediate VM task for %s was successfully scheduled.') % @host
65
- redirect_to(foreman_tasks_task_path(task.id))
141
+
142
+ task = User.as_anonymous_admin do
143
+ triggering.trigger(::Actions::ForemanWreckingball::BulkRemediate, @statuses)
144
+ end
145
+
146
+ redirect_to foreman_tasks_task_path(task.id)
66
147
  end
67
148
 
68
149
  private
@@ -73,13 +154,32 @@ module ForemanWreckingball
73
154
  end
74
155
  end
75
156
 
76
- def find_status
77
- @status = HostStatus::Status.find_by!(:id => params[:status_id], :host_id => @host.id)
157
+ def statuses_params
158
+ @statuses_params ||= params.permit(:host_association, :owned_only, status_ids: [])
159
+ end
160
+
161
+ def find_statuses
162
+ @statuses = begin
163
+ host_association = statuses_params[:host_association]
164
+ status_class = HostStatus.find_wreckingball_status_by_host_association(host_association)
165
+ if status_class
166
+ Host.authorized(:remediate_vmware_status_hosts, Host)
167
+ .joins(status_class.host_association)
168
+ .includes(status_class.host_association)
169
+ .try { |query| statuses_params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
170
+ .where.not('host_status.status': status_class.global_ok_list)
171
+ .map { |host| host.send(status_class.host_association) }
172
+ else
173
+ HostStatus::Status.includes(:host).where(id: statuses_params[:status_ids]).select do |status|
174
+ User.current.can?(:remediate_vmware_status_hosts, status.host)
175
+ end
176
+ end
177
+ end
78
178
  end
79
179
 
80
180
  def action_permission
81
181
  case params[:action]
82
- when 'status_dashboard'
182
+ when 'status_dashboard', 'status_hosts', 'status_managed_hosts_dashboard'
83
183
  'view'
84
184
  when 'refresh_status_dashboard'
85
185
  'refresh_vmware_status'