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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby_ci.yml +7 -0
- data/app/controllers/job_invocations_controller.rb +1 -1
- data/app/controllers/ui_job_wizard_controller.rb +7 -0
- data/app/graphql/types/job_invocation.rb +16 -0
- data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +5 -1
- data/app/helpers/remote_execution_helper.rb +9 -3
- data/app/lib/actions/remote_execution/run_host_job.rb +5 -1
- data/app/lib/actions/remote_execution/run_hosts_job.rb +1 -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 +4 -4
- data/app/models/job_template.rb +1 -1
- data/app/models/remote_execution_feature.rb +5 -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/app/views/templates/ssh/module_action.erb +1 -0
- data/app/views/templates/ssh/power_action.erb +2 -0
- data/app/views/templates/ssh/puppet_run_once.erb +1 -0
- data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
- data/foreman_remote_execution.gemspec +2 -3
- data/lib/foreman_remote_execution/engine.rb +3 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/graphql/queries/job_invocation_query_test.rb +31 -0
- data/test/graphql/queries/job_invocations_query_test.rb +35 -0
- data/test/unit/concerns/host_extensions_test.rb +4 -4
- data/test/unit/input_template_renderer_test.rb +1 -89
- data/test/unit/job_invocation_composer_test.rb +15 -13
- data/test/unit/job_invocation_test.rb +1 -1
- data/webpack/JobWizard/JobWizard.js +28 -8
- data/webpack/JobWizard/JobWizard.scss +39 -0
- data/webpack/JobWizard/JobWizardConstants.js +10 -0
- data/webpack/JobWizard/JobWizardSelectors.js +9 -0
- data/webpack/JobWizard/__tests__/fixtures.js +104 -2
- data/webpack/JobWizard/__tests__/integration.test.js +13 -85
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +21 -4
- data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +67 -0
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +73 -59
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +135 -16
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +23 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +122 -51
- data/webpack/JobWizard/steps/Schedule/QueryType.js +48 -0
- data/webpack/JobWizard/steps/Schedule/RepeatOn.js +61 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleType.js +25 -0
- data/webpack/JobWizard/steps/Schedule/StartEndDates.js +51 -0
- data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +22 -0
- data/webpack/JobWizard/steps/Schedule/index.js +41 -0
- data/webpack/JobWizard/steps/form/FormHelpers.js +1 -0
- data/webpack/JobWizard/steps/form/Formatter.js +149 -0
- data/webpack/JobWizard/steps/form/NumberInput.js +33 -0
- data/webpack/JobWizard/steps/form/SelectField.js +14 -2
- data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +76 -0
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
- data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +43 -0
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +72 -66
- data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +98 -0
- data/webpack/react_app/components/RecentJobsCard/constants.js +11 -0
- data/webpack/react_app/components/RecentJobsCard/styles.scss +11 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -0
- data/webpack/react_app/extend/fillRecentJobsCard.js +1 -1
- metadata +25 -16
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
- data/test/models/orchestration/ssh_test.rb +0 -56
- data/webpack/JobWizard/__tests__/JobWizard.test.js +0 -13
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +0 -32
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +0 -249
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +0 -113
- data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +0 -38
- data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +0 -23
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +0 -37
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +0 -23
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 742978171c8d62de9fdf9e14b2be742235dc1cce90c0c522871d65a90ee1f612
|
|
4
|
+
data.tar.gz: caae67492773457e26461ae6e39addec2cc1b105bf387a9cf0dbfc667ad25102
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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,
|
|
@@ -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)
|
|
@@ -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.
|
|
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.
|
|
516
|
+
Bookmark.my_bookmarks.where(:controller => ['hosts', 'dashboard'])
|
|
517
517
|
end
|
|
518
518
|
|
|
519
519
|
def targeted_hosts
|
data/app/models/job_template.rb
CHANGED
|
@@ -20,7 +20,11 @@ class RemoteExecutionFeature < ApplicationRecord
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def self.feature(label)
|
|
23
|
-
self.find_by(label: 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
|
-
|
|
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
|
|
@@ -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'
|
|
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', '>=
|
|
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
|