GeekFactory

int128.hatenablog.com

Gradle SSH Plugin 2.6.0 released

Gradle SSH Plugin 2.6.0、Groovy SSH 2.6.0をリリースしました。

github.com

2.6.0の変更点

New feature

  • Add executeScript method for script execution (thanks to @matthiasbalke)
  • Add inputStream setting for command or shell (thanks to @matthiasbalke)
  • Automatically add host key to known_hosts

Bug fixes

  • Fix executeSudo works if error message is changed from default

Add executeScript method for script execution

リモートでスクリプトを実行するメソッド executeScript を追加しました。これまではファイルを転送してから実行する必要がありましたが、 executeScript では文字列で指定したスクリプトを直接実行できるようになりました。

executeScript '''#!/bin/bash -xe
echo 1
echo 2
'''

executeScript は文字列からShebangを読み取ってインタープリタを実行します。上記の例では /bin/bash -xe を実行します。そして、標準入力に文字列を流し込むことでスクリプトを実行します。

Add inputStream setting for command or shell

executeexecuteBackgroundexecuteSudo メソッドに標準入力を渡せるようになりました。前項の executeScript はこの仕組みで実現しています。

execute '/bin/sh', inputStream: '''#!/bin/sh
echo 1
echo 2
'''

executeSudo メソッドはsudoプロンプトとのやり取りがあるので実装が難しかったです。sudoプロンプトにパスワードを渡した後に標準入力にデータを渡します。ただし、パスワード認証に失敗した場合は再度プロンプトが現れることを考慮する必要があります。

Automatically add host key to known_hosts

2.6.0の目玉ともいえる機能です。これまではsshコマンドなどでknown_hostsを生成する必要がありましたが、Gradle SSH Plugin単体でknown_hostsに自動的にホストキーを追加できるようになりました。sshコマンドでいう StrictHostKeyChecking=ask ですね。

knownHosts = addHostKey(file('.ssh/known_hosts'))

これまでHost Key Checkingに起因する問題が多く寄せられていたため、この機能を追加することにしました。

実装にはだいぶ苦戦しました。苦労したのは以下の2点です。

  1. UserInfo を指定するとHost Key CheckingだけでなくUser Authenticationにも副作用がある。
  2. ゲートウェイ(踏み台)を経由する場合、トンネルのローカルポートがknown_hostsに書かれてしまう。

当初の実装では StrictHostKeyChecking=ask を指定して、JSchの UserInfo でHost Key Checkingのプロンプトにtrueを返すことでknown_hostsを更新する仕組みにしていました。しかし、この実装ではユーザ認証失敗時の例外のメッセージが Auth cancel に変わってしまいます。どうやら UserInfo がnullを返すと認証がキャンセルされたことになるようです。

また、ゲートウェイを経由する場合はトンネルのローカルポートを読み替える必要があります。 通常の方法では、known_hostsに書き出すホストを変えることは不可能です。

そこで、以下の流れに実装を変えることにしました。

  1. StrictHostKeyChecking=ask を指定してリモートホストに接続する。
  2. Host Key Checkingに成功した場合は、そのまま処理を続ける。
  3. Host Key Checkingに失敗した場合は、StrictHostKeyChecking=ask を指定してリモートホストに再接続する。そして、Host Key Repositoryに追加されたホストキーをknown_hostsに書き出す。もしゲートウェイ経由の場合はホスト名を読み替える。

テストを通っているので問題ないはずですが、もしバグを見つけたら教えてください。

Bump to Groovy 2.4.7

traitに10個以上のプロパティを含めるとコンパイルエラーになるバグが2.4.4以前に含まれるため、2.4.7に上げました。

[GROOVY-7387] Trait compilation error: IllegalArgumentException: Comparison method violates its general contract! - ASF JIRA

振り返り

StrictHostKeyCheckingやHostKeyRepositoryの挙動にだいぶ悩まされました。Server Integration Testを書いていたおかげでいろいろ試行錯誤してたどり着けたと思います。

少しずつCIの時間短縮を進めていて、5分台に乗るようになりました。Gradle 1.xサポートを廃止すればもっと短くなりそうです。