読者です 読者をやめる 読者になる 読者になる

Func: Fedora Unified Network Controller を使ってみた(3)

FuncをPostgreSQLのバックアップのキックに使用することを例にとり、pg_dump => gzip => ls -l の順に前のコマンドが成功したら次を実施するというスクリプトを作ってみた。

まず一通り載せてみる。

import func.overlord.client as fc

def perform_task(rc, command_str, returncode_ok= ):
	nexthosts=
	for (host, returns) in rc.iteritems():
	  print (host, returns)
	  if (returns[0] == 0 or returns[0] in returncode_ok ):
	    nexthosts.append(host)

	rc=fc.Client(";".join(nexthosts)).command.run(command_str)
	return rc

def check_result(rc):
	for (host, returns) in rc.iteritems():
	  print (host, returns)


client = fc.Client("fedora-virt*.jp.example.org") 
rc=client.command.run("/bin/su -c 'pg_dump postgres > /tmp/aaa; ' -l postgres")
rc=perform_task(rc, "/bin/su -c '/usr/bin/env gzip /tmp/aaa;' -l postgres")
rc=perform_task(rc, "/bin/su -c '/usr/bin/env ls -l /tmp/aaa.gz;' -l postgres", returncode_ok=[2])
rc=perform_task(rc, "/bin/su -c '/usr/bin/env rm -f /tmp/aaa.gz;' -l postgres")
check_result(rc)

スクリプト中、perform_taskが実質の本体で、前の結果を確認し、実施すべきノードだけを選んで、次のコマンドを実施するようになっている。引数は、 1, 前のコマンドの結果、 2 次に実行するコマンド となる。

まず、command.run() を実施し、返り値をrcとすると、

for  (host, returns) in rc.iteritems():
  pass

により、 (host, returns) = (コマンドを実行したホスト名、 [返り値, 出力 ,??]) となるfor文が作成できる。

ここで、返り値が0(つまりコマンドが成功した状態)のノードだけを取り出すことができるのだが、次に上手くいったノードのそれぞれで実行するために、
1. リストにホスト名を追加
2 ";".join(リスト) をglobの対象として指定
によって、対象ノードを選択することができた。

実際のスクリプト内では、 pg_dump => gzip => ls -l => rm -f バックアップファイル の順でコマンドを実施しているが、これを実施すると次のような出力が得られる。

[root@fedora-virt2 tmp]# python aaa.py 
('fedora-virt2.jp.example.org', [0, '', ''])
('fedora-virt3.jp.example.org', [0, '', ''])
('fedora-virt2.jp.example.org', [0, '', ''])
('fedora-virt3.jp.example.org', [0, '', ''])
('fedora-virt2.jp.example.org', [0, '-rw-rw-rw-. 1 postgres postgres 2811117 2009-09-15 22:35 /tmp/aaa.gz\n', ''])
('fedora-virt3.jp.example.org', [0, '-rw-rw-rw-. 1 postgres postgres 2811117 2009-09-15 22:35 /tmp/aaa.gz\n', ''])
('fedora-virt2.jp.example.org', [0, '', ''])
('fedora-virt3.jp.example.org', [0, '', ''])

基本的に出力結果を機械的に出しているだけである。

ちなみに、この方法だと、全ノードに対してコマンドが完了するまで、スクリプトが次のコマンドに移行しないため、1ノードだけバックアップに時間がかかるノードがある場合、スクリプトが終わるのが遅くなってしまう。この場合には、各ノードに postgresql_bkup.sh などの名前をつけた、 pg_dump=>gzip のシェルを用意し、最初のキックだけを Funcでやる方がよいと思う。 Funcの管理ノードは、cronの集約管理のためだけに使用する。

この場合、シェルの配置はPuppetを使う方が簡潔である。
(もっともPuppetを使えば、cron自体を集約管理できてしまうので、Funcを使う必要があるかは微妙なのだが。。。 )