foreman_remote_execution 3.2.1 → 3.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9caedc0baf4a767d6b0149fd1b349b97081460193cdccad1cb9a3208d278b67f
4
- data.tar.gz: 709c83b4582ffd65cab576e84d1b502ce31a70c57f0ce9af76e3ffd9978de031
3
+ metadata.gz: 19c80592b90b1ba20ac213bae2ff36e9608202161e29718a063d3ac52ed249b3
4
+ data.tar.gz: daa58fc0cfe1a9b788a49372c1d200579502331ef9e1f1424fa4a81270898a8b
5
5
  SHA512:
6
- metadata.gz: 9ca7d43729ca2e9b8d2012c8f1e9055832ba52a7c7abe8b14c37ad92b73af1a689dd92ec6415e2f4f1532b18a10310caee45c2370579e389914237acb2496cbb
7
- data.tar.gz: 687feaca288aec140529e59948290a4e99aae6261567953768340b0b36aa6a8920f9e2640fd0b7a8a02cb22f727b417302569fba4bfda736c0a2a0b6c04b41a1
6
+ metadata.gz: c3b9ee1922a5ece712f8f431eb84de7ab5793d5108fe4959ce690a0acd6edb14f21ab5135cc1b7bcf37d3fbe81af45731fe1900e1803683c131bc3dba13aa931
7
+ data.tar.gz: 5db356770b3017319ef2e4f0d1a16598025c9227b540661b2f3e6104f2bd522dbbfb351266eae0bc63d19667a2edc079de0136b50e648e6abddf973bbbe58ead
@@ -19,6 +19,10 @@ module Api
19
19
  api :GET, '/job_invocations/:id', N_('Show job invocation')
20
20
  param :id, :identifier, :required => true
21
21
  def show
22
+ @hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
23
+ @template_invocations = @job_invocation.template_invocations
24
+ .where(host: @hosts)
25
+ .includes(:input_values)
22
26
  end
23
27
 
24
28
  def_param_group :job_invocation do
@@ -146,7 +150,7 @@ module Api
146
150
  end
147
151
 
148
152
  def find_host
149
- @host = Host.authorized(:view_hosts).find(params['host_id'])
153
+ @host = @nested_obj.targeting.hosts.authorized(:view_hosts, Host).find(params['host_id'])
150
154
  rescue ActiveRecord::RecordNotFound
151
155
  not_found({ :error => { :message => (_("Host with id '%{id}' was not found") % { :id => params['host_id'] }) } })
152
156
  end
@@ -26,7 +26,10 @@ module Api
26
26
  private
27
27
 
28
28
  def resource_scope_for_template_invocations
29
- @job_invocation.template_invocations.search_for(*search_options)
29
+ @job_invocation.template_invocations
30
+ .includes(:host)
31
+ .where(host: Host.authorized(:view_hosts, Host))
32
+ .search_for(*search_options)
30
33
  end
31
34
 
32
35
  def find_job_invocation
@@ -29,7 +29,7 @@ module JobInvocationsHelper
29
29
  end
30
30
 
31
31
  def preview_hosts(template_invocation)
32
- hosts = template_invocation.targeting.hosts.take(20)
32
+ hosts = template_invocation.targeting.hosts.authorized(:view_hosts, Host).take(20)
33
33
  hosts.map do |host|
34
34
  collapsed_preview(host) +
35
35
  render(:partial => 'job_invocations/user_input',
@@ -49,7 +49,7 @@ module ForemanRemoteExecution
49
49
  keys = remote_execution_ssh_keys
50
50
  source = 'global'
51
51
  if keys.present?
52
- value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| v || [] }
52
+ value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| [v].flatten.compact }
53
53
  params['remote_execution_ssh_keys'] = {:value => value + keys, :safe_value => safe_value + keys, :source => source}
54
54
  end
