foreman_wreckingball 3.0.0 → 3.0.1

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 (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_wreckingball/hosts_controller.rb +2 -1
  3. data/app/helpers/foreman_wreckingball/hypervisors_helper.rb +15 -0
  4. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/host.rb +1 -26
  5. data/app/lib/fog_extensions/foreman_wreckingball/vsphere/real.rb +7 -67
  6. data/app/models/concerns/foreman_wreckingball/compute_resource_extensions.rb +5 -0
  7. data/app/models/concerns/foreman_wreckingball/host_extensions.rb +5 -0
  8. data/app/models/foreman_wreckingball/spectre_v2_status.rb +62 -0
  9. data/app/models/foreman_wreckingball/vmware_facet.rb +24 -9
  10. data/app/models/foreman_wreckingball/vmware_hypervisor_facet.rb +8 -0
  11. data/app/services/foreman_wreckingball/debris_collector.rb +249 -0
  12. data/app/services/foreman_wreckingball/vmware_hypervisor_importer.rb +2 -1
  13. data/app/views/compute_resources/_hypervisors_tab.html.erb +22 -0
  14. data/db/migrate/20180504135345_add_cpu_features_to_vmware_facets.rb +7 -0
  15. data/db/migrate/20180504135515_add_hardware_version_to_vmware_facets.rb +7 -0
  16. data/db/migrate/20180614105545_add_feature_capabilities_to_vmware_hypervisor_facets.rb +7 -0
  17. data/lib/foreman_wreckingball/engine.rb +9 -1
  18. data/lib/foreman_wreckingball/version.rb +1 -1
  19. data/test/actions/foreman_wreckingball/host/refresh_vmware_facet_test.rb +7 -2
  20. data/test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb +1 -0
  21. data/test/controllers/compute_resources_controller_test.rb +19 -0
  22. data/test/factories/foreman_wreckingball_factories.rb +105 -0
  23. data/test/models/compute_resource_test.rb +2 -0
  24. data/test/models/foreman_wreckingball/spectre_v2_status_test.rb +113 -0
  25. data/test/models/foreman_wreckingball/vmware_facet_test.rb +56 -0
  26. data/test/models/foreman_wreckingball/vmware_hypervisor_facet_test.rb +27 -0
  27. data/test/models/host_test.rb +1 -0
  28. metadata +15 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91f8e9b4e8ec69fe49517364365ff0ea5e46435998461cd967718539c9e69546
4
- data.tar.gz: 444176c10728b0457d50ab41adf8a923d66d30f383bb0564e9b172973bace129
3
+ metadata.gz: d61b28b92f7f4ed29367841c4bec7b80ea38cc4610daf6e4ec78f1181ac8b5c9
4
+ data.tar.gz: 89f264e68c658e9135a07f761584f23e51b543ba8264bb4a0ead2aef132449b5
5
5
  SHA512:
6
- metadata.gz: 21d17ab1949782bf8a6b0f2c0f2e5d7d4fa43d8c25d93112b3ac3e1412f16b5418357b82c05643248fff7c57671bbbe31bdfc04c11559b34db5d7351f90e6514
7
- data.tar.gz: 489a9097ef263bc2e1eb4cff7d0ae695e1e53fd7462066ad8f06be48efc7aedadc5b013287198a4350f9c22908c1d99f9abe78ba46dd11bd254b8d3b9b545bd0
6
+ metadata.gz: 0e24c4e6c7ad4cd4eb6bb6f6e66a18712bc090fb41f60d0b639448b9763aad0655aa49a4f80206b036b25fc70d9acae8319a5d027becb8f43d6a26263152232a
7
+ data.tar.gz: 76271354a6bd79fd6263bca07ffdc8cba779b1be3ad9744f0675bc5b80c4498c214c473d2b7825af3af5f73d0f20def793bceeffcecfd784f8e0d78f2e6c8a20
@@ -10,7 +10,8 @@ module ForemanWreckingball
10
10
  statuses = [
11
11
  ToolsStatus,
12
12
  OperatingsystemStatus,
13
- CpuHotAddStatus
13
+ CpuHotAddStatus,
14
+ SpectreV2Status
14
15
  ]
15
16
 
16
17
  @newest_data = Host.authorized(:view_hosts, Host).joins(:vmware_facet).maximum('vmware_facets.updated_at')
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanWreckingball
4
+ module HypervisorsHelper
5
+ def wreckingball_spectre_v2_status(vmware_hypervisor_facet)
6
+ if vmware_hypervisor_facet.feature_capabilities.blank?
7
+ icon_text('unknown', '', kind: 'pficon', title: _('N/A'))
8
+ elsif vmware_hypervisor_facet.provides_spectre_features?
9
+ icon_text('ok', '', kind: 'pficon', title: _('CPU-Features are present on this host.'))
10
+ else
11
+ icon_text('error-circle-o', '', kind: 'pficon', title: _('Required CPU features are missing. This host is most likely vulnerable.'))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,33 +4,8 @@ module FogExtensions
4
4
  module Host
5
5
  extend ActiveSupport::Concern
6
6
 
7
- module Overrides
8
- def vm_ids
9
- attributes[:vm_ids] = attributes[:vm_ids].call if attributes[:vm_ids].is_a?(Proc)
10
- attributes[:vm_ids]
11
- end
12
- end
13
-
14
7
  included do
15
- prepend Overrides
16
-
17
- attribute :cpu_cores
18
- attribute :cpu_sockets
19
- attribute :cpu_threads
20
- attribute :memory
21
- attribute :uuid
22
- attribute :model
23
- attribute :vendor
24
- attribute :ipaddress
25
- attribute :ipaddress6
26
- attribute :product_name
27
- attribute :product_version
28
- attribute :hostname
29
- attribute :domainname
30
- end
31
-
32
- def memory_mb
33
- memory / 1024 / 1024
8
+ attribute :feature_capabilities
34
9
  end
35
10
  end
36
11
  end
@@ -5,80 +5,20 @@ module FogExtensions
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module Overrides
8
- def list_hosts(filters = {})
9
- cluster = get_raw_cluster(filters[:cluster], filters[:datacenter])
10
-
11
- results = property_collector_results(host_system_filter_spec(cluster))
8
+ def host_system_attribute_mapping
9
+ super.merge(
10
+ feature_capabilities: 'config.featureCapability'
11
+ )
12
+ end
12
13
 
13
- results.map do |host|
14
- hsh = map_attrs_to_hash(host, host_system_attribute_mapping)
15
- hsh.merge(
16
- datacenter: filters[:datacenter],
17
- cluster: filters[:cluster],
18
- ipaddress: (host['config.network.vnic'].first.spec.ip.ipAddress rescue nil),
19
- ipaddress6: (host['config.network.vnic'].first.spec.ip.ipV6Config.ipV6Address.first.ipAddress rescue nil),
20
- vm_ids: Proc.new { host['vm'].map {|vm| vm.config.instanceUuid rescue nil} }
21
- )
22
- end
14
+ def list_hosts(filters = {})
15
+ super.map { |h| h[:feature_capabilities] = h[:feature_capabilities].map(&:key); h }
23
16
  end
24
17
  end
25
18
 
26
19
  included do
27
20
  prepend Overrides
28
21
  end
29
-
30
- protected
31
-
32
- def map_attrs_to_hash(obj, attribute_mapping)
33
- attribute_mapping.each_with_object({}) do |(k, v), hsh|
34
- hsh[k] = obj[v]
35
- end
36
- end
37
-
38
- def property_collector_results(filter_spec)
39
- property_collector = connection.serviceContent.propertyCollector
40
- property_collector.RetrieveProperties(:specSet => [filter_spec])
41
- end
42
-
43
- def compute_resource_host_traversal_spec
44
- RbVmomi::VIM.TraversalSpec(
45
- :name => 'computeResourceHostTraversalSpec',
46
- :type => 'ComputeResource',
47
- :path => 'host',
48
- :skip => false
49
- )
50
- end
51
-
52
- def host_system_filter_spec(obj)
53
- RbVmomi::VIM.PropertyFilterSpec(
54
- :objectSet => [
55
- :obj => obj,
56
- :selectSet => [
57
- compute_resource_host_traversal_spec
58
- ]
59
- ],
60
- :propSet => [
61
- { :type => 'HostSystem', :pathSet => host_system_attribute_mapping.values + ['config.network.vnic', 'vm'] }
62
- ]
63
- )
64
- end
65
-
66
- def host_system_attribute_mapping
67
- {
68
- name: 'name',
69
- cpu_cores: 'hardware.cpuInfo.numCpuCores',
70
- cpu_sockets: 'hardware.cpuInfo.numCpuPackages',
71
- cpu_threads: 'hardware.cpuInfo.numCpuThreads',
72
- memory: 'hardware.memorySize',
73
- uuid: 'hardware.systemInfo.uuid',
74
- model: 'hardware.systemInfo.model',
75
- vendor: 'hardware.systemInfo.vendor',
76
- product_name: 'summary.config.product.name',
77
- product_version: 'summary.config.product.version',
78
- hostname: 'config.network.dnsConfig.hostName',
79
- domainname: 'config.network.dnsConfig.domainName'
80
- }
81
- end
82
22
  end
83
23
  end
84
24
  end
@@ -8,6 +8,11 @@ module ForemanWreckingball
8
8
  included do
9
9
  has_many :vmware_clusters, :class_name => 'ForemanWreckingball::VmwareCluster',
10
10
  :inverse_of => :compute_resource, :dependent => :destroy
11
+
12
+ has_many :vmware_hypervisor_facets, :class_name => '::ForemanWreckingball::VmwareHypervisorFacet', :through => :vmware_clusters,
13
+ :inverse_of => :compute_resource
14
+
15
+ has_many :hypervisor_hosts, :class_name => 'Host::Managed', :through => :vmware_hypervisor_facets, :source => :host, :inverse_of => :compute_resource
11
16
  end
12
17
 
13
18
  def action_input_key
@@ -21,6 +21,11 @@ module ForemanWreckingball
21
21
  :foreign_key => 'host_id',
22
22
  :inverse_of => :host,
23
23
  :dependent => :destroy
24
+ has_one :vmware_spectre_v2_status_object,
25
+ :class_name => 'ForemanWreckingball::SpectreV2Status',
26
+ :foreign_key => 'host_id',
27
+ :inverse_of => :host,
28
+ :dependent => :destroy
24
29
  end
25
30
 
26
31
  def action_input_key
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanWreckingball
4
+ class SpectreV2Status < ::HostStatus::Status
5
+ ENABLED = 0
6
+ MISSING = 1
7
+
8
+ def self.status_name
9
+ N_('Spectre v2 Guest Mitigation Enabled')
10
+ end
11
+
12
+ def self.host_association
13
+ :vmware_spectre_v2_status_object
14
+ end
15
+
16
+ def self.description
17
+ N_('In order to use hardware based branch target injection mitigation within virtual machines, Hypervisor-Assisted Guest Mitigation must be enabled.')
18
+ end
19
+
20
+ def self.supports_remediate?
21
+ false
22
+ end
23
+
24
+ def to_status(_options = {})
25
+ guest_mitigation_enabled? ? ENABLED : MISSING
26
+ end
27
+
28
+ def to_global(_options = {})
29
+ case status
30
+ when MISSING
31
+ HostStatus::Global::ERROR
32
+ else
33
+ HostStatus::Global::OK
34
+ end
35
+ end
36
+
37
+ def to_label(_options = {})
38
+ case status
39
+ when MISSING
40
+ N_('Guest Mitigation Missing')
41
+ else
42
+ N_('Guest Mitigation Enabled')
43
+ end
44
+ end
45
+
46
+ def relevant?(_options = {})
47
+ host && host&.vmware_facet && host.vmware_facet.cpu_features.any?
48
+ end
49
+
50
+ def guest_mitigation_enabled?
51
+ recent_hw_version? && required_cpu_features_present?
52
+ end
53
+
54
+ def recent_hw_version?
55
+ host.vmware_facet.hardware_version.gsub(/^vmx-/, '').to_i >= 9
56
+ end
57
+
58
+ def required_cpu_features_present?
59
+ !(host.vmware_facet.cpu_features & ['cpuid.IBRS', 'cpuid.IBPB', 'cpuid.STIBP']).empty?
60
+ end
61
+ end
62
+ end
@@ -19,6 +19,8 @@ module ForemanWreckingball
19
19
 
20
20
  validates :host, :presence => true, :allow_blank => false
21
21
 
22
+ serialize :cpu_features, JSON
23
+
22
24
  def tools_state_label
23
25
  case tools_state.to_sym
24
26
  when :toolsNotInstalled
@@ -35,22 +37,35 @@ module ForemanWreckingball
35
37
  def refresh!
36
38
  vm = host.compute_object
37
39
  return unless vm
38
- update(
39
- :vmware_cluster => ::ForemanWreckingball::VmwareCluster.find_by(:name => vm.cluster, :compute_resource => host.compute_resource),
40
- :cpus => vm.cpus,
41
- :corespersocket => vm.corespersocket,
42
- :memory_mb => vm.memory_mb,
43
- :tools_state => vm.tools_state,
44
- :guest_id => vm.guest_id,
45
- :cpu_hot_add => vm.cpuHotAddEnabled
46
- )
40
+ data_for_update = {
41
+ vmware_cluster: ::ForemanWreckingball::VmwareCluster.find_by(name: vm.cluster, compute_resource: host.compute_resource),
42
+ cpus: vm.cpus,
43
+ corespersocket: vm.corespersocket,
44
+ memory_mb: vm.memory_mb,
45
+ tools_state: vm.tools_state,
46
+ guest_id: vm.guest_id,
47
+ cpu_hot_add: vm.cpuHotAddEnabled,
48
+ hardware_version: vm.hardware_version,
49
+ cpu_features: []
50
+ }
51
+ data_for_update[:cpu_features] = raw_vm_object.runtime.featureRequirement.map(&:key) if vm.ready?
52
+ update(data_for_update)
47
53
  end
48
54
 
49
55
  def refresh_statuses
50
56
  host.get_status(::ForemanWreckingball::ToolsStatus).refresh!
51
57
  host.get_status(::ForemanWreckingball::CpuHotAddStatus).refresh!
52
58
  host.get_status(::ForemanWreckingball::OperatingsystemStatus).refresh!
59
+ host.get_status(::ForemanWreckingball::SpectreV2Status).refresh!
53
60
  host.refresh_global_status!
54
61
  end
62
+
63
+ private
64
+
65
+ def raw_vm_object
66
+ instance_uuid = host.compute_object.try(:instance_uuid)
67
+ return unless instance_uuid
68
+ host.compute_resource.send(:client).send(:get_vm_ref, instance_uuid)
69
+ end
55
70
  end
56
71
  end
@@ -10,11 +10,19 @@ module ForemanWreckingball
10
10
 
11
11
  belongs_to :vmware_cluster, :inverse_of => :vmware_hypervisor_facets, :class_name => 'ForemanWreckingball::VmwareCluster'
12
12
 
13
+ has_one :compute_resource, :inverse_of => :vmware_hypervisor_facets, :through => :vmware_cluster
14
+
13
15
  has_many :vmware_facets, :class_name => '::ForemanWreckingball::VmwareFacet', :through => :vmware_clusters,
14
16
  :inverse_of => :vmware_hypervisor_facets
15
17
 
18
+ serialize :feature_capabilities, JSON
19
+
16
20
  def self.sanitize_name(name)
17
21
  name.tr('_', '-').chomp('.').downcase
18
22
  end
23
+
24
+ def provides_spectre_features?
25
+ !((feature_capabilities || []) & ['cpuid.IBRS', 'cpuid.IBPB', 'cpuid.STIBP']).empty?
26
+ end
19
27
  end
20
28
  end
@@ -0,0 +1,249 @@
1
+ require 'rbvmomi'
2
+
3
+ module ForemanWreckingball
4
+ class DebrisCollector
5
+
6
+ PROPERTY_MAPPING = {
7
+ :VirtualMachine => {
8
+ mapped: {
9
+ cpus: 'config.hardware.numCPU',
10
+ corespersocket: 'config.hardware.numCoresPerSocket',
11
+ memory_mb: 'config.hardware.memoryMB',
12
+ tools_state: 'guest.toolsStatus',
13
+ guest_id: 'config.guestId',
14
+ cpu_hot_add: 'config.cpuHotAddEnabled',
15
+ hardware_version: 'config.version',
16
+ #cpu_features: ''
17
+ },
18
+ additional: [
19
+ 'name',
20
+ 'config.instanceUuid'
21
+ ]
22
+ },
23
+ :Folder => {
24
+ mapped: {
25
+ name: 'name'
26
+ },
27
+ additional: [
28
+ 'childEntity'
29
+ ]
30
+ },
31
+ }.freeze
32
+
33
+ attr_reader :compute_resource
34
+ attr_accessor :version, :stop_requested
35
+
36
+ delegate :logger, to: ::Rails
37
+
38
+ def initialize(compute_resource:)
39
+ logger.debug "Wreckingball Debris Collector: Initializing."
40
+ @compute_resource = compute_resource
41
+ self.version = ''
42
+ self.stop_requested = false
43
+ end
44
+
45
+
46
+ def run
47
+ logger.debug "Wreckingball Debris Collector: Started."
48
+
49
+ property_filter
50
+
51
+ logger.debug "Wreckingball Debris Collector: Starting initial import."
52
+ initial_refresh
53
+ logger.debug "Wreckingball Debris Collector: Finished initial import."
54
+
55
+ logger.debug "Wreckingball Debris Collector: Finished."
56
+ ensure
57
+ destroy_property_filter
58
+ end
59
+
60
+ def stop
61
+ logger.debug "Wreckingball Debris Collector: Stop requested."
62
+ self.stop_requested = true
63
+ end
64
+
65
+ private
66
+
67
+ def initial_refresh
68
+ monitor_updates
69
+ end
70
+
71
+ def monitor_updates
72
+ begin
73
+ update_set = wait_for_updates
74
+ return version if update_set.nil?
75
+
76
+ self.version = update_set.version
77
+ process_update_set(update_set)
78
+ end while update_set.truncated
79
+ end
80
+
81
+ def process_update_set(update_set)
82
+ property_filter_update = update_set.filterSet.to_a.detect do |update|
83
+ update.filter == property_filter
84
+ end
85
+ return if property_filter_update.nil?
86
+
87
+ object_update_set = property_filter_update.objectSet
88
+ return if object_update_set.blank?
89
+
90
+ logger.debug "Wreckingball Debris Collector: Processing #{object_update_set.count} updates..."
91
+
92
+ process_object_update_set(object_update_set)
93
+
94
+ logger.debug "Wreckingball Debris Collector: Processing #{object_update_set.count} updates... completed."
95
+ end
96
+
97
+ def process_object_update_set(object_update_set)
98
+ object_update_set.each do |object_update|
99
+ process_object_update(object_update)
100
+ end
101
+ end
102
+
103
+ def process_object_update(object_update)
104
+ managed_object = object_update.obj
105
+
106
+ logger.debug "#{object_update.kind} #{object_update.obj.class.wsdl_name}:#{object_update.obj._ref}"
107
+
108
+ case object_update.obj.class.wsdl_name
109
+ when 'VirtualMachine'
110
+ process_virtual_machine_update(object_update)
111
+ else
112
+ # Ignore this for now
113
+ end
114
+ end
115
+
116
+ def process_virtual_machine_update(object_update)
117
+ managed_object = object_update.obj
118
+ # TODO: Cache this
119
+ uuid = managed_object.config.instanceUuid
120
+
121
+ logger.error "Processing for uuid #{uuid}"
122
+
123
+ host = Host::Managed.find_by(compute_resource: compute_resource, uuid: uuid)
124
+
125
+ return unless host
126
+
127
+ facet = host.vmware_facet || host.build_vmware_facet
128
+
129
+ # TODO: Cluster
130
+ facet.update(
131
+ map_update_to_properties(:VirtualMachine, object_update.changeSet)
132
+ )
133
+ end
134
+
135
+ def map_update_to_properties(type, change_set)
136
+ mapping = PROPERTY_MAPPING[type][:mapped]
137
+
138
+ change_set.each_with_object({}) do |property_change, hsh|
139
+ hsh[mapping.key(property_change.name)] = property_change.val if mapping.key(property_change.name)
140
+ end
141
+ end
142
+
143
+ def wait_for_updates
144
+ connection.propertyCollector.WaitForUpdatesEx(
145
+ :version => version,
146
+ :options => wait_for_updates_options
147
+ )
148
+ end
149
+
150
+ def wait_for_updates_options
151
+ RbVmomi::VIM.WaitOptions(
152
+ :maxWaitSeconds => 10
153
+ )
154
+ end
155
+
156
+ def property_filter
157
+ @property_filter ||= create_property_filter
158
+ end
159
+
160
+ def property_set
161
+ PROPERTY_MAPPING.map do |type, properties|
162
+ RbVmomi::VIM::PropertySpec(
163
+ type: type,
164
+ pathSet: properties[:mapped].values + (properties[:additional] || [])
165
+ )
166
+ end
167
+ end
168
+
169
+ def traversal_spec_folder_to_child_entity
170
+ RbVmomi::VIM.TraversalSpec(
171
+ :name => 'FolderTraversalSpec',
172
+ :type => 'Folder',
173
+ :path => 'childEntity',
174
+ :skip => false,
175
+ :selectSet => [
176
+ RbVmomi::VIM.SelectionSpec(:name => 'FolderTraversalSpec'),
177
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsDcToDsFolder'),
178
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsDcToHostFolder'),
179
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsDcToNetworkFolder'),
180
+ RbVmomi::VIM.SelectionSpec(:name => 'DatacenterToVmFolderTraversalSpec'),
181
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsCrToHost'),
182
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsCrToRp'),
183
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsRpToRp'),
184
+ #RbVmomi::VIM.SelectionSpec(:name => 'tsRpToVm')
185
+ ]
186
+ )
187
+ end
188
+
189
+ def traversal_spec_datacenter_to_vm_folder
190
+ RbVmomi::VIM.TraversalSpec(
191
+ :name => 'DatacenterToVmFolderTraversalSpec',
192
+ :type => 'Datacenter',
193
+ :path => 'vmFolder',
194
+ :skip => false,
195
+ :selectSet => [
196
+ RbVmomi::VIM.SelectionSpec(:name => 'FolderTraversalSpec')
197
+ ]
198
+ )
199
+ end
200
+
201
+ def object_set(root)
202
+ traversal_spec = [
203
+ traversal_spec_folder_to_child_entity,
204
+ #datacenter_to_datastore_folder,
205
+ #datacenter_to_host_folder,
206
+ #datacenter_to_network_folder,
207
+ traversal_spec_datacenter_to_vm_folder
208
+ #compute_resource_to_host,
209
+ #compute_resource_to_resource_pool,
210
+ #resource_pool_to_resource_pool,
211
+ #resource_pool_to_vm,
212
+ ]
213
+
214
+ RbVmomi::VIM.ObjectSpec(
215
+ :obj => root,
216
+ :selectSet => traversal_spec
217
+ )
218
+ end
219
+
220
+ def create_property_filter
221
+ property_filter_spec = RbVmomi::VIM.PropertyFilterSpec(
222
+ :objectSet => [
223
+ object_set(
224
+ root_folder
225
+ )
226
+ ],
227
+ :propSet => property_set
228
+ )
229
+
230
+ connection.propertyCollector.CreateFilter(
231
+ :spec => property_filter_spec,
232
+ :partialUpdates => true
233
+ )
234
+ end
235
+
236
+ def destroy_property_filter
237
+ return unless @property_filter
238
+ @property_filter.DestroyPropertyFilter
239
+ end
240
+
241
+ def root_folder
242
+ connection.serviceContent.rootFolder
243
+ end
244
+
245
+ def connection
246
+ compute_resource.send(:client).send(:connection)
247
+ end
248
+ end
249
+ end
@@ -63,7 +63,8 @@ module ForemanWreckingball
63
63
  :cpu_sockets => hypervisor.cpu_sockets,
64
64
  :cpu_threads => hypervisor.cpu_threads,
65
65
  :memory => hypervisor.memory,
66
- :uuid => hypervisor.uuid
66
+ :uuid => hypervisor.uuid,
67
+ :feature_capabilities => hypervisor.feature_capabilities
67
68
  }
