foreman_remote_execution 3.1.0 → 3.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36a15d0142caa911a59ff7d9797ceab5dabb0e601f605c0fee3d547d1be168f5
4
- data.tar.gz: d41aba8d661cae6ef74cfee2bd9e007a37f218c3056e9d9b8ae3a1de5f243bc6
3
+ metadata.gz: 9821a3370ca6a9a1fa582ab4412d5adea5bbfc125b4102c3bc2a2c92724aaf48
4
+ data.tar.gz: 6464d913e62d09c6e7318d887f4680a5f7a996a7f537e015a07abd366bda01c8
5
5
  SHA512:
6
- metadata.gz: 20d61e7658cda93e3f24340ae6caa65c1c7868f37e699d7e6a9da524f2acaef9cccdf86cd47a7d2a1386037ad5aac0900935f3c3b2b4706926f16e60245f1b64
7
- data.tar.gz: 66e0c4b3af2d1feab711fe90b2af6a5ce08d4159501a1725a98243647a022431d871081bf2d1e82d46f8490c41589a1df6f15f2ee6f13391fb10df240bd41fe4
6
+ metadata.gz: 66f0fe8d87d3b70fd5f23d2892abbe6f7b525e27635bc480eaf6517ae33a3510b81a1f2732373cac7b66f54333e5731f0a457a5d63bda16f233d2615a07efbb0
7
+ data.tar.gz: 6390c063f681c358200e91b6702bcc235ff953428052ab8b39f13821e26d14b30409ad87df431af468eaf57e6a39437438422016fd817da41ccb1dfaa607b090
@@ -37,6 +37,8 @@ module JobInvocationsChartHelper
37
37
  _('running %{percent}%%') % {:percent => percent}
38
38
  when HostStatus::ExecutionStatus::OK
39
39
  _('succeeded')
40
+ when HostStatus::ExecutionStatus::CANCELLED
41
+ _('cancelled')
40
42
  when HostStatus::ExecutionStatus::ERROR
41
43
  _('failed')
42
44
  else
@@ -13,9 +13,13 @@ module RemoteExecutionHelper
13
13
  end
14
14
  end
15
15
 
16
- def template_invocation_status(task)
16
+ def template_invocation_status(task, parent_task)
17
17
  if task.nil?
18
- icon_text('question', 'N/A', :kind => 'fa')
18
+ if parent_task.result == 'cancelled'
19
+ icon_text('warning-triangle-o', _('cancelled'), :kind => 'pficon')
20
+ else
21
+ icon_text('question', 'N/A', :kind => 'fa')
22
+ end
19
23
  elsif task.state == 'running'
20
24
  icon_text('running', _('running'), :kind => 'pficon')
21
25
  elsif task.state == 'planned'
@@ -10,5 +10,11 @@ module ::ProxyAPI
10
10
  rescue => e
11
11
  raise ProxyException.new(url, e, N_('Unable to fetch public key'))
12
12
  end
13
+
14
+ def drop_from_known_hosts(hostname)
15
+ delete('known_hosts/' + hostname)
16
+ rescue => e
17
+ raise ProxyException.new(url, e, N_('Unable to remove host from known hosts'))
18
+ end
13
19
  end
14
20
  end
