foreman_remote_execution 4.5.0 → 4.5.1
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/job_invocations_controller.rb +1 -1
- data/app/lib/actions/remote_execution/run_host_job.rb +5 -1
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +2 -0
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
- data/app/models/host_proxy_invocation.rb +4 -0
- data/app/models/host_status/execution_status.rb +3 -3
- data/app/models/job_invocation.rb +9 -6
- data/app/models/job_invocation_composer.rb +2 -2
- data/app/models/remote_execution_provider.rb +1 -1
- data/app/models/setting/remote_execution.rb +2 -2
- data/app/models/targeting.rb +5 -1
- data/app/views/job_invocations/index.html.erb +1 -1
- data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
- data/lib/foreman_remote_execution/engine.rb +0 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/unit/job_invocation_composer_test.rb +14 -1
- data/test/unit/job_invocation_test.rb +1 -1
- metadata +4 -5
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
- data/test/models/orchestration/ssh_test.rb +0 -56
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e6f79124fa44d1ce9756c7c680a43ea7c9c1d309836641e4f1d91fe713a75fdb
         | 
| 4 | 
            +
              data.tar.gz: 1db640940ff3ba7a44b183c017ee0c1c3262e5263553365e930695b5f1686b8e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 9c105b218161cc5e509c5da55ca76d339d37d217e318aff139609361ece08ff0fa36c0b70fbb41e0c2bfac2633c86218fd4539e762e1c4f0e1ed49dc778ec728
         | 
| 7 | 
            +
              data.tar.gz: 9d148bc9b8af5f27c6b5bb91d8e28ea27bbff870ce1239a2e87413d5cf49b5740ccad18f713f22a1d348ff5fe185bdef015dd2bbd1b85f2efe802547e88fe193
         | 
| @@ -67,7 +67,7 @@ class JobInvocationsController < ApplicationController | |
| 67 67 | 
             
              end
         | 
| 68 68 |  | 
| 69 69 | 
             
              def index
         | 
| 70 | 
            -
                @job_invocations = resource_base_search_and_page. | 
| 70 | 
            +
                @job_invocations = resource_base_search_and_page.preload(:task, :targeting).order('job_invocations.id DESC')
         | 
| 71 71 | 
             
              end
         | 
| 72 72 |  | 
| 73 73 | 
             
              # refreshes the form
         | 
| @@ -47,12 +47,16 @@ module Actions | |
| 47 47 | 
             
                    script = renderer.render
         | 
| 48 48 | 
             
                    raise _('Failed rendering template: %s') % renderer.error_message unless script
         | 
| 49 49 |  | 
| 50 | 
            +
                    first_execution = host.executed_through_proxies.where(:id => proxy.id).none?
         | 
| 51 | 
            +
                    host.executed_through_proxies << proxy if first_execution
         | 
| 52 | 
            +
             | 
| 50 53 | 
             
                    additional_options = { :hostname => provider.find_ip_or_hostname(host),
         | 
| 51 54 | 
             
                                           :script => script,
         | 
| 52 55 | 
             
                                           :execution_timeout_interval => job_invocation.execution_timeout_interval,
         | 
| 53 56 | 
             
                                           :secrets => secrets(host, job_invocation, provider),
         | 
| 54 57 | 
             
                                           :use_batch_triggering => true,
         | 
| 55 | 
            -
                                           :use_concurrency_control => options[:use_concurrency_control] | 
| 58 | 
            +
                                           :use_concurrency_control => options[:use_concurrency_control],
         | 
| 59 | 
            +
                                           :first_execution => first_execution }
         | 
| 56 60 | 
             
                    action_options = provider.proxy_command_options(template_invocation, host)
         | 
| 57 61 | 
             
                                             .merge(additional_options)
         | 
| 58 62 |  | 
| @@ -6,6 +6,8 @@ module ForemanRemoteExecution | |
| 6 6 | 
             
                    has_many :template_invocations, :dependent => :destroy, :foreign_key => 'host_id'
         | 
| 7 7 | 
             
                    has_one :execution_status_object, :class_name => 'HostStatus::ExecutionStatus', :foreign_key => 'host_id', :dependent => :destroy
         | 
| 8 8 | 
             
                    has_many :run_host_job_tasks, :through => :template_invocations
         | 
