foreman_wreckingball 3.2.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/app/assets/javascripts/foreman_wreckingball/modal.js +26 -17
  4. data/app/assets/javascripts/foreman_wreckingball/status_hosts_table.js +34 -2
  5. data/app/assets/javascripts/foreman_wreckingball/status_managed_hosts_dashboard.js +14 -0
  6. data/app/assets/stylesheets/foreman_wreckingball/status_hosts_table.css.scss +7 -0
  7. data/app/assets/stylesheets/foreman_wreckingball/status_managed_hosts_dashboard.css.scss +8 -0
  8. data/app/controllers/foreman_wreckingball/hosts_controller.rb +73 -43
  9. data/app/helpers/foreman_wreckingball/statuses_helper.rb +21 -0
  10. data/app/lib/actions/foreman_wreckingball/bulk_remediate.rb +27 -0
  11. data/app/lib/vsphere_os_identifiers/data.yaml +14 -0
  12. data/app/models/concerns/foreman_wreckingball/host_extensions.rb +4 -0
  13. data/app/models/concerns/foreman_wreckingball/host_status_extensions.rb +1 -1
  14. data/app/models/foreman_wreckingball/spectre_v2_status.rb +1 -1
  15. data/app/models/foreman_wreckingball/vmware_hypervisor_facet.rb +4 -7
  16. data/app/models/setting/wreckingball.rb +7 -3
  17. data/app/services/foreman_wreckingball/vmware_hypervisor_importer.rb +1 -3
  18. data/app/views/foreman_wreckingball/hosts/_hosts.json.rabl +9 -13
  19. data/app/views/foreman_wreckingball/hosts/_status_dashboard_content.erb +2 -0
  20. data/app/views/foreman_wreckingball/hosts/_status_managed_hosts_dashboard_cards.html.erb +16 -0
  21. data/app/views/foreman_wreckingball/hosts/_status_managed_hosts_dashboard_cards_card.html.erb +11 -0
  22. data/app/views/foreman_wreckingball/hosts/_status_row.html.erb +8 -12
  23. data/app/views/foreman_wreckingball/hosts/_status_row_actions.html.erb +22 -0
  24. data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table.html.erb +8 -1
  25. data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table_actions.html.erb +9 -0
  26. data/app/views/foreman_wreckingball/hosts/schedule_remediate.html.erb +44 -26
  27. data/app/views/foreman_wreckingball/hosts/status_dashboard.html.erb +6 -6
  28. data/app/views/foreman_wreckingball/hosts/status_managed_hosts_dashboard.html.erb +121 -28
  29. data/config/routes.rb +2 -4
  30. data/lib/foreman_wreckingball/engine.rb +41 -24
  31. data/lib/foreman_wreckingball/version.rb +1 -1
  32. data/lib/tasks/foreman_vmware_checks_tasks.rake +1 -1
  33. data/test/actions/foreman_wreckingball/bulk_remediate_test.rb +31 -0
  34. data/test/actions/foreman_wreckingball/host/refresh_vmware_facet_test.rb +3 -3
  35. data/test/actions/foreman_wreckingball/host/remediate_hardware_version_test.rb +2 -2
  36. data/test/actions/foreman_wreckingball/host/remediate_spectre_v2_test.rb +2 -2
  37. data/test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb +1 -1
  38. data/test/controllers/foreman_wreckingball/hosts_controller_test.rb +83 -31
  39. data/test/factories/compute_resource.rb +1 -1
  40. data/test/factories/foreman_wreckingball_factories.rb +120 -116
  41. data/test/factories/task.rb +3 -3
  42. data/test/helpers/foreman_wreckingball/status_helper.rb +10 -0
  43. data/test/integration/hosts_status_dashboard_test.rb +15 -15
  44. data/test/integration/hosts_status_managed_hosts_test.rb +30 -18
  45. data/test/integration_test_plugin_helper.rb +1 -0
  46. data/test/models/foreman_wreckingball/vmware_facet_test.rb +5 -5
  47. data/test/models/host_test.rb +2 -2
  48. data/test/test_plugin_helper.rb +2 -0
  49. metadata +20 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de6be68d909a39447b86fc7b8ce9f372cc12c929364910205beac6d8dc244829
