SSHのコマンドをRubyから実行出来たら便利ですよね。シェルスクリプトとExpectでも良いんですが.Rubyパッケージを利用するともっと書きやすくなりますよね.
インストール
gem install net-ssh
基本的な使い方
リモートサーバー内にアクセスする.
require 'rubygems' require 'net/ssh' Net::SSH.start('hostname', 'user', :password => 'password') do |ssh| puts ssh.exec! 'ls /etc/' end
公開鍵・秘密鍵を使ってログインする
Net::SSH.start('hostname', 'username', :keys => ['/path/to/private_key'], :passphrase => 'passphrase') do |ssh| end
ここまでは簡単なんですよ.チョッと突っ込んだ使い方をすると途端に難しくなる.
対話入力があると全滅
- su する
- sudo する
- rsync をする(対話的パスワード認証)
こうのはどうするか?
対話的なコンソールをNet::SSHから使って自動化する
対話コンソールに入力を流し込みたい。その為に、出入力のttyを確保する。
その為に request_pty っていうメソッドがある。
channel.request_pty do |ch, success| end
コレを使って,対話的なIntractiveShellを使うことが出来るみたい
channelってなに
net-ssh のサブクラスです。ssh の接続は複数のデータチャネルをもてるみたいです。
Channel単位で出入力を制御している。つまり対話コンソールに入力するのも出力を受信するのもChannel経由で行うようです.(よくわかってない)
ゲートウェイを踏み台にRsyncを起動するRuby
仕組みを調べるとSSHそのものに対する理解が必要なので詳しくはパスするとして.
手元のターミナルでRubyを起動して,Rubyがゲートウェイに接続し,ゲートウェイでRsyncを起動させてみる。
Terminal->Ruby->Net::SSH---->Gateway->SSH(rsync)---->Server
のような接続をする。手作業でしていた同期処理を自動化してみる。
#!/usr/bin/env ruby require 'rubygems' require 'net/ssh' Net::SSH.start('gw.example.net', 'USERNAME', :password => '****') do |ssh| command = "rsync -avz --progress /var/www/ 192.168.10.21:/var/www/\n" channel = ssh.open_channel do |ch| channel.request_pty do |ch, success| raise "Could not obtain pty " if !success end channel.exec command do |ch, success| raise "failed to execute command" unless success ch.on_data do |c, data| if data =~ /password/ then #入力ダイアログが来たら channel.send_data "****\n" #パスワードを送信する end puts data end end end ssh.loop#転送待ち end
一回動いてしまえば簡単でした.
関連
Expect コマンドで同じことをする
コマンドを自動化する expect - ブックマクロ開発に