@@ -0,0 +1,58 @@
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(args)
12
+ proxy_id, target = args
13
+ proxy = ::SmartProxy.find(proxy_id)
14
+ begin
15
+ proxy.drop_host_from_known_hosts(target)
16
+ rescue => e
17
+ Rails.logger.warn e.message
18
+ return false
19
+ end
20
+ true
21
+ end
22
+
23
+ def ssh_destroy
24
+ logger.debug "Scheduling SSH known_hosts cleanup"
25
+
26
+ host, _kind, target = host_kind_target
27
+ proxies = host.remote_execution_proxies('SSH').values
28
+ proxies.flatten.uniq.each do |proxy|
29
+ 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]])
31
+ end
32
+ end
33
+
34
+ def queue_ssh_destroy
35
+ should_drop_from_known_hosts? && ssh_destroy
36
+ end
37
+
38
+ def should_drop_from_known_hosts?
39
+ host, = host_kind_target
40
+ host&.build && host&.changes&.key?('build')
41
+ end
42
+
43
+ private
44
+
45
+ def host_kind_target
46
+ if self.is_a?(::Host::Base)
47
+ [self, 'host', name]
48
+ else
49
+ [self.host, 'interface', ip]
50
+ end
51
+ end
52
+
53
+ def queue_id(proxy_id)
54
+ _, kind, id = host_kind_target
55
+ "ssh_remove_known_hosts_#{kind}_#{id}_#{proxy_id}"
56
+ end
57
+ end
58
+ end
@@ -12,6 +12,10 @@ module ForemanRemoteExecution
12
12
  key
13
13
  end
14
14
 
15
+ def drop_host_from_known_hosts(host)
16
+ ::ProxyAPI::RemoteExecutionSSH.new(:url => url).drop_from_known_hosts(host)
17
+ end
18
+
15
19
  def refresh
16
20
  errors = super
17
21
  update_pubkey
@@ -7,8 +7,10 @@ class HostStatus::ExecutionStatus < HostStatus::Status
7
7
  QUEUED = 2
8
8
  # execution is in progress, dynflow task was created
9
9
  RUNNING = 3
10
+ # execution has been cancelled
11
+ CANCELLED = 4
10
12
  # mapping to string representation
11
- STATUS_NAMES = { OK => 'succeeded', ERROR => 'failed', QUEUED => 'queued', RUNNING => 'running' }.freeze
13
+ STATUS_NAMES = { OK => 'succeeded', ERROR => 'failed', QUEUED => 'queued', RUNNING => 'running', CANCELLED => 'cancelled' }.freeze
12
14
 
13
15
  def relevant?(*args)
14
16
  execution_tasks.present?
@@ -38,6 +40,8 @@ class HostStatus::ExecutionStatus < HostStatus::Status
38
40
  case to_status(options)
39
41
  when OK
40
42
  execution_tasks.present? ? N_('Last execution succeeded') : N_('No execution finished yet')
43
+ when CANCELLED
44
+ N_('Last execution cancelled')
41
45
  when ERROR
42
46
  N_('Last execution failed')
43
47
  else
@@ -54,6 +58,8 @@ class HostStatus::ExecutionStatus < HostStatus::Status
54
58
  case status
55
59
  when OK
56
60
  [ "state = 'stopped' AND result = 'success'" ]
61
+ when CANCELLED
62
+ [ "state = 'stopped' AND result = 'cancelled'" ]
57
63
  when ERROR
58
64
  [ "state = 'stopped' AND (result = 'error' OR result = 'warning')" ]
59
65
  when QUEUED
@@ -74,6 +80,8 @@ class HostStatus::ExecutionStatus < HostStatus::Status
74
80
  QUEUED
75
81
  elsif task.state == 'stopped' && task.result == 'success'
76
82
  OK
83
+ elsif task.state == 'stopped' && task.result == 'cancelled'
84
+ CANCELLED
77
85
  elsif task.pending?
78
86
  RUNNING
79
87
  else
@@ -5,6 +5,7 @@
5
5
  </h2>
6
6
  <div class="card-pf-body">
7
7
  <div id='status_chart'>
8
+ <%= react_component('JobInvocationContainer', data: { url: "/job_invocations/chart?id=#{job_invocation.id}" }) %>
8
9
  </div>
9
10
  </div>
10
11
  </div>
