Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

YAML生成を工夫してembulkの設定ファイルを使い易く

More than 5 years have passed since last update.

embulk meetupの後にsonots先輩に何か書いてくださいよーって言われたので、
embulkに限った話ではないのですが、関連する話題なのでEmbulk Advent Calendarに書かせてもらおうと思います。

embulkは設定ファイルがYAMLです。
現時点ではテンプレート機能はまだ限定的な機能しかなくて、それ程表現力がありません。
それならもう、YAMLの生成を別に任せようと思って簡単なgemを作りました。

joker1007/yaml_master

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.ymlconfig/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なりその他のワークフローエンジンに組み込む際にも色々と工夫できるかと思います。

repro
世界59か国6,500以上の導入実績を持つCE(カスタマーエンゲージメント)プラットフォーム「Repro(リプロ)」を提供
https://repro.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away