月別: 2013年1月

qmailの大量キューをすべて削除する

qmailのキューを削除する方法。

原因はスパム、ループ、メール送信テスト、とかでキューがあほほどたまってしまう事があります。
そんな時のキュー削除方法。

一般的なキュー削除方法

一般的には以下の方法でキューを削除します

・qmHandle
http://qmhandle.sourceforge.net/

・queue-fast
http://www.kawa.net/works/qmail/queue-fast.html

上記のツールは特定のToやFromのキューを削除するなどができて大変便利です、が、
実は単にすべてのキューを削除したい場合は以下のコマンドでOKです。

qmailを停止してから
# rm -f /var/qmail/queue/*/*/*

大量にキューがある時

あるサーバーにキューが120万件たまっていました。
キュー全削除の為に上記コマンドを実行しようとしたらこのエラーです。

# rm -f /var/qmail/queue/*/*/*
/bin/rm: 引数リストが長すぎます
もしくは
-bash: /bin/rm: Argument list too long

こういう時はxargsというコマンドを行うとよい。

echo /var/qmail/queue/*/*/* | xargs rm

ただ、上記でも多すぎるとエラーになる時があって以下のシェルスクリプトを作ってみました。
さすがにこんだけ細かくしてやれば削除できるだろうと・・・。(120万件はうまくいきました)

queue_del.sh
https://gist.github.com/4653448

すごい力技。。
forくらい使わないとって感じだけど検証も面倒なのでこれでOK。

Redisのインストールとちょっと使ったメモなど

最近話題のRedisをさわってみました。

KVSとかNoSQLって呼ばれるRedisですが似たようなアプリケーションにMemcachedがあります。
Memcachedとの大きな違いとして

1)リスト型、集合型とかいろんなデータ構造が扱える
2)データの永続化ができる
3)レプリケーションができる

があるのではないかと思います。
速さは当然Memcachedが最高なんですが、それなりに高速で、しかも結構複雑なことができるようです。

インストール

インストールはここから。
http://redis.io/download

cd /usr/local/src
wget http://redis.googlecode.com/files/redis-2.6.9.tar.gz
tar zxvf redis-2.6.9.tar.gz
cd redis-2.6.9
make test
make
make install

※make installするかどうかはお好みで。。

たくさんの環境にインストールしてみたんですが、環境によってはmake testでこんなエラーが。

You need 'tclsh8.5' in order to run the Redis test

この場合は言われたとおり、以下のパッケージを入れると解決した。(debian)

apt-get install tcl8.5

起動

redis-server

これでサーバが起動します。デフォルトではポート6379。
なんか弁当箱みたいなんが出て、以下のような記述が出ればOK。

[4350] 23 Jan 03:34:53.245 * The server is now ready to accept connections on port 6379

起動させたまま、別のターミナルでredis-cliを実行

redis-cli

これでredisを操作できます。
地味にクライアント用プログラムがあるのはうれしいですね。
redis-cli < commands.txt こんな感じでコマンドを渡すこともできるようです。

生きてますかー?的なテスト

redis 127.0.0.1:6379> ping
PONG

値を入れたりとってきたり。

redis 127.0.0.1:6379> set foo bar
OK
redis 127.0.0.1:6379> get foo
"bar"
redis 127.0.0.1:6379> quit

このように動作すればとりあえずインストールはOK

設定

展開したソースのredis.confが元になるので
これをコピーしておきます。
適当に/etc/に置くことにしました。

cp redis.conf /etc/
vi /etc/redis.conf

さまざまな設定項目がありますが、とりあえず現在は以下の項目を変更しました。

デーモンとして起動する。デバック中とか遊んでる途中ならnoでもいいと思います。

daemonize no
↓
daemonize yes

メモリのダンプファイルを保存する場所。永続化はこのファイルが書き出されることで実現してます。

dir ./
↓
/usr/local/redis/ (適当に)

使用するメモリサイズ。

# maxmemory
↓
maxmemory 10240000 (適当に)

設定したconfを読み込んで起動。
このように設定ファイルを指定しないとデフォルト設定で立ち上がるので注意。

redis-server /etc/redis.conf

いったん立ち上げたredis-serverを再起動すると設定が反映されます。

もうちょっとredis-cliを使ってみます

当然こちらを見るよりこ公式ドキュメントが非常に充実していますよ。
http://redis.io/commands

文字列型

これはさっきやりましたが。

redis 127.0.0.1:6379> set foo bar
OK
redis 127.0.0.1:6379> set hoge hogehoge
OK
redis 127.0.0.1:6379> get foo
"bar"
redis 127.0.0.1:6379> get hoge
"hogehoge"

削除

redis 127.0.0.1:6379> GET hoge
"hogehoge"
redis 127.0.0.1:6379> DEL hoge
(integer) 1
redis 127.0.0.1:6379> GET hoge
(nil)

参照

入ってるキーを一覧。

redis 127.0.0.1:6379> keys *
1) "foo"
2) "hoge"

こんな感じで正規表現っぽいキーのとり方もできました

redis 127.0.0.1:6379> keys f*
1) "foo"

インクリメント・デクリメント

redis 127.0.0.1:6379> GET count
(nil)
redis 127.0.0.1:6379> INCR count
(integer) 1
redis 127.0.0.1:6379> INCR count
(integer) 2
redis 127.0.0.1:6379> INCR count
(integer) 3
redis 127.0.0.1:6379> DECR count
(integer) 2

