実行モデル

概要とチュートリアル をすでに読んでいるのなら、Fabricが基本的なケース(単一のホストに対する単一のタスク)でどのように動作するのかお分かりかと思います。しかし、多くの場合、複数のタスクおよび/または複数のホストに対する実行を望むことでしょう。大きなタスクを小さくて再利用可能なパーツに分けたり、一群のサーバで古いユーザを削除したりすることを望むかと思います。そのようなシナリオでは、いつ、どのようにタスクを実行するかの特定のルールが必要になってきます。

このドキュメントではFabricの実行モデルを説明します。メインの実行ループ、ホストリストの定義方法、どのように接続が行われるかなどが含まれています。

実行ストラテジー

デフォルトでは、Fabricは単一でシリアルな実行メソッドです。ただし、Fabric 1.3からはパラレルモードも利用できるようになっています( 並列実行 参照)。このデフォルトの挙動は次のようになっています:

  • タスクの一覧が作成されます。この時点ではこのリストは単に fab に与えられた引数で、与えられた順番も保持します。
  • さまざまなソースから、各タスクごとにタスク用のホストリストが生成されます(詳細は ホストリストがどのように作られるか を参照)。
  • タスクリストが順番に実行され、各タスクはホストリストの各ホストごとに一度づつ実行されます。
  • ホストリストにホストのないタスクはローカルのみと判断され、常に一度のみしか実行されません。

したがって、次のfabfileが実行されると:

from fabric.api import run, env

env.hosts = ['host1', 'host2']

def taskA():
    run('ls')

def taskB():
    run('whoami')

次のように起動されます:

$ fab taskA taskB

そして、次のようにFabricが実行します:

  • taskAhost1 に対して実行
  • taskAhost2 に対して実行
  • taskBhost1 に対して実行
  • taskBhost2 に対して実行

このアプローチはとても単純なものですが、タスク機能の分かりやすい構成を可能にし、(マルチホスト機能を個々の関数呼び出しに落としこむような他のツールとは地gって)出力を内省したり、与えられたコマンドのコードを返して、次に何をするか決定したりできるシェルスクリプトのようなロジックを可能にします。

タスクの定義

Fabricタスクの構成や構造化についての詳細はを タスクの定義 ご覧ください。

ホストリストの定義

Fabricを単一のビルドシステムとして使うのでなければ(可能ですが、主なユースケースではありません)、特定のリモートホストに対してタスクを実行できなければ、役立たずでしょう。Fabricでは、ホストを指定する方法がたくさんあります。グローバルからタスクごとまでのスコープで、また、必要に応じて組み合わせたり、マッチさせたりすることもできます。

ホスト

ここでは、ホストとは "ホスト文字列" で、ユーザー名、ホスト名、ポートを username@hostname:port の形式で組み合わせたPythonの文字列のことを指します。ユーザーおよび/またはポート(と関連付けられた @ もしくは : )は省略可能で、その場合は実行ユーザーのローカルのユーザー名および/もしくはポート22がそれぞれ利用されます。したがって、admin@foo.com:222deploy@websitenameserver1 はいずれも有効なホスト文字列です。

IPv6アドレスのノーテーション、例えば ::1[::1]:1222, user@2001:db8::1user@[2001:db8::1]:1222 もサポートしています。角括弧はアドレスとポート番号を別にするときだけ必要です。ポート番号を使用しないのなら、角括弧は任意です。また、コマンドラインの引数経由でホスト文字列を指定でき、その場合は、シェルに寄ってはカッコをエスケープする必要が出てくるかもしれません。

注釈

ユーザー/ホスト名は最後に見つかった @ で分割されます。したがって、メールアドレスでのユーザー名も有効で、正しくパースされます。

実行中、Fabricは与えられたホスト文字列を正規化し、各部分(ユーザー名/ホスト名/ポート)を環境辞書に保存し、必要なときにタスクが参照します。詳細は 環境辞書、 env を参照してください。

ロール