68
69
  )
69
70
  if result
@@ -0,0 +1,22 @@
1
+ <table class="<%= table_css_classes 'table-fixed' %>">
2
+ <thead>
3
+ <tr>
4
+ <th><%= _('Name') %></th>
5
+ <th class="col-md-3"><%= _('Cluster') %></th>
6
+ <th class="col-md-1"><%= _('Cores') %></th>
7
+ <th class="col-md-1"><%= _('Sockets') %></th>
8
+ <th class="col-md-1"><%= _('Spectre v2') %></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% @compute_resource.hypervisor_hosts.includes(:vmware_hypervisor_facet, :vmware_cluster).each do |host| %>
13
+ <tr>
14
+ <td class="ellipsis"><%= link_to_if_authorized(host.name, hash_for_host_path(:id => host)) %></td>
15
+ <td><%= host.vmware_cluster.name %></td>
16
+ <td><%= host.vmware_hypervisor_facet.cpu_cores %></td>
17
+ <td><%= host.vmware_hypervisor_facet.cpu_sockets %></td>
18
+ <td><%= wreckingball_spectre_v2_status(host.vmware_hypervisor_facet) %></td>
19
+ </tr>
20
+ <% end %>
21
+ </tbody>
22
+ </table>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCpuFeaturesToVmwareFacets < ActiveRecord::Migration[5.1]
4
+ def change
5
+ add_column :vmware_facets, :cpu_features, :text
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddHardwareVersionToVmwareFacets < ActiveRecord::Migration[5.1]
4
+ def change
5
+ add_column :vmware_facets, :hardware_version, :string
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddFeatureCapabilitiesToVmwareHypervisorFacets < ActiveRecord::Migration[5.1]
4
+ def change
5
+ add_column :vmware_hypervisor_facets, :feature_capabilities, :text
6
+ end
7
+ end
@@ -55,6 +55,14 @@ module ForemanWreckingball
55
55
  register_facet(ForemanWreckingball::VmwareHypervisorFacet, :vmware_hypervisor_facet)