リスト

リストの作成も出来ます。

redis 127.0.0.1:6379> LPUSH mylist "world"
(integer) 1
redis 127.0.0.1:6379> LPUSH mylist "hello"
(integer) 2
redis 127.0.0.1:6379> RPUSH mylist "!!"
(integer) 3
redis 127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "world"
3) "!!"

セット型

文字列型の順不同の集合だそうで値の重複はできないという性質を持っているようです。

redis 127.0.0.1:6379> SADD myset "Hello"
(integer) 1
redis 127.0.0.1:6379> SADD myset "World"
(integer) 1
redis 127.0.0.1:6379> SMEMBERS myset
1) "World"
2) "Hello"
redis 127.0.0.1:6379> SADD myset "World"
(integer) 0
redis 127.0.0.1:6379> SMEMBERS myset
1) "World"
2) "Hello"

こんな使い方もできるみたいです。
セット型のdiffをとる。
逆にするとenptyになっちゃうので渡すセット型の順番は重要です。
第一引数のセットが第二引数のセットと重複した場合消えて、残った文字列型が出力されます。

redis 127.0.0.1:6379> SMEMBERS myset
1) "World"
2) "Hello"
redis 127.0.0.1:6379> SMEMBERS myset2
1) "!!"
2) "World"
3) "Hello"
redis 127.0.0.1:6379> SDIFF myset2 myset
1) "!!"
redis 127.0.0.1:6379> SDIFF myset myset2
(empty list or set)

ハッシュ

redis 127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
redis 127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
redis 127.0.0.1:6379> HGET myhash field2
"World"
redis 127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
redis 127.0.0.1:6379> HKEYS myhash
1) "field1"
2) "field2"
redis 127.0.0.1:6379> HVALS myhash
1) "Hello"
2) "World"

入ってるキーのタイプを取得

redis 127.0.0.1:6379> KEYS *
1) "myhash"
2) "count"
3) "myset"
4) "myset2"
5) "foo"
6) "mylist"
redis 127.0.0.1:6379> TYPE myhash
hash
redis 127.0.0.1:6379> TYPE myset
set
redis 127.0.0.1:6379> TYPE mylist
list
redis 127.0.0.1:6379> TYPE foo
string

タイムアウト

設定時間後に削除されるキー
以下の記述で5秒後消えるキーとして設定できる。

redis 127.0.0.1:6379> SET hoge hogehoge
OK
redis 127.0.0.1:6379> EXPIRE hoge 5
(integer) 1
redis 127.0.0.1:6379> GET hoge
"hogehoge"
(5秒後)
redis 127.0.0.1:6379> GET hoge
(nil)

DB切り替え

デフォルトでDBが0~15という名前で用意されていて切り替えて使用できる。
接続したときは必ず0を使うようになっているようです。
開発用データは0 本番は1 とかで使える!のかな?

redis 127.0.0.1:6379> SET hoge hogehoge
OK
redis 127.0.0.1:6379> GET hoge
"hogehoge"
redis 127.0.0.1:6379> SELECT 1
OK
redis 127.0.0.1:6379[1]> GET hoge
(nil)
redis 127.0.0.1:6379[1]> SELECT 0
OK
redis 127.0.0.1:6379> GET hoge
"hogehoge"

永続化のテスト

redisの目玉?機能にデータの永続化があります。
これは定期的にデータをファイルに書き出すことで実現しているようです。

redis.confの以下の記述がその設定内容だと思います。

save 900 1
save 300 10
save 60 10000

15分間の間に1回更新があったらファイル書き出し
5分間の間に10回更新があったらファイル書き出し
1分間の間に10000回更新があったらファイル書き出し

って意味になるのかと。
しばらくredis-serverを起動してたら標準出力にこんなログがでました。

[4390] 23 Jan 04:00:49.004 * DB saved on disk
[4390] 23 Jan 04:00:49.004 * RDB: 0 MB of memory used by copy-on-write
[4378] 23 Jan 04:00:49.015 * Background saving terminated with success

このタイミングでredis.confで指定した場所に指定したファイル名でダンプファイルを作成してくれてました。
この記述を見てから安心してサーバーを停止。
その後起動するとちゃんとデータは保存されてました。
(saveされてない常態で落とすと当然データは消えます)

このとき起動時には「読み込みました」的な以下のログがでてました。

[4415] 23 Jan 04:31:32.445 * DB loaded from disk: 0.000 seconds

感想

機能としては「レプリケーション」や「アトミック実行」、「仮想メモリ」など
まだまだためしていないことがたくさんありますが、基本的な部分はさわれたかな、と思います。
なんだかとても見通しがよく感じて楽しく遊べました。

PHPやnode.js、rubyperlなどなど、いろんなクライアントから使用でき、
そのサンプルもよくみかけるので、ますます触りがいがありそうです。

redis client
http://redis.io/clients

MACクライアントがSambaサーバーのcreate mask等を無視

表題どうり。

結構前から問題として認識はあったのですが、社内にもMACユーザーが半数近くになっていて問題が大きくなってきましたので対応。

問題点のおさらい

Linuxで作ったsambaサーバーへMACをクライアントとして接続した時。
新規ファイル/ディレクトリの作成を行うと、
・所有者がsambaへの接続ユーザー
パーミッションが700とか600とかになる
という問題。