| 9 | 
            +
                    has_many :host_proxy_invocations, :foreign_key => 'host_id', :dependent => :destroy
         | 
| 10 | 
            +
                    has_many :executed_through_proxies, :through => :host_proxy_invocations, :source => 'smart_proxy'
         | 
| 9 11 |  | 
| 10 12 | 
             
                    scoped_search :relation => :run_host_job_tasks, :on => :result, :rename => 'job_invocation.result',
         | 
| 11 13 | 
             
                      :ext_method => :search_by_job_invocation,
         | 
| @@ -64,11 +64,11 @@ class HostStatus::ExecutionStatus < HostStatus::Status | |
| 64 64 |  | 
| 65 65 | 
             
                  case status
         | 
| 66 66 | 
             
                    when OK
         | 
| 67 | 
            -
                      [ "foreman_tasks_tasks.state = 'stopped' AND result = 'success'" ]
         | 
| 67 | 
            +
                      [ "foreman_tasks_tasks.state = 'stopped' AND foreman_tasks_tasks.result = 'success'" ]
         | 
| 68 68 | 
             
                    when CANCELLED
         | 
| 69 | 
            -
                      [ "foreman_tasks_tasks.state = 'stopped' AND result = 'cancelled'" ]
         | 
| 69 | 
            +
                      [ "foreman_tasks_tasks.state = 'stopped' AND foreman_tasks_tasks.result = 'cancelled'" ]
         | 
| 70 70 | 
             
                    when ERROR
         | 
| 71 | 
            -
                      [ "foreman_tasks_tasks.state = 'stopped' AND (result = 'error' OR result = 'warning')" ]
         | 
| 71 | 
            +
                      [ "foreman_tasks_tasks.state = 'stopped' AND (foreman_tasks_tasks.result = 'error' OR foreman_tasks_tasks.result = 'warning')" ]
         | 
| 72 72 | 
             
                    when QUEUED
         | 
| 73 73 | 
             
                      [ "foreman_tasks_tasks.state = 'scheduled' OR foreman_tasks_tasks.state IS NULL" ]
         | 
| 74 74 | 
             
                    when RUNNING
         | 
| @@ -65,8 +65,6 @@ class JobInvocation < ApplicationRecord | |
| 65 65 | 
             
              scoped_search :on => 'pattern_template_name', :rename => 'pattern_template_name', :operators => ['= '],
         | 
| 66 66 | 
             
                :complete_value => false, :only_explicit => true, :ext_method => :search_by_pattern_template
         | 
| 67 67 |  | 
| 68 | 
            -
              scope :with_task, -> { references(:task) }
         | 
| 69 | 
            -
             | 
| 70 68 | 
             
              scoped_search :relation => :recurring_logic, :on => 'id', :rename => 'recurring_logic.id'
         | 
| 71 69 |  | 
| 72 70 | 
             
              scoped_search :relation => :recurring_logic, :on => 'id', :rename => 'recurring',
         | 
| @@ -99,7 +97,7 @@ class JobInvocation < ApplicationRecord | |
| 99 97 | 
             
              def self.search_by_status(key, operator, value)
         | 
| 100 98 | 
             
                conditions = HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.sql_conditions_for(value)
         | 
| 101 99 | 
             
                conditions[0] = "NOT (#{conditions[0]})" if operator == '<>'
         | 
