bricolage 5.23.3 → 5.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/bricolage/application.rb +160 -37
- data/lib/bricolage/commandlineapplication.rb +0 -0
- data/lib/bricolage/commandutils.rb +0 -20
- data/lib/bricolage/context.rb +19 -4
- data/lib/bricolage/job.rb +38 -38
- data/lib/bricolage/jobfile.rb +2 -1
- data/lib/bricolage/jobnet.rb +21 -3
- data/lib/bricolage/jobnetrunner.rb +102 -62
- data/lib/bricolage/logfilepath.rb +2 -2
- data/lib/bricolage/loglocator.rb +71 -0
- data/lib/bricolage/loglocatorbuilder.rb +29 -0
- data/lib/bricolage/psqldatasource.rb +1 -1
- data/lib/bricolage/s3writer.rb +22 -0
- data/lib/bricolage/version.rb +1 -1
- data/test/home/Gemfile.lock +41 -0
- data/test/home/config/bricolage.yml +3 -0
- data/test/home/config/development/database.yml +113 -0
- data/test/home/config/development/password.yml +6 -0
- data/test/home/config/development/variable.yml +7 -0
- data/test/home/config/streamingload.yml +8 -0
- data/test/home/log/20170117/subsys::job1/20170117_202014082/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::job1/20170117_202334852/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::job1/20170117_202405056/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::migrate/20170117_202548409/subsys-migrate.log +80 -0
- data/test/home/log/20170117/subsys::migrate/20170117_202636115/subsys-migrate.log +79 -0
- data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job2.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job3.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job4.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job2.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job3.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job4.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job1.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job2.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job3.log +3 -0
- data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job4.log +3 -0
- data/test/home/log/20170629/subsys::job1/20170629_155543985/subsys-job1.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job1.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job2.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job3.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job4.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job1.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job2.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job3.log +3 -0
- data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job4.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job1.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job2.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job3.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job4.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job1.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job2.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job3.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job4.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job1.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job2.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job3.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job4.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_153437221/subsys-job1.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job1.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job2.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job3.log +3 -0
- data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job4.log +3 -0
- data/test/home/log/20170704/subsys::insert.sql.job/20170704_163033119/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert.sql.job/20170704_172410576/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert.sql.job/20170704_173130175/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert.sql.job/20170704_173201376/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert.sql/20170704_164143661/subsys-insert.sql.log +14 -0
- data/test/home/log/20170704/subsys::insert/20170704_164335210/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert/20170704_164344251/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::insert/20170704_164723299/subsys-insert.log +14 -0
- data/test/home/log/20170704/subsys::net1/20170704_162457694/subsys-job1.log +3 -0
- data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job1.log +3 -0
- data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job2.log +3 -0
- data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job3.log +3 -0
- data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job4.log +3 -0
- data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job1.log +3 -0
- data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job2.log +3 -0
- data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job3.log +3 -0
- data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job4.log +3 -0
- data/test/home/log/20170707/subsys::insert/20170707_020050817/subsys-insert.log +51 -0
- data/test/home/log/20170707/subsys::insert/20170707_020050817/subsys-insert.log.status +1 -0
- data/test/home/log/20170707/subsys::job1/20170707_020542902/subsys-job1.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job1.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job2.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job3.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job4.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job1.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job2.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job3.log +3 -0
- data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job4.log +3 -0
- data/test/home/revert.sh +7 -0
- data/test/home/s +1 -0
- metadata +125 -43
data/lib/bricolage/jobfile.rb
CHANGED
data/lib/bricolage/jobnet.rb
CHANGED
|
@@ -5,27 +5,45 @@ module Bricolage
|
|
|
5
5
|
|
|
6
6
|
# Represents "first" jobnet given by command line (e.g. bricolage-jobnet some.jobnet)
|
|
7
7
|
class RootJobNet
|
|
8
|
+
def RootJobNet.load_auto(ctx, path)
|
|
9
|
+
if path.extname == '.job'
|
|
10
|
+
load_single_job(ctx, path)
|
|
11
|
+
else
|
|
12
|
+
load(ctx, path)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
8
16
|
def RootJobNet.load(ctx, path)
|
|
9
|
-
root = new(JobNet::FileLoader.new(ctx), JobNet.load(path))
|
|
17
|
+
root = new(JobNet::FileLoader.new(ctx), JobNet.load(path), path)
|
|
10
18
|
root.load_recursive
|
|
11
19
|
root.fix
|
|
12
20
|
root
|
|
13
21
|
end
|
|
14
22
|
|
|
15
23
|
def RootJobNet.load_single_job(ctx, path)
|
|
16
|
-
root = new(JobNet::FileLoader.new(ctx), JobNet.load_single_job(path))
|
|
24
|
+
root = new(JobNet::FileLoader.new(ctx), JobNet.load_single_job(path), path)
|
|
17
25
|
root.load_recursive
|
|
18
26
|
root.fix
|
|
19
27
|
root
|
|
20
28
|
end
|
|
21
29
|
|
|
22
|
-
def initialize(jobnet_loader, start_jobnet)
|
|
30
|
+
def initialize(jobnet_loader, start_jobnet, path = nil)
|
|
23
31
|
@jobnet_loader = jobnet_loader
|
|
24
32
|
@start_jobnet = start_jobnet
|
|
33
|
+
@path = path
|
|
25
34
|
@jobnets = {start_jobnet.ref => start_jobnet}
|
|
26
35
|
@graph = nil
|
|
27
36
|
end
|
|
28
37
|
|
|
38
|
+
def id
|
|
39
|
+
return nil unless @path
|
|
40
|
+
@id ||= begin
|
|
41
|
+
subsys = @path.dirname.basename
|
|
42
|
+
base = @path.basename.to_s.sub(/\..*\z/, '')
|
|
43
|
+
"#{subsys}/#{base}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
29
47
|
attr_reader :start_jobnet
|
|
30
48
|
|
|
31
49
|
def each_jobnet(&block)
|
|
@@ -8,6 +8,7 @@ require 'bricolage/datasource'
|
|
|
8
8
|
require 'bricolage/variables'
|
|
9
9
|
require 'bricolage/eventhandlers'
|
|
10
10
|
require 'bricolage/logfilepath'
|
|
11
|
+
require 'bricolage/loglocatorbuilder'
|
|
11
12
|
require 'bricolage/logger'
|
|
12
13
|
require 'bricolage/exception'
|
|
13
14
|
require 'bricolage/version'
|
|
@@ -26,8 +27,6 @@ module Bricolage
|
|
|
26
27
|
@hooks = ::Bricolage
|
|
27
28
|
@jobnet_id = nil
|
|
28
29
|
@jobnet_start_time = Time.now
|
|
29
|
-
@job_start_time = nil
|
|
30
|
-
@log_path = nil
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
EXIT_SUCCESS = JobResult::EXIT_SUCCESS
|
|
@@ -37,24 +36,31 @@ module Bricolage
|
|
|
37
36
|
def main
|
|
38
37
|
opts = Options.new(self)
|
|
39
38
|
@hooks.run_before_option_parsing_hooks(opts)
|
|
40
|
-
opts.parse
|
|
39
|
+
opts.parse!(ARGV)
|
|
40
|
+
|
|
41
41
|
@ctx = Context.for_application(job_path: opts.jobnet_file, environment: opts.environment, global_variables: opts.global_variables)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
jobnet =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
opts.merge_saved_options(@ctx.load_system_options)
|
|
43
|
+
|
|
44
|
+
jobnet = RootJobNet.load_auto(@ctx, opts.jobnet_file)
|
|
45
|
+
@jobnet_id = jobnet.id
|
|
46
|
+
|
|
47
|
+
if opts.dump_options?
|
|
48
|
+
puts "jobnet-id=#{@jobnet_id}"
|
|
49
|
+
puts "jobnet-file=#{opts.jobnet_file}"
|
|
50
|
+
opts.option_pairs.each do |key, value|
|
|
51
|
+
puts "#{key}=#{value.inspect}"
|
|
49
52
|
end
|
|
53
|
+
exit EXIT_SUCCESS
|
|
54
|
+
end
|
|
55
|
+
|
|
50
56
|
queue = get_queue(opts)
|
|
51
57
|
if queue.locked?
|
|
52
58
|
raise ParameterError, "Job queue is still locked. If you are sure to restart jobnet, #{queue.unlock_help}"
|
|
53
59
|
end
|
|
54
60
|
unless queue.queued?
|
|
55
61
|
enqueue_jobs jobnet, queue
|
|
56
|
-
logger.info "jobs are queued."
|
|
57
62
|
end
|
|
63
|
+
|
|
58
64
|
if opts.list_jobs?
|
|
59
65
|
list_jobs queue
|
|
60
66
|
exit EXIT_SUCCESS
|
|
@@ -64,6 +70,8 @@ module Bricolage
|
|
|
64
70
|
puts "OK"
|
|
65
71
|
exit EXIT_SUCCESS
|
|
66
72
|
end
|
|
73
|
+
|
|
74
|
+
@log_locator_builder = LogLocatorBuilder.for_options(@ctx, opts.log_path_format, opts.log_s3_ds, opts.log_s3_key_format)
|
|
67
75
|
run_queue queue
|
|
68
76
|
exit EXIT_SUCCESS
|
|
69
77
|
rescue OptionError => ex
|
|
@@ -144,11 +152,11 @@ module Bricolage
|
|
|
144
152
|
|
|
145
153
|
def execute_job(ref, queue)
|
|
146
154
|
logger.debug "job #{ref}"
|
|
147
|
-
|
|
155
|
+
job_start_time = Time.now
|
|
148
156
|
job = Job.load_ref(ref, @ctx)
|
|
149
157
|
job.compile
|
|
150
158
|
@hooks.run_before_job_hooks(BeforeJobEvent.new(ref))
|
|
151
|
-
result = job.execute_in_process(
|
|
159
|
+
result = job.execute_in_process(log_locator: make_log_locator(ref, job_start_time))
|
|
152
160
|
@hooks.run_after_job_hooks(AfterJobEvent.new(result))
|
|
153
161
|
result
|
|
154
162
|
rescue Exception => ex
|
|
@@ -157,12 +165,11 @@ module Bricolage
|
|
|
157
165
|
JobResult.error(ex)
|
|
158
166
|
end
|
|
159
167
|
|
|
160
|
-
def
|
|
161
|
-
|
|
162
|
-
@log_path.format(
|
|
168
|
+
def make_log_locator(ref, job_start_time)
|
|
169
|
+
@log_locator_builder.build(
|
|
163
170
|
job_ref: ref,
|
|
164
171
|
jobnet_id: @jobnet_id,
|
|
165
|
-
job_start_time:
|
|
172
|
+
job_start_time: job_start_time,
|
|
166
173
|
jobnet_start_time: @jobnet_start_time
|
|
167
174
|
)
|
|
168
175
|
end
|
|
@@ -189,51 +196,40 @@ module Bricolage
|
|
|
189
196
|
File.basename($PROGRAM_NAME, '.*')
|
|
190
197
|
end
|
|
191
198
|
|
|
192
|
-
class Options
|
|
199
|
+
class Options < CommonApplicationOptions
|
|
193
200
|
def initialize(app)
|
|
194
201
|
@app = app
|
|
195
202
|
@environment = nil
|
|
203
|
+
@global_variables = Variables.new
|
|
196
204
|
@jobnet_files = nil
|
|
197
|
-
|
|
198
|
-
@
|
|
199
|
-
if path = ENV['BRICOLAGE_QUEUE_PATH']
|
|
200
|
-
@enable_queue = true
|
|
201
|
-
@queue_path = Pathname(path)
|
|
202
|
-
elsif ENV['BRICOLAGE_ENABLE_QUEUE']
|
|
203
|
-
@enable_queue = true
|
|
204
|
-
@queue_path = nil
|
|
205
|
-
else
|
|
206
|
-
@enable_queue = false
|
|
207
|
-
@queue_path = nil
|
|
208
|
-
end
|
|
205
|
+
|
|
206
|
+
@dump_options = false
|
|
209
207
|
@check_only = false
|
|
210
208
|
@list_jobs = false
|
|
211
|
-
@global_variables = Variables.new
|
|
212
|
-
@parser = OptionParser.new
|
|
213
|
-
define_options @parser
|
|
214
|
-
end
|
|
215
209
|
|
|
216
|
-
|
|
217
|
-
attr_reader :jobnet_file
|
|
218
|
-
attr_reader :log_path
|
|
219
|
-
|
|
220
|
-
attr_reader :local_state_dir
|
|
221
|
-
|
|
222
|
-
def enable_queue?
|
|
223
|
-
@enable_queue
|
|
210
|
+
init_options
|
|
224
211
|
end
|
|
225
212
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
213
|
+
def opts_default
|
|
214
|
+
super.merge({
|
|
215
|
+
'local-state-dir' => OptionValue.new('default value', nil),
|
|
216
|
+
'enable-queue' => OptionValue.new('default value', false),
|
|
217
|
+
'queue-path' => OptionValue.new('default value', '/tmp/bricolage')
|
|
218
|
+
})
|
|
230
219
|
end
|
|
220
|
+
private :opts_default
|
|
231
221
|
|
|
232
|
-
def
|
|
233
|
-
|
|
222
|
+
def opts_env
|
|
223
|
+
env = super
|
|
224
|
+
if ENV['BRICOLAGE_ENABLE_QUEUE']
|
|
225
|
+
env['enable-queue'] = OptionValue.new('env BRICOLAGE_ENABLE_QUEUE', true)
|
|
226
|
+
end
|
|
227
|
+
if path = ENV['BRICOLAGE_QUEUE_PATH']
|
|
228
|
+
env['queue-path'] = OptionValue.new('env BRICOLAGE_QUEUE_PATH', path)
|
|
229
|
+
end
|
|
230
|
+
env
|
|
234
231
|
end
|
|
235
|
-
|
|
236
|
-
attr_reader :global_variables
|
|
232
|
+
private :opts_env
|
|
237
233
|
|
|
238
234
|
def help
|
|
239
235
|
@parser.help
|
|
@@ -248,20 +244,17 @@ Options:
|
|
|
248
244
|
parser.on('-e', '--environment=NAME', "Sets execution environment. [default: #{Context::DEFAULT_ENV}]") {|env|
|
|
249
245
|
@environment = env
|
|
250
246
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
parser.on('--log-path=PATH', 'Log file path template.') {|path|
|
|
255
|
-
@log_path = LogFilePath.new(path)
|
|
256
|
-
}
|
|
247
|
+
|
|
248
|
+
define_common_options
|
|
249
|
+
|
|
257
250
|
parser.on('--local-state-dir=PATH', 'Stores local state in this path.') {|path|
|
|
258
|
-
@
|
|
251
|
+
@opts_cmdline['local-state-dir'] = OptionValue.new('--local-state-dir option', path)
|
|
259
252
|
}
|
|
260
253
|
parser.on('-Q', '--enable-queue', 'Enables job queue.') {
|
|
261
|
-
@
|
|
254
|
+
@opts_cmdline['enable-queue'] = OptionValue.new('--enable-queue option', true)
|
|
262
255
|
}
|
|
263
256
|
parser.on('--queue-path=PATH', 'Enables job queue with this path.') {|path|
|
|
264
|
-
@
|
|
257
|
+
@opts_cmdline['queue-path'] = OptionValue.new('--queue-path option', path)
|
|
265
258
|
}
|
|
266
259
|
parser.on('-c', '--check-only', 'Checks job parameters and quit without executing.') {
|
|
267
260
|
@check_only = true
|
|
@@ -273,6 +266,9 @@ Options:
|
|
|
273
266
|
name, value = name_value.split('=', 2)
|
|
274
267
|
@global_variables[name] = value
|
|
275
268
|
}
|
|
269
|
+
parser.on('--dump-options', 'Shows option parsing result and quit.') {
|
|
270
|
+
@dump_options = true
|
|
271
|
+
}
|
|
276
272
|
parser.on('--help', 'Shows this message and quit.') {
|
|
277
273
|
@app.puts parser.help
|
|
278
274
|
@app.exit 0
|
|
@@ -287,14 +283,58 @@ Options:
|
|
|
287
283
|
@parser.on(*args, &block)
|
|
288
284
|
end
|
|
289
285
|
|
|
290
|
-
def parse(argv)
|
|
291
|
-
@parser.parse!
|
|
286
|
+
def parse!(argv)
|
|
287
|
+
@parser.parse!(argv)
|
|
292
288
|
raise OptionError, "missing jobnet file" if argv.empty?
|
|
293
289
|
raise OptionError, "too many jobnet file" if argv.size > 1
|
|
294
|
-
@jobnet_file =
|
|
290
|
+
@jobnet_file = Pathname(argv.first)
|
|
291
|
+
build_common_options!
|
|
295
292
|
rescue OptionParser::ParseError => ex
|
|
296
293
|
raise OptionError, ex.message
|
|
297
294
|
end
|
|
295
|
+
|
|
296
|
+
attr_reader :environment
|
|
297
|
+
attr_reader :jobnet_file
|
|
298
|
+
|
|
299
|
+
attr_reader :global_variables
|
|
300
|
+
|
|
301
|
+
def dump_options?
|
|
302
|
+
@dump_options
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def check_only?
|
|
306
|
+
@check_only
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def list_jobs?
|
|
310
|
+
@list_jobs
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def local_state_dir
|
|
314
|
+
@local_state_dir ||= begin
|
|
315
|
+
opt = @opts['local-state-dir']
|
|
316
|
+
Pathname(opt.value)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def enable_queue?
|
|
321
|
+
opt = @opts['enable-queue']
|
|
322
|
+
opt.value
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def queue_path
|
|
326
|
+
if opt = @opts['queue-path']
|
|
327
|
+
Pathname(opt.value)
|
|
328
|
+
else
|
|
329
|
+
nil
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def option_pairs
|
|
334
|
+
common_options.merge({
|
|
335
|
+
'environment' => OptionValue.new(nil, @environment)
|
|
336
|
+
})
|
|
337
|
+
end
|
|
298
338
|
end
|
|
299
339
|
end
|
|
300
340
|
|
|
@@ -14,14 +14,14 @@ module Bricolage
|
|
|
14
14
|
@template = template
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
Params = Struct.new(:job_ref, :jobnet_id, :job_start_time, :jobnet_start_time)
|
|
18
|
-
|
|
19
17
|
def format(job_ref:, jobnet_id:, job_start_time:, jobnet_start_time:)
|
|
20
18
|
return nil unless @template
|
|
21
19
|
params = Params.new(job_ref, jobnet_id, job_start_time, jobnet_start_time)
|
|
22
20
|
fill_template(@template, params)
|
|
23
21
|
end
|
|
24
22
|
|
|
23
|
+
Params = Struct.new(:job_ref, :jobnet_id, :job_start_time, :jobnet_start_time)
|
|
24
|
+
|
|
25
25
|
def fill_template(template, params)
|
|
26
26
|
template.gsub(/%\{\w+\}/) {|var|
|
|
27
27
|
case var
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Bricolage
|
|
2
|
+
class LogLocator
|
|
3
|
+
def LogLocator.empty
|
|
4
|
+
new(nil, nil)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def initialize(path, s3_writer)
|
|
8
|
+
@path = path
|
|
9
|
+
@s3_writer = s3_writer
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attr_reader :path
|
|
13
|
+
|
|
14
|
+
def s3_url
|
|
15
|
+
return nil unless @s3_writer
|
|
16
|
+
@s3_writer.url
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def redirect_stdouts
|
|
20
|
+
return yield unless @path
|
|
21
|
+
FileUtils.mkdir_p File.dirname(@path)
|
|
22
|
+
@original_stdout = $stdout.dup
|
|
23
|
+
@original_stderr = $stderr.dup
|
|
24
|
+
begin
|
|
25
|
+
# Use 'w+' to make readable for retrieve_last_match_from_stderr
|
|
26
|
+
File.open(@path, 'w+') {|f|
|
|
27
|
+
f.sync = true
|
|
28
|
+
$stdout.reopen f
|
|
29
|
+
$stderr.reopen f
|
|
30
|
+
}
|
|
31
|
+
return yield
|
|
32
|
+
ensure
|
|
33
|
+
$stdout.reopen @original_stdout; @original_stdout.close
|
|
34
|
+
$stderr.reopen @original_stderr; @original_stderr.close
|
|
35
|
+
upload
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# CLUDGE: FIXME: We redirect stderr to the file, we can find error messages from there.
|
|
40
|
+
# Using a temporary file or Ruby SQL driver is **MUCH** better.
|
|
41
|
+
def self.slice_last_stderr(re, nth = 0)
|
|
42
|
+
return unless $stderr.stat.file?
|
|
43
|
+
$stderr.flush
|
|
44
|
+
f = $stderr.dup
|
|
45
|
+
matched = nil
|
|
46
|
+
begin
|
|
47
|
+
f.seek(0)
|
|
48
|
+
f.each do |line|
|
|
49
|
+
m = line.slice(re, nth)
|
|
50
|
+
matched = m if m
|
|
51
|
+
end
|
|
52
|
+
ensure
|
|
53
|
+
f.close
|
|
54
|
+
end
|
|
55
|
+
matched = matched.to_s.strip
|
|
56
|
+
matched.empty? ? nil : matched
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def upload
|
|
60
|
+
return unless @path
|
|
61
|
+
return unless @s3_writer
|
|
62
|
+
# FIXME: Shows HTTP URL?
|
|
63
|
+
puts "bricolage: S3 log: #{s3_url}"
|
|
64
|
+
begin
|
|
65
|
+
@s3_writer.upload(path)
|
|
66
|
+
rescue => ex
|
|
67
|
+
puts "warning: S3 upload failed: #{s3_url}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'bricolage/loglocator'
|
|
2
|
+
require 'bricolage/s3writer'
|
|
3
|
+
|
|
4
|
+
module Bricolage
|
|
5
|
+
class LogLocatorBuilder
|
|
6
|
+
def LogLocatorBuilder.for_options(ctx, log_path_format, s3_ds, s3_key_format)
|
|
7
|
+
ds = s3_ds ? ctx.get_data_source('s3', s3_ds) : nil
|
|
8
|
+
new(log_path_format, ds, s3_key_format)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(log_path_format, s3_ds, s3_key_format)
|
|
12
|
+
@log_path_format = log_path_format
|
|
13
|
+
@s3_ds = s3_ds
|
|
14
|
+
@s3_key_format = s3_key_format
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build(**params)
|
|
18
|
+
path = @log_path_format ? @log_path_format.format(**params) : nil
|
|
19
|
+
s3_writer =
|
|
20
|
+
if @s3_ds and @s3_key_format
|
|
21
|
+
key = @s3_key_format.format(**params)
|
|
22
|
+
S3Writer.new(@s3_ds, key)
|
|
23
|
+
else
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
LogLocator.new(path, s3_writer)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -71,7 +71,7 @@ module Bricolage
|
|
|
71
71
|
'--no-password',
|
|
72
72
|
*options,
|
|
73
73
|
env: get_psql_env
|
|
74
|
-
msg =
|
|
74
|
+
msg = LogLocator.slice_last_stderr(/^psql:.*?:\d+: ERROR: (.*)/, 1) unless st.success?
|
|
75
75
|
JobResult.for_process_status(st, msg)
|
|
76
76
|
}
|
|
77
77
|
end
|