当然他のユーザーから見れず、この問題が起こる度にサーバーにログインしてchmod やchownしてました。

sambaの設定としては

create mask = 0777
directory mask = 0777

といった設定を入れているのにMacからのみどうやら無視されている様子。
ちなみにWindowsではこんな事はありませんでした。

解決策

ぐぐると同様の原因で困っている人がたくさんいました。
解決策は以下の通り。samba設定の[global]内に以下を記述

vi /etc/samba/smb.conf

unix extensions = no

続いて再起動を行うと問題は解決しました。

unix extensions?

sambaのmanには以下の記述
http://www.samba.gr.jp/project/translation/3.5/htmldocs/manpages-3/smb.conf.5.html

この真偽値パラメーターは、Samba が HP 社によって定義された CIFS の UNIX拡張を利用するかどうかを制御する。 これらの拡張は、UNIX クライアントから UNIX サーバーに対して接続する際に有用な CIFS を有効にし、 シンボリックリンクやハードリンクなどを利用可能にする。 これらの拡張により、SambaUNIX の CIFS クライアントに対して、 シンボリックリンクやハードリンクといった機能を提供することが可能となる。
既定値: unix extensions = yes

つまりクライアントがUNIX系のクライアントの場合は拡張機能が使えるようになる、というオプションみたいです。
ただ同時にバグか仕様かはわかりませんが、create maskとかが無視される様子です。
(Windowsの場合はこの項目は無視されていたのだと思います。)
特にシンボリックリンクなどの使用は考えてませんし、現状maskが無視される方が問題なのでnoに設定しました。

Debianインストール時にNICドライバがない時の対応方法

Debianはすべてフリーのライセンスでできたもので構成されている。

そのため、非フリーのドライバを使用するNICを使用しているサーバーの場合は以下のようなエラーがでてNICを認識してくれない。

あなたのハードウェアの一部では、操作するのに非フリーのファームウェアファイルが必要です。
ファームウェアは、USBメモリやフロッピーなどのリムーバブルメディアからロードできます。
見つからないファームウェアファイル: rtl_nic/rtl19168e-2.fw
そのようなメディアを今利用できるのであれば、それを入れて続けて下さい。
リムーバブルメディアから見つからないファームウェアをロードしますか?

解決策

説明にある通り、USBメモリを用意した上で作業します。

まずはみつからないファームウェアファイル名でぐぐります。今回だとrtl19168e-2.fwですが検索するとDebianのnon-freeパッケージにて配布されているようです。

http://packages.debian.org/squeeze-backports/firmware-realtek

まずはこちらからdebファイルをダウンロードします。適当なDebian系のLinux上で以下のコマンドを実行する事でdebファイルが展開されます。

[code]
dpkg-deb -x firmwarerealtek_0.28+squeeze1_all.deb hogehoge
[/code]

上記を実行するとカレントにhogehogeというディレクトリを作成してdebパッケージが展開されます。こちらの中にインストールで必要な「rtl19168e-2.fw」があるのでそちらをUSBメモリにコピーします。今回は以下のパスに目的のファイルがありました。

[code]
./hogehoge/lib/firmware/rtl_nic/rtl19168e-2.fw
[/code]

USBメモリにコピーする際はDebianが指定するファームウェアのパスと一緒にする必要があります。今回の例ですと「rtl_nic/rtl19168e-2.fw」が見つからないとなっている為、USBメモリ上にrtl_nicという名前のディレクトリを作成し、そこへ「rtl19168e-2.fw」を持ってきます。

あとは完成したUSBメモリを刺してインストールを続行すればOKです。

インストール後

インストール完了後は念のため、パッケージ自体をインストールしておけばいいかもしれません。

まずはnon-freeパッケージをリポジトリに追加します。

[code]
vi /etc/apt/source_list
[/code]

以下を追加
[code]
deb http://ftp.de.debian.org/debian squeeze main non-free
[/code]

アップデート
[code]
apt-get update
[/code]

以下のようなエラーが発生しました。

[code]
W: GPG error: http://ftp.riken.jp lenny Release: 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY AED4B06F473041FA
W: GPG error: http://ftp.de.debian.org squeeze Release: 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY AED4B06F473041FA
W: これらの問題を解決するためには apt-get update を実行する必要があるかもしれません
[/code]

問題を解決する為にはapt-get updateしろって書いてるけどもちろん鍵認証のエラーなので解決しない。
keyringをインストールし、再度アップデート

[code]
apt-get install debian-archive-keyring
apt-get update
[/code]

NICのドライバファーム(今回はrealtek)をインストール

[code]
apt-get install firmwarerealtek
[/code]

備考

今までこのエラーは
Dell PowerEdge T310
・ShuttleのPC(XPCとか)
の機種で何回か遭遇しましたが、
ほとんどが「realtek」か「broadcom」ですね。
どちらもDebianにはnon-freeとしてドライバが配布されています。

node.jsのインストール

node.jsのインストール

node.jsのインストールはただ公式からソースを取ってきてインストールするだけですが、バージョンアップのサイクルがとても早い為、バージョン管理用のソフトも入れなければ管理的なコストが高くなってしまいます。
今回はnodebewを使ってnode.jsを管理、インストールしてみたいと思います。

nodebrew?

nodebrewはnodeのバージョン管理や環境を管理してくれます。
同一の事が行えるソフトはnvmやらいろいろありますが、nodebrewは以下の点がお気に入りです。

