foreman-tasks 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|