56
56
 
57
57
  add_controller_action_scope(HostsController, :index) { |base_scope| base_scope.includes(:vmware_facet) }
58
+
59
+ # extend host show page
60
+ extend_page('compute_resources/show') do |context|
61
+ context.add_pagelet :main_tabs,
62
+ :name => N_('Hypervisors'),
63
+ :partial => 'compute_resources/hypervisors_tab',
64
+ :onlyif => proc { |cr| cr.provider_friendly_name == 'VMware' && cr.vmware_hypervisor_facets.any? }
65
+ end
58
66
  end
59
67
  end
60
68
 
@@ -95,7 +103,7 @@ module ForemanWreckingball
95
103
  require 'fog/vsphere'
96
104
  require 'fog/vsphere/compute'
97
105
  require 'fog/vsphere/models/compute/host'
98
- !::Fog::Compute::Vsphere::Host.instance_methods.include?(:uuid)
106
+ !::Fog::Compute::Vsphere::Host.instance_methods.include?(:feature_capabilities)
99
107
  rescue LoadError
100
108
  false
101
109
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanWreckingball
4
- VERSION = '3.0.0'
4
+ VERSION = '3.0.1'
5
5
  end
@@ -7,8 +7,15 @@ module Actions
7
7
  module Vmware
8
8
  class RefreshVmwareFacetTest < ActiveSupport::TestCase
