-
Notifications
You must be signed in to change notification settings - Fork 29
Add Puppet proxy (CA) bulk actions #429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| module ForemanPuppet | ||
| module Api | ||
| module V2 | ||
| class HostsBulkActionsController < ::ForemanPuppet::Api::V2::PuppetBaseController | ||
| include ::Api::V2::BulkHostsExtension | ||
| before_action :find_editable_hosts, only: %i[change_puppet_proxy remove_puppet_proxy] | ||
| before_action :find_smart_proxy, only: %i[change_puppet_proxy] | ||
|
|
||
| def_param_group :bulk_params do | ||
| param :organization_id, :number, required: true, desc: N_('ID of the organization') | ||
| param :included, Hash, required: true, action_aware: true do | ||
| param :search, String, required: false, desc: N_('Search string for hosts to perform an action on') | ||
| param :ids, Array, required: false, desc: N_('List of host ids to perform an action on') | ||
| end | ||
| param :excluded, Hash, required: true, action_aware: true do | ||
| param :ids, Array, required: false, desc: N_('List of host ids to exclude and not run an action on') | ||
| end | ||
| end | ||
|
|
||
| api :PUT, '/hosts/bulk/change_puppet_proxy', N_('Change Puppet (CA) Proxy') | ||
| param_group :bulk_params | ||
| param :proxy_id, :number, required: true, desc: N_('ID of the Puppet proxy to reassign the hosts to') | ||
| param :ca_proxy, :bool, required: true, desc: N_('True, if Puppet CA proxy should be changed instead of the Puppet proxy') | ||
| def change_puppet_proxy | ||
| error_hosts = ::BulkHostsManager.new(hosts: @hosts).change_puppet_proxy(@proxy, ca_proxy?) | ||
| process_bulk_puppet_proxy_response( | ||
| error_hosts, | ||
| success_message: format(n_( | ||
| 'Updated host: changed %{proxy_type}', | ||
| 'Updated hosts: changed %{proxy_type}', | ||
| @hosts.count | ||
| ), proxy_type: proxy_type), | ||
| error_message: format(n_( | ||
| 'Failed to change %{proxy_type} for %{count} host', | ||
| 'Failed to change %{proxy_type} for %{count} hosts', | ||
| error_hosts.count | ||
| ), proxy_type: proxy_type, count: error_hosts.count) | ||
| ) | ||
|
nadjaheitmann marked this conversation as resolved.
|
||
| end | ||
|
|
||
| api :PUT, '/hosts/bulk/remove_puppet_proxy', N_('Remove Puppet (CA) Proxy') | ||
| param_group :bulk_params | ||
| param :ca_proxy, :bool, required: true, desc: N_('True, if Puppet CA proxy should be removed instead of the Puppet proxy') | ||
| def remove_puppet_proxy | ||
| error_hosts = ::BulkHostsManager.new(hosts: @hosts).change_puppet_proxy(nil, ca_proxy?) | ||
| process_bulk_puppet_proxy_response( | ||
| error_hosts, | ||
| success_message: format(n_( | ||
| 'Updated host: removed %{proxy_type}', | ||
| 'Updated hosts: removed %{proxy_type}', | ||
| @hosts.count | ||
| ), proxy_type: proxy_type), | ||
| error_message: format(n_( | ||
| 'Failed to remove %{proxy_type} for %{count} host', | ||
| 'Failed to remove %{proxy_type} for %{count} hosts', | ||
| error_hosts.count | ||
| ), proxy_type: proxy_type, count: error_hosts.count) | ||
| ) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def find_editable_hosts | ||
| find_bulk_hosts(:edit_hosts, params) | ||
| end | ||
|
|
||
| def process_bulk_puppet_proxy_response(error_hosts, success_message:, error_message:) | ||
| if error_hosts.empty? | ||
| process_response(true, { message: success_message }) | ||
| else | ||
| render_error(:bulk_hosts_error, status: :unprocessable_entity, | ||
| locals: { message: error_message, failed_host_ids: error_hosts }) | ||
| end | ||
| end | ||
|
|
||
| def find_smart_proxy | ||
| feature = ca_proxy? ? 'Puppet CA' : 'Puppet' | ||
| @proxy = SmartProxy.with_features(feature).find_by(id: params[:proxy_id]) | ||
|
|
||
| if @proxy.nil? | ||
| render json: { | ||
| error: { | ||
| message: format(_('A Smart Proxy with id %{id} and the %{proxy_type} feature could not be found.'), id: params[:proxy_id], proxy_type: proxy_type), | ||
| }, | ||
| }, status: :unprocessable_entity | ||
| false | ||
| else | ||
| true | ||
| end | ||
| end | ||
|
|
||
| def ca_proxy? | ||
| Foreman::Cast.to_bool(params[:ca_proxy]) | ||
| end | ||
|
|
||
| def proxy_type | ||
| ca_proxy? ? _('Puppet CA proxy') : _('Puppet proxy') | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| module ForemanPuppet | ||
| module Extensions | ||
| module BulkHostsManager | ||
| extend ActiveSupport::Concern | ||
|
|
||
| def change_puppet_proxy(proxy, is_ca_proxy) | ||
|
nadjaheitmann marked this conversation as resolved.
|
||
| error_hosts = [] | ||
| @hosts.each do |host| | ||
| if is_ca_proxy | ||
| host.puppet_ca_proxy = proxy | ||
| else | ||
| host.puppet_proxy = proxy | ||
| end | ||
| host.save(validate: false) | ||
| rescue StandardError => e | ||
| message = format(_('Failed to set proxy for %{host}.'), host: host) | ||
| Foreman::Logging.exception(message, e) | ||
| error_hosts << host.id | ||
|
Comment on lines
+10
to
+18
|
||
| end | ||
| error_hosts | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| require 'test_puppet_helper' | ||
|
|
||
| module ForemanPuppet | ||
| module Api | ||
| module V2 | ||
| class HostsBulkActionsControllerTest < ActionController::TestCase | ||
| tests ::ForemanPuppet::Api::V2::HostsBulkActionsController | ||
|
|
||
| setup do | ||
| @routes = ::Foreman::Application.routes | ||
| end | ||
|
|
||
| let(:host) { FactoryBot.create(:host, :with_puppet_enc) } | ||
| let(:host2) do | ||
| FactoryBot.create(:host, :with_puppet_enc, | ||
| organization: host.organization, | ||
| location: host.location) | ||
| end | ||
| let(:proxy) { FactoryBot.create(:puppet_and_ca_smart_proxy, organizations: [host.organization], locations: [host.location]) } | ||
|
|
||
| test 'changes puppet proxy for selected hosts' do | ||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: proxy.id, ca_proxy: false) | ||
|
|
||
| assert_response :success | ||
| assert_equal proxy.id, host2.reload.puppet_proxy_id | ||
| assert_equal proxy.id, host.reload.puppet_proxy_id | ||
| end | ||
|
|
||
| test 'changes puppet ca proxy for selected hosts' do | ||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: proxy.id, ca_proxy: true) | ||
|
|
||
| assert_response :success | ||
| assert_equal proxy.id, host2.reload.puppet_ca_proxy_id | ||
| assert_equal proxy.id, host.reload.puppet_ca_proxy_id | ||
| end | ||
|
|
||
| test 'removes puppet proxy for selected hosts' do | ||
| host.update!(puppet_proxy: proxy) | ||
| host2.update!(puppet_proxy: proxy) | ||
|
|
||
| assert_equal proxy, host.reload.puppet_proxy | ||
|
|
||
| put :remove_puppet_proxy, | ||
| params: bulk_params.merge(ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :success | ||
| assert_nil host.reload.puppet_proxy | ||
| assert_nil host2.reload.puppet_proxy | ||
| end | ||
|
|
||
| test 'returns error when puppet proxy is missing' do | ||
| missing_proxy_id = 999_999 | ||
|
|
||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: missing_proxy_id, ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal "A Smart Proxy with id #{missing_proxy_id} and the Puppet proxy feature could not be found.", | ||
| response.dig('error', 'message') | ||
| end | ||
|
|
||
| test 'returns error when puppet ca proxy is missing' do | ||
| missing_proxy_id = 999_999 | ||
|
|
||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: missing_proxy_id, ca_proxy: true), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal "A Smart Proxy with id #{missing_proxy_id} and the Puppet CA proxy feature could not be found.", | ||
| response.dig('error', 'message') | ||
| end | ||
|
|
||
| test 'returns error when smart proxy is missing puppet feature' do | ||
| invalid_proxy = FactoryBot.create(:smart_proxy, organizations: [host.organization], locations: [host.location]) | ||
| invalid_proxy.smart_proxy_feature_by_name('Puppet')&.destroy! | ||
|
|
||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: invalid_proxy.id, ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal "A Smart Proxy with id #{invalid_proxy.id} and the Puppet proxy feature could not be found.", | ||
| response.dig('error', 'message') | ||
| end | ||
|
|
||
| test 'returns error when smart proxy is missing puppet ca feature' do | ||
| invalid_proxy = FactoryBot.create(:puppet_smart_proxy, organizations: [host.organization], locations: [host.location]) | ||
|
|
||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: invalid_proxy.id, ca_proxy: true), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal "A Smart Proxy with id #{invalid_proxy.id} and the Puppet CA proxy feature could not be found.", | ||
| response.dig('error', 'message') | ||
| end | ||
|
|
||
| test 'returns error when changing puppet proxy fails for some hosts' do | ||
| ::BulkHostsManager.any_instance.expects(:change_puppet_proxy) | ||
| .with(proxy, false) | ||
| .returns([host2.id]) | ||
|
|
||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: proxy.id, ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal 'Failed to change Puppet proxy for 1 host', | ||
| response.dig('error', 'message') | ||
| assert_equal [host2.id], response.dig('error', 'failed_host_ids') | ||
| end | ||
|
|
||
| test 'returns error when removing puppet proxy fails for some hosts' do | ||
| host.update!(puppet_proxy: proxy) | ||
| host2.update!(puppet_proxy: proxy) | ||
| ::BulkHostsManager.any_instance.expects(:change_puppet_proxy) | ||
| .with(nil, false) | ||
| .returns([host.id]) | ||
|
|
||
| put :remove_puppet_proxy, | ||
| params: bulk_params.merge(ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal 'Failed to remove Puppet proxy for 1 host', | ||
| response.dig('error', 'message') | ||
| assert_equal [host.id], response.dig('error', 'failed_host_ids') | ||
| assert_equal proxy.id, host.reload.puppet_proxy_id | ||
| end | ||
|
|
||
| test 'returns error when removing puppet ca proxy fails for some hosts' do | ||
| host.update!(puppet_ca_proxy: proxy) | ||
| host2.update!(puppet_ca_proxy: proxy) | ||
| ::BulkHostsManager.any_instance.expects(:change_puppet_proxy) | ||
| .with(nil, true) | ||
| .returns([host.id]) | ||
|
|
||
| put :remove_puppet_proxy, | ||
| params: bulk_params.merge(ca_proxy: true), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal 'Failed to remove Puppet CA proxy for 1 host', | ||
| response.dig('error', 'message') | ||
| assert_equal [host.id], response.dig('error', 'failed_host_ids') | ||
| assert_equal proxy.id, host.reload.puppet_ca_proxy_id | ||
| end | ||
|
|
||
| def bulk_params | ||
| { | ||
| organization_id: host.organization_id, | ||
| included: { ids: [host.id, host2.id] }, | ||
| excluded: { ids: [] }, | ||
| } | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| require 'test_puppet_helper' | ||
|
|
||
| class BulkHostsManagerTest < ActiveSupport::TestCase | ||
| let(:hosts) { FactoryBot.create_list(:host, 2, :with_puppet_enc) } | ||
| let(:manager) { ::BulkHostsManager.new(hosts: hosts) } | ||
| let(:proxy) { FactoryBot.create(:puppet_smart_proxy) } | ||
|
|
||
| test 'changes puppet proxy for hosts' do | ||
| manager.change_puppet_proxy(proxy, false) | ||
|
|
||
| hosts.each do |host| | ||
| assert_equal proxy.id, host.reload.puppet_proxy_id | ||
| end | ||
| end | ||
|
|
||
| test 'changes puppet ca proxy for hosts' do | ||
| manager.change_puppet_proxy(proxy, true) | ||
|
|
||
| hosts.each do |host| | ||
| assert_equal proxy.id, host.reload.puppet_ca_proxy_id | ||
| end | ||
| end | ||
|
|
||
| test 'clears puppet proxy when proxy is nil' do | ||
| hosts.each { |host| host.update!(puppet_proxy: proxy) } | ||
|
|
||
| manager.change_puppet_proxy(nil, false) | ||
|
|
||
| hosts.each do |host| | ||
| assert_nil host.reload.puppet_proxy | ||
| end | ||
| end | ||
| end |
Uh oh!
There was an error while loading. Please reload this page.