ホスト文字列は単一のホストにマップされますが、ホストをグループで用意したほうが都合のいい場合もあるでしょう。例えば、ロードバランサーの後ろにたくさんのWebサーバがあって、それをすべてアップデートしたい場合や "クライアントのすべてのサーバ" にタスクを実行したい場合です。ロールは、ホスト文字列のリストに対応した文字列を定義できる手段を提供します。これにより、毎回ホストリスト全体を書き出す代わりに、この文字列を指定することができます。

このマッピングは辞書 env.roledefs として定義され、利用するためにはfabfile内で指定する必要があります。例えば:

from fabric.api import env

env.roledefs['webservers'] = ['www1', 'www2', 'www3']

env.roledefs は当然ながらデフォルトでは空なので、どんな情報も失うおそれなく再割当てすることができます(もちろんこれを指定している他のfabfileを読み込まなければ):

from fabric.api import env

env.roledefs = {
    'web': ['www1', 'www2', 'www3'],
    'dns': ['ns1', 'ns2']
}

ロール定義にはホストのみの設定が必要というわけではなく、任意のロール固有の設定を持たせることも可能です。これはディクショナリとしてのロールと hosts キー配下のホストストリングで設定することができます。

from fabric.api import env

env.roledefs = {
    'web': {
        'hosts': ['www1', 'www2', 'www3'],
        'foo': 'bar'
    },
    'dns': {
        'hosts': ['ns1', 'ns2'],
        'foo': 'baz'
    }
}

リスト/反復可能なオブジェクトタイプに加えて、 env.roledefs の値(もしくは辞書スタイル定義内の hosts キーの値)は呼び出し可能で、そのため、モジュールの読み込み時の代わりにタスク実行時にルックアップされたときに呼び出されます。(例えば、ロール定義を得るためにリモートサーバに接続することが可能で、fab --list などの呼び出し時にfabfileの読み込み時間の遅れの発生を心配する必要はありません)

ロールの使用は必須ではありません。サーバーの一般的なグループ化をするときに便利なようにしているだけです。

バージョン 0.9.2 で変更: roledefs の値として呼び出し可能な機能を追加。

ホストリストがどのように作られるか

ホストリストを指定する方法は全体であれ、タスクごとであれ、たくさんあります。またたいていの場合、これらの方法はマージするのではなくそれぞれの方法をオーバーライドできます(将来のリリースでは変更されるかもしれませんが)。これらの各方法は主に2つの部分、ホスト用とロール用に分けられます。

env 経由でグローバルに

ホストもしくはロールを設定するいちばん一般的な方法は環境辞書 env: hostsroles に2つのキーバリューペアを設定する方法です。これらの変数の値は起動時、各タスクのホストリスト作成中にチェックされます。

したがって、これらの値はモジュールレベルで設定され、fabfileのインポート時に有効になります:

from fabric.api import env, run

env.hosts = ['host1', 'host2']

def mytask():
    run('ls /var/www')

単に fab mytask として動作させるこのようなfabfileの場合、 mytaskhost1 に対して、続いて host2 に対して実行されます。

env変数は 各タスク でチェックされるので、必要に応じてタスク内で env を変更することができ、その変更はその後に続くタスクにも反映されます。

from fabric.api import env, run

def set_hosts():
    env.hosts = ['host1', 'host2']

def mytask():
    run('ls /var/www')

fab set_hosts mytask として実行すると、 set_hosts はホストリストがからのため "local" タスクとなりますが、 mytask は与えられた2つのホストに対して再び実行されます。

注釈

この手法は見せかけの "roles" の作成方法としてよく利用されていましたが、ロール機能が完全に実装されたので今は必要性が少なくなりました。とは言え、場合によっては今でも便利な方法です。

env.hosts と同じように、 env.roles (env.roledefs と間違えにように!)が与えられると、env.roledefs 内を探すためにロール名のリストとして扱われます。

コマンドライン経由でグローバルに

モジュールレベルでの env.hostsenv.rolesenv.exclude_hosts の設定に加え、コンマで分けた文字列引数としてコマンドラインのスイッチ --hosts/-H--roles/-R に渡すことでもこれらの設定が可能です。:

$ fab -H host1,host2 mytask

こうした実行は env.hosts = ['host1', 'host2'] と同等で、引数パーサーはこれらの引数を探し、パース時に env を設定します。

注釈

これらのスイッチを単一のホストやロールを設定するためだけに利用するのは、可能ですし、たしかに一般的です。Fabricは、与えられた文字列に対して string.split(',') を単に呼び出しているだけで、コンマがない文字列は単一のアイテムリストとして扱われます。

これらのコマンドラインスイッチは、fabfileが 読み込まれる前 に解釈されるということは重要なので、これに留意してください。つまり、fabfile内の env.hosts もしくは env.roles で再割当てされた値がこれらのスイッチを上書きするのです。

コマンドラインのホストとfabfileで指定されたホストの非破壊的なマージをしたい場合は、fabfileで env.hosts.extend() を使うようにしてください:

from fabric.api import env, run

env.hosts.extend(['host3', 'host4'])

def mytask():
    run('ls /var/www')

このfabfileを fab -H host1,host2 mytask として起動すると、 mytask の実行時に ['host1', 'host2', 'host3', 'host4']env.hosts に含まれます。

注釈

env.hosts は単なるPythonのリストオブジェクトなので env.hosts.append() やその他のメソッドも使うことができます。

コマンドライン経由でタスクごとに

いつも同じホストリストに対してすべてのタスクを実行したいのなら、グローバルにホストリストを設定するといいでしょう。しかし常にそうとは限らないので、Fabricはより粒度の細かい方法をいくつか提供していて、単一のタスクのみに適用されるホストリストを指定することができます。最初の方法はタスク引数を利用する方法です。

fab オプションと引数 でも説明したように、特別なコマンドラインシンタックスによってタスクごとに引数を指定できます。タスク機能に実際に引数を設定できるのに加え、hosthostsroleroles "引数" をセットするのに使われます。これはホストリストの組み立て時にFabricによって解釈されます(そして、タスクに渡された引数から取り除かれます)。

注釈

コンマはすでにタスク引数の分割に使われているので、各ホスト文字列やロール名の設定にはそれぞれの hosts もしくは roles 引数でセミコロンを使う必要があります。さらに、シェルがセミコロンを解釈しないように引数はクォートされていなければなりません。

以下のfabfileを見てみると、これまで使っていたものと同じですが、ホストの情報はまったく設定されていません:

from fabric.api import run

def mytask():
    run('ls /var/www')

mytast 用のタスクごとのホストを指定するには、以下のように実行します:

$ fab mytask:hosts="host1;host2"

これはどんなホストリストも上書きし、mytask は常にこの2つのホストに対して実行されます。

デコレーター経由でタスクごとに

与えられたタスクが常に事前に定義されたホストリストに対して実行される場合は、fabfile内でのこのリストの指定を望むことでしょう。これは hosts もしくは roles デコレータでタスク関数をデコレートすることで可能です。これらのデコレータは変数引数リストをとります。例えば:

from fabric.api import hosts, run

@hosts('host1', 'host2')
def mytask():
    run('ls /var/www')

これは、繰り返し可能な単一の引数を取ることもできます。例えば:

my_hosts = ('host1', 'host2')
@hosts(my_hosts)
def mytask():
    # ...

これが利用されると、このデコレータはこの特定のタスクのホストリスト用の env のチェックをオーバーライドします(env が変更されるわけではありません。単に無視されます)。そして、たとえ上記fabfileで env.hosts が指定されていたり fab--hosts/-H を使っていても mytask['host1', 'host2'] のホストリストに対して実行されます。

とは言え、デコレータのホストリストは、上のセクションで説明したタスクごとのコマンドラインを 上書きすることはありません

優先順位