55
55
  [:remote_execution_ssh_user, :remote_execution_effective_user_method,
@@ -8,11 +8,16 @@ module ForemanRemoteExecution
8
8
  register_rebuild(:queue_ssh_destroy, N_("SSH_#{self.to_s.split('::').first}"))
9
9
  end
10
10
 
11
- def drop_from_known_hosts(args)
12
- proxy_id, target = args
11
+ def drop_from_known_hosts(proxy_id)
12
+ _, _, target = host_kind_target
13
+ return true if target.nil?
14
+
13
15
  proxy = ::SmartProxy.find(proxy_id)
14
16
  begin
15
17
  proxy.drop_host_from_known_hosts(target)
18
+ rescue RestClient::ResourceNotFound => e
19
+ # ignore 404 when known_hosts entry is missing or the module was not enabled
20
+ Foreman::Logging.exception "Proxy failed to delete SSH known_hosts for #{name}, #{ip}", e, :level => :error
16
21
  rescue => e
17
22
  Rails.logger.warn e.message
18
23
  return false
@@ -23,11 +28,11 @@ module ForemanRemoteExecution
23
28
  def ssh_destroy
24
29
  logger.debug "Scheduling SSH known_hosts cleanup"
25
30
 
26
- host, _kind, target = host_kind_target
31
+ host, _kind, _target = host_kind_target
27
32
  proxies = host.remote_execution_proxies('SSH').values
28
33
  proxies.flatten.uniq.each do |proxy|
29
34
  queue.create(id: queue_id(proxy.id), name: _("Remove SSH known hosts for %s") % self,
30
- priority: 200, action: [self, :drop_from_known_hosts, [proxy.id, target]])
35
+ priority: 200, action: [self, :drop_from_known_hosts, proxy.id])
31
36
  end
32
37
  end
33
38
 
@@ -37,7 +42,7 @@ module ForemanRemoteExecution
37
42
 
38
43
  def should_drop_from_known_hosts?
39
44
  host, = host_kind_target
40
- host&.build && host&.changes&.key?('build')
45
+ host && !host.new_record? && host.build && host.changes.key?('build')
41
46
  end
42
47
 
43
48
  private
@@ -19,7 +19,7 @@ child :targeting do
19
19
  attributes :bookmark_id, :search_query, :targeting_type, :user_id, :status, :status_label,
20
20
  :randomized_ordering
21
21
 
22
- child :hosts do
22
+ child @hosts do
23
23
  extends 'api/v2/hosts/base'
24
24
  end
25
25
  end
@@ -28,7 +28,7 @@ child :task do
28
28
  attributes :id, :state
29
29
  end
30
30
 
31
- child :template_invocations do
31
+ child @template_invocations do
32
32
  attributes :template_id, :template_name
33
33
  child :input_values do
34
34
  attributes :template_input_name, :template_input_id
@@ -1,3 +1,3 @@
1
1
  module ForemanRemoteExecution
2
- VERSION = '3.2.1'.freeze
2
+ VERSION = '3.2.2'.freeze
3
3
  end
@@ -4,7 +4,7 @@ module Api
4
4
  module V2
5
5
  class JobInvocationsControllerTest < ActionController::TestCase
6
6
  setup do
7
- @invocation = FactoryBot.create(:job_invocation, :with_template, :with_task)
7
+ @invocation = FactoryBot.create(:job_invocation, :with_template, :with_task, :with_unplanned_host)
8
8
  @template = FactoryBot.create(:job_template, :with_input)
9
9
 
10
10
  # Without this the template in template_invocations and in pattern_template_invocations
@@ -20,18 +20,32 @@ module Api
20
20
  assert_response :success
21
21
  end
22
22
 
23
- test 'should get invocation detail' do
24
- get :show, params: { :id => @invocation.id }
25
- assert_response :success
26
- template = ActiveSupport::JSON.decode(@response.body)
27
- assert_not_empty template
28
- assert_equal template['job_category'], @invocation.job_category
29
- end
23
+ describe 'show' do
24
+ test 'should get invocation detail' do
25
+ get :show, params: { :id => @invocation.id }
26
+ assert_response :success
27
+ template = ActiveSupport::JSON.decode(@response.body)
28
+ assert_not_empty template
29
+ assert_equal template['job_category'], @invocation.job_category
30
+ assert_not_empty template['targeting']['hosts']
31
+ end
30
32
 
31
- test 'should get invocation detail when taxonomies are set' do
32
- taxonomy_params = %w(organization location).reduce({}) { |acc, cur| acc.merge("#{cur}_id" => FactoryBot.create(cur)) }
33
- get :show, params: taxonomy_params.merge(:id => @invocation.id)
34
- assert_response :success
33
+ test 'should get invocation detail when taxonomies are set' do
34
+ taxonomy_params = %w(organization location).reduce({}) { |acc, cur| acc.merge("#{cur}_id" => FactoryBot.create(cur)) }
35
+ get :show, params: taxonomy_params.merge(:id => @invocation.id)
36
+ assert_response :success
37
+ end
38
+
39
+ test 'should see only permitted hosts' do
40
+ @user = FactoryBot.create(:user, admin: false)
41
+ setup_user('view', 'job_invocations', nil, @user)
42
+ setup_user('view', 'hosts', 'name ~ nope.example.com', @user)
43
+
44
+ get :show, params: { :id => @invocation.id }, session: set_session_user(@user)
45
+ assert_response :success
46
+ response = ActiveSupport::JSON.decode(@response.body)
47
+ assert_empty response['targeting']['hosts']
48
+ end
35
49
  end
