dvdplm-taskr 0.3.1
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.
- data/CHANGELOG.txt +1 -0
- data/GPLv3-LICENSE.txt +674 -0
- data/History.txt +50 -0
- data/Manifest.txt +34 -0
- data/README.txt +27 -0
- data/Rakefile +85 -0
- data/bin/taskr +35 -0
- data/bin/taskr-ctl +32 -0
- data/config.example.yml +176 -0
- data/examples/active_resource_client_example.rb +46 -0
- data/examples/php_client_example.php +125 -0
- data/lib/public/prototype.js +3271 -0
- data/lib/public/taskr.css +45 -0
- data/lib/taskr.rb +97 -0
- data/lib/taskr/actions.rb +318 -0
- data/lib/taskr/controllers.rb +338 -0
- data/lib/taskr/environment.rb +48 -0
- data/lib/taskr/helpers.rb +79 -0
- data/lib/taskr/models.rb +370 -0
- data/lib/taskr/version.rb +9 -0
- data/lib/taskr/views.rb +455 -0
- data/setup.rb +1585 -0
- data/taskr4rails/LICENSE.txt +504 -0
- data/taskr4rails/README +31 -0
- data/taskr4rails/Rakefile +22 -0
- data/taskr4rails/init.rb +1 -0
- data/taskr4rails/install.rb +26 -0
- data/taskr4rails/lib/taskr4rails_controller.rb +76 -0
- data/taskr4rails/tasks/taskr4rails_tasks.rake +4 -0
- data/taskr4rails/test/taskr4rails_test.rb +8 -0
- data/taskr4rails/uninstall.rb +1 -0
- data/test.rb +3 -0
- data/test/taskr_test.rb +11 -0
- data/test/test_helper.rb +2 -0
- metadata +140 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
body {
|
2
|
+
font-size: 9pt;
|
3
|
+
font-family: Verdana;
|
4
|
+
}
|
5
|
+
|
6
|
+
table {
|
7
|
+
border-collapse: collapse;
|
8
|
+
}
|
9
|
+
|
10
|
+
th, td {
|
11
|
+
font-size: 9pt;
|
12
|
+
padding-left: 2pt;
|
13
|
+
padding-right: 6pt;
|
14
|
+
vertical-align: top;
|
15
|
+
}
|
16
|
+
|
17
|
+
th {
|
18
|
+
text-align: right;
|
19
|
+
}
|
20
|
+
|
21
|
+
thead th {
|
22
|
+
background: #dde;
|
23
|
+
text-align: left;
|
24
|
+
font-size: 8pt;
|
25
|
+
}
|
26
|
+
|
27
|
+
td {
|
28
|
+
|
29
|
+
}
|
30
|
+
|
31
|
+
label {
|
32
|
+
font-weight: bold;
|
33
|
+
}
|
34
|
+
|
35
|
+
tr.expired td {
|
36
|
+
color: #aaa;
|
37
|
+
}
|
38
|
+
|
39
|
+
tr.expired td.job-id {
|
40
|
+
text-decoration: line-through;
|
41
|
+
}
|
42
|
+
|
43
|
+
tr.error td {
|
44
|
+
background-color: #faa;
|
45
|
+
}
|
data/lib/taskr.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# This file is part of Taskr.
|
2
|
+
#
|
3
|
+
# Taskr is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# Taskr is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with Taskr. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
$: << File.dirname(File.expand_path(__FILE__))
|
17
|
+
require 'taskr/environment'
|
18
|
+
|
19
|
+
Camping.goes :Taskr
|
20
|
+
Taskr.picnic!
|
21
|
+
|
22
|
+
require 'taskr/controllers'
|
23
|
+
|
24
|
+
module Taskr
|
25
|
+
@@scheduler = nil
|
26
|
+
def self.scheduler=(scheduler)
|
27
|
+
@@scheduler = scheduler
|
28
|
+
end
|
29
|
+
def self.scheduler
|
30
|
+
@@scheduler
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'taskr/actions'
|
35
|
+
require 'taskr/models'
|
36
|
+
require 'taskr/helpers'
|
37
|
+
require 'taskr/views'
|
38
|
+
require 'taskr/controllers'
|
39
|
+
|
40
|
+
module Taskr
|
41
|
+
include Taskr::Models
|
42
|
+
|
43
|
+
def self.authenticate(credentials)
|
44
|
+
credentials[:username] == Taskr::Conf[:authentication][:username] &&
|
45
|
+
credentials[:password] == Taskr::Conf[:authentication][:password]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
include Taskr::Models
|
50
|
+
|
51
|
+
if Taskr::Conf[:authentication]
|
52
|
+
Taskr.authenticate_using(Taskr::Conf[:authentication][:method] || :basic)
|
53
|
+
end
|
54
|
+
|
55
|
+
$CONF[:public_dir] = {
|
56
|
+
:path => "public",
|
57
|
+
:dir => File.join(File.expand_path(File.dirname(__FILE__)),"public")
|
58
|
+
}
|
59
|
+
|
60
|
+
def Taskr.create
|
61
|
+
$LOG.info "Initializing Taskr..."
|
62
|
+
Taskr::Models::Base.establish_connection(Taskr::Conf.database)
|
63
|
+
Taskr::Models.create_schema
|
64
|
+
|
65
|
+
if self::Conf[:external_actions]
|
66
|
+
if self::Conf[:external_actions].kind_of? Array
|
67
|
+
external_actions = self::Conf[:external_actions]
|
68
|
+
else
|
69
|
+
external_actions = [self::Conf[:external_actions]]
|
70
|
+
end
|
71
|
+
external_actions.each do |f|
|
72
|
+
$LOG.info "Loading additional action definitions from #{self::Conf[:external_actions]}..."
|
73
|
+
require f
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def Taskr.prestart
|
79
|
+
$LOG.info "Starting Rufus Scheduler..."
|
80
|
+
|
81
|
+
Taskr.scheduler = Rufus::Scheduler.new
|
82
|
+
Taskr.scheduler.start
|
83
|
+
|
84
|
+
$LOG.debug "Scheduler is: #{Taskr.scheduler.inspect}"
|
85
|
+
|
86
|
+
tasks = Taskr::Models::Task.find(:all)
|
87
|
+
|
88
|
+
$LOG.info "Scheduling #{tasks.length} persisted tasks..."
|
89
|
+
|
90
|
+
tasks.each do |t|
|
91
|
+
t.schedule! Taskr.scheduler
|
92
|
+
end
|
93
|
+
|
94
|
+
Taskr.scheduler.instance_variable_get(:@scheduler_thread).run
|
95
|
+
end
|
96
|
+
|
97
|
+
Taskr.start_picnic
|
@@ -0,0 +1,318 @@
|
|
1
|
+
# This file is part of Taskr.
|
2
|
+
#
|
3
|
+
# Taskr is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# Taskr is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with Taskr. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'rufus/scheduler'
|
17
|
+
|
18
|
+
#require 'active_resource'
|
19
|
+
require 'restr'
|
20
|
+
|
21
|
+
|
22
|
+
unless $LOG
|
23
|
+
$LOG = Logger.new(STDERR)
|
24
|
+
$LOG.level = Logger::ERROR
|
25
|
+
end
|
26
|
+
|
27
|
+
module Taskr
|
28
|
+
module Actions
|
29
|
+
|
30
|
+
def self.list
|
31
|
+
actions = []
|
32
|
+
Taskr::Actions.constants.each do |m|
|
33
|
+
a = Taskr::Actions.const_get(m)
|
34
|
+
actions << a if a < Taskr::Actions::Base
|
35
|
+
end
|
36
|
+
return actions
|
37
|
+
end
|
38
|
+
|
39
|
+
# The base class for all Actions.
|
40
|
+
# Extend this to define your own custom Action.
|
41
|
+
class Base
|
42
|
+
include Rufus::Schedulable
|
43
|
+
|
44
|
+
class_inheritable_accessor :parameters
|
45
|
+
class_inheritable_accessor :description
|
46
|
+
|
47
|
+
attr_accessor :parameters
|
48
|
+
attr_accessor :task
|
49
|
+
attr_accessor :task_action
|
50
|
+
|
51
|
+
def initialize(parameters)
|
52
|
+
self.parameters = HashWithIndifferentAccess.new(parameters)
|
53
|
+
end
|
54
|
+
|
55
|
+
def execute
|
56
|
+
raise NotImplementedError, "Implement me!"
|
57
|
+
end
|
58
|
+
|
59
|
+
def trigger(trigger_args = {})
|
60
|
+
begin
|
61
|
+
$LOG.info("Executing task #{self.task.name.inspect}")
|
62
|
+
execute
|
63
|
+
task.update_attribute(:last_triggered, Time.now)
|
64
|
+
task.update_attribute(:last_triggered_error, nil)
|
65
|
+
rescue => e
|
66
|
+
puts
|
67
|
+
$LOG.error("Error while executing task #{self.task.name.inspect}! The error was: #{e} (see Taskr log for debugging details)")
|
68
|
+
$LOG.debug(e.backtrace.join($/))
|
69
|
+
details = e.message
|
70
|
+
details += "\n\n#{$LAST_ERROR_BODY}" if $LAST_ERROR_BODY # dumb way of reading Restr errors... Restr needs to be fixed
|
71
|
+
task.update_attribute(:last_triggered, Time.now)
|
72
|
+
task.update_attribute(:last_triggered_error, {:type => e.class.to_s, :message => details})
|
73
|
+
raise e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
"#{self.class.name}(#{parameters.inspect})"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Do not extend this class. It is used internally to schedule multiple
|
83
|
+
# actions per task.
|
84
|
+
#
|
85
|
+
# If you want to define your own custom Action, extend Taskr::Actions::Base
|
86
|
+
class Multi
|
87
|
+
include Rufus::Schedulable
|
88
|
+
|
89
|
+
attr_accessor :actions
|
90
|
+
attr_accessor :task
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
self.actions = []
|
94
|
+
end
|
95
|
+
|
96
|
+
def trigger(trigger_args = {})
|
97
|
+
begin
|
98
|
+
$LOG.info("Executing task #{self.task.name.inspect}")
|
99
|
+
actions.each do |a|
|
100
|
+
a.execute
|
101
|
+
LogEntry.info(a, "Action #{a} executed.")
|
102
|
+
end
|
103
|
+
# TODO: maybe we should store last_triggered time on a per-action basis?
|
104
|
+
task.update_attribute(:last_triggered, Time.now)
|
105
|
+
task.update_attribute(:last_triggered_error, nil)
|
106
|
+
rescue => e
|
107
|
+
$LOG.error("Error while executing task #{self.task.name.inspect}! The error was: #{e} (see Taskr log for debugging details)")
|
108
|
+
$LOG.debug("#{e.backtrace}")
|
109
|
+
task.update_attribute(:last_triggered, Time.now)
|
110
|
+
task.update_attribute(:last_triggered_error, {:type => e.class.to_s, :details => "#{e.message}"})
|
111
|
+
# FIXME: Maybe actions should be responseible for logging their errors, otherwise we double-log the same error.
|
112
|
+
LogEntry.error(task, "Task #{task} raised an exception: \n#{e.class}: #{e.message}\n#{e.backtrace}")
|
113
|
+
raise e
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class RotateTaskLog < Base
|
119
|
+
self.parameters = ['delete_old_log_entries_after_days']
|
120
|
+
self.description = "Deletes old task log entries from this Taskr server's database."
|
121
|
+
|
122
|
+
def execute
|
123
|
+
num = parameters['delete_old_log_entries_after_days'].to_i
|
124
|
+
|
125
|
+
cond = ['timestamp < ?', Time.now - num.days]
|
126
|
+
LogEntry.delete_all(cond)
|
127
|
+
LogEntry.debug(task_action, "Deleted log entries with conditions: #{cond.inspect}")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Shell < Base
|
132
|
+
self.parameters = ['command', 'as_user']
|
133
|
+
self.description = "Execute a shell command (be careful!)"
|
134
|
+
|
135
|
+
def execute
|
136
|
+
if parameters.kind_of? Hash
|
137
|
+
user = parameters['as_user']
|
138
|
+
cmd = parameters['command']
|
139
|
+
else
|
140
|
+
user = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
unless user.blank?
|
144
|
+
cmd = "sudo -u #{user} #{cmd}"
|
145
|
+
end
|
146
|
+
|
147
|
+
outio = StringIO.new
|
148
|
+
errio = StringIO.new
|
149
|
+
old_stdout, $stdout = $stdout, outio
|
150
|
+
old_stderr, $stderr = $stderr, errio
|
151
|
+
|
152
|
+
out = `#{cmd}`
|
153
|
+
|
154
|
+
err = errio.string
|
155
|
+
out = outio.string
|
156
|
+
LogEntry.debug(task_action, out) unless out.blank?
|
157
|
+
LogEntry.error(task_action, err) unless err.blank?
|
158
|
+
|
159
|
+
$stdout = old_stdout
|
160
|
+
$stderr = old_stderr
|
161
|
+
|
162
|
+
unless $?.success?
|
163
|
+
msg = "Shell command #{cmd.inspect} failed (returned code #{$?}): #{out}"
|
164
|
+
LogEntry.error(task_action, msg)
|
165
|
+
raise msg
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Ruby < Base
|
171
|
+
self.parameters = ['code']
|
172
|
+
self.description = "Execute some Ruby code."
|
173
|
+
|
174
|
+
def execute
|
175
|
+
outio = StringIO.new
|
176
|
+
errio = StringIO.new
|
177
|
+
old_stdout, $stdout = $stdout, outio
|
178
|
+
old_stderr, $stderr = $stderr, errio
|
179
|
+
|
180
|
+
code = parameters['code']
|
181
|
+
eval(code)
|
182
|
+
|
183
|
+
err = errio.string
|
184
|
+
out = outio.string
|
185
|
+
LogEntry.debug(task_action, out) unless out.blank?
|
186
|
+
LogEntry.error(task_action, err) unless err.blank?
|
187
|
+
|
188
|
+
$stdout = old_stdout
|
189
|
+
$stderr = old_stderr
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# This is too complicated... we use Restr instead.
|
195
|
+
# class ActiveResource < Base
|
196
|
+
# self.parameters = ['site', 'resource', 'action', 'parameters']
|
197
|
+
# self.description = "Perform a REST call on a remote service using ActiveResource."
|
198
|
+
#
|
199
|
+
# def execute
|
200
|
+
# $LOG.debug self
|
201
|
+
# ::ActiveResource::Base.logger = $LOG
|
202
|
+
# ::ActiveResource::Base.logger.progname = (task ? task.to_s : self)
|
203
|
+
#
|
204
|
+
# eval %{
|
205
|
+
# class Proxy < ::ActiveResource::Base
|
206
|
+
# self.site = "#{parameters['site']}"
|
207
|
+
# self.collection_name = "#{parameters['resource'].pluralize}"
|
208
|
+
# end
|
209
|
+
# }
|
210
|
+
#
|
211
|
+
# begin
|
212
|
+
# case parameters['action']
|
213
|
+
# when 'create'
|
214
|
+
# obj = Proxy.new(parameters['parameters'])
|
215
|
+
# obj.save
|
216
|
+
# when 'update', "'update' action is not implemented"
|
217
|
+
# raise NotImplementedError
|
218
|
+
# when 'delete'
|
219
|
+
# Proxy.delete(parameters['parameters'])
|
220
|
+
# when 'find'
|
221
|
+
# raise NotImplementedError, "'find' action is not implemented"
|
222
|
+
# else
|
223
|
+
# raise ArgumentError, "unknown action #{parameters['action'].inspect}"
|
224
|
+
# end
|
225
|
+
# rescue ::ActiveResource::ServerError => e
|
226
|
+
# $LOG.error #{self} ERROR: #{e.methods.inspect}"
|
227
|
+
# raise e
|
228
|
+
# end
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# class Howlr < ActiveResource
|
233
|
+
# self.parameters = ['site', 'from', 'recipients', 'subject', 'body']
|
234
|
+
# self.description = "Send a message through a Howlr service."
|
235
|
+
#
|
236
|
+
# def execute
|
237
|
+
# parameters['action'] = 'create'
|
238
|
+
# parameters['resource'] = 'message'
|
239
|
+
# parameters['parameters'] = {
|
240
|
+
# 'from' => parameters['from'],
|
241
|
+
# 'recipients' => parameters['recipients'],
|
242
|
+
# 'subject' => parameters['subject'],
|
243
|
+
# 'body' => parameters['body']
|
244
|
+
# }
|
245
|
+
#
|
246
|
+
# super
|
247
|
+
# end
|
248
|
+
# end
|
249
|
+
|
250
|
+
class Rest < Base
|
251
|
+
self.parameters = ['method', 'url', 'params', 'username', 'password']
|
252
|
+
self.description = "Perform a REST call on a remote service."
|
253
|
+
|
254
|
+
def execute
|
255
|
+
auth = nil
|
256
|
+
if parameters['username']
|
257
|
+
auth = {}
|
258
|
+
auth['username'] = parameters['username'] if parameters['username']
|
259
|
+
auth['password'] = parameters['password'] if parameters['password']
|
260
|
+
end
|
261
|
+
|
262
|
+
if parameters['params'].kind_of? String
|
263
|
+
params2 = {}
|
264
|
+
parameters['params'].split('&').collect do |p|
|
265
|
+
key, value = p.split('=')
|
266
|
+
params2[key] = value
|
267
|
+
end
|
268
|
+
parameters['params'] = params2
|
269
|
+
end
|
270
|
+
|
271
|
+
Restr.logger = LogEntry.logger_for_action(task_action)
|
272
|
+
Restr.do(parameters['method'], parameters['url'], (parameters['params'] unless parameters['params'].blank?), auth)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class Howlr < Rest
|
277
|
+
self.parameters = ['url', 'from', 'recipients', 'subject', 'body', 'username', 'password', 'content_type']
|
278
|
+
self.description = "Send a message through a Howlr service."
|
279
|
+
|
280
|
+
def execute
|
281
|
+
content_type = parameters['content_type']
|
282
|
+
content_type = 'text/plain' if content_type.blank?
|
283
|
+
|
284
|
+
parameters['method'] = 'post'
|
285
|
+
parameters['params'] = {
|
286
|
+
'content_type' => content_type,
|
287
|
+
'from' => parameters['from'],
|
288
|
+
'recipients' => parameters['recipients'],
|
289
|
+
'subject' => parameters['subject'],
|
290
|
+
'body' => parameters['body'],
|
291
|
+
'format' => 'XML'
|
292
|
+
}
|
293
|
+
|
294
|
+
super
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
class Taskr4rails < Base
|
299
|
+
self.parameters = ['url', 'auth', 'ruby_code', 'dont_wait']#, 'shell_command']
|
300
|
+
self.description = "Executes code on a remote Rails server via the taskr4rails plugin."
|
301
|
+
|
302
|
+
def execute
|
303
|
+
data = {
|
304
|
+
:task_name => task.name,
|
305
|
+
:task_id => task.id,
|
306
|
+
:auth => parameters['auth'],
|
307
|
+
:dont_wait => parameters['dont_wait'],
|
308
|
+
:ruby_code => parameters['ruby_code']#,
|
309
|
+
#:shell_command => parameters['shell_command']
|
310
|
+
}
|
311
|
+
|
312
|
+
|
313
|
+
Restr.logger = LogEntry.logger_for_action(task_action)
|
314
|
+
Restr.post(parameters['url'], data)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|