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.
@@ -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
+ }
@@ -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