@@ -1 +1 @@
1
- <td class="host_status" id="<%= dom_id(host) %>-status" data-refresh_required="<%= task.nil? || task.pending? ? 'true' : '' %>" data-id="<%= host.id %>"><%= template_invocation_status(task) %></td>
1
+ <td class="host_status" id="<%= dom_id(host) %>-status" data-refresh_required="<%= task.nil? || task.pending? ? 'true' : '' %>" data-id="<%= host.id %>"><%= template_invocation_status(task, job_invocation.task) %></td>
@@ -1,7 +1,7 @@
1
1
  <% template_invocations = job_invocation.pattern_template_invocations %>
2
2
  <div class='row'>
3
3
  <div class="col-xs-6 col-sm-6 col-md-6">
4
- <%= render :partial => 'card_results' %>
4
+ <%= render :partial => 'card_results', :locals => { :job_invocation => job_invocation } %>
5
5
  <%= render :partial => 'card_schedule', :locals => { :job_invocation => job_invocation } %>
6
6
  </div>
7
7
  <div class='col-xs-12 col-sm-6 col-md-6'>
@@ -1,7 +1,7 @@
1
1
  <% title @job_invocation.description %>
2
2
  <% stylesheet 'foreman_remote_execution/foreman_remote_execution' %>
3
3
  <% javascript 'charts', 'foreman_remote_execution/template_invocation' %>
4
- <%= javascript_include_tag *webpack_asset_paths('foreman_remote_execution', :extension => 'js'), "data-turbolinks-track" => true, 'defer' => 'defer' %>
4
+ <% javascript *webpack_asset_paths('foreman_remote_execution', :extension => 'js') %>
5
5
 
6
6
  <%= breadcrumbs name_field: 'description' %>
7
7
 
data/config/routes.rb CHANGED
@@ -16,7 +16,8 @@ Rails.application.routes.draw do
16
16
  end
17
17
  end
18
18
 
19
- resources :job_invocations, :only => [:new, :create, :show, :index] do
19
+ match 'job_invocations/new', to: 'job_invocations#new', via: [:get, :post], as: 'new_job_invocation'
20
+ resources :job_invocations, :only => [:create, :show, :index] do
20
21
  collection do
21
22
  post 'refresh'
22
23
  get 'chart'
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.extra_rdoc_files = Dir['README*', 'LICENSE']
26
26
 
27
27
  s.add_dependency 'deface'
28
- s.add_dependency 'dynflow', '>= 1.0.1', '< 2.0.0'
28
+ s.add_dependency 'dynflow', '>= 1.0.2', '< 2.0.0'
29
29
  s.add_dependency 'foreman_remote_execution_core'
30
30
  s.add_dependency 'foreman-tasks', '>= 0.15.1'
31
31
 
@@ -166,10 +166,12 @@ module ForemanRemoteExecution
166
166
 
167
167
  Host::Managed.prepend ForemanRemoteExecution::HostExtensions
168
168
  Host::Managed.include ForemanTasks::Concerns::HostActionSubject
169
+ Host::Managed.include ForemanRemoteExecution::Orchestration::SSH
169
170
 
170
171
  (Nic::Base.descendants + [Nic::Base]).each do |klass|
171
172
  klass.send(:include, ForemanRemoteExecution::NicExtensions)
172
173
  end
174
+ Nic::Managed.include ForemanRemoteExecution::Orchestration::SSH
173
175
 
174
176
  Bookmark.include ForemanRemoteExecution::BookmarkExtensions
175
177
  HostsHelper.prepend ForemanRemoteExecution::HostsHelperExtensions
@@ -1,3 +1,3 @@
1
1
  module ForemanRemoteExecution
2
- VERSION = '3.1.0'.freeze
2
+ VERSION = '3.2.0'.freeze
3
3
  end
@@ -46,4 +46,16 @@ class JobInvocationsControllerTest < ActionController::TestCase
46
46
  assert_equal(template_invocation_params,
47
47
  assigns(:composer).params['template_invocations'])
48
48
  end
