概要
fabric2のインストール手順と簡単な使い方です。
fabric1と2は別物だと考えた方がよいです。fabric2は、Pythonのinvokeライブラリのラッパーなので、invokeのドキュメントも参考になります。
Version
- Python 3.7.1
- fabric 2.4.0
fabric2のインストール
以下のコマンドでインストール。
$ pip install fabric
以下でもインストール可能だが、fab2コマンドになったり、import fabric2
としなくてはいけなくなるので面倒。
$ pip install fabric2
基本的な使い方
fabfile.pyを作成。
以下は接続先でhostnameコマンドを実行するサンプルスクリプト。
#-*- coding:utf-8 -*-
import getpass
from fabric import Connection, Config
from invoke import task
@task
def sample(c):
Config.user = 'username'
hostname = 'example.com'
sudo_pass = getpass.getpass("What's your sudo password?")
config = Config(overrides={'sudo': {'password': sudo_pass}})
c = Connection(hostname, config=config)
c.run('hostname')
以下のコマンドで実行可能task一覧を確認できる。
$ fab -l
Available tasks:
sample
sample taskを実行。
$ fab sample
What's your sudo password?
example.com
fabコマンドではなくpythonコマンドで実行する方法
以下で実行できる。
from fabric import Connection, Config
Config.user = 'username'
hostname = 'yourhostname'
c = Connection(hostname)
c.run('hostname')
$ python sample.py
sudoコマンドにパスワードを渡す方法
結論から言うと、以下の「方法3」がベスト。
方法1
sudoでsudo: no tty present and no askpass program specified
と怒られる場合、runでpty=True
を付ける。
ただし、この方法だとsudoコマンドがある度にパスワードの入力が必要になる。
#-*- coding:utf-8 -*-
from fabric import Connection, Config
from invoke import task
@task
def sample(c):
Config.user = 'username'
hostname = 'example.com'
c = Connection(hostname)
c.run('hostname')
c.run('whoami')
c.run('sudo whoami', pty=True)
実行
$ fab sample
example.com
username
[sudo] password for username:
root
方法2
c.sudoを使い、引数でpasswordを渡す。
この方法なら毎度sudoパスワードを入力しなくて済む。
環境変数でpasswordを渡すことで、ソース内にパスワードを記述することを回避できる。
@task
def sample(c):
c.sudo('whoami', password=os.environ.get('SUDO_PASSWORD'))
方法3
--prompt-for-sudo-password
optionを使う。
このオプションを使うことで、最初にパスワードをpromptで入力させることができる。しかも、最初に1度だけ入力させればよい。c.sudo()
へのパスワードの渡し方は、方法2と同じ。
$ fab --prompt-for-sudo-password sample
Desired 'sudo.password' config value:
c.config.sudo.password
で入力した文字列を取得できます。
@task
def sample(c):
print(c.config.sudo.password)
c.sudo('whoami', hide='both', echo=True, password=c.config.sudo.password)
ちなみに、以下のドキュメントを読んだが、入力したパスワードを取得する方法がよくわからなかったので
http://docs.pyinvoke.org/en/1.2/invoke.html
以下のinvokeのソースを追ったら分かった。
https://github.com/pyinvoke/invoke/blob/0de7020aa908d4a1afc5a7287e29196a657c292a/tests/_support/sudo_prompt.py
fabfileを分割する
fabfileをtaskごとに分割します。
production, developmentで環境ごとに異なる設定を読み込み、接続先でwhoamiを実行するサンプルを作ってみます。
以下のディレクトリ構成でファイルを作成します。
.
└── fabfile
├── hosts.py # 環境ごとの設定を読むモジュール
├── __init__.py # モジュールをimportするファイル
└── sample.py # mainのtask(whoamiを実行する)
__init__.pyで、hosts, sampleをimportします。
#-*- coding:utf-8 -*-
from fabfile.hosts import *
from fabfile.sample import *
production, developmentそれぞれの設定を定義します。
#-*- coding:utf-8 -*-
from fabric import Connection, Config
from invoke import task
@task
def production(c):
Config.environment = 'production'
Config.hostname = 'prod.example.com'
Config.user = 'username'
@task
def development(c):
Config.environment = 'development'
Config.hostname = 'dev.example.com'
Config.user = 'username'
whoamiを実行するtaskを作成。
#-*- coding:utf-8 -*-
from fabric import Connection, Config
from invoke import task
import os
@task(default=True)
def check(c):
print(Config.environment)
print(Config.hostname)
with Connection(Config.hostname) as c:
'''
結果を変数にセットすることも可能
hide=Trueでrunコマンドの標準出力を抑制する
'''
result = c.run('whoami', hide=True)
print(result.stdout.strip())
'''
echo=Trueで実行コマンドも出力する
ただし、hide=Trueだと出力されなくなるので、hide='both'とする
'''
result = c.run('whoami', hide='both', echo=True)
print(result.stdout.strip())
'''
sudoで実行
'''
result = c.sudo('whoami', hide='both', password=os.environ.get('SUDO_PASSWORD'))
print(result.stdout.strip())
'''
warn=Trueで、コマンドでエラーが発生しても中断しないようにできる
以下のように自分でエラー処理を定義できる
'''
result = c.run('abcdef', hide=True, warn=True)
if result.ok:
print(result.stdout.strip())
else:
print("ERROR: {}".format(result.stderr.strip()))
実行可能コマンド一覧を確認。
$ export SUDO_PASSWORD=mypassword
$ fab --list
Available tasks:
check
production
development
Default task: check
実行
$ fab development check
development
dev.example.com
username
whoami
username
root
ERROR: bash: abcdef: command not found
fabコマンドに任意のoptionを付与する方法
foo
というoptionを付与する場合
#-*- coding:utf-8 -*-
from fabfile.sample import *
#-*- coding:utf-8 -*-
from fabric import Connection, Config
from invoke import task
@task(optional=['foo'])
def foobar(c, foo=''):
print(foo)
実行
$ fab foobar --foo=bar
bar
コマンドを連続で実行する場合
cd /tmp && pwd
のようなことする場合。
以下のやり方では、それぞれ独立して動いてしまうため、pwd
しても/tmp
とはならない。
@task
def sample(c):
with Connection('hostname') as c:
c.run('cd /tmp'):
c.run('pwd')
方法1: cd()
を使って事前にディレクトリを移動する方法
@task
def sample(c):
with Connection('hostname') as c:
with c.cd('cd /tmp'):
c.run('pwd')
方法2: prefix()
で事前にコマンドを実行する方法
こちらであれば、cd
以外のコマンドを実行したい場合でも使える。
@task
def sample(c):
with Connection('hostname') as c:
with c.prefix('cd /tmp'):
c.run('pwd')
ssh秘密鍵のパスを指定する方法
#-*- coding:utf-8 -*-
from fabric import Connection, Config
from invoke import task
@task
def sample(c):
c = Connection(
host='example.com',
user='username',
connect_kwargs={
"key_filename": "/home/username/.ssh/private.key",
},
)
c.run('hostname')
c.run('whoami')
c.run('sudo whoami', pty=True)