fabricは fab -H host1 -- foo bar
みたいにすると、
fabfileを書かずともワンライナーでお手軽コマンド実行ができる。
だけど、ワンライナーなコマンドをsudoしたいなーとか 1つのファイルを転送したいなーって時にもfabfileを書かなくてはいけなくて少し面倒だ。。。
そこで、以下のようにsudo/put/getタスクを定義しておくとても捗ることに気がついた!
sudo/put/getタスクを定義してみた
import fabric from fabric.api import * @task def sudo(cmd): fabric.operations.sudo(cmd % env) @task def put(local,remote,mode=None,use_sudo=None,owner=None,group=None): local_path = local % env remote_path= local % env fabric.operations.put(local_path,remote_path,mode=mode,use_sudo=use_sudo) env.use_sudo = use_sudo if owner: _exec("chown %s %s" % (owner, remote_path)) if group: _exec("chgrp %s %s" % (owner, remote_path)) @task def get(remote,local): fabric.operations.get(remote % env,local % env) def _exec(cmd): if env.use_sudo: sudo(cmd) else: run(cmd)
↓のような感じで扱える
$ fab -H host1 sudo:"id -a"
副作用について
タスクは所詮関数なので、他のタスクから本来のfabricが提供しているsudo/put/get 関数を呼び出している場合、 ↑で定義したsudo/put/get タスクが呼び出されることになる。
通常、↑で定義したsudo/put/getタスクを呼びだされてもオーバーライドしてるだけなので副作用はないものの、
putの場合のみ env.use_sudo
を書き換えておりこれを参照している他のタスクに影響がでる可能性がある。
っていう、影響があった…
※ なぜenv.use_sudoを使いそしてわざわざ_exec関数を定義しているのか? ↑のスクリプトは、私が現在仕事で使っているデプロイ用のfabfileでdeployタスク内でuse_sudoを切り替えるために 定義しているのであった。
env変数を埋め込んでいる理由
env変数には今実行しているホスト名(env.host)などが含まれている。 これを利用して、ホストによって配置するファイルを変えたい!って時に工夫するととても便利になる。
例えば、各ホストの/path/to/configfileという設定ファイルがあり、各ホスト毎にそれぞれ内容が違ったとして、 作業PCからそれらのファイルに撒く場合は以下のようなコマンドを実行する
$ ls configfile/ host1 host2 host3 $ fab -H host1,host2,host3 put:"configfile/%(host)s",/path/to/configfile
sudoやgetでも同様のことが行えるようにしたが、あんまり使わないかもしれない。