foreman_wreckingball 3.0.0 → 3.0.1

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