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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 99bc7ed098375451dddebc63a0d2c5af37ec3374
4
- data.tar.gz: 573580a8808e4c68f84a82db9a05919b960aa771
2
+ SHA256:
3
+ metadata.gz: fddcfe8ab9f1550261511074f70d3391836126c7fe54839857f0c10c31d2d456
4
+ data.tar.gz: ac4bf4b19d05f6d6af13440655d76fce521ec76a7bdae32207a1ed883cfaa569
5
5
  SHA512:
6
- metadata.gz: 9f37b871477d68c476aef947749d516337e3ae8fe5d71bc7f49f82bc5f0467fa265ac324661cb3ad9a2e7368159e92e017e101cd940422b2f1eaea24e4960948
7
- data.tar.gz: a11510b41ff6b00d8d76acaa01a3dede47792c732711ee916e86979e2f56cd02ca861a8d648673ac34e9d8d0bf73452677029969557311446c90b391ecebcb24
6
+ metadata.gz: 0d6e2483dfdf63d5b32980889edd41af2d496ba5fce667593887f678781587282c17fb9abf3e77e22750d4c965c7930e45608c9a4ec7fa475d6c8f0b8e3a69e6
7
+ data.tar.gz: 5345f2fdce7081763d79468b548add5eea06093ec43581efbc3a84614571477d7446faaf4d10bda41b5c3007f0c0e3a207ab9d0d403ece7872aa2ee7ca2825a3
data/README.md CHANGED
@@ -21,6 +21,7 @@ happening/happened in your Foreman instance. A framework for asynchronous tasks
21
21
  | >= 1.16 | ~> 0.10.0 |
22
22
  | >= 1.17 | ~> 0.11.0 |
23
23
  | >= 1.18 | ~> 0.13.0 |
24
+ | >= 1.20 | ~> 0.14.0 |
24
25
 
25
26
  Installation
26
27
  ------------
@@ -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
- csv_response(@tasks, [:action_label, :state, :result, 'started_at.in_time_zone', 'ended_at.in_time_zone', :username], ['Action', 'State', 'Result', 'Started At', 'Ended At', 'User'])
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
- .paginate(:page => params[:page], :per_page => params[:per_page]).distinct
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
@@ -1,7 +1,5 @@
1
1
  module Actions
2
2
  class Actions::ActionWithSubPlans < Actions::EntryAction
3
- middleware.use Actions::Middleware::KeepCurrentUser
4
-
5
3
  include Dynflow::Action::WithSubPlans
6
4
 
7
5
  def plan(*_args)
@@ -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::Base.import_host(host_name, certname, proxy_id)
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 assume it's gone
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
- tasks
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: label,
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
- condition = if key.blank?
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),
@@ -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.0'
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
- finished.wait if async == false
31
- ForemanTasks::Task::DynflowTask.where(:external_id => id).first!
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '0.14.0'.freeze
2
+ VERSION = '0.14.1'.freeze
3
3
  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)] }
@@ -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.0
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-07-31 00:00:00.000000000 Z
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.0
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.0
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.6.12
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