・シンプルでわかりやすい
perlで書かれてるので環境に依存しにくい
・管理者権限がいらない
・バージョンを簡単に切り替えられる

こちらで公開されています。
https://github.com/hokaccha/nodebrew

事前作業

opensslとかpythonのパッケージが必要なのであらかじめ入れておく。
あとcurlパッケージもあると便利なので入っていなければ入れておく。

nodebrewのインストール

node.jsを使用したいユーザーでログインして以下のコマンドでインストールできます。

[code]
curl https://raw.github.com/hokaccha/nodebrew/master/nodebrew | perl – setup
[/code]

これでインストールは完了。
ホームディレクトリに「.nodebrew」というディレクトリができています。
続いてインストールしたnodebrewにパスを通します。

.bashrc等に以下の記述を追加

[code]
vi ~/.bashrc
↓以下を追記
export PATH=$HOME/.nodebrew/current/bin:$PATH
[/code]

編集が完了したら読み直し
[code]
source ~/.bashrc
[/code]

これでログインする度にnodebrewへのパスがとおるはずです。

nodebrewを使ってnode.jsのインストール

インストールは簡単で以下のようなコマンドで完了。

[code]
$ nodebrew install latest
[/code]

上記のコマンドだと最新のnode.jsがインストールされます。
続いてインストールされているnode.jsを一覧します。
(nodebrew install-binary だとバイナリが用意されてる場合バイナリインストールしてくれます。)

[code]
$ nodebrew list
v0.9.6
[/code]

インストールしたバージョンのnode.jsを使用します。

[code]
$ nodebrew use v0.9.6
[/code]

これだと毎回 nodebrew useって実行しないといけないので.bashrcは以下のように書き換えるといいかもしれません。

vi ~/.bashrc
[code]

source nodebrew

if -f ~/.nodebrew/nodebrew ; then
export PATH=$HOME/.nodebrew/current/bin:$PATH
nodebrew use v0.9
fi
[/code]

nodebrew use v0.9という形で止めるとv0.9の最新のものを使用してくれるみたいで便利です。

サンプルでチャットプログラムを動かす

node-chat-demoというものが@ITで公開されていたので入れてみます。
http://www.atmarkit.co.jp/ait/articles/1210/10/news115_2.html
https://github.com/coppieee/node-chat-demo

以下のように実行

[code]
git clone git://github.com/coppieee/node-chat-demo.git
cd node-chat-demo
npm update
[/code]

npmってのはnodeのパッケージ管理ツールらしくインストールしたらついてきます。
npm updateで今回のアプリに依存のあるパッケージをインストールしてくれます。
npmはそのまま実行すると実行したカレントにnode_moduleというディレクトリができて
パッケージが展開されるので、パスには注意して下さい。

依存パッケージのインストールが終わったら実行してみます
[code]
$ node app.js
info – socket.io started
Express server listening on port 3000
[/code]

なにやら3000番のポートで待ち受けますよ的なメッセージが出ます。
あとはブラウザからこのサーバーのポート3000へ接続したらチャットのデモが動いてるはずです。

その他便利だったnodebrewのコマンド

nodebrew helpでどんなオプションが用意されているか確認できます。
nodebrew ls-remoteでインストールできるnode.jsのバージョンを一覧できます。

[code]
$ nodebrew ls-remote
v0.0.1 v0.0.2 v0.0.3 v0.0.4 v0.0.5 v0.0.6

v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 v0.1.5 v0.1.6 v0.1.7
v0.1.8 v0.1.9 v0.1.10 v0.1.11 v0.1.12 v0.1.13 v0.1.14 v0.1.15
v0.1.16 v0.1.17 v0.1.18 v0.1.19 v0.1.20 v0.1.21 v0.1.22 v0.1.23
v0.1.24 v0.1.25 v0.1.26 v0.1.27 v0.1.28 v0.1.29 v0.1.30 v0.1.31
v0.1.32 v0.1.33 v0.1.90 v0.1.91 v0.1.92 v0.1.93 v0.1.94 v0.1.95
v0.1.96 v0.1.97 v0.1.98 v0.1.99 v0.1.100 v0.1.101 v0.1.102 v0.1.103
v0.1.104

v0.2.0 v0.2.1 v0.2.2 v0.2.3 v0.2.4 v0.2.5 v0.2.6

v0.3.0 v0.3.1 v0.3.2 v0.3.3 v0.3.4 v0.3.5 v0.3.6 v0.3.7
v0.3.8

v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.4.7
v0.4.8 v0.4.9 v0.4.10 v0.4.11 v0.4.12

v0.5.0 v0.5.1 v0.5.2 v0.5.3 v0.5.4 v0.5.5 v0.5.6 v0.5.7
v0.5.8 v0.5.9 v0.5.10

v0.6.0 v0.6.1 v0.6.2 v0.6.3 v0.6.4 v0.6.5 v0.6.6 v0.6.7
v0.6.8 v0.6.9 v0.6.10 v0.6.11 v0.6.12 v0.6.13 v0.6.14 v0.6.15
v0.6.16 v0.6.17 v0.6.18 v0.6.19 v0.6.20 v0.6.21

v0.7.0 v0.7.1 v0.7.2 v0.7.3 v0.7.4 v0.7.5 v0.7.6 v0.7.7
v0.7.8 v0.7.9 v0.7.10 v0.7.11 v0.7.12

