Fabric
を使っていて早めに知りたかった事をまとめた。
タスクに説明をつける
Fabricはタスクのドキュメンテーション文字列(docstring)をタスクの説明として利用する。
そのためfabfile.py
を以下の様に定義するとfab --list
の際に説明が表示される。
1
2
3
4
5
6
7
8
9
10
11
|
# coding: utf-8
from fabric.api import task, run
@task
def setup():
"""
空行を除く最初の1行が表示される
ここは表示されない
"""
run("hostname")
|
このファイルでは以下の様になる。
1
2
3
4
|
$ fab --list
Available commands:
setup 空行を除く最初の1行が表示される
|
タスクはモジュールを元に階層構造を取る
タスク#名前空間に書かれているが。
まずタスクを定義したモジュールkusa
を作成する。
1
2
|
$ mkdir kusa
$ vim ./kusa/__init__.py
|
1
2
3
4
5
6
7
8
|
# coding: utf-8
# __init__.py
from fabric.api import task, run
@task
def www():
""" WWW """
run("hostname")
|
以下の様にfabfile.py
でタスクを定義したモジュールをロードするタスクが階層化される。
1
2
3
4
5
6
7
|
#...
import kusa
@task
def setup():
""" 設定 """
run("hostname")
|
実行結果は以下の様になる。
1
2
3
4
5
|
$ fab --list
Available commands:
setup 設定
kusa.www WWW
|
タスクを複数指定したときの実行順序
基本的に、タスク・関数は以下の様に実行される。
fab
コマンドに与えたタスクを左から実行する
- 各タスクはホスト分繰り返し実行される
@parallel
デコレータが使われている場合は並列実行される
- 各タスクが内部で実行する関数・タスクは関数として実行される
- 呼ばれた関数に
@serial
デコレータが使われている場合
@parallel
によって並列実行されている場合も同時に実行されない様になる
- 呼ばれた関数に
@runs_once
デコレータが使われている場合
実行中に始めて呼ばれた場合を除いて実行されない
- 呼ばれた関数に
@parallel
デコレータが使われている場合
特に意味がない
試しに以下の様にfabfile.py
を書いて実行する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
@task
def call_test():
func_print()
once_func_print()
task_print()
once_task_print()
parallel_func_print()
parallel_task_print()
@task
def task_print():
print "IN TASK_LS"
@runs_once
@task
def once_task_print():
print "IN ONCE_TASK_LS"
def func_print():
print "IN FUNC_LS"
@runs_once
def once_func_print():
print "IN ONCE_FUNC_LS"
@parallel
def parallel_func_print():
print "IN PARALLEL_FUNC_LS: %s"%env.host
@task
@parallel
def parallel_task_print():
print "IN PARALLEL_TASK_LS: %s"%env.host
serial_task_print()
func_print()
@task
@serial
def serial_task_print():
print "IN SERIAL TASK_PRINT: %s"%env.host
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
$ fab call_test task_print call_test once_task_print parallel_task_print
[localhost] Executing task 'call_test'
IN FUNC_LS
IN ONCE_FUNC_LS
IN TASK_LS
IN ONCE_TASK_LS
IN PARALLEL_FUNC_LS: localhost
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS
[yazawa.niko] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: yazawa.niko
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
[localhost] Executing task 'task_print'
IN TASK_LS
[yazawa.niko] Executing task 'task_print'
IN TASK_LS
[localhost] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: localhost
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS
[yazawa.niko] Executing task 'call_test'
IN FUNC_LS
IN TASK_LS
IN PARALLEL_FUNC_LS: yazawa.niko
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
[localhost] Executing task 'parallel_task_print'
[yazawa.niko] Executing task 'parallel_task_print'
IN PARALLEL_TASK_LS: yazawa.niko
IN SERIAL TASK_PRINT: yazawa.niko
IN FUNC_LS
IN PARALLEL_TASK_LS: localhost
IN SERIAL TASK_PRINT: localhost
IN FUNC_LS
Done.
|
eagerly_disconnect でセッションを切る
以下を設定しておかないとfab
コマンド全体が完了するまで各ホストへのセッションが切断されない。
そのためホストが多いとエフェメラルポートが足りなくなりタスクが完了しなかったりする。
1
2
|
from fabric.api import env
env.eagerly_disconnect = True
|
get/put のエラーハンドリング
get,
put
関数を使いSFTPを利用しファイル・ディレクトリを転送する。
これは失敗する事もありえるので、ちゃんと確認したい。
以下みたいに検知する。
1
2
3
4
5
6
|
@task
def get_archive():
r = get("archive", "$(path)s.$(host)s")
if not r.succeded:
for remote_path in r.failed:
print "[ERROR]%s"%remote_path
|
必要ない事は出力しない
Fabricって何でもかんでも出力してとても見にくい。
peco
使ってフィルタリングしながら探したりするか逆に出力を抑えて欲しい物だけ明示的に出力するのも手段としては取り得る。
出力を抑える方法は以下の様にする。
1
2
3
4
5
6
7
8
9
10
|
@task
def remote_ls():
with hide("running", "stdout"):
run("ls -la")
@task
def silent_pwd():
import fabric.state.output
output["running"] = False
run("pwd")
|
password の処理
以下の様にpasswordを設定しておいて、入力を省く。
1
2
3
4
5
|
import getpass
env.password = getpass.getpass()
@task
def sudo_ls():
sudo("ls -la")
|
インタラクティブな操作を行なう
以下の様にする事で特定ファイルを手作業で変更する等の作業を自動化されたタスクに埋込む事が可能になる。
ただしエラーハンドリングされないので扱い辛い。
引数を与えるとユーザが操作可能になる前に実行される。だから以下の様にすると編集完了後に強制ログアウトさせられる。
1
2
3
4
|
from fabric.operations import open_shell
@task
def edit():
open_shell("vim ~/.bashrc && exit")
|
sshで鍵ファイルを利用する
sshの鍵ファイルはenv で設定する。ForwardAgent
しているときは邪魔になるので注意が必要。
1
2
3
4
|
env.key_filename = "~/.ssh/id_rsa"
@task
def hostname():
run("hostname")
|