ansibleでmysqlにinsertしたらData too long for columnだけど手動だと成功する

結論: 環境変数 LANG (LC_ALL) を UTF-8 対応のにする


やりたかったこと: mysql -uuser -ppassword < insert_data.sql のansible化

ansibleではこのようなタスクを定義:

- name: insert data
  shell: mysql -uuser -ppassword < insert_data.sql

実行するとエラー

mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1406 (22001) at line 6: Data too long for column 'hoge' at row 1
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1452 (23000) at line 3: Cannot add or update a child row: a foreign key constraint fails (`huga`.`piyo`, CONSTRAINT `piyo_1` FOREIGN KEY (`puyo`) REFERENCES `puyo` (`poyo`))

(パスワード直書きはこの際置いておく)

ググると、 Data too long エラーの解決策は、sql_mode を strict じゃないのにするといいらしい。
しかし、同じデータを使っている他のサーバの sql_mode は全く同じ内容で、しかも strict も存在する。

謎すぎるためとりあえずシェルに入って手動で実行してみる。

$ mysql -uuser -ppassword < insert_data.sql

…できた。??

手動ではできたということは、コマンドの実行環境が違う疑いが持てる。

# ログインシェルのbashで試行
- name: shell with login shell
  shell: bash -lc "mysql -uuser -ppassword < insert_data.sql"

# become (sudo) なしで試行
- name: shell without become
  shell: mysql -uuser -ppassword < insert_data.sql
  become: no

どちらもだめ。

仕方ないので現在の変数定義をみてみる。

- name: show login shell environments
  shell: bash -lc declare
  become: no

手動でシェルに入って見てみた分と比較。(どちらも一部抜粋)

--- 手動でシェルに入った分
+++ ansibleでの分

-BASH=/bin/bash
-BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:globasciiranges:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
+BASH=/usr/bin/bash
+BASHOPTS=checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
 IFS=$' \t\n'
-LANG=C.UTF-8
+LANG=C
+LC_ALL=C
+LC_CTYPE=C.UTF-8
+LC_MESSAGES=C

BASHOPTSが微妙に違うな〜などと見ていると、あれ、LANG系が全然違うぞと。
そういえばinsertするデータは日本語が入ってたなと。

試しにLANGをCにして実行してみる

LANG=C mysql -uuser -ppassword < insert_data.sql

無事に失敗!

ということで犯人はansibleが勝手に環境変数を変えた結果のLANGでした。

なのでansibleではこのようなタスクを定義して対処:

- name: insert data
  shell: LC_ALL=C.UTF-8 mysql -uuser -ppassword < insert_data.sql

うー、それにしてもなんで変数が変わってるのか…。

こんな記事

redj.hatenablog.com

もあることからansible側を掘らないとわからないかも。

とりあえず対処できたのでヨシ!