bricolage 5.8.7
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 +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
|
+
}
|