foreman_remote_execution 3.3.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -1
  3. data/app/assets/stylesheets/foreman_remote_execution/job_invocations.scss +6 -5
  4. data/app/controllers/api/v2/job_invocations_controller.rb +3 -2
  5. data/app/controllers/job_invocations_controller.rb +22 -8
  6. data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
  7. data/app/lib/actions/remote_execution/run_hosts_job.rb +1 -1
  8. data/app/lib/foreman_remote_execution/renderer/scope/input.rb +35 -0
  9. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +11 -4
  10. data/app/models/job_invocation.rb +6 -3
  11. data/app/models/job_invocation_composer.rb +2 -2
  12. data/app/models/remote_execution_provider.rb +2 -2
  13. data/app/models/setting/remote_execution.rb +2 -2
  14. data/app/models/ssh_execution_provider.rb +1 -1
  15. data/app/services/default_proxy_proxy_selector.rb +3 -1
  16. data/app/views/api/v2/job_invocations/main.json.rabl +2 -2
  17. data/app/views/job_invocations/_card_target_hosts.html.erb +1 -1
  18. data/app/views/job_invocations/_form.html.erb +1 -1
  19. data/app/views/job_invocations/_tab_hosts.html.erb +1 -20
  20. data/app/views/job_invocations/index.html.erb +2 -1
  21. data/app/views/job_invocations/show.html.erb +9 -0
  22. data/app/views/job_invocations/show.js.erb +5 -0
  23. data/app/views/job_invocations/show.json.erb +2 -1
  24. data/app/views/templates/ssh/package_action.erb +1 -0
  25. data/app/views/templates/ssh/puppet_agent_disable.erb +3 -0
  26. data/app/views/templates/ssh/puppet_agent_enable.erb +3 -0
  27. data/app/views/templates/ssh/puppet_install_modules_from_forge.erb +3 -0
  28. data/app/views/templates/ssh/puppet_run_once.erb +3 -0
  29. data/db/migrate/20200623073022_rename_sudo_password_to_effective_user_password.rb +34 -0
  30. data/db/seeds.d/20-permissions.rb +9 -0
  31. data/lib/foreman_remote_execution/engine.rb +4 -1
  32. data/lib/foreman_remote_execution/version.rb +1 -1
  33. data/test/functional/api/v2/job_invocations_controller_test.rb +65 -2
  34. data/test/functional/job_invocations_controller_test.rb +71 -0
  35. data/test/models/orchestration/ssh_test.rb +1 -1
  36. data/test/support/remote_execution_helper.rb +5 -0
  37. data/test/unit/actions/run_host_job_test.rb +3 -3
  38. data/test/unit/actions/run_hosts_job_test.rb +1 -1
  39. data/test/unit/job_invocation_composer_test.rb +5 -5
  40. data/test/unit/remote_execution_provider_test.rb +6 -6
  41. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  42. data/webpack/__mocks__/foremanReact/components/SearchBar.js +2 -0
  43. data/webpack/__mocks__/foremanReact/constants.js +21 -0
  44. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +2 -0
  45. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors.js +1 -0
  46. data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +21 -15
  47. data/webpack/react_app/components/TargetingHosts/TargetingHostsHelpers.js +10 -0
  48. data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +62 -0
  49. data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +6 -0
  50. data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +10 -2
  51. data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsPage.test.js +9 -0
  52. data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +26 -0
  53. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +16 -1
  54. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +68 -0
  55. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +11 -0
  56. data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +35 -19
  57. data/webpack/react_app/components/TargetingHosts/index.js +73 -13
  58. metadata +18 -3
  59. data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d093d837d0009e477549fba4700f3e0090045ba23f8b2c50fb05439fee53e403
4
- data.tar.gz: 54dffc56caa3fa1bb72bb159b152d267d2e348b64b57322ea74cdf0ad9289cc1
3
+ metadata.gz: 93860edb8974a0691383b3a199a1a2d079d10401d7780b99aa6275b75125eb58
4
+ data.tar.gz: d333f8eb85a42b36694dee932447d4364b57ed2c095ad5a055d1e7adf69a9866
5
5
  SHA512:
6
- metadata.gz: e3524503031c73f86a0f3ed0b6c8dd39499f85df47052eca941f455552665b93ff041e5d6df9870cfb95ac1219017a561a483556306905bdc005caf252a5e088
7
- data.tar.gz: 537da427406ce7c794d5e589e7e82f8c6fbda33a3a4231129905b69171421f41e98563c0496d9c7cc748f675d200729ec52f4d9067a8f7879972922358a2a868
6
+ metadata.gz: 70c300e719d6587639719a4d95aa23da2d3f3a16d51692392c789b70cd381b31320789db0f45b57c129e4b90d36bd1a8ddadd29db4f38f2d9e40a39219b1d130
7
+ data.tar.gz: 1feab0c5cfd3fee6054a004eba812b7257df80a2dce50aa200d15dd20797f24f8a614d802668ac6daf043c189b7caa8e8d5f0d4a997726764c80c91173d9437b
@@ -30,10 +30,11 @@ jobs:
30
30
  strategy:
31
31
  fail-fast: false
32
32
  matrix:
33
- foreman-core-branch: [2.1-stable, develop]
33
+ foreman-core-branch: [develop]
34
34
  ruby-version: [2.5, 2.6]
35
35
  node-version: [12]
36
36
  steps:
37
+ - run: sudo apt-get update
37
38
  - run: sudo apt-get install build-essential libcurl4-openssl-dev zlib1g-dev libpq-dev
38
39
  - uses: actions/checkout@v2
39
40
  with:
@@ -1,9 +1,6 @@
1
- div.infoblock {
2
- margin-bottom: 20px;
3
- line-height: 2;
4
-
1
+ .target-hosts-card {
5
2
  pre {
6
- margin-top: 5px;
3
+ white-space:pre-line;
7
4
  }
8
5
  }
9
6
 
@@ -29,3 +26,7 @@ div.infoblock {
29
26
  }
30
27
  }
31
28
  }
29
+
30
+ .text_warp{
31
+ word-wrap: break-word;
32
+ }
@@ -18,14 +18,14 @@ module Api
18
18
 
19
19
  api :GET, '/job_invocations/:id', N_('Show job invocation')
20
20
  param :id, :identifier, :required => true
21
- param :host_status, String, required: false, allow_blank: true, desc: N_('Show Job status for the hosts.')
21
+ param :host_status, :bool, required: false, desc: N_('Show Job status for the hosts')
22
22
  def show
23
23
  @hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
24
24
  @template_invocations = @job_invocation.template_invocations
25
25
  .where(host: @hosts)
26
26
  .includes(:input_values)
27
27
 
28
- if params[:host_status]
28
+ if params[:host_status] == 'true'
29
29
  template_invocations = @template_invocations.includes(:run_host_job_task).to_a
30
30
  @host_statuses = Hash[template_invocations.map { |ti| [ti.host_id, template_invocation_status(ti)] }]
31
31
  end
@@ -80,6 +80,7 @@ module Api
80
80
  end
81
81
  composer.trigger!
82
82
  @job_invocation = composer.job_invocation
83
+ @hosts = @job_invocation.targeting.hosts
83
84
  process_response @job_invocation
84
85
  end
85
86
 
@@ -52,16 +52,18 @@ class JobInvocationsController < ApplicationController
52
52
 
53
53
  def show
54
54
  @job_invocation = resource_base.includes(:template_invocations => :run_host_job_task).find(params[:id])
55
- @auto_refresh = @job_invocation.task.try(:pending?)
56
- @resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
57
- # There's no need to do the joining if we're not filtering
58
- unless params[:search].nil?
59
- @resource_base = @resource_base.joins(:template_invocations)
60
- .where(:template_invocations => { :job_invocation_id => @job_invocation.id})
61
- end
62
- @hosts = resource_base_search_and_page
63
55
  @job_organization = Taxonomy.find_by(id: @job_invocation.task.input[:current_organization_id])
64
56
  @job_location = Taxonomy.find_by(id: @job_invocation.task.input[:current_location_id])
57
+ @auto_refresh = @job_invocation.task.try(:pending?)
58
+
59
+ respond_to do |format|
60
+ format.json do
61
+ targeting_hosts_resources
62
+ end
63
+
64
+ format.html
65
+ format.js
66
+ end
65
67
  end
66
68
 
67
69
  def index
@@ -153,4 +155,16 @@ class JobInvocationsController < ApplicationController
153
155
  JobInvocationComposer.from_ui_params(with_triggering)
154
156
  end
155
157
  end
158
+
159
+ def targeting_hosts_resources
160
+ @auto_refresh = @job_invocation.task.try(:pending?)
161
+ @resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
162
+
163
+ unless params[:search].nil?
164
+ @resource_base = @resource_base.joins(:template_invocations)
165
+ .where(:template_invocations => { :job_invocation_id => @job_invocation.id})
166
+ end
167
+ @hosts = resource_base_search_and_page
168
+ @total_hosts = resource_base_with_search.size
169
+ end
156
170
  end