| 102 | 
            -
                { :conditions => sanitize_sql_for_conditions(conditions), : | 
| 100 | 
            +
                { :conditions => sanitize_sql_for_conditions(conditions), :joins => :task }
         | 
| 103 101 | 
             
              end
         | 
| 104 102 |  | 
| 105 103 | 
             
              def self.search_by_recurring_logic(key, operator, value)
         | 
| @@ -193,11 +191,16 @@ class JobInvocation < ApplicationRecord | |
| 193 191 | 
             
              end
         | 
| 194 192 |  | 
| 195 193 | 
             
              def total_hosts_count
         | 
| 194 | 
            +
                count = _('N/A')
         | 
| 195 | 
            +
             | 
| 196 196 | 
             
                if targeting.resolved?
         | 
| 197 | 
            -
                  task&.main_action | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 197 | 
            +
                  count = if task&.main_action.respond_to?(:total_count)
         | 
| 198 | 
            +
                            task.main_action.total_count
         | 
| 199 | 
            +
                          else
         | 
| 200 | 
            +
                            targeting.hosts.count
         | 
| 201 | 
            +
                          end
         | 
| 200 202 | 
             
                end
         | 
| 203 | 
            +
                count
         | 
| 201 204 | 
             
              end
         | 
| 202 205 |  | 
| 203 206 | 
             
              def pattern_template_invocation_for_host(host)
         | 
| @@ -174,7 +174,7 @@ class JobInvocationComposer | |
| 174 174 | 
             
                    input = template.template_inputs_with_foreign.find { |i| i.name == name }
         | 
| 175 175 | 
             
                    unless input
         | 
| 176 176 | 
             
                      raise ::Foreman::Exception, _('Unknown input %{input_name} for template %{template_name}') %
         | 
| 177 | 
            -
             | 
| 177 | 
            +
                        { :input_name => name, :template_name => template.name }
         | 
| 178 178 | 
             
                    end
         | 
| 179 179 | 
             
                    { :template_input_id => input.id, :value => value }
         | 
| 180 180 | 
             
                  end
         | 
| @@ -405,7 +405,7 @@ class JobInvocationComposer | |
| 405 405 | 
             
                job_invocation.effective_user_password = params[:effective_user_password]
         | 
| 406 406 |  | 
| 407 407 | 
             
                if @reruns && job_invocation.targeting.static?
         | 
| 408 | 
            -
                  job_invocation.targeting. | 
| 408 | 
            +
                  job_invocation.targeting.assign_host_ids(JobInvocation.find(@reruns).targeting.host_ids)
         | 
| 409 409 | 
             
                  job_invocation.targeting.mark_resolved!
         | 
| 410 410 | 
             
                end
         | 
| 411 411 |  | 
| @@ -50,7 +50,7 @@ class RemoteExecutionProvider | |
| 50 50 | 
             
                  method = host_setting(host, :remote_execution_effective_user_method)
         | 
| 51 51 | 
             
                  unless EFFECTIVE_USER_METHODS.include?(method)
         | 
| 52 52 | 
             
                    raise _('Effective user method "%{current_value}" is not one of %{valid_methods}') %
         | 
| 53 | 
            -
             | 
| 53 | 
            +
                      { :current_value => method, :valid_methods => EFFECTIVE_USER_METHODS}
         | 
| 54 54 | 
             
                  end
         | 
| 55 55 | 
             
                  method
         | 
| 56 56 | 
             
                end
         | 
| @@ -70,13 +70,13 @@ class Setting::RemoteExecution < Setting | |
| 70 70 | 
             
                  self.set('remote_execution_form_job_template',
         | 
| 71 71 | 
             
                    N_('Choose a job template that is pre-selected in job invocation form'),
         | 
| 72 72 | 
             
                    'Run Command - SSH Default',
         | 
| 73 | 
            -
                     | 
| 73 | 
            +
                    N_('Form Job Template'),
         | 
| 74 74 | 
             
                    nil,
         | 
| 75 75 | 
             
                    { :collection => proc { Hash[JobTemplate.unscoped.map { |template| [template.name, template.name] }] } }),
         | 
| 76 76 | 
             
                  self.set('remote_execution_job_invocation_report_template',
         | 
| 77 77 | 
             
                    N_('Select a report template used for generating a report for a particular remote execution job'),
         | 
| 78 78 | 
             
                    'Jobs - Invocation report template',
         | 
| 79 | 
            -
                     | 
| 79 | 
            +
                    N_('Job Invocation Report Template'),
         | 
| 80 80 | 
             
                    nil,
         | 
| 81 81 | 
             
                    { :collection => proc { self.job_invocation_report_templates_select } }),
         | 
| 82 82 | 
             
                ]
         | 
    
        data/app/models/targeting.rb
    CHANGED
    
    | @@ -46,9 +46,13 @@ class Targeting < ApplicationRecord | |
| 46 46 | 
             
                #   pluck(:id) returns duplicate results for HostCollections
         | 
| 47 47 | 
             
                host_ids = User.as(user.login) { Host.authorized(RESOLVE_PERMISSION, Host).search_for(search_query).order(:name, :id).pluck(:id).uniq }
         | 
| 48 48 | 
             
                host_ids.shuffle!(random: Random.new) if randomized_ordering
         | 