ここまで、ホストリスト設定のどの方法が他の方法よりも優先するかについて説明してきました。もっと明確にするため、以下に簡単にまとめます:

  • タスクごとのコマンドラインホストリスト(fab mytask:host=host1)は他のすべてを完全にオーバーライドする。
  • タスクごとのデコレータで指定されたホストリスト(@hosts('host1'))は env 変数をオーバーライドする。
  • fabfileでグローバルに指定されたホストリスト(env.hosts = ['host1'])はコマンドラインでのホストリストをオーバーライド できる が、それは自分が注意していない場合(もしくは意図的に行った場合)のみ。
  • コマンドラインでグローバルに設定されたホストリストは(--hosts=host1) env 変数を初期化するが、それだけしかしない。

この優先順位はより一貫性を持たせるために将来的には少し変更されるかもしれません(例えば、コマンドラインのタスクごとのリストがコード内のリストに優先されるのと同じように --hostsenv.hosts より優先される)が、それは後方互換性リリースの時だけです。

ホストリストの結合

ホストリストがどのように作られるか で言及している様々なソース間のホストを "結合" する方法はありません。もし env.hosts['host1', 'host2', 'host3'] に設定されていて、関数ごと(例えば hosts 経由)のホストリストが ['host2', 'host3'] と設定されている場合、この関数は host1 に対しては 実行されません 。タスクごとのデコレータホストリストがの方が優先されるからです。

とは言え、与えられた各ソースでは、もしロールとホストの 両方 が設定された場合、両方ともひとつのホストリストにマージされます。例えば、以下のように両方のデコレータが使われているfabfileを見てみましょう:

from fabric.api import env, hosts, roles, run

env.roledefs = {'role1': ['b', 'c']}

@hosts('a', 'b')
@roles('role1')
def mytask():
    run('ls /var/www')

mytask 実行時にはコマンドラインのホストやロールが与えられていないとすると、このfabfileは role1hosts 呼び出しの中身の結合されたホストリスト ['a', 'b', 'c'] に対して mytask を実行します。

ホストリストの重複

デフォルトでは、 ホストリストの結合 をサポートするためFabricは最終的なホストリストから重複を取り除くので、与えられるどのホスト文字列も一度だけしか対象になりません。とは言え、これでは有益なこともある同じターゲットホストに対して明示的/意図的な複数回タスクの実行ができません。

重複除去の機能を無効にするには env.dedupe_hostsFalse にします。

特定のホストの除外

時には、ひとつもしくは複数の特定のホストを除外すると便利な時もあります。例えば、あるロールや自動的に生成されたホストリストから引き出されるいくつかの必要のないホストをオーバーライドする場合などです。

注釈

Fabric 1.4 からは接続できなかったホストをスキップする skip_bad_hosts を使うこともできます。

グローバルでは --exclude-hosts/-x でホストの除外ができます:

$ fab -R myrole -x host2,host5 mytask

myrole['host1', 'host2', ..., 'host15'] として定義されている場合、上のように実行すると、有効なホストリスト ['host1', 'host3', 'host4', 'host6', ..., 'host15'] となります。

注釈

このオプションを利用しても env.hosts は修正されません。メインの実行ループがリクエストされたホストをスキップするだけです。

除外は、付加的な exclude_hosts 引数を利用することでタスクごとに指定することもできます。これは、上記で言及したタスクごとの hostsroles 引数と同じように実装されていて、実際のタスク実行にストリップされます。以下の例では、上記のグローバル除外と同じ結果になります:

$ fab mytask:roles=myrole,exclude_hosts="host2;host5"

ホストリストはタスクごと引数の hosts と同じようにセミコロンで分けられます。

除外の結合

ホスト除外リストは、ホストリスト自身と同じように、宣言されている "levels" が違うリスト間ではマージされません。例えば、グローバルな -x オプションは、デコレータやキーワード引数でセットされたタスクごとのホストリストに影響しません。また、タスクごとの exclude_hosts キーワード引数もグローバルな -H リストに影響しません。

このルールにはひとつだけ小さな例外があります。@hosts もしくは @roles 経由でのホストリストの分析時に、CLIレベルのキーワード引数(mytask:exclude_hosts=x,y)が取り入れられます。したがって、 @hosts('host1', 'host2') でデコレートされているタスク関数が fab taskname:exclude_hosts=host2 として実行されると、 host1 だけに対してのみ実行されます。