4
- data.tar.gz: 2908a912c935764b978d0f094306ecbad458c70c9bed5138051f52d73f83697f
3
+ metadata.gz: 69707f89619ebddac7ddefecc16e1a029f917acff12ebcd5b043f212b71ea1cc
4
+ data.tar.gz: 71db825c47159fb7e7a083b2b0555f32f1ee094239ee93b8d2cf8961d8e3eb5b
5
5
  SHA512:
6
- metadata.gz: d4de761155c5e670000022056211ad3f4064a303914b869c8624f40679b723e6d90d7aa2ba3f156c9f2b535a02a9474cf8c817b7e967f537e7ca8e843a764a84
7
- data.tar.gz: 84e82bf20310a20cde12e50dcacd5fb84ab638e1eabf280aefbf3f1cb3d9a1253cbb57136dbb29ea618e95425380cd296a011f8dc40738b7339837833fd5bfa5
6
+ metadata.gz: dddb50886e2f10627b4d4d0a7058c0daeabb8659f68e9b8c1499d94ad3c764840b536d3bda174f74e179a647507d0172996bf3be4be089721fdafb2e32993b7c
7
+ data.tar.gz: 508e576b9e2568f4804424712d71065e2a957417d32f703923d789040ac4490361a7855aaf278ab33c9b4b35c008f840361dc594c95ceab34a4aa022b7e600b3
data/README.md CHANGED
@@ -11,7 +11,8 @@ This is a plugin for Foreman that adds several VMware related status checks to y
11
11
  | >= 1.15 | ~> 0.1 |
12
12
  | >= 1.16 | ~> 1.0 |
13
13
  | >= 1.17 | ~> 2.0 |
14
- | >= 1.18 | ~> 3.0 |
14
+ | >= 1.21 | ~> 3.0 |
15
+ | >= 2.3 | ~> 4.0 |
15
16
 
16
17
  ## Installation
17
18
 