| 49 | 
            +
                self.assign_host_ids(host_ids)
         | 
| 50 | 
            +
                self.save(:validate => false)
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def assign_host_ids(host_ids)
         | 
| 49 54 | 
             
                # this can be optimized even more, by introducing bulk insert
         | 
| 50 55 | 
             
                self.targeting_hosts.build(host_ids.map { |id| { :host_id => id } })
         | 
| 51 | 
            -
                self.save(:validate => false)
         | 
| 52 56 | 
             
              end
         | 
| 53 57 |  | 
| 54 58 | 
             
              def dynamic?
         | 
| @@ -21,7 +21,7 @@ | |
| 21 21 | 
             
                <% @job_invocations.each do |invocation| %>
         | 
| 22 22 | 
             
                  <tr>
         | 
| 23 23 | 
             
                    <td class="text_warp"><%= link_to_if_authorized invocation_description(invocation), hash_for_job_invocation_path(invocation).merge(:auth_object => invocation, :permission => :view_job_invocations, :authorizer => authorizer) %></td>
         | 
| 24 | 
            -
                    <td><%= trunc_with_tooltip(invocation | 
| 24 | 
            +
                    <td><%= trunc_with_tooltip(invocation.targeting.search_query, 15) %></td>
         | 
| 25 25 | 
             
                    <td><%= link_to_invocation_task_if_authorized(invocation) %></td>
         | 
| 26 26 | 
             
                    <td><%= invocation_result(invocation, :success_count) %></td>
         | 
| 27 27 | 
             
                    <td><%= invocation_result(invocation, :failed_count) %></td>
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            class AddHostProxyInvocations < ActiveRecord::Migration[6.0]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                # rubocop:disable Rails/CreateTableWithTimestamps
         | 
| 4 | 
            +
                create_table :host_proxy_invocations do |t|
         | 
| 5 | 
            +
                  t.references :host, :null => false
         | 
| 6 | 
            +
                  t.references :smart_proxy, :null => false
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
                # rubocop:enable Rails/CreateTableWithTimestamps
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                add_index :host_proxy_invocations, [:host_id, :smart_proxy_id], unique: true
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -201,12 +201,10 @@ module ForemanRemoteExecution | |
| 201 201 |  | 
| 202 202 | 
             
                  Host::Managed.prepend ForemanRemoteExecution::HostExtensions
         | 
| 203 203 | 
             
                  Host::Managed.include ForemanTasks::Concerns::HostActionSubject
         | 
| 204 | 
            -
                  Host::Managed.include ForemanRemoteExecution::Orchestration::SSH
         | 
| 205 204 |  | 
| 206 205 | 
             
                  (Nic::Base.descendants + [Nic::Base]).each do |klass|
         | 
| 207 206 | 
             
                    klass.send(:include, ForemanRemoteExecution::NicExtensions)
         | 
| 208 207 | 
             
                  end
         | 
| 209 | 
            -
                  Nic::Managed.include ForemanRemoteExecution::Orchestration::SSH
         | 
| 210 208 |  | 
| 211 209 | 
             
                  Bookmark.include ForemanRemoteExecution::BookmarkExtensions
         | 
| 212 210 | 
             
                  HostsHelper.prepend ForemanRemoteExecution::HostsHelperExtensions
         | 
| @@ -864,7 +864,9 @@ class JobInvocationComposerTest < ActiveSupport::TestCase | |
| 864 864 | 
             
                it 'marks targeting as resolved if static' do
         | 
| 865 865 | 
             
                  created = JobInvocationComposer.from_job_invocation(job_invocation).job_invocation
         | 
| 866 866 | 
             
                  assert created.targeting.resolved?
         | 
| 867 | 
            -
                   | 
| 867 | 
            +
                  created.targeting.save
         | 
| 868 | 
            +
                  created.targeting.reload
         | 
| 869 | 
            +
                  assert_equal job_invocation.template_invocations_host_ids, created.targeting.targeting_hosts.pluck(:host_id)
         | 
| 868 870 | 
             
                end
         | 
| 869 871 |  | 
| 870 872 | 
             
                it 'takes randomized_ordering from the original job invocation when rerunning failed' do
         | 
| @@ -874,6 +876,17 @@ class JobInvocationComposerTest < ActiveSupport::TestCase | |
| 874 876 | 
             
                  composer = JobInvocationComposer.from_job_invocation(job_invocation, :host_ids => host_ids)
         | 
| 875 877 | 
             
                  assert composer.job_invocation.targeting.randomized_ordering
         | 
| 876 878 | 
             
                end
         | 
| 879 | 
            +
             | 
| 880 | 
            +
                it 'works with invalid hosts' do
         | 
| 881 | 
            +
                  host = job_invocation.targeting.hosts.first
         | 
| 882 | 
            +
                  ::Host::Managed.any_instance.stubs(:valid?).returns(false)
         | 
| 883 | 
            +
                  composer = JobInvocationComposer.from_job_invocation(job_invocation, {})
         | 
| 884 | 
            +
                  targeting = composer.compose.job_invocation.targeting
         | 
| 885 | 
            +
                  targeting.save!
         | 
| 886 | 
            +
                  targeting.reload
         | 
| 887 | 
            +
                  assert targeting.valid?
         | 
| 888 | 
            +
                  assert_equal targeting.hosts.pluck(:id), [host.id]
         | 
| 889 | 
            +
                end
         | 
| 877 890 | 
             
              end
         | 
| 878 891 |  | 
| 879 892 | 
             
              describe '.for_feature' do
         | 
| @@ -10,7 +10,7 @@ class JobInvocationTest < ActiveSupport::TestCase | |
| 10 10 | 
             
                end
         | 
| 11 11 |  | 
| 12 12 | 
             
                it 'is able to perform search through job invocations' do
         | 
| 13 | 
            -
                  found_jobs = JobInvocation.search_for(%{job_category = "#{job_invocation.job_category}"}).paginate(:page => 1). | 
| 13 | 
            +
                  found_jobs = JobInvocation.search_for(%{job_category = "#{job_invocation.job_category}"}).paginate(:page => 1).order('job_invocations.id DESC')
         | 
| 14 14 | 
             
                  _(found_jobs).must_equal [job_invocation]
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: foreman_remote_execution
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4.5. | 
| 4 | 
            +
              version: 4.5.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Foreman Remote Execution team
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021- | 
| 11 | 
            +
            date: 2021-07-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: deface
         | 
| @@ -171,7 +171,6 @@ files: | |
| 171 171 | 
             
            - app/models/concerns/foreman_remote_execution/foreman_tasks_triggering_extensions.rb
         | 
| 172 172 | 
             
            - app/models/concerns/foreman_remote_execution/host_extensions.rb
         | 
| 173 173 | 
             
            - app/models/concerns/foreman_remote_execution/nic_extensions.rb
         | 
| 174 | 
            -
            - app/models/concerns/foreman_remote_execution/orchestration/ssh.rb
         | 
| 175 174 | 
             
            - app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb
         | 
| 176 175 | 
             
            - app/models/concerns/foreman_remote_execution/subnet_extensions.rb
         | 
| 177 176 | 
             
            - app/models/concerns/foreman_remote_execution/taxonomy_extensions.rb
         | 
| @@ -180,6 +179,7 @@ files: | |
| 180 179 | 
             
            - app/models/concerns/foreman_remote_execution/template_overrides.rb
         | 
| 181 180 | 
             
            - app/models/concerns/foreman_remote_execution/user_extensions.rb
         | 
| 182 181 | 
             
            - app/models/foreign_input_set.rb
         | 
| 182 | 
            +
            - app/models/host_proxy_invocation.rb
         | 
| 183 183 | 
             
            - app/models/host_status/execution_status.rb
         | 
| 184 184 | 
             
            - app/models/input_template_renderer.rb
         | 
| 185 185 | 
             
            - app/models/invocation_provider_input_value.rb
         | 
| @@ -324,6 +324,7 @@ files: | |
| 324 324 | 
             
            - db/migrate/20200623073022_rename_sudo_password_to_effective_user_password.rb
         | 
| 325 325 | 
             
            - db/migrate/20200820122057_add_proxy_selector_override_to_remote_execution_feature.rb
         | 
| 326 326 | 
             
            - db/migrate/20210312074713_add_provider_inputs.rb
         | 
| 327 | 
            +
            - db/migrate/2021051713291621250977_add_host_proxy_invocations.rb
         | 
| 327 328 | 
             
            - db/seeds.d/100-assign_features_with_templates.rb
         | 
| 328 329 | 
             
            - db/seeds.d/20-permissions.rb
         | 
| 329 330 | 
             
            - db/seeds.d/50-notification_blueprints.rb
         | 
| @@ -380,7 +381,6 @@ files: | |
| 380 381 | 
             
            - test/functional/job_templates_controller_test.rb
         | 
| 381 382 | 
             
            - test/functional/ui_job_wizard_controller_test.rb
         | 
| 382 383 | 
             
            - test/helpers/remote_execution_helper_test.rb
         | 
| 383 | 
            -
            - test/models/orchestration/ssh_test.rb
         | 
| 384 384 | 
             
            - test/support/remote_execution_helper.rb
         | 
| 385 385 | 
             
            - test/test_plugin_helper.rb
         | 
| 386 386 | 
             
            - test/unit/actions/run_host_job_test.rb
         | 
| @@ -518,7 +518,6 @@ test_files: | |
| 518 518 | 
             
            - test/functional/job_templates_controller_test.rb
         | 
| 519 519 | 
             
            - test/functional/ui_job_wizard_controller_test.rb
         | 
| 520 520 | 
             
            - test/helpers/remote_execution_helper_test.rb
         | 
| 521 | 
            -
            - test/models/orchestration/ssh_test.rb
         | 
| 522 521 | 
             
            - test/support/remote_execution_helper.rb
         | 
| 523 522 | 
             
            - test/test_plugin_helper.rb
         | 
| 524 523 | 
             
            - test/unit/actions/run_host_job_test.rb
         | 
| @@ -1,70 +0,0 @@ | |
| 1 | 
            -
            module ForemanRemoteExecution
         | 
| 2 | 
            -
              module Orchestration::SSH
         | 
| 3 | 
            -
                extend ActiveSupport::Concern
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                included do
         | 
| 6 | 
            -
                  before_destroy :ssh_destroy
         | 
| 7 | 
            -
                  after_validation :queue_ssh_destroy
         | 
| 8 | 
            -
                  register_rebuild(:queue_ssh_destroy, N_("SSH_#{self.to_s.split('::').first}"))
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def drop_from_known_hosts(proxy_id)
         | 
| 12 | 
            -
                  _, _, target = host_kind_target
         | 
| 13 | 
            -
                  return true if target.nil?
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  proxy = ::SmartProxy.find(proxy_id)
         | 
| 16 | 
            -
                  begin
         | 
| 17 | 
            -
                    proxy.drop_host_from_known_hosts(target)
         | 
| 18 | 
            -
                  rescue ::ProxyAPI::ProxyException => e
         | 
| 19 | 
            -
                    if e.wrapped_exception.is_a?(RestClient::NotFound)
         | 
| 20 | 
            -
                      # ignore 404 when known_hosts entry is missing or the module was not enabled
         | 
| 21 | 
            -
                      Foreman::Logging.exception "Proxy failed to delete SSH known_hosts for #{name}, #{ip}", e, :level => :error
         | 
| 22 | 
            -
                    else
         | 
| 23 | 
            -
                      raise e
         | 
| 24 | 
            -
                    end
         | 
| 25 | 
            -
                  rescue => e
         | 
| 26 | 
            -
                    Rails.logger.warn e.message
         | 
| 27 | 
            -
                    return false
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                  true
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                def ssh_destroy
         | 
| 33 | 
            -
                  logger.debug "Scheduling SSH known_hosts cleanup"
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                  host, _kind, _target = host_kind_target
         | 
| 36 | 
            -
                  # #remote_execution_proxies may not be defined on the host object in some case
         | 
| 37 | 
            -
                  # for example Host::Discovered does not have it defined, even though these hosts
         | 
| 38 | 
            -
                  # have Nic::Managed interfaces associated with them
         | 
| 39 | 
            -
                  proxies = (host.try(:remote_execution_proxies, 'SSH') || {}).values
         | 
| 40 | 
            -
                  proxies.flatten.uniq.each do |proxy|
         | 
| 41 | 
            -
                    queue.create(id: queue_id(proxy.id), name: _("Remove SSH known hosts for %s") % self,
         | 
| 42 | 
            -
                      priority: 200, action: [self, :drop_from_known_hosts, proxy.id])
         | 
| 43 | 
            -
                  end
         | 
| 44 | 
            -
                end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                def queue_ssh_destroy
         | 
| 47 | 
            -
                  should_drop_from_known_hosts? && ssh_destroy
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                def should_drop_from_known_hosts?
         | 
| 51 | 
            -
                  host, = host_kind_target
         | 
| 52 | 
            -
                  host && !host.new_record? && host.build && host.changes.key?('build')
         | 
| 53 | 
            -
                end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                private
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                def host_kind_target
         | 
| 58 | 
            -
                  if self.is_a?(::Host::Base)
         | 
| 59 | 
            -
                    [self, 'host', name]
         | 
| 60 | 
            -
                  else
         | 
| 61 | 
            -
                    [self.host, 'interface', ip]
         | 
| 62 | 
            -
                  end
         | 
| 63 | 
            -
                end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                def queue_id(proxy_id)
         | 
| 66 | 
            -
                  _, kind, id = host_kind_target
         | 
| 67 | 
            -
                  "ssh_remove_known_hosts_#{kind}_#{id}_#{proxy_id}"
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
            end
         | 
| @@ -1,56 +0,0 @@ | |
| 1 | 
            -
            require 'test_plugin_helper'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class SSHOrchestrationTest < ActiveSupport::TestCase
         | 
| 4 | 
            -
              let(:host) { FactoryBot.create(:host, :managed, :with_subnet) }
         | 
| 5 | 
            -
              let(:proxy) { FactoryBot.create(:smart_proxy, :ssh) }
         | 
| 6 | 
            -
              let(:interface) { host.interfaces.first }
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              before { interface.subnet.remote_execution_proxies = [proxy] }
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              it 'attempts to drop IP address and hostname from smart proxies on destroy' do
         | 
| 11 | 
            -
                host.stubs(:skip_orchestration?).returns false
         | 
| 12 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(interface.ip)
         | 
| 13 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(host.name)
         | 
| 14 | 
            -
                host.destroy
         | 
| 15 | 
            -
              end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
              it 'attempts to drop IP address and hostname from smart proxies on rebuild' do
         | 
| 18 | 
            -
                host.stubs(:skip_orchestration?).returns false
         | 
| 19 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(interface.ip)
         | 
| 20 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(host.name)
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                host.build = true
         | 
| 23 | 
            -
                host.save!
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
         | 
| 26 | 
            -
                       "ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
         | 
| 27 | 
            -
                _(host.queue.task_ids).must_equal ids
         | 
| 28 | 
            -
                _(host.queue.items.map(&:status)).must_equal %w(completed completed)
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
              it 'does not fail on 404 from the smart proxy' do
         | 
| 32 | 
            -
                host.stubs(:skip_orchestration?).returns false
         | 
| 33 | 
            -
                ::ProxyAPI::RemoteExecutionSSH.any_instance.expects(:delete).raises(RestClient::ResourceNotFound).twice
         | 
| 34 | 
            -
                host.build = true
         | 
| 35 | 
            -
                host.save!
         | 
| 36 | 
            -
                ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
         | 
| 37 | 
            -
                       "ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
         | 
| 38 | 
            -
                _(host.queue.task_ids).must_equal ids
         | 
| 39 | 
            -
                _(host.queue.items.map(&:status)).must_equal %w(completed completed)
         | 
| 40 | 
            -
              end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              it 'does not trigger the removal when creating a new host' do
         | 
| 43 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).never
         | 
| 44 | 
            -
                host = Host::Managed.new(:name => 'test', :ip => '127.0.0.1')
         | 
| 45 | 
            -
                host.stubs(:skip_orchestration?).returns false
         | 
| 46 | 
            -
                _(host.queue.task_ids).must_equal []
         | 
| 47 | 
            -
              end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
              it 'does not call to the proxy when target is nil' do
         | 
| 50 | 
            -
                host.stubs(:skip_orchestration?).returns false
         | 
| 51 | 
            -
                SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(host.name)
         | 
| 52 | 
            -
                host.interfaces.first.stubs(:ip)
         | 
| 53 | 
            -
                host.destroy
         | 
| 54 | 
            -
                _(host.queue.items.map(&:status)).must_equal %w(completed completed)
         | 
| 55 | 
            -
              end
         | 
| 56 | 
            -
            end
         |