ホストリストのマージに関しては、現行では機能は限定的(実装をシンプルに保つためでもあります)で、将来のリリースでは拡張されるかもしれません。

execute での賢いタスクの実行

バージョン 1.3 で追加.

ここの情報のほとんどは、最初の例で fab taskA taskB を呼び出したように、 fab 経由で実行される "トップレベル" のタスクに作用します。とは言え、以下の "meta" タスクのような複数タスクの実行をまとめたものも便利な時があります。

Fabric 1.3以前は ライブラリの利用 で書かれていたように手動で行う必要がありました。Fabricのデザインは魔法的な挙動を避けているので、単純にタスクを 呼び出しても roles のようなデコレータは考慮 しません

Fabric 1.3では新しく execute ヘルパー関数が追加されました。これは最初の引数としてタスクオブジェクトもしくはタスク名を取ります。コマンドラインから与えられたタスクを呼び出すのと同じくらい効率的に利用できます。上の ホストリストがどのように作られるか で与えられたすべてのルールが適用されます。( execute への hostsroles キーワード引数は、他のすべてのホスト/ロール設定方法をオーバーライドする CLIのタスクごとの引数 に類似しています)

例として、ウェブアプリケーションをデプロイする2つの別個に定義されたfabfileをあげます。

from fabric.api import run, roles

env.roledefs = {
    'db': ['db1', 'db2'],
    'web': ['web1', 'web2', 'web3'],
}

@roles('db')
def migrate():
    # Database stuff here.
    pass

@roles('web')
def update():
    # Code updates here.
    pass

Fabric <=1.2では、migrate をDBサーバに対して確実に実行し、update をWebサーバに対して確実に実行する唯一の方法( env.host_string 操作の短いマニュアル)は両方をトップレベルのタスクとして呼び出す方法しかありませんでした:

$ fab migrate update

Fabric >=1.3ではメタタスクのセットアップに execute が使えます。 import の行を以下のようにします:

from fabric.api import run, roles, execute

そして、ファイルの最後に次を追加します:

def deploy():
    execute(migrate)
    execute(update)

これだけです; roles デコレータが期待通りに履行し、以下の実行シーケンスの結果になります:

  • db1 に対して migrate
  • db2 に対して migrate
  • web1 に対して update
  • web2 に対して update
  • web3 に対して update

警告

このテクニックは、ホストリストを自分では持たないタスク(これにはグローバルなホストリスト設定も含まれます)は一度しか実行されないので動作します。もし、複数ホストに対して実行される "通常の" タスク内で利用された場合、execute への呼び出しは複数回実行され、結果としてサブタスク呼び出しの倍数分実行されるので、お気をつけて!

自分の execute 呼び出しを1度だけの呼び出しにするには runs_once デコレータを使います。

参考

execute, runs_once

マルチホストの結果へのアクセスに execute を活用する

Fabricの実行がひと仕事ある場合、特に並列にある場合、最後にたくさんあるホストごとの結果の値を、例えばテーブルサマリーの表示や計算の実行をするためなど、ひとまとめにしたいことがあると思います。

Fabricのデフォルトの "ナイーブ" モード(あなたが頼りにしている、ホストリストに対するあなたのために行うFabricの繰り返し処理のモードです)ではこれはできませんが、 execute を使うととても簡単です。単純に実際の分割したタスクの呼び出しから execute との実行をコントロールする "meta" タスクの呼び出しにスイッチします。

from fabric.api import task, execute, run, runs_once

@task
def workhorse():
    return run("get my infos")

@task
@runs_once
def go():
    results = execute(workhorse)
    print results

上の例では、 workhorse はFabricで可能なこと、文字通り古い "naive" なタスクはすべて可能です。なにか有益なことを返す必要がある時を除いてですが。

go は新しいエントリーポイント( fab go などとして実行されます)で、その仕事は execute 呼び出しから results 辞書を取り出し、それに対して必要なことをなんでもすることです。返り値の構造についての詳細はAPIドキュメントをご覧ください。

ホストリストの動的セットとの execute の利用