@@ -60,7 +60,7 @@ module Actions
60
60
  def secrets(host, job_invocation, provider)
61
61
  job_secrets = { :ssh_password => job_invocation.password,
62
62
  :key_passphrase => job_invocation.key_passphrase,
63
- :sudo_password => job_invocation.sudo_password }
63
+ :effective_user_password => job_invocation.effective_user_password }
64
64
 
65
65
  job_secrets.merge(provider.secrets(host)) { |_key, job_secret, provider_secret| job_secret || provider_secret }
66
66
  end
@@ -47,7 +47,7 @@ module Actions
47
47
  end
48
48
 
49
49
  def finalize
50
- job_invocation.password = job_invocation.key_passphrase = job_invocation.sudo_password = nil
50
+ job_invocation.password = job_invocation.key_passphrase = job_invocation.effective_user_password = nil
51
51
  job_invocation.save!
52
52
 
53
53
  Rails.logger.debug "cleaning cache for keys that begin with 'job_invocation_#{job_invocation.id}'"
@@ -3,14 +3,33 @@ module ForemanRemoteExecution
3
3
  module Scope
4
4
  class Input < ::Foreman::Renderer::Scope::Template
5
5
  include Foreman::Renderer::Scope::Macros::HostTemplate
6
+ extend ApipieDSL::Class
6
7
 
7
8
  attr_reader :template, :host, :invocation, :input_template_instance, :current_user
8
9
  delegate :input, to: :input_template_instance
9
10
 
11
+ apipie :class, 'Macros related to template rendering' do
12
+ name 'Template Input Render'
13
+ sections only: %w[all jobs]
14
+ end
15
+
16
+ apipie :method, 'Always raises an error with a description provided as an argument' do
17
+ desc 'This method is useful for aborting script execution if some of the conditions are not met'
18
+ required :message, String, desc: 'Description for the error'
19
+ raises error: ::InputTemplateRenderer::RenderError, desc: 'The error is always being raised'
20
+ returns nil, desc: "Doesn't return anything"
21
+ example "<%
22
+ @host.operatingsystem #=> nil
23
+ render_error(N_('Unsupported or no operating system found for this host.')) unless @host.operatingsystem #=> InputTemplateRenderer::RenderError is raised and the execution of the script is aborted
24
+ %>"
25
+ end
10
26
  def render_error(message)
11
27
  raise ::InputTemplateRenderer::RenderError.new(message)
12
28
  end
13
29
 
30
+ apipie :method, 'Check whether the template in preview mode or not' do
31
+ returns one_of: [true, false], desc: 'Returns true if the template in preview mode, false otherwise'
32
+ end
14
33
  def preview?
15
34
  !!@preview
16
35
  end
@@ -23,6 +42,16 @@ module ForemanRemoteExecution
23
42
  Rails.cache.fetch(cache_key, &block)
24
43
  end
25
44
 
45
+ # rubocop:disable Lint/InterpolationCheck
46
+ apipie :method, 'Render template by given name' do
47
+ required :template_name, String, desc: 'name of the template to render'
48
+ optional :input_values, Hash, desc: 'key:value list of input values for the template'
49
+ optional :options, Hash, desc: 'Additional options such as :with_foreign_input_set. Set to true if a foreign input set should be considered when rendering the template'
50
+ raises error: StandardError, desc: 'raises an error if there is no template or template input with such name'
51
+ returns String, desc: 'Rendered template'
52
+ example '<%= render_template("Run Command - Ansible Default", command: "yum -y group install #{input("package")}") %>'
53
+ end
54
+ # rubocop:enable Lint/InterpolationCheck
26
55
  def render_template(template_name, input_values = {}, options = {})
27
56
  options.assert_valid_keys(:with_foreign_input_set)
28
57
  with_foreign_input_set = options.fetch(:with_foreign_input_set, true)
@@ -59,6 +88,12 @@ module ForemanRemoteExecution
59
88
  input_values.merge(overrides).with_indifferent_access
60
89
  end
61
90
 
91
+ apipie :method, 'Returns the value of template input' do
92
+ required :name, String, desc: 'name of the template input'
93
+ raises error: UndefinedInput, desc: 'when there is no input with such name defined for the current template'
94
+ returns Object, desc: 'The value of template input'
95
+ example 'input("Include Facts") #=> "yes"'
96
+ end
62
97
  def input(name)
63
98
  return template_input_values[name.to_s] if template_input_values.key?(name.to_s)
64
99
 
@@ -15,9 +15,13 @@ module ForemanRemoteExecution
15
15
  proxy = ::SmartProxy.find(proxy_id)
16
16
  begin
17
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
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
21
25
  rescue => e
22
26
  Rails.logger.warn e.message
23
27
  return false
@@ -29,7 +33,10 @@ module ForemanRemoteExecution
29
33
  logger.debug "Scheduling SSH known_hosts cleanup"
30
34
 
31
35
  host, _kind, _target = host_kind_target
32
- proxies = host.remote_execution_proxies('SSH').values
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
33
40
  proxies.flatten.uniq.each do |proxy|
34
41
  queue.create(id: queue_id(proxy.id), name: _("Remove SSH known hosts for %s") % self,
35
42
  priority: 200, action: [self, :drop_from_known_hosts, proxy.id])
@@ -41,7 +41,10 @@ class JobInvocation < ApplicationRecord
41
41
  has_many :template_invocation_tasks, :through => :template_invocations,
42
42
  :class_name => 'ForemanTasks::Task',
43
43
  :source => 'run_host_job_task'
44
-
44
+ has_one :user, through: :task
45
+ scoped_search relation: :user, on: :login, rename: 'user', complete_value: true,
46
+ value_translation: ->(value) { value == 'current_user' ? User.current.login : value },
47
+ special_values: [:current_user], aliases: ['owner'], :only_explicit => true
45
48
  scoped_search :relation => :task, :on => :started_at, :rename => 'started_at', :complete_value => true
46
49
  scoped_search :relation => :task, :on => :start_at, :rename => 'start_at', :complete_value => true
47
50
  scoped_search :relation => :task, :on => :ended_at, :rename => 'ended_at', :complete_value => true
@@ -70,7 +73,7 @@ class JobInvocation < ApplicationRecord
70
73
 
71
74
  delegate :start_at, :to => :task, :allow_nil => true
72
75
 
73
- encrypts :password, :key_passphrase, :sudo_password
76
+ encrypts :password, :key_passphrase, :effective_user_password
74
77
 
75
78
  def self.search_by_status(key, operator, value)
76
79
  conditions = HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.sql_conditions_for(value)
@@ -139,7 +142,7 @@ class JobInvocation < ApplicationRecord
139
142
  invocation.pattern_template_invocations = self.pattern_template_invocations.map(&:deep_clone)
140
143
  invocation.password = self.password
141
144
  invocation.key_passphrase = self.key_passphrase
142
- invocation.sudo_password = self.sudo_password
145
+ invocation.effective_user_password = self.effective_user_password
143
146
  end
144
147
  end
145
148
 
@@ -15,7 +15,7 @@ class JobInvocationComposer
15
15
  :description_format => job_invocation_base[:description_format],
16
16
  :password => blank_to_nil(job_invocation_base[:password]),
17
17
  :key_passphrase => blank_to_nil(job_invocation_base[:key_passphrase]),
18
- :sudo_password => blank_to_nil(job_invocation_base[:sudo_password]),
18
+ :effective_user_password => blank_to_nil(job_invocation_base[:effective_user_password]),
19
19
  :concurrency_control => concurrency_control_params,
20
20
  :execution_timeout_interval => execution_timeout_interval,
21
21
  :template_invocations => template_invocations_params }.with_indifferent_access
@@ -348,7 +348,7 @@ class JobInvocationComposer
348
348
  job_invocation.execution_timeout_interval = params[:execution_timeout_interval]
349
349
  job_invocation.password = params[:password]
350
350
  job_invocation.key_passphrase = params[:key_passphrase]
351
- job_invocation.sudo_password = params[:sudo_password]
351
+ job_invocation.effective_user_password = params[:effective_user_password]
352
352
 
353
353
  if @reruns && job_invocation.targeting.static?
354
354
  job_invocation.targeting.host_ids = JobInvocation.find(@reruns).targeting.host_ids
@@ -57,8 +57,8 @@ class RemoteExecutionProvider
57
57
  [true, 'true', 'True', 'TRUE', '1'].include?(setting)
58
58
  end
59
59
 
60
- def sudo_password(host)
61
- host_setting(host, :remote_execution_sudo_password)
60
+ def effective_user_password(host)
61
+ host_setting(host, :remote_execution_effective_user_password)
62
62
  end
63
63
 
64
64
  def effective_interfaces(host)
@@ -1,6 +1,6 @@
1
1
  class Setting::RemoteExecution < Setting
