前提
項目 | 説明 |
---|---|
OS | MacOSX Yosemite 10.11.2 |
Rust | 1.5.0 |
検証日時 | 2016.01.05 |
Crate
ssh2-rsを使う
https://github.com/alexcrichton/ssh2-rs
リモートホストでlsコマンドを叩くコード例
extern crate ssh2;
use ssh2::Session;
use std::io::prelude::*;
use std::net::TcpStream;
use std::env;
static USERNAME: &'static str = "username";
static REMOTE_ADDRESS: &'static str = "127.0.0.1:22";
fn main() {
let tcp = TcpStream::connect(REMOTE_ADDRESS).unwrap();
let mut session = Session::new().unwrap();
session.handshake(&tcp).unwrap();
let privatekey_filepath = env::home_dir().unwrap().join(".ssh/id_rsa");
session.userauth_pubkey_file(USERNAME, None, privatekey_filepath.as_path(), None).unwrap();
assert!(session.authenticated());
let mut chan = session.channel_session().unwrap();
chan.exec("ls").unwrap();
let mut s = String::new();
chan.read_to_string(&mut s).unwrap();
println!("{}", s);
}
scpのコード例
extern crate ssh2;
use ssh2::Session;
use std::io::prelude::*;
use std::net::TcpStream;
use std::env;
use std::path::Path;
static USERNAME: &'static str = "username";
static REMOTE_ADDRESS: &'static str = "127.0.0.1:22";
static REMOTE_FILE: &'static str = "/path/to/remote";
static NEW_REMOTE_FILE: &'static str = "/path/to/remote.new";
fn main() {
let tcp = TcpStream::connect(REMOTE_ADDRESS).unwrap();
let mut session = Session::new().unwrap();
session.handshake(&tcp).unwrap();
let privatekey_filepath = env::home_dir().unwrap().join(".ssh/id_rsa");
session.userauth_pubkey_file(USERNAME, None, privatekey_filepath.as_path(), None).unwrap();
let (mut remote_file, stat) = session.scp_recv(Path::new(REMOTE_FILE))
.unwrap();
println!("remote file stat: {}", stat.size());
let mut contents = Vec::new();
remote_file.read_to_end(&mut contents).unwrap();
let mut new_remote_file = session.scp_send(Path::new(NEW_REMOTE_FILE),
0o644,
stat.size(),
None)
.unwrap();
new_remote_file.write_all(&contents).unwrap();
}
注意点
TcpStream
やSession
をつくって認証するところをlib.rs
に切り出して共通化(モジュール作ってget_session
的な関数に)しようとしたが、TCPのライフサイクルが関数内しか保持できないため、叶わぬ夢になってしまった。
良い方法をご存知の方いれば教えていただきたく。
[2016.01.06追記]
TCPのライフサイクルが関数内しか保持できないため、叶わぬ夢になってしまった。
ここは私の理解不足で、TcpStream
をもった変数(サンプル内のtcp
にあたるもの)の寿命を考慮できていないことが原因でした。