実行時にターゲットホストリストの参照を並行で行うのはFabricの中級から上級のよくあるユースケースです( ロール の利用では十分ではない場合)。 execute は以下のようにこれをとても簡単に実現できます:

from fabric.api import run, execute, task

# For example, code talking to an HTTP API, or a database, or ...
from mylib import external_datastore

# This is the actual algorithm involved. It does not care about host
# lists at all.
def do_work():
    run("something interesting on a host")

# This is the user-facing task invoked on the command line.
@task
def deploy(lookup_param):
    # This is the magic you don't get with @hosts or @roles.
    # Even lazy-loading roles require you to declare available roles
    # beforehand. Here, the sky is the limit.
    host_list = external_datastore.query(lookup_param)
    # Put this dynamically generated host list together with the work to be
    # done.
    execute(do_work, hosts=host_list)

例えば、 external_datastore が単純な "データベース内をタグでホストをルックアップ" するサービスなら、そして自分のアプリケーション スタックに関連するタグが付けられたすべてのホストに対してタスクを実行するのなら、上記を以下のように呼び出すことができます:

$ fab deploy:app

ちょっと待って! DBサーバ上のデータのマイグレーションがどっかに行ってしまいました。ソースリポジトリのマイグレーション用のコードを修正して、DBボックスだけに再度どプロイしてみましょう:

$ fab deploy:db

このユースケースはロールに似ていますが、もっと潜在力があり、決してひとつの引数だけに限定されるものでもありません。どのようにもタスクを定義でき、必要に応じてどのようにも外部のデータストアにクエリーを行うことができます。結局のところ、ただのPythonなのです。

別のアプローチ

上記と似ているけれども、execute 呼び出しを明示する代わりに fab の機能を利用して連続で複数タスクを呼び出すには、ホストリストの参照タスクでの env.hosts を変化させ、同じセッションで do_work を呼び出します:

from fabric.api import run, task

from mylib import external_datastore

# Marked as a publicly visible task, but otherwise unchanged: still just
# "do the work, let somebody else worry about what hosts to run on".
@task
def do_work():
    run("something interesting on a host")

@task
def set_hosts(lookup_param):
    # Update env.hosts instead of calling execute()
    env.hosts = external_datastore.query(lookup_param)

そして次のように実行されます:

$ fab set_hosts:app do_work

その前のアプローチと比べた時のこちらのアプローチの利点は do_work をどんな "workhorse" タスクとも入れ替え可能ということです:

$ fab set_hosts:db snapshot
$ fab set_hosts:cassandra,cluster2 repair_ring
$ fab set_hosts:redis,environ=prod status

失敗の扱い

タスクリストが構築されると、Fabricは 実行ストラテジー で説明したようにこのタスクの実行を開始し、そのホストリスト全体にすべてのタスクが実行されます。とは言え、Fabricはデフォルトでは "fail-fast" の挙動パターンになっていて、もし何かが失敗した場合、例えばリモートプログラムがノンゼロ返り値を返したり、自分のfabfileのPythonコードが例外に遭遇したりした場合、すぐに停止します。

これは通常は望ましい挙動ですが、このルールにはたくさんの例外があり、そのため、Fabricはブール設定の env.warn_only を提供しています。これはデフォルトでは False になっていて、エラー状態はただちにそのプログラムの停止を意味します。しかし、もし失敗時に -- settings コンテキストマネージャーなどで -- env.warn_onlyTrue に設定されていると、Fabricは警告メッセージを発しますがプログラムの実行は継続します。

接続

実は fab 自身ではリモートホストへの接続は行っていません。その代わり、それぞれのホストごとに対して一つのタスクをそれぞれ個別に実行するようにすることと、env変数 env.host_string に正しい値がセットされていることを単純に保証しています。Fabricをライブラリとして活用したいユーザーは、手動で行うことにより同じような動作を達成することができます(とは言え、Fabric 1.3では execute の利用をのほうが好ましく、より強力です)。