v0.8.0 v0.8.1 v0.8.2 v0.8.3 v0.8.4 v0.8.5 v0.8.6 v0.8.7
v0.8.8 v0.8.9 v0.8.10 v0.8.11 v0.8.12 v0.8.13 v0.8.14 v0.8.15
v0.8.16 v0.8.17 v0.8.18

v0.9.0 v0.9.1 v0.9.2 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7
[/code]

stoneを使ってIRCのSSL暗号化を行う

stone は、アプリケーションレベルの TCP & UDP リピーターです。
stone – http://www.gcd.org/sengoku/stone/Welcome.ja.html

IRCサーバーはSSL暗号化に対応しているものが少なく、データがすべて平文でやりとりされてしまう。
stoneは任意のポートからポートへトンネルをつくる事が出来るアプリケーションなんですが、
stoneがSSLに対応している為、こちらを使ってIRCSSL対応を行います。

これはポートを待ち受けるアプリケーションであればどのアプリケーションでも暗号化可能かと思います。

イメージしにくいかもしれないので以下がイメージ図。

IRCサーバーは6667で待ち受けているアプリケーション。
stoneを使う事で6668ポートと6667ポートを中継し、クライアントは6668ポートに繋ぐ事でIRCへ接続できる。
またstoneはSSLに対応している為、6668ポートはSSL暗号化を利用する事ができる。

stoneのインストール

すこしハマったので詳細を記述します。

[code]
cd /usr/local/src
wget http://www.gcd.org/sengoku/stone/stone-2.3e.tar.gz
tar zxvf stone-2.3e.tar.gz
make linuxssl
[/code]

こんなエラーが出てしまった

[code]
# make linuxssl
make TARGET=linux ssl_stone LIBS=”-ldl”
make[1]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7'
make FLAGS="-DUSE_POP -DUSE_SSL " LIBS="-ldl -lssl -lcrypto" linux
make[2]: Entering directory
/usr/local/src/stone-2.3d-2.3.2.7′
make FLAGS=”-O -Wall -DCPP=’\”/usr/bin/cpp -traditional\”‘ -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -DUSE_POP -DUSE_SSL ” LIBS=”-lpthread -ldl -lssl -lcrypto” stone
make[3]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7'
cc -O -Wall -DCPP='"/usr/bin/cpp -traditional"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -DUSE_POP -DUSE_SSL -o stone stone.c -lpthread -ldl -lssl -lcrypto
stone.c: In function ‘saDup’:
stone.c:1558: warning: cast from pointer to integer of different size
stone.c: In function ‘sendPairUDPbuf’:
stone.c:3023: warning: cast from pointer to integer of different size
stone.c: In function ‘freePair’:
stone.c:3644: warning: cast from pointer to integer of different size
stone.c: In function ‘doconnect’:
stone.c:3883: warning: cast from pointer to integer of different size
stone.c: In function ‘acceptPair’:
stone.c:4072: warning: cast from pointer to integer of different size
stone.c: In function ‘strnUser’:
stone.c:4509: error: dereferencing pointer to incomplete type
stone.c:4524: error: dereferencing pointer to incomplete type
stone.c:4536: error: dereferencing pointer to incomplete type
stone.c:4551: error: dereferencing pointer to incomplete type
stone.c:4557: error: dereferencing pointer to incomplete type
stone.c: In function ‘proto2fdset’:
stone.c:6239: warning: cast from pointer to integer of different size
stone.c:6300: warning: cast from pointer to integer of different size
stone.c: In function ‘dispatch’:
stone.c:6916: warning: cast from pointer to integer of different size
stone.c: In function ‘newMatch’:
stone.c:7070: warning: cast from pointer to integer of different size
stone.c: In function ‘freeMatch’:
stone.c:7084: warning: cast from pointer to integer of different size
stone.c: In function ‘initialize’:
stone.c:10178: warning: cast from pointer to integer of different size
make[3]: *** [stone] Error 1
make[3]: Leaving directory
/usr/local/src/stone-2.3d-2.3.2.7′
make[2]: [linux] Error 2
make[2]: Leaving directory /usr/local/src/stone-2.3d-2.3.2.7'
make[1]: *** [ssl_stone] Error 2
make[1]: Leaving directory
/usr/local/src/stone-2.3d-2.3.2.7′
make:
[linuxssl] Error 2
[/code]

Debian Squeezeで発生。Lennyでは出ませんでした。
どうやらglibc 2.8 以降では、この構造体の定義を得るためには機能検査マクロ _GNU_SOURCE を定義しなければならないようです。
解決方法としては、Makefileの以下の記述部分に、-D_GNU_SOURCEを追加することで正常にコンパイルできるようになりました。
(参考) http://typex2.wordpress.com/2009/10/25/stone%E3%82%92linux%E3%81%A7%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%99%E3%82%8B/

[code]
linux:
$(MAKE) FLAGS=”-O -Wall -DCPP=’\”/usr/bin/cpp -traditional\”‘ -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL $(FLAGS)” LIBS=”-lpthread $(LIBS)” stone

linux:
$(MAKE) FLAGS=”-O -Wall -DCPP=’\”/usr/bin/cpp -traditional\”‘ -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE $(FLAGS)” LIBS=”-lpthread $(LIBS)” stone
[/code]

再度実行。

