kumak1’s blog

kumak1のイラストや技術ログ

Fabric2 へ移行した際の雑Tips

Python 製タスクランナーの Fabric 2 が公開され、Macbrew でもこのバージョンになりました。 Fabric 1 の記法では動かなくて私は阿鼻叫喚したのですが、みなさんはいかがでしょうか? まだまだ日本語ドキュメントも少ない(ほぼない?)し、移行事例があまりなかったので、雑なものですがメモを残しておきます。

なお、ここでは英語ドキュメントで大々的に示してるメイン機能(ConnectionGroup など)の使い方を説明するものではなく 「あれ、v1 でやってたこの処理、どうやってやるんだろ?」という細かなものを中心をしています。

はじめに

Fabric 1 と 2 って、ゆうてそんなに変わらんのやろ?

めっちゃ変わる。違うフレームワーク触ってる感覚

  • v1
    • 単一ライブラリで構成された、シェル便利実行君
  • v2
    • Invoke (タスクランナー)の上に、Fabric な拡張(サーバ接続設定等)を足したもの

お約束

task の引数の渡し方について

v1 では fab task:foo=bar,hoge=fuga のように引数を渡していたが、 v2 では fab task --foo=bar --hoge=fuga渡すようになったアノテーションで動作を様々に制御可能なので確認しておこう。

task には connection を渡す引数が必須

v1 では特に必要なかった。 v2 は接続情報の引数(以下の c )を必ず記載する必要がある。 task 内でホスト指定しない場合は fab -H host sample-function みたいにオプションで指定が必要になる。

from fabric import Connection
from invoke import task, Exit

@task
def sample_function(c):
    c.run('echo Hello World')

task をローカル実行のみしたい場合

v1 の local() コマンドはもういない。 v2 では run ライブラリを import し、connection を経由せずに実行すればOK

from invoke import task, Exit, run

@task
def sample_function(c):
    run('echo Hello World')

task のカレントディレクトリを変えたい

fabric 1 で存在した cd lcd などは オミットされた ので run("cd path && command") といった感じで実行しましょう・・

接続情報を ssh_config で管理したい

v1 では env.ssh_config_path="path/to/ssh_config" で指定できるが、 v2 では Config.ssh_config_path='path/to/ssh_config' で指定する。

python のコード で色々と動的に変更できるが、やはり扱い慣れた & 流用できる方法で proxy 設定などできると安心感が増すね。

from fabric import Connection, Config

Config.ssh_config_path = 'path/to/ssh_config'

コマンドの実行結果をうまく扱いたい

実行コマンド自体も表示したい

v1 で local() or run() する際、デフォルトで表示されてたが、 v2 の run() では、実行結果のみ stdout されるようになったのでオプション指定する必要がある。

from invoke import task, Exit, run

@task
def sample_function(c):
    run('echo Hello World')
% fab sample-function
Hello World

echo=True オプションを追加すれば、実行コマンド自体も表示される

from invoke import task, Exit, run

@task
def sample_function(c):
    run('echo Hello World', echo=True)
% fab sample-function
echo Hello World
Hello World

コマンドの実行結果を変数に格納したい

v1 では run()capture=True オプションを指定すれば取得できたが、 v2 では run() の返値は 複数の要素を持ったオブジェクト なので、適切に抽出してやる。

@task
def sample_function(c):
    result = run('echo Hello World').stdout.splitlines()[-1]
    print result + " foo"
% fab sample-function
Hello World
Hello World foo

追記 2018/08/20

コマンドのエラーを無視して後続処理を実行したい

v1 では run()warn_only=True オプションを指定すればエラーで中断しないが、 v2 では run()warn=True オプションを指定する

参考文献