Bad knowhow
Authentication failure
I have hosts, that use SSH Host-Based authentication. When I write a script like below (ssh.rb), it throws Net::SSH::AuthenticationFailed.
#!/usr/local/bin/ruby require 'rubygems' require 'net/ssh' Net::SSH.start( 'target.foo.co.jp', 'daiba', :auth_methods => %w(hostbased), :keys => %w(/etc/ssh/ssh_host_dsa_key) ) do |ssh| puts ssh.exec!('hostname') end
Investigation
First, to use "hostbased authentication", your script need to read the local host's private-key. This file is read only by root, so, you must run your script with root privilege.
$ sudo ./ssh.rb
Second, Net::SSH::Authentication::Methods::Hostbased.authenticate_with method
def authenticate_with(identity, next_service, username, key_manager) debug { "trying hostbased (#{identity.fingerprint})" } client_username = ENV['USER'] || username
checks userneme by "ENV['USER']", then your script gets client_username as 'root'. I don't know why, but my host's /etc/ssh/sshd_configuration deny 'client_username = root' access. This is the problem.
Bad knowhow
I want 'client_username == username', so change the line like below.
def authenticate_with(identity, next_service, username, key_manager) debug { "trying hostbased (#{identity.fingerprint})" } # client_username = ENV['USER'] || username client_username = username
And you can run your script without Net::SSH::AuthenticationFailed.
拡張子一覧を作る
サーバにはどんなファイルがある?
ファイルサーバにどんなファイルがどれだけ入ってるのか調べてくれ,と言われました.ちょっと考えたんですが,うまいやり方を思いつかなかったので地道に手作業で調べてみたのでその手順です.
準備
まずはファイルサーバをネットワークドライブとしてAdministrator権限で接続します.そのためには,
net use \\servername password /USER:Administrator@mydomain.foo.co.jp
として,サーバに管理者権限でログインしてからGUIでネットワークドライブ接続します.net useの使い方は"net use /?"で確認できますが大したことは書いてありません.次にネットワークドライブ毎にファイル名の一覧を作成します.
Z:\>dir /B /L /OE /S /-D > c:\Documents and Settings\daiba\デスクトップ\filenames.txt
これで準備できました.dirの使い方は"dir /?"で確認できます.何気なく使ってるコマンドでも色々とオプションがあってちょっとした驚きがありますね.ま,そんなことはおいといて,必要なのは解析です.普段はperlでさくっと調べるのですが,今回はluaでやってみました.
luaプログラム
始めてなのか久しぶりなのかわからないぐらい忘れていたので単純に書いてみました.行毎に正規表現で処理して,それをテーブルに挿入し内容を書き出しています.拡張子の数の多いものから出力するようなことも考えてみたんですが,面倒になったのでそれはexcelか何かでやることにしました.
io.input("filenames.txt") suffix = {} while true do line = io.read() if (line == nil) then break end for result in string.gmatch(line, "%.%w%w%w$") do suffix[result] = suffix[result] and (suffix[result] + 1) or 1 end end for key,value in pairs(suffix) do out = string.format("%4s %d",key,value) print(out) end
終わりに
luaはなかなか癖がある言語だけど,使いこなせれば面白そうです.nmapにも組み込まれているので,色んなチェックツールを書けそうです.
use Moose
Jabber Channel Bot
Google waveでJabberを拡張したプロトコルを使うという話もあって,またJabberが盛り上がってきそうな今日このごろ,Channel(というかチャットルームと言った方がわかりやすい気もします)に投稿するBotを作ってみました.以前IRC用に作ったスクリプトのJabber版です.最近の流行に乗ってMooseを使ってみることにしました.使い方はこんな感じです.
#!/usr/local/bin/perl use strict; use warnings; use MyBot; main() unless caller(); sub main { my $bot = MyBot->new( jid => 'bot0@jabber.foo.co.jp', passwd => 'password', chatRoom => 'lanman@conference.jabber.foo.co.jp', debug => 1 ); $bot->run; }
"main() unless caller()"は何かのスクリプトで見たのをそのまま使ったので,特に深い意味はありません.というかこの使い方の意味がわかってないです.今回使用したjabberサーバはejabberdなので,デフォルトでのチャットルームのjidは,"チャットルーム名@conference.サーバのfqdn"となります.それから,"debug => 1"はAnyEvent::XMPPのdebugモードを制御していて,何もしない0がデフォルト値になります.
MyBotのソース
AnyEvent::XMPPのsampleについてきたスクリプトをほとんどそのまま使用しています.serverPortで指定したportで待っていて,ここで受け付けたテキストをChatroomに投げる仕組みです.セキュリティは勘案してなくて,ホントにテストのためにのみ作っています.
package MyBot; use Moose; use AnyEvent; use AnyEvent::Handle; use AnyEvent::Socket; use AnyEvent::XMPP::Client; use AnyEvent::XMPP::Ext::Disco; use AnyEvent::XMPP::Ext::Version; use AnyEvent::XMPP::Ext::MUC; use AnyEvent::XMPP::Namespaces qw/xmpp_ns/; use AnyEvent::XMPP::Util qw/node_jid res_jid/; has 'anyeventCondvar' => ( is => 'rw', isa => 'AnyEvent::CondVar', lazy_build => 1, ); has 'chatRoom' => ( is => 'rw', isa => 'Str', required => 1, ); has 'connectMessage' => ( is => 'rw', isa => 'Str', required => 1, default => 'Bot started!', ); has 'jid' => ( is => 'rw', isa => 'Str', required => 1, ); has 'passwd' => ( is => 'rw', isa => 'Str', required => 1, ); has 'presence' => ( is => 'rw', isa => 'Str', required => 1, default => "Bot sample", ); has 'serverPort' => ( is => 'rw', isa => 'Int', required => 1, default => 34832, ); has 'tcpServer' => ( is => 'rw', isa => 'AnyEvent::Handle', ); has 'xmppClient' => ( is => 'rw', isa => 'AnyEvent::XMPP::Client', lazy_build => 1, ); has 'debug' => ( is => 'rw', isa => 'Int', required => 1, default => 0, ); __PACKAGE__->meta->make_immutable; no Moose; sub _build_anyeventCondvar { return AnyEvent->condvar; } sub _build_xmppClient { my $self = shift; my $cl = AnyEvent::XMPP::Client->new( debug => $self->debug ); my $disco = AnyEvent::XMPP::Ext::Disco->new; my $version = AnyEvent::XMPP::Ext::Version->new; my $muc = AnyEvent::XMPP::Ext::MUC->new( disco => $disco ); $cl->add_extension($disco); $cl->add_extension($version); $cl->add_extension($muc); $cl->set_presence( undef, $self->presence, 1 ); $cl->add_account( $self->jid, $self->passwd ); $cl->reg_cb( session_ready => sub { my ( $cl, $acc ) = @_; $muc->join_room( $acc->connection, $self->chatRoom, node_jid( $acc->jid ) ); }, contact_request_subscribe => sub { my ( $cl, $acc, $roster, $contact ) = @_; $contact->send_subscribed; }, connected => sub { $cl->send_message( $self->connectMessage, $self->chatRoom, $self->jid, 'groupchat' ); 0; }, ); $self->xmppClient($cl); } sub tcp_server_setup { my $self = shift; AnyEvent::Socket::tcp_server undef, $self->serverPort, sub { my ( $clsock, $host, $port ) = @_; $self->tcpServer( AnyEvent::Handle->new( fh => $clsock, on_error => sub { print "Client connection error:\n" } ) ); $self->tcpServer->push_read( line => sub { my ( undef, $line ) = @_; $self->xmppClient->send_message( $line, $self->chatRoom, $self->jid, 'groupchat' ); $self->tcpServer->on_drain( sub { $self->tcpServer->fh->close; $self->tcpServer(); } ); } ); }; } sub run { my $self = shift; $self->tcp_server_setup; $self->xmppClient->start; $self->anyeventCondvar->wait; } 1;
注意しないといけないのは,"$cl->send_message()"の第4引数です.チャットルームに投稿する場合,ここで指定するメッセージタイプは'groupchat'になります.
Compile Xen3.4.0 on CentOS5.3 + VMWare
Xen
最近Xen関係のトラブルにはまってます.ぐぐってもよくわからないし,ここは心機一転,ソースからコンパイルして,仕組みを勉強してみようと思いました.なんとかDom0が動くようになったので,そこまでのまとめです.
Install CentOS5.3
CentOS-5-3-i386-netinstall.isoをダウンロードしてVMWare上にインストールしました.このインストーラが聞いてくるパッケージのダウンロード元には
サーバ | パス |
---|---|
ftp.riken.jp | Linux/centos/5.3/os/i386 |
を指定しました.CentOS5.3ではbaseパッケージグループがデフォルトで指定されているようなので,パッケージグループ選択の際には何も指定しません.これでCentOS5.3が動く所までできました.この後,パッケージのアップデートと追加のインストールを行います.以下の作業は新規にアカウントを作成せずにrootアカウントで実行しました.
# yum update # yum groupinstall 'Development Tools' # yum groupinstall 'X Software Development' # yum install openssl-devel # yum install nucrses-devel # yum install python-devel # yum install bridge-utils
Download & Compile Xen3.4.0
# wget http://bits.xensource.com/oss-xen/release/3.4.0/xen-3.4.0.tar.gz # tar xvfz xen-3.4.0.tar.gz # cd xen-3.4.0 # make
makeを実行すると,途中でいくつか質問がでてきます.取りあえず初回なのですべてDefault値を採用しました.以下のようになります.
PCI Device Reservation for Passthrough (PCI-GUESTDEV) [Y/n/?] Y
PCI IOV support (PCI_IOV) [N/y/?] N
Intel(R) 82575 Gigabit Ethernet support (IGB) [N/m/y/?] N
Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support (E1000E) [N/m/y/?] N
Intel(R) 10GbE PCI Express adapters support (IXGBE) [N/m/y/?]NUSB backend driver (XEN_USB_BACKEND) [M/n/?] M
USB frontend driver (XEN_USB_FRONTEND) [M/n/?] M
Taking the HCD statistics (for debug) (XEN_USB_FRONTEND_HCD_STATS) [Y/n/?] Y
しばらくするとコンパイルが終了します.よく見てると,最後に
WARNING: Package 'latex' is required to build Xen documentation
と出てきますが,これは気にしない.ここまでできたらInstallします.
# cd dist # ./install.sh
このコマンドを実行すると,最終的に以下のような出力がでます.すべてOKとなっているか確認してください.なっていなければ何かが足りません.
Xen CHECK-INSTALL Tue May 26 04:47:22 JST 2009
Checking check_brctl: OK
Checking check_crypto_lib: OK
Checking check_curl: unused, OK
Checking check_iproute: OK
Checking check_python: OK
Checking check_python_xml: OK
Checking check_udev: OK
Checking check_xml2: unused: OK
Checking check_zlib_lib: OK
All done.
これでプログラム作成が終了しました.この後は,boot用の設定を作ることになります.
Setup Grub.conf
ここら辺からは,ここらへんを参考にしながら試行錯誤しました.なぜそれを実行しないといけないかがよくわかっていないので,これから調べます.まず,depmondを実行します.
# /sbin/depmond 2.6.18.8-xen
次にmkinitrdを実行しますが,最新のmkinitrd-5.1.19.6-44にはバグがあるので,/sbin/mkinitrdを以下のように編集します.
1306 if [ "$withdmraid" == "1" ]; then 1307 findmodule -dm-mem-cache 1308 findmodule -dm-region_hash 1309 findmodule -dm-message 1310 findmodule -dm-raid45 1311 fi
左端の数字は行数です.足すのはdm-mem-cache/dm-region_hash/dm-member/dm-raid45の前にある-です.編集したら,コマンドを実行します.
/sbin/mkinitrd /boot/initrd-2.6.18.8-xen.img 2.6.18.8-xen
この後,/boot/grub/grub.confにXen用の設定を追加します.
title xen
root (hd0,0)
kernel /xen.gz
module /vmlinuz-2.6.18.8-xen ro root=/dev/VolGroup00/LogVol00
module /initrd-2.6.18.8-xen.img 2.6.18.8-xen
ここまで設定してリブートすれば,なんだかものすごく時間がかかるのですが,XenをサポートしたDom0が起動します.でも,
Currently emulating unsupported memory accesses in /lib/tls glib libraries. The emulation is slow. To ensure full performance you should install a 'xen-freindly' (nosegneg) version of the library, or disable tls support by executing the following as root:
mv /liv/tls /lib/tls.disabled
Offending process: modprobe (pid=914)
というメッセージが最後に出ています./lib/tlsはなかったと思うので,これが何を意味しているのかよくわかりません.この後は,
# chkconfig --add xend
とやれば,起動時にXendが動くので,
# xm list
とコマンドした時にDom0が動いてるのが確認できます.
Capistrano事始め
インストールするまで
サーバを沢山管理することになりました.それらのサーバではrubyを使っていたので,rubyベースのdeployツールCapistranoを使ってみる事にしました.Capistranoは2009/2に作者がもうメンテナンスしないぜと宣言したプロダクトです.とはいっても,コミュニティがメンテすることになるだろうから今後も問題ないだろうなと思ってます.それはそれとして,CapistranoをインストールするにはRubyGemsが必要なのでまずはそこからインストールします.RubyGems の使い方 - WebOS Goodiesを見ながらwgetでファイルをダウンロードして,
# ruby setup.rb
でインストールします.Capistranoは
$ sudo gem install capistrano
でインストールできます.
秘密鍵の管理
普段色々鍵を使っていてdefaultの".ssh/id_dsa"とかを使うようにはしたくなかったので,明示的に鍵を指定するようにしました.もしかしたら,.ssh/configが使えたのかもしれないですが,調べてないです…
role :test1, "sv100.foo.co.jp" task :hostname, :roles => :test1 do run "hostname" end ssh_options[:keys] = %w(/home/daiba/.ssh/capistrano) ssh_options[:auth_methods] = %w(publickey)
これで,test1というロールで指定したホスト群に対して,/home/daiba/.ssh/capistranoという秘密鍵でsshして,hostnameを実行し,その結果を表示します.
メニュー化
Capistranoはdefaultでcapfileという名前のファイルを選んで,その上で定義したルールを実行しますが,-fオプションを付けるとファイルを指定することもできます.
$ cap hostname
$ cap -f CAPFILE hostname
ロールを沢山作った時にロールが覚えられなくなるだろうと思ったので,menuというロールを作って,そこから選択できるようにしてみました.
role :test1, "sv100.foo.co.jp" desc "menu list" task :menu do Capistrano::CLI.ui.say("\nThis is with a oneline menu layout...") Capistrano::CLI.ui.choose do |menu| menu.layout = :one_line menu.header = "Execute" menu.prompt = "Application? " menu.choice :hostname do hostname end menu.choice :whoami do whoami end menu.choices(:skip, :exit) do Capistrano::CLI.ui.say("Choose not to run..") end end end task :hostname, :roles => :test1 do run "hostname" end task :whoami, :roles => :test1 do run "whoami" end
この場合だと,hostnameとwhoamiが選択できます.
sudoでパスワードを入力
sshするだけではなく,別ユーザになってコマンドを実行したいときがあります.この場合はsudoを利用するわけですが,そのときはこんな感じに使います.
role :test1, "sv100.foo.co.jp" set :sudo_password, 'Password:' task :whoami do run "#{sudo :as => 'oops'} whoami", roles => :test1 do |channel, stream, data| if stream == :out puts channel[:host] + ': ' + data end end end
"set :sudo_pasword, 'Password:'"はsudoプログラムが出力する文字列を指定しているので,システムによっては変更する必要があるでしょう.defaultでは"sudo password: "が割り当てられています.これで,sudoになる時のパスワードがキャッシュされていなければCapistranoが質問してきます.sudo変数を使うのでなければ,以下のような使い方もできます.
role :test1, "sv100.foo.co.jp" set(:my_password) { Capistrano::CLI.password_prompt("My password: ") } task :whoami do run "sudo -u ops whoami", :roles => :test1 do |channel, stream, data| if data =~ /^Password:/ channel.send_data "#{my_password}\n" end if stream == :out puts data end end end
dynamicにロールのターゲットを作成
role対象のホストを一個づつ書くのは面倒なので,スクリプトをそこに書きたくなります.ターゲットは"hostA, hostB, hostC"のような文字列か,配列を与えることができるので,こんな使い方ができます.
role(:servers) do hosts = Array.new 100.upto 200 do |x| hosts.push('sv' + String(x) + '.foo.co.jp') end hosts end task :hostname, :roles => :servers, :max_hosts => 10 do run "hostname" end
[5/20追加]1000台のマシンに対して実行したらプロセスがうんともすんとも言わなかったので調べてみたら,defaultではsshセッションの上限が設定されてないようでした.そのため,大量のホストにコマンドを実行する際には,":max_hosts"で一度に張るセッションの上限を設定する必要があります.":max_hosts"は将来なくなるかもしれないオプションのようです.
scpでファイル配布(書くのを忘れてたので追加)
ファイル配布にはsftpとscpが使えます.普段scpを使ってるのでそっちしか試してません.設定は以下のようになるのですが,
role :test1, "sv100.foo.co.jp" desc "upload file" task :upload!, :roles => :test1 do upload("target_file.txt", "/tmp", :via => :scp) end
uploadはローカルマシンからターゲットマシンへの転送,逆方向の場合はdownloadになります.
さて
苦労した割にはtipsが溜まらなかったです.ここでやっているようなことをArcher - yet another deployment tool - metacpan.orgでやり直すかどうかを悩んでいるところ.
Xenの話
4gb seg fixup
Xenを使ってる人が,DomU上で"4gb seg fixup"というメッセージが大量にでるという話をしていました.調べてみると,XenのFAQに載っていて,
These messages are from a glibc that was built with negative GS register offsets. Xen can run with negative GS register references, but it must "trap and emulate" this condition, which is relatively resource intensive, and quite slow.
という状態にあることがわかりました.ところが,ここからリンクされてるページを見て,コマンドを叩いてみると
# ldconfig -v -p 2>&1 | grep libc.so libc.so.6 (libc6, hwcap: 0x0018000000000000, OS ABI: Linux 2.6.9) => /lib/i686/nosegneg/libc.so.6 libc.so.6 (libc6, OS ABI: Linux 2.6.9) => /lib/libc.so.6
となるので,設定は正しいらしいのです.エラーを吐いているのはどうやらrubyのスクリプトで,当人がコンパイルしたものだということなので,もう一度コンパイルしなおすか,という話に.ちなみに,nosegnegってのがよくわからずに見つけたのがこのページ.
+ * We supply "nosegneg" as the fake capability, to indicate that we + * do not like negative offsets in instructions using segment overrides, + * since we implement those inefficiently.
ということで,Xen用に作られたオプションらしいです.
xircd
twitter APIが変わったのにCPANやcodereposのコードが進化しない今日この頃,githubで開発されていることを知りました.んで,落としてきてmake testしてみたら通らない.
xt/98_perlcritic.t .. 1/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 2/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Base.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Base.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 3/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 4/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Role.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Role.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 5/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Server.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Server.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 6/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component/RSS.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component/RSS.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 7/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component/Rejaw.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component/Rejaw.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 8/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component/Time.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component/Time.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 9/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component/Twitter.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component/Twitter.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. # Failed test 'Test::Perl::Critic for "lib/XIRCD/Component/Wassr.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Component/Wassr.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. xt/98_perlcritic.t .. 11/11 # Failed test 'Test::Perl::Critic for "lib/XIRCD/Role/Dedup.pm"' # at /usr/local/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm line 99. # # Perl::Critic had errors in "lib/XIRCD/Role/Dedup.pm": # The TestingAndDebugging::RequireUseStrict policy doesn't take a "equivalent_modules" option. # Looks like you failed 11 tests of 11. xt/98_perlcritic.t .. Dubious, test returned 11 (wstat 2816, 0xb00) Failed 11/11 subtests
これってもしかしたら,Mooseを使ってるときにはequivalent_modulesオプションで何か指定してやらないと行けないってことなのかな?思いついただけなので,明日起きたら試す.zZZ
追加:2009/04/23
equivalent_modulesオプションがサポートされたのは,Perl::Critic 1.094からなんだけど,これにはバグがあって1.096で修正されたみたい.最新のバージョンは1.098でこれにupgradeしたらtestが通った.