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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/foreman_wreckingball/status_hosts_table.js +49 -0
- data/app/assets/stylesheets/foreman_wreckingball/status_hosts_table.css.scss +13 -0
- data/app/controllers/foreman_wreckingball/hosts_controller.rb +53 -13
- data/app/helpers/concerns/foreman_wreckingball/hosts_helper_extensions.rb +0 -15
- data/app/lib/actions/foreman_wreckingball/host/remediate_hardware_version.rb +63 -0
- data/app/lib/fog_extensions/foreman_wreckingball/vsphere/mock.rb +13 -0
- data/app/lib/fog_extensions/foreman_wreckingball/vsphere/real.rb +7 -0
- data/app/lib/fog_extensions/foreman_wreckingball/vsphere/server.rb +14 -0
- data/app/models/concerns/foreman_wreckingball/host_extensions.rb +5 -0
- data/app/models/foreman_wreckingball/hardware_version_status.rb +62 -0
- data/app/models/foreman_wreckingball/spectre_v2_status.rb +2 -2
- data/app/models/foreman_wreckingball/tools_status.rb +1 -1
- data/app/models/foreman_wreckingball/vmware_facet.rb +9 -0
- data/app/models/setting/wreckingball.rb +22 -0
- data/app/services/foreman_wreckingball/vmware_cluster_importer.rb +6 -1
- data/app/services/foreman_wreckingball/vmware_hypervisor_importer.rb +16 -1
- data/app/views/foreman_wreckingball/hosts/_hosts.json.rabl +41 -0
- data/app/views/foreman_wreckingball/hosts/_status_dashboard_content.erb +1 -2
- data/app/views/foreman_wreckingball/hosts/_status_row.html.erb +8 -43
- data/app/views/foreman_wreckingball/hosts/_status_row_hosts_table.html.erb +17 -0
- data/app/views/foreman_wreckingball/hosts/status_dashboard.html.erb +2 -0
- data/app/views/foreman_wreckingball/hosts/status_hosts.json.rabl +13 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20181020174609_add_power_state_to_vmware_facets.rb +7 -0
- data/db/migrate/20181021111543_add_indexes_to_vmware_hypervisor_facets.rb +8 -0
- data/lib/foreman_wreckingball/engine.rb +17 -1
- data/lib/foreman_wreckingball/version.rb +1 -1
- data/test/actions/foreman_wreckingball/host/refresh_vmware_facet_test.rb +2 -1
- data/test/actions/foreman_wreckingball/host/remediate_hardware_version_test.rb +63 -0
- data/test/actions/foreman_wreckingball/host/remediate_vmware_operatingsystem_test.rb +3 -1
- data/test/controllers/foreman_wreckingball/hosts_controller_test.rb +19 -0
- data/test/factories/compute_resource.rb +5 -0
- data/test/factories/foreman_wreckingball_factories.rb +15 -0
- data/test/factories/host.rb +8 -0
- data/test/models/foreman_wreckingball/hardware_version_status_test.rb +88 -0
- data/test/models/foreman_wreckingball/tools_status_test.rb +5 -2
- data/test/models/foreman_wreckingball/vmware_facet_test.rb +23 -2
- data/test/models/host_test.rb +1 -0
- data/test/unit/foreman_wreckingball/vmware_hypervisor_importer_test.rb +11 -0
- metadata +18 -3
- data/app/services/foreman_wreckingball/debris_collector.rb +0 -249
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module ForemanWreckingball
|
4
4
|
class VmwareClusterImporter
|
5
|
-
delegate :logger, :to => :Rails
|
6
5
|
attr_accessor :compute_resource, :counters
|
7
6
|
|
8
7
|
def initialize(options = {})
|
@@ -39,5 +38,11 @@ module ForemanWreckingball
|
|
39
38
|
def cluster_names
|
40
39
|
@cluster_names ||= compute_resource.clusters
|
41
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def logger
|
45
|
+
::Foreman::Logging.logger('foreman_wreckingball/import')
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module ForemanWreckingball
|
4
4
|
class VmwareHypervisorImporter
|
5
|
-
delegate :logger, :to => :Rails
|
6
5
|
attr_accessor :compute_resource, :counters
|
7
6
|
|
8
7
|
def initialize(options = {})
|
@@ -16,6 +15,7 @@ module ForemanWreckingball
|
|
16
15
|
compute_resource.refresh_cache
|
17
16
|
compute_resource.vmware_clusters.each do |cluster|
|
18
17
|
import_hypervisors(cluster)
|
18
|
+
delete_removed_hypervisors(cluster)
|
19
19
|
end
|
20
20
|
logger.info("Import hypervisors for '#{compute_resource}' completed. Added: #{counters[:added] || 0}, Updated: #{counters[:updated] || 0}, Deleted: #{counters[:deleted] || 0} hypervisors") # rubocop:disable Metrics/LineLength
|
21
21
|
end
|
@@ -101,6 +101,17 @@ module ForemanWreckingball
|
|
101
101
|
host
|
102
102
|
end
|
103
103
|
|
104
|
+
def delete_removed_hypervisors(cluster)
|
105
|
+
hypervisor_names = hypervisors(cluster).map(&:name)
|
106
|
+
hypervisor_uuids = hypervisors(cluster).map(&:uuid)
|
107
|
+
delete_query = ::ForemanWreckingball::VmwareHypervisorFacet.joins(:host).where(vmware_cluster: cluster).where.not('hosts.name': hypervisor_names).where.not(uuid: hypervisor_uuids)
|
108
|
+
counters[:deleted] = if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?('mysql')
|
109
|
+
::ForemanWreckingball::VmwareHypervisorFacet.where(:id => delete_query.pluck(:id)).delete_all
|
110
|
+
else
|
111
|
+
delete_query.delete_all
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
104
115
|
def organization
|
105
116
|
return unless SETTINGS[:organizations_enabled]
|
106
117
|
compute_resource.organizations.first
|
@@ -122,5 +133,9 @@ module ForemanWreckingball
|
|
122
133
|
counters[id] ||= 0
|
123
134
|
counters[id] += 1
|
124
135
|
end
|
136
|
+
|
137
|
+
def logger
|
138
|
+
::Foreman::Logging.logger('foreman_wreckingball/import')
|
139
|
+
end
|
125
140
|
end
|
126
141
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
collection @hosts
|
4
|
+
|
5
|
+
attributes :name
|
6
|
+
|
7
|
+
child owner: :owner do
|
8
|
+
attribute :name
|
9
|
+
end
|
10
|
+
|
11
|
+
child :environment do
|
12
|
+
attribute :name
|
13
|
+
end
|
14
|
+
|
15
|
+
node(:path) { |host| host_path(host) }
|
16
|
+
|
17
|
+
node(:status) do |host|
|
18
|
+
status = host.public_send(locals[:host_association])
|
19
|
+
{
|
20
|
+
label: status.to_label,
|
21
|
+
icon_class: host_global_status_icon_class(status.to_global),
|
22
|
+
status_class: host_global_status_class(status.to_global)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
node(:remediate, if: lambda do |host|
|
27
|
+
locals[:supports_remediate] && begin
|
28
|
+
options = hash_for_schedule_remediate_host_path(id: host,
|
29
|
+
status_id: host.public_send(locals[:host_association]).id)
|
30
|
+
.merge(auth_object: host,
|
31
|
+
permission: :remediate_vmware_status_hosts)
|
32
|
+
authorized_for(options)
|
33
|
+
end
|
34
|
+
end) do |host|
|
35
|
+
status_id = host.public_send(locals[:host_association]).id
|
36
|
+
{
|
37
|
+
label: _('Remediate'),
|
38
|
+
title: _('Remediate Host OS'),
|
39
|
+
path: schedule_remediate_host_path(host, status_id: status_id)
|
40
|
+
}
|
41
|
+
end
|
@@ -11,9 +11,8 @@
|
|
11
11
|
render :partial => 'status_row', locals: {
|
12
12
|
name: status[:name],
|
13
13
|
description: status[:description],
|
14
|
-
counter:
|
14
|
+
counter: status[:counter],
|
15
15
|
status: status[:host_association],
|
16
|
-
hosts: status[:hosts],
|
17
16
|
supports_remediate: status[:supports_remediate],
|
18
17
|
id: idx
|
19
18
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="list-group-item list-view-pf-stacked list-view-pf-top-align">
|
1
|
+
<div class="status-row list-group-item list-view-pf-stacked list-view-pf-top-align">
|
2
2
|
<div class="list-group-item-header">
|
3
3
|
<div class="list-view-pf-expand">
|
4
4
|
<span class="fa fa-angle-right"></span>
|
@@ -53,50 +53,15 @@
|
|
53
53
|
<span class="pficon pficon-close"></span>
|
54
54
|
</div>
|
55
55
|
<div class="row">
|
56
|
-
<div class="col-md-12">
|
56
|
+
<div class="col-md-12 status-hosts-container">
|
57
57
|
<% if counter[:warning] > 0 || counter[:critical] > 0 %>
|
58
58
|
<p><%= _('The following host require manual attention:') %></p>
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
<th><%= _('Puppet Environment') %></th>
|
66
|
-
<% if supports_remediate %>
|
67
|
-
<th><%= _('Actions') %></th>
|
68
|
-
<% end %>
|
69
|
-
</tr>
|
70
|
-
</thead>
|
71
|
-
<tbody>
|
72
|
-
<% hosts.each do |host| %>
|
73
|
-
<% next if host.public_send(status).to_global == HostStatus::Global::OK %>
|
74
|
-
<tr>
|
75
|
-
<td class="ellipsis"><%= link_to_if_authorized(host.name, hash_for_host_path(:id => host)) %></td>
|
76
|
-
<td>
|
77
|
-
<span class="<%= host_global_status_icon_class(host.public_send(status).to_global) %>"></span>
|
78
|
-
<span class="<%= host_global_status_class(host.public_send(status).to_global) %>"><%= _(host.public_send(status).to_label) %></span>
|
79
|
-
</td>
|
80
|
-
<td class="ellipsis"><%= host.owner %></td>
|
81
|
-
<td class="ellipsis"><%= host.environment %></td>
|
82
|
-
<% if supports_remediate %>
|
83
|
-
<td>
|
84
|
-
<%=
|
85
|
-
action_buttons(
|
86
|
-
display_link_if_authorized(
|
87
|
-
_('Remediate'),
|
88
|
-
hash_for_schedule_remediate_host_path(:id => host, :status_id => host.public_send(status).id).merge(:auth_object => host, :permission => 'remediate_vmware_status_hosts'),
|
89
|
-
:data => { :title => _('Remediate Host OS'), :submit_class => 'btn-danger' },
|
90
|
-
:onclick => 'show_modal(this); return false;'
|
91
|
-
)
|
92
|
-
)
|
93
|
-
%>
|
94
|
-
</td>
|
95
|
-
<% end %>
|
96
|
-
</tr>
|
97
|
-
<% end %>
|
98
|
-
</tbody>
|
99
|
-
</table>
|
59
|
+
<%=
|
60
|
+
render :partial => 'status_row_hosts_table', locals: {
|
61
|
+
status: status,
|
62
|
+
supports_remediate: supports_remediate
|
63
|
+
}
|
64
|
+
%>
|
100
65
|
<% else %>
|
101
66
|
<p><%= _('No manual actions required.') %></p>
|
102
67
|
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= content_tag :table, id: status,
|
2
|
+
class: 'table table-striped table-fixed status-hosts',
|
3
|
+
'data-hosts-url': ajax_status_dashboard_hosts_path(status) do %>
|
4
|
+
<%= content_tag :thead do %>
|
5
|
+
<%= content_tag :tr do %>
|
6
|
+
<%= content_tag :th, _('Hostname') %>
|
7
|
+
<%= content_tag :th, _('Status') %>
|
8
|
+
<%= content_tag :th, _('Owner') %>
|
9
|
+
<%= content_tag :th, _('Puppet Environment') %>
|
10
|
+
<%= content_tag :th, _('Actions') %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
<%= content_tag(:tbody) {} %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= alert header: _("Oops, we're sorry but something went wrong"), text: '',
|
17
|
+
class: 'alert-danger', close: false %>
|
@@ -1,5 +1,7 @@
|
|
1
1
|
<% title _('VMware Status Overview') %>
|
2
2
|
<% javascript 'foreman_wreckingball/modal' %>
|
3
|
+
<% javascript 'foreman_wreckingball/status_hosts_table' %>
|
4
|
+
<% stylesheet 'foreman_wreckingball/status_hosts_table' %>
|
3
5
|
<% javascript 'foreman_tasks/trigger_form' %>
|
4
6
|
<% stylesheet 'foreman_tasks/trigger_form' %>
|
5
7
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
object false
|
4
|
+
|
5
|
+
node(:recordsTotal) { @count }
|
6
|
+
node(:recordsFiltered) { @count }
|
7
|
+
node(:data) do
|
8
|
+
partial 'foreman_wreckingball/hosts/_hosts', object: @hosts,
|
9
|
+
locals: {
|
10
|
+
host_association: @status.host_association,
|
11
|
+
supports_remediate: @status.supports_remediate?
|
12
|
+
}
|
13
|
+
end
|
data/config/routes.rb
CHANGED
@@ -23,6 +23,15 @@ module ForemanWreckingball
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
initializer 'foreman_wreckingball.load_default_settings', before: :load_config_initializers do
|
27
|
+
table_exists = begin
|
28
|
+
Setting.table_exists?
|
29
|
+
rescue StandardError
|
30
|
+
false
|
31
|
+
end
|
32
|
+
require_dependency File.expand_path('../../app/models/setting/wreckingball.rb', __dir__) if table_exists
|
33
|
+
end
|
34
|
+
|
26
35
|
initializer 'foreman_wreckingball.register_plugin', :before => :finisher_hook do |_app|
|
27
36
|
Foreman::Plugin.register :foreman_wreckingball do
|
28
37
|
requires_foreman '>= 1.18'
|
@@ -49,6 +58,8 @@ module ForemanWreckingball
|
|
49
58
|
register_custom_status(ForemanWreckingball::ToolsStatus)
|
50
59
|
register_custom_status(ForemanWreckingball::OperatingsystemStatus)
|
51
60
|
register_custom_status(ForemanWreckingball::CpuHotAddStatus)
|
61
|
+
register_custom_status(ForemanWreckingball::SpectreV2Status)
|
62
|
+
register_custom_status(ForemanWreckingball::HardwareVersionStatus)
|
52
63
|
|
53
64
|
register_facet(ForemanWreckingball::VmwareFacet, :vmware_facet)
|
54
65
|
|
@@ -63,6 +74,9 @@ module ForemanWreckingball
|
|
63
74
|
:partial => 'compute_resources/hypervisors_tab',
|
64
75
|
:onlyif => proc { |cr| cr.provider_friendly_name == 'VMware' && cr.vmware_hypervisor_facets.any? }
|
65
76
|
end
|
77
|
+
|
78
|
+
# add custom logger
|
79
|
+
logger :import, enabled: true
|
66
80
|
end
|
67
81
|
end
|
68
82
|
|
@@ -82,7 +96,9 @@ module ForemanWreckingball
|
|
82
96
|
|
83
97
|
if ForemanWreckingball.fog_patches_required?
|
84
98
|
Fog::Compute::Vsphere::Host.send(:include, FogExtensions::ForemanWreckingball::Vsphere::Host)
|
99
|
+
Fog::Compute::Vsphere::Server.send(:include, FogExtensions::ForemanWreckingball::Vsphere::Server)
|
85
100
|
Fog::Compute::Vsphere::Real.send(:include, FogExtensions::ForemanWreckingball::Vsphere::Real)
|
101
|
+
Fog::Compute::Vsphere::Mock.send(:include, FogExtensions::ForemanWreckingball::Vsphere::Mock)
|
86
102
|
end
|
87
103
|
rescue StandardError => e
|
88
104
|
Rails.logger.warn "ForemanWreckingball: skipping engine hook (#{e})\n#{e.backtrace.join("\n")}"
|
@@ -103,7 +119,7 @@ module ForemanWreckingball
|
|
103
119
|
require 'fog/vsphere'
|
104
120
|
require 'fog/vsphere/compute'
|
105
121
|
require 'fog/vsphere/models/compute/host'
|
106
|
-
|
122
|
+
true
|
107
123
|
rescue LoadError
|
108
124
|
false
|
109
125
|
end
|
@@ -18,11 +18,12 @@ module Actions
|
|
18
18
|
::ForemanWreckingball::SpectreV2Status.any_instance.stubs(:recent_hw_version?).returns(true)
|
19
19
|
# this is not stubbed correctly in fog-vsphere
|
20
20
|
Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
|
21
|
+
Setting::Wreckingball.load_defaults
|
21
22
|
end
|
22
23
|
teardown { ::Fog.unmock! }
|
23
24
|
|
24
25
|
let(:compute_resource) do
|
25
|
-
cr = FactoryBot.create(:compute_resource, :vmware, :uuid => 'Solutions')
|
26
|
+
cr = FactoryBot.create(:compute_resource, :vmware, :with_taxonomy, :uuid => 'Solutions')
|
26
27
|
ComputeResource.find(cr.id)
|
27
28
|
end
|
28
29
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
module Actions
|
6
|
+
module ForemanWreckingball
|
7
|
+
module Vmware
|
8
|
+
class RemediateHardwareVersionTest < ActiveSupport::TestCase
|
9
|
+
include ::Dynflow::Testing
|
10
|
+
setup do
|
11
|
+
::Fog.mock!
|
12
|
+
# this is not stubbed correctly in fog-vsphere
|
13
|
+
Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
|
14
|
+
Fog::Compute::Vsphere::Server.any_instance.stubs(:hardware_version).returns('vmx-13')
|
15
|
+
::ForemanWreckingball::SpectreV2Status.any_instance.stubs(:recent_hw_version?).returns(true)
|
16
|
+
::PowerManager::Virt.any_instance.stubs(:ready?).returns(true)
|
17
|
+
Setting::Wreckingball.load_defaults
|
18
|
+
end
|
19
|
+
teardown { ::Fog.unmock! }
|
20
|
+
|
21
|
+
let(:compute_resource) do
|
22
|
+
cr = FactoryBot.create(:compute_resource, :vmware, :with_taxonomy, :uuid => 'Solutions')
|
23
|
+
ComputeResource.find(cr.id)
|
24
|
+
end
|
25
|
+
let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
|
26
|
+
let(:vm) { compute_resource.find_vm_by_uuid(uuid) }
|
27
|
+
|
28
|
+
let(:host) do
|
29
|
+
FactoryBot.create(
|
30
|
+
:host,
|
31
|
+
:managed,
|
32
|
+
:with_vmware_facet,
|
33
|
+
compute_resource: compute_resource,
|
34
|
+
uuid: uuid
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:action_class) { ::Actions::ForemanWreckingball::Host::RemediateHardwareVersion }
|
39
|
+
let(:action) do
|
40
|
+
create_action(action_class).tap do |action|
|
41
|
+
action.stubs(:action_subject).returns(host)
|
42
|
+
action.input.update(
|
43
|
+
host: {
|
44
|
+
id: host.id
|
45
|
+
}
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
let(:planned_action) do
|
50
|
+
plan_action(action, host)
|
51
|
+
end
|
52
|
+
let(:runned_action) { run_action(planned_action) }
|
53
|
+
|
54
|
+
test "it remediates the host's hardware version" do
|
55
|
+
assert_equal :success, runned_action.state
|
56
|
+
assert_equal true, runned_action.output.fetch('state')
|
57
|
+
assert_equal true, runned_action.output.fetch('initially_powered_on')
|
58
|
+
assert_equal 'vmx-13', host.reload.vmware_facet.hardware_version
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -12,11 +12,13 @@ module Actions
|
|
12
12
|
# this is not stubbed correctly in fog-vsphere
|
13
13
|
Fog::Compute::Vsphere::Server.any_instance.stubs(:cpuHotAddEnabled).returns(false)
|
14
14
|
::ForemanWreckingball::SpectreV2Status.any_instance.stubs(:recent_hw_version?).returns(true)
|
15
|
+
::PowerManager::Virt.any_instance.stubs(:ready?).returns(true)
|
16
|
+
Setting::Wreckingball.load_defaults
|
15
17
|
end
|
16
18
|
teardown { ::Fog.unmock! }
|
17
19
|
|
18
20
|
let(:compute_resource) do
|
19
|
-
cr = FactoryBot.create(:compute_resource, :vmware, :uuid => 'Solutions')
|
21
|
+
cr = FactoryBot.create(:compute_resource, :vmware, :with_taxonomy, :uuid => 'Solutions')
|
20
22
|
ComputeResource.find(cr.id)
|
21
23
|
end
|
22
24
|
let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
|
@@ -11,6 +11,10 @@ module ForemanWreckingball
|
|
11
11
|
)
|
12
12
|
end
|
13
13
|
|
14
|
+
setup do
|
15
|
+
Setting::Wreckingball.load_defaults
|
16
|
+
end
|
17
|
+
|
14
18
|
describe '#status_dashboard' do
|
15
19
|
test 'shows an empty status page' do
|
16
20
|
get :status_dashboard, session: set_session_user
|
@@ -24,6 +28,21 @@ module ForemanWreckingball
|
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
31
|
+
describe '#status_hosts' do
|
32
|
+
test 'returns hosts for status' do
|
33
|
+
ok_status = FactoryBot.create(:vmware_hardware_version_status, :with_ok_status)
|
34
|
+
out_of_date_status = FactoryBot.create(:vmware_hardware_version_status, :with_out_of_date_status)
|
35
|
+
|
36
|
+
get :status_hosts, params: { status: ::ForemanWreckingball::HardwareVersionStatus.host_association },
|
37
|
+
session: set_session_user, xhr: true
|
38
|
+
|
39
|
+
assert_response :ok
|
40
|
+
hosts_names = JSON.parse(response.body)['data'].map { |host| host['name'] }
|
41
|
+
assert_includes hosts_names, out_of_date_status.host.name
|
42
|
+
refute_includes hosts_names, ok_status.host.name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
27
46
|
describe '#refresh_status_dashboard' do
|
28
47
|
test 'redirects to scheduled task' do
|
29
48
|
ForemanTasks.expects(:async_task).returns(fake_task)
|
@@ -11,5 +11,10 @@ FactoryBot.modify do
|
|
11
11
|
create_list(:vmware_cluster, evaluator.vmware_clusters_count, compute_resource: compute_resource)
|
12
12
|
end
|
13
13
|
end
|
14
|
+
|
15
|
+
trait :with_taxonomy do
|
16
|
+
organizations { [Organization.find_by(name: 'Organization 1')] }
|
17
|
+
locations { [Location.find_by(name: 'Location 1')] }
|
18
|
+
end
|
14
19
|
end
|
15
20
|
end
|