9
9
  include ::Dynflow::Testing
10
+
11
+ let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
12
+ let(:vm) { compute_resource.find_vm_by_uuid(uuid) }
13
+
10
14
  setup do
11
15
  ::Fog.mock!
16
+ ::Fog::Compute::Vsphere::Mock.any_instance.stubs(:get_vm_ref).returns(vm)
17
+ ::Fog::Compute::Vsphere::Server.any_instance.stubs(:ready?).returns(false)
18
+ ::ForemanWreckingball::SpectreV2Status.any_instance.stubs(:recent_hw_version?).returns(true)
12
19
  # this is not stubbed correctly in fog-vsphere
13
20
  Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
14
21
  end
@@ -18,8 +25,6 @@ module Actions
18
25
  cr = FactoryBot.create(:compute_resource, :vmware, :uuid => 'Solutions')
19
26
  ComputeResource.find(cr.id)
20
27
  end
21
- let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
22
- let(:vm) { compute_resource.find_vm_by_uuid(uuid) }
23
28
 
24
29
  let(:host) do
25
30
  FactoryBot.create(
@@ -11,6 +11,7 @@ module Actions
11
11
  ::Fog.mock!
12
12
  # this is not stubbed correctly in fog-vsphere
13
13
  Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
14
+ ::ForemanWreckingball::SpectreV2Status.any_instance.stubs(:recent_hw_version?).returns(true)
14
15
  end
15
16
  teardown { ::Fog.unmock! }
16
17
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class ComputeResourcesControllerTest < ActionController::TestCase
6
+ describe '#show' do
7
+ let(:compute_resource) { FactoryBot.create(:compute_resource, :vmware) }
8
+ let(:vmware_cluster) { FactoryBot.create(:vmware_cluster, compute_resource: compute_resource) }
9
+
10
+ test 'shows a compute resource with hypervisors' do
11
+ skip if Gem::Version.new(Foreman::Version.new.to_s) < Gem::Version.new('1.19.0')
12
+ FactoryBot.create_list(:vmware_hypervisor_facet, 5, vmware_cluster: vmware_cluster)
13
+
14
+ get :show, params: { :id => compute_resource.to_param }, session: set_session_user
15
+ assert_response :success
16
+ assert @response.body.match(/Hypervisors/)
17
+ end
18
+ end
19
+ end
@@ -9,6 +9,29 @@ FactoryBot.define do
9
9
  memory_mb 8192
10
10
  guest_id 'rhel6_64Guest'
11
11
  cpu_hot_add false
12
+ hardware_version 'vmx-10'
13
+ cpu_features [
14
+ 'cpuid.SSE3',
15
+ 'cpuid.PCLMULQDQ',
16
+ 'cpuid.SSSE3',
17
+ 'cpuid.CMPXCHG16B',
18
+ 'cpuid.PCID',
19
+ 'cpuid.SSE41',
20
+ 'cpuid.SSE42',
21
+ 'cpuid.POPCNT',
22
+ 'cpuid.AES',
23
+ 'cpuid.XSAVE',
24
+ 'cpuid.AVX',
25
+ 'cpuid.DS',
26
+ 'cpuid.SS',
27
+ 'cpuid.XCR0_MASTER_SSE',
28
+ 'cpuid.XCR0_MASTER_YMM_H',
29
+ 'cpuid.LAHF64',
30
+ 'cpuid.NX',
31
+ 'cpuid.RDTSCP',
32
+ 'cpuid.LM',
33
+ 'cpuid.Intel'
34
+ ]
12
35
  host
13
36
  end
14
37
 
@@ -20,6 +43,88 @@ FactoryBot.define do
20
43
  cpu_threads 36
21
44
  memory 412_046_372_864
22
45
  uuid { SecureRandom.uuid }
46
+ feature_capabilities [
47
+ 'cpuid.3DNOW',
48
+ 'cpuid.3DNOWPLUS',
49
+ 'cpuid.3DNPREFETCH',
50
+ 'cpuid.ABM',
51
+ 'cpuid.ADX',
52
+ 'cpuid.AES',
53
+ 'cpuid.AMD',
54
+ 'cpuid.AVX',
55
+ 'cpuid.AVX2',
56
+ 'cpuid.BMI1',
57
+ 'cpuid.BMI2',
58
+ 'cpuid.CMPXCHG16B',
59
+ 'cpuid.CR8AVAIL',
60
+ 'cpuid.Cyrix',
61
+ 'cpuid.DS',
62
+ 'cpuid.ENFSTRG',
63
+ 'cpuid.EXTAPICSPC',
64
+ 'cpuid.F16C',
65
+ 'cpuid.FFXSR',
66
+ 'cpuid.FMA',
67
+ 'cpuid.FMA4',
68
+ 'cpuid.FSGSBASE',
69
+ 'cpuid.HLE',
70
+ 'cpuid.IBPB',
71
+ 'cpuid.IBRS',
72
+ 'cpuid.INVPCID',
73
+ 'cpuid.Intel',
74
+ 'cpuid.LAHF64',
75
+ 'cpuid.LM',
76
+ 'cpuid.MISALIGNED_SSE',
77
+ 'cpuid.MMXEXT',
78
+ 'cpuid.MOVBE',
79
+ 'cpuid.MWAIT',
80
+ 'cpuid.NX',
81
+ 'cpuid.PCID',
82
+ 'cpuid.PCLMULQDQ',
83
+ 'cpuid.PDPE1GB',
84
+ 'cpuid.POPCNT',
85
+ 'cpuid.PSN',
86
+ 'cpuid.RDRAND',
87
+ 'cpuid.RDSEED',
88
+ 'cpuid.RDTSCP',
89
+ 'cpuid.RTM',
90
+ 'cpuid.SMAP',
91
+ 'cpuid.SMEP',
92
+ 'cpuid.SS',
93
+ 'cpuid.SSE3',
94
+ 'cpuid.SSE41',
95
+ 'cpuid.SSE42',
96
+ 'cpuid.SSE4A',
97
+ 'cpuid.SSSE3',
98
+ 'cpuid.STIBP',
99
+ 'cpuid.SVM',
100
+ 'cpuid.SVM_DECODE_ASSISTS',
101
+ 'cpuid.SVM_FLUSH_BY_ASID',
102
+ 'cpuid.SVM_NPT',
103
+ 'cpuid.SVM_NRIP',
104
+ 'cpuid.SVM_VMCB_CLEAN',
105
+ 'cpuid.TBM',
106
+ 'cpuid.VIA',
107
+ 'cpuid.VMX',
108
+ 'cpuid.XCR0_MASTER_SSE',
109
+ 'cpuid.XCR0_MASTER_YMM_H',
110
+ 'cpuid.XOP',
111
+ 'cpuid.XSAVE',
112
+ 'cpuid.XSAVEOPT',
113
+ 'hv.capable',
114
+ 'misc.cpuidFaulting',
115
+ 'vpmc.fixctr.0',
116
+ 'vpmc.fixedWidth',
117
+ 'vpmc.genWidth',
118
+ 'vpmc.genctr.0',
119
+ 'vpmc.genctr.1',
120
+ 'vpmc.genctr.2',
121
+ 'vpmc.genctr.3',
122
+ 'vpmc.microarchitecture.ivybridge',
123
+ 'vpmc.numFixedCtrs',
124
+ 'vpmc.numGenCtrs',
125
+ 'vpmc.version',
126
+ 'vt.realmode'
127
+ ]
23
128
  end
24
129
 
25
130
  factory :vmware_cluster, class: 'ForemanWreckingball::VmwareCluster' do
@@ -4,4 +4,6 @@ require 'test_plugin_helper'
4
4
 
5
5
  class ComputeResourceTest < ActiveSupport::TestCase
6
6
  should have_many(:vmware_clusters)
7
+ should have_many(:vmware_hypervisor_facets)
8
+ should have_many(:hypervisor_hosts)
7
9
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ module ForemanWreckingball
6
+ class SpectreV2StatusTest < ActiveSupport::TestCase
7
+ setup do
8
+ User.current = users(:admin)
9
+ end
10
+
11
+ should belong_to(:host)
12
+
13
+ let(:host) do
14
+ FactoryBot.create(
15
+ :host,
16
+ :managed,
17
+ :with_vmware_facet
18
+ )
19
+ end
20
+ let(:status) { ForemanWreckingball::SpectreV2Status.new(host: host) }
21
+
22
+ test 'has a host association' do
23
+ status.save!
24
+ assert_equal status, host.public_send(status.class.host_association)
25
+ end
26
+
27
+ test '#relevant is only for hosts with a vmware facet' do
28
+ h = FactoryBot.build(:host, :managed)
29
+ refute ForemanWreckingball::ToolsStatus.new(host: h).relevant?
30
+ assert status.relevant?
31
+ end
32
+
33
+ test '#relevant is for hosts with cpu features' do
34
+ assert status.relevant?
35
+ host.vmware_facet.cpu_features = []
36
+ refute status.relevant?
37
+ end
38
+
39
+ describe 'status calculation' do
40
+ test 'is missing when mitigations are missing' do
41
+ status.stubs(:guest_mitigation_enabled?).returns(false)
42
+ assert_equal SpectreV2Status::MISSING, status.to_status
43
+ end
44
+
45
+ test 'is enabled when mitigations are present' do
46
+ status.stubs(:guest_mitigation_enabled?).returns(true)
47
+ assert_equal SpectreV2Status::ENABLED, status.to_status
48
+ end
49
+
50
+ test 'is missing when hardware version is ancient' do
51
+ status.stubs(:recent_hw_version?).returns(false)
52
+ assert_equal SpectreV2Status::MISSING, status.to_status
53
+ end
54
+ end
55
+
56
+ describe 'status labels' do
57
+ test 'when mitigations are missing' do
58
+ status.status = SpectreV2Status::MISSING
59
+ assert_equal 'Guest Mitigation Missing', status.to_label
60
+ end
61
+
62
+ test 'when mitigations are present' do
63
+ status.status = SpectreV2Status::ENABLED
64
+ assert_equal 'Guest Mitigation Enabled', status.to_label
65
+ end
66
+ end
67
+
68
+ describe 'global status' do
69
+ test 'is error when mitigations are missing' do
70
+ status.status = SpectreV2Status::MISSING
71
+ assert_equal HostStatus::Global::ERROR, status.to_global
72
+ end
73
+
74
+ test 'is ok when mitigations are present' do
75
+ status.status = SpectreV2Status::ENABLED
76
+ assert_equal HostStatus::Global::OK, status.to_global
77
+ end
78
+ end
79
+
80
+ describe '#recent_hw_version?' do
81
+ test 'is true when hw version is quite new' do
82
+ assert status.recent_hw_version?
83
+ end
84
+
85
+ test 'is false when hw version is ancient' do
86
+ host.vmware_facet.hardware_version = 'vmx-3'
87
+ refute status.recent_hw_version?
88
+ end
89
+ end
90
+
91
+ describe '#required_cpu_features_present?' do
92
+ test 'is false when neither cpuid.IBRS, cpuid.IBPB nor cpuid.STIBP is present' do
93
+ host.vmware_facet.cpu_features = ['cpuid.SSE42']
94
+ refute status.required_cpu_features_present?
95
+ end
96
+
97
+ test 'is true when cpuid.IBRS is present' do
98
+ host.vmware_facet.cpu_features = ['cpuid.IBRS']
99
+ assert status.required_cpu_features_present?
100
+ end
101
+
102
+ test 'is true when cpuid.IBPB is present' do
103
+ host.vmware_facet.cpu_features = ['cpuid.IBPB']
104
+ assert status.required_cpu_features_present?
105
+ end
106
+
107
+ test 'is true when cpuid.STIBP is present' do
108
+ host.vmware_facet.cpu_features = ['cpuid.STIBP']
109
+ assert status.required_cpu_features_present?
110
+ end
111
+ end
112
+ end
113
+ end
@@ -7,5 +7,61 @@ module ForemanWreckingball
7
7
  should validate_presence_of(:host)
8
8
  should belong_to(:vmware_cluster)
9
9
  should have_many(:vmware_hypervisor_facets)
10
+
11
+ describe '#refresh!' do
12
+ let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
13
+ let(:vm) do
14
+ OpenStruct.new(
15
+ runtime: OpenStruct.new(
16
+ featureRequirement: [
17
+ 'cpuid.SSE3',
18
+ 'cpuid.AES',
19
+ 'cpuid.Intel'
20
+ ].map do |cpu_feature|
21
+ OpenStruct.new(key: cpu_feature)
22
+ end
23
+ )
24
+ )
25
+ end
26
+
27
+ let(:compute_resource) do
28
+ cr = FactoryBot.create(:compute_resource, :vmware, :uuid => 'Solutions')
29
+ ComputeResource.find(cr.id)
30
+ end
31
+
32
+ let(:host) do
33
+ FactoryBot.create(
34
+ :host,
35
+ :managed,
36
+ :with_vmware_facet,
37
+ compute_resource: compute_resource,
38
+ uuid: uuid
39
+ )
40
+ end
41
+ let(:vmware_facet) { host.vmware_facet }
42
+
43
+ setup do
44
+ ::Fog.mock!
45
+ ::Fog::Compute::Vsphere::Mock.any_instance.stubs(:get_vm_ref).returns(vm)
46
+ # this is not stubbed correctly in fog-vsphere
47
+ ::Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
48
+ ::Fog::Compute::Vsphere::Server.any_instance.stubs(:hardware_version).returns('vmx-9')
49
+ ::Fog::Compute::Vsphere::Server.any_instance.stubs(:corespersocket).returns(1)
50
+ ::Fog::Compute::Vsphere::Server.any_instance.stubs(:ready?).returns(true)
51
+ end
52
+ teardown { ::Fog.unmock! }
53
+
54
+ test 'refreshes facet data from vm data' do
55
+ vmware_facet.refresh!
56
+ assert_equal 1, vmware_facet.cpus
57
+ assert_equal 1, vmware_facet.corespersocket
58
+ assert_equal 2196, vmware_facet.memory_mb
59
+ assert_equal 'rhel6_64Guest', vmware_facet.guest_id
60
+ assert_equal 'toolsOk', vmware_facet.tools_state
61
+ assert_equal false, vmware_facet.cpu_hot_add
62
+ assert_equal ['cpuid.SSE3', 'cpuid.AES', 'cpuid.Intel'], vmware_facet.cpu_features
63
+ assert_equal 'vmx-9', vmware_facet.hardware_version
64
+ end
65
+ end
10
66
  end
11
67
  end
@@ -7,9 +7,36 @@ module ForemanWreckingball
7
7
  should validate_presence_of(:host)
8
8
  should belong_to(:vmware_cluster)
9
9
  should have_many(:vmware_facets)
10
+ should have_one(:compute_resource)
10
11
 
11
12
  test 'should sanitize name' do
12
13
  assert_equal 'abc-server.example.com', ForemanWreckingball::VmwareHypervisorFacet.sanitize_name('abc_server.example.com.')
13
14
  end
15
+
16
+ describe '#provides_spectre_features?' do
17
+ let(:facet) do
18
+ FactoryBot.build(:vmware_hypervisor_facet)
19
+ end
20
+
21
+ test 'should be true when IBRS is available' do
22
+ facet.feature_capabilities = ['cpuid.IBRS']
23
+ assert_equal true, facet.provides_spectre_features?
24
+ end
25
+
26
+ test 'should be true when IBPB is available' do
27
+ facet.feature_capabilities = ['cpuid.IBPB']
28
+ assert_equal true, facet.provides_spectre_features?
29
+ end
30
+
31
+ test 'should be true when STIBP is available' do
32
+ facet.feature_capabilities = ['cpuid.STIBP']
33
+ assert_equal true, facet.provides_spectre_features?
34
+ end
35
+
36
+ test 'should be false when neither IBRS, IBPB nor STIBP is available' do
37
+ facet.feature_capabilities = ['cpuid.WHATEVER']
38
+ assert_equal false, facet.provides_spectre_features?
39
+ end
40
+ end
14
41
  end
15
42
  end
@@ -9,4 +9,5 @@ class Host::ManagedTest < ActiveSupport::TestCase
9
9
  should have_one(:vmware_tools_status_object)
10
10
  should have_one(:vmware_operatingsystem_status_object)
11
11
  should have_one(:vmware_cpu_hot_add_status_object)
12
+ should have_one(:vmware_spectre_v2_status_object)
12
13
  end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_wreckingball
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timo Goebel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-11 00:00:00.000000000 Z
11
+ date: 2018-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: foreman-tasks
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.13.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.13.1
27
27
  - !ruby/object:Gem::Dependency
@@ -65,6 +65,7 @@ files:
65
65
  - app/assets/javascripts/foreman_wreckingball/modal.js
66
66
  - app/controllers/foreman_wreckingball/hosts_controller.rb
67
67
  - app/helpers/concerns/foreman_wreckingball/hosts_helper_extensions.rb
68
+ - app/helpers/foreman_wreckingball/hypervisors_helper.rb
68
69
  - app/jobs/update_hosts_vmware_facets.rb
69
70
  - app/lib/actions/foreman_wreckingball/host/refresh_vmware_facet.rb
70
71
  - app/lib/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem.rb
@@ -82,12 +83,15 @@ files:
82
83
  - app/models/concerns/foreman_wreckingball/vmware_hypervisor_facet_host_extensions.rb
83
84
  - app/models/foreman_wreckingball/cpu_hot_add_status.rb
84
85
  - app/models/foreman_wreckingball/operatingsystem_status.rb
86
+ - app/models/foreman_wreckingball/spectre_v2_status.rb
85
87
  - app/models/foreman_wreckingball/tools_status.rb
86
88
  - app/models/foreman_wreckingball/vmware_cluster.rb
87
89
  - app/models/foreman_wreckingball/vmware_facet.rb
88
90
  - app/models/foreman_wreckingball/vmware_hypervisor_facet.rb
91
+ - app/services/foreman_wreckingball/debris_collector.rb
89
92
  - app/services/foreman_wreckingball/vmware_cluster_importer.rb
90
93
  - app/services/foreman_wreckingball/vmware_hypervisor_importer.rb
94
+ - app/views/compute_resources/_hypervisors_tab.html.erb
91
95
  - app/views/foreman_wreckingball/hosts/_status_dashboard_content.erb
92
96
  - app/views/foreman_wreckingball/hosts/_status_dashboard_empty.erb
93
97
  - app/views/foreman_wreckingball/hosts/_status_row.html.erb
@@ -95,6 +99,9 @@ files:
95
99
  - app/views/foreman_wreckingball/hosts/status_dashboard.html.erb
96
100
  - config/routes.rb
97
101
  - db/migrate/20171106155000_create_vmware_facets.rb
102
+ - db/migrate/20180504135345_add_cpu_features_to_vmware_facets.rb
103
+ - db/migrate/20180504135515_add_hardware_version_to_vmware_facets.rb
104
+ - db/migrate/20180614105545_add_feature_capabilities_to_vmware_hypervisor_facets.rb
98
105
  - lib/foreman_wreckingball.rb
99
106
  - lib/foreman_wreckingball/engine.rb
100
107
  - lib/foreman_wreckingball/scheduled_jobs.rb
@@ -108,6 +115,7 @@ files:
108
115
  - test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb
109
116
  - test/actions/foreman_wreckingball/vmware/schedule_vmware_sync_test.rb
110
117
  - test/actions/foreman_wreckingball/vmware/sync_compute_resource_test.rb
118
+ - test/controllers/compute_resources_controller_test.rb
111
119
  - test/controllers/foreman_wreckingball/hosts_controller_test.rb
112
120
  - test/factories/compute_resource.rb
113
121
  - test/factories/foreman_wreckingball_factories.rb
@@ -116,6 +124,7 @@ files:
116
124
  - test/models/compute_resources/vmware_test.rb
117
125
  - test/models/foreman_wreckingball/cpu_hot_add_status_test.rb
118
126
  - test/models/foreman_wreckingball/operatingsystem_status_test.rb
127
+ - test/models/foreman_wreckingball/spectre_v2_status_test.rb
119
128
  - test/models/foreman_wreckingball/tools_status_test.rb
120
129
  - test/models/foreman_wreckingball/vmware_cluster_test.rb
121
130
  - test/models/foreman_wreckingball/vmware_facet_test.rb
@@ -154,6 +163,7 @@ test_files:
154
163
  - test/models/compute_resource_test.rb
155
164
  - test/models/host_test.rb
156
165
  - test/models/foreman_wreckingball/operatingsystem_status_test.rb
166
+ - test/models/foreman_wreckingball/spectre_v2_status_test.rb
157
167
  - test/models/foreman_wreckingball/vmware_hypervisor_facet_test.rb
158
168
  - test/models/foreman_wreckingball/cpu_hot_add_status_test.rb
159
169
  - test/models/foreman_wreckingball/vmware_cluster_test.rb
@@ -168,4 +178,5 @@ test_files:
168
178
  - test/actions/foreman_wreckingball/vmware/sync_compute_resource_test.rb
169
179
  - test/actions/foreman_wreckingball/vmware/schedule_vmware_sync_test.rb
170
180
  - test/test_plugin_helper.rb
181
+ - test/controllers/compute_resources_controller_test.rb
171
182
  - test/controllers/foreman_wreckingball/hosts_controller_test.rb