Red Hatのさいとうです。
今月中に(おそらく)リリースされる予定の、Ansibleの最新バージョン2.8の新機能について、これから数回に分けて紹介しようと思います。
第1回として選んだのはInterpreter Discovery機能です。
Interpreter Discovery機能
Ansibleは、モジュールから生成されたPythonの実行プログラムを、ターゲットホスト上に転送し、これをSSHログインして実行することで、ターゲットホストに対してユーザの追加やパッケージのインストールなどの、さまざまな操作を行います。
このときに利用されるPythonインタプリタは、インベントリファイルやPlaybookの変数(ansible_python_interpreter
)にパスを設定することで、明示的に指定することができます。ちなみにデフォルトパスは/usr/bin/python
です。
Ansible 2.8では、規定されたPythonインタプリタのリストから、ターゲットホストにマッチしたPythonインタプリタを見つけ出して、実行時に利用するというInventory Discovery機能が実装されました。ただし、Interpreter DiscoveryはターゲットホストがLinuxである場合にのみ機能します。
尚、ansible_python_interpreter
でパスが明示的に指定されている場合は、上記のリストにマッチするPythonインタプリタが存在した場合でも、この値でオーバーライドされて、実行時のパスとしてはansible_python_interpreter
の値が採用されます。
Interpreter Discoveryの仕組み
Interpreter Discoveryの挙動の指定
Interpreter Discoveryの挙動は、Ansibleの設定ファイル(ansible.cfg
)のdefaults
セクションにあるinterpreter_python
に、以下の4つのパラメータから1つを選んで指定することができます。
- auto_legacy (Ansible 2.8のデフォルト値)
- auto (Ansible 2.12リリースでのデフォルト値となる予定...いつだよ)
- auto_legacy_silent (auto_legacyと同様の振る舞いだがWARNINGレベルのメッセージ出力されない)
- auto_silent(autoと同様の振る舞いだがWARNINGレベルのメッセージは出力されない)
auto_legacy | auto_legacy_silent
auto_legacyは、その名の通りAnsibleの過去のバージョンの挙動(/usr/bin/python
を利用する)を踏襲しつつ、/usr/bin/python
が存在しなかった場合は、Interpreter Discovery機能で取得したPythonインタプリタのパスを利用する挙動となっています。
1.ターゲットとなるLinuxのディストリビューションとバージョンを取得します(gather_facts
の前段で動作することになるため、別の仕組みでターゲットホストのOS情報を取得しています)
2.INTERPRETER_PYTHON_DISTRO_MAP
で規定されているLinuxディストリビューションとバージョンから、デフォルト値となるPythonインタプリタを決める。バージョンマップは以下の通りです(CentOS8まだ出てないよ!とか、Fedoraはもう30だよ! とかいうのは気にしない...気にしない)
centos: &id001 '6': /usr/bin/python '8': /usr/libexec/platform-python fedora: '23': /usr/bin/python3 redhat: *id001 rhel: *id001 ubuntu: '14': /usr/bin/python '16': /usr/bin/python3
3.INTERPRETER_PYTHON_DISTRO_MAP
で規定されたPythonインタプリタが存在しなかった場合に備えて、INTERPRETER_PYTHON_FALLBACK
で規定されたPythonインタプリタ候補のパスをディスカバリして存在しないパスをフィルタしたリストを作成する。候補リストのフィルタリングはターゲットホスト上でcommand -v <パス>
の実行可否で判断しています。リスト構造となっているので、これがそのままPythonインタプリタの優先順位となります。
- /usr/bin/python - python3.7 - python3.6 - python3.5 - python2.7 - python2.6 - /usr/libexec/platform-python - /usr/bin/python3 - python
4.1-3の処理が終わったところで、Pythonインタプリタのパスを決定します。まず、以前のバージョンとの互換性を保つために、/usr/bin/python
が存在していれば、最優先でこれを利用します。/usr/bin/python
が存在しなかった場合は、INTERPRETER_PYTHON_DISTRO_MAP
で選択されたパスが、更にINTERPRETER_PYTHON_DISTRO_MAP
のパスも存在しなかった場合は、INTERPRETER_PYTHON_FALLBACK
でリストにある有効な最初のパスのPythonインタプリタが採用されます。
ちなみに、INTERPRETER_PYTHON_DISTRO_MAP
とINTERPRETER_PYTHON_FALLBACK
の既定値は、ansible-config list
コマンドで確認することができますが、この値をansible.cfg
ファイル内で変更することはできません(いまのところ)。
auto | auto_silent
auto_legacyの挙動と違うのは、/usr/bin/python
が存在していても無条件で採用しない点です。INTERPRETER_PYTHON_DISTRO_MAP
で取得されたPythonインタプリタのパスが存在している場合は、これが優先され、存在しなかった場合はINTERPRETER_PYTHON_FALLBACK
を元に作成された有効なパスリストの優先順にしたがって、Pythonインタプリタのパスが決定されます。
テストしてみる
それでは、Ansible 2.8.0rc2を使用して、Interpreter Discoveryの動きを見てみましょう。インベントリファイルで明示的にansible_python_interpreter
に/usr/libexec/platform-python
を指定することなく、前述のルールにしたがって、Pythonインタプリタのパスをディスカバリしてくれます。
$ ansible rhel8 -i inventory -m ping tower | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" }
まとめ
Interpreter Discovery機能は非常に便利ですが、残念ながらINTERPRETER_PYTHON_DISTRO_MAP
とINTERPRETER_PYTHON_FALLBACK
は、設定ファイル(ansible.cfg
)上で自由に編集することはできません。それでも、RHEL8やUbuntu18.04のように/usr/bin/python
を持たない可能性のあるOSを、特別な設定をすることなく操作できるという点では、現状でも十分に利用価値があります。今後のエンハンスに期待しつつ、挙動を理解して有効に活用していきましょう。
次はどの新機能について書こうかなぁ...