foreman_remote_execution 4.6.0 → 4.7.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_ci.yml +7 -0
  3. data/app/controllers/job_invocations_controller.rb +1 -1
  4. data/app/controllers/ui_job_wizard_controller.rb +7 -0
  5. data/app/graphql/types/job_invocation.rb +16 -0
  6. data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +5 -1
  7. data/app/helpers/remote_execution_helper.rb +9 -3
  8. data/app/lib/actions/remote_execution/run_host_job.rb +5 -1
  9. data/app/lib/actions/remote_execution/run_hosts_job.rb +1 -1
  10. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +2 -0
  11. data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
  12. data/app/models/host_proxy_invocation.rb +4 -0
  13. data/app/models/host_status/execution_status.rb +3 -3
  14. data/app/models/job_invocation.rb +9 -6
  15. data/app/models/job_invocation_composer.rb +4 -4
  16. data/app/models/job_template.rb +1 -1
  17. data/app/models/remote_execution_feature.rb +5 -1
  18. data/app/models/setting/remote_execution.rb +2 -2
  19. data/app/models/targeting.rb +5 -1
  20. data/app/views/job_invocations/index.html.erb +1 -1
  21. data/app/views/templates/ssh/module_action.erb +1 -0
  22. data/app/views/templates/ssh/power_action.erb +2 -0
  23. data/app/views/templates/ssh/puppet_run_once.erb +1 -0
  24. data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
  25. data/foreman_remote_execution.gemspec +2 -3
  26. data/lib/foreman_remote_execution/engine.rb +3 -2
  27. data/lib/foreman_remote_execution/version.rb +1 -1
  28. data/test/graphql/queries/job_invocation_query_test.rb +31 -0
  29. data/test/graphql/queries/job_invocations_query_test.rb +35 -0
  30. data/test/unit/concerns/host_extensions_test.rb +4 -4
  31. data/test/unit/input_template_renderer_test.rb +1 -89
  32. data/test/unit/job_invocation_composer_test.rb +15 -13
  33. data/test/unit/job_invocation_test.rb +1 -1
  34. data/webpack/JobWizard/JobWizard.js +28 -8
  35. data/webpack/JobWizard/JobWizard.scss +39 -0
  36. data/webpack/JobWizard/JobWizardConstants.js +10 -0
  37. data/webpack/JobWizard/JobWizardSelectors.js +9 -0
  38. data/webpack/JobWizard/__tests__/fixtures.js +104 -2
  39. data/webpack/JobWizard/__tests__/integration.test.js +13 -85
  40. data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +21 -4
  41. data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +67 -0
  42. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +73 -59
  43. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +135 -16
  44. data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +23 -0
  45. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +122 -51
  46. data/webpack/JobWizard/steps/Schedule/QueryType.js +48 -0
  47. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +61 -0
  48. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +25 -0
  49. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +51 -0
  50. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +22 -0
  51. data/webpack/JobWizard/steps/Schedule/index.js +41 -0
  52. data/webpack/JobWizard/steps/form/FormHelpers.js +1 -0
  53. data/webpack/JobWizard/steps/form/Formatter.js +149 -0
  54. data/webpack/JobWizard/steps/form/NumberInput.js +33 -0
  55. data/webpack/JobWizard/steps/form/SelectField.js +14 -2
  56. data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +76 -0
  57. data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
  58. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +43 -0
  59. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +72 -66
  60. data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +98 -0
  61. data/webpack/react_app/components/RecentJobsCard/constants.js +11 -0
  62. data/webpack/react_app/components/RecentJobsCard/styles.scss +11 -0
  63. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -0
  64. data/webpack/react_app/extend/fillRecentJobsCard.js +1 -1
  65. metadata +25 -16
  66. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
  67. data/test/models/orchestration/ssh_test.rb +0 -56
  68. data/webpack/JobWizard/__tests__/JobWizard.test.js +0 -13
  69. data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +0 -32
  70. data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +0 -249
  71. data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +0 -113
  72. data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +0 -38
  73. data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +0 -23
  74. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +0 -37
  75. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +0 -23
  76. data/webpack/react_app/components/RecentJobsCard/styles.css +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14dc89216ec220750d38149b86e0ecded26e13d99678505302a5a157b0c7c9e2
4
- data.tar.gz: b2091af78be3ed0fec0d5acea056a49e601e6d1ef96954c49976fd1c0da39ecb
3
+ metadata.gz: 742978171c8d62de9fdf9e14b2be742235dc1cce90c0c522871d65a90ee1f612
4
+ data.tar.gz: caae67492773457e26461ae6e39addec2cc1b105bf387a9cf0dbfc667ad25102
5
5
  SHA512:
6
- metadata.gz: 10d901fec16519db44d05d9b9ecb2b15923e1a2e439f1e0032778b9272ed4c48a446436b4ef7375bb5113f8067d5596035b5a7fa593a522fc37e56a472d51c31
7
- data.tar.gz: cb7686bf72b55bf65bbd35cee82910925f12b9dd29ec573dc96bb340fb1cc629833a80239e96317dcef2163d17d00ba93db92f5f50a10c5a4f4363d77647f729
6
+ metadata.gz: e40d5600dbe09f3ea875179a3ac44a4046ffd8615efe5c88f364828e7bd21b24d2d2a7f5f8ea09954f2f00056bc6d867efc22f7b82b0189de766f225101ae896
7
+ data.tar.gz: 6875df7248f14be5a915f7b3001cd6d4a50476f84824b0118747d4ba7b2993b977cf85cfe5f9cdde8706b2d2cb4fea20c1770988405adebf09683cc966ba9e70
@@ -71,3 +71,10 @@ jobs:
71
71
  run: |
72
72
  bundle exec rake test:foreman_remote_execution
73
73
  bundle exec rake test TEST="test/unit/foreman/access_permissions_test.rb"
74
+ - name: 'Upload logs'
75
+ uses: actions/upload-artifact@v2
76
+ if: failure()
77
+ with:
78
+ name: logs
79
+ path: log/*.log
80
+ retention-days: 5
@@ -67,7 +67,7 @@ class JobInvocationsController < ApplicationController
67
67
  end
68
68
 
69
69
  def index
70
- @job_invocations = resource_base_search_and_page.with_task.order('job_invocations.id DESC')
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
@@ -10,9 +10,12 @@ class UiJobWizardController < ::Api::V2::BaseController
10
10
 
11
11
  def template
12
12
  job_template = JobTemplate.authorized.find(params[:id])
13
+ advanced_template_inputs, template_inputs = map_template_inputs(job_template.template_inputs_with_foreign).partition { |x| x["advanced"] }
13
14
  render :json => {
14
15
  :job_template => job_template,
15
16
  :effective_user => job_template.effective_user,
17
+ :template_inputs => template_inputs,
18
+ :advanced_template_inputs => advanced_template_inputs,
16
19
  }
17
20
  end
18
21
 
@@ -20,6 +23,10 @@ class UiJobWizardController < ::Api::V2::BaseController
20
23
  nested_resource || 'job_template'
21
24
  end
22
25
 
26
+ def map_template_inputs(template_inputs_with_foreign)
27
+ template_inputs_with_foreign.map { |input| input.attributes.merge({:resource_type => input.resource_type&.tableize }) }
28
+ end
29
+
23
30
  def resource_class
24
31
  JobTemplate
25
32
  end
@@ -0,0 +1,16 @@
1
+ module Types
2
+ class JobInvocation < BaseObject
3
+ description 'A Job Invocation'
4
+
5
+ global_id_field :id
6
+ field :job_category, String
7
+ field :description, String
8
+ field :time_span, Integer
9
+ field :start_at, GraphQL::Types::ISO8601DateTime
10
+ field :status_label, String
11
+
12
+ belongs_to :triggering, Types::Triggering
13
+ belongs_to :task, Types::Task
14
+ field :recurring_logic, Types::RecurringLogic
15
+ end
16
+ end
@@ -7,7 +7,9 @@ module ForemanRemoteExecution
7
7
  end
8
8
 
9
9
  def multiple_actions
10
- super + [ [_('Schedule Remote Job'), new_job_invocation_path, false] ]
10
+ res = super
11
+ res += [ [_('Schedule Remote Job'), new_job_invocation_path, false] ] if authorized_for(controller: :job_invocations, action: :new)
12
+ res
11
13
  end
12
14
 
13
15
  def schedule_job_multi_button(*args)
@@ -21,12 +23,14 @@ module ForemanRemoteExecution
21
23
  end
22
24
 
23
25
  def rex_host_features(*args)
26
+ return unless authorized_for(controller: :job_invocations, action: :create)
24
27
  RemoteExecutionFeature.with_host_action_button.order(:label).map do |feature|
25
28
  link_to(_('%s') % feature.name, job_invocations_path(:host_ids => [args.first.id], :feature => feature.label), :method => :post)
26
29
  end
27
30
  end
28
31
 
29
32
  def schedule_job_button(*args)
33
+ return unless authorized_for(controller: :job_invocations, action: :new)
30
34
  link_to(_('Schedule Remote Job'), new_job_invocation_path(:host_ids => [args.first.id]), :id => :run_button, :class => 'btn btn-default')
31
35
  end
32
36
 
@@ -7,6 +7,10 @@ module RemoteExecutionHelper
7
7
  @job_hosts_authorizer ||= Authorizer.new(User.current, :collection => @hosts)
8
8
  end
9
9
 
10
+ def host_tasks_authorizer
11
+ @host_tasks_authorizer ||= Authorizer.new(User.current, :collection => @job_invocation.sub_tasks)
12
+ end
13
+
10
14
  def host_counter(label, count)
11
15
  content_tag(:div, :class => 'host_counter') do
12
16
  content_tag(:div, label, :class => 'header') + content_tag(:div, count.to_s, :class => 'count')
@@ -36,7 +40,7 @@ module RemoteExecutionHelper
36
40
  'data-method': 'get', id: "#{host.name}-actions-rerun" } }
37
41
  end
38
42
 
39
- if host_task.present? && authorized_for(hash_for_foreman_tasks_task_path(host_task).merge(auth_object: host_task, permission: :view_foreman_tasks))
43
+ if host_task.present? && authorized_for(hash_for_foreman_tasks_task_path(host_task).merge(auth_object: host_task, permission: :view_foreman_tasks, authorizer: host_tasks_authorizer))
40
44
  links << { title: _('Host task'),
41
45
  action: { href: foreman_tasks_task_path(host_task),
42
46
  'data-method': 'get', id: "#{host.name}-actions-task" } }
@@ -109,12 +113,14 @@ module RemoteExecutionHelper
109
113
  :class => 'btn btn-danger',
110
114
  :title => _('Try to cancel the job on a host'),
111
115
  :disabled => !task.cancellable?,
112
- :method => :post)
116
+ :method => :post,
117
+ :remote => true)
113
118
  buttons << link_to(_('Abort Job'), abort_foreman_tasks_task_path(task),
114
119
  :class => 'btn btn-danger',
115
120
  :title => _('Try to abort the job on a host without waiting for its result'),
116
121
  :disabled => !task.cancellable?,
117
- :method => :post)
122
+ :method => :post,
123
+ :remote => true)
118
124
  end
119
125
  buttons
120
126
  end
@@ -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
 
@@ -72,7 +72,7 @@ module Actions
72
72
 
73
73
  def total_count
74
74
  # For compatibility with already existing tasks
75
- return output[:total_count] unless output.has_key?(:host_count) || task.pending?
75
+ return output[:total_count] || hosts.count unless output.has_key?(:host_count) || task.pending?
76
76
 
77
77
  output[:host_count] || hosts.count
78
78
  end
@@ -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,
@@ -1,5 +1,11 @@
1
1
  module ForemanRemoteExecution
2
2
  module SmartProxyExtensions
3
+ def self.prepended(base)
4
+ base.instance_eval do
5
+ has_many :host_proxy_invocations, :dependent => :destroy
6
+ end
7
+ end
8
+
3
9
  def pubkey
4
10
  self[:pubkey] || update_pubkey
5
11
  end
@@ -0,0 +1,4 @@
1
+ class HostProxyInvocation < ApplicationRecord
2
+ belongs_to :host, :class_name => 'Host::Managed', :inverse_of => :host_proxy_invocations
3
+ belongs_to :smart_proxy
4
+ end
@@ -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), :include => :task }
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&.total_count || targeting.hosts.count
198
- else
199
- _('N/A')
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)
@@ -209,7 +209,7 @@ class JobInvocationComposer
209
209
  def format_datetime(datetime)
210
210
  return datetime if datetime.blank?
211
211
 
212
- Time.parse(datetime).strftime('%Y-%m-%d %H:%M')
212
+ Time.parse(datetime).utc.strftime('%Y-%m-%d %H:%M')
213
213
  end
214
214
  end
215
215
 
@@ -296,7 +296,7 @@ class JobInvocationComposer
296
296
  attr_reader :feature_label, :feature, :provided_inputs
297
297
 
298
298
  def initialize(feature_label, hosts, provided_inputs = {})
299
- @feature = RemoteExecutionFeature.feature(feature_label)
299
+ @feature = RemoteExecutionFeature.feature!(feature_label)
300
300
  @provided_inputs = provided_inputs
301
301
  translator = HostIdsTranslator.new(hosts)
302
302
  @host_bookmark = translator.bookmark
@@ -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.host_ids = JobInvocation.find(@reruns).targeting.host_ids
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
 
@@ -513,7 +513,7 @@ class JobInvocationComposer
513
513
  end
514
514
 
515
515
  def available_bookmarks
516
- Bookmark.authorized(:view_bookmarks).my_bookmarks.where(:controller => ['hosts', 'dashboard'])
516
+ Bookmark.my_bookmarks.where(:controller => ['hosts', 'dashboard'])
517
517
  end
518
518
 
519
519
  def targeted_hosts
@@ -83,7 +83,7 @@ class JobTemplate < ::Template
83
83
  end
84
84
 
85
85
  def acceptable_template_input_types
86
- [ :user, :fact, :variable, :puppet_parameter ]
86
+ [ :user, :fact, :variable ]
87
87
  end
88
88
 
89
89
  def default_render_scope_class
@@ -20,7 +20,11 @@ class RemoteExecutionFeature < ApplicationRecord
20
20
  end
21
21
 
22
22
  def self.feature(label)
23
- self.find_by(label: label) || raise(::Foreman::Exception.new(N_('Unknown remote execution feature %s'), label))
23
+ self.find_by(label: label)
24
+ end
25
+
26
+ def self.feature!(label)
27
+ feature(label) || raise(::Foreman::Exception.new(N_('Unknown remote execution feature %s'), label))
24
28
  end
25
29
 
26
30
  def self.register(label, name, options = {})
@@ -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
- _('Form Job Template'),
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
- _('Job Invocation Report Template'),
79
+ N_('Job Invocation Report Template'),
80
80
  nil,
81
81
  { :collection => proc { self.job_invocation_report_templates_select } }),
82
82
  ]
@@ -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&.targeting&.search_query, 15) %></td>
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>
@@ -29,6 +29,7 @@ template_inputs:
29
29
  input_type: user
30
30
  required: false
31
31
  advanced: true
32
+ feature: katello_module_stream_action
32
33
  %>
33
34
 
34
35
  <%
@@ -13,6 +13,8 @@ template_inputs:
13
13
  required: true
14
14
  %>
15
15
 
16
+ PATH="$PATH:/usr/sbin:/sbin"
17
+
16
18
  echo <%= input('action') %> host && sleep 3
17
19
  <%= case input('action')
18
20
  when 'restart'
@@ -10,6 +10,7 @@ template_inputs:
10
10
  description: Additional options to pass to puppet
11
11
  input_type: user
12
12
  required: false
13
+ feature: puppet_run_host
13
14
  %>
14
15
  <% if @host.operatingsystem.family == 'Debian' -%>
15
16
  export PATH=/opt/puppetlabs/bin:$PATH
@@ -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
@@ -16,8 +16,7 @@ Gem::Specification.new do |s|
16
16
  'management functionality with remote management functionality.'
17
17
 
18
18
  s.files = `git ls-files`.split("\n").reject do |file|
19
- file.start_with?('scripts', 'lib/foreman_remote_execution_core') ||
20
- file == 'foreman_remote_execution_core.gemspec'
19
+ file.start_with?('scripts')
21
20
  end
22
21
 
23
22
  s.test_files = `git ls-files test`.split("\n")
@@ -25,7 +24,7 @@ Gem::Specification.new do |s|
25
24
 
26
25
  s.add_dependency 'deface'
27
26
  s.add_dependency 'dynflow', '>= 1.0.2', '< 2.0.0'
28
- s.add_dependency 'foreman-tasks', '>= 4.1.0'
27
+ s.add_dependency 'foreman-tasks', '>= 5.0.0'
29
28
 
30
29
  s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
31
30
  s.add_development_dependency 'rdoc'
@@ -152,6 +152,9 @@ module ForemanRemoteExecution
152
152
  ctx.permit :execution
153
153
  end
154
154
 
155
+ register_graphql_query_field :job_invocations, '::Types::JobInvocation', :collection_field
156
+ register_graphql_query_field :job_invocation, '::Types::JobInvocation', :record_field
157
+
155
158
  extend_template_helpers ForemanRemoteExecution::RendererMethods
156
159
 
157
160
  extend_rabl_template 'api/v2/smart_proxies/main', 'api/v2/smart_proxies/pubkey'
@@ -201,12 +204,10 @@ module ForemanRemoteExecution
201
204
 
202
205
  Host::Managed.prepend ForemanRemoteExecution::HostExtensions
203
206
  Host::Managed.include ForemanTasks::Concerns::HostActionSubject
204
- Host::Managed.include ForemanRemoteExecution::Orchestration::SSH
205
207
 
206
208
  (Nic::Base.descendants + [Nic::Base]).each do |klass|
207
209
  klass.send(:include, ForemanRemoteExecution::NicExtensions)
208
210
  end
209
- Nic::Managed.include ForemanRemoteExecution::Orchestration::SSH
210
211
 
211
212
  Bookmark.include ForemanRemoteExecution::BookmarkExtensions
212
213
  HostsHelper.prepend ForemanRemoteExecution::HostsHelperExtensions
@@ -1,3 +1,3 @@
1
1
  module ForemanRemoteExecution
2
- VERSION = '4.6.0'.freeze
2
+ VERSION = '4.7.0'.freeze
3
3
  end