bricolage 5.8.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +4 -0
- data/bin/bricolage +6 -0
- data/bin/bricolage-jobnet +6 -0
- data/jobclass/create.rb +21 -0
- data/jobclass/exec.rb +17 -0
- data/jobclass/insert-delta.rb +31 -0
- data/jobclass/insert.rb +33 -0
- data/jobclass/load.rb +39 -0
- data/jobclass/my-export.rb +40 -0
- data/jobclass/my-migrate.rb +103 -0
- data/jobclass/noop.rb +13 -0
- data/jobclass/rebuild-drop.rb +37 -0
- data/jobclass/rebuild-rename.rb +49 -0
- data/jobclass/s3-put.rb +19 -0
- data/jobclass/sql.rb +29 -0
- data/jobclass/td-delete.rb +20 -0
- data/jobclass/td-export.rb +30 -0
- data/jobclass/unload.rb +30 -0
- data/jobclass/wait-file.rb +48 -0
- data/lib/bricolage/application.rb +260 -0
- data/lib/bricolage/commandutils.rb +52 -0
- data/lib/bricolage/configloader.rb +126 -0
- data/lib/bricolage/context.rb +108 -0
- data/lib/bricolage/datasource.rb +144 -0
- data/lib/bricolage/eventhandlers.rb +47 -0
- data/lib/bricolage/exception.rb +47 -0
- data/lib/bricolage/filedatasource.rb +42 -0
- data/lib/bricolage/filesystem.rb +165 -0
- data/lib/bricolage/genericdatasource.rb +37 -0
- data/lib/bricolage/job.rb +212 -0
- data/lib/bricolage/jobclass.rb +98 -0
- data/lib/bricolage/jobfile.rb +100 -0
- data/lib/bricolage/jobflow.rb +389 -0
- data/lib/bricolage/jobnetrunner.rb +264 -0
- data/lib/bricolage/jobresult.rb +74 -0
- data/lib/bricolage/logger.rb +52 -0
- data/lib/bricolage/mysqldatasource.rb +223 -0
- data/lib/bricolage/parameters.rb +653 -0
- data/lib/bricolage/postgresconnection.rb +78 -0
- data/lib/bricolage/psqldatasource.rb +449 -0
- data/lib/bricolage/resource.rb +68 -0
- data/lib/bricolage/rubyjobclass.rb +42 -0
- data/lib/bricolage/s3datasource.rb +144 -0
- data/lib/bricolage/script.rb +120 -0
- data/lib/bricolage/sqlstatement.rb +351 -0
- data/lib/bricolage/taskqueue.rb +156 -0
- data/lib/bricolage/tddatasource.rb +116 -0
- data/lib/bricolage/variables.rb +208 -0
- data/lib/bricolage/version.rb +4 -0
- data/lib/bricolage.rb +8 -0
- data/libexec/sqldump +9 -0
- data/libexec/sqldump.Darwin +0 -0
- data/libexec/sqldump.Linux +0 -0
- data/test/all.rb +3 -0
- data/test/home/config/development/database.yml +57 -0
- data/test/home/config/development/password.yml +2 -0
- data/test/home/subsys/separated.job +1 -0
- data/test/home/subsys/separated.sql +1 -0
- data/test/home/subsys/unified.jobnet +1 -0
- data/test/home/subsys/unified.sql.job +5 -0
- data/test/test_filesystem.rb +19 -0
- data/test/test_parameters.rb +401 -0
- data/test/test_variables.rb +114 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: afb5228b706d506b2b2f7b468f216f76cdd82dc9
|
4
|
+
data.tar.gz: 9c947de18235c29e7db2b3a7b54fa095f8bf2335
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3759c24eda01c02d78d0f3724c14254dc8dd8b687fc0bdd82869ec3db4ef9120b6cff2a5312533a04ef79d912fc9be96191edde3a81e0f79477783fc563245e9
|
7
|
+
data.tar.gz: 3873fafbb3f9dbbec2b2a38afbcbe4f2230ecd1f4467c421ceb37717a6be6723fa111a456c568adf03353471e9c3f5a89ecee9d1d649b02248b95d24858b36d0
|
data/README.md
ADDED
data/bin/bricolage
ADDED
data/jobclass/create.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
JobClass.define('create') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'CREATE TABLE file.')
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
|
6
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
|
7
|
+
params.add DataSourceParam.new('sql')
|
8
|
+
}
|
9
|
+
|
10
|
+
declarations {|params|
|
11
|
+
params['table-def'].declarations
|
12
|
+
}
|
13
|
+
|
14
|
+
script {|params, script|
|
15
|
+
script.task(params['data-source']) {|task|
|
16
|
+
task.drop_force_if params['drop']
|
17
|
+
task.exec params['table-def']
|
18
|
+
task.analyze_if params['analyze']
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
data/jobclass/exec.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
JobClass.define('exec') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add StringListParam.new('args', 'ARG', 'Command line arguments.')
|
4
|
+
}
|
5
|
+
|
6
|
+
script {|params, script|
|
7
|
+
script.task(params.generic_ds) {|task|
|
8
|
+
task.action(params['args'].join(' ')) {|ds|
|
9
|
+
ds.logger.info '[CMD] ' + params['args'].join(' ')
|
10
|
+
system(*params['args'])
|
11
|
+
st = $?
|
12
|
+
ds.logger.info "status=#{st.exitstatus}"
|
13
|
+
JobResult.for_bool(st.exitstatus == 0)
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
JobClass.define('insert-delta') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add StringParam.new('delete-cond', 'SQL_EXPR', 'DELETE condition.')
|
7
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
|
8
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
9
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
10
|
+
params.add DataSourceParam.new('sql')
|
11
|
+
}
|
12
|
+
|
13
|
+
parameters_filter {|job|
|
14
|
+
job.provide_sql_file_by_job_id
|
15
|
+
}
|
16
|
+
|
17
|
+
declarations {|params|
|
18
|
+
params['sql-file'].declarations
|
19
|
+
}
|
20
|
+
|
21
|
+
script {|params, script|
|
22
|
+
script.task(params['data-source']) {|task|
|
23
|
+
task.transaction {
|
24
|
+
task.exec SQLStatement.delete_where(params['delete-cond'])
|
25
|
+
task.exec params['sql-file']
|
26
|
+
}
|
27
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort']
|
28
|
+
task.analyze_if params['analyze']
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
data/jobclass/insert.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
JobClass.define('insert') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.', optional: true)
|
7
|
+
params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
|
8
|
+
params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
|
9
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
|
10
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
11
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
12
|
+
params.add DataSourceParam.new('sql')
|
13
|
+
}
|
14
|
+
|
15
|
+
parameters_filter {|job|
|
16
|
+
job.provide_sql_file_by_job_id
|
17
|
+
}
|
18
|
+
|
19
|
+
declarations {|params|
|
20
|
+
params['sql-file'].declarations
|
21
|
+
}
|
22
|
+
|
23
|
+
script {|params, script|
|
24
|
+
script.task(params['data-source']) {|task|
|
25
|
+
task.truncate_if params['truncate']
|
26
|
+
task.drop_force_if params['drop']
|
27
|
+
task.exec params['table-def'] if params['table-def']
|
28
|
+
task.exec params['sql-file']
|
29
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort']
|
30
|
+
task.analyze_if params['analyze']
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
data/jobclass/load.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'bricolage/psqldatasource'
|
2
|
+
|
3
|
+
JobClass.define('load') {
|
4
|
+
parameters {|params|
|
5
|
+
params.add DataSourceParam.new('s3', 'src-ds', 'Input data source.')
|
6
|
+
params.add SrcFileParam.new
|
7
|
+
params.add DataSourceParam.new('sql', 'dest-ds', 'Target data source.')
|
8
|
+
params.add DestTableParam.new(optional: false)
|
9
|
+
params.add EnumParam.new('format', %w(tsv json), 'Data file format.', default: 'tsv')
|
10
|
+
params.add StringParam.new('jsonpath', 'PATH', 'jsonpath to specify columns of json format records', optional: true)
|
11
|
+
params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
|
12
|
+
optional: true, default: PSQLLoadOptions.new,
|
13
|
+
value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
|
14
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.', optional: true)
|
15
|
+
params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
|
16
|
+
params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
|
17
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
|
18
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
19
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
20
|
+
params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed. (required keys: privilege, to)')
|
21
|
+
}
|
22
|
+
|
23
|
+
declarations {|params|
|
24
|
+
Declarations.new("dest_table" => nil)
|
25
|
+
}
|
26
|
+
|
27
|
+
script {|params, script|
|
28
|
+
script.task(params['dest-ds']) {|task|
|
29
|
+
task.drop_force_if params['drop']
|
30
|
+
task.exec params['table-def'] if params['table-def']
|
31
|
+
task.truncate_if params['truncate']
|
32
|
+
task.load params['src-ds'], params['src-file'], params['dest-table'],
|
33
|
+
params['format'], params['jsonpath'], params['options']
|
34
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort']
|
35
|
+
task.analyze_if params['analyze']
|
36
|
+
task.grant_if params['grant'], params['dest-table']
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
JobClass.define('my-export') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new(optional: true)
|
4
|
+
params.add DestFileParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add EnumParam.new('format', %w(json tsv csv), 'Target file format.', default: 'json')
|
7
|
+
params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.')
|
8
|
+
params.add OptionalBoolParam.new('override', 'If true, clears target file. Otherwise causes error.')
|
9
|
+
params.add OptionalBoolParam.new('sqldump', 'If true, clears use sqldump command to dump, only wheen usable.')
|
10
|
+
params.add DataSourceParam.new('mysql')
|
11
|
+
}
|
12
|
+
|
13
|
+
declarations {|params|
|
14
|
+
sql_statement(params).declarations
|
15
|
+
}
|
16
|
+
|
17
|
+
script {|params, script|
|
18
|
+
script.task(params['data-source']) {|task|
|
19
|
+
task.export sql_statement(params),
|
20
|
+
path: params['dest-file'],
|
21
|
+
format: params['format'],
|
22
|
+
override: params['override'],
|
23
|
+
gzip: params['gzip'],
|
24
|
+
sqldump: params['sqldump']
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
def sql_statement(params)
|
29
|
+
if sql = params['sql-file']
|
30
|
+
sql
|
31
|
+
else
|
32
|
+
srcs = params['src-tables']
|
33
|
+
raise ParameterError, "src-tables must be singleton when no sql-file is given" unless srcs.size == 1
|
34
|
+
src_table_var = srcs.keys.first
|
35
|
+
stmt = SQLStatement.for_string("select * from $#{src_table_var};")
|
36
|
+
stmt.declarations = Declarations.new({src_table_var => src_table_var})
|
37
|
+
stmt
|
38
|
+
end
|
39
|
+
end
|
40
|
+
}
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'bricolage/psqldatasource'
|
2
|
+
|
3
|
+
JobClass.define('my-migrate') {
|
4
|
+
parameters {|params|
|
5
|
+
# Export
|
6
|
+
params.add SrcTableParam.new(optional: false)
|
7
|
+
params.add DataSourceParam.new('mysql', 'src-ds', 'Source data source.')
|
8
|
+
params.add DestFileParam.new('tmp-file', 'PATH', 'Temporary local file path.')
|
9
|
+
params.add OptionalBoolParam.new('sqldump', 'If true, use sqldump command to dump, only on available.', default: true)
|
10
|
+
|
11
|
+
# Put
|
12
|
+
params.add DestFileParam.new('s3-file', 'PATH', 'Temporary S3 file path.')
|
13
|
+
params.add DataSourceParam.new('s3', 's3-ds', 'Temporary file storage.')
|
14
|
+
params.add OptionalBoolParam.new('override', 'If true, overwrite s3 target file. Otherwise causes error.')
|
15
|
+
|
16
|
+
# Load
|
17
|
+
params.add DestTableParam.new(optional: false)
|
18
|
+
params.add DataSourceParam.new('sql', 'dest-ds', 'Destination data source.')
|
19
|
+
params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
|
20
|
+
optional: true, default: PSQLLoadOptions.new,
|
21
|
+
value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
|
22
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
|
23
|
+
|
24
|
+
# Misc
|
25
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
|
26
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
27
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
28
|
+
params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed.')
|
29
|
+
|
30
|
+
# All
|
31
|
+
params.add OptionalBoolParam.new('export', 'Runs EXPORT task.')
|
32
|
+
params.add OptionalBoolParam.new('put', 'Runs PUT task.')
|
33
|
+
params.add OptionalBoolParam.new('load', 'Runs LOAD task.')
|
34
|
+
params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.', default: true)
|
35
|
+
}
|
36
|
+
|
37
|
+
declarations {|params|
|
38
|
+
decls = sql_statement(params).declarations
|
39
|
+
decls.declare 'dest-table', nil
|
40
|
+
decls
|
41
|
+
}
|
42
|
+
|
43
|
+
script {|params, script|
|
44
|
+
run_all = !params['export'] && !params['put'] && !params['load']
|
45
|
+
|
46
|
+
# Export
|
47
|
+
if params['export'] || run_all
|
48
|
+
script.task(params['src-ds']) {|task|
|
49
|
+
task.export sql_statement(params),
|
50
|
+
path: params['tmp-file'],
|
51
|
+
format: 'json',
|
52
|
+
override: true,
|
53
|
+
gzip: params['gzip'],
|
54
|
+
sqldump: params['sqldump']
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Put
|
59
|
+
if params['put'] || run_all
|
60
|
+
script.task(params['s3-ds']) {|task|
|
61
|
+
task.put params['tmp-file'], params['s3-file'], check_args: false
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Load
|
66
|
+
if params['load'] || run_all
|
67
|
+
script.task(params['dest-ds']) {|task|
|
68
|
+
prev_table = '${dest_table}_old'
|
69
|
+
work_table = '${dest_table}_wk'
|
70
|
+
|
71
|
+
# CREATE
|
72
|
+
task.drop_force prev_table
|
73
|
+
task.drop_force work_table
|
74
|
+
task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table)
|
75
|
+
|
76
|
+
# COPY
|
77
|
+
task.load params['s3-ds'], params['s3-file'], work_table,
|
78
|
+
'json', nil, params['options'].merge('gzip' => params['gzip'])
|
79
|
+
|
80
|
+
# VACUUM, ANALYZE, GRANT
|
81
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort'], work_table
|
82
|
+
task.analyze_if params['analyze'], work_table
|
83
|
+
task.grant_if params['grant'], work_table
|
84
|
+
|
85
|
+
# RENAME
|
86
|
+
task.create_dummy_table '${dest_table}'
|
87
|
+
task.transaction {
|
88
|
+
task.rename_table params['dest-table'].to_s, "#{params['dest-table'].name}_old"
|
89
|
+
task.rename_table work_table, params['dest-table'].name
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
}
|
94
|
+
|
95
|
+
def sql_statement(params)
|
96
|
+
srcs = params['src-tables']
|
97
|
+
raise ParameterError, "src-tables must be singleton when no sql-file is given" unless srcs.size == 1
|
98
|
+
src_table_var = srcs.keys.first
|
99
|
+
stmt = SQLStatement.for_string("select * from $#{src_table_var};")
|
100
|
+
stmt.declarations = Declarations.new({src_table_var => src_table_var})
|
101
|
+
stmt
|
102
|
+
end
|
103
|
+
}
|
data/jobclass/noop.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
JobClass.define('noop') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add OptionalBoolParam.new('failure', 'Finish with failure or not.')
|
4
|
+
}
|
5
|
+
|
6
|
+
script {|params, script|
|
7
|
+
script.task(params.generic_ds) {|task|
|
8
|
+
task.action('return !$failure') {
|
9
|
+
JobResult.for_bool(!params['failure'])
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
JobClass.define('rebuild-drop') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
|
7
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
|
8
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
9
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
10
|
+
params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed. (required keys: on, to)')
|
11
|
+
params.add DataSourceParam.new('sql')
|
12
|
+
}
|
13
|
+
|
14
|
+
parameters_filter {|job|
|
15
|
+
job.provide_sql_file_by_job_id
|
16
|
+
}
|
17
|
+
|
18
|
+
declarations {|params|
|
19
|
+
params['sql-file'].declarations
|
20
|
+
}
|
21
|
+
|
22
|
+
script {|params, script|
|
23
|
+
script.task(params['data-source']) {|task|
|
24
|
+
# CREATE
|
25
|
+
task.drop_force params['dest-table']
|
26
|
+
task.exec params['table-def']
|
27
|
+
|
28
|
+
# INSERT
|
29
|
+
task.exec params['sql-file']
|
30
|
+
|
31
|
+
# VACUUM, ANALYZE, GRANT
|
32
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort'], params['dest-table']
|
33
|
+
task.analyze_if params['analyze'], params['dest-table']
|
34
|
+
task.grant_if params['grant'], params['dest-table']
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
JobClass.define('rebuild-rename') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
|
7
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
|
8
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
9
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
10
|
+
params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed.')
|
11
|
+
params.add DataSourceParam.new('sql')
|
12
|
+
}
|
13
|
+
|
14
|
+
parameters_filter {|job|
|
15
|
+
job.provide_sql_file_by_job_id
|
16
|
+
}
|
17
|
+
|
18
|
+
declarations {|params|
|
19
|
+
params['sql-file'].declarations
|
20
|
+
}
|
21
|
+
|
22
|
+
script {|params, script|
|
23
|
+
script.task(params['data-source']) {|task|
|
24
|
+
prev_table = '${dest_table}_old'
|
25
|
+
work_table = '${dest_table}_wk'
|
26
|
+
|
27
|
+
# CREATE
|
28
|
+
task.drop_force prev_table
|
29
|
+
task.drop_force work_table
|
30
|
+
task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table)
|
31
|
+
|
32
|
+
# INSERT
|
33
|
+
task.exec params['sql-file'].replace(/\$\{?dest_table\}?\b/, work_table)
|
34
|
+
|
35
|
+
# VACUUM, ANALYZE, GRANT
|
36
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort'], work_table
|
37
|
+
task.analyze_if params['analyze'], work_table
|
38
|
+
task.grant_if params['grant'], work_table
|
39
|
+
|
40
|
+
# RENAME
|
41
|
+
task.create_dummy_table '$dest_table'
|
42
|
+
task.transaction {
|
43
|
+
dest_table = params['dest-table']
|
44
|
+
task.rename_table dest_table.to_s, "#{dest_table.name}_old"
|
45
|
+
task.rename_table "#{dest_table}_wk", dest_table.name
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
data/jobclass/s3-put.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
JobClass.define('s3-put') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add DestFileParam.new
|
4
|
+
params.add SrcFileParam.new
|
5
|
+
params.add OptionalBoolParam.new('remove', 'Removes source files after PUT is succeeded.')
|
6
|
+
params.add DataSourceParam.new('s3')
|
7
|
+
}
|
8
|
+
|
9
|
+
script {|params, script|
|
10
|
+
script.task(params['data-source']) {|task|
|
11
|
+
task.put params['src-file'], params['dest-file']
|
12
|
+
}
|
13
|
+
if params['remove']
|
14
|
+
script.task(params.file_ds) {|task|
|
15
|
+
task.remove params['src-file']
|
16
|
+
}
|
17
|
+
end
|
18
|
+
}
|
19
|
+
}
|
data/jobclass/sql.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
JobClass.define('sql') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestTableParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
|
7
|
+
params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
|
8
|
+
params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
|
9
|
+
params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
|
10
|
+
params.add DataSourceParam.new('sql')
|
11
|
+
}
|
12
|
+
|
13
|
+
parameters_filter {|job|
|
14
|
+
job.provide_sql_file_by_job_id
|
15
|
+
}
|
16
|
+
|
17
|
+
declarations {|params|
|
18
|
+
params['sql-file'].declarations
|
19
|
+
}
|
20
|
+
|
21
|
+
script {|params, script|
|
22
|
+
script.task(params['data-source']) {|task|
|
23
|
+
task.truncate_if params['truncate']
|
24
|
+
task.exec params['sql-file']
|
25
|
+
task.vacuum_if params['vacuum'], params['vacuum-sort']
|
26
|
+
task.analyze_if params['analyze']
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
JobClass.define('td-delete') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add DestTableParam.new(optional: false)
|
4
|
+
params.add DataSourceParam.new('td')
|
5
|
+
params.add DateParam.new('from', 'DATE', 'Start date of logs to delete (%Y-%m-%d).')
|
6
|
+
params.add DateParam.new('to', 'DATE', 'End date of logs to delete (%Y-%m-%d).')
|
7
|
+
}
|
8
|
+
|
9
|
+
declarations {|params|
|
10
|
+
Declarations.new("dest_table" => nil)
|
11
|
+
}
|
12
|
+
|
13
|
+
script {|params, script|
|
14
|
+
script.task(params['data-source']) {|task|
|
15
|
+
task.delete params['dest-table'],
|
16
|
+
from: params['from'],
|
17
|
+
to: params['to']
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
JobClass.define('td-export') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add SQLFileParam.new
|
4
|
+
params.add DestFileParam.new
|
5
|
+
params.add SrcTableParam.new
|
6
|
+
params.add StringParam.new('src-database', 'NAME', 'Source TD database name.', optional: true)
|
7
|
+
params.add EnumParam.new('format', %w(msgpack tsv csv json), 'Target file format.', default: 'msgpack')
|
8
|
+
params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.')
|
9
|
+
params.add OptionalBoolParam.new('override', 'If true, clears target file. Otherwise causes error.')
|
10
|
+
params.add DataSourceParam.new('td')
|
11
|
+
}
|
12
|
+
|
13
|
+
parameters_filter {|job|
|
14
|
+
job.provide_sql_file_by_job_id
|
15
|
+
}
|
16
|
+
|
17
|
+
declarations {|params|
|
18
|
+
params['sql-file'].declarations
|
19
|
+
}
|
20
|
+
|
21
|
+
script {|params, script|
|
22
|
+
script.task(params['data-source']) {|task|
|
23
|
+
task.export params['sql-file'],
|
24
|
+
path: params['dest-file'],
|
25
|
+
format: params['format'],
|
26
|
+
gzip: params['gzip'],
|
27
|
+
override: params['override']
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
data/jobclass/unload.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'bricolage/psqldatasource'
|
2
|
+
|
3
|
+
JobClass.define('unload') {
|
4
|
+
parameters {|params|
|
5
|
+
params.add SQLFileParam.new
|
6
|
+
params.add DataSourceParam.new('sql', 'src-ds', 'Input data source (sql).')
|
7
|
+
params.add SrcTableParam.new(optional: false)
|
8
|
+
params.add DataSourceParam.new('s3', 'dest-ds', 'Target data source (s3).')
|
9
|
+
params.add DestFileParam.new
|
10
|
+
params.add EnumParam.new('format', %w(tsv), 'Data file format.', default: 'tsv')
|
11
|
+
params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
|
12
|
+
optional: true, default: PSQLLoadOptions.new,
|
13
|
+
value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
|
14
|
+
}
|
15
|
+
|
16
|
+
parameters_filter {|job|
|
17
|
+
job.provide_sql_file_by_job_id
|
18
|
+
}
|
19
|
+
|
20
|
+
declarations {|params|
|
21
|
+
params['sql-file'].declarations
|
22
|
+
}
|
23
|
+
|
24
|
+
script {|params, script|
|
25
|
+
script.task(params['src-ds']) {|task|
|
26
|
+
task.unload params['sql-file'], params['dest-ds'], params['dest-file'],
|
27
|
+
params['format'], params['options']
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
JobClass.define('wait-file') {
|
2
|
+
parameters {|params|
|
3
|
+
params.add DestFileParam.new
|
4
|
+
params.add StringParam.new('condition-expr', 'RUBY_EXPR', 'Wait condition expression (in Ruby). (default: check file existance)', optional: true)
|
5
|
+
params.add StringParam.new('max-wait-minutes', 'NUM', 'Max waiting minutes.')
|
6
|
+
}
|
7
|
+
|
8
|
+
script {|params, script|
|
9
|
+
script.task(params.generic_ds) {|task|
|
10
|
+
dest_file = params['dest-file']
|
11
|
+
max_wait_minutes = params['max-wait-minutes'].to_i
|
12
|
+
|
13
|
+
default_expr = "File.exist?('#{dest_file}')"
|
14
|
+
condition_expr = params['condition-expr'] || default_expr
|
15
|
+
|
16
|
+
task.action("wait #{dest_file} (condition: #{condition_expr})") {|ds|
|
17
|
+
wait_file_condition(dest_file, condition_expr, max_wait_minutes, ds.logger)
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
REPORT_INTERVAL = 90 # 15 min
|
23
|
+
WAIT_INTERVAL = 5
|
24
|
+
|
25
|
+
def wait_file_condition(dest_file, condition_expr, max_wait_minutes, logger)
|
26
|
+
logger.info "waiting file by { #{condition_expr} }"
|
27
|
+
|
28
|
+
# DO NOT CHANGE these variables name; they are condition expression interface.
|
29
|
+
start_time = Time.now
|
30
|
+
wait_limit = start_time + max_wait_minutes * 60
|
31
|
+
last_log_time = start_time
|
32
|
+
|
33
|
+
until eval(condition_expr)
|
34
|
+
now = Time.now
|
35
|
+
if now > wait_limit
|
36
|
+
logger.error "exceeded wait limit (#{max_wait_minutes} minutes); abort"
|
37
|
+
return JobResult.for_bool(false)
|
38
|
+
end
|
39
|
+
if now - last_log_time > REPORT_INTERVAL
|
40
|
+
logger.info "waiting..."
|
41
|
+
last_log_time = Time.now
|
42
|
+
end
|
43
|
+
sleep WAIT_INTERVAL
|
44
|
+
end
|
45
|
+
logger.info "condition fullfilled"
|
46
|
+
JobResult.for_bool(true)
|
47
|
+
end
|
48
|
+
}
|