@@ -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);
@@ -10,7 +10,8 @@ $(document).ready(() => {
10
10
  processing: true,
11
11
  serverSide: true,
12
12
  columnDefs: [
13
- { className: 'ellipsis', targets: [0, 1, 2, 3] }
13
+ { className: 'ellipsis', targets: [1, 2, 3, 4] },
14
+ { width: '10px', targets: 0 }
14
15
  ],
15
16
  ajax: {
16
17
  url: $(element).data('hosts-url'),
@@ -26,13 +27,23 @@ $(document).ready(() => {
26
27
  dataSrc: (json) => {
27
28
  return json.data.map((e) => {
28
29
  let row = [
30
+ `<input name='status-id' type='checkbox' value='${e.status.id}' data-remediate='${!!e.remediate}' >`,
29
31
  `<a href="${e.path}">${e.name}</a>`,
30
32
  `<span class="${e.status.icon_class}"></span><span class="${e.status.status_class}">${e.status.label}</span>`,
31
33
  (e.owner || {}).name || '',
32
34
  (e.environment || {}).name || ''
33
35
  ];
34
36
  if(e.remediate) {
35
- row.push(`<span class="btn btn-sm btn-default"><a data-title="${e.remediate.title}" data-submit-class="btn-danger" onclick="show_modal(this); return false;" data-id="aid_wreckingball_hosts_${e.name}_schedule_remediate" href="${e.remediate.path}">${e.remediate.label}</a></span>`);
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>`);
36
47
  } else {
37
48
  row.push(null);
38
49
  }
@@ -44,6 +55,27 @@ $(document).ready(() => {
44
55
  $(element).on('error.dt', (_, settings) => {
45
56
  $(settings.nTable).closest('.status-hosts-container').addClass('ajax-error');
46
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
+ });
47
79
  });
48
80
  });
49
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
+ });
@@ -11,3 +11,10 @@ div.status-hosts-container.ajax-error div.dataTables_wrapper,
11
11
  div.status-hosts-container.ajax-error p {
12
12
  display: none;
13
13
  }
14
+
15
+ table.status-hosts.hide-puppet-environment {
16
+ th:nth-child(5),
17
+ td:nth-child(5) {
18
+ display: none;
19
+ }
20
+ }
@@ -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
+ }
@@ -4,16 +4,11 @@ module ForemanWreckingball
4
4
  class HostsController < ::HostsController
5
5
  include ::ForemanTasks::Concerns::Parameters::Triggering
6
6
  include ::HostsHelper
7
- if Gem::Version.new(SETTINGS[:version].short) < Gem::Version.new('1.20')
8
- include ::ApplicationHelper
9
- else
10
- include ::AuthorizeHelper
11
- end
7
+ include ::AuthorizeHelper
12
8
 
13
9
  AJAX_REQUESTS = [:status_hosts].freeze
14
10
  before_action :ajax_request, :only => AJAX_REQUESTS
15
- before_action :find_resource, :only => [:submit_remediate, :schedule_remediate]
16
- before_action :find_status, :only => [:submit_remediate, :schedule_remediate]
11
+ before_action :find_statuses, :only => [:schedule_remediate, :submit_remediate]
17
12
 
18
13
  def status_dashboard
19
14
  @newest_data = Host.authorized(:view_hosts).joins(:vmware_facet).maximum('vmware_facets.updated_at')
@@ -43,48 +38,63 @@ module ForemanWreckingball
43
38
  end
44
39
 
45
40
  def status_managed_hosts_dashboard
46
- @hosts = Host::Managed.authorized(:view_hosts, Host)
47
- .try { |query| params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
41
+ vmware_compute_resources = Foreman::Model::Vmware.unscoped.all
48
42
 
49
- compute_resources = ComputeResource.where(:type => 'Foreman::Model::Vmware')
43
+ @errors = {}
50
44
 
51
- # get all vms by compute resource id
52
- vms_by_compute_resource_id = {}
53
45
  # NOTE The call to ComputeResource#vms may slow things down
54
- compute_resources.each { |cr| vms_by_compute_resource_id[cr.id] = cr.vms(eager_loading: true) }
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
55
52
 
56
- vms_by_uuid = vms_by_compute_resource_id.values.flatten.group_by(&:uuid)
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
57
55
 
58
- # Find all hosts with duplicate VMs
59
- @duplicate_vms = vms_by_uuid.select { |_uuid, vms| vms.size > 1 }
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
60
61
 
61
62
  @missing_hosts = []
62
- @different_hosts = []
63
+ @wrong_hosts = []
64
+ @more_than_one_hosts = []
63
65
 
64
- @hosts.each do |host|
65
- next unless host.compute_resource_id
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|
66
71
 
67
- # find the compute resource id of the host in the vm map
68
- cr_id, _vms = vms_by_compute_resource_id.find { |_cr_id, vms| vms.find { |vm| vm.uuid == host.uuid } }
72
+ compute_resources = @vm_compute_resource_mapping[host.uuid]
69
73
 
70
- if cr_id.nil?
71
- # No compute resource id is found, vSphere does not have the vm uuid
74
+ if compute_resources.empty?
75
+ # VM is not found on any compute resource, vSphere does not have the vm uuid
72
76
  @missing_hosts << host
73
- elsif cr_id != host.compute_resource_id
74
- # The host uuid is found in a different compute resource
75
- @different_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
76
83
  end
77
84
  end
85
+
86
+ @compute_resource_authorizer = Authorizer.new(User.current, collection: vmware_compute_resources)
87
+ @host_authorizer = Authorizer.new(User.current)
78
88
  end
79
89
 
80
90
  # ajax method
81
91
  def status_hosts
82
- @status = HostStatus.find_wreckingball_status_by_host_association(params.fetch(:status).to_sym)
92
+ @status = HostStatus.find_wreckingball_status_by_host_association(params.fetch(:status))
83
93
 
84
94
  all_hosts = Host.authorized(:view_hosts, Host)
85
95
  .joins(@status.host_association)
86
96
  .try { |query| params[:owned_only] ? query.owned_by_current_user_or_group_with_current_user : query }
87
- .includes(@status.host_association, :vmware_facet, :environment)
97
+ .includes([*(:environment if Host::Managed.reflect_on_environment?), @status.host_association, :vmware_facet])
88
98
  .where.not('host_status.status': @status.global_ok_list)
89
99
  .preload(:owner)
90
100
  .order(:name)
@@ -119,20 +129,21 @@ module ForemanWreckingball
119
129
  end
120
130
 
121
131
  def submit_remediate
122
- raise Foreman::Exception, _('VMware Status can not be remediated.') unless @status.class.respond_to?(:supports_remediate?) && @status.class.supports_remediate?
123
- task = User.as_anonymous_admin do
124
- triggering = ::ForemanTasks::Triggering.new_from_params(triggering_params)
125
- if triggering.future?
126
- triggering.parse_start_at!
127
- triggering.parse_start_before!
128
- else
129
- triggering.start_at ||= Time.zone.now
130
- end
132
+ return not_found unless @statuses.any?
131
133
 
132
- 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
133
140
  end
134
- flash[:success] = _('Remediate VM task for %s was successfully scheduled.') % @host
135
- 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)
136
147
  end
137
148
 
138
149
  private
@@ -143,13 +154,32 @@ module ForemanWreckingball
143
154
  end
144
155
  end
145
156
 
146
- def find_status
147
- @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
148
178
  end
149
179
 
150
180
  def action_permission
151
181
  case params[:action]
152
- when 'status_dashboard', 'status_hosts'
182
+ when 'status_dashboard', 'status_hosts', 'status_managed_hosts_dashboard'
153
183
  'view'
154
184
  when 'refresh_status_dashboard'
155
185
  'refresh_vmware_status'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanWreckingball
4
+ module StatusesHelper
5
+ def status_actions(host_association, owned_only, supports_remediate)
6
+ actions = []
7
+ actions << display_link_if_authorized(_('Refresh'),
8
+ hash_for_refresh_status_dashboard_hosts_path,
9
+ title: _('Refresh Data'),
10
+ method: :put)
11
+ if supports_remediate
12
+ actions << display_link_if_authorized(_('Remediate All'),
13
+ hash_for_schedule_remediate_hosts_path,
14
+ 'data-host-association': host_association,
15
+ 'data-owned-only': owned_only,
16
+ onClick: 'show_modal(this); return false;')
17
+ end
18
+ actions.reject(&:blank?)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Actions
4
+ module ForemanWreckingball
5
+ class BulkRemediate < Actions::Base
6
+ def plan(statuses)
7
+ sequence do
8
+ statuses.group_by(&:class).each do |statuses_klass, statuses_list|
9
+ plan_action(::Actions::BulkAction, statuses_klass.remediate_action, statuses_list.map(&:host)) if statuses_klass.respond_to?(:remediate_action)
10
+ end
11
+ end
12
+ end
13
+
14
+ def run
15
+ # dummy run phase to save input
16
+ end
17
+
18
+ def resource_locks
19
+ :link
20
+ end
21
+
22
+ def humanized_name
23
+ _('Bulk remediate')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -388,6 +388,13 @@ rhel7_64Guest:
388
388
  :name: RedHat
389
389
  :major: 7
390
390
  :since: 5.5
391
+ rhel8_64Guest:
392
+ :description: Red Hat Enterprise Linux 8 (64-bit)
393
+ :architecture: x86_64
394
+ :osfamily: Redhat
395
+ :name: RedHat
396
+ :major: 8
397
+ :since: 6.5
391
398
  sjdsGuest:
392
399
  :description: Sun Java Desktop System
393
400
  sles10Guest:
@@ -426,6 +433,13 @@ sles12_64Guest:
426
433
  :name: SLES
427
434
  :major: 12
428
435
  :since: 5.5
436
+ sles15_64Guest:
437
+ :description: SUSE Linux Enterprise 15 (64-bit)
438
+ :architecture: x86_64
439
+ :osfamily: Suse
440
+ :name: SLES
441
+ :major: 15
442
+ :since: 6.0
429
443
  sles64Guest:
430
444
  :description: SUSE Linux Enterprise 8/9 (64-bit)
431
445
  :architecture: x86_64
@@ -16,6 +16,10 @@ module ForemanWreckingball
16
16
  scope :owned_by_current_user, -> { where(owner_type: 'User', owner_id: User.current.id) }
17
17
  scope :owned_by_group_with_current_user, -> { where(owner_type: 'Usergroup', owner_id: User.current.usergroup_ids_with_parents) }
18
18
  scope :owned_by_current_user_or_group_with_current_user, -> { owned_by_current_user.or(owned_by_group_with_current_user) }
19
+
20
+ def self.reflect_on_environment?
21
+ reflect_on_association(:environment).present?
22
+ end
19
23
  end
20
24
 
21
25
  def action_input_key
@@ -7,7 +7,7 @@ module ForemanWreckingball
7
7
  end
8
8
 
9
9
  def find_wreckingball_status_by_host_association(host_association)
10
- wreckingball_statuses.find { |s| s.host_association == host_association }
10
+ wreckingball_statuses.find { |s| s.host_association.to_s == host_association.to_s }
11
11
  end
12
12
  end
13
13
  end
@@ -72,7 +72,7 @@ module ForemanWreckingball
72
72
  end
73
73
 
74
74
  def required_cpu_features_present?
75
- !(host.vmware_facet.cpu_features & ['cpuid.IBRS', 'cpuid.IBPB', 'cpuid.STIBP']).empty?
75
+ !(host.vmware_facet.cpu_features.map(&:downcase) & ['cpuid.ibrs', 'cpuid.ibpb', 'cpuid.stibp']).empty?
76
76
  end
77
77
  end
78
78
  end
@@ -6,14 +6,11 @@ module ForemanWreckingball
6
6
 
7
7
  validates_lengths_from_database
8
8
 
9
- validates :host, :presence => true, :allow_blank => false
9
+ validates :host, presence: true, allow_blank: false
10
10
 
11
- belongs_to :vmware_cluster, :inverse_of => :vmware_hypervisor_facets, :class_name => 'ForemanWreckingball::VmwareCluster'
12
-
13
- has_one :compute_resource, :inverse_of => :vmware_hypervisor_facets, :through => :vmware_cluster
14
-
15
- has_many :vmware_facets, :class_name => '::ForemanWreckingball::VmwareFacet', :through => :vmware_clusters,
16
- :inverse_of => :vmware_hypervisor_facets
11
+ belongs_to :vmware_cluster, inverse_of: :vmware_hypervisor_facets, class_name: '::ForemanWreckingball::VmwareCluster'
12
+ has_one :compute_resource, inverse_of: :vmware_hypervisor_facets, through: :vmware_cluster
13
+ has_many :vmware_facets, inverse_of: :vmware_hypervisor_facets, through: :vmware_cluster
17
14
 
18
15
  serialize :feature_capabilities, JSON
19
16
 
@@ -2,14 +2,18 @@
2
2
 
3
3
  class Setting
4
4
  class Wreckingball < ::Setting
5
+ def self.default_settings
6
+ [
7
+ set('min_vsphere_hardware_version', N_('Minimum required Hardware version for vSphere VMs'), 13, N_('Hardware version'))
8
+ ]
9
+ end
10
+
5
11
  def self.load_defaults
6
12
  return unless ActiveRecord::Base.connection.table_exists?('settings')
7
13
  return unless super
8
14
 
9
15
  Setting.transaction do
10
- [
11
- set('min_vsphere_hardware_version', N_('Minimum required Hardware version for vSphere VMs'), 13, N_('Hardware version'))
12
- ].compact.each { |s| Setting::Wreckingball.create s.update(category: 'Setting::Wreckingball') }
16
+ default_settings.compact.each { |s| Setting::Wreckingball.create s.update(category: 'Setting::Wreckingball') }
13
17
  end
14
18
 
15
19
  true
@@ -11,7 +11,7 @@ module ForemanWreckingball
11
11
  end
12
12
 
13
13
  def import!
14
- logger.info "Can not determine organization for compute resource #{compute_resource}." if SETTINGS[:organizations_enabled]
14
+ logger.info "Can not determine organization for compute resource #{compute_resource}."
15
15
  compute_resource.refresh_cache
16
16
  compute_resource.vmware_clusters.each do |cluster|
17
17
  import_hypervisors(cluster)
@@ -113,12 +113,10 @@ module ForemanWreckingball
113
113
  end
114
114
 
115
115
  def organization
116
- return unless SETTINGS[:organizations_enabled]
117
116
  compute_resource.organizations.first
118
117
  end
119
118
 
120
119
  def location
121
- return unless SETTINGS[:locations_enabled]
122
120
  compute_resource.locations.first
123
121
  end
124
122
 
@@ -2,14 +2,16 @@
2
2
 
3
3
  collection @hosts
4
4
 
5
- attributes :name
5
+ attributes :id, :name
6
6
 
7
7
  child owner: :owner do
8
8
  attribute :name
9
9
  end
10
10
 
11
- child :environment do
12
- attribute :name
11
+ if Host::Managed.reflect_on_environment?
12
+ child :environment do
13
+ attribute :name
14
+ end
13
15
  end
14
16
 
15
17
  node(:path) { |host| host_path(host) }
@@ -17,6 +19,7 @@ node(:path) { |host| host_path(host) }
17
19
  node(:status) do |host|
18
20
  status = host.public_send(locals[:host_association])
19
21
  {
22
+ id: status.id,
20
23
  label: status.to_label,
21
24
  icon_class: host_global_status_icon_class(status.to_global),
22
25
  status_class: host_global_status_class(status.to_global)
@@ -24,18 +27,11 @@ node(:status) do |host|
24
27
  end
25
28
 
26
29
  node(:remediate, if: lambda do |host|
27
- locals[:supports_remediate] && begin
28
- options = hash_for_schedule_remediate_host_path(id: host,
29
- status_id: host.public_send(locals[:host_association]).id)
30
- .merge(auth_object: host,
31
- permission: :remediate_vmware_status_hosts)
32
- authorized_for(options)
33
- end
34
- end) do |host|
35
- status_id = host.public_send(locals[:host_association]).id
30
+ locals[:supports_remediate] && User.current.can?(:remediate_vmware_status_hosts, host)
31
+ end) do
36
32
  {
37
33
  label: _('Remediate'),
38
34
  title: _('Remediate Host OS'),
39
- path: schedule_remediate_host_path(host, status_id: status_id)
35
+ path: schedule_remediate_hosts_path
40
36
  }
41
37
  end
@@ -24,6 +24,8 @@
24
24
  counter: status[:counter],
25
25
  status: status[:host_association],
26
26
  supports_remediate: status[:supports_remediate],
27
+ host_association: status[:host_association],
28
+ owned_only: params[:owned_only],
27
29
  id: idx
28
30
  }
29
31
  %>
@@ -0,0 +1,16 @@
1
+ <div class='status-managed-hosts-dashboard-cards container-fluid container-cards-pf'>
2
+ <div class='row row-cards-pf'>
3
+ <%= render partial: 'status_managed_hosts_dashboard_cards_card', locals: {
4
+ title: _('Hosts not found in vSphere'),
5
+ count: missing_hosts_count
6
+ } %>
7
+ <%= render partial: 'status_managed_hosts_dashboard_cards_card', locals: {
8
+ title: _('Hosts associated to wrong Compute Resource'),
9
+ count: wrong_hosts_count
10
+ } %>
11
+ <%= render partial: 'status_managed_hosts_dashboard_cards_card', locals: {
12
+ title: _('Hosts found on more than one Compute Resource'),
13
+ count: more_than_one_hosts_count
14
+ } %>
15
+ </div>
16
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class='col-xs-12 col-sm-4'>
2
+ <div class='card-pf card-pf-accented card-pf-aggregate-status'>
3
+ <%= content_tag :h2, title, class: 'card-pf-title' %>
4
+ <div class='card-pf-body'>
5
+ <p class='card-pf-aggregate-status-notifications'>
6
+ <%= content_tag :span, nil, class: "pficon pficon-#{count > 0 ? 'error-circle-o' : 'ok'}" %>
7
+ <%= count if count > 0 %>
8
+ </p>
9
+ </div>
10
+ </div>
11
+ </div>
@@ -3,18 +3,14 @@
3
3
  <div class="list-view-pf-expand">
4
4
  <span class="fa fa-angle-right"></span>
5
5
  </div>
6
- <div class="list-view-pf-actions">
7
- <% if User.current.allowed_to?(hash_for_refresh_status_dashboard_hosts_path) %>
8
- <div class="dropdown pull-right dropdown-kebab-pf">
9
- <button class="btn btn-link dropdown-toggle" type="button" id="dropdownKebabRight<%= id %>" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
10
- <span class="fa fa-ellipsis-v"></span>
11
- </button>
12
- <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownKebabRight<%= id %>">
13
- <li><%= display_link_if_authorized(_('Refresh'), hash_for_refresh_status_dashboard_hosts_path, :title => _('Refresh data'), :method => :put) %></li>
14
- </ul>
15
- </div>
16
- <% end %>
17
- </div>
6
+ <%=
7
+ render :partial => 'status_row_actions', locals: {
8
+ id: id,
9
+ supports_remediate: supports_remediate,
10
+ host_association: host_association,
11
+ owned_only: owned_only
12
+ }
13
+ %>
18
14
  <div class="list-view-pf-main-info">
19
15
  <div class="list-view-pf-left">
20
16
  <span class="pficon list-view-pf-icon-md <%= classes_for_vmware_status_row(counter) %>"></span>