embulk meetupの後にsonots先輩に何か書いてくださいよーって言われたので、
embulkに限った話ではないのですが、関連する話題なのでEmbulk Advent Calendarに書かせてもらおうと思います。
embulkは設定ファイルがYAMLです。
現時点ではテンプレート機能はまだ限定的な機能しかなくて、それ程表現力がありません。
それならもう、YAMLの生成を別に任せようと思って簡単なgemを作りました。
YAMLの設定ファイルの大本になるマスターファイルを作っておいて、そこから特定の範囲だけを別のYAMLとして出力するだけのgemです。
その際にerbでRubyを埋め込めるようにしているので、Rubyで表現できることは何でもできます。
環境変数から日付を取ってそれをRangeにしてループしたり、ActiveRecordからSQL作ったりとか。
まあ、そもそものモチベーションとしては、RailsアプリにもDBの認証情報とかAPIトークンをyamlで書いていて、その他のSQLバッチを実行するフレームワークにも同じこと書いていて、更にembulkの設定も別ファイルで書いていて、という状態が嫌だったから作ったものです。
アプリ毎に微妙にキー名違ってて互換性無いし……。
なので、こっちで一回ラップして、そっから吐くという形にしたものです。
簡単な例だと以下の様なmaster.yml
を書いておきます。
yaml_master:
database_yml: <%= ENV["CONFIG_DIR"] %>/database.yml
embulk_yml: <%= ENV["CONFIG_DIR"] %>/embulk.yml
database_config: &database_config
development: &database_development
adapter: mysql2
encoding: utf8
database: development
pool: 5
host: &database_development_host
username: &database_development_username root
password: &database_development_password
socket: /tmp/mysql.sock
test: &database_test
adapter: mysql2
encoding: utf8
database: test
host: &database_test_host
username: &database_test_username root
password: &database_test_password
production: &database_production
adapter: mysql2
encoding: utf8
database: production
pool: 5
host: &database_production_host "192.168.1.100"
username: &database_production_username root
password: &database_production_password
socket: /tmp/mysql.sock
data:
database_yml:
<<: *database_config
embulk_yml:
in:
type: file
path_prefix: example.csv
parser:
type: csv
skip_header_lines: 1
columns:
- {name: key_name, type: string}
- {name: day, type: timestamp, format: '%Y-%m-%d'}
- {name: new_clients, type: long}
out:
type: mysql
host: *database_<%= ENV["RAILS_ENV"] %>_host
user: *database_<%= ENV["RAILS_ENV"] %>_username
password: *database_<%= ENV["RAILS_ENV"] %>_password
database: my_database
table: my_table
mode: insert
その後、以下のようにコマンドを打ちます。
$ RAILS_ENV=production CONFIG_DIR="config" yaml_master -m master.yml --all
こうすると、yaml_master
というブロックにあるキー名と一致するyamlの中身をdata
ブロックから引っ張ってきて、それをvalueをファイル名として出力します。
上記の例だとconfig/database.yml
とconfig/embulk.yml
が出力されます。
その際、まずERBを評価してYAMLにした後、YAMLのエイリアス機能を使って記述内容を再利用します。
また、特定の設定だけをファイル名をして出力することもできます。
$ RAILS_ENV=production CONFIG_DIR="config" yaml_master -m master.yml -k embulk_yml -o embulk_config.yml
# -o オプションが無い場合は標準出力
その他の機能
組み込みのヘルパーメソッド
その他の機能としては、ERBで使える組み込みのヘルパーメソッドがあって、masterファイルのフルパスが取れたりHOMEディレクトリのパスが取れたり、ファイルが存在する時だけ中身を読み取って文字列を出力する、といった処理が書けます。
詳しくはテストコードを見てください。
実行時変数として使えるプロパティを指定する
$ RAILS_ENV=production CONFIG_DIR="config" yaml_master -m master.yml -k embulk_yml -p "foo=bar,hoge=fuga"
という感じで-p
もしくは--properties
オプションでプロパティを渡せます。
このプロパティはERB内でproperties["foo"]
という形で参照できます。
別のyamlファイルをincludeして読み込む
一つのマスターファイルに何でも書くと、とても長くなってしまいそうなので、別のyamlファイルをincludeして埋め込めるようにしました。
ただ、現時点ではYAMLのエイリアス機能が共通化できてないので、イマイチな感じです。
これぐらいの表現力があれば、cronなりその他のワークフローエンジンに組み込む際にも色々と工夫できるかと思います。