foreman-tasks 0.14.0 → 0.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +1 -0
- data/app/controllers/foreman_tasks/tasks_controller.rb +7 -5
- data/app/lib/actions/action_with_sub_plans.rb +0 -2
- data/app/lib/actions/foreman/host/import_facts.rb +7 -3
- data/app/lib/actions/middleware/watch_delegated_proxy_sub_tasks.rb +2 -2
- data/app/models/foreman_tasks/task.rb +34 -11
- data/app/models/setting/foreman_tasks.rb +1 -0
- data/foreman-tasks.gemspec +1 -1
- data/lib/foreman_tasks.rb +9 -2
- data/lib/foreman_tasks/engine.rb +5 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/tasks_controller_test.rb +8 -0
- data/test/unit/task_test.rb +18 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fddcfe8ab9f1550261511074f70d3391836126c7fe54839857f0c10c31d2d456
|
4
|
+
data.tar.gz: ac4bf4b19d05f6d6af13440655d76fce521ec76a7bdae32207a1ed883cfaa569
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d6e2483dfdf63d5b32980889edd41af2d496ba5fce667593887f678781587282c17fb9abf3e77e22750d4c965c7930e45608c9a4ec7fa475d6c8f0b8e3a69e6
|
7
|
+
data.tar.gz: 5345f2fdce7081763d79468b548add5eea06093ec43581efbc3a84614571477d7446faaf4d10bda41b5c3007f0c0e3a207ab9d0d403ece7872aa2ee7ca2825a3
|
data/README.md
CHANGED
@@ -11,13 +11,14 @@ module ForemanTasks
|
|
11
11
|
|
12
12
|
def index
|
13
13
|
params[:order] ||= 'started_at DESC'
|
14
|
-
@tasks = filter(resource_base)
|
15
14
|
respond_to do |format|
|
16
15
|
format.html do
|
16
|
+
@tasks = filter(resource_base)
|
17
17
|
render :index
|
18
18
|
end
|
19
19
|
format.csv do
|
20
|
-
|
20
|
+
@tasks = filter(resource_base, paginate: false)
|
21
|
+
csv_response(@tasks, [:action, :state, :result, 'started_at.in_time_zone', 'ended_at.in_time_zone', :username], ['Action', 'State', 'Result', 'Started At', 'Ended At', 'User'])
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -124,11 +125,12 @@ module ForemanTasks
|
|
124
125
|
resource_scope.where(:type => 'ForemanTasks::Task::DynflowTask').find(params[:id])
|
125
126
|
end
|
126
127
|
|
127
|
-
def filter(scope)
|
128
|
+
def filter(scope, paginate: true)
|
128
129
|
search = current_taxonomy_search
|
129
130
|
search = [search, params[:search]].select(&:present?).join(' AND ')
|
130
|
-
scope.search_for(search, :order => params[:order])
|
131
|
-
|
131
|
+
scope = scope.search_for(search, :order => params[:order])
|
132
|
+
scope = scope.paginate(:page => params[:page], :per_page => params[:per_page]) if paginate
|
133
|
+
scope.distinct
|
132
134
|
end
|
133
135
|
|
134
136
|
def current_taxonomy_search
|
@@ -9,13 +9,13 @@ module Actions
|
|
9
9
|
def plan(_host_type, host_name, facts, certname, proxy_id)
|
10
10
|
facts['domain'].try(:downcase!)
|
11
11
|
host = if SETTINGS[:version].short > '1.16'
|
12
|
-
::Host::
|
12
|
+
::Host::Managed.import_host(host_name, certname)
|
13
13
|
else
|
14
14
|
# backwards compatibility
|
15
15
|
::Host::Managed.import_host(host_name, facts['_type'], certname, proxy_id)
|
16
16
|
end
|
17
17
|
host.save(:validate => false) if host.new_record?
|
18
|
-
action_subject(host, :facts => facts)
|
18
|
+
action_subject(host, :facts => facts.to_unsafe_h, :proxy_id => proxy_id)
|
19
19
|
if host.build?
|
20
20
|
::Foreman::Logging.logger('foreman-tasks').info "Skipping importing of facts for #{host.name} because it's in build mode"
|
21
21
|
else
|
@@ -26,7 +26,7 @@ module Actions
|
|
26
26
|
def run
|
27
27
|
::User.as :admin do
|
28
28
|
host = ::Host.find(input[:host][:id])
|
29
|
-
state = host.import_facts(input[:facts])
|
29
|
+
state = host.import_facts(input[:facts], proxy)
|
30
30
|
output[:state] = state
|
31
31
|
end
|
32
32
|
rescue ::Foreman::Exception => e
|
@@ -36,6 +36,10 @@ module Actions
|
|
36
36
|
raise e unless e.code == 'ERF51-9911'
|
37
37
|
end
|
38
38
|
|
39
|
+
def proxy
|
40
|
+
SmartProxy.find_by(id: input[:proxy_id]) if input[:proxy_id].present?
|
41
|
+
end
|
42
|
+
|
39
43
|
def rescue_strategy
|
40
44
|
::Dynflow::Action::Rescue::Skip
|
41
45
|
end
|
@@ -64,9 +64,9 @@ module Actions
|
|
64
64
|
task
|
65
65
|
end
|
66
66
|
rescue => e
|
67
|
-
# We could not reach the remote task, we
|
67
|
+
# We could not reach the remote task, we'll try again next time
|
68
68
|
action.action_logger.warn(_('Failed to check on tasks on proxy at %{url}: %{exception}') % { :url => url, :exception => e.message })
|
69
|
-
|
69
|
+
[]
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
@@ -51,7 +51,8 @@ module ForemanTasks
|
|
51
51
|
:complete_value => true,
|
52
52
|
:rename => 'owner.id',
|
53
53
|
:ext_method => :search_by_owner,
|
54
|
-
:validator => ->(value) { ScopedSearch::Validators::INTEGER.call(value) || value == 'current_user' }
|
54
|
+
:validator => ->(value) { ScopedSearch::Validators::INTEGER.call(value) || value == 'current_user' },
|
55
|
+
:aliases => ['user.id']
|
55
56
|
scoped_search :relation => :owners, :on => :login, :complete_value => true, :rename => 'owner.login', :ext_method => :search_by_owner, :aliases => [:user]
|
56
57
|
scoped_search :relation => :owners, :on => :firstname, :complete_value => true, :rename => 'owner.firstname', :ext_method => :search_by_owner
|
57
58
|
scoped_search :relation => :task_groups, :on => :id, :complete_value => true, :rename => 'task_group.id', :validator => ScopedSearch::Validators::INTEGER
|
@@ -85,8 +86,24 @@ module ForemanTasks
|
|
85
86
|
delayed? ? N_('Delayed') : N_('Immediate')
|
86
87
|
end
|
87
88
|
|
89
|
+
def get_humanized(method)
|
90
|
+
attr = case method
|
91
|
+
when :humanized_name
|
92
|
+
:action
|
93
|
+
when :humanized_input
|
94
|
+
:input
|
95
|
+
when :humanized_output
|
96
|
+
:output
|
97
|
+
end
|
98
|
+
if attr
|
99
|
+
humanized[attr]
|
100
|
+
else
|
101
|
+
_('N/A')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
88
105
|
def humanized
|
89
|
-
{ action:
|
106
|
+
{ action: action,
|
90
107
|
input: '',
|
91
108
|
output: '' }
|
92
109
|
end
|
@@ -158,6 +175,20 @@ module ForemanTasks
|
|
158
175
|
# using uniq suffix to avoid colisions when searching by two different owners via ScopedSearch
|
159
176
|
uniq_suffix = SecureRandom.hex(3)
|
160
177
|
key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
|
178
|
+
value.sub!('*', '%%')
|
179
|
+
condition = if key.blank?
|
180
|
+
sanitize_sql_for_conditions(["users#{uniq_suffix}.login #{operator} ? or users#{uniq_suffix}.firstname #{operator} ? ", value, value])
|
181
|
+
elsif key =~ /\.id\Z/
|
182
|
+
value = User.current.id if value == 'current_user'
|
183
|
+
sanitize_sql_for_conditions(["foreman_tasks_locks_owner#{uniq_suffix}.resource_id #{operator} ?", value])
|
184
|
+
else
|
185
|
+
placeholder, value = operator == 'IN' ? ['(?)', value.split(',').map(&:strip)] : ['?', value]
|
186
|
+
sanitize_sql_for_conditions(["users#{uniq_suffix}.#{key_name} #{operator} #{placeholder}", value])
|
187
|
+
end
|
188
|
+
{ :conditions => condition, :joins => joins_for_user_search(key, uniq_suffix) }
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.joins_for_user_search(key, uniq_suffix)
|
161
192
|
joins = <<-SQL
|
162
193
|
INNER JOIN foreman_tasks_locks AS foreman_tasks_locks_owner#{uniq_suffix}
|
163
194
|
ON (foreman_tasks_locks_owner#{uniq_suffix}.task_id = foreman_tasks_tasks.id AND
|
@@ -170,15 +201,7 @@ module ForemanTasks
|
|
170
201
|
ON (users#{uniq_suffix}.id = foreman_tasks_locks_owner#{uniq_suffix}.resource_id)
|
171
202
|
SQL
|
172
203
|
end
|
173
|
-
|
174
|
-
sanitize_sql_for_conditions(["users#{uniq_suffix}.login #{operator} ? or users#{uniq_suffix}.firstname #{operator} ? ", value, value])
|
175
|
-
elsif key =~ /\.id\Z/
|
176
|
-
value = User.current.id if value == 'current_user'
|
177
|
-
sanitize_sql_for_conditions(["foreman_tasks_locks_owner#{uniq_suffix}.resource_id #{operator} ?", value])
|
178
|
-
else
|
179
|
-
sanitize_sql_for_conditions(["users#{uniq_suffix}.#{key_name} #{operator} ?", value])
|
180
|
-
end
|
181
|
-
{ :conditions => condition, :joins => joins }
|
204
|
+
joins
|
182
205
|
end
|
183
206
|
|
184
207
|
def progress
|
@@ -5,6 +5,7 @@ class Setting::ForemanTasks < Setting
|
|
5
5
|
|
6
6
|
transaction do
|
7
7
|
[
|
8
|
+
set('foreman_tasks_sync_task_timeout', N_('Number of seconds to wait for synchronous task to finish.'), 120),
|
8
9
|
set('dynflow_allow_dangerous_actions', N_('Allow unlocking actions which can have dangerous consequences.'), false),
|
9
10
|
set('dynflow_enable_console', N_('Enable the dynflow console (/foreman_tasks/dynflow) for debugging'), true),
|
10
11
|
set('dynflow_console_require_auth', N_('Require user to be authenticated as user with admin rights when accessing dynflow console'), true),
|
data/foreman-tasks.gemspec
CHANGED
@@ -29,7 +29,7 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
|
|
29
29
|
s.extra_rdoc_files = Dir['README*', 'LICENSE']
|
30
30
|
|
31
31
|
s.add_dependency "foreman-tasks-core"
|
32
|
-
s.add_dependency "dynflow", '~> 1.0', '>= 1.1.
|
32
|
+
s.add_dependency "dynflow", '~> 1.0', '>= 1.1.1'
|
33
33
|
s.add_dependency "sinatra" # for Dynflow web console
|
34
34
|
s.add_dependency "parse-cron", '~> 0.1.4'
|
35
35
|
s.add_dependency "get_process_mem" # for memory polling
|
data/lib/foreman_tasks.rb
CHANGED
@@ -27,8 +27,15 @@ module ForemanTasks
|
|
27
27
|
raise error
|
28
28
|
end),
|
29
29
|
(on ::Dynflow::World::Triggered.call(execution_plan_id: ~any, future: ~any) do |id, finished|
|
30
|
-
|
31
|
-
|
30
|
+
unless async
|
31
|
+
timeout = Setting['foreman_tasks_sync_task_timeout']
|
32
|
+
finished.wait(timeout)
|
33
|
+
task = ForemanTasks::Task::DynflowTask.where(:external_id => id).first
|
34
|
+
if task.nil? || task.pending?
|
35
|
+
raise TimeoutError, "The time waiting for task #{task.try(:id)} to finish exceeded the 'foreman_tasks_sync_task_timeout' (#{timeout}s)"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
task || ForemanTasks::Task::DynflowTask.where(:external_id => id).first!
|
32
39
|
end)
|
33
40
|
end
|
34
41
|
end
|
data/lib/foreman_tasks/engine.rb
CHANGED
@@ -115,8 +115,12 @@ module ForemanTasks
|
|
115
115
|
|
116
116
|
initializer 'foreman_tasks.require_dynflow', :before => 'foreman_tasks.initialize_dynflow' do |_app|
|
117
117
|
ForemanTasks.dynflow.require!
|
118
|
-
::ForemanTasks.dynflow.config.on_init do |world|
|
118
|
+
::ForemanTasks.dynflow.config.on_init(false) do |world|
|
119
|
+
world.middleware.use Actions::Middleware::KeepCurrentTaxonomies
|
119
120
|
world.middleware.use Actions::Middleware::KeepCurrentUser
|
121
|
+
end
|
122
|
+
|
123
|
+
::ForemanTasks.dynflow.config.on_init do |world|
|
120
124
|
ForemanTasksCore.dynflow_setup(world)
|
121
125
|
end
|
122
126
|
end
|
@@ -24,6 +24,14 @@ module ForemanTasks
|
|
24
24
|
Organization.current = Location.current = nil
|
25
25
|
end
|
26
26
|
|
27
|
+
it 'supports csv export' do
|
28
|
+
FactoryBot.create(:some_task, :action => 'Some action')
|
29
|
+
get(:index, params: { format: :csv }, session: set_session_user)
|
30
|
+
assert_response :success
|
31
|
+
assert_equal 2, response.body.lines.size
|
32
|
+
assert_include response.body.lines[1], 'Some action'
|
33
|
+
end
|
34
|
+
|
27
35
|
describe 'taxonomy scoping' do
|
28
36
|
let(:organizations) { (0..1).map { FactoryBot.create(:organization) } }
|
29
37
|
let(:tasks) { organizations.map { |o| linked_task(o) } + [FactoryBot.create(:some_task)] }
|
data/test/unit/task_test.rb
CHANGED
@@ -21,6 +21,24 @@ class TasksTest < ActiveSupport::TestCase
|
|
21
21
|
test 'can search the tasks by current_user in combination with implicit search' do
|
22
22
|
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id = current_user AND #{@task_one.label}")
|
23
23
|
end
|
24
|
+
|
25
|
+
test 'can search the tasks by user' do
|
26
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user = #{@user_one.login}")
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'can search the tasks by user\'s id' do
|
30
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user.id = #{@user_one.id}")
|
31
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id = #{@user_one.id}")
|
32
|
+
end
|
33
|
+
|
34
|
+
test 'can search the tasks by user with wildcards' do
|
35
|
+
glob = '*' + @user_one.login[1..-1] # search for '*ser1' if login is 'user1'
|
36
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user ~ #{glob}")
|
37
|
+
end
|
38
|
+
|
39
|
+
test 'can search the tasks by array' do
|
40
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user ^ (this_user, #{@user_one.login}, that_user)")
|
41
|
+
end
|
24
42
|
end
|
25
43
|
|
26
44
|
describe 'authorization filtering' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Nečas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: foreman-tasks-core
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: '1.0'
|
34
34
|
- - ">="
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: 1.1.
|
36
|
+
version: 1.1.1
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 1.1.
|
46
|
+
version: 1.1.1
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sinatra
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -297,7 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
297
|
version: '0'
|
298
298
|
requirements: []
|
299
299
|
rubyforge_project:
|
300
|
-
rubygems_version: 2.
|
300
|
+
rubygems_version: 2.7.3
|
301
301
|
signing_key:
|
302
302
|
specification_version: 4
|
303
303
|
summary: Foreman plugin for showing tasks information for resoruces and users
|