foreman-tasks 0.14.3 → 0.14.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ca474011e1808cd85f5566a30769a192a5bb171e
4
- data.tar.gz: 7f9d5e194413251db13425c423978d473c14341d
2
+ SHA256:
3
+ metadata.gz: 6f8451837ba0e15aae21f3bf127323a6b068ebfd160e2b66e703cbff3eb33313
4
+ data.tar.gz: e0aa650d6b258b8fc7c379055716c8bda2588b6e621f71e43c00cfc99de860ef
5
5
  SHA512:
6
- metadata.gz: 73ce88e6cf0e8d4b745e792bb615d17d74d41e729db518e9a1fd21737e53432fdb8b17e67f7f4ead0e256448bdebc62cc0b1e860d11a49e7d85717882ac1294c
7
- data.tar.gz: 14fc6a89d2d076eadaacc5286a90868f83e6e5aaea69492864653f8ab95d00dc56633abbc43c856fc1c831717b4947a519e11b563d65e616f06a40a5daec202d
6
+ metadata.gz: 6e14391d65b6c1bea3c60ab6f487a47a24e452eca949672900943abe37add259eb484675f26caef1cf3e627cd5668d97b95caa809d75a64562531cc1a88bd42d
7
+ data.tar.gz: b35ee50b3ac877d780e145f61892ac9545684bac290c09de2a6a97fbf5bf854e77e3492fe0b14730b235afd8715fde193dd8eead3f3fcf55265778570b2a3919
data/.rubocop.yml CHANGED
@@ -75,6 +75,9 @@ Layout/IndentHeredoc:
75
75
  - '*.gemspec'
76
76
  - bin/*
77
77
 
78
+ Layout/EmptyLineAfterGuardClause:
79
+ Enabled: false
80
+
78
81
  Style/RescueStandardError:
79
82
  Enabled: false
80
83
 
@@ -27,22 +27,14 @@ module Actions
27
27
 
28
28
  # This method should return String or Array<String> describing input for the task
29
29
  def humanized_input
30
- if task_input.blank?
31
- ''
32
- else
33
- task_input.pretty_inspect
34
- end
30
+ ''
35
31
  end
36
32
 
37
33
  # This method should return String describing output for the task.
38
34
  # It should aggregate the data from subactions as well and it's used for humanized
39
35
  # description of restuls of the action
40
36
  def humanized_output
41
- if task_output.blank?
42
- ''
43
- else
44
- task_output.pretty_inspect
45
- end
37
+ ''
46
38
  end
47
39
 
48
40
  # This method should return String or Array<String> describing the errors during the action
@@ -48,7 +48,9 @@ module Actions
48
48
  target_class = input[:target_class].constantize
49
49
  targets = target_class.where(:id => current_batch)
50
50
 
51
- targets.map do |target|
51
+ missing = Array.new((current_batch - targets.map(&:id)).count) { nil }
52
+
53
+ (targets + missing).map do |target|
52
54
  trigger(action_class, target, *input[:args])
53
55
  end
54
56
  end
@@ -0,0 +1,50 @@
1
+ module Actions
2
+ module Middleware
3
+ class KeepCurrentTimezone < Dynflow::Middleware
4
+ def delay(*args)
5
+ pass(*args).tap { store_current_timezone }
6
+ end
7
+
8
+ def plan(*args)
9
+ with_current_timezone do
10
+ pass(*args).tap { store_current_timezone }
11
+ end
12
+ end
13
+
14
+ def run(*args)
15
+ restore_curent_timezone { pass(*args) }
16
+ end
17
+
18
+ def finalize
19
+ restore_curent_timezone { pass }
20
+ end
21
+
22
+ # Run all execution plan lifecycle hooks as the original timezone
23
+ def hook(*args)
24
+ restore_curent_timezone { pass(*args) }
25
+ end
26
+
27
+ private
28
+
29
+ def with_current_timezone
30
+ if action.input[:current_timezone].nil?
31
+ yield
32
+ else
33
+ restore_curent_timezone { yield }
34
+ end
35
+ end
36
+
37
+ def store_current_timezone
38
+ action.input[:current_timezone] = Time.zone.name
39
+ end
40
+
41
+ def restore_curent_timezone
42
+ old_zone = Time.zone
43
+ Time.zone = Time.find_zone(action.input[:current_timezone]) if action.input[:current_timezone].present?
44
+ yield
45
+ ensure
46
+ Time.zone = old_zone
47
+ end
48
+ end
49
+ end
50
+ end
@@ -158,7 +158,7 @@ module ForemanTasks
158
158
  cronline = if triggering.input_type == :cronline
159
159
  triggering.cronline
160
160
  else
161
- ::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash(triggering.input_type, triggering.time, triggering.days_of_week))
161
+ ::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash(triggering.input_type, triggering.time, triggering.days, triggering.days_of_week))
162
162
  end
163
163
  ::ForemanTasks::RecurringLogic.new_from_cronline(cronline).tap do |manager|
164
164
  manager.end_time = triggering.end_time if triggering.end_time_limited.present?
@@ -167,11 +167,10 @@ module ForemanTasks
167
167
  end
168
168
  end
169
169
 
170
- def self.cronline_hash(recurring_type, time_hash, days_of_week_hash)
170
+ def self.cronline_hash(recurring_type, time_hash, days, days_of_week_hash)
171
171
  hash = Hash[[:years, :months, :days, :hours, :minutes].zip(time_hash.values)]
172
- hash.update :days_of_week => days_of_week_hash
173
- .select { |_key, value| value == '1' }
174
- .keys.join(',')
172
+ days_of_week = days_of_week_hash.select { |_key, value| value == '1' }.keys.join(',')
173
+ hash.update :days_of_week => days_of_week, :days => days
175
174
  allowed_keys = case recurring_type
176
175
  when :monthly
177
176
  [:minutes, :hours, :days]
@@ -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.1'
32
+ s.add_dependency "dynflow", '~> 1.0', '>= 1.1.5'
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
@@ -8,10 +8,10 @@ module ForemanTasks
8
8
 
9
9
  initializer 'foreman_tasks.load_default_settings', :before => :load_config_initializers do
10
10
  require_dependency File.expand_path('../../../app/models/setting/foreman_tasks.rb', __FILE__) if begin
11
- Setting.table_exists?
12
- rescue
13
- (false)
14
- end
11
+ Setting.table_exists?
12
+ rescue
13
+ false
14
+ end
15
15
  end
16
16
 
17
17
  # Precompile any JS or CSS files under app/assets/
@@ -118,6 +118,7 @@ module ForemanTasks
118
118
  ::ForemanTasks.dynflow.config.on_init(false) do |world|
119
119
  world.middleware.use Actions::Middleware::KeepCurrentTaxonomies
120
120
  world.middleware.use Actions::Middleware::KeepCurrentUser
121
+ world.middleware.use Actions::Middleware::KeepCurrentTimezone
121
122
  end
122
123
 
123
124
  ::ForemanTasks.dynflow.config.on_init do |world|
@@ -201,7 +201,7 @@ namespace :foreman_tasks do
201
201
  #{template}
202
202
  <body>
203
203
  </html>
204
- HTML
204
+ HTML
205
205
  end
206
206
 
207
207
  def self.copy_assets(tmp_dir)
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '0.14.3'.freeze
2
+ VERSION = '0.14.4'.freeze
3
3
  end
@@ -30,20 +30,35 @@ module ForemanTasks
30
30
  describe 'GET /api/tasks/summary' do
31
31
  class DummyTestSummaryAction < Support::DummyDynflowAction
32
32
  # a dummy test action that do nothing
33
+ def plan(suspend = false)
34
+ plan_self :suspend => suspend
35
+ end
36
+
33
37
  def run
34
38
  # a dummy run method
39
+ if input[:suspend] && output[:suspended].nil?
40
+ output[:suspended] = true
41
+ suspend
42
+ end
35
43
  end
36
44
  end
37
45
 
38
46
  test_attributes :pid => 'bdcab413-a25d-4fe1-9db4-b50b5c31ebce'
39
47
  it 'get tasks summary' do
40
- ForemanTasks.trigger(DummyTestSummaryAction)
48
+ triggered = ForemanTasks.trigger(DummyTestSummaryAction, true)
49
+ wait_for { ForemanTasks::Task.find_by(external_id: triggered.id).state == 'running' }
50
+ wait_for do
51
+ w = ForemanTasks.dynflow.world
52
+ w.persistence.load_step(triggered.id, 2, w).state == :suspended
53
+ end
41
54
  get :summary
42
55
  assert_response :success
43
56
  response = JSON.parse(@response.body)
44
57
  assert_kind_of Array, response
45
- refute response.empty?
58
+ assert_not response.empty?
46
59
  assert_kind_of Hash, response[0]
60
+ ForemanTasks.dynflow.world.event(triggered.id, 2, nil)
61
+ triggered.finished.wait
47
62
  end
48
63
  end
49
64
 
@@ -56,6 +71,7 @@ module ForemanTasks
56
71
  'Proxy::DummyAction',
57
72
  'foo' => 'bar')
58
73
  Support::DummyProxyAction.proxy.task_triggered.wait(5)
74
+ wait_for { ForemanTasks::Task.find_by(external_id: triggered.id).state == 'running' }
59
75
 
60
76
  task = ForemanTasks::Task.where(:external_id => triggered.id).first
61
77
  task.state.must_equal 'running'
@@ -12,3 +12,14 @@ FactoryBot.find_definitions
12
12
 
13
13
  ForemanTasks.dynflow.require!
14
14
  ForemanTasks.dynflow.config.disable_active_record_actions = true
15
+
16
+ # waits for the passed block to return non-nil value and reiterates it while getting false
17
+ # (till some reasonable timeout). Useful for forcing the tests for some event to occur
18
+ def wait_for(waiting_message = 'something to happen')
19
+ 30.times do
20
+ ret = yield
21
+ return ret if ret
22
+ sleep 0.3
23
+ end
24
+ raise "waiting for #{waiting_message} was not successful"
25
+ end
@@ -0,0 +1,52 @@
1
+ require 'foreman_tasks_test_helper'
2
+
3
+ module Actions
4
+ module Middleware
5
+ class KeepCurrentTimezoneTest < ActiveSupport::TestCase
6
+ include ::Dynflow::Testing
7
+
8
+ class TestAction < Support::DummyDynflowAction
9
+ middleware.use KeepCurrentTimezone
10
+
11
+ def run; end
12
+ end
13
+
14
+ describe 'plan' do
15
+ let(:zone) { Time.find_zone('Pacific/Honolulu') }
16
+ test 'with current user set' do
17
+ Time.expects(:zone).returns(zone)
18
+ action = create_and_plan_action(TestAction)
19
+ assert_equal(zone.name, action.input['current_timezone'])
20
+ end
21
+ end
22
+
23
+ describe 'run' do
24
+ let(:zone) { Time.find_zone('Pacific/Honolulu') }
25
+
26
+ before do
27
+ @real_zone = Time.zone
28
+ @action = create_and_plan_action(TestAction)
29
+ end
30
+
31
+ test 'when timezone is not set in input' do
32
+ # It saves and restore the real zone
33
+ Time.expects(:zone=).with(@real_zone)
34
+ @action.stubs(:input).returns({})
35
+ run_action(@action)
36
+ end
37
+
38
+ test 'with current timezone as input' do
39
+ # We plan the @action in @real_zone
40
+ # We run the action in Pacific/Honolulu
41
+ Time.stubs(:zone).returns(zone)
42
+ # It restores the orinal time zone
43
+ Time.expects(:zone=).with(zone)
44
+
45
+ # It restores the saved time zone
46
+ Time.expects(:zone=).with(@real_zone)
47
+ run_action(@action)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,47 @@
1
+ require 'foreman_tasks_test_helper'
2
+
3
+ module ForemanTasks
4
+ class BulkActionTest < ActiveSupport::TestCase
5
+ before do
6
+ User.current = User.where(:login => 'apiadmin').first
7
+ end
8
+
9
+ Target = Struct.new(:id)
10
+
11
+ class ParentAction < Actions::BulkAction; end
12
+
13
+ class ChildAction < Actions::EntryAction
14
+ def plan(target)
15
+ target.id
16
+ end
17
+ end
18
+
19
+ describe Actions::BulkAction do
20
+ let(:targets) { (1..5).map { |i| Target.new i } }
21
+ let(:task) do
22
+ triggered = ForemanTasks.trigger(ParentAction, ChildAction, targets)
23
+ task = ForemanTasks::Task.where(:external_id => triggered.id).first
24
+ wait_for { task.reload.state == 'stopped' }
25
+ task
26
+ end
27
+
28
+ specify 'it plans a task for each target' do
29
+ Target.expects(:where).with(:id => targets.map(&:id)).returns(targets)
30
+
31
+ task.sub_tasks.count.must_equal targets.count
32
+ success, failed = task.sub_tasks.partition { |sub_task| sub_task.result == 'success' }
33
+ failed.must_be :empty?
34
+ success.count.must_equal 5
35
+ end
36
+
37
+ specify 'it plans a task for each target even if target cannot be found' do
38
+ Target.expects(:where).with(:id => targets.map(&:id)).returns(targets.take(4))
39
+
40
+ task.sub_tasks.count.must_equal targets.count
41
+ success, failed = task.sub_tasks.partition { |sub_task| sub_task.result == 'success' }
42
+ success.count.must_equal 4
43
+ failed.count.must_equal 1
44
+ end
45
+ end
46
+ end
47
+ end
@@ -114,7 +114,7 @@ module ForemanTasks
114
114
  action.world.stubs(:persistence).returns(persistence)
115
115
  action.wipe_secrets!(nil)
116
116
 
117
- refute action.input.key?(:secrets)
117
+ assert_not action.input.key?(:secrets)
118
118
  end
119
119
  end
120
120
  end
@@ -22,7 +22,7 @@ module ForemanTasks
22
22
  :minutes => 0,
23
23
  :hours => 12,
24
24
  :days => 1,
25
- :months => (Time.zone.now.month + 1) % 12
25
+ :months => ((Time.zone.now.month + 1) % 12) + 1
26
26
  }
27
27
  end
28
28
 
@@ -57,18 +57,18 @@ module ForemanTasks
57
57
  end
58
58
 
59
59
  it 'can see only the tasks he has permissions on' do
60
- refute dynflow_console_authorized?
60
+ assert_not dynflow_console_authorized?
61
61
  assert dynflow_console_authorized?(own_task)
62
- refute dynflow_console_authorized?(foreign_task)
62
+ assert_not dynflow_console_authorized?(foreign_task)
63
63
  end
64
64
  end
65
65
 
66
66
  describe 'user without edit_foreman_tasks permissions' do
67
67
  let(:user) { FactoryBot.create(:user) }
68
68
  it 'can not see any tasks' do
69
- refute dynflow_console_authorized?
70
- refute dynflow_console_authorized?(own_task)
71
- refute dynflow_console_authorized?(foreign_task)
69
+ assert_not dynflow_console_authorized?
70
+ assert_not dynflow_console_authorized?(own_task)
71
+ assert_not dynflow_console_authorized?(foreign_task)
72
72
  end
73
73
  end
74
74
  end
@@ -43,15 +43,15 @@ class RecurringLogicsTest < ActiveSupport::TestCase
43
43
  hours = '12'
44
44
  days = '11'
45
45
  days_of_week = { '1' => '1', '2' => '0', '3' => '0', '4' => '1', '5' => '0', '6' => '1', '7' => '0' }
46
- time_hash = { '0' => '2015', '1' => '12', '2' => '11', '3' => hours, '4' => minutes }
46
+ time_hash = { '0' => '2015', '1' => '12', '2' => '10', '3' => hours, '4' => minutes }
47
47
  expected_result_hourly = { :minutes => minutes }
48
48
  expected_result_daily = { :minutes => minutes, :hours => hours }
49
49
  expected_result_weekly = { :minutes => minutes, :hours => hours, :days_of_week => '1,4,6' }
50
50
  expected_result_monthly = { :minutes => minutes, :hours => hours, :days => days }
51
- ForemanTasks::RecurringLogic.cronline_hash(:hourly, time_hash, days_of_week).must_equal expected_result_hourly
52
- ForemanTasks::RecurringLogic.cronline_hash(:daily, time_hash, days_of_week).must_equal expected_result_daily
53
- ForemanTasks::RecurringLogic.cronline_hash(:weekly, time_hash, days_of_week).must_equal expected_result_weekly
54
- ForemanTasks::RecurringLogic.cronline_hash(:monthly, time_hash, days_of_week).must_equal expected_result_monthly
51
+ ForemanTasks::RecurringLogic.cronline_hash(:hourly, time_hash, days, days_of_week).must_equal expected_result_hourly
52
+ ForemanTasks::RecurringLogic.cronline_hash(:daily, time_hash, days, days_of_week).must_equal expected_result_daily
53
+ ForemanTasks::RecurringLogic.cronline_hash(:weekly, time_hash, days, days_of_week).must_equal expected_result_weekly
54
+ ForemanTasks::RecurringLogic.cronline_hash(:monthly, time_hash, days, days_of_week).must_equal expected_result_monthly
55
55
  end
56
56
 
57
57
  it 'can have limited number of repeats' do
@@ -94,7 +94,9 @@ class RecurringLogicsTest < ActiveSupport::TestCase
94
94
  future_time = Time.zone.now + 1.week
95
95
  recurring_logic.start_after(::Support::DummyRecurringDynflowAction, future_time)
96
96
 
97
- assert_equal future_time.change(:min => future_time.min + 1, :sec => 0), recurring_logic.tasks.first.start_at
97
+ # Add one minute to the time, set seconds to 0
98
+ target_time = (future_time + 1.minute).change(:sec => 0)
99
+ assert_equal target_time, recurring_logic.tasks.first.start_at
98
100
  end
99
101
 
100
102
  it 'has a task group associated to all tasks that were created as part of the recurring logic' do
@@ -147,7 +149,7 @@ class RecurringLogicsTest < ActiveSupport::TestCase
147
149
  assert_equal 'active', logic.state
148
150
 
149
151
  task = logic.tasks.find_by(:state => 'scheduled')
150
- refute ForemanTasks.dynflow.world.persistence.load_delayed_plan(task.execution_plan.id).frozen
152
+ assert_not ForemanTasks.dynflow.world.persistence.load_delayed_plan(task.execution_plan.id).frozen
151
153
  assert task.start_at > Time.zone.now
152
154
  end
153
155
  end
@@ -152,7 +152,7 @@ class TasksTest < ActiveSupport::TestCase
152
152
  let(:task) { FactoryBot.create(:dynflow_task) }
153
153
 
154
154
  it 'can indicate it is recurring' do
155
- refute task.recurring?
155
+ assert_not task.recurring?
156
156
  task.add_missing_task_groups(logic.task_group)
157
157
  task.reload
158
158
  assert task.recurring?
@@ -163,7 +163,7 @@ class TasksTest < ActiveSupport::TestCase
163
163
  let(:task) { FactoryBot.create(:some_task) }
164
164
 
165
165
  it 'can indicate it is delayed' do
166
- refute task.delayed?
166
+ assert_not task.delayed?
167
167
  task.execution_type.must_equal 'Immediate'
168
168
  task.start_at = Time.now.utc + 100
169
169
  assert task.delayed?
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.3
4
+ version: 0.14.4
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-22 00:00:00.000000000 Z
11
+ date: 2018-12-11 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.1
36
+ version: 1.1.5
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.1
46
+ version: 1.1.5
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sinatra
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -147,6 +147,7 @@ files:
147
147
  - app/lib/actions/middleware/hide_secrets.rb
148
148
  - app/lib/actions/middleware/inherit_task_groups.rb
149
149
  - app/lib/actions/middleware/keep_current_taxonomies.rb
150
+ - app/lib/actions/middleware/keep_current_timezone.rb
150
151
  - app/lib/actions/middleware/keep_current_user.rb
151
152
  - app/lib/actions/middleware/rails_executor_wrap.rb
152
153
  - app/lib/actions/middleware/recurring_logic.rb
@@ -258,6 +259,7 @@ files:
258
259
  - test/foreman_tasks_test_helper.rb
259
260
  - test/helpers/foreman_tasks/tasks_helper_test.rb
260
261
  - test/lib/actions/middleware/keep_current_taxonomies_test.rb
262
+ - test/lib/actions/middleware/keep_current_timezone_test.rb
261
263
  - test/lib/actions/middleware/keep_current_user_test.rb
262
264
  - test/support/dummy_active_job.rb
263
265
  - test/support/dummy_dynflow_action.rb
@@ -266,6 +268,7 @@ files:
266
268
  - test/support/dummy_task_group.rb
267
269
  - test/tasks/generate_task_actions_test.rb
268
270
  - test/unit/actions/action_with_sub_plans_test.rb
271
+ - test/unit/actions/bulk_action_test.rb
269
272
  - test/unit/actions/proxy_action_test.rb
270
273
  - test/unit/actions/recurring_action_test.rb
271
274
  - test/unit/cleaner_test.rb
@@ -297,7 +300,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
297
300
  version: '0'
298
301
  requirements: []
299
302
  rubyforge_project:
300
- rubygems_version: 2.6.11
303
+ rubygems_version: 2.7.6
301
304
  signing_key:
302
305
  specification_version: 4
303
306
  summary: Foreman plugin for showing tasks information for resoruces and users
@@ -312,6 +315,7 @@ test_files:
312
315
  - test/foreman_tasks_test_helper.rb
313
316
  - test/helpers/foreman_tasks/tasks_helper_test.rb
314
317
  - test/lib/actions/middleware/keep_current_taxonomies_test.rb
318
+ - test/lib/actions/middleware/keep_current_timezone_test.rb
315
319
  - test/lib/actions/middleware/keep_current_user_test.rb
316
320
  - test/support/dummy_active_job.rb
317
321
  - test/support/dummy_dynflow_action.rb
@@ -320,6 +324,7 @@ test_files:
320
324
  - test/support/dummy_task_group.rb
321
325
  - test/tasks/generate_task_actions_test.rb
322
326
  - test/unit/actions/action_with_sub_plans_test.rb
327
+ - test/unit/actions/bulk_action_test.rb
323
328
  - test/unit/actions/proxy_action_test.rb
324
329
  - test/unit/actions/recurring_action_test.rb
325
330
  - test/unit/cleaner_test.rb