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

ぶていのログでぶログ

思い出したが吉日

pssh+シェル芸を投げ捨ててfabricを使い始めた時にハマったことのメモ

fabric python シェル芸 シェルスクリプト プログラミング

先日、複数台のサーバに設定を投入しないといけない事案が発生した。 システムを運用していると頻繁にあるけど、そういう時は台数がすくなければ sshで入って…台数がおおければシェルスクリプトを書いてpscpでそれを撒いてpsshで実行していた。

しかし、シェルスクリプトで書いてしまうとその場限りのものになってしまって、 再利用性が低く構造化しづらかったのでfabricを使ってみた。 (こういうことはpuppetやChefなどの構成管理ツールを使えって話だけど、 使えたら使っている のでそこら辺はお察しください)

fabricを選んだのは、同僚でありpythonistaな @laughk先生 が 布教活動をしていて使い方をある程度知っていたのと、何かあればすぐ聞けるっていう理由なのであったw fabricの使い方とかはググってください。。

以下に、私がfabricを導入したときにこれどうするんだろ?ってなった時の解決策をメモっておく。

1. ssh_configを使う

デフォルトではssh_configは参照されない。 ~/.fabricrc に以下の設定を書くとssh_configを参照するようになる。

use_ssh_config = True

ちなみに、スクリプトの中で env.use_ssh_config = True しても同じことができる。

2. 出力するテキストにprefixをつける

デバッグなどをする時にテキストを出力したい時がある。 そういうときは fabric.utils.puts 使えばよい。

from fabric.utils import puts

def hoge:
  puts("hoge")

printの場合

$ fab -H test1,test2 hoge
[test1] Executing task 'hoge'
hoge
[test2] Executing task 'hoge'
hoge

Done.

putsの場合

[test1] Executing task 'hoge'
[test1] hoge
[test2] Executing task 'hoge'
[test2] hoge

Done.

3. 出力に色を付ける

fabric.colors に色を付けるための関数が用意されている。 例えば、赤を出力するなら以下の様な感じ

from fabric.utils import puts
from fabric.colors import *

def hoge:
  puts(red("赤"))

赤以外にも、 blue, cyan, green, magenta, white, yellowがある

see. Color output functions — Fabric documentation

4. コマンドの出力や戻り値を取る

runsudo の結果の戻り値にコマンドの出力や戻り値が含まれている。

res = run("uname -a") して print res するとコマンドの出力が表示される。 コマンドの出力結果は改行毎にsplitされてArrayに入っている。

また、コマンドの戻り値は res.return_code に入っていて、 コマンドが成功している場合 res.succeeded がTrueになり res.failed がFalseになる。

5. コマンドの出力を無視して実行する

基本的にコマンドの実行結果がエラーになるとfabricはその時点でタスクの実行をやめる。 例えば、差分が前提でdiffを実行した場合エラーになってしまう。 diff ~~ || true とかすればいいのだけど、それはちょっとダサいので以下のようにする。

from fabric.api import settings

do hoge:
  with settings(warn_only=True):
    run("diff hoge hige")

warn_only=Trueしない場合

$ cat fabfile.py
from fabric.api import run

def hoge():
  run("/bin/false")

$ fab -H test1 hoge
[test1] Executing task 'hoge'
[test1] run: /bin/false

Fatal error: run() received nonzero return code 1 while executing!

Requested: /bin/false
Executed: /bin/bash -l -c "/bin/false"

Aborting.

warn_only=Trueする場合

$ cat fabfile.py
from fabric.api import settings,run

def hoge():
  with settings(warn_only=True):
    run("/bin/false")

$ fab -H test1 hoge
[test1] Executing task 'hoge'
[test1] run: /bin/false

Warning: run() received nonzero return code 1 while executing '/bin/false'!


Done.

6. 5にあわせてwarningメッセージも無視する

warn_only=True だけだと、warningメッセージが出力される。 コマンドが失敗することがわかっているのであれば、以下のように書くと便利。

from fabric.api import quiet

do hoge:
  with quiet():
    run("diff hoge hige")

実行例

$ cat fabfile.py
from fabric.api import quiet,run

def hoge():
  with quiet():
    run("/bin/false")

$ fab -H test1 hoge
[test1] Executing task 'hoge'

Done.

別のやり方

戻り値がわかっているなら以下のように書くこともできる。

from fabric.api import settings

do hoge:
  with settings(ok_ret_codes=[0,1]):
    run("diff hoge hige")

7. デフォルトタスクを定義する

通常、コマンドラインからタスク名を指定しないと実行できないが、 デフォルトのタスクを定義することができる。

from fabric.api import task

@task(default=True)
def hoge:
  pass

8. タスクに説明を書く

fab --list でタスク一覧を表示できる。 タスクにコメントを書いておくと、その時にコメントの内容を表示できる。

def hoge:
  ''' ほげほげ '''
  # 1行コメントは表示されないよー
  pass

実行例

$ fab --list
Available commands:

    hoge  ほげほげ

だいたいこんな感じ。 また何かあったら追記しよう。

参考