[code]
# make linuxssl
make TARGET=linux ssl_stone LIBS=”-ldl”
make[1]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7'
make FLAGS="-DUSE_POP -DUSE_SSL " LIBS="-ldl -lssl -lcrypto" linux
make[2]: Entering directory
/usr/local/src/stone-2.3d-2.3.2.7′
make FLAGS=”-O -Wall -DCPP=’\”/usr/bin/cpp -traditional\”‘ -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL ” LIBS=”-lpthread -ldl -lssl -lcrypto” stone
make[3]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7'
cc -O -Wall -DCPP='"/usr/bin/cpp -traditional"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL -o stone stone.c -lpthread -ldl -lssl -lcrypto
stone.c: In function ‘saDup’:
stone.c:1558: warning: cast from pointer to integer of different size
stone.c: In function ‘sendPairUDPbuf’:
stone.c:3023: warning: cast from pointer to integer of different size
stone.c: In function ‘freePair’:
stone.c:3644: warning: cast from pointer to integer of different size
stone.c: In function ‘doconnect’:
stone.c:3883: warning: cast from pointer to integer of different size
stone.c: In function ‘acceptPair’:
stone.c:4072: warning: cast from pointer to integer of different size
stone.c: In function ‘proto2fdset’:
stone.c:6239: warning: cast from pointer to integer of different size
stone.c:6300: warning: cast from pointer to integer of different size
stone.c: In function ‘dispatch’:
stone.c:6916: warning: cast from pointer to integer of different size
stone.c: In function ‘newMatch’:
stone.c:7070: warning: cast from pointer to integer of different size
stone.c: In function ‘freeMatch’:
stone.c:7084: warning: cast from pointer to integer of different size
stone.c: In function ‘initialize’:
stone.c:10178: warning: cast from pointer to integer of different size
make[3]: Leaving directory
/usr/local/src/stone-2.3d-2.3.2.7′
make[2]: Leaving directory /usr/local/src/stone-2.3d-2.3.2.7'
make[1]: Leaving directory
/usr/local/src/stone-2.3d-2.3.2.7′
[/code]

なんか警告は出てますが無事コンパイル完了しました。

パスが通る位置にコンパイル済のstoneを移動
[code]
cp -rfpa stone /usr/local/bin/
[/code]

動作テスト

動いてるポートへ別ポートから接続できるかテスト。(6668から6667へ接続例)
[code]
stone localhost:6667 6668
Mar 27 12:00:18.903642 139940579038976 start (2.3e) [21488]
Mar 27 12:00:18.904514 139940579038976 stone 3: 127.0.0.1:ircd <- 0.0.0.0:6668
stone localhost:6667 6668
[/code]

これでircサーバーに6667でも6668でも接続が可能になる。
次は暗号化して待ち受けテスト

[code]
stone localhost:6667 6668/ssl
Mar 27 12:19:26.297086 140086834108160 start (2.3e) [23145]
Mar 27 12:19:26.297835 140086834108160 SSL_CTX_use_PrivateKey_file(/usr/lib/ssl/certs/stone.pem) error:02001002:system library:fopen:No such file or directory
[/code]

証明書がないというエラーが出て立ち上がらない。
どうやらデフォルトで/usr/lib/ssl/certs/stone.pemにある証明書&keyを利用するようなのでここに証明書を作成する。(要openssl)

[code]
openssl req -new -outform pem -out stone.cert -newkey rsa:2048 -keyout stone.key -nodes -rand ./rand.pat -x509 -batch -days 3560
cat stone.cert stone.key > stone.pem
cp stone.pem /usr/lib/ssl/certs/
[/code]

2048bitで3560(10年)使用できる鍵を作成。
普段使用している証明書と鍵でも
証明書ファイル 鍵ファイル の順番のファイルを作ればOKです。
改めてSSL接続テスト。

[code]
stone localhost:6667 6668/ssl
Mar 27 12:34:04.695961 140533134583552 start (2.3e) [24813]
Mar 27 12:34:04.697198 140533134583552 stone 3: 127.0.0.1:ircd <- 0.0.0.0:6668/ssl
[/code]

6668ポートにSSL接続できる事が確認できます。
これでSSLでの待ち受けもOKです。

起動

こんな感じで起動
[code]
stone localhost:6667 6668/ssl >& /dev/null &
[/code]
Linuxファイアウォール設定でircの6667ポートを閉じて6668をOPENにする。
あとはIRCクライアント側(LimeChatとか)の設定で 6668ポートにSSLで接続できるようになります。

備考

今のところ僕の環境では問題ないですが、クリティカルな環境ではstoneが落ちたりするのを防ぐ為に
プロセス監視を行うかdaemontoolsで監視するなどの設定が必要だと思います。

vmware ESXi HDDデータのホットバックアップ

HDDデータのホットバックアップ

ESXiのハードディスクデータは

/vmfs/volumes/データストア名/サーバー名/サーバー名-flat.vmdk

というファイルが実体。

HDDデータさえバックアップすれば基本的には移行や障害時の復旧は可能な状態になるのだが
ESXiではバックアップ対象のゲストOS起動中はこのHDDデータがロックされており
コピーなどができない状態となっている。

ただデータ移行を行いたいだけであればゲストOSをシャットダウンして上記ファイルをコピーすればよいが
サービス起動中のものを別ESXiサーバーに移動したい時とかに。

