foreman-tasks 0.14.3 → 0.14.4

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: 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