foreman_puppet 10.1.3 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/foreman_puppet/extensions/hosts_controller_extensions.rb +1 -1
- data/app/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller.rb +75 -1
- data/app/models/concerns/foreman_puppet/extensions/host.rb +2 -2
- data/app/models/concerns/foreman_puppet/extensions/host_common.rb +35 -0
- data/app/models/concerns/foreman_puppet/extensions/hostgroup.rb +10 -3
- data/app/models/foreman_puppet/config_group.rb +6 -0
- data/app/models/foreman_puppet/puppetclass.rb +14 -0
- data/app/services/concerns/foreman_puppet/extensions/bulk_hosts_manager.rb +18 -0
- data/config/api_routes.rb +1 -0
- data/db/seeds.d/111_puppet_proxy_feature.rb +1 -1
- data/lib/foreman_puppet/register.rb +2 -1
- data/lib/foreman_puppet/version.rb +1 -1
- data/test/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller_test.rb +93 -0
- data/test/models/foreman_puppet/host_test.rb +66 -0
- data/test/models/foreman_puppet/hostgroup_test.rb +32 -0
- data/test/services/foreman_puppet/bulk_hosts_manager_test.rb +45 -0
- data/webpack/__mocks__/foremanReact/redux/API/index.js +8 -0
- data/webpack/global_index.js +18 -1
- data/webpack/src/Extends/Hosts/ActionsBar/index.js +20 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangeProxyCommon/__tests__/actions.test.js +0 -7
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangeProxyCommon/index.js +9 -13
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy/__tests__/index.test.js +3 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy/index.js +2 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/BulkChangePuppetEnvironmentModal.js +239 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/BulkChangePuppetEnvironmentModal.test.js +155 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/actions.test.js +49 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/index.test.js +66 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/actions.js +37 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/index.js +30 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetProxy/__tests__/index.test.js +160 -44
- data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetProxy/index.js +2 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemoveProxyCommon/__tests__/actions.test.js +0 -6
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemoveProxyCommon/index.js +8 -13
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy/__tests__/index.test.js +138 -38
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy/index.js +2 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/BulkRemovePuppetEnvironmentModal.js +148 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/BulkRemovePuppetEnvironmentModal.test.js +80 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/index.test.js +66 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/index.js +30 -0
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy/__tests__/index.test.js +125 -33
- data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy/index.js +2 -0
- data/webpack/src/Router/routes.fixtures.js +13 -0
- data/webpack/src/Router/routes.test.js +68 -8
- data/webpack/src/foreman_puppet_host_form.test.js +3 -1
- data/webpack/test_setup.js +1 -0
- metadata +14 -3
- data/webpack/src/Router/__snapshots__/routes.test.js.snap +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5aa351556f85774a9796437e9ee6fd0671f46db4bb3519aa6a94c1691c90d6ca
|
|
4
|
+
data.tar.gz: a9507d1ae1d1961d4256eba509e88e72f5ee1124d2d2532751f6f3ff7b2e2ac2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 31593435b997b9202741f97a709aa40bbd57ed82f6c09aeadbe8e83432d0273b0f2523aebe0a13cf03f3e534592418091f21da8eb768cad3dfc7f0a68c1c3277
|
|
7
|
+
data.tar.gz: 4625c5cfbefe7af792e45ffad193ca1f0867aac29ac3596c003072aec34c366d3ade137244a861802ddab8d75c45651343c76901d871bfd0b145509ea4a67df1
|
|
@@ -3,7 +3,9 @@ module ForemanPuppet
|
|
|
3
3
|
module V2
|
|
4
4
|
class HostsBulkActionsController < ::ForemanPuppet::Api::V2::PuppetBaseController
|
|
5
5
|
include ::Api::V2::BulkHostsExtension
|
|
6
|
-
before_action :find_editable_hosts, only: %i[change_puppet_proxy remove_puppet_proxy]
|
|
6
|
+
before_action :find_editable_hosts, only: %i[change_puppet_environment change_puppet_proxy remove_puppet_proxy]
|
|
7
|
+
before_action :find_environment, only: %i[change_puppet_environment]
|
|
8
|
+
before_action :validate_environment_taxonomies, only: %i[change_puppet_environment]
|
|
7
9
|
before_action :find_smart_proxy, only: %i[change_puppet_proxy]
|
|
8
10
|
|
|
9
11
|
def_param_group :bulk_params do
|
|
@@ -17,6 +19,27 @@ module ForemanPuppet
|
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
api :PUT, '/hosts/bulk/change_puppet_environment', N_('Change Puppet environment')
|
|
23
|
+
param_group :bulk_params
|
|
24
|
+
param :environment_id, String, required: false, desc: N_('ID of the Puppet environment to set for the selected hosts')
|
|
25
|
+
def change_puppet_environment
|
|
26
|
+
error_hosts = ::BulkHostsManager.new(hosts: @hosts).change_puppet_environment(resolved_environment)
|
|
27
|
+
|
|
28
|
+
process_bulk_response(
|
|
29
|
+
error_hosts,
|
|
30
|
+
success_message: format(n_(
|
|
31
|
+
'Updated host: changed environment',
|
|
32
|
+
'Updated hosts: changed environment',
|
|
33
|
+
@hosts.count
|
|
34
|
+
)),
|
|
35
|
+
error_message: format(n_(
|
|
36
|
+
'Failed to change environment for %{count} host',
|
|
37
|
+
'Failed to change environment for %{count} hosts',
|
|
38
|
+
error_hosts.count
|
|
39
|
+
), count: error_hosts.count)
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
20
43
|
api :PUT, '/hosts/bulk/change_puppet_proxy', N_('Change Puppet (CA) Proxy')
|
|
21
44
|
param_group :bulk_params
|
|
22
45
|
param :proxy_id, :number, required: true, desc: N_('ID of the Puppet proxy to reassign the hosts to')
|
|
@@ -65,6 +88,14 @@ module ForemanPuppet
|
|
|
65
88
|
end
|
|
66
89
|
|
|
67
90
|
def process_bulk_puppet_proxy_response(error_hosts, success_message:, error_message:)
|
|
91
|
+
process_bulk_response(
|
|
92
|
+
error_hosts,
|
|
93
|
+
success_message: success_message,
|
|
94
|
+
error_message: error_message
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def process_bulk_response(error_hosts, success_message:, error_message:)
|
|
68
99
|
if error_hosts.empty?
|
|
69
100
|
process_response(true, { message: success_message })
|
|
70
101
|
else
|
|
@@ -93,6 +124,49 @@ module ForemanPuppet
|
|
|
93
124
|
Foreman::Cast.to_bool(params[:ca_proxy])
|
|
94
125
|
end
|
|
95
126
|
|
|
127
|
+
def find_environment
|
|
128
|
+
return true if environment_value == 'inherit' || environment_value.blank?
|
|
129
|
+
|
|
130
|
+
@environment = ForemanPuppet::Environment.find_by(id: environment_value)
|
|
131
|
+
return true if @environment.present?
|
|
132
|
+
|
|
133
|
+
render json: {
|
|
134
|
+
error: {
|
|
135
|
+
message: format(_('A Puppet environment with id %{id} could not be found.'), id: environment_value),
|
|
136
|
+
},
|
|
137
|
+
}, status: :unprocessable_entity
|
|
138
|
+
false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def validate_environment_taxonomies
|
|
142
|
+
return true if resolved_environment.blank? || resolved_environment == 'inherit'
|
|
143
|
+
|
|
144
|
+
invalid_host_ids = @hosts.reject do |host|
|
|
145
|
+
ForemanPuppet::Environment.with_taxonomy_scope(host.organization, host.location)
|
|
146
|
+
.exists?(id: resolved_environment.id)
|
|
147
|
+
end.map(&:id)
|
|
148
|
+
|
|
149
|
+
return true if invalid_host_ids.empty?
|
|
150
|
+
|
|
151
|
+
render_error(:bulk_hosts_error, status: :unprocessable_entity,
|
|
152
|
+
locals: {
|
|
153
|
+
message: _('Selected Puppet environment is not assigned to the proper organization and/or location for all hosts.'),
|
|
154
|
+
failed_host_ids: invalid_host_ids,
|
|
155
|
+
})
|
|
156
|
+
false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def environment_value
|
|
160
|
+
params[:environment_id]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def resolved_environment
|
|
164
|
+
return 'inherit' if environment_value == 'inherit'
|
|
165
|
+
return nil if environment_value.blank?
|
|
166
|
+
|
|
167
|
+
@environment
|
|
168
|
+
end
|
|
169
|
+
|
|
96
170
|
def proxy_type
|
|
97
171
|
ca_proxy? ? _('Puppet CA proxy') : _('Puppet proxy')
|
|
98
172
|
end
|
|
@@ -13,9 +13,9 @@ module ForemanPuppet
|
|
|
13
13
|
include_in_clone puppet: %i[config_groups host_config_groups host_classes]
|
|
14
14
|
|
|
15
15
|
scoped_search relation: :environment, on: :name, complete_value: true, rename: :environment
|
|
16
|
-
scoped_search relation: :
|
|
16
|
+
scoped_search relation: :search_puppetclasses, on: :name, complete_value: true, rename: :puppetclass, only_explicit: true, operators: ['= ', '~ '],
|
|
17
17
|
ext_method: :search_by_puppetclass
|
|
18
|
-
scoped_search relation: :
|
|
18
|
+
scoped_search relation: :search_config_groups, on: :name, complete_value: true, rename: :config_group, only_explicit: true, operators: ['= ', '~ '],
|
|
19
19
|
ext_method: :search_by_config_group
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -3,6 +3,41 @@ module ForemanPuppet
|
|
|
3
3
|
module HostCommon
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
+
ASSIGNMENT_RELATIONS = %i[search_puppetclasses search_config_groups].freeze
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
singleton_class.prepend CompletionMethods
|
|
10
|
+
|
|
11
|
+
has_many :search_puppetclasses, through: :puppet, source: :puppetclasses, class_name: '::ForemanPuppet::Puppetclass'
|
|
12
|
+
has_many :search_config_groups, through: :puppet, source: :config_groups, class_name: '::ForemanPuppet::ConfigGroup'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module CompletionMethods
|
|
16
|
+
def complete_for(query, options = {})
|
|
17
|
+
return super if query.nil?
|
|
18
|
+
|
|
19
|
+
completer = AssignmentCompleter.new(scoped_search_definition, query, options)
|
|
20
|
+
return super unless completer.assignment_field?
|
|
21
|
+
|
|
22
|
+
completer.build_autocomplete_options
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class AssignmentCompleter < ScopedSearch::AutoCompleteBuilder
|
|
27
|
+
def assignment_field?
|
|
28
|
+
return false unless complete_options(last_node).include?(:value)
|
|
29
|
+
|
|
30
|
+
token = last_token_is(COMPARISON_OPERATORS) ? tokens[-2] : tokens[-3]
|
|
31
|
+
ASSIGNMENT_RELATIONS.include?(definition.field_by_name(token)&.relation)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def completer_scope(field)
|
|
35
|
+
return super unless ASSIGNMENT_RELATIONS.include?(field.relation)
|
|
36
|
+
|
|
37
|
+
field.klass.completer_scope(@options).reorder(Arel.sql(field.quoted_field))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
6
41
|
def all_puppetclasses(env = environment)
|
|
7
42
|
return ForemanPuppet::Puppetclass.none unless puppet
|
|
8
43
|
puppet.all_puppetclasses(env)
|
|
@@ -16,13 +16,13 @@ module ForemanPuppet
|
|
|
16
16
|
|
|
17
17
|
# will need through relation to work properly
|
|
18
18
|
scoped_search relation: :environment, on: :name, complete_value: true, rename: :environment, only_explicit: true
|
|
19
|
-
scoped_search relation: :
|
|
19
|
+
scoped_search relation: :search_puppetclasses, on: :name,
|
|
20
20
|
complete_value: true,
|
|
21
21
|
rename: :puppetclass,
|
|
22
22
|
only_explicit: true,
|
|
23
23
|
operators: ['= ', '~ '],
|
|
24
24
|
ext_method: :search_by_puppetclass
|
|
25
|
-
scoped_search relation: :
|
|
25
|
+
scoped_search relation: :search_config_groups, on: :name,
|
|
26
26
|
complete_value: true,
|
|
27
27
|
rename: :config_group,
|
|
28
28
|
only_explicit: true,
|
|
@@ -45,9 +45,16 @@ module ForemanPuppet
|
|
|
45
45
|
def search_by_puppetclass(_key, operator, value)
|
|
46
46
|
conditions = sanitize_sql_for_conditions(["puppetclasses.name #{operator} ?", value_to_sql(operator, value)])
|
|
47
47
|
hostgroup_ids = ::Hostgroup.joins(puppet: :puppetclasses).where(conditions).map(&:subtree_ids)
|
|
48
|
+
config_group_ids = ForemanPuppet::ConfigGroup.joins(:puppetclasses).where(conditions).pluck(:id)
|
|
49
|
+
if config_group_ids.any?
|
|
50
|
+
hostgroup_cg_ids = ForemanPuppet::HostgroupPuppetFacet.joins(:host_config_groups)
|
|
51
|
+
.where(host_config_groups: { config_group_id: config_group_ids })
|
|
52
|
+
.pluck(:hostgroup_id)
|
|
53
|
+
hostgroup_ids += ::Hostgroup.where(id: hostgroup_cg_ids).map(&:subtree_ids)
|
|
54
|
+
end
|
|
48
55
|
|
|
49
56
|
conds = []
|
|
50
|
-
conds << "hostgroups.id IN (#{hostgroup_ids.join(',')})" if hostgroup_ids.present?
|
|
57
|
+
conds << "hostgroups.id IN (#{hostgroup_ids.uniq.join(',')})" if hostgroup_ids.present?
|
|
51
58
|
|
|
52
59
|
{ conditions: conds.join(' OR ').presence || 'hostgroups.id < 0' }
|
|
53
60
|
end
|
|
@@ -16,6 +16,8 @@ module ForemanPuppet
|
|
|
16
16
|
|
|
17
17
|
validates :name, presence: true, uniqueness: true
|
|
18
18
|
|
|
19
|
+
scope :assigned_to_hosts, -> { where(id: ForemanPuppet::HostConfigGroup.select(:config_group_id)) }
|
|
20
|
+
|
|
19
21
|
scoped_search on: :name, complete_value: true
|
|
20
22
|
scoped_search relation: :puppetclasses, on: :name, complete_value: true, rename: :puppetclass, only_explicit: true, operators: ['= ', '~ ']
|
|
21
23
|
|
|
@@ -41,5 +43,9 @@ module ForemanPuppet
|
|
|
41
43
|
def hostgroups_count
|
|
42
44
|
::Hostgroup.authorized.search_for(%(config_group="#{name}")).size
|
|
43
45
|
end
|
|
46
|
+
|
|
47
|
+
def self.completer_scope(options)
|
|
48
|
+
super.merge(assigned_to_hosts)
|
|
49
|
+
end
|
|
44
50
|
end
|
|
45
51
|
end
|
|
@@ -41,6 +41,16 @@ module ForemanPuppet
|
|
|
41
41
|
|
|
42
42
|
default_scope -> { order(:name) }
|
|
43
43
|
|
|
44
|
+
scope :assigned_to_hosts, lambda {
|
|
45
|
+
direct = ForemanPuppet::HostClass.select(:puppetclass_id)
|
|
46
|
+
via_hostgroup = ForemanPuppet::HostgroupClass.select(:puppetclass_id)
|
|
47
|
+
via_config_group = ForemanPuppet::ConfigGroupClass
|
|
48
|
+
.where(config_group_id: ForemanPuppet::HostConfigGroup.select(:config_group_id))
|
|
49
|
+
.select(:puppetclass_id)
|
|
50
|
+
|
|
51
|
+
where(id: direct).or(where(id: via_hostgroup)).or(where(id: via_config_group))
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
scoped_search on: :name, complete_value: true
|
|
45
55
|
scoped_search relation: :environments, on: :name, complete_value: true, rename: 'environment'
|
|
46
56
|
scoped_search relation: :organizations, on: :name, complete_value: true, rename: 'organization', only_explicit: true
|
|
@@ -142,5 +152,9 @@ module ForemanPuppet
|
|
|
142
152
|
puppet_classes = (direct + indirect).uniq
|
|
143
153
|
{ conditions: "puppetclasses.id IN(#{puppet_classes.join(',')})" }
|
|
144
154
|
end
|
|
155
|
+
|
|
156
|
+
def self.completer_scope(options)
|
|
157
|
+
super.merge(assigned_to_hosts)
|
|
158
|
+
end
|
|
145
159
|
end
|
|
146
160
|
end
|
|
@@ -3,6 +3,24 @@ module ForemanPuppet
|
|
|
3
3
|
module BulkHostsManager
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
+
def change_puppet_environment(environment)
|
|
7
|
+
error_hosts = []
|
|
8
|
+
@hosts.each do |host|
|
|
9
|
+
puppet = host.puppet || host.build_puppet
|
|
10
|
+
puppet.environment = if environment == 'inherit'
|
|
11
|
+
host.hostgroup&.puppet&.environment
|
|
12
|
+
else
|
|
13
|
+
environment
|
|
14
|
+
end
|
|
15
|
+
host.save(validate: false)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
message = format(_('Failed to set Puppet environment for %{host}.'), host: host)
|
|
18
|
+
Foreman::Logging.exception(message, e)
|
|
19
|
+
error_hosts << host.id
|
|
20
|
+
end
|
|
21
|
+
error_hosts
|
|
22
|
+
end
|
|
23
|
+
|
|
6
24
|
def change_puppet_proxy(proxy, is_ca_proxy)
|
|
7
25
|
error_hosts = []
|
|
8
26
|
@hosts.each do |host|
|
data/config/api_routes.rb
CHANGED
|
@@ -4,6 +4,7 @@ Foreman::Application.routes.draw do
|
|
|
4
4
|
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v1|v2/, constraints: ApiConstraints.new(version: 2, default: true) do
|
|
5
5
|
match 'hosts/bulk/change_puppet_proxy', to: 'hosts_bulk_actions#change_puppet_proxy', via: [:put]
|
|
6
6
|
match 'hosts/bulk/remove_puppet_proxy', to: 'hosts_bulk_actions#remove_puppet_proxy', via: [:put]
|
|
7
|
+
match 'hosts/bulk/change_puppet_environment', to: 'hosts_bulk_actions#change_puppet_environment', via: [:put]
|
|
7
8
|
end
|
|
8
9
|
end
|
|
9
10
|
end
|
|
@@ -4,5 +4,5 @@ proxy_features = %w[Puppet]
|
|
|
4
4
|
|
|
5
5
|
proxy_features.each do |f_name|
|
|
6
6
|
f = Feature.where(name: f_name).first_or_create
|
|
7
|
-
raise "Unable to create proxy feature: #{format_errors
|
|
7
|
+
raise "Unable to create proxy feature: #{SeedHelper.format_errors(f)}" if f.nil? || f.errors.any?
|
|
8
8
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Foreman::Plugin.register :foreman_puppet do
|
|
2
|
-
requires_foreman '>=
|
|
2
|
+
requires_foreman '>= 5.0'
|
|
3
3
|
register_gettext
|
|
4
4
|
|
|
5
5
|
# Add Global JS file for extending foreman-core components and routes
|
|
@@ -62,6 +62,7 @@ Foreman::Plugin.register :foreman_puppet do
|
|
|
62
62
|
p.actions << 'hosts/update_multiple_environment'
|
|
63
63
|
p.actions << 'hosts/select_multiple_puppet_proxy'
|
|
64
64
|
p.actions << 'hosts/update_multiple_puppet_proxy'
|
|
65
|
+
p.actions << 'foreman_puppet/api/v2/hosts_bulk_actions/change_puppet_environment'
|
|
65
66
|
p.actions << 'foreman_puppet/api/v2/hosts_bulk_actions/change_puppet_proxy'
|
|
66
67
|
p.actions << 'foreman_puppet/api/v2/hosts_bulk_actions/remove_puppet_proxy'
|
|
67
68
|
end
|
|
@@ -16,8 +16,101 @@ module ForemanPuppet
|
|
|
16
16
|
organization: host.organization,
|
|
17
17
|
location: host.location)
|
|
18
18
|
end
|
|
19
|
+
let(:environment) { FactoryBot.create(:environment, organizations: [host.organization], locations: [host.location]) }
|
|
20
|
+
let(:hostgroup_environment) { FactoryBot.create(:environment, organizations: [host.organization], locations: [host.location]) }
|
|
21
|
+
let(:hostgroup) do
|
|
22
|
+
FactoryBot.create(:hostgroup, :with_puppet_enc,
|
|
23
|
+
environment: hostgroup_environment,
|
|
24
|
+
organizations: [host.organization],
|
|
25
|
+
locations: [host.location])
|
|
26
|
+
end
|
|
19
27
|
let(:proxy) { FactoryBot.create(:puppet_and_ca_smart_proxy, organizations: [host.organization], locations: [host.location]) }
|
|
20
28
|
|
|
29
|
+
def put_change_puppet_environment(params:, session: nil)
|
|
30
|
+
put :change_puppet_environment, params: params, session: session
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test 'changes puppet environment for selected hosts' do
|
|
34
|
+
put_change_puppet_environment(params: bulk_params.merge(environment_id: environment.id))
|
|
35
|
+
|
|
36
|
+
assert_response :success
|
|
37
|
+
assert_equal environment.id, host2.reload.puppet.environment_id
|
|
38
|
+
assert_equal environment.id, host.reload.puppet.environment_id
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test 'inherits puppet environment from hostgroups for selected hosts' do
|
|
42
|
+
host.update!(hostgroup: hostgroup)
|
|
43
|
+
host2.update!(hostgroup: hostgroup)
|
|
44
|
+
|
|
45
|
+
put_change_puppet_environment(params: bulk_params.merge(environment_id: 'inherit'))
|
|
46
|
+
|
|
47
|
+
assert_response :success
|
|
48
|
+
assert_equal hostgroup_environment.id, host2.reload.puppet.environment_id
|
|
49
|
+
assert_equal hostgroup_environment.id, host.reload.puppet.environment_id
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
test 'clears puppet environment for selected hosts' do
|
|
53
|
+
host.puppet.update!(environment: environment)
|
|
54
|
+
host2.puppet.update!(environment: environment)
|
|
55
|
+
|
|
56
|
+
put_change_puppet_environment(
|
|
57
|
+
params: bulk_params.merge(environment_id: nil),
|
|
58
|
+
session: set_session_user
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
assert_response :success
|
|
62
|
+
assert_nil host.reload.puppet.environment
|
|
63
|
+
assert_nil host2.reload.puppet.environment
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
test 'returns error when puppet environment is missing' do
|
|
67
|
+
missing_environment_id = 999_999
|
|
68
|
+
|
|
69
|
+
put_change_puppet_environment(
|
|
70
|
+
params: bulk_params.merge(environment_id: missing_environment_id),
|
|
71
|
+
session: set_session_user
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
assert_response :unprocessable_entity
|
|
75
|
+
response = JSON.parse(@response.body)
|
|
76
|
+
assert_equal "A Puppet environment with id #{missing_environment_id} could not be found.",
|
|
77
|
+
response.dig('error', 'message')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
test 'returns error when changing puppet environment fails for some hosts' do
|
|
81
|
+
::BulkHostsManager.any_instance.expects(:change_puppet_environment)
|
|
82
|
+
.with(environment)
|
|
83
|
+
.returns([host2.id])
|
|
84
|
+
|
|
85
|
+
put_change_puppet_environment(
|
|
86
|
+
params: bulk_params.merge(environment_id: environment.id),
|
|
87
|
+
session: set_session_user
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
assert_response :unprocessable_entity
|
|
91
|
+
response = JSON.parse(@response.body)
|
|
92
|
+
assert_equal 'Failed to change environment for 1 host',
|
|
93
|
+
response.dig('error', 'message')
|
|
94
|
+
assert_equal [host2.id], response.dig('error', 'failed_host_ids')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
test 'returns error when puppet environment is outside host taxonomies' do
|
|
98
|
+
invalid_environment = FactoryBot.create(:environment,
|
|
99
|
+
organizations: [host.organization],
|
|
100
|
+
locations: [FactoryBot.create(:location)])
|
|
101
|
+
|
|
102
|
+
put_change_puppet_environment(
|
|
103
|
+
params: bulk_params.merge(environment_id: invalid_environment.id),
|
|
104
|
+
session: set_session_user
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert_response :unprocessable_entity
|
|
108
|
+
response = JSON.parse(@response.body)
|
|
109
|
+
assert_equal 'Selected Puppet environment is not assigned to the proper organization and/or location for all hosts.',
|
|
110
|
+
response.dig('error', 'message')
|
|
111
|
+
assert_equal [host.id, host2.id].sort, response.dig('error', 'failed_host_ids').sort
|
|
112
|
+
end
|
|
113
|
+
|
|
21
114
|
test 'changes puppet proxy for selected hosts' do
|
|
22
115
|
put :change_puppet_proxy,
|
|
23
116
|
params: bulk_params.merge(proxy_id: proxy.id, ca_proxy: false)
|
|
@@ -117,6 +117,72 @@ module ForemanPuppet
|
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
describe '#complete_for' do
|
|
121
|
+
let(:host) { FactoryBot.create(:host, :with_puppet_enc, :with_puppetclass) }
|
|
122
|
+
|
|
123
|
+
test 'can complete Puppet class values' do
|
|
124
|
+
puppetclass = host.puppet.puppetclasses.first
|
|
125
|
+
completions = ::Host::Managed.complete_for("puppetclass = #{puppetclass.name}")
|
|
126
|
+
|
|
127
|
+
assert_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
test 'can complete config group values' do
|
|
131
|
+
config_group = FactoryBot.create(:config_group)
|
|
132
|
+
host.puppet.config_groups << config_group
|
|
133
|
+
completions = ::Host::Managed.complete_for("config_group = #{config_group.name}")
|
|
134
|
+
|
|
135
|
+
assert_includes completions, %(config_group = "#{config_group.name}")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
test 'can complete Puppet class values inherited from a hostgroup' do
|
|
139
|
+
hostgroup = FactoryBot.create(:hostgroup, :with_puppet_enc, :with_puppetclass)
|
|
140
|
+
FactoryBot.create(:host, hostgroup: hostgroup)
|
|
141
|
+
puppetclass = hostgroup.puppet.puppetclasses.first
|
|
142
|
+
completions = ::Host::Managed.complete_for("puppetclass = #{puppetclass.name}")
|
|
143
|
+
|
|
144
|
+
assert_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
test 'can complete Puppet class values assigned through a config group' do
|
|
148
|
+
config_group = FactoryBot.create(:config_group, :with_puppetclass)
|
|
149
|
+
host.puppet.config_groups << config_group
|
|
150
|
+
puppetclass = config_group.puppetclasses.first
|
|
151
|
+
completions = ::Host::Managed.complete_for("puppetclass = #{puppetclass.name}")
|
|
152
|
+
|
|
153
|
+
assert_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
test 'can complete config group values inherited from a hostgroup' do
|
|
157
|
+
hostgroup = FactoryBot.create(:hostgroup, :with_puppet_enc, :with_config_group)
|
|
158
|
+
FactoryBot.create(:host, hostgroup: hostgroup)
|
|
159
|
+
config_group = hostgroup.puppet.config_groups.first
|
|
160
|
+
completions = ::Host::Managed.complete_for("config_group = #{config_group.name}")
|
|
161
|
+
|
|
162
|
+
assert_includes completions, %(config_group = "#{config_group.name}")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
test 'does not complete unassigned Puppet class values' do
|
|
166
|
+
puppetclass = FactoryBot.create(:puppetclass)
|
|
167
|
+
completions = ::Host::Managed.complete_for("puppetclass = #{puppetclass.name}")
|
|
168
|
+
|
|
169
|
+
assert_not_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
test 'does not complete unassigned config group values' do
|
|
173
|
+
config_group = FactoryBot.create(:config_group)
|
|
174
|
+
completions = ::Host::Managed.complete_for("config_group = #{config_group.name}")
|
|
175
|
+
|
|
176
|
+
assert_not_includes completions, %(config_group = "#{config_group.name}")
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
test 'preserves core host value completions' do
|
|
180
|
+
completions = as_admin { ::Host::Managed.complete_for('user.login =') }
|
|
181
|
+
|
|
182
|
+
assert_includes completions, 'user.login = current_user'
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
120
186
|
describe '#info puppet bits' do
|
|
121
187
|
test 'ENC YAML omits environment if no puppet facet' do
|
|
122
188
|
host = FactoryBot.build_stubbed(:host)
|
|
@@ -22,5 +22,37 @@ module ForemanPuppet
|
|
|
22
22
|
assert_includes hostgroup.puppet.puppetclasses, puppet_class
|
|
23
23
|
assert_includes hostgroup.puppetclasses, puppet_class
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
test 'can complete Puppet class values' do
|
|
27
|
+
puppetclass = FactoryBot.create(:puppetclass)
|
|
28
|
+
hostgroup.puppet.puppetclasses << puppetclass
|
|
29
|
+
completions = ::Hostgroup.complete_for("puppetclass = #{puppetclass.name}")
|
|
30
|
+
|
|
31
|
+
assert_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
test 'can complete config group values' do
|
|
35
|
+
config_group = hostgroup.puppet.config_groups.first
|
|
36
|
+
completions = ::Hostgroup.complete_for("config_group = #{config_group.name}")
|
|
37
|
+
|
|
38
|
+
assert_includes completions, %(config_group = "#{config_group.name}")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test 'can complete Puppet class values inherited from a parent hostgroup' do
|
|
42
|
+
parent = FactoryBot.create(:hostgroup, :with_puppet_enc, :with_puppetclass)
|
|
43
|
+
FactoryBot.create(:hostgroup, parent: parent)
|
|
44
|
+
puppetclass = parent.puppet.puppetclasses.first
|
|
45
|
+
completions = ::Hostgroup.complete_for("puppetclass = #{puppetclass.name}")
|
|
46
|
+
|
|
47
|
+
assert_includes completions, %(puppetclass = "#{puppetclass.name}")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
test 'searches Puppet class values assigned through a config group' do
|
|
51
|
+
config_group = hostgroup.puppet.config_groups.first
|
|
52
|
+
puppetclass = FactoryBot.create(:puppetclass)
|
|
53
|
+
config_group.puppetclasses << puppetclass
|
|
54
|
+
|
|
55
|
+
assert_includes ::Hostgroup.search_for("puppetclass = #{puppetclass.name}"), hostgroup
|
|
56
|
+
end
|
|
25
57
|
end
|
|
26
58
|
end
|
|
@@ -4,6 +4,51 @@ class BulkHostsManagerTest < ActiveSupport::TestCase
|
|
|
4
4
|
let(:hosts) { FactoryBot.create_list(:host, 2, :with_puppet_enc) }
|
|
5
5
|
let(:manager) { ::BulkHostsManager.new(hosts: hosts) }
|
|
6
6
|
let(:proxy) { FactoryBot.create(:puppet_smart_proxy) }
|
|
7
|
+
let(:environment) { FactoryBot.create(:environment, organizations: [hosts.first.organization], locations: [hosts.first.location]) }
|
|
8
|
+
|
|
9
|
+
test 'changes puppet environment for hosts' do
|
|
10
|
+
manager.change_puppet_environment(environment)
|
|
11
|
+
|
|
12
|
+
hosts.each do |host|
|
|
13
|
+
assert_equal environment.id, host.reload.puppet.environment_id
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test 'inherits puppet environment from hostgroup' do
|
|
18
|
+
organization = FactoryBot.create(:organization)
|
|
19
|
+
location = FactoryBot.create(:location)
|
|
20
|
+
inherited_environment = FactoryBot.create(:environment, organizations: [organization], locations: [location])
|
|
21
|
+
initial_environment = FactoryBot.create(:environment, organizations: [organization], locations: [location])
|
|
22
|
+
hostgroup = FactoryBot.create(:hostgroup, :with_puppet_enc,
|
|
23
|
+
environment: inherited_environment,
|
|
24
|
+
organizations: [organization],
|
|
25
|
+
locations: [location])
|
|
26
|
+
inherited_hosts = FactoryBot.create_list(:host, 2, :with_puppet_enc,
|
|
27
|
+
environment: initial_environment,
|
|
28
|
+
hostgroup: hostgroup,
|
|
29
|
+
organization: organization,
|
|
30
|
+
location: location)
|
|
31
|
+
|
|
32
|
+
inherited_hosts.each do |host|
|
|
33
|
+
assert_not_equal inherited_environment.id, host.reload.puppet.environment_id
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
::BulkHostsManager.new(hosts: inherited_hosts).change_puppet_environment('inherit')
|
|
37
|
+
|
|
38
|
+
inherited_hosts.each do |host|
|
|
39
|
+
assert_equal inherited_environment.id, host.reload.puppet.environment_id
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test 'clears puppet environment when environment is nil' do
|
|
44
|
+
hosts.each { |host| host.puppet.update!(environment: environment) }
|
|
45
|
+
|
|
46
|
+
manager.change_puppet_environment(nil)
|
|
47
|
+
|
|
48
|
+
hosts.each do |host|
|
|
49
|
+
assert_nil host.reload.puppet.environment
|
|
50
|
+
end
|
|
51
|
+
end
|
|
7
52
|
|
|
8
53
|
test 'changes puppet proxy for hosts' do
|
|
9
54
|
manager.change_puppet_proxy(proxy, false)
|
|
@@ -6,5 +6,13 @@ export const API = {
|
|
|
6
6
|
patch: jest.fn(),
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
export const APIActions = {
|
|
10
|
+
get: jest.fn(),
|
|
11
|
+
post: jest.fn(),
|
|
12
|
+
put: jest.fn(),
|
|
13
|
+
patch: jest.fn(),
|
|
14
|
+
delete: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
9
17
|
export const get = data => ({ type: 'get-some-type', ...data });
|
|
10
18
|
export const post = data => ({ type: 'post-some-type', ...data });
|
data/webpack/global_index.js
CHANGED
|
@@ -7,12 +7,15 @@ import reducers from './src/reducers';
|
|
|
7
7
|
import { registerFills } from './src/Extends/Fills';
|
|
8
8
|
import { registerLegacy } from './legacy';
|
|
9
9
|
import HostsIndexActionsBar from './src/Extends/Hosts/ActionsBar';
|
|
10
|
+
import BulkChangePuppetEnvironment from './src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment';
|
|
11
|
+
import BulkRemovePuppetEnvironment from './src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment';
|
|
10
12
|
import BulkChangePuppetProxy from './src/Extends/Hosts/BulkActions/BulkChangePuppetProxy';
|
|
11
13
|
import BulkChangePuppetCAProxy from './src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy';
|
|
12
14
|
import BulkRemovePuppetProxy from './src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy';
|
|
13
15
|
import BulkRemovePuppetCAProxy from './src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy';
|
|
14
16
|
|
|
15
17
|
const GLOBAL_FILL_PRIORITY = 100;
|
|
18
|
+
const PUPPET_ENV_COLUMN_WEIGHT = 2700;
|
|
16
19
|
|
|
17
20
|
// register reducers
|
|
18
21
|
registerReducer('puppet', reducers);
|
|
@@ -28,7 +31,7 @@ const puppetHostsIndexColumns = [
|
|
|
28
31
|
title: __('Puppet env'),
|
|
29
32
|
isSorted: true,
|
|
30
33
|
wrapper: hostDetails => hostDetails.environment_name,
|
|
31
|
-
weight:
|
|
34
|
+
weight: PUPPET_ENV_COLUMN_WEIGHT,
|
|
32
35
|
},
|
|
33
36
|
];
|
|
34
37
|
|
|
@@ -45,6 +48,20 @@ addGlobalFill(
|
|
|
45
48
|
GLOBAL_FILL_PRIORITY
|
|
46
49
|
);
|
|
47
50
|
|
|
51
|
+
addGlobalFill(
|
|
52
|
+
'_all-hosts-modals',
|
|
53
|
+
'BulkChangePuppetEnvironment',
|
|
54
|
+
<BulkChangePuppetEnvironment key="bulk-change-puppet-environment" />,
|
|
55
|
+
GLOBAL_FILL_PRIORITY
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
addGlobalFill(
|
|
59
|
+
'_all-hosts-modals',
|
|
60
|
+
'BulkRemovePuppetEnvironment',
|
|
61
|
+
<BulkRemovePuppetEnvironment key="bulk-remove-puppet-environment" />,
|
|
62
|
+
GLOBAL_FILL_PRIORITY
|
|
63
|
+
);
|
|
64
|
+
|
|
48
65
|
addGlobalFill(
|
|
49
66
|
'_all-hosts-modals',
|
|
50
67
|
'BulkChangePuppetProxy',
|