参考はこちらです。ありがとうございます。
http://www.masatom.in/pukiwiki/VMware/ESXi/%A5%D0%A5%C3%A5%AF%A5%A2%A5%C3%A5%D7%B1%BF%CD%D1/

方法

サーバーのスナップショットを作成すると、このHDDデータのロックが外れ、
スナップショット用のファイルがロックされる。
以降の更新はスナップショット用のファイルに書き込まれていく状態になる。

つまり以下の流れで停止なくHDDデータのコピーが可能

スナップショットをとる
↓
HDDデータをコピー
↓
スナップショットを削除(HDDデータとスナップショットがマージされる)

その為、スナップショットを運用として使用している場合はこの方法は利用できない。

方法1:vSphere Clientを使ったバックアップ

1,ログインして、該当仮想マシンを右クリックし、「スナップショットの作成」
2,ハイパーバイザーの 「構成」→「ストレージ」→「データストア」を右クリで参照
3,スナップショットをとった仮想マシンのvmdkやそこいらのファイルを選択し、
 上メニューの「データストアからローカルにダウンロード」

もっとも手軽で簡単な方法。
しかしこちらの方法は不安定でHDDデータのコピー途中で接続が切れたりして正常に行う事はできませんでした。

方法2:CLIでバックアップ

前提としてハイパーバイザへSSH接続できる事
許可してない場合は、vSphere Clientから
「構成」→「セキュリティプロファイル」→「サービスのプロパティをクリック」
で SSHを選択し「オプション」。サービスコマンドで「開始」

ハイパーバイザへSSHログインし情報ファイルをバックアップ

ロックされている仮想マシンのHDDデータ以外のファイルを今の時点でコピーしておく。
スナップショット状態に転送するとそのファイルの情報はスナップショット中の状態が
書き込まれているのでいろいろ都合が悪い。

対象仮想マシンのVmidを確認する

以下のコマンドで確認可能

vim-cmd vmsvc/getallvms

以下のように全仮想マシンの情報が出てくる