2
2
 
3
- ::Setting::BLANK_ATTRS.concat %w{remote_execution_ssh_password remote_execution_ssh_key_passphrase remote_execution_sudo_password remote_execution_cockpit_url remote_execution_form_job_template}
3
+ ::Setting::BLANK_ATTRS.concat %w{remote_execution_ssh_password remote_execution_ssh_key_passphrase remote_execution_sudo_password remote_execution_effective_user_password remote_execution_cockpit_url remote_execution_form_job_template}
4
4
 
5
5
  def self.default_settings
6
6
  [
@@ -27,7 +27,7 @@ class Setting::RemoteExecution < Setting
27
27
  N_('Effective User Method'),
28
28
  nil,
29
29
  { :collection => proc { Hash[SSHExecutionProvider::EFFECTIVE_USER_METHODS.map { |method| [method, method] }] } }),
30
- self.set('remote_execution_sudo_password', N_("Sudo password"), '', N_("Sudo password"), nil, {:encrypted => true}),
30
+ self.set('remote_execution_effective_user_password', N_("Effective user password"), '', N_("Effective user password"), nil, {:encrypted => true}),
31
31
  self.set('remote_execution_sync_templates',
32
32
  N_('Whether we should sync templates from disk when running db:seed.'),
33
33
  true,
@@ -32,7 +32,7 @@ class SSHExecutionProvider < RemoteExecutionProvider
32
32
  {
33
33
  :ssh_password => ssh_password(host),
34
34
  :key_passphrase => ssh_key_passphrase(host),
35
- :sudo_password => sudo_password(host),
35
+ :effective_user_password => effective_user_password(host),
36
36
  }
37
37
  end
38
38
 
@@ -10,7 +10,9 @@ class DefaultProxyProxySelector < ::RemoteExecutionProxySelector
10
10
  def available_proxies(host, provider)
11
11
  # TODO: Once we have a internal proxy marker/feature on the proxy, we can
12
12
  # swap the implementation
13
- internal_proxy = ::Katello.default_capsule
13
+ raise _('default_capsule method missing from SmartProxy') unless ::SmartProxy.respond_to?(:default_capsule)
14
+
15
+ internal_proxy = ::SmartProxy.default_capsule
14
16
  super.reduce({}) do |acc, (key, proxies)|
15
17
  acc.merge(key => proxies.select { |proxy| proxy == internal_proxy })
16
18
  end
@@ -19,10 +19,10 @@ 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 => :hosts do
23
23
  extends 'api/v2/hosts/base'
24
24
 
25
- if params[:host_status]
25
+ if params[:host_status] == 'true'
26
26
  node :job_status do |host|
27
27
  @host_statuses[host.id]
28
28
  end
@@ -1,5 +1,5 @@
1
1
  <% template_invocations = job_invocation.pattern_template_invocations %>
2
- <div class="card-pf card-pf-accented">
2
+ <div class="card-pf card-pf-accented target-hosts-card">
3
3
  <div class="card-pf-title">
4
4
  <h2 style="height: 18px;" class="card-pf-title">
5
5
  <%= _('Target hosts') %>
@@ -95,7 +95,7 @@
95
95
  <div class="advanced hidden">
96
96
  <%= password_f f, :password, :placeholder => '*****', :label => _('Password'), :label_help => N_('Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution.') %>
97
97
  <%= password_f f, :key_passphrase, :placeholder => '*****', :label => _('Private key passphrase'), :label_help => N_('Key passhprase is only applicable for SSH provider. Other providers ignore this field. <br> Passphrase is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution.') %>
98
- <%= password_f f, :sudo_password, :placeholder => '*****', :label => _('Sudo password'), :label_help => N_('Sudo password is only applicable for SSH provider. Other providers ignore this field. <br> Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution.') %>
98
+ <%= password_f f, :effective_user_password, :placeholder => '*****', :label => _('Effective user password'), :label_help => N_('Effective user password is only applicable for SSH provider. Other providers ignore this field. <br> Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution.') %>
99
99
  </div>
100
100
 
101
101
  <div class="advanced hidden">
@@ -1,24 +1,5 @@
1
1
  <% if job_invocation.resolved? %>
2
- <%= form_with url: job_invocation_path(job_invocation), method: "get", id: "search-form" do |f| %>
3
- <div class="row">
4
- <div class="title_filter col-md-6">
5
- <div class="input-group">
6
- <%= autocomplete_f(f, :search, value: params[:search].try(:squeeze, " "), placeholder: _("Filter") + ' ...', path: hosts_path, only_input: true) %>
7
- <span class="input-group-btn">
8
- <button class="btn btn-default" type="submit">
9
- <%= icon_text('search', content_tag(:span, _('Search'), :class => 'hidden-xs', :kind => 'fa')) %>
10
- </button>
11
- </span>
12
- </div>
13
- </div>
14
- </div>
15
- <% end %>
16
- <br>
17
-
18
- <div id="targeting_hosts">
19
- <%= mount_react_component('TargetingHosts', '#targeting_hosts') %>
20
- </div>
21
- <%= will_paginate_with_info @hosts, :container => true %>
2
+ <%= react_component('TargetingHosts' ) %>
22
3
  <% else %>
23
4
  <div class="alert alert-warning">
24
5
  <%=
@@ -1,3 +1,4 @@
1
+ <% stylesheet 'foreman_remote_execution/foreman_remote_execution' %>
1
2
  <% title _('Job invocations') %>
2
3
 
3
4
  <% title_actions(job_invocations_buttons) %>
@@ -19,7 +20,7 @@
19
20
  <tbody>
20
21
  <% @job_invocations.each do |invocation| %>
21
22
  <tr>
22
- <td><%= link_to_if_authorized invocation_description(invocation), hash_for_job_invocation_path(invocation).merge(:auth_object => invocation, :permission => :view_job_invocations, :authorizer => authorizer) %></td>
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>
23
24
  <td><%= trunc_with_tooltip(invocation&.targeting&.search_query, 15) %></td>
24
25
  <td><%= link_to_invocation_task_if_authorized(invocation) %></td>
25
26
  <td><%= invocation_result(invocation, :success_count) %></td>
@@ -2,6 +2,9 @@
2
2
  <% stylesheet 'foreman_remote_execution/foreman_remote_execution' %>
3
3
  <% javascript 'charts', 'foreman_remote_execution/template_invocation' %>
4
4
  <% javascript *webpack_asset_paths('foreman_remote_execution', :extension => 'js') %>
5
+ <% content_for(:stylesheets) do %>
6
+ <%= webpacked_plugins_css_for :foreman_remote_execution %>
7
+ <% end %>
5
8
 
6
9
  <%= breadcrumbs name_field: 'description' %>
7
10
 
@@ -41,3 +44,9 @@
41
44
  <% end %>
42
45
  <%= render_tab_content_for(:main_tabs, subject: @job_invocation) %>
43
46
  </div>
47
+
48
+ <script id="job_invocation_refresh" data-refresh-url="<%= job_invocation_path(@job_invocation) %>">
49
+ <% if @auto_refresh %>
50
+ delayed_refresh($('script#job_invocation_refresh').data('refresh-url'), {});
51
+ <% end %>
52
+ </script>
@@ -0,0 +1,5 @@
1
+ $('div#title_action div.btn-group').html('<%= button_group(job_invocation_task_buttons(@job_invocation.task)).html_safe %>');
2
+
3
+ <% if @auto_refresh %>
4
+ delayed_refresh($('script#job_invocation_refresh').data('refresh-url'), job_invocation_refresh_data());
5
+ <% end %>
@@ -1,4 +1,5 @@
1
1
  {
2
2
  "autoRefresh": "<%= @auto_refresh %>",
3
- "hosts": <%= targeting_hosts(@job_invocation, @hosts).to_json.html_safe %>
3
+ "hosts": <%= targeting_hosts(@job_invocation, @hosts).to_json.html_safe %>,
4
+ "total_hosts": <%= @total_hosts %>
4
5
  }
@@ -97,6 +97,7 @@ handle_zypp_res_codes () {
97
97
  end
98
98
  end
99
99
  -%>
100
+ [ -x "$(command -v subscription-manager)" ] && subscription-manager refresh
100
101
  apt-get -y update
101
102
  apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y <%= action %> <%= input("package") %>
102
103
  <% elsif package_manager == 'zypper' -%>
@@ -13,4 +13,7 @@ template_inputs:
13
13
  provider_type: SSH
14
14
  kind: job_template
15
15
  -%>
16
+ <% if @host.operatingsystem.family == 'Debian' -%>
17
+ export PATH=/opt/puppetlabs/bin:$PATH
18
+ <% end -%>
16
19
  puppet agent --disable "<%= input("comment").present? ? input("comment") : "Disabled using Foreman Remote Execution" %> - <%= current_user %> - $(date "+%d/%m/%Y %H:%M")"