こんにちは、滝澤です。
いくつかのプロジェクトでタスクランナーFabric 2を使う機会がありました。少しですが知見が溜まったので紹介します。 また、Fabric 1.xを利用していた方は互換性も気になると思いますでのその点についても紹介します。
記事が長くなったので3編に分けます。
- 前編: Fabricの概要
- 中編: Invokeの使い方
- 後編: Fabricの使い方
本記事は後編の「Fabricの使い方」になります。
なお、執筆時点(2018年11月21日)での最新バージョンはFabric 2.4.0、Invoke 1.2.0です。 動作確認はPython 3.7.1にて行っています。
Fabricについて
Fabricについては前編で紹介したのでここでは省略します。
Fabricのインストール
pipコマンドでインストールできます。依存によりInvokeやParamikoもインストールされます。
$ pip install fabric
タスクランナーFabric
Fabricのタスクランナーとしての使い方を紹介します。
ssh_configと設定ファイル
リモートのホストにSSH接続を行うため、リモートホストへのSSH接続の情報が必要となります。
そのため、ssh_config
ファイルを用意するとよいでしょう。デフォルトでは~/.ssh/config
や/etc/ssh/ssh_config
が参照されますが、このタスクのプロジェクト用として独立して配置してもよいでしょう。
Host host01 User foo Identityfile ~/.ssh/host01.key HostName host01.example.com
後述するfab
コマンドのオプション-S
や--ssh-config
でssh_config
ファイルを指定できます。
fab -S ssh_config タスク名
ssh_config
ファイルを指定するのを省略したい場合はFabricの設定ファイルを用意します。
設定ファイルの配置方法や記述方法にはいくつかあるのですが、ここでは同じ場所にfabric.yaml
という名前のファイルを作成し、次のようにパラメータssh_config_path
にssh_config
ファイルのパス名を指定します。
--- ssh_config_path: ssh_config
公式ドキュメント:
タスク実行
タスクの定義方法を紹介します。 例として、与えられたシェルコマンドを単純に実行するタスクshを定義してみます。
まず、fabric.py
という名前のファイルを作成します。
fabricパッケージからtaskモジュールをインポートします。
from fabric import task
タスク名sh
の関数を定義し、1つ目の引数にはFabricのコネクションの変数としてc
を指定し、2つ目以降の引数にはfabコマンドで渡される引数を指定します。さらに、タスクとして認識させるためにデコレーター@task
を付けます。
run()
の引数にシェルで実行するコマンドを指定します。
@task def sh(c, command): """Execute a shell command.""" c.run(command)
tasks.py
ファイルと同じディレクトリにおいて、fabコマンドを実行します。fabコマンドの基本的な使い方は次の通りです。
fab -H ホスト名のカンマ区切りのリスト タスク名 [引数...]
ここで接続先のホスト名とタスク名sh
と引数のuname -n
を指定してfabコマンドを実行してみます。
SSHのパスフレーズを入力する場合は--prompt-for-passphrase
オプションを付けます。
$ fab --prompt-for-passphrase -H host01 sh 'uname -n' host01
uname -n
コマンドの実行結果が出力されます。
なお、ssh-agentを利用して予めパスフレーズを入力しておけば、--prompt-for-passphrase
オプションを省略できます。
$ ssh-agent /bin/bash $ ssh-add ~/.ssh/host01.key Enter passphrase for /home/foo/.ssh/host01.key: Identity added: /home/foo/.ssh/host01.key (/home/foo/.ssh/host01.key) $ fab -H host01 sh 'uname -n' host01
タスクの実行方法は以上の通りです。
上記の例ではタスクsh
を定義しましたが、実は次のように--
を指定するとタスクの読み込みをせずにシェルコマンドを実行することができます。SSH接続の確認に使うとよいでしょう。
$ fab -H host01 -- uname -n host01
前編で説明しましたが、Fabric 2はInvokeのSSHラッパーです。
そのため、Invokeで説明したrun()
, sudo()
, cd()
, prefix()
はSSH接続先で実行されます。
タスク一覧についても、Invokeと同様に--list
オプションを付けてfabコマンドを実行することで表示できます。
$ fab --list Available tasks: get Execute get(). local Execute local(). print-date Print date. put Execute put(). sh Execute a shell command. uname Execute uname.
Fabric特有の機能もありますので、以降のセクションで紹介していきます。
公式ドキュメント:
local()
SSH接続先ではなく、ローカルでコマンドを実行したい場合はlocal()
を使います。
@task def local(c): """Execute local().""" c.local("uname -n")
タスクlocal
を実行すると、接続先のホストではなくローカル上でコマンドが実行されます。
$ fab -H host01 local foo-pc.local
公式ドキュメント:
put()とget()
SFTPを利用して、リモートホストにファイルを送信したり、リモートホストからファイルを取得したりすることができます。
ファイルの送信にはput()
を、ファイルの取得にはget()
を使います。
それぞれのラッパーのタスクを次のように作成してみます。
@task def put(c, local, remote): """Execute put().""" c.put(local, remote) @task def get(c, remote, local): """Execute get().""" c.get(remote, local)
タスクput
とタスクget
をそれぞれ実行してみます。
$ fab -H host01 put test.dat test.dat $ fab -H host01 -- ls -l test.dat -rw-r--r-- 1 foo users 5 11月 21 15:04 2018 test.dat $ fab -H host01 get test.dat test2.dat -rw-r--r-- 1 foo staff 5 Nov 21 15:07 test2.dat
なお、put()
のlocal
およびget()
のlocal
にはfile-likeオブジェクトも利用できます。
以上でタスクランナーとしてのFabricの基本的な使い方を紹介しました。
公式ドキュメント:
Patchwork
リモートのホスト上でファイルの中身を操作しようとするとそれなりに作り込みが必要になります。
Fabric 1.xではcontribモジュールにおいて様々な便利なファイル操作の関数が提供されていました。
Fabric 2ではcontribモジュールは提供されていなく、代わりにPatchworkという関連プロジェクトのライブラリが提供されています。しかし、"still early in development"というステータスではあります。
While Patchwork has been released with a major version number to signal adherence to semantic versioning, it's still early in development and has not fully achieved its design vision yet.
公式ドキュメント:
ライブラリとしての利用例
FabricをSSH経由でリモートシェルコマンドを実行するPythonライブラリとして利用する例を紹介します。
基本的な処理の流れ
ライブラリとしての利用方法を次のスクリプトを用いて説明します。
ホストhost01にSSH接続してuname -n
コマンドを実行するだけのものです。
from fabric import Config, Connection def get_uname(hostname, config=None): """Execute uname.""" c = Connection(hostname, config=config) result = c.run("uname -n", hide=True) uname = result.stdout.strip() return uname def main(): config = Config( runtime_ssh_path="ssh_config" ) uname = get_uname("host01", config=config) print(uname) if __name__ == '__main__': main()
処理の流れは次の通りです。なお、ssh-agentを利用してパスフレーズの入力を省略する前提での流れです。
Config
オブジェクトの生成- システムやユーザーのデフォルトの
ssh_config
ファイルではなく、独自のssh_config
ファイルを使いたい場合は、上記のようにruntime_ssh_path
パラメータを指定してConfig
オブジェクトを生成します。
- システムやユーザーのデフォルトの
Connection
オブジェクトの生成- 接続先のホスト名を引数として
Connection
オブジェクトを生成します。デフォルトの設定のままでよければconfig
パラメータの指定は不要です。
- 接続先のホスト名を引数として
- 生成した
Connection
オブジェクトに対して、コマンドを実行する関数を実行します。ここではrun()
を実行しています。
なお、ドキュメントによると生成したConnection
オブジェクトの明示的なクローズは必要ないそうです。
公式ドキュメント:
スクリプト内での設定
ssh_config
ファイルを使わずにスクリプト内でSSH接続のパラメータを設定したい場合には、次のようにoverrides
パラメータを指定してConfigオブジェクトを生成します。
user = "foo" port = 22 key_filename = "/home/foo/.ssh/host01.key" config = Config(overrides={ "user": user, "port": port, "connect_kwargs": { "key_filename": key_filename }, })
overrides
パラメータにはデフォルトの設定値を上書きする設定パラメータをディクショナリーとして格納します。
デフォルトの設定値の詳細は次のサイトをご覧ください。
例えば、sudoのパスワードも指定したい場合は、次のような内容をoverrides
のディクショナリーに追加します。
"sudo": { "password": sudo_password },
connect_kwargs
にはParamikoのSSHClient.connect()に渡すパラメータを指定します。
ここではkey_filename
にプライベート鍵ファイルのパスを指定しています。
以上のようにして設定パラメータをカスタマイズできます。
公式ドキュメント:
最後に
本記事ではFabric 2とInvokeの基本的な使い方を紹介しました。
Fabric 1.xのスクリプトをFabric 2に移行するのに私自身が色々嵌まったので本記事が少しでも参考になれば幸いです。
目次
- 前編: Fabricの概要
- 中編: Invokeの使い方
- 後編: Fabricの使い方