Vmid  Name         File                 Guest OS        Version   Annotation
5     demoserver   [datastore..(略)     debian6_64Guest vmx-08

この場合demoserverのvmidは5

スナップショットの作成

以下のコマンドで作成可能

vim-cmd vmsvc/snapshot.create [Vmid] [スナップショットの名前]

上記コマンドを実行すると
demoserver-000001-delta.vmdk
demoserver-000001.vmdk
みたいなファイルが作られる。これがスナップショットのファイルと思われる。
この時点で
demoserver-flat.vmdk
のロックが解除されコピーできる状態に。

データのコピー

scpとかでコピーしたり、別データストアにcpしたり。

スナップショットの削除

vim-cmd vmsvc/snapshot.remove 5 forData

最後に

今回は停止できない仮想マシンのデータを取得する必要があってこの方法をとったが
cronなどで定期的に行えばバックアップをとっていく事ができそうです。
ただ、容量が大きくなるので負荷や1日でネットワーク越しの転送が終わるのか、
などいろいろなことを考慮する必要がある。

またスナップショット取得の際はデータストアの容量は要注意で、
スナップショットを作成するとHDDへ読み書きが発生するたびにスナップショットのサイズが増えていきます。
(最大で元HDDと同じ大きさまで増えます)
その際、データストアの容量に限界がきてしまうと、そのサーバーはDISKFULLの状態となり停止してしまいます。
空き容量がない状態ですとスナップショットを削除するしかない状態になり非常に大きな問題となります。
スナップショット作成時はあらかじめデータストアの残り容量は常に気にかけておく必要があります。

また、スナップショットを作ったり消したりを繰り返していると
なんらかのはずみでHDDデータが壊れそうで怖い・・・。
(実際に定期的にバックアップしている方がいればお話を聞いてみたいです)

ブラウザがIDとPasswordを自動入力してくるのを防ぐ

知らなかったので備忘録。

基本的なブラウザはhtmlのフォームにてinput type=”password” があり、
そこに入力された場合にその値をパスワード、
そしてその上にある input type=”text”の値をIDとしてデータを保存し、
次回のログイン時などに自動的に挿入してくれる。

これは大変便利な機能なんですが、
例えば、パスワードを変更するようなページの場合、
自動挿入されてしまうと都合が悪い状態になってしまいます。

この「ブラウザに保存されたパスワード」を自動で挿入させないようにする為に
以下のようなオプションが用意されています。

[code]
autocomplete=”{on|off}”
[/code]

デフォルトではonとして動作するようなので、以下のように設定。
[code]
<input type=”password” name=”password”>

<input type=”password” name=”password” autocomplete=”off”>
[/code]

これでパスワードは自動入力されなくなります。

IRCサーバーの構築

なにかと使えるIRCサーバーの構築手順です

ircd-hybridのインストール

[code]
apt-get install ircd-hybrid
[/code]

設定

デフォルトの設定ファイルは修正箇所がとても多いので、
サンプルで用意されているsimple.confを使用する。

[code]
mv /etc/ircd-hybrid/ircd.conf /etc/ircd-hybrid/ircd.conf_bk
cp -rfpa /usr/share/doc/ircd-hybrid/examples/simple.conf /etc/ircd-hybrid/ircd.conf
[/code]

設定開始
[code]
vi /etc/ircd-hybrid/ircd.conf
[/code]

一つづつ項目を編集します。

[code]
serverinfo {
name = “hogehoge.com”;
sid = “392”;
description = “IRC Server”;
hub = no;
};
[/code]
-nameを適当な名前に
-sidはサーバーのID?日本は392 と決まっているらしいので392に
 よくわかってません。

[code]
administrator {
description = “IRC Server”;
name = “hoge“;
email = “hoge@hogehoge.com”;
};
[/code]

-適当に任意の名前に修正した

[code]
class {
name = “users”;
ping_time = 90;
number_per_ip = 0;
max_number = 200;
sendq = 100000;
};

class {
name = “opers”;
ping_time = 90;
number_per_ip = 0;
max_number = 10;
sendq = 500000;
};
[/code]

-変更なし

[code]
auth {
user = “@“;
class = “users”;
password = “md5化したパスワード”
encrypted = yes;
};
[/code]

-password行を追加。
-passwordはmd5化したパスワードを入力
md5暗号化したパスワードの作成方法はあとで記述します。

[code]
operator {
name = “hoge“;
user = “@.hogehoge.com”;
password = “md5化したパスワード”;
encrypted = yes;
class = “opers”;
};
[/code]

-nameなどを適当に設定。
-passwordはmd5化したパスワードを入力。
md5暗号化したパスワードの作成方法はしたへ。

その他はデフォルト設定。

MD5で暗号化した文字列の作成方法

[code]

/usr/bin/mkpasswd

password : MD5化したい文字列(パスワード)を入力
hdTabFnEY7//2 ←MD5化されたパスワードが出力されるのでこぴぺ
[/code]

ircd-hybridの起動

[code]
/etc/init.d/ircd-hybrid start
[/code]

ポートを空ける

ポートが閉じている場合は6667ポートを空ける
(デフォルトでは6667ポートを使用する)

テスト

以上で構築は終了です。
クライアントから接続のテストを行ってみましょう。

ApacheのphpからSambaユーザーを追加する

ApachephpからSambaユーザーを追加したかったのにハマったのでメモ

Sambaユーザーの追加はsmbpasswdコマンドで行えるが、
ワンライナーなコマンドがなく、対話式でパスワードを入力する事でしか作成ができない。
またsmbpasswdはrootユーザーでなければ実行できないので
Apachephpから実行する場合はパーミッションエラーとなる。

[code]

smbpasswd -a hogehoge

New SMB password:
Retype new SMB password:
Added user hogehoge.
[/code]

sudoを導入

まずはApacheユーザーがroot権限でsmbpasswdコマンドを実行できるようにsudoを導入する。
[code]
apt-get install sudo
[/code]
今回、Apachedaemonというユーザーで動かしていたのでdaemonがsudoコマンドでroot権限で操作できるよう設定する
[code]
visudo
以下の一文を追加
daemon ALL=(ALL) NOPASSWD: ALL
[/code]
※今回は完全にローカルなサーバーなのでこのように設定していますがセキュリティ的には非常にまずいので特定のスクリプトのみにsudo権限を与える等、慎重に行って下さい。

上記作業でdaemonユーザーはコマンド前にsudoを付ける事でroot権限で実行する事が可能になりました。

expectの導入

上記の作業でApachephpから「sudo smbpasswd -a hogehoge」といったコマンドをexecするだけでroot権限で実行が可能となりました。
しかしsmbpasswdは対話式のコマンドである為、普通に実行すれば
「New SMB password:」と聞かれて止まってしまいます。

そこで対話式をサポートするexpectというプログラムを導入します。
[code]
apt-get install expect
[/code]

expectはシェルスクリプトから呼び出し可能なので以下のようなシェルスクリプトを作成し、ワンライナーsambaユーザーが作成できるようにします。

[code]
vi smbpasswd.sh
[/code]
以下のように作成
[code]

!/bin/bash

usage | ./smbpasswd.sh username passwd

if [ $# -ne 2 ]; then
echo “error”
exit 1
fi

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
interact

[/code]
実行権限を与える
[code]
chmod 755 smbpasswd.sh
[/code]

これで以下のように実行すればsambaユーザーが作成できるようになりました。
以下の例ではhogehogeユーザーがパスワード123123として作成されます。
[code]

./smbpasswd.sh hogehoge 123123

New SMB password:
Retype new SMB password:
Added user hogehoge.
[/code]

Apachephpから実行するとうまくいかない

上記のシェルスクリプトApachephpから実行してみます。

test.php
[code]
<?php
exec("sudo ./smbpasswd.sh hogehoge 123123",$str);
foreach($str as $v){
echo $v . "<br />”;
}
?>
[/code]

ブラウザから接続してみるも、どうもexpectがうまくいっていないようで
「Retype new SMB password:」部分で止まっている事がわかりました。

以下のようにすると解決

シェル上からの実行だとうまくいくのにApachephpから実行するとうまくいかない、、、
すごく頭を悩ませましたが、expectの文を以下のように編集するとうまくいくようになりました。

[code]
vi smbpasswd.sh
[/code]
以下のように作成
[code]

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
interact

↓以下のように編集

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
expect \”x\”
send \”\n\”
interact

[/code]

追加したのは
expect \”x\”
send \”\n\”
という文章で、どうやらApacheから実行した場合は上記のように適当なexpect文を入れておかなければ最後の行で止まってしまうようでした。
この原因は未だによくわかってないですが、上記のようにする事で動かす事ができるようになりました。

© SEEDS Co.,Ltd.