foreman-tasks 0.6.13 → 0.6.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +93 -6
- data/app/controllers/foreman_tasks/tasks_controller.rb +6 -0
- data/app/lib/actions/bulk_action.rb +4 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +18 -0
- data/app/models/foreman_tasks/task/status_explicator.rb +17 -0
- data/app/models/foreman_tasks/task/summarizer.rb +13 -0
- data/app/models/setting/foreman_tasks.rb +1 -0
- data/app/views/foreman_tasks/tasks/_details.html.erb +24 -15
- data/app/views/foreman_tasks/tasks/_running_steps.html.erb +5 -1
- data/app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb +15 -0
- data/app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb +15 -0
- data/app/views/foreman_tasks/tasks/show.html.erb +16 -0
- data/config/routes.rb +6 -2
- data/lib/foreman_tasks.rb +1 -0
- data/lib/foreman_tasks/dynflow.rb +2 -0
- data/lib/foreman_tasks/engine.rb +8 -3
- data/lib/foreman_tasks/tasks/export_tasks.rake +247 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/foreman_tasks/widget_manager.rb +16 -0
- data/test/factories/task_factory.rb +9 -3
- data/test/unit/task_test.rb +17 -0
- metadata +56 -60
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njc1OWI4YzE5OWI1ZmNhMmI3YjIwMzc3NDRjZjVjMTViMzNjZjNhOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTMzODQyZWM1MDljMmNmZDcxMGM0OTc5MDExOTVjOGE3YWNhMmMyNg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
N2M3NTQzNzFiMGVlN2NiZDE5NTU2YmM1ZmYzMWU2YWQwYWRmYmFmNzUxZDMz
|
10
|
+
MDkzYzc3NmFkMjYwZGE3MjgzMTI4ZWZlMjM1NzU4NjkzY2Q4ODU3NTAxNDM5
|
11
|
+
MTZmY2Q4YzU3MWM5MjNmNGU3Mzg5NmI5NzdhZTgwOWQzNzk0NWQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YmUzZTYyNjUyOTFkZjFiZWVlZDJmNGFmMjEyNTYwYmJmM2IwMGViNGMzMWQ4
|
14
|
+
Y2VkMzM2YzdhNTg2YmYzNTk3NDNhODg1Yzk2ODU2ZmY5NDE2MjU2NjU3YjE1
|
15
|
+
YzUyYmU1OTZhZGYzYmJiZThmMzAwOWQ2NzUzMjEwYmQwNDNlYTI=
|
@@ -28,6 +28,11 @@ module ForemanTasks
|
|
28
28
|
|
29
29
|
before_filter :find_resource, :only => [:show]
|
30
30
|
|
31
|
+
api :GET, "/tasks/summary", "Show task summary"
|
32
|
+
def summary
|
33
|
+
render :json => ForemanTasks::Task::Summarizer.new.summarize_by_status
|
34
|
+
end
|
35
|
+
|
31
36
|
api :GET, "/tasks/:id", "Show task details"
|
32
37
|
param :id, :identifier, desc: "UUID of the task"
|
33
38
|
def show
|
@@ -76,6 +81,83 @@ module ForemanTasks
|
|
76
81
|
render :json => ret
|
77
82
|
end
|
78
83
|
|
84
|
+
api :POST, '/tasks/bulk_resume', N_('Resume all paused error tasks')
|
85
|
+
param :search, String, :desc => N_('Resume tasks matching search string')
|
86
|
+
param :task_ids, Array, :desc => N_('Resume specific tasks by id')
|
87
|
+
def bulk_resume
|
88
|
+
scope = resource_scope
|
89
|
+
scope = scope.search_for(params[:search]) if params[:search]
|
90
|
+
scope = scope.select('DISTINCT foreman_tasks_tasks.*')
|
91
|
+
if params[:search].nil? && params[:task_ids].nil?
|
92
|
+
scope = scope.where(:state => :paused)
|
93
|
+
scope = scope.where(:result => :error)
|
94
|
+
end
|
95
|
+
scope = scope.where(:id => params[:task_ids]) if params[:task_ids]
|
96
|
+
|
97
|
+
resumed = []
|
98
|
+
failed = []
|
99
|
+
skipped = []
|
100
|
+
scope.each do |task|
|
101
|
+
if task.resumable?
|
102
|
+
begin
|
103
|
+
ForemanTasks.dynflow.world.execute(task.execution_plan.id)
|
104
|
+
resumed << task_hash(task)
|
105
|
+
rescue RuntimeError => e
|
106
|
+
failed << task_hash(task)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
skipped << task_hash(task)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
render :json => {
|
114
|
+
total: resumed.length + failed.length + skipped.length,
|
115
|
+
resumed: resumed,
|
116
|
+
failed: failed,
|
117
|
+
skipped: skipped
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
api :GET, '/tasks', N_("List tasks")
|
122
|
+
param :search, String, :desc => N_("Search string")
|
123
|
+
param :page, :number, :desc => N_("Page number, starting at 1")
|
124
|
+
param :per_page, :number, :desc => N_("Number of results per page to return")
|
125
|
+
param :order, String, :desc => N_("Sort field and order, eg. 'name DESC'")
|
126
|
+
param :sort, Hash, :desc => N_("Hash version of 'order' param") do
|
127
|
+
param :by, String, :desc => N_("Field to sort the results on")
|
128
|
+
param :order, String, :desc => N_("How to order the sorted results (e.g. ASC for ascending)")
|
129
|
+
end
|
130
|
+
def index
|
131
|
+
scope =resource_scope.search_for(params[:search]).select('DISTINCT foreman_tasks_tasks.*')
|
132
|
+
total = scope.count
|
133
|
+
|
134
|
+
ordering_params = {
|
135
|
+
sort_by: params[:sort_by] || 'started_at',
|
136
|
+
sort_order: params[:sort_order] || 'DESC'
|
137
|
+
}
|
138
|
+
scope = ordering_scope(scope, ordering_params)
|
139
|
+
|
140
|
+
|
141
|
+
pagination_params = {
|
142
|
+
page: params[:page] || 1,
|
143
|
+
per_page: params[:per_page] || 20
|
144
|
+
}
|
145
|
+
scope = pagination_scope(scope, pagination_params)
|
146
|
+
results = scope.map { |task| task_hash(task) }
|
147
|
+
|
148
|
+
render :json => {
|
149
|
+
total: total,
|
150
|
+
subtotal: results.count,
|
151
|
+
page: pagination_params[:page],
|
152
|
+
per_page: pagination_params[:per_page],
|
153
|
+
sort: {
|
154
|
+
by: ordering_params[:sort_by],
|
155
|
+
order: ordering_params[:sort_order]
|
156
|
+
},
|
157
|
+
results: results
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
79
161
|
private
|
80
162
|
|
81
163
|
def search_tasks(search_params)
|
@@ -127,7 +209,8 @@ module ForemanTasks
|
|
127
209
|
end
|
128
210
|
|
129
211
|
def action_types_scope(scope, search_params)
|
130
|
-
|
212
|
+
action_types = search_params[:action_types]
|
213
|
+
if action_types
|
131
214
|
scope.for_action_types(action_types)
|
132
215
|
else
|
133
216
|
scope
|
@@ -137,21 +220,23 @@ module ForemanTasks
|
|
137
220
|
def pagination_scope(scope, search_params)
|
138
221
|
page = search_params[:page] || 1
|
139
222
|
per_page = search_params[:per_page] || 10
|
140
|
-
scope = scope.limit(per_page).offset((page - 1) * per_page)
|
223
|
+
scope = scope.limit(per_page).offset((page.to_i - 1) * per_page.to_i)
|
141
224
|
end
|
142
225
|
|
143
|
-
def ordering_scope(scope,
|
144
|
-
|
226
|
+
def ordering_scope(scope, ordering_params)
|
227
|
+
sort_by = ordering_params[:sort_by] || 'started_at'
|
228
|
+
sort_order = ordering_params[:sort_order] || 'DESC'
|
229
|
+
scope.order("#{sort_by} #{sort_order}")
|
145
230
|
end
|
146
231
|
|
147
232
|
def task_hash(task)
|
148
|
-
return @tasks[task.id] if @tasks[task.id]
|
233
|
+
return @tasks[task.id] if @tasks && @tasks[task.id]
|
149
234
|
task_hash = Rabl.render(
|
150
235
|
task, 'show',
|
151
236
|
view_path: "#{ForemanTasks::Engine.root}/app/views/foreman_tasks/api/tasks",
|
152
237
|
format: :hash,
|
153
238
|
scope: self)
|
154
|
-
@tasks[task.id] = task_hash
|
239
|
+
@tasks[task.id] = task_hash if @tasks
|
155
240
|
return task_hash
|
156
241
|
end
|
157
242
|
|
@@ -165,6 +250,8 @@ module ForemanTasks
|
|
165
250
|
case params[:action]
|
166
251
|
when 'bulk_search'
|
167
252
|
:view
|
253
|
+
when 'bulk_resume'
|
254
|
+
:edit
|
168
255
|
else
|
169
256
|
super
|
170
257
|
end
|
@@ -2,6 +2,8 @@ module ForemanTasks
|
|
2
2
|
class TasksController < ::ApplicationController
|
3
3
|
include Foreman::Controller::AutoCompleteSearch
|
4
4
|
|
5
|
+
before_filter :restrict_dangerous_actions, :only => [:unlock, :force_unlock]
|
6
|
+
|
5
7
|
def show
|
6
8
|
@task = find_resource
|
7
9
|
end
|
@@ -62,6 +64,10 @@ module ForemanTasks
|
|
62
64
|
|
63
65
|
private
|
64
66
|
|
67
|
+
def restrict_dangerous_actions
|
68
|
+
render_403 unless Setting['dynflow_allow_dangerous_actions']
|
69
|
+
end
|
70
|
+
|
65
71
|
def controller_permission
|
66
72
|
'foreman_tasks'
|
67
73
|
end
|
@@ -17,7 +17,9 @@ module ForemanTasks
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
self.label ||= main_action.class.name
|
20
|
+
changes = self.changes
|
20
21
|
self.save!
|
22
|
+
return changes
|
21
23
|
end
|
22
24
|
|
23
25
|
def resumable?
|
@@ -80,5 +82,21 @@ module ForemanTasks
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
85
|
+
|
86
|
+
def self.consistency_check
|
87
|
+
fixed_count = 0
|
88
|
+
self.running.each do |task|
|
89
|
+
begin
|
90
|
+
changes = task.update_from_dynflow(task.execution_plan.to_hash)
|
91
|
+
unless changes.empty?
|
92
|
+
fixed_count += 1
|
93
|
+
Rails.logger.warn("Task %s updated at consistency check: %s" % [task.id, changes.inspect])
|
94
|
+
end
|
95
|
+
rescue => e
|
96
|
+
Rails.logger.warn("Failed at consistency check for task %s: %s\n %s" % [task.id, e.message, e.backtrace.join("\n")])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return fixed_count
|
100
|
+
end
|
83
101
|
end
|
84
102
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
class Task::StatusExplicator
|
3
|
+
ANY = 1
|
4
|
+
ERRONEOUS_STATUSES = [
|
5
|
+
{ :state => 'paused', :result => ANY },
|
6
|
+
{ :state => ANY, :result => 'error'},
|
7
|
+
{ :state => ANY, :result => 'warning'}
|
8
|
+
]
|
9
|
+
def is_erroneous(task)
|
10
|
+
remainder = ERRONEOUS_STATUSES.select do |status|
|
11
|
+
(status[:state] == ANY || status[:state] == task.state) &&
|
12
|
+
(status[:result] == ANY || status[:result] == task.result)
|
13
|
+
end
|
14
|
+
!remainder.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
class Task::Summarizer
|
3
|
+
def summarize_by_status(since=nil)
|
4
|
+
result = ::ForemanTasks::Task.select('count(state), state, result').group(:state, :result).order(:state)
|
5
|
+
result.where('started_at > ?', since) if since
|
6
|
+
result
|
7
|
+
end
|
8
|
+
|
9
|
+
def latest_tasks_in_errors_warning(limit=5)
|
10
|
+
::ForemanTasks::Task.where('result in (?)', ['error', 'warning']).order('started_at DESC').limit(limit)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -6,6 +6,7 @@ class Setting::ForemanTasks < Setting
|
|
6
6
|
|
7
7
|
self.transaction do
|
8
8
|
[
|
9
|
+
self.set('dynflow_allow_dangerous_actions', N_("Allow unlocking actions which can have dangerous consequences."), false),
|
9
10
|
self.set('dynflow_enable_console', N_("Enable the dynflow console (/foreman_tasks/dynflow) for debugging"), true),
|
10
11
|
self.set('dynflow_console_require_auth', N_("Require user to be authenticated as user with admin rights when accessing dynflow console"), true)
|
11
12
|
].each { |s| self.create! s.update(:category => "Setting::ForemanTasks")}
|
@@ -9,18 +9,19 @@
|
|
9
9
|
resume_foreman_tasks_task_path(@task),
|
10
10
|
class: ['btn', 'btn-sm', 'btn-primary', ('disabled' unless @task.resumable?)].compact,
|
11
11
|
method: :post) %>
|
12
|
+
<% if Setting['dynflow_allow_dangerous_actions'] %>
|
13
|
+
<%= link_to(_('Unlock'),
|
14
|
+
'',
|
15
|
+
class: ['btn', 'btn-sm', 'btn-warning', 'reload-button-stop', ('disabled' unless @task.state == 'paused')].compact,
|
16
|
+
:'data-toggle' => "modal",
|
17
|
+
:'data-target' => "#unlock_modal") %>
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
<%= link_to(_('Force Unlock'),
|
20
|
-
'',
|
21
|
-
class: ['btn', 'btn-sm', 'btn-danger', 'reload-button-stop', ('disabled' if @task.state == 'stopped')].compact,
|
22
|
-
:'data-toggle' => "modal",
|
23
|
-
:'data-target' => "#force_unlock_modal") %>
|
19
|
+
<%= link_to(_('Force Unlock'),
|
20
|
+
'',
|
21
|
+
class: ['btn', 'btn-sm', 'btn-danger', 'reload-button-stop', ('disabled' if @task.state == 'stopped')].compact,
|
22
|
+
:'data-toggle' => "modal",
|
23
|
+
:'data-target' => "#force_unlock_modal") %>
|
24
|
+
<% end %>
|
24
25
|
<% end %>
|
25
26
|
</p>
|
26
27
|
|
@@ -35,11 +36,15 @@
|
|
35
36
|
</h2>
|
36
37
|
</div>
|
37
38
|
<div class="modal-body">
|
38
|
-
<%= _("This will unlock the resources that the task is running against. Please note that this might lead to inconsistent state and should be used with caution, after making sure that the task can't be resumed") %>
|
39
|
+
<%= _("This will unlock the resources that the task is running against. Please note that this might lead to inconsistent state and should be used with caution, after making sure that the task can't be resumed.") %>
|
40
|
+
<div>
|
41
|
+
<input class="disable-unlock" type="checkbox"/>
|
42
|
+
<%= _("I understand that this may cause harm and have working database backups of all backend services.") %>
|
43
|
+
</div>
|
39
44
|
</div>
|
40
45
|
<div class="modal-footer">
|
41
46
|
<button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
|
42
|
-
<%= link_to(_("Unlock"), unlock_foreman_tasks_task_path(@task), method: :post, class: 'btn btn-warning') %>
|
47
|
+
<%= link_to(_("Unlock"), unlock_foreman_tasks_task_path(@task), method: :post, class: 'btn btn-warning modal-submit disabled') %>
|
43
48
|
</div>
|
44
49
|
</div>
|
45
50
|
</div>
|
@@ -57,10 +62,14 @@
|
|
57
62
|
</div>
|
58
63
|
<div class="modal-body">
|
59
64
|
<%= _("Resources will be unlocked and will not prevent other tasks from being run. As the task might be still running, it should be avoided to use this unless you are really sure the task got stuck") %>
|
65
|
+
<div>
|
66
|
+
<input class="disable-unlock" type="checkbox"/>
|
67
|
+
<%= _("I understand that this may cause harm and have working database backups of all backend services.") %>
|
68
|
+
</div>
|
60
69
|
</div>
|
61
70
|
<div class="modal-footer">
|
62
71
|
<button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
|
63
|
-
<%= link_to(_("Force Unlock"), force_unlock_foreman_tasks_task_path(@task), method: :post, class: 'btn btn-danger') %>
|
72
|
+
<%= link_to(_("Force Unlock"), force_unlock_foreman_tasks_task_path(@task), method: :post, class: 'btn btn-danger modal-submit disabled') %>
|
64
73
|
</div>
|
65
74
|
</div>
|
66
75
|
</div>
|
@@ -162,4 +171,4 @@
|
|
162
171
|
<pre><%= @task.humanized[:errors].join("\n") %></pre>
|
163
172
|
</span>
|
164
173
|
</div>
|
165
|
-
<% end %>
|
174
|
+
<% end %>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<%= _("No running steps") %>
|
6
6
|
<% else %>
|
7
7
|
<% running_steps.each do |step| %>
|
8
|
-
<% action =
|
8
|
+
<% action = ForemanTasks.dynflow.world.persistence.load_action(step) %>
|
9
9
|
<div class="alert alert-warning">
|
10
10
|
<p>
|
11
11
|
<% if @task.cancellable_action?(action) %>
|
@@ -20,6 +20,10 @@
|
|
20
20
|
<span class="param-value">
|
21
21
|
<pre><%= action.class %></pre>
|
22
22
|
</span>
|
23
|
+
<p>
|
24
|
+
<span class="param-name"><%= _("State") %>:</span>
|
25
|
+
<span class="param-value"><%= action.humanized_state %></span>
|
26
|
+
</p>
|
23
27
|
<span class="param-name"><%= _("Input") %>:</span>
|
24
28
|
<span class="param-value">
|
25
29
|
<pre><%= action.input.pretty_inspect %></pre>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h4><%= link_to _("Latest Warning/Error Tasks "), foreman_tasks_tasks_path(:order=>'started_at DESC') %></h4>
|
2
|
+
<table class="table table-striped">
|
3
|
+
<tr>
|
4
|
+
<th><%= _("Name") %></th>
|
5
|
+
<th><%= _("State") %></th>
|
6
|
+
<th><%= _("Result") %></th>
|
7
|
+
</tr>
|
8
|
+
<% ForemanTasks::Task::Summarizer.new.latest_tasks_in_errors_warning.each do |task| %>
|
9
|
+
<tr class="<%= ForemanTasks::Task::StatusExplicator.new.is_erroneous(task) ? 'text-danger' : '' %>">
|
10
|
+
<td><%= link_to task.humanized[:action], defined?(main_app) ? main_app.foreman_tasks_task_path(task.id) : foreman_tasks_task_path(task.id) %></td>
|
11
|
+
<td><%= task.state %></td>
|
12
|
+
<td><%= task.result %></td>
|
13
|
+
</tr>
|
14
|
+
<% end %>
|
15
|
+
</table>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h4 class="header"><%=_("Task Status")%></h4>
|
2
|
+
<table class="table table-striped">
|
3
|
+
<tr>
|
4
|
+
<th><%= _("State") %></th>
|
5
|
+
<th><%= _("Result") %></th>
|
6
|
+
<th><%= _("No. of Tasks") %></th>
|
7
|
+
</tr>
|
8
|
+
<% ForemanTasks::Task::Summarizer.new.summarize_by_status.each do |result| %>
|
9
|
+
<tr class="<%= ForemanTasks::Task::StatusExplicator.new.is_erroneous(result) ? 'text-danger' : '' %>">
|
10
|
+
<td><%= result.state %></td>
|
11
|
+
<td><%= result.result %></td>
|
12
|
+
<td><%= link_to result.count, main_app.foreman_tasks_tasks_path(:search => "state=#{result.state}&result=#{result.result}") %></td>
|
13
|
+
</tr>
|
14
|
+
<% end %>
|
15
|
+
</table>
|
@@ -41,6 +41,22 @@
|
|
41
41
|
};
|
42
42
|
|
43
43
|
$(document).ready(function () {
|
44
|
+
$('.modal-submit').click(function(e){
|
45
|
+
if($(this).hasClass('disabled')){
|
46
|
+
e.preventDefault();
|
47
|
+
}
|
48
|
+
});
|
49
|
+
$('.disable-unlock').click(function() {
|
50
|
+
var button = $(this).parents('.modal').find('.modal-submit');
|
51
|
+
|
52
|
+
if($(this).is(':checked')){
|
53
|
+
button.removeClass('disabled')
|
54
|
+
}
|
55
|
+
else{
|
56
|
+
button.addClass('disabled')
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
44
60
|
$('.reload-button').click(function (event) {
|
45
61
|
taskProgressReloader.toggle();
|
46
62
|
event.preventDefault();
|
data/config/routes.rb
CHANGED
@@ -14,8 +14,12 @@ Foreman::Application.routes.draw do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
namespace :api do
|
17
|
-
resources :tasks, :only => [:show] do
|
18
|
-
|
17
|
+
resources :tasks, :only => [:show, :index] do
|
18
|
+
collection do
|
19
|
+
post :bulk_search
|
20
|
+
post :bulk_resume
|
21
|
+
get :summary
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
data/lib/foreman_tasks.rb
CHANGED
data/lib/foreman_tasks/engine.rb
CHANGED
@@ -17,8 +17,9 @@ module ForemanTasks
|
|
17
17
|
|
18
18
|
security_block :foreman_tasks do |map|
|
19
19
|
permission :view_foreman_tasks, {:'foreman_tasks/tasks' => [:auto_complete_search, :sub_tasks, :index, :show],
|
20
|
-
:'foreman_tasks/api/tasks' => [:bulk_search, :show] }, :resource_type => ForemanTasks::Task.name
|
21
|
-
permission :edit_foreman_tasks, {:'foreman_tasks/tasks' => [:resume, :unlock, :force_unlock, :cancel_step]
|
20
|
+
:'foreman_tasks/api/tasks' => [:bulk_search, :show, :index, :summary] }, :resource_type => ForemanTasks::Task.name
|
21
|
+
permission :edit_foreman_tasks, {:'foreman_tasks/tasks' => [:resume, :unlock, :force_unlock, :cancel_step],
|
22
|
+
:'foreman_tasks/api/tasks' => [:bulk_resume]}, :resource_type => ForemanTasks::Task.name
|
22
23
|
end
|
23
24
|
|
24
25
|
role "Tasks Manager", [:view_foreman_tasks, :edit_foreman_tasks]
|
@@ -79,6 +80,10 @@ module ForemanTasks
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
83
|
+
initializer "foreman_tasks.initialize_dynflow", :after => 'foreman_tasks.initializer' do
|
84
|
+
::ForemanTasks::WidgetManager.register_widgets
|
85
|
+
end
|
86
|
+
|
82
87
|
config.to_prepare do
|
83
88
|
ForemanTasks.dynflow.eager_load_actions!
|
84
89
|
|
@@ -87,7 +92,7 @@ module ForemanTasks
|
|
87
92
|
|
88
93
|
|
89
94
|
rake_tasks do
|
90
|
-
%w[dynflow.rake test.rake].each do |rake_file|
|
95
|
+
%w[dynflow.rake test.rake export_tasks.rake].each do |rake_file|
|
91
96
|
full_path = File.expand_path("../tasks/#{rake_file}", __FILE__)
|
92
97
|
load full_path if File.exists?(full_path)
|
93
98
|
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
#
|
2
|
+
# export_tasks.rake is a debugging tool to extract tasks from the
|
3
|
+
# current foreman instance.
|
4
|
+
#
|
5
|
+
# Run "foreman-rake export_tasks" to export tasks whcih are not listed
|
6
|
+
# as successful.
|
7
|
+
# To export all tasks "foreman-rake export_tasks tasks=all"
|
8
|
+
# to specify the number of days of tasks to gather: days=60 (defaults to 60)
|
9
|
+
|
10
|
+
namespace :foreman_tasks do
|
11
|
+
desc 'Export Dynflow Tasks'
|
12
|
+
|
13
|
+
task :export_tasks => :environment do
|
14
|
+
|
15
|
+
class TaskRender
|
16
|
+
def initialize
|
17
|
+
@cache = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def h(foo)
|
21
|
+
foo
|
22
|
+
end
|
23
|
+
|
24
|
+
def url(foo)
|
25
|
+
foo
|
26
|
+
end
|
27
|
+
|
28
|
+
def render_task(task)
|
29
|
+
@plan = task.execution_plan
|
30
|
+
erb('show', {})
|
31
|
+
end
|
32
|
+
|
33
|
+
def world
|
34
|
+
ForemanTasks.dynflow.world
|
35
|
+
end
|
36
|
+
|
37
|
+
def template(filename)
|
38
|
+
File.join(Gem::Specification.find_by_name("dynflow").gem_dir, 'web', 'views', "#{filename}.erb")
|
39
|
+
end
|
40
|
+
|
41
|
+
def erb(file, options)
|
42
|
+
unless @cache[file]
|
43
|
+
@cache[file] = Tilt.new(template(file))
|
44
|
+
end
|
45
|
+
@cache[file].render(self, options[:locals])
|
46
|
+
end
|
47
|
+
|
48
|
+
def prettify_value(value)
|
49
|
+
YAML.dump(value)
|
50
|
+
end
|
51
|
+
|
52
|
+
def prettyprint(value)
|
53
|
+
value = prettyprint_references(value)
|
54
|
+
if value
|
55
|
+
pretty_value = prettify_value(value)
|
56
|
+
<<-HTML
|
57
|
+
<pre class="prettyprint lang-yaml">#{h(pretty_value)}</pre>
|
58
|
+
HTML
|
59
|
+
else
|
60
|
+
""
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def prettyprint_references(value)
|
65
|
+
case value
|
66
|
+
when Hash
|
67
|
+
value.reduce({}) do |h, (key, val)|
|
68
|
+
h.update(key => prettyprint_references(val))
|
69
|
+
end
|
70
|
+
when Array
|
71
|
+
value.map { |val| prettyprint_references(val) }
|
72
|
+
when Dynflow::ExecutionPlan::OutputReference
|
73
|
+
value.inspect
|
74
|
+
else
|
75
|
+
value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def duration_to_s(duration)
|
80
|
+
h("%0.2fs" % duration)
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_action(step)
|
84
|
+
world.persistence.load_action(step)
|
85
|
+
end
|
86
|
+
|
87
|
+
def step_error(step)
|
88
|
+
if step.error
|
89
|
+
['<pre>',
|
90
|
+
"#{h(step.error.message)} (#{h(step.error.exception_class)})\n",
|
91
|
+
h(step.error.backtrace.join("\n")),
|
92
|
+
'</pre>'].join
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def show_action_data(label, value)
|
97
|
+
value_html = prettyprint(value)
|
98
|
+
if !value_html.empty?
|
99
|
+
<<-HTML
|
100
|
+
<p>
|
101
|
+
<b>#{h(label)}</b>
|
102
|
+
#{value_html}
|
103
|
+
</p>
|
104
|
+
HTML
|
105
|
+
else
|
106
|
+
""
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def atom_css_classes(atom)
|
111
|
+
classes = ["atom"]
|
112
|
+
step = @plan.steps[atom.step_id]
|
113
|
+
case step.state
|
114
|
+
when :success
|
115
|
+
classes << "success"
|
116
|
+
when :error
|
117
|
+
classes << "error"
|
118
|
+
when :skipped, :skipping
|
119
|
+
classes << "skipped"
|
120
|
+
end
|
121
|
+
return classes.join(" ")
|
122
|
+
end
|
123
|
+
|
124
|
+
def flow_css_classes(flow, sub_flow = nil)
|
125
|
+
classes = []
|
126
|
+
case flow
|
127
|
+
when Dynflow::Flows::Sequence
|
128
|
+
classes << "sequence"
|
129
|
+
when Dynflow::Flows::Concurrence
|
130
|
+
classes << "concurrence"
|
131
|
+
when Dynflow::Flows::Atom
|
132
|
+
classes << atom_css_classes(flow)
|
133
|
+
else
|
134
|
+
raise "Unknown run plan #{run_plan.inspect}"
|
135
|
+
end
|
136
|
+
classes << atom_css_classes(sub_flow) if sub_flow.is_a? Dynflow::Flows::Atom
|
137
|
+
return classes.join(" ")
|
138
|
+
end
|
139
|
+
|
140
|
+
def step_css_class(step)
|
141
|
+
case step.state
|
142
|
+
when :success
|
143
|
+
"success"
|
144
|
+
when :error
|
145
|
+
"important"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def progress_width(step)
|
150
|
+
if step.state == :error
|
151
|
+
100 # we want to show the red bar in full width
|
152
|
+
else
|
153
|
+
step.progress_done * 100
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def step(step_id)
|
158
|
+
@plan.steps[step_id]
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
def updated_url(new_params)
|
163
|
+
url("?" + Rack::Utils.build_nested_query(params.merge(new_params.stringify_keys)))
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
class PageHelper
|
170
|
+
def self.pagify(template)
|
171
|
+
pre = <<-HTML
|
172
|
+
<html>
|
173
|
+
<head>
|
174
|
+
<title>Dynflow Console</title>
|
175
|
+
<script src="jquery.js"></script>
|
176
|
+
<link rel="stylesheet" type="text/css" href="bootstrap.css">
|
177
|
+
<link rel="stylesheet" type="text/css" href="application.css">
|
178
|
+
<script src="bootstrap.js"></script>
|
179
|
+
<script src="run_prettify.js"></script>
|
180
|
+
<script src="application.js"></script>
|
181
|
+
</head>
|
182
|
+
<body>
|
183
|
+
#{template}
|
184
|
+
<body>
|
185
|
+
</html>
|
186
|
+
HTML
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.copy_assets(tmp_dir)
|
190
|
+
['vendor/bootstrap/js/bootstrap.js',
|
191
|
+
'vendor/google-code-prettify/run_prettify.js',
|
192
|
+
'vendor/jquery/jquery.js',
|
193
|
+
'vendor/jquery/jquery.js',
|
194
|
+
'javascripts/application.js',
|
195
|
+
'vendor/bootstrap/css/bootstrap.css',
|
196
|
+
'stylesheets/application.css'].each do |file|
|
197
|
+
|
198
|
+
filename = File.join(Gem::Specification.find_by_name("dynflow").gem_dir, 'web', 'assets', file)
|
199
|
+
FileUtils.copy_file(filename, File.join(tmp_dir, File.basename(file)))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.generate_index(tasks)
|
204
|
+
html = "<div><table class=\"table\">"
|
205
|
+
tasks.order("started_at desc").all.each do |task|
|
206
|
+
html << "<tr><td><a href=\"#{task.id}.html\">#{task.label}</a></td><td>#{task.started_at}</td>\
|
207
|
+
<td>#{task.state}</td><td>#{task.result}</td></tr>"
|
208
|
+
end
|
209
|
+
html << "</table></div>"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
if ENV['tasks'] == 'all'
|
215
|
+
tasks = ForemanTasks::Task
|
216
|
+
else
|
217
|
+
tasks = ForemanTasks::Task.where("result != 'success'")
|
218
|
+
end
|
219
|
+
|
220
|
+
days = ENV['days'].try(:to_i) || 60
|
221
|
+
tasks = tasks.where('started_at > ?', days.days.ago)
|
222
|
+
export_filename = ENV['export'] || "/tmp/task-export-#{DateTime.now.to_i}.tar.gz"
|
223
|
+
|
224
|
+
puts _("Gathering last #{days} days of tasks.")
|
225
|
+
Dir.mktmpdir('task-export') do |tmp_dir|
|
226
|
+
PageHelper.copy_assets(tmp_dir)
|
227
|
+
|
228
|
+
|
229
|
+
renderer = TaskRender.new
|
230
|
+
count = 1
|
231
|
+
total = tasks.count
|
232
|
+
|
233
|
+
tasks.all.each do |task|
|
234
|
+
File.open(File.join(tmp_dir, "#{task.id}.html"), 'w') {|file| file.write(PageHelper.pagify(renderer.render_task(task)))}
|
235
|
+
puts "#{count}/#{total}"
|
236
|
+
count += 1
|
237
|
+
end
|
238
|
+
|
239
|
+
File.open(File.join(tmp_dir, "index.html"), 'w') {|file| file.write(PageHelper.pagify(PageHelper.generate_index(tasks)))}
|
240
|
+
|
241
|
+
sh("tar cvzf #{export_filename} #{tmp_dir} > /dev/null")
|
242
|
+
end
|
243
|
+
|
244
|
+
puts "Created #{export_filename}"
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
class WidgetManager
|
3
|
+
DEFAULT_WIDGETS = [
|
4
|
+
{:template=>'foreman_tasks/tasks/dashboard/tasks_status', :sizex=>6, :sizey=>1, :name=> N_('Tasks Status table')},
|
5
|
+
{:template=>'foreman_tasks/tasks/dashboard/latest_tasks_in_error_warning', :sizex=>6, :sizey=>1,:name=> N_('Tasks in Error/Warning')}
|
6
|
+
]
|
7
|
+
|
8
|
+
def self.register_widgets
|
9
|
+
if ForemanTasks.dynflow.required?
|
10
|
+
DEFAULT_WIDGETS.each do |widget|
|
11
|
+
Dashboard::Manager.register_default_widget(widget)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -23,10 +23,10 @@ FactoryGirl.define do
|
|
23
23
|
parent_task_id nil
|
24
24
|
|
25
25
|
after(:build) do |task|
|
26
|
-
|
26
|
+
execution_plan = ForemanTasks.dynflow.world.plan(Support::DummyDynflowAction)
|
27
27
|
# remove the task created automatically by the persistence
|
28
|
-
ForemanTasks::Task.where(:external_id =>
|
29
|
-
task.
|
28
|
+
ForemanTasks::Task.where(:external_id => execution_plan.id).delete_all
|
29
|
+
task.update_from_dynflow(execution_plan.to_hash)
|
30
30
|
end
|
31
31
|
|
32
32
|
trait :user_create_task do
|
@@ -36,6 +36,12 @@ FactoryGirl.define do
|
|
36
36
|
trait :product_create_task do
|
37
37
|
label "Actions::Katello::Product::Create"
|
38
38
|
end
|
39
|
+
|
40
|
+
trait :inconsistent_dynflow_task do
|
41
|
+
after(:build) do |task|
|
42
|
+
task.update_attributes!(:state => 'running')
|
43
|
+
end
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|
data/test/unit/task_test.rb
CHANGED
@@ -34,4 +34,21 @@ class TasksTest < ActiveSupport::TestCase
|
|
34
34
|
assert auth.can?(permission.name.to_sym, task)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
describe 'consistency check' do
|
39
|
+
|
40
|
+
let(:consistent_task) { FactoryGirl.create(:dynflow_task) }
|
41
|
+
let(:inconsistent_task) { FactoryGirl.create(:dynflow_task, :inconsistent_dynflow_task) }
|
42
|
+
|
43
|
+
it 'ensures the tasks marked as running are really running in Dynflow' do
|
44
|
+
consistent_task.state.must_equal 'planned'
|
45
|
+
inconsistent_task.state.must_equal 'running'
|
46
|
+
|
47
|
+
fixed_count = ForemanTasks::Task::DynflowTask.consistency_check
|
48
|
+
|
49
|
+
fixed_count.must_equal 1
|
50
|
+
consistent_task.reload.state.must_equal 'planned'
|
51
|
+
inconsistent_task.reload.state.must_equal 'planned'
|
52
|
+
end
|
53
|
+
end
|
37
54
|
end
|
metadata
CHANGED
@@ -1,36 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
5
|
-
prerelease:
|
4
|
+
version: 0.6.14
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ivan Nečas
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2015-
|
11
|
+
date: 2015-06-30 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: dynflow
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.7.
|
19
|
+
version: 0.7.9
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.7.
|
26
|
+
version: 0.7.9
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: sequel
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sinatra
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: daemons
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -94,105 +85,110 @@ executables: []
|
|
94
85
|
extensions: []
|
95
86
|
extra_rdoc_files: []
|
96
87
|
files:
|
97
|
-
-
|
98
|
-
-
|
99
|
-
- app/models/foreman_tasks/concerns/host_action_subject.rb
|
100
|
-
- app/models/foreman_tasks/concerns/action_triggering.rb
|
101
|
-
- app/models/foreman_tasks/concerns/architecture_action_subject.rb
|
102
|
-
- app/models/foreman_tasks/concerns/action_subject.rb
|
103
|
-
- app/models/foreman_tasks/lock.rb
|
104
|
-
- app/models/foreman_tasks/task.rb
|
105
|
-
- app/models/setting/foreman_tasks.rb
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
106
90
|
- app/assets/stylesheets/foreman_tasks/application.css.scss
|
107
|
-
- app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb
|
108
91
|
- app/controllers/foreman_tasks/api/tasks_controller.rb
|
92
|
+
- app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb
|
109
93
|
- app/controllers/foreman_tasks/tasks_controller.rb
|
110
|
-
- app/
|
111
|
-
- app/lib/actions/
|
112
|
-
- app/lib/actions/
|
94
|
+
- app/helpers/foreman_tasks/tasks_helper.rb
|
95
|
+
- app/lib/actions/action_with_sub_plans.rb
|
96
|
+
- app/lib/actions/base.rb
|
113
97
|
- app/lib/actions/bulk_action.rb
|
98
|
+
- app/lib/actions/entry_action.rb
|
114
99
|
- app/lib/actions/foreman/architecture/create.rb
|
115
|
-
- app/lib/actions/foreman/architecture/update.rb
|
116
100
|
- app/lib/actions/foreman/architecture/destroy.rb
|
101
|
+
- app/lib/actions/foreman/architecture/update.rb
|
117
102
|
- app/lib/actions/foreman/host/import_facts.rb
|
118
|
-
- app/lib/actions/
|
119
|
-
- app/lib/actions/
|
120
|
-
- app/lib/actions/
|
103
|
+
- app/lib/actions/helpers/args_serialization.rb
|
104
|
+
- app/lib/actions/helpers/humanizer.rb
|
105
|
+
- app/lib/actions/helpers/lock.rb
|
121
106
|
- app/lib/actions/middleware/keep_current_user.rb
|
107
|
+
- app/models/foreman_tasks/concerns/action_subject.rb
|
108
|
+
- app/models/foreman_tasks/concerns/action_triggering.rb
|
109
|
+
- app/models/foreman_tasks/concerns/architecture_action_subject.rb
|
110
|
+
- app/models/foreman_tasks/concerns/host_action_subject.rb
|
111
|
+
- app/models/foreman_tasks/lock.rb
|
112
|
+
- app/models/foreman_tasks/task.rb
|
113
|
+
- app/models/foreman_tasks/task/dynflow_task.rb
|
114
|
+
- app/models/foreman_tasks/task/status_explicator.rb
|
115
|
+
- app/models/foreman_tasks/task/summarizer.rb
|
116
|
+
- app/models/setting/foreman_tasks.rb
|
117
|
+
- app/views/foreman_tasks/api/tasks/show.json.rabl
|
122
118
|
- app/views/foreman_tasks/tasks/_details.html.erb
|
123
|
-
- app/views/foreman_tasks/tasks/index.html.erb
|
124
|
-
- app/views/foreman_tasks/tasks/_running_steps.html.erb
|
125
119
|
- app/views/foreman_tasks/tasks/_errors.html.erb
|
120
|
+
- app/views/foreman_tasks/tasks/_locks.html.erb
|
126
121
|
- app/views/foreman_tasks/tasks/_raw.html.erb
|
122
|
+
- app/views/foreman_tasks/tasks/_running_steps.html.erb
|
123
|
+
- app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb
|
124
|
+
- app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb
|
125
|
+
- app/views/foreman_tasks/tasks/index.html.erb
|
127
126
|
- app/views/foreman_tasks/tasks/show.html.erb
|
128
|
-
- app/views/foreman_tasks/tasks/_locks.html.erb
|
129
|
-
- app/views/foreman_tasks/api/tasks/show.json.rabl
|
130
127
|
- bin/dynflow-executor
|
131
128
|
- bin/foreman-tasks
|
132
129
|
- config/routes.rb
|
133
|
-
- db/seeds.d/20-foreman_tasks_permissions.rb
|
134
130
|
- db/migrate/20131205204140_create_foreman_tasks.rb
|
131
|
+
- db/migrate/20131209122644_create_foreman_tasks_locks.rb
|
135
132
|
- db/migrate/20140324104010_remove_foreman_tasks_progress.rb
|
136
133
|
- db/migrate/20140813215942_add_parent_task_id.rb
|
137
|
-
- db/
|
134
|
+
- db/seeds.d/20-foreman_tasks_permissions.rb
|
135
|
+
- deploy/foreman-tasks.init
|
138
136
|
- deploy/foreman-tasks.service
|
139
137
|
- deploy/foreman-tasks.sysconfig
|
140
|
-
- deploy/foreman-tasks.init
|
141
|
-
- lib/tasks/gettext.rake
|
142
138
|
- lib/foreman-tasks.rb
|
143
|
-
- lib/foreman_tasks
|
144
|
-
- lib/foreman_tasks/
|
145
|
-
- lib/foreman_tasks/triggers.rb
|
139
|
+
- lib/foreman_tasks.rb
|
140
|
+
- lib/foreman_tasks/authorizer_ext.rb
|
146
141
|
- lib/foreman_tasks/dynflow.rb
|
147
|
-
- lib/foreman_tasks/dynflow/console_authorizer.rb
|
148
142
|
- lib/foreman_tasks/dynflow/configuration.rb
|
149
|
-
- lib/foreman_tasks/dynflow/
|
143
|
+
- lib/foreman_tasks/dynflow/console_authorizer.rb
|
150
144
|
- lib/foreman_tasks/dynflow/daemon.rb
|
151
|
-
- lib/foreman_tasks/
|
145
|
+
- lib/foreman_tasks/dynflow/persistence.rb
|
152
146
|
- lib/foreman_tasks/engine.rb
|
153
147
|
- lib/foreman_tasks/task_error.rb
|
154
|
-
- lib/foreman_tasks.
|
155
|
-
-
|
156
|
-
-
|
157
|
-
-
|
158
|
-
-
|
159
|
-
-
|
148
|
+
- lib/foreman_tasks/tasks/dynflow.rake
|
149
|
+
- lib/foreman_tasks/tasks/export_tasks.rake
|
150
|
+
- lib/foreman_tasks/triggers.rb
|
151
|
+
- lib/foreman_tasks/version.rb
|
152
|
+
- lib/foreman_tasks/widget_manager.rb
|
153
|
+
- lib/tasks/gettext.rake
|
160
154
|
- test/controllers/api/tasks_controller_test.rb
|
161
155
|
- test/factories/task_factory.rb
|
162
|
-
- test/
|
156
|
+
- test/foreman_tasks_test_helper.rb
|
157
|
+
- test/helpers/foreman_tasks/tasks_helper_test.rb
|
158
|
+
- test/support/dummy_dynflow_action.rb
|
163
159
|
- test/unit/actions/action_with_sub_plans_test.rb
|
160
|
+
- test/unit/dynflow_console_authorizer_test.rb
|
164
161
|
- test/unit/task_test.rb
|
165
162
|
homepage: https://github.com/theforeman/foreman-tasks
|
166
163
|
licenses: []
|
164
|
+
metadata: {}
|
167
165
|
post_install_message:
|
168
166
|
rdoc_options: []
|
169
167
|
require_paths:
|
170
168
|
- lib
|
171
169
|
required_ruby_version: !ruby/object:Gem::Requirement
|
172
|
-
none: false
|
173
170
|
requirements:
|
174
171
|
- - ! '>='
|
175
172
|
- !ruby/object:Gem::Version
|
176
173
|
version: '0'
|
177
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
-
none: false
|
179
175
|
requirements:
|
180
176
|
- - ! '>='
|
181
177
|
- !ruby/object:Gem::Version
|
182
178
|
version: '0'
|
183
179
|
requirements: []
|
184
180
|
rubyforge_project:
|
185
|
-
rubygems_version:
|
181
|
+
rubygems_version: 2.4.8
|
186
182
|
signing_key:
|
187
|
-
specification_version:
|
183
|
+
specification_version: 4
|
188
184
|
summary: Foreman plugin for showing tasks information for resoruces and users
|
189
185
|
test_files:
|
190
|
-
- test/helpers/foreman_tasks/tasks_helper_test.rb
|
191
186
|
- test/support/dummy_dynflow_action.rb
|
187
|
+
- test/factories/task_factory.rb
|
188
|
+
- test/helpers/foreman_tasks/tasks_helper_test.rb
|
192
189
|
- test/foreman_tasks_test_helper.rb
|
193
190
|
- test/controllers/api/tasks_controller_test.rb
|
194
|
-
- test/factories/task_factory.rb
|
195
191
|
- test/unit/dynflow_console_authorizer_test.rb
|
196
|
-
- test/unit/actions/action_with_sub_plans_test.rb
|
197
192
|
- test/unit/task_test.rb
|
193
|
+
- test/unit/actions/action_with_sub_plans_test.rb
|
198
194
|
has_rdoc:
|