chefのscriptでexpectを使う
対話型のインストーラをchefで動かす。ということでレシピ中にscriptリソースを使ってexpectでスクリプトを作成しました。複数台に対してインストーラを実施するのですが、それぞれの機器で与える文字列が少しづつ違う。
expectの-cオプションで与えるコマンド中に差分を反映させるための変数を与えるため、expect -c に続くコマンド文字列はダブルクオートである必要があります。シングルクオートだと変数展開してくれませんからね。
故に、書き出しとしてはこんな感じ。
script "hogehoge" do interperter "bash" user "root" group "root" code <<-EOH /usr/bin/expect -c " set timeout -1 spawn /home/hoge/installer.sh expect { -re \"Enter license code.*\"{ (以下略)
/usr/bin/expectに与えるコマンドをダブルクオートで囲っているので、コマンド中のダブルクオートはバックスラッシュでクオートしてあげる必要があります。
ところが、これをchef経由で動かすと動かない。
---- Begin output of "bash" "/tmp/chef-script20150326-24613-1f8qbh4" ---- STDOUT: spawn scp /tmp/mm.sh 10.231.1.21:/tmp/hoge.sh STDERR: missing close-brace while executing "expect { -re Enter" couldn't read file "license": no such file or directory
どうも-re expect の次のダブルクオートがちゃんとクオートでされてないみたい。
chefではscriptリソース部分はcode <<-EOH 〜EOHで囲まれた部分を/tmp以下のファイルに書き出してそれをinterpeterで指定されたものに引数として渡して実行しています。
上記のエラーでいうと
---- Begin output of "bash" "/tmp/chef-script20150326-24613-1f8qbh4" ----
のところですね。chefの動作を途中で停止して/tmpにできるファイルの中身を参照してみると、こうなっていました。
/usr/bin/expect -c " set timeout -1 spawn /home/hoge/installer.sh expect { -re "Enter license code.*"{ (後略)
ふーむ、chefが書き出すときにクオートが抜けちゃってるみたいです。
そうすると、バックスラッシュもクオートする必要があるってことですね。
レシピを以下に修正。
script "hogehoge" do interperter "bash" user "root" group "root" code <<-EOH /usr/bin/expect -c " set timeout -1 spawn /home/hoge/installer.sh expect { -re \\"Enter license code.*\\"{
これでちゃんと動作しました。ということでchefのscriptでexpectを書くときはバックスラッシュもクオートしましょうというお話でした。