env.host_string は、(その名称がほのめかしているように) "カレントの" ホスト文字列で、ネットワークを利用する関数が実行されるときに、どの接続を行うか(もしくは再利用するか)をFabricが決定するために利用されます。 runput のようなオペレーションは、ホスト文字列をSSH接続オブジェクトにマップしている共有辞書内の参照キーとして env.host_string を利用します。

注釈

この接続用の辞書(今のところ fabric.state.connections にあります)はキャッシュとして振る舞い、オーバーヘッドを減らすために可能なら前回作成された接続を返そうとし、そうした接続がなければ新たに作成します。

レイジーな接続

接続は各オペレーションによって駆動されるので、Fabricは実際に必要になるまで接続を行いません。以下の例を見てください。このタスクはリモートサーバとのやりとりの前にローカルでハウスキーピング処理を行います:

from fabric.api import *

@hosts('host1')
def clean_and_upload():
    local('find assets/ -name "*.DS_Store" -exec rm '{}' \;')
    local('tar czf /tmp/assets.tgz assets/')
    put('/tmp/assets.tgz', '/tmp/assets.tgz')
    with cd('/var/www/myapp/'):
        run('tar xzf /tmp/assets.tgz')

接続という観点からどのようなことが起こっているのか順に見て行きましょう:

  1. 2つの local 呼び出しがどんなものであれ接続をまったく行わないで実行されます
  2. puthost1 へ接続するための接続キャッシュを要求します
  3. 接続キャッシュは該当のホスト文字列用の既存の接続を見つけられなかったので、新しいSSH接続を作成し、その接続を put に返します
  4. put がこの接続を通じてファイルをアップロードします
  5. 最後に、 run 呼び出しが同じホスト文字列への接続のためのキャッシュを要求し、既存のキャッシュされた接続を自身の利用のために与えます

以上を基に推察すると、ネットワーク関連の操作を伴わないタスクは実際にどのような接続も始めないことがお分かりになるでしょう(ただし、もしあればですが、ホストリスト内の各ホストに一度実行されます)。

接続の解除

Fabricの接続キャッシュは接続自身を閉じることはありません。どのように使われていてもそのままにしておきます。 fab ツールがその状態を保持し、すべての開いている接続に対して繰り返し処理を行い、プログラムから抜け出る直前に(タスクの成功、不成功に関わらず)それらの接続を閉じます。

ライブラリのユーザーは、自分のプログラムから抜け出る前にすべての開いている接続を確実に閉じるようにする必要が有ります。これは、自分のスクリプトの最後で disconnect_all を呼び出すことによって実施可能です。

注釈

disconnect_all は将来的にはよりパブリックな場所に移動されるかもしれません。わたしたちは、Fabricのライブラリとしての側面をより堅固に、より整理されたものへしようと作業をしています。

複数回接続の試みとうまくいかないホストのスキップ

Fabric 1.4では、エラーを伴った中止の前に、リモートサーバーへの接続が複数回試行されるかもしれません。Fabricはあきらめる前に env.connection_attempts での回数分、毎回 env.timeout で指定された秒数のタイムアウトまで接続をトライします(これらの値は、現行では以前の挙動に合わせるためデフォルトで1回と10秒になっていますが、必要に応じて安全に変更かのうです)。

さらに、サーバへの接続の完全な失敗が完全にハード的な停止ではない場合でも set env.skip_bad_hostsTrue にすれば大抵の場合(通常は初期接続)でFabricは中止をする代わりに単に警告を発し、タスクの実行を続けます。

バージョン 1.4 で追加.

パスワード管理

Fabricはメモリー上に2層のパスワードキャッシュを保持し、特定の状況でのログインとsudoのパスワードを記憶します。これにより、複数システムで同じパスワードを共有しているとき [1] やリモートシステムの sudo 設定が自身のパスワードをキャッシュしない時に退屈な再入力を避けるのに役立ちます。

最初の層は単純なデフォルトもしくはフォールバックのパスワードのキャッシュ、 env.password です(これは --password もしくは --initial-password-prompt 経由のコマンドラインでも設定可能です)。このenv変数は(空でない場合に)特定のホストのキャッシュ(下を参照)がカレントの ホスト文字列 用のエントリを持っていない時に試される一つのパスワードを保持します。

