foreman_wreckingball 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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