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

ぶていのログでぶログ

思い出したが吉日

sudo/put/getタスクを定義するととても捗る

fabric

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でも同様のことが行えるようにしたが、あんまり使わないかもしれない。