こんばんは。
今日はVagrant+シェルスクリプトでアプリケーションの実行環境の作成してる時に困った話をします
環境作成にchefやpuppet, ansibleを使わずシェルスクリプトを使っているのですが、アプリケーションをgit cloneする時に
Are you sure you want to continue connecting (yes/no)?
とか
Enter passphrase for key '/path/to/key/private_key':
聞くなよやってるのはvagrantだy
などのプロンプトが出てきて、 vagrant up中にインストール出来ず嫌だなーと思ったので対処法を探しました。そしてたどり着いたのが、 expectコマンド
ということで、お試しにgit cloneを自動化してみました。
作ったレポジトリ
概要
expectコマンドを利用して、vagrant上に自分自身のレポジトリ GitHub - ara-ta3/expect-command-getting-started をcloneしてきます。
準備
expectコマンドとgitをインストールします。
yum install -y expect git
やったこと
#! /bin/sh password=`cat /vagrant/script/keys/password_for_private_key` # パスワードはtextファイルに事前に書いておきます。 repo=git@github.com:tarata/expect-command-getting-started.git expect_message_ssh="Are you sure you want to continue connecting (yes/no)?" expect_message_key_password="Enter passphrase for key '/home/vagrant/.ssh/private_key_for_github': " # 秘密鍵の設定は別で行っています。 # https://github.com/tarata/expect-command-getting-started/blob/master/script/install/vagrant/install-keys.sh expect -c " set timeout -1 spawn git clone $repo expect \"${expect_message_ssh}\" { send \"yes\n\" expect \"${expect_message_key_password}\" send \"${password}\n\" expect \"${expect_message_key_password}\" { set timeout 1 } \"*$\"; } \"${expect_message_key_password}\" { send \"${password}\n\" expect \"${expect_message_key_password}\" { set timeout 1 } \"*$\"; } " if [ ! -d $HOME/`basename ${repo%.git}` ]; then echo "\n" echo "failed to git clone" fi
主な部分はexpect -c 以降の部分です。
expect \"hogehoge\"
とやれば「hogehogeという文字が標準出力に出現したら」という意味になります。
{}を利用することで条件分岐が出来るようです。
条件分岐というとif文が出てきたのですが、イメージ的にはswitch文が近いかと思います。
なので、expectの部分をなんとなく、switchに直すと
git clone $repo switch (標準出力) { case 初ssh時に出る出力(${expect_message_ssh}) yes\nと打つ; switch(標準出力) { case パスワード入力(${expect_message_key_password}): [パスワード]\nと打つ; switch(標準出力) { case パスワード入力(${expect_message_key_password}): タイムアウトを1秒にする(パスワードが間違ってるため止める処理); break; default: break; } break; default: break; case パスワード入力(${expect_message_key_password}): [パスワード]\nと打つ; switch(標準出力) { case パスワード入力(${expect_message_key_password}): タイムアウトを1秒にする(パスワードが間違ってるため止める処理); break; default: break; } }
みたいな対応かと・・・(わかりづらい・・・?w
という感じに事前に鍵の準備とパスワードをどこかに記載する必要は当然必要になりますが、プロンプトが出るようなものであったとしても自動化できます。
色々やって困ったこと
expectの条件分岐を使ってるんだけど、なぜか2つ目の条件分岐に引っかからない
expect hoge { ...何らかの処理 } expect fuga { # expectがいらない }
となっていた。
case文的な感じなので、expectはいらない。つまり
expect hoge { ...何らかの処理 } fuga { }
みたいな感じです。
プロンプトも操れるようになったので、もうなんでも出来る気がします←
上にも書いちゃいましたが、こちらが今回作ったレポジトリです。
GitHub - ara-ta3/expect-command-getting-started
vagrant upで一応動きは確認できます。
/path/to/project/script/keys/private_key_for_github
にgithubに登録した秘密鍵を置き、
/path/to/project/script/keys/password_for_private_key
にその秘密鍵のパスワードを記載し、
/path/to/project/script/install/vagrant/install-application.sh
のrepo変数のレポジトリを変更すれば試せるかと思います。
鍵のパスワードが無くても動く・・・はずw
追記
ssh-agentとssh_configで色々出来るよねと突っ込まれたので、メモとして書いておきます
expect_message_ssh="Are you sure you want to continue connecting (yes/no)?" expect_message_key_password="Enter passphrase for key '/home/vagrant/.ssh/private_key_for_github':
この部分を他の方法でどうにかできます。
前者はssh_config
後者はssh-agent
Are you sure you want to continue connecting (yes/no)? の対処
今、ssh_configは /home/vagrant/.ssh/config に書いていて、以下のようになってますが、
Host github.com User git Port 22 Hostname github.com IdentityFile ~/.ssh/private_key_for_github TCPKeepAlive yes IdentitiesOnly yes
StrictHostKeyChecking noを追記すれば Are you sure you want to continue connecting (yes/no)? は尋ねられなくなります。
Enter passphrase for key '/home/vagrant/... の対処
こっちはssh-agent、または、forward-agent機能(?)によって、上手くやれそうです(できてない)
思いついたやり方は2つ
- ゲストOS(VM)でssh-agentを実行し、ssh-addでgithub用の秘密鍵を登録する。
- ホストOS(VMではない本体)でssh-addを行いforward-agentによって、秘密鍵をゲストOSと共有する
このいずれかの設定ができれば、git push時などにも秘密鍵のパスワードを入力しなくていいので便利です。
2つのやり方のうち前者であれば、ゲストOSで完結するのでMacやWindowsに依らない点がメリットです
(なんだけど出来ない(´・ω・`)w
後者はホストOSで設定している鍵を利用できるので、ゲスト側で設定する必要が無いという点がメリットかなぁと思います。
ちなみに、Vagrantの場合Vagrantfileに以下を設定すればforward-agentの設定が出来るようです。
config.ssh.forward_agent = true