env.passwords (複数形!) はユーザーごと/ホストごとのキャッシュとして利用され、ユーザー/ホスト/ポートの各組み合わせごとにもっとも最近入力されたパスワードを保持します (もしこの構造を手動で修正する場合は この3つすべての値 を必ず含める必要があるということに 留意 してください)。このキャッシュのおかげで同一セッションでの複数の異なるユーザーおよび/またはホストへの接続で、それぞれ一度のパスワード入力だけで済ますことができます。(Fabricの以前のバージョンでは単一のデフォルトパスワードのキャッシュのみしか利用できなかったため、その前に入力されたパスワードは毎回無効になり、パスワードの再入力が必要になっていました)

設定やセッションが接続するホストの数にもよりますが、このenv変数のどちらかもしくは両方を設定すると便利でしょう。とは言え、Fabricは必要に応じて追加の設定なしでも自動的にこれらを入力します。

特に、ユーザーにパスワードプロンプトが表示されるたびに、入力された値は単一のデフォルトパスワードキャッシュと env.host_string のカレントの値のためのキャッシュの値の両方のアップデートに使われます。

[1]同一のパスワード設定に頼るよりもSSHの 鍵ベースのアクセス の利用を強くおすすめします。こちらのほうがかなり安全です。

ネイティブのSSH configファイルの活用

コマンドラインのSSHクライアント( OpenSSH によって提供されているものなど)は、通常は ssh_config として知られる特定の設定フォーマットを利用し、プラットフォーム特有の場所の $HOME/.ssh/config (もしくは --ssh-config-path/env.ssh_config_path に与えられる任意のパス)にあるファイルからそれを読み込みます。このファイルはデフォルトもしくはホストごとのユーザ名、ホスト名のエイリアス、その他設定の切り替え( エージェントフォワーディング を利用するか否かなど)など、さまざまなSSHオプションの設定を可能にします。

FabricのSSH実装では、実際にSSH configファイルがあればそこからこれらのオプションのサブセットを読み込むことが可能です。この挙動は後方互換性のためにデフォルトでは有効になっていませんが、お使いのfabfileの一番上で env.use_ssh_configTrue にすることによって有効にすることができます。

これを有効にすると、次のSSH config指示が読み込まれ、Fabricによって履行されます:

  • UserPort は、次の方法で他に指定されない限り、適切な接続パラメータに利用されます:

    • グローバルに指定された User/Port は、該当のenv変数がセットされていなければ、カレントの初期値(それぞれローカルのユーザー名と22)の代わりに利用されます。
    • しかし、 env.user/env.portセットされていれば 、グローバルの User/Port の値をオーバーライドします。
    • ホスト文字列自身の User/port の値(例えば``hostname:222``)は ssh_config の値を含むすべてをオーバーライドします。
  • 通常の ssh と同じように HostName は与えられたホスト名で置き換えられます。 HostName example.com を指定している Host foo のエントリーは、Fabricにホスト名 'foo' を与えることができ、接続時に 'example.com' に展開されます。

  • IdentityFileenv.key_filename を(置き換えるのではなく)拡張します。

  • ForwardAgent は "OR(論理和)" 方式で env.forward_agent を補完します。どちらかが真の値にセットされていれば、エージェントフォワーディングは有効になります。

  • ProxyCommand は通常の ssh と同じようにホスト接続でのプロキシコマンドを動作させます。

    注釈

    もしSSHのトラフィックをゲートウェイに送るだけなら、ゲートウェイとして ProxyCommand を使う通常の ssh gatewayhost nc %h %p 方式よりも env.gateway の方がより効率的な接続方法です。

    注釈

    もしSSH configファイルが ProxyCommand を含んでいて なおかつ env.gatewayNone 以外の値にセットされている場合、env.gateway が優先され ProxyCommand は無視されます。

    もしすでにSSH configファイルが作成されていれば、confファイルの内容全体で対処するよりも env.gateway (例えば settings 経由で)を修正するほうが容易でしょう。