49
+
50
+ test 'new via GET and POST' do
51
+ template = FactoryBot.create(:job_template, :with_input)
52
+ feature = FactoryBot.create(:remote_execution_feature, job_template: template)
53
+ params = { feature: feature.label, inputs: { template.template_inputs.first.name => 'foobar' } }
54
+
55
+ get :new, params: params, session: set_session_user
56
+ assert_response :success
57
+
58
+ post :new, params: params, session: set_session_user
59
+ assert_response :success
60
+ end
49
61
  end
@@ -0,0 +1,24 @@
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.build = true
19
+ host.save!
20
+ ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
21
+ "ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
22
+ _(host.queue.task_ids).must_equal ids
23
+ end
24
+ end
@@ -149,7 +149,10 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
149
149
  FactoryBot.create(:host) do |host|
150
150
  host.interfaces = [FactoryBot.build(:nic_managed, flags.merge(:ip => nil, :name => 'somehost.somedomain.org', :primary => true)),
151
151
  FactoryBot.build(:nic_managed, flags.merge(:ip => '127.0.0.1'))]
152
- end
152
+ end.reload
153
+ # Reassigning the interfaces triggers the on-deletion ssh key removal for the interface which is being replaced
154
+ # This has an undesired side effect of caching the original interface as execution one which made the tests
155
+ # give wrong results. Reloading the host wipes the cache
153
156
  end
154
157
 
155
158
  let(:flags) do
data/webpack/index.js CHANGED
@@ -12,18 +12,3 @@ componentRegistry.register({
12
12
  });
13
13
 
14
14
  registerReducer('foremanRemoteExecutionReducers', rootReducer);
15
-
16
- if (window.location.href.match(/job_invocations/)) {
17
- const jobInvocationId = parseInt(
18
- new URI(window.location.href).filename(),
19
- 10,
20
- );
21
-
22
- const mountJobInvocationContainer = () => {
23
- mount('JobInvocationContainer', '#status_chart', {
24
- url: `/job_invocations/chart?id=${jobInvocationId}`,
25
- });
26
- };
27
-
28
- document.addEventListener('page:change', mountJobInvocationContainer);
29
- }
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.1.0
4
+ version: 3.2.0
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-04-07 00:00:00.000000000 Z
11
+ date: 2020-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.1
33
+ version: 1.0.2
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
36
  version: 2.0.0
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.0.1
43
+ version: 1.0.2
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: 2.0.0
@@ -178,6 +178,7 @@ files:
178
178
  - app/models/concerns/foreman_remote_execution/foreman_tasks_triggering_extensions.rb
179
179
  - app/models/concerns/foreman_remote_execution/host_extensions.rb
180
180
  - app/models/concerns/foreman_remote_execution/nic_extensions.rb
181
+ - app/models/concerns/foreman_remote_execution/orchestration/ssh.rb
181
182
  - app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb
182
183
  - app/models/concerns/foreman_remote_execution/subnet_extensions.rb
183
184
  - app/models/concerns/foreman_remote_execution/taxonomy_extensions.rb
@@ -377,6 +378,7 @@ files:
377
378
  - test/functional/job_invocations_controller_test.rb
378
379
  - test/functional/job_templates_controller_test.rb
379
380
  - test/helpers/remote_execution_helper_test.rb
381
+ - test/models/orchestration/ssh_test.rb
380
382
  - test/test_plugin_helper.rb
381
383
  - test/unit/actions/run_host_job_test.rb
382
384
  - test/unit/actions/run_hosts_job_test.rb
@@ -442,6 +444,7 @@ test_files:
442
444
  - test/functional/job_invocations_controller_test.rb
443
445
  - test/functional/job_templates_controller_test.rb
444
446
  - test/helpers/remote_execution_helper_test.rb
447
+ - test/models/orchestration/ssh_test.rb
445
448
  - test/test_plugin_helper.rb
446
449
  - test/unit/actions/run_host_job_test.rb
447
450
  - test/unit/actions/run_hosts_job_test.rb