36
50
 
37
51
  context 'creation' do
@@ -108,7 +122,7 @@ module Api
108
122
  end
109
123
 
110
124
  describe '#output' do
111
- let(:host) { @invocation.template_invocations_hosts.first }
125
+ let(:host) { @invocation.targeting.hosts.first }
112
126
 
113
127
  test 'should provide output for delayed task' do
114
128
  ForemanTasks::Task.any_instance.expects(:scheduled?).returns(true)
@@ -137,6 +151,12 @@ module Api
137
151
  assert_equal result['message'], "Job invocation not found by id '#{invocation_id}'"
138
152
  assert_response :missing
139
153
  end
154
+
155
+ test 'should get output only for host in job invocation' do
156
+ get :output, params: { job_invocation_id: @invocation.id,
157
+ host_id: FactoryBot.create(:host).id }
158
+ assert_response :missing
159
+ end
140
160
  end
141
161
 
142
162
  describe 'raw output' do
@@ -148,7 +168,7 @@ module Api
148
168
  let(:fake_task) do
149
169
  OpenStruct.new :pending? => false, :main_action => OpenStruct.new(:live_output => fake_output)
150
170
  end
151
- let(:host) { @invocation.template_invocations_hosts.first }
171
+ let(:host) { @invocation.targeting.hosts.first }
152
172
 
153
173
  test 'should provide raw output for a host' do
154
174
  JobInvocation.any_instance.expects(:task).returns(OpenStruct.new(:scheduled? => false))
@@ -184,6 +204,12 @@ module Api
184
204
  assert_nil result['output']
185
205
  assert_response :success
186
206
  end
207
+
208
+ test 'should get raw output only for host in job invocation' do
209
+ get :raw_output, params: { job_invocation_id: @invocation.id,
210
+ host_id: FactoryBot.create(:host).id }
211
+ assert_response :missing
212
+ end
187
213
  end
188
214
 
189
215
  test 'should cancel a job' do
@@ -232,11 +258,13 @@ module Api
232
258
  end
233
259
 
234
260
  test 'should not raise an exception when reruning failed has no hosts' do
261
+ @invocation.targeting.hosts.first.destroy
235
262
  JobInvocation.any_instance.expects(:generate_description)
236
263
  JobInvocationComposer.any_instance
237
264
  .expects(:validate_job_category)
238
265
  .with(@invocation.job_category)
239
266
  .returns(@invocation.job_category)
267
+
240
268
  post :rerun, params: { :id => @invocation.id, :failed_only => true }
241
269
  assert_response :success
242
270
  result = ActiveSupport::JSON.decode(@response.body)
@@ -15,10 +15,42 @@ class SSHOrchestrationTest < ActiveSupport::TestCase
15
15
  end
16
16
 
17
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
+
18
22
  host.build = true
19
23
  host.save!
24
+
20
25
  ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
21
26
  "ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
22
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
+ SmartProxy.any_instance.expects(:drop_host_from_known_hosts).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)
23
55
  end
24
56
  end
@@ -48,6 +48,13 @@ class ForemanRemoteExecutionHostExtensionsTest < ActiveSupport::TestCase
48
48
  _(host.host_param('remote_execution_ssh_keys')).must_include sshkey
49
49
  end
50
50
 
51
+ it 'merges ssh key as a string from host parameters and proxies' do
52
+ key = 'ssh-rsa not-even-a-key something@somewhere.com'
53
+ host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_keys', :value => key)
54
+ _(host.host_param('remote_execution_ssh_keys')).must_include key
55
+ _(host.host_param('remote_execution_ssh_keys')).must_include sshkey
56
+ end
57
+
51
58
  it 'has ssh keys in the parameters even when no user specified' do
52
59
  # this is a case, when using the helper in provisioning templates
53
60
  FactoryBot.create(:smart_proxy, :ssh)
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: 3.2.1
4
+ version: 3.2.2
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: 2020-05-14 00:00:00.000000000 Z
11
+ date: 2020-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface