foreman-tasks 0.8.6 → 0.9.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/.rubocop.yml +35 -0
- data/.rubocop_todo.yml +138 -0
- data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +3 -4
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +56 -72
- data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +2 -4
- data/app/controllers/foreman_tasks/recurring_logics_controller.rb +2 -5
- data/app/controllers/foreman_tasks/tasks_controller.rb +7 -8
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +44 -46
- data/app/helpers/foreman_tasks/tasks_helper.rb +1 -1
- data/app/lib/actions/action_with_sub_plans.rb +6 -8
- data/app/lib/actions/base.rb +6 -7
- data/app/lib/actions/bulk_action.rb +13 -9
- data/app/lib/actions/entry_action.rb +1 -3
- data/app/lib/actions/foreman/host/import_facts.rb +2 -5
- data/app/lib/actions/foreman/puppetclass/import.rb +1 -1
- data/app/lib/actions/helpers/args_serialization.rb +0 -1
- data/app/lib/actions/helpers/humanizer.rb +16 -21
- data/app/lib/actions/helpers/with_continuous_output.rb +0 -1
- data/app/lib/actions/helpers/with_delegated_action.rb +2 -2
- data/app/lib/actions/middleware/inherit_task_groups.rb +3 -5
- data/app/lib/actions/middleware/keep_current_user.rb +0 -3
- data/app/lib/actions/middleware/recurring_logic.rb +0 -1
- data/app/lib/actions/proxy_action.rb +8 -8
- data/app/lib/actions/serializers/active_record_serializer.rb +0 -3
- data/app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb +3 -3
- data/app/models/foreman_tasks/concerns/action_subject.rb +4 -6
- data/app/models/foreman_tasks/concerns/action_triggering.rb +20 -33
- data/app/models/foreman_tasks/concerns/host_action_subject.rb +5 -5
- data/app/models/foreman_tasks/lock.rb +29 -37
- data/app/models/foreman_tasks/recurring_logic.rb +23 -24
- data/app/models/foreman_tasks/task.rb +65 -39
- data/app/models/foreman_tasks/task/dynflow_task.rb +23 -24
- data/app/models/foreman_tasks/task/status_explicator.rb +3 -3
- data/app/models/foreman_tasks/task/summarizer.rb +3 -3
- data/app/models/foreman_tasks/task_group.rb +0 -2
- data/app/models/foreman_tasks/task_group_member.rb +0 -2
- data/app/models/foreman_tasks/task_groups/recurring_logic_task_group.rb +1 -4
- data/app/models/foreman_tasks/triggering.rb +19 -19
- data/app/models/setting/foreman_tasks.rb +8 -11
- data/app/services/foreman_tasks/proxy_selector.rb +4 -5
- data/app/views/foreman_tasks/tasks/_details.html.erb +1 -1
- data/bin/dynflow-executor +1 -1
- data/bin/foreman-tasks +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20150814204140_add_task_type_value_index.rb +1 -1
- data/db/migrate/20160924213030_change_tasks_widget_names.rb +8 -8
- data/db/seeds.d/61-foreman_tasks_bookmarks.rb +3 -3
- data/deploy/foreman-tasks.sysconfig +6 -0
- data/extra/dynflow-debug.sh +12 -0
- data/foreman-tasks.gemspec +1 -1
- data/lib/foreman_tasks.rb +3 -3
- data/lib/foreman_tasks/authorizer_ext.rb +1 -1
- data/lib/foreman_tasks/cleaner.rb +14 -16
- data/lib/foreman_tasks/dynflow.rb +11 -9
- data/lib/foreman_tasks/dynflow/configuration.rb +8 -10
- data/lib/foreman_tasks/dynflow/console_authorizer.rb +4 -5
- data/lib/foreman_tasks/dynflow/daemon.rb +17 -19
- data/lib/foreman_tasks/dynflow/persistence.rb +5 -8
- data/lib/foreman_tasks/engine.rb +30 -31
- data/lib/foreman_tasks/task_error.rb +1 -3
- data/lib/foreman_tasks/tasks/cleanup.rake +7 -19
- data/lib/foreman_tasks/tasks/dynflow.rake +1 -1
- data/lib/foreman_tasks/tasks/export_tasks.rake +51 -59
- data/lib/foreman_tasks/test_extensions.rb +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/tasks/gettext.rake +10 -7
- data/locale/action_names.rb +3 -6
- data/locale/en/foreman_tasks.po +189 -177
- data/locale/foreman_tasks.pot +177 -137
- data/test/controllers/api/recurring_logics_controller_test.rb +3 -5
- data/test/controllers/api/tasks_controller_test.rb +5 -7
- data/test/factories/task_factory.rb +8 -8
- data/test/factories/triggering_factory.rb +2 -3
- data/test/helpers/foreman_tasks/tasks_helper_test.rb +11 -11
- data/test/support/dummy_proxy_action.rb +3 -4
- data/test/unit/actions/action_with_sub_plans_test.rb +5 -6
- data/test/unit/actions/proxy_action_test.rb +5 -8
- data/test/unit/cleaner_test.rb +11 -12
- data/test/unit/dynflow_console_authorizer_test.rb +4 -4
- data/test/unit/proxy_selector_test.rb +3 -3
- data/test/unit/recurring_logic_test.rb +19 -17
- data/test/unit/task_groups_test.rb +3 -4
- data/test/unit/task_test.rb +72 -5
- data/test/unit/triggering_test.rb +0 -1
- metadata +7 -6
- data/app/controllers/foreman_tasks/concerns/environments_extension.rb +0 -24
@@ -5,7 +5,7 @@ module ForemanTasks
|
|
5
5
|
include ForemanTasks::Concerns::ActionSubject
|
6
6
|
|
7
7
|
def action_input_key
|
8
|
-
|
8
|
+
'host'
|
9
9
|
end
|
10
10
|
|
11
11
|
def available_locks
|
@@ -16,15 +16,15 @@ module ForemanTasks
|
|
16
16
|
# TODO: This should get into the Foreman core, extracting the
|
17
17
|
# +importHostAndFacts+ method into two
|
18
18
|
def import_host(hostname, certname, facts, proxy_id = nil)
|
19
|
-
raise
|
20
|
-
raise
|
19
|
+
raise Foreman::Exception, 'Invalid Facts, must be a Hash' unless facts.is_a?(Hash)
|
20
|
+
raise Foreman::Exception, 'Invalid Hostname, must be a String' unless hostname.is_a?(String)
|
21
21
|
|
22
22
|
# downcase everything
|
23
23
|
hostname.try(:downcase!)
|
24
24
|
certname.try(:downcase!)
|
25
25
|
|
26
|
-
host = certname.present? ? Host.
|
27
|
-
host ||= Host.
|
26
|
+
host = certname.present? ? Host.find_by(certname: certname) : nil
|
27
|
+
host ||= Host.find_by name: hostname
|
28
28
|
host ||= Host.new(:name => hostname, :certname => certname) if Setting[:create_new_host_when_facts_are_uploaded]
|
29
29
|
|
30
30
|
return Host.new if host.nil?
|
@@ -1,32 +1,31 @@
|
|
1
1
|
module ForemanTasks
|
2
2
|
class Lock < ActiveRecord::Base
|
3
|
-
|
4
3
|
LINK_LOCK_NAME = :link_resource
|
5
4
|
OWNER_LOCK_NAME = :task_owner
|
6
5
|
|
7
|
-
# not really
|
6
|
+
# not really intended to be created in database, but it's used for
|
8
7
|
# explicitly stating that the all the locks for resource should be used
|
9
8
|
ALL_LOCK_NAME = :all
|
10
9
|
|
11
|
-
RESERVED_LOCK_NAMES = [LINK_LOCK_NAME, OWNER_LOCK_NAME, ALL_LOCK_NAME]
|
10
|
+
RESERVED_LOCK_NAMES = [LINK_LOCK_NAME, OWNER_LOCK_NAME, ALL_LOCK_NAME].freeze
|
12
11
|
|
13
12
|
class LockConflict < StandardError
|
14
13
|
attr_reader :required_lock, :conflicting_locks
|
15
14
|
def initialize(required_lock, conflicting_locks)
|
16
|
-
header = _(
|
15
|
+
header = _('Required lock is already taken by other running tasks.')
|
17
16
|
header << "\n"
|
18
|
-
header << _(
|
17
|
+
header << _('Please inspect their state, fix their errors and resume them.')
|
19
18
|
header << "\n\n"
|
20
|
-
header << _(
|
19
|
+
header << _('Required lock: %s') % required_lock.name
|
21
20
|
header << "\n"
|
22
|
-
header << _(
|
21
|
+
header << _('Conflicts with tasks:')
|
23
22
|
header << "\n"
|
24
23
|
url_helpers = Rails.application.routes.url_helpers
|
25
|
-
conflicting_tasks = conflicting_locks
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
conflicting_tasks = conflicting_locks
|
25
|
+
.map(&:task)
|
26
|
+
.uniq
|
27
|
+
.map { |task| "- #{Setting['foreman_url'] + url_helpers.foreman_tasks_task_path(task)}" }
|
28
|
+
.join("\n")
|
30
29
|
|
31
30
|
super header + conflicting_tasks
|
32
31
|
@required_lock = required_lock
|
@@ -38,21 +37,17 @@ module ForemanTasks
|
|
38
37
|
|
39
38
|
belongs_to :resource, polymorphic: true
|
40
39
|
|
41
|
-
scope :active, ->
|
42
|
-
joins(:task).where('foreman_tasks_tasks.state != ?', :stopped)
|
43
|
-
end
|
40
|
+
scope :active, -> { joins(:task).where('foreman_tasks_tasks.state != ?', :stopped) }
|
44
41
|
|
45
42
|
validates :task_id, :name, :resource_id, :resource_type, presence: true
|
46
43
|
|
47
44
|
validate do
|
48
|
-
unless available?
|
49
|
-
raise LockConflict.new(self, colliding_locks)
|
50
|
-
end
|
45
|
+
raise LockConflict.new(self, colliding_locks) unless available?
|
51
46
|
end
|
52
47
|
|
53
48
|
# returns true if it's possible to aquire this kind of lock
|
54
49
|
def available?
|
55
|
-
|
50
|
+
!colliding_locks.exists?
|
56
51
|
end
|
57
52
|
|
58
53
|
# returns a scope of the locks colliding with this one
|
@@ -62,14 +57,13 @@ module ForemanTasks
|
|
62
57
|
colliding_locks_scope = colliding_locks_scope.where(name: name,
|
63
58
|
resource_id: resource_id,
|
64
59
|
resource_type: resource_type)
|
65
|
-
unless
|
60
|
+
unless exclusive?
|
66
61
|
colliding_locks_scope = colliding_locks_scope.where(:exclusive => true)
|
67
62
|
end
|
68
|
-
|
63
|
+
colliding_locks_scope
|
69
64
|
end
|
70
65
|
|
71
66
|
class << self
|
72
|
-
|
73
67
|
# Locks the resource so that no other task can lock it while running.
|
74
68
|
# No other task related to the resource is not allowed (even not-locking ones)
|
75
69
|
# A typical usecase is resource deletion, where it's good idea to make sure
|
@@ -82,7 +76,6 @@ module ForemanTasks
|
|
82
76
|
build_exclusive_locks(resource).all?(&:available?)
|
83
77
|
end
|
84
78
|
|
85
|
-
|
86
79
|
# Locks the resource so that no other task can lock it while running.
|
87
80
|
# Other not-locking tasks are tolerated.
|
88
81
|
#
|
@@ -103,12 +96,12 @@ module ForemanTasks
|
|
103
96
|
end
|
104
97
|
|
105
98
|
def locked?(resource, uuid, *lock_names)
|
106
|
-
|
99
|
+
!lockable?(resource, uuid, *lock_names)
|
107
100
|
end
|
108
101
|
|
109
102
|
def colliding_locks(resource, uuid, *lock_names)
|
110
|
-
build_locks(resource, lock_names, uuid)
|
111
|
-
|
103
|
+
build_locks(resource, lock_names, uuid)
|
104
|
+
.inject([]) { |collisions, lock| collisions.concat lock.colliding_locks.to_a }
|
112
105
|
end
|
113
106
|
|
114
107
|
# Assigns the resource to the task to easily track the task in context of
|
@@ -136,7 +129,7 @@ module ForemanTasks
|
|
136
129
|
def all_lock_names(resource, include_links = false)
|
137
130
|
lock_names = []
|
138
131
|
if resource.class.respond_to?(:available_locks) &&
|
139
|
-
|
132
|
+
resource.class.available_locks.any?
|
140
133
|
lock_names.concat(resource.class.available_locks)
|
141
134
|
else
|
142
135
|
raise "The resource #{resource.class.name} doesn't define any available lock"
|
@@ -145,7 +138,7 @@ module ForemanTasks
|
|
145
138
|
raise "Lock name #{lock_name} is reserved"
|
146
139
|
end
|
147
140
|
lock_names.concat([LINK_LOCK_NAME, OWNER_LOCK_NAME]) if include_links
|
148
|
-
|
141
|
+
lock_names
|
149
142
|
end
|
150
143
|
|
151
144
|
def build_exclusive_locks(resource, uuid = nil)
|
@@ -161,7 +154,7 @@ module ForemanTasks
|
|
161
154
|
locks << build(uuid, resource, lock_name, true)
|
162
155
|
end
|
163
156
|
locks.concat(build_links(resource, uuid))
|
164
|
-
|
157
|
+
locks
|
165
158
|
end
|
166
159
|
|
167
160
|
def build_links(resource, uuid = nil)
|
@@ -179,23 +172,22 @@ module ForemanTasks
|
|
179
172
|
end
|
180
173
|
|
181
174
|
def build(uuid, resource, lock_name, exclusive)
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
175
|
+
new(task_id: uuid,
|
176
|
+
name: lock_name,
|
177
|
+
resource_type: resource.class.name,
|
178
|
+
resource_id: resource.id,
|
179
|
+
exclusive: !!exclusive)
|
187
180
|
end
|
188
181
|
|
189
182
|
# recursively search for related resources of the resource (using
|
190
183
|
# the +related_resources+ method, avoiding the cycles
|
191
184
|
def related_resources(resource)
|
192
185
|
if resource.respond_to?(:all_related_resources)
|
193
|
-
|
186
|
+
resource.all_related_resources
|
194
187
|
else
|
195
|
-
|
188
|
+
[]
|
196
189
|
end
|
197
190
|
end
|
198
191
|
end
|
199
|
-
|
200
192
|
end
|
201
193
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module ForemanTasks
|
2
|
-
|
3
2
|
require 'parse-cron'
|
4
3
|
|
5
4
|
class RecurringLogic < ActiveRecord::Base
|
@@ -15,13 +14,13 @@ module ForemanTasks
|
|
15
14
|
has_many :task_groups, -> { uniq }, :through => :tasks
|
16
15
|
end
|
17
16
|
|
18
|
-
scoped_search :on => :id, :complete_value => false
|
17
|
+
scoped_search :on => :id, :complete_value => false, :validator => ScopedSearch::Validators::INTEGER
|
19
18
|
scoped_search :on => :max_iteration, :complete_value => false, :rename => :iteration_limit
|
20
19
|
scoped_search :on => :iteration, :complete_value => false
|
21
20
|
scoped_search :on => :cron_line, :complete_value => true
|
22
21
|
|
23
22
|
before_create do
|
24
|
-
|
23
|
+
task_group.save
|
25
24
|
end
|
26
25
|
|
27
26
|
def self.allowed_states
|
@@ -35,16 +34,16 @@ module ForemanTasks
|
|
35
34
|
end
|
36
35
|
|
37
36
|
def trigger_repeat(action_class, *args)
|
38
|
-
|
39
|
-
self.state = 'finished'
|
40
|
-
save!
|
41
|
-
return
|
42
|
-
else
|
37
|
+
if can_continue?
|
43
38
|
self.iteration += 1
|
44
39
|
save!
|
45
40
|
::ForemanTasks.delay action_class,
|
46
41
|
generate_delay_options,
|
47
42
|
*args
|
43
|
+
else
|
44
|
+
self.state = 'finished'
|
45
|
+
save!
|
46
|
+
nil
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
@@ -54,21 +53,21 @@ module ForemanTasks
|
|
54
53
|
tasks.active.each(&:cancel)
|
55
54
|
end
|
56
55
|
|
57
|
-
def next_occurrence_time(time = Time.now)
|
58
|
-
@parser ||= CronParser.new(cron_line)
|
56
|
+
def next_occurrence_time(time = Time.zone.now)
|
57
|
+
@parser ||= CronParser.new(cron_line, Time.zone)
|
59
58
|
@parser.next(time)
|
60
59
|
end
|
61
60
|
|
62
|
-
def generate_delay_options(time = Time.now, options = {})
|
61
|
+
def generate_delay_options(time = Time.zone.now, options = {})
|
63
62
|
{
|
64
63
|
:start_at => next_occurrence_time(time),
|
65
64
|
:start_before => options['start_before'],
|
66
|
-
:recurring_logic_id =>
|
65
|
+
:recurring_logic_id => id
|
67
66
|
}
|
68
67
|
end
|
69
68
|
|
70
69
|
def valid?(*_)
|
71
|
-
cron_line.present? && valid_cronline? && !
|
70
|
+
cron_line.present? && valid_cronline? && !state.nil? || can_start?
|
72
71
|
end
|
73
72
|
|
74
73
|
def valid_cronline?
|
@@ -77,21 +76,21 @@ module ForemanTasks
|
|
77
76
|
false
|
78
77
|
end
|
79
78
|
|
80
|
-
def can_start?(time = Time.now)
|
79
|
+
def can_start?(time = Time.zone.now)
|
81
80
|
(end_time.nil? || next_occurrence_time(time) < end_time) &&
|
82
81
|
(max_iteration.nil? || iteration < max_iteration)
|
83
82
|
end
|
84
83
|
|
85
|
-
def can_continue?(time = Time.now)
|
86
|
-
|
84
|
+
def can_continue?(time = Time.zone.now)
|
85
|
+
state == 'active' && can_start?(time)
|
87
86
|
end
|
88
87
|
|
89
88
|
def finished?
|
90
|
-
|
89
|
+
state == 'finished'
|
91
90
|
end
|
92
91
|
|
93
92
|
def humanized_state
|
94
|
-
case
|
93
|
+
case state
|
95
94
|
when 'active'
|
96
95
|
N_('Active')
|
97
96
|
when 'cancelled'
|
@@ -104,13 +103,13 @@ module ForemanTasks
|
|
104
103
|
end
|
105
104
|
|
106
105
|
def self.assemble_cronline(hash)
|
107
|
-
hash.values_at(
|
108
|
-
.map { |value|
|
106
|
+
hash.values_at(:minutes, :hours, :days, :months, :days_of_week)
|
107
|
+
.map { |value| value.nil? || value.blank? ? '*' : value }
|
109
108
|
.join(' ')
|
110
109
|
end
|
111
110
|
|
112
111
|
def self.new_from_cronline(cronline)
|
113
|
-
|
112
|
+
new.tap do |logic|
|
114
113
|
logic.cron_line = cronline
|
115
114
|
logic.task_group = ::ForemanTasks::TaskGroups::RecurringLogicTaskGroup.new
|
116
115
|
end
|
@@ -120,7 +119,7 @@ module ForemanTasks
|
|
120
119
|
cronline = if triggering.input_type == :cronline
|
121
120
|
triggering.cronline
|
122
121
|
else
|
123
|
-
::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash
|
122
|
+
::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash(triggering.input_type, triggering.time, triggering.days_of_week))
|
124
123
|
end
|
125
124
|
::ForemanTasks::RecurringLogic.new_from_cronline(cronline).tap do |manager|
|
126
125
|
manager.end_time = triggering.end_time unless triggering.end_time_limited.blank?
|
@@ -132,8 +131,8 @@ module ForemanTasks
|
|
132
131
|
def self.cronline_hash(recurring_type, time_hash, days_of_week_hash)
|
133
132
|
hash = Hash[[:years, :months, :days, :hours, :minutes].zip(time_hash.values)]
|
134
133
|
hash.update :days_of_week => days_of_week_hash
|
135
|
-
|
136
|
-
|
134
|
+
.select { |_key, value| value == '1' }
|
135
|
+
.keys.join(',')
|
137
136
|
allowed_keys = case recurring_type
|
138
137
|
when :monthly
|
139
138
|
[:minutes, :hours, :days]
|
@@ -4,7 +4,7 @@ module ForemanTasks
|
|
4
4
|
class Task < ActiveRecord::Base
|
5
5
|
include Authorizable
|
6
6
|
|
7
|
-
# TODO missing validation of states
|
7
|
+
# TODO: missing validation of states
|
8
8
|
|
9
9
|
self.primary_key = :id
|
10
10
|
before_create :generate_id
|
@@ -18,17 +18,16 @@ module ForemanTasks
|
|
18
18
|
if Rails::VERSION::MAJOR < 4
|
19
19
|
has_many :recurring_logic_task_groups, :through => :task_group_members, :conditions => { :type => 'ForemanTasks::TaskGroups::RecurringLogicTaskGroup' }, :source => :task_group
|
20
20
|
has_many :owners, :through => :locks, :source => :resource, :source_type => 'User',
|
21
|
-
|
21
|
+
:conditions => ['foreman_tasks_locks.name = ?', Lock::OWNER_LOCK_NAME]
|
22
22
|
else
|
23
23
|
has_many :recurring_logic_task_groups, -> { where :type => 'ForemanTasks::TaskGroups::RecurringLogicTaskGroup' },
|
24
24
|
:through => :task_group_members, :source => :task_group
|
25
25
|
# in fact, the task has only one owner but Rails don't let you to
|
26
26
|
# specify has_one relation though has_many relation
|
27
|
-
has_many :owners,
|
27
|
+
has_many :owners, -> { where(['foreman_tasks_locks.name = ?', Lock::OWNER_LOCK_NAME]) },
|
28
28
|
:through => :locks, :source => :resource, :source_type => 'User'
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
31
|
scoped_search :on => :id, :complete_value => false
|
33
32
|
scoped_search :on => :label, :complete_value => true
|
34
33
|
scoped_search :on => :state, :complete_value => true
|
@@ -37,21 +36,26 @@ module ForemanTasks
|
|
37
36
|
scoped_search :on => :start_at, :complete_value => false
|
38
37
|
scoped_search :on => :ended_at, :complete_value => false
|
39
38
|
scoped_search :on => :parent_task_id, :complete_value => true
|
40
|
-
scoped_search :
|
41
|
-
scoped_search :
|
42
|
-
scoped_search :
|
43
|
-
|
44
|
-
|
45
|
-
|
39
|
+
scoped_search :relation => :locks, :on => :resource_type, :complete_value => true, :rename => 'resource_type', :ext_method => :search_by_generic_resource
|
40
|
+
scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'resource_id', :ext_method => :search_by_generic_resource
|
41
|
+
scoped_search :relation => :owners,
|
42
|
+
:on => :id,
|
43
|
+
:complete_value => true,
|
44
|
+
:rename => 'owner.id',
|
45
|
+
:ext_method => :search_by_owner,
|
46
|
+
:validator => ->(value) { ScopedSearch::Validators::INTEGER.call(value) || value == 'current_user' }
|
47
|
+
scoped_search :relation => :owners, :on => :login, :complete_value => true, :rename => 'owner.login', :ext_method => :search_by_owner
|
48
|
+
scoped_search :relation => :owners, :on => :firstname, :complete_value => true, :rename => 'owner.firstname', :ext_method => :search_by_owner
|
49
|
+
scoped_search :relation => :task_groups, :on => :id, :complete_value => true, :rename => 'task_group.id', :validator => ScopedSearch::Validators::INTEGER
|
46
50
|
|
47
51
|
scope :active, -> { where('foreman_tasks_tasks.state != ?', :stopped) }
|
48
|
-
scope :running, -> {
|
52
|
+
scope :running, -> { where("foreman_tasks_tasks.state NOT IN ('stopped', 'paused')") }
|
49
53
|
scope :for_resource,
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
scope :for_action_types, (
|
54
|
+
(lambda do |resource|
|
55
|
+
joins(:locks).where(:"foreman_tasks_locks.resource_id" => resource.id,
|
56
|
+
:"foreman_tasks_locks.resource_type" => resource.class.name)
|
57
|
+
end)
|
58
|
+
scope :for_action_types, (->(action_types) { where('foreman_tasks_tasks.label IN (?)', Array(action_types)) })
|
55
59
|
|
56
60
|
def input
|
57
61
|
{}
|
@@ -62,61 +66,67 @@ module ForemanTasks
|
|
62
66
|
end
|
63
67
|
|
64
68
|
def owner
|
65
|
-
|
69
|
+
owners.first
|
66
70
|
end
|
67
71
|
|
68
72
|
def username
|
69
|
-
|
73
|
+
owner.try(:login)
|
70
74
|
end
|
71
75
|
|
72
76
|
def execution_type
|
73
|
-
|
77
|
+
delayed? ? N_('Delayed') : N_('Immediate')
|
74
78
|
end
|
75
79
|
|
76
80
|
def humanized
|
77
81
|
{ action: label,
|
78
|
-
input:
|
79
|
-
output:
|
82
|
+
input: '',
|
83
|
+
output: '' }
|
80
84
|
end
|
81
85
|
|
82
86
|
def cli_example
|
83
|
-
|
87
|
+
''
|
84
88
|
end
|
85
89
|
|
86
90
|
# returns true if the task is running or waiting to be run
|
87
91
|
def pending?
|
88
|
-
|
92
|
+
state != 'stopped'
|
89
93
|
end
|
90
|
-
|
94
|
+
alias pending pending?
|
91
95
|
|
92
96
|
def resumable?
|
93
97
|
false
|
94
98
|
end
|
95
99
|
|
96
100
|
def paused?
|
97
|
-
|
101
|
+
state == 'paused'
|
102
|
+
end
|
103
|
+
|
104
|
+
def recurring?
|
105
|
+
!recurring_logic_task_group_ids.empty?
|
106
|
+
end
|
107
|
+
|
108
|
+
def delayed?
|
109
|
+
start_at.to_i != started_at.to_i
|
98
110
|
end
|
99
111
|
|
100
112
|
def self_and_parents
|
101
113
|
[self].tap do |ret|
|
102
|
-
if parent_task
|
103
|
-
ret.concat(parent_task.self_and_parents)
|
104
|
-
end
|
114
|
+
ret.concat(parent_task.self_and_parents) if parent_task
|
105
115
|
end
|
106
116
|
end
|
107
117
|
|
108
118
|
def self.search_by_generic_resource(key, operator, value)
|
109
|
-
key =
|
110
|
-
key_name =
|
119
|
+
key = 'resource_type' if key.blank?
|
120
|
+
key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
|
111
121
|
condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} ?", value])
|
112
122
|
|
113
|
-
|
123
|
+
{ :conditions => condition, :joins => :locks }
|
114
124
|
end
|
115
125
|
|
116
126
|
def self.search_by_owner(key, operator, value)
|
117
127
|
return { :conditions => '0 = 1' } if value == 'current_user' && User.current.nil?
|
118
128
|
|
119
|
-
key_name =
|
129
|
+
key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
|
120
130
|
joins = <<-SQL
|
121
131
|
INNER JOIN foreman_tasks_locks AS foreman_tasks_locks_owner
|
122
132
|
ON (foreman_tasks_locks_owner.task_id = foreman_tasks_tasks.id AND
|
@@ -132,21 +142,19 @@ module ForemanTasks
|
|
132
142
|
condition = if key.blank?
|
133
143
|
sanitize_sql_for_conditions(["users.login #{operator} ? or users.firstname #{operator} ? ", value, value])
|
134
144
|
elsif key =~ /\.id\Z/
|
135
|
-
if value == 'current_user'
|
136
|
-
value = User.current.id
|
137
|
-
end
|
145
|
+
value = User.current.id if value == 'current_user'
|
138
146
|
sanitize_sql_for_conditions(["foreman_tasks_locks_owner.resource_id #{operator} ?", value])
|
139
147
|
else
|
140
148
|
sanitize_sql_for_conditions(["users.#{key_name} #{operator} ?", value])
|
141
149
|
end
|
142
|
-
|
150
|
+
{ :conditions => condition, :joins => joins }
|
143
151
|
end
|
144
152
|
|
145
153
|
def progress
|
146
|
-
case
|
147
|
-
when
|
154
|
+
case state.to_s
|
155
|
+
when 'running', 'paused'
|
148
156
|
0.5
|
149
|
-
when
|
157
|
+
when 'stopped'
|
150
158
|
1
|
151
159
|
else
|
152
160
|
0
|
@@ -163,6 +171,24 @@ module ForemanTasks
|
|
163
171
|
(groups - task_groups).each { |group| task_groups << group }
|
164
172
|
end
|
165
173
|
|
174
|
+
def sub_tasks_counts
|
175
|
+
result = %w(cancelled error pending success warning).zip([0].cycle).to_h
|
176
|
+
result.update sub_tasks.group(:result).count
|
177
|
+
sum = result.values.reduce(:+)
|
178
|
+
if respond_to?(:main_action) && main_action.respond_to?(:total_count)
|
179
|
+
result[:total] = main_action.total_count
|
180
|
+
# In case of batch planning there might be some plans still unplanned (not present in database).
|
181
|
+
# To get correct counts we need to add them to either:
|
182
|
+
# cancelled when the parent is stopped
|
183
|
+
# pending when the parent is still running.
|
184
|
+
key = state == 'stopped' ? 'cancelled' : 'pending'
|
185
|
+
result[key] += result[:total] - sum
|
186
|
+
else
|
187
|
+
result[:total] = sum
|
188
|
+
end
|
189
|
+
result.symbolize_keys
|
190
|
+
end
|
191
|
+
|
166
192
|
protected
|
167
193
|
|
168
194
|
def generate_id
|