foreman_wreckingball 3.0.1 → 3.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_wreckingball/status_hosts_table.js +49 -0
  3. data/app/assets/stylesheets/foreman_wreckingball/status_hosts_table.css.scss +13 -0
  4. data/app/controllers/foreman_wreckingball/hosts_controller.rb +53 -13
  5. data/app/helpers/concerns/foreman_wreckingball/hosts_helper_extensions.rb +0 -15
  6. data/app/lib/actions/foreman_wreckingball/host/remediate_hardware_version.rb +63 -0
  7. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/mock.rb +13 -0
  8. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/real.rb +7 -0
  9. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/server.rb +14 -0
  10. data/app/models/concerns/foreman_wreckingball/host_extensions.rb +5 -0
  11. data/app/models/foreman_wreckingball/hardware_version_status.rb +62 -0
  12. data/app/models/foreman_wreckingball/spectre_v2_status.rb +2 -2
  13. data/app/models/foreman_wreckingball/tools_status.rb +1 -1
  14. data/app/models/foreman_wreckingball/vmware_facet.rb +9 -0
  15. data/app/models/setting/wreckingball.rb +22 -0
  16. data/app/services/foreman_wreckingball/vmware_cluster_importer.rb +6 -1
  17. data/app/services/foreman_wreckingball/vmware_hypervisor_importer.rb +16 -1
  18. data/app/views/foreman_wreckingball/hosts/_hosts.json.rabl +41 -0
  19. data/app/views/foreman_wreckingball/hosts/_status_dashboard_content.erb +1 -2
  20. data/app/views/foreman_wreckingball/hosts/_status_row.html.erb +8 -43
  21. data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table.html.erb +17 -0
  22. data/app/views/foreman_wreckingball/hosts/status_dashboard.html.erb +2 -0
  23. data/app/views/foreman_wreckingball/hosts/status_hosts.json.rabl +13 -0
  24. data/config/routes.rb +1 -0
  25. data/db/migrate/20181020174609_add_power_state_to_vmware_facets.rb +7 -0
  26. data/db/migrate/20181021111543_add_indexes_to_vmware_hypervisor_facets.rb +8 -0
  27. data/lib/foreman_wreckingball/engine.rb +17 -1
  28. data/lib/foreman_wreckingball/version.rb +1 -1
  29. data/test/actions/foreman_wreckingball/host/refresh_vmware_facet_test.rb +2 -1
  30. data/test/actions/foreman_wreckingball/host/remediate_hardware_version_test.rb +63 -0
  31. data/test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb +3 -1
  32. data/test/controllers/foreman_wreckingball/hosts_controller_test.rb +19 -0
  33. data/test/factories/compute_resource.rb +5 -0
  34. data/test/factories/foreman_wreckingball_factories.rb +15 -0
  35. data/test/factories/host.rb +8 -0
  36. data/test/models/foreman_wreckingball/hardware_version_status_test.rb +88 -0
  37. data/test/models/foreman_wreckingball/tools_status_test.rb +5 -2
  38. data/test/models/foreman_wreckingball/vmware_facet_test.rb +23 -2
  39. data/test/models/host_test.rb +1 -0
  40. data/test/unit/foreman_wreckingball/vmware_hypervisor_importer_test.rb +11 -0
  41. metadata +18 -3
  42. 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: 76ab3d42565e2f65a0fd36a5e1f54c610793f02d8a520cde857dbdb19c3db0c3
4
+ data.tar.gz: 8dacc5958e40ecd78d06e28baeaff904ae5f26965d4eed3d3b56deeb924dbad6
5
5
  SHA512:
6
- metadata.gz: 0e24c4e6c7ad4cd4eb6bb6f6e66a18712bc090fb41f60d0b639448b9763aad0655aa49a4f80206b036b25fc70d9acae8319a5d027becb8f43d6a26263152232a
7
- data.tar.gz: 76271354a6bd79fd6263bca07ffdc8cba779b1be3ad9744f0675bc5b80c4498c214c473d2b7825af3af5f73d0f20def793bceeffcecfd784f8e0d78f2e6c8a20
6
+ metadata.gz: 8eca4ac7802cfdd392505b99e2233f288210246da2b7936a167aa809e26e8696b44a27b6da983fda2548389c88a3dc84c4aaee9cd544e859ff43e2aef6aca41d
7
+ data.tar.gz: a7e4f716a844d628d29abbbd1443c9010b0f543d32fa047d9e4d566fcc6c8c4a29c9988686656dbc10034a5a1e2bd47ffd33131899ece6b2087719309600b1d3
@@ -0,0 +1,49 @@
1
+ $(document).ready(() => {
2
+ $.fn.dataTable.ext.errMode = 'none';
3
+ $('.status-row.list-group-item').one('click', (a, b, c) => {
4
+ $(a.currentTarget).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: [0, 1, 2, 3] }
14
+ ],
15
+ ajax: {
16
+ url: $(element).data('hosts-url'),
17
+ type: 'GET',
18
+ data: (_, oSettings) => {
19
+ const { _iDisplayStart: start, _iDisplayLength: perPage } = oSettings;
20
+ const page = (start / perPage) + 1;
21
+ return {
22
+ page: page || 1,
23
+ per_page: perPage
24
+ };
25
+ },
26
+ dataSrc: (json) => {
27
+ return json.data.map((e) => {
28
+ let row = [
29
+ `<a href="${e.path}">${e.name}</a>`,
30
+ `<span class="${e.status.icon_class}"></span><span class="${e.status.status_class}">${e.status.label}</span>`,
31
+ (e.owner || {}).name || '',
32
+ (e.environment || {}).name || ''
33
+ ];
34
+ 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>`);
36
+ } else {
37
+ row.push(null);
38
+ }
39
+ return row;
40
+ });
41
+ }
42
+ }
43
+ });
44
+ $(element).on('error.dt', (_, settings) => {
45
+ $(settings.nTable).closest('.status-hosts-container').addClass('ajax-error');
46
+ });
47
+ });
48
+ });
49
+ });
@@ -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
+ }
@@ -3,6 +3,15 @@
3
3
  module ForemanWreckingball
4
4
  class HostsController < ::HostsController
5
5
  include ::ForemanTasks::Concerns::Parameters::Triggering
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
12
+
13
+ AJAX_REQUESTS = [:status_hosts].freeze
14
+ before_action :ajax_request, :only => AJAX_REQUESTS
6
15
  before_action :find_resource, :only => [:submit_remediate, :schedule_remediate]
7
16
  before_action :find_status, :only => [:submit_remediate, :schedule_remediate]
8
17
 
@@ -11,31 +20,62 @@ module ForemanWreckingball
11
20
  ToolsStatus,
12
21
  OperatingsystemStatus,
13
22
  CpuHotAddStatus,
14
- SpectreV2Status
23
+ SpectreV2Status,
24
+ HardwareVersionStatus
15
25
  ]
16
26
 
17
27
  @newest_data = Host.authorized(:view_hosts, Host).joins(:vmware_facet).maximum('vmware_facets.updated_at')
18
-
19
28
  @data = statuses.map do |status|
20
29
  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)
30
+ counter = Host.authorized(:view_hosts, Host)
31
+ .joins(host_association)
32
+ .includes(host_association)
33
+ .map { |host| host.public_send(host_association).to_global }
34
+ .group_by { |global_status| global_status }
35
+ .each_with_object({}) { |(global_status, items), hash| hash[global_status] = items.size }
29
36
  {
30
37
  name: status.status_name,
31
- hosts: hosts,
32
38
  description: status.description,
33
- host_association: host_association,
34
- supports_remediate: status.supports_remediate?
39
+ host_association: status.host_association,
40
+ supports_remediate: status.supports_remediate?,
41
+ counter: {
42
+ ok: counter[HostStatus::Global::OK] || 0,
43
+ warning: counter[HostStatus::Global::WARN] || 0,
44
+ critical: counter[HostStatus::Global::ERROR] || 0
45
+ }
35
46
  }
36
47
  end
37
48
  end
38
49
 
50
+ # ajax method
51
+ def status_hosts
52
+ statuses_map = {
53
+ vmware_tools_status_object: ForemanWreckingball::ToolsStatus,
54
+ vmware_operatingsystem_status_object: ForemanWreckingball::OperatingsystemStatus,
55
+ vmware_cpu_hot_add_status_object: ForemanWreckingball::CpuHotAddStatus,
56
+ vmware_spectre_v2_status_object: ForemanWreckingball::SpectreV2Status,
57
+ vmware_hardware_version_status_object: ForemanWreckingball::HardwareVersionStatus
58
+ }
59
+
60
+ @status = statuses_map[params[:status].to_sym]
61
+ all_hosts = Host.authorized(:view_hosts, Host)
62
+ .joins(@status.host_association)
63
+ .includes(@status.host_association, :vmware_facet, :environment)
64
+ .preload(:owner)
65
+ .order(:name)
66
+ @count = all_hosts.count
67
+ @hosts = all_hosts.reject { |h| h.send(@status.host_association).to_global == HostStatus::Global::OK }
68
+ .paginate(page: params.fetch(:page, 1), per_page: params.fetch(:per_page, 100))
69
+
70
+ respond_to do |format|
71
+ format.json do
72
+ Rabl::Renderer.json(@hosts, 'foreman_wreckingball/hosts/status_hosts',
73
+ view_path: "#{ForemanWreckingball::Engine.root}/app/views",
74
+ scope: self)
75
+ end
76
+ end
77
+ end
78
+
39
79
  def refresh_status_dashboard
40
80
  flash[:success] = _('Refresh Compute Resource data task was successfully scheduled.')
41
81
  task = User.as_anonymous_admin do
@@ -9,20 +9,5 @@ module ForemanWreckingball
9
9
  return 'pficon-warning-triangle-o list-view-pf-icon-warning' if (counter[:warning] || 0).positive?
10
10
  'pficon-ok list-view-pf-icon-success'
11
11
  end
12
-
13
- def vmware_status_counter(hosts, status_object)
14
- count = hosts.map do |host|
15
- host.public_send(status_object).to_global
16
- end.group_by do |status|
17
- status
18
- end.each_with_object({}) do |(status, items), hash|
19
- hash[status] = items.size
20
- end
21
- {
22
- :ok => count[HostStatus::Global::OK] || 0,
23
- :warning => count[HostStatus::Global::WARN] || 0,
24
- :critical => count[HostStatus::Global::ERROR] || 0
25
- }
26
- end
27
12
  end
28
13
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Actions
4
+ module ForemanWreckingball
5
+ module Host
6
+ class RemediateHardwareVersion < Actions::EntryAction
7
+ middleware.use Actions::Middleware::KeepCurrentUser
8
+
9
+ def delay(delay_options, host)
10
+ action_subject(host)
11
+ super(delay_options, host)
12
+ end
13
+
14
+ def plan(host)
15
+ action_subject(host)
16
+ plan_self
17
+ end
18
+
19
+ def run
20
+ host = ::Host.find(input[:host][:id])
21
+
22
+ output[:old_hardware_version] = host.vmware_facet.hardware_version
23
+
24
+ initially_powered_on = host.power.ready?
25
+ output[:initially_powered_on] = initially_powered_on
26
+
27
+ vm = host.compute_object
28
+
29
+ if initially_powered_on
30
+ vm.stop
31
+ vm.wait_for { power_state == 'poweredOff' }
32
+ fail _('Could not shut down VM.') if vm.ready?
33
+ end
34
+
35
+ vm.vm_upgrade_hardware
36
+
37
+ state = host.refresh_vmware_facet!
38
+ output[:state] = state
39
+ output[:new_hardware_version] = host.vmware_facet.hardware_version
40
+ ensure
41
+ vm.start if vm && initially_powered_on
42
+ end
43
+
44
+ def humanized_name
45
+ _('Upgrade VM Hardware Version')
46
+ end
47
+
48
+ def humanized_input
49
+ input[:host] && input[:host][:name]
50
+ end
51
+
52
+ def append_error(message)
53
+ output[:errors] ||= []
54
+ output[:errors] << message
55
+ end
56
+
57
+ def rescue_strategy
58
+ Dynflow::Action::Rescue::Skip
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ module FogExtensions
2
+ module ForemanWreckingball
3
+ module Vsphere
4
+ module Mock
5
+ extend ActiveSupport::Concern
6
+
7
+ def vm_upgrade_hardware(version: nil, instance_uuid:)
8
+ { 'task_state' => 'success' }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -19,6 +19,13 @@ module FogExtensions
19
19
  included do
20
20
  prepend Overrides
21
21
  end
22
+
23
+ def vm_upgrade_hardware(version: nil, instance_uuid:)
24
+ vm_mob_ref = get_vm_ref(instance_uuid)
25
+ task = vm_mob_ref.UpgradeVM_Task(version: version)
26
+ task.wait_for_completion
27
+ { 'task_state' => task.info.state }
28
+ end
22
29
  end
23
30
  end
24
31
  end
@@ -0,0 +1,14 @@
1
+ module FogExtensions
2
+ module ForemanWreckingball
3
+ module Vsphere
4
+ module Server
5
+ extend ActiveSupport::Concern
6
+
7
+ def vm_upgrade_hardware(version: nil)
8
+ requires :instance_uuid
9
+ service.vm_upgrade_hardware(instance_uuid: instance_uuid, version: version)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -26,6 +26,11 @@ module ForemanWreckingball
26
26
  :foreign_key => 'host_id',
27
27
  :inverse_of => :host,
28
28
  :dependent => :destroy
29
+ has_one :vmware_hardware_version_status_object,
30
+ :class_name => 'ForemanWreckingball::HardwareVersionStatus',
31
+ :foreign_key => 'host_id',
32
+ :inverse_of => :host,
33
+ :dependent => :destroy
29
34
  end
30
35
 
31
36
  def action_input_key
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanWreckingball
4
+ class HardwareVersionStatus < ::HostStatus::Status
5
+ OK = 0
6
+ OUTOFDATE = 1
7
+
8
+ def self.status_name
9
+ N_('vSphere Hardware Version')
10
+ end
11
+
12
+ def self.host_association
13
+ :vmware_hardware_version_status_object
14
+ end
15
+
16
+ def self.description
17
+ N_('In order to use recent vSphere features, the VM must use a recent virtual hardware version.')
18
+ end
19
+
20
+ def self.supports_remediate?
21
+ true
22
+ end
23
+
24
+ def self.dangerous_remediate?
25
+ true
26
+ end
27
+
28
+ def self.remediate_action
29
+ ::Actions::ForemanWreckingball::Host::RemediateHardwareVersion
30
+ end
31
+
32
+ def to_status(_options = {})
33
+ recent_hw_version? ? OK : OUTOFDATE
34
+ end
35
+
36
+ def to_global(_options = {})
37
+ case status
38
+ when OUTOFDATE
39
+ HostStatus::Global::WARN
40
+ else
41
+ HostStatus::Global::OK
42
+ end
43
+ end
44
+
45
+ def to_label(_options = {})
46
+ case status
47
+ when OUTOFDATE
48
+ N_('Out of date')
49
+ else
50
+ N_('OK')
51
+ end
52
+ end
53
+
54
+ def relevant?(_options = {})
55
+ host && host&.vmware_facet && host.vmware_facet.hardware_version.present?
56
+ end
57
+
58
+ def recent_hw_version?
59
+ host.vmware_facet.hardware_version.to_s.gsub(/^vmx-/, '').to_i >= Setting[:min_vsphere_hardware_version]
60
+ end
61
+ end
62
+ end
@@ -44,7 +44,7 @@ module ForemanWreckingball
44
44
  end
45
45
 
46
46
  def relevant?(_options = {})
47
- host && host&.vmware_facet && host.vmware_facet.cpu_features.any?
47
+ host && host&.vmware_facet && host.vmware_facet.hardware_version.present? && host.vmware_facet.cpu_features.any?
48
48
  end
49
49
 
50
50
  def guest_mitigation_enabled?
@@ -52,7 +52,7 @@ module ForemanWreckingball
52
52
  end
53
53
 
54
54
  def recent_hw_version?
55
- host.vmware_facet.hardware_version.gsub(/^vmx-/, '').to_i >= 9
55
+ host.vmware_facet.hardware_version.to_s.gsub(/^vmx-/, '').to_i >= 9
56
56
  end
57
57
 
58
58
  def required_cpu_features_present?
@@ -21,7 +21,7 @@ module ForemanWreckingball
21
21
  end
22
22
 
23
23
  def to_status(_options = {})
24
- return POWERDOWN unless host.supports_power_and_running?
24
+ return POWERDOWN unless host.supports_power? && host.vmware_facet.vm_ready?
25
25
  VmwareFacet.tools_states[host.vmware_facet.tools_state]
26
26
  end
27
27
 
@@ -8,6 +8,9 @@ module ForemanWreckingball
8
8
 
9
9
  enum :tools_state => VALID_GUEST_STATUSES
10
10
 
11
+ VALID_POWER_STATES = [:poweredOff, :poweredOn, :suspended].freeze
12
+ enum :power_state => VALID_POWER_STATES
13
+
11
14
  belongs_to :vmware_cluster, :class_name => '::ForemanWreckingball::VmwareCluster',
12
15
  :inverse_of => :vmware_facets
13
16
 
@@ -43,6 +46,7 @@ module ForemanWreckingball
43
46
  corespersocket: vm.corespersocket,
44
47
  memory_mb: vm.memory_mb,
45
48
  tools_state: vm.tools_state,
49
+ power_state: vm.power_state,
46
50
  guest_id: vm.guest_id,
47
51
  cpu_hot_add: vm.cpuHotAddEnabled,
48
52
  hardware_version: vm.hardware_version,
@@ -57,9 +61,14 @@ module ForemanWreckingball
57
61
  host.get_status(::ForemanWreckingball::CpuHotAddStatus).refresh!
58
62
  host.get_status(::ForemanWreckingball::OperatingsystemStatus).refresh!
59
63
  host.get_status(::ForemanWreckingball::SpectreV2Status).refresh!
64
+ host.get_status(::ForemanWreckingball::HardwareVersionStatus).refresh!
60
65
  host.refresh_global_status!
61
66
  end
62
67
 
68
+ def vm_ready?
69
+ power_state == 'poweredOn'
70
+ end
71
+
63
72
  private
64
73
 
65
74
  def raw_vm_object
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Setting
4
+ class Wreckingball < ::Setting
5
+ def self.load_defaults
6
+ return unless ActiveRecord::Base.connection.table_exists?('settings')
7
+ return unless super
8
+
9
+ 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') }
13
+ end
14
+
15
+ true
16
+ end
17
+
18
+ def self.humanized_category
19
+ N_('Wreckingball')
20
+ end
21
+ end
22
+ end