NetOpsの自動化領域では標準的APIの不足のため、泣く泣くexpect
で対話的プログラムを実現しているケースも多いと思う。私自身あまりexpect
を使ったことはないが、expect
プログラムにはinteract
なるコマンドがありプロセス制御をユーザーに戻すことができる便利機能が実装されている1ことを知った。
spawn telnet $HOSTNAME
expect "login:"
send "$USERNAME\n"
expect "Password:"
send "$PASSWORD\n"
interact
同様の機能をRubyの標準モジュールであるnet/telnet
にも実装してみる。
要するに標準入力から送られたキーストロークをtelnetセッションへ、またtelnetセッションからの応答を標準出力に転送してやれば良いわけで、複数ソケットからの受信待ち受けにはIO.selectが使える。
module Net
class Telnet
def interact!
$stdin.raw!
loop do
rs, _ = IO.select([$stdin, @sock])
rs.each do |fh|
case fh
when $stdin
bs = fh.getc.chr
if bs == "\e"
begin
bs << fh.read_nonblock(3)
bs << fh.read_nonblock(2)
rescue IO::WaitReadable
end
end
@sock.syswrite(bs)
when @sock
bs = fh.readpartial(1024)
$stdout.syswrite(bs)
end
end
end
rescue EOFError
$stdout.puts "\r\n", "Conneciton closed."
self.close
ensure
$stdin.cooked!
end
end
end
# 冒頭のexpectプログラムと同様
session = Net::Telnet.new('Host' => $hostname)
session.login($username, $password)
session.interact!
-
自動化領域でユーザに制御を戻すのは負けでは?という当然の意見はこの際無視する ↩