はじめに
最近、ansible/ansible-sdk というリポジトリが公開されました。
Python から Playbook を実行できるようです。とりあえず気になるので試してみました。
リポジトリ内にサンプルの Python スクリプトと、Playbookが入ってるので試すだけならかなり簡単でした。
現状はまだPyPi にも公開されておらず、ドキュメント上も TBD な箇所も多いため、発展途上のようです。書いてあることがすぐ通用しなくなる可能性が高いのでご了承ください。雰囲気だけということで・・。
[2023/05/14 追記ここから]
2023/03/08 に バージョン 1.0.0 としてリリースされていたようです。PyPi にも登録され、pip install ansible-sdk
でインストールできるようになりました。ただし、記事全体的に 2022年10月に試した時点となっていますのでご注意ください。
[追記ここまで]
インストール
ドキュメントにインストール方法が掲載されています。
https://github.com/ansible/ansible-sdk/blob/main/docs/source/install.rst
まずは ansible-sdk
リポジトリを clone して、できたディレクトリに移動します。
git clone https://github.com/ansible/ansible-sdk.git cd ansible-sdk
(ドキュメントにあった git clone git://github.com/ansible/ansible-sdk
は Operation timed out
というエラーになってしまったので、https
にしました)
続いて関連パッケージのインストールです。今回試す範囲では不要そうなものもありますが、今回用の venv 内にとりあえず全部インストールしてみます。
pip install ansible-core pip install ansible-runner pip install receptorctl
最後に、ansible-sdk
をインストールします。
pip install -e .
先述の通りまだ PyPi に登録されていないので、git clone して このようにする必要があります。
ansible 関連の Python パッケージは以下のようになりました。
% pip list | grep -i ansible ansible-core 2.13.5 ansible-runner 2.2.1 ansible-sdk 0.0.1 /Users/sakana/Documents/git/ansible-sdk
ここでの ansible-sdk
のバージョン表記は 0.0.1
となりました。ただ、リポジトリ上は現状はまだタグやリリースがない状態です。
おためし
サンプル類の調査とそれの実行を試します。
サンプルはすべて、このコミット時点のものです。
サンプル類の調査
clone したディレクトリの examples
内にサンプルがいくつかあります。
% cd examples % tree ├── datadir │ ├── inventory │ │ └── hosts │ └── project │ └── pb.yml ├── example_common.py ├── example_docker_job.py ├── example_mesh_job.py ├── example_podman_job.py ├── example_subprocess_job.py └── receptor_config ├── bar.yml ├── baz.yml └── foo.yml
example_*.py
の種類を見るといくつか形式があるようです。今思えば mesh に対応するために receptorctl
をインストールするという手順だったのかなと思います。
今回は、一番シンプルそうな example_subprocess_job.py
を試します。
import asyncio from ansible_sdk.executors import AnsibleSubprocessJobExecutor, AnsibleSubprocessJobOptions from example_common import run_one_stdout, run_one_events, run_many async def main(): executor = AnsibleSubprocessJobExecutor() executor_options = AnsibleSubprocessJobOptions() await run_one_stdout(executor, executor_options) await run_one_events(executor, executor_options) await run_many(executor, executor_options) if __name__ == '__main__': asyncio.run(main())
import されている example_common.py
の方も見てみます。run_one_stdout
だけ抜粋します。
async def run_one_stdout(executor, executor_options): """ Run a single playbook job with several hosts and echo the display output as it arrives """ try: job_def = AnsibleJobDef(data_dir='datadir', playbook='pb.yml') job_status = await executor.submit_job(job_def, executor_options) async for line in job_status.stdout_lines: print(line) # directly await the job object print('*** directly awaiting the job status...') await job_status finally: print('all done, exiting
Running Ansible jobs のドキュメントによると、以下のような使い方のようです。
AnsibleJobDed
でジョブを定義するJobExecutor
でジョブを実行する
今回の場合は、
example_subprocess_job.py
でimport
しているAnsibleSubprocessJobExecutor
がJobExecutor
に当たるということだと思います。
AnsibleJobDed
の data_dir
で指定されているディレクトリ datadir
には Playbook と インベントリがありました。
# expamples ディレクトリ抜粋
├── datadir
│ ├── inventory
│ │ └── hosts
│ └── project
│ └── pb.yml
invnetory
ディレクトリにインベントリファイルを入れ、project
ディレクトリに Playbook を入れておくのは、ansible-runner
のディレクトリ構造と同じですね。
この pb.yml
を Python 経由で実行するということのようです。ping
、wait_for
、shell
モジュールを利用した簡単な内容です。
インベントリは inventory/hosts
が利用されます。
実行
お目当ての example_subprocess_job.py
を実行します。
・・・と一回ためしたのですが、ログが沢山表示されてよくわからなくなってしまったので、実行する箇所をしぼりました。
await run_one_stdout(executor, executor_options) # これだけ # await run_one_events(executor, executor_options) # await run_many(executor, executor_options)
気を取り直して、再度実行。
% python example_subprocess_job.py PLAY [taskhosts] *************************************************************** TASK [Gathering Facts] ********************************************************* [WARNING]: Platform darwin on host h4 is using the discovered Python interpreter at /usr/local/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible- core/2.13/reference_appendices/interpreter_discovery.html for more information. ok: [h4] [WARNING]: Platform darwin on host h2 is using the discovered Python interpreter at /usr/local/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible- core/2.13/reference_appendices/interpreter_discovery.html for more information. ok: [h2] [WARNING]: Platform darwin on host h3 is using the discovered Python interpreter at /usr/local/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible- core/2.13/reference_appendices/interpreter_discovery.html for more information. ok: [h3] [WARNING]: Platform darwin on host h1 is using the discovered Python interpreter at /usr/local/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible- core/2.13/reference_appendices/interpreter_discovery.html for more information. ok: [h1] [WARNING]: Platform darwin on host h5 is using the discovered Python interpreter at /usr/local/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible- core/2.13/reference_appendices/interpreter_discovery.html for more information. ok: [h5] TASK [ping] ******************************************************************** ok: [h5] ok: [h2] ok: [h3] ok: [h4] ok: [h1] TASK [wait_for] **************************************************************** ok: [h4] ok: [h2] ok: [h1] ok: [h5] ok: [h3] TASK [shell] ******************************************************************* changed: [h4] changed: [h3] changed: [h5] changed: [h2] changed: [h1] PLAY RECAP ********************************************************************* h1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 h2 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 h3 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 h4 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 h5 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 *** directly awaiting the job status... all done, exiting
っぽいのが表示されました。
なお、Gathering Facts
で表示されている、Python インタープリターの警告は、明示的に指定していないと表示されるものです。
気になる場合は、inventory/hosts
の ansible_python_interpreter
変数で指定するなりします。
[taskhosts:vars] ansible_connection=local ansible_pipelining=true # 以下追記例 ansible_python_interpreter=/Users/sakana/envs/as/bin/python
おわりに
用意されたとても簡単なサンプルを動かしただけですが、ansible-sdk
を試してみました。
使ったことないですが、Ansible の Python APIよりも簡単に使える雰囲気でした。ansible-runner
を経由するおかげでしょうか。
先日書いたansible-rulebook
もそうですが、何かに Ansible を組み込む手段が最近増えてきたように思います。
参考資料
もっと作り込まれたデモ github.com