-
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
base: master
Are you sure you want to change the base?
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,109 @@ | ||
| 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 | ||
| @proxy = SmartProxy.find_by(id: params[:proxy_id]) | ||
|
nadjaheitmann marked this conversation as resolved.
|
||
|
|
||
| if @proxy.nil? | ||
| render json: { | ||
| error: { | ||
| message: format(_('The %{proxy_type} you have provided cannot be found.'), proxy_type: proxy_type), | ||
| }, | ||
| }, status: :unprocessable_entity | ||
| false | ||
| elsif (ca_proxy? && !@proxy.has_feature?('Puppet CA')) || | ||
| (!ca_proxy? && !@proxy.has_feature?('Puppet')) | ||
| render json: { | ||
| error: { | ||
| message: format(_('The Smart Proxy you have provided does not have the feature %{proxy_type}.'), proxy_type: proxy_type), | ||
| }, | ||
| }, status: :unprocessable_entity | ||
| false | ||
| else | ||
| true | ||
| end | ||
|
nadjaheitmann marked this conversation as resolved.
|
||
| 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, ca_proxy) | ||
| error_hosts = [] | ||
| @hosts.each do |host| | ||
| if 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,167 @@ | ||
| 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 | ||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: 999_999, ca_proxy: false), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal 'The Puppet proxy you have provided cannot be found.', | ||
| response.dig('error', 'message') | ||
| end | ||
|
|
||
| test 'returns error when puppet ca proxy is missing' do | ||
| put :change_puppet_proxy, | ||
| params: bulk_params.merge(proxy_id: 999_999, ca_proxy: true), | ||
| session: set_session_user | ||
|
|
||
| assert_response :unprocessable_entity | ||
| response = JSON.parse(@response.body) | ||
| assert_equal 'The Puppet CA proxy you have provided cannot 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 'The Smart Proxy you have provided does not have the feature Puppet proxy.', | ||
| 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 'The Smart Proxy you have provided does not have the feature Puppet CA proxy.', | ||
| 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.