foreman_wreckingball 3.2.0 → 4.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.
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>