Ansible2.8の新機能1 - Interpreter Discovery

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つを選んで指定することができます。

  1. auto_legacy (Ansible 2.8のデフォルト値)
  2. auto (Ansible 2.12リリースでのデフォルト値となる予定...いつだよ)
  3. auto_legacy_silent (auto_legacyと同様の振る舞いだがWARNINGレベルのメッセージ出力されない)
  4. 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_MAPINTERPRETER_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_MAPINTERPRETER_PYTHON_FALLBACKは、設定ファイル(ansible.cfg)上で自由に編集することはできません。それでも、RHEL8やUbuntu18.04のように/usr/bin/pythonを持たない可能性のあるOSを、特別な設定をすることなく操作できるという点では、現状でも十分に利用価値があります。今後のエンハンスに期待しつつ、挙動を理解して有効に活用していきましょう。 次はどの新機能について書こうかなぁ...

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません