目的
Ansible にあるたくさんのモジュールの中からよく使われそうなモジュールを使ってみて知見を得る
環境
Microsoft Azure Cloud Shell
Ubuntu 16.04.4 LTS
Ansible のバージョン
kono@Azure:~/ansible_pj$ ansible --version ansible 2.5.2 config file = None configured module search path = [u'/home/kono/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /opt/ansible/local/lib/python2.7/site-packages/ansible executable location = /opt/ansible/bin/ansible python version = 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609] kono@Azure:~/ansible_pj$
予めしておくこと
Ansible による構成対象の VM に ssh ログイン出来るように Cloud Shell の公開鍵を登録することです。おそらく VM を作るときに聞いてくると思いますが。。。すみません確認して追記します。
Commands modules
Commands modules — Ansible Documentation
まずは Commands modules から見ていく
command
command_module.yaml を作成
$ cat command_modules.yaml # Command modules test - hosts: any user: takashi tasks: - name: return distribution command: cat /etc/lsb-release - name: return df command: df -h - name: return memory free command: free - name: return inodes info command: df -i - name: ip address command: ip a - name: list of listened ports command: netstat -nlt
実行してみる
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts command_modules.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.70.39] TASK [return distribution] ****************************************************************************************************************************************************************************************************************** changed: [40.74.70.39] TASK [return df] **************************************************************************************************************************************************************************************************************************** changed: [40.74.70.39] TASK [return memory free] ******************************************************************************************************************************************************************************************************************* changed: [40.74.70.39] TASK [return inodes info] ******************************************************************************************************************************************************************************************************************* changed: [40.74.70.39] TASK [ip address] *************************************************************************************************************************************************************************************************************************** changed: [40.74.70.39] TASK [list of listened ports] *************************************************************************************************************************************************************************************************************** changed: [40.74.70.39] PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.70.39 : ok=7 changed=6 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
実行されているような気がしますね。では、デバッグメッセージのオプションを使ってみましょう
$ ansible-playbook -i hosts command_modules.yaml -vvv
上記のように、 -vvv
オプションをつけることで詳細なメッセージを確認できます。
v
の数が何個かで出力レベルがわかるので、自分の欲しい情報が何か整理してから使っても良いかも。基本とりあえず -vvv
で。という感じなんだと妄想してみる。
ちなみに、ソースコードを確認してみる
https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/commands/command.py
https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/commands/command.py#L137-L145
このあたりで色々定義しているのがわかる
expect
https://docs.ansible.com/ansible/latest/modules/expect_module.html#expect-module
先に書きますが、私の環境では上手く行きませんでした。
以下は参考までにどうぞ。
まず、適当に playbook を書いてみた。
expect.yaml
kono@Azure:~/ansible_pj$ cat expect.yaml - hosts: any user: takashi tasks: - name: expect module test expect: command: /usr/bin/python3 /home/takashi/input_test.py responses: 'please input something: ' : 'This is expect module test' kono@Azure:~/ansible_pj$
expect というくらいなので、ターミナルに何かコメントがあって、入力待ち状態になる時にこれを使うはず。
というわけで、ssh 先の VM に python3 で適当にコードを書いてみた。
takashi@test1:~$ cat input_test.py #!/usr/bin/python3 # coding: utf-8 tmp = input("please input something: ") print(tmp) takashi@test1:~$
で、実行
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts expect.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.95.98] TASK [expect module test] ******************************************************************************************************************************************************************************************************************* fatal: [40.74.95.98]: FAILED! => {"changed": false, "msg": "The pexpect python module is required"} to retry, use: --limit @/home/kono/ansible_pj/expect.retry PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.95.98 : ok=1 changed=0 unreachable=0 failed=1 kono@Azure:~/ansible_pj$
失敗した。
メッセージには、 The expected python module is required
とある。
このモジュールを使うためには、 pexpect
が必須なんですね。
公式のドキュメントにも書いてありました。
expect - Executes a command and responds to prompts. — Ansible Documentation
ということで、 pexpect
が入っているか確認します。
kono@Azure:~/ansible_pj$ ansible --version ansible 2.5.2 ... python version = 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609] kono@Azure:~/ansible_pj$ pip2 pip2 pip2.7 kono@Azure:~/ansible_pj$ pip2.7 list | grep pexpect kono@Azure:~/ansible_pj$
ない!
pexpect
のインストールですね。 やってみましょう。
kono@Azure:~/ansible_pj$ pip2.7 install pexpect Collecting pexpect Using cached https://files.pythonhosted.org/packages/89/e6/b5a1de8b0cc4e07ca1b305a4fcc3f9806025c1b651ea302646341222f88b/pexpect-4.6.0-py2.py3-none-any.whl Collecting ptyprocess>=0.5 (from pexpect) Using cached https://files.pythonhosted.org/packages/d1/29/605c2cc68a9992d18dada28206eeada56ea4bd07a239669da41674648b6f/ptyprocess-0.6.0-py2.py3-none-any.whl Installing collected packages: ptyprocess, pexpect Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/ptyprocess-0.6.0.dist-info' Consider using the `--user` option or check the permissions. kono@Azure:~/ansible_pj$
??? 何かおかしい。 Permissiono denied
ですと!?
--user
オプションを使ってみましょう。書いてあるとおり。
kono@Azure:~/ansible_pj$ pip2.7 install pexpect --user Collecting pexpect Using cached https://files.pythonhosted.org/packages/89/e6/b5a1de8b0cc4e07ca1b305a4fcc3f9806025c1b651ea302646341222f88b/pexpect-4.6.0-py2.py3-none-any.whl Collecting ptyprocess>=0.5 (from pexpect) Using cached https://files.pythonhosted.org/packages/d1/29/605c2cc68a9992d18dada28206eeada56ea4bd07a239669da41674648b6f/ptyprocess-0.6.0-py2.py3-none-any.whl Installing collected packages: ptyprocess, pexpect Successfully installed pexpect-4.6.0 ptyprocess-0.6.0 kono@Azure:~/ansible_pj$ kono@Azure:~/ansible_pj$ pip2.7 list | grep pexpect pexpect 4.6.0 kono@Azure:~/ansible_pj$
あっさり解決。。。ちゃんと入った。
ということで、リトライします。
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts expect.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.95.98] TASK [expect module test] ******************************************************************************************************************************************************************************************************************* fatal: [40.74.95.98]: FAILED! => {"changed": false, "msg": "The pexpect python module is required"} to retry, use: --limit @/home/kono/ansible_pj/expect.retry PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.95.98 : ok=1 changed=0 unreachable=0 failed=1 kono@Azure:~/ansible_pj$
??? 同じエラーが出てしましました。 モジュールが必要だったのは、もしかすると、VM の方だったのかな?
本当は pip のインストール及び、 pexpect
のインストールも Ansible
で実施したかったけど、本質じゃないので普通に apt-get install python3-pip
で実施することにした。
takashi@test1:~$ pip3 -V pip 1.5.4 from /usr/lib/python3/dist-packages (python 3.4) takashi@test1:~$
しかし、 pip3
がインストールできたので、 pexpext
のインストールを Ansible
でやってみる。
kono@Azure:~/ansible_pj$ cat python_modules.yaml # Command modules test - hosts: any user: takashi become: true tasks: - name: install pexpect command: /usr/bin/pip3 install pexpect kono@Azure:~/ansible_pj$
プレイブックが出来たので、実行してみる
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts python_modules.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.95.98] TASK [install pexpect] ********************************************************************************************************************************************************************************************************************** changed: [40.74.95.98] PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.95.98 : ok=2 changed=1 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
お。出来てそう。VM で確認してみる。
takashi@test1:~$ pip3 list | grep pexpect pexpect (4.6.0) takashi@test1:~$
入りました。
ようやく準備が出来たので、 expect
をもう一度試してみる。
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts expect.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.95.98] TASK [expect module test] ******************************************************************************************************************************************************************************************************************* fatal: [40.74.95.98]: FAILED! => {"changed": false, "msg": "The pexpect python module is required"} to retry, use: --limit @/home/kono/ansible_pj/expect.retry PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.95.98 : ok=1 changed=0 unreachable=0 failed=1 kono@Azure:~/ansible_pj$
それでもダメだった。。。んー、何がいけなかったのか。。。
テスト
Azure
の Cloud Shell
環境での動作について
https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/commands/expect.py#L95-L99
ここでやっていることと同じことをしてみる。
python2.7
の場合の import pexpect
のテスト
kono@Azure:~/ansible_pj$ python2.7 Python 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> try: ... import pexpect ... print(True) ... except ImportError: ... print(False) ... True >>>
OK 問題ない。
kono@Azure:~/ansible_pj$ python Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> try: ... import pexpect ... print(True) ... except ImportError: ... print(False) ... False >>>
pexpect
がインポート出来ていない。
もう一度、確認。
kono@Azure:~/ansible_pj$ ansible --version ansible 2.5.2 config file = None configured module search path = [u'/home/kono/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /opt/ansible/local/lib/python2.7/site-packages/ansible executable location = /opt/ansible/bin/ansible python version = 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609] kono@Azure:~/ansible_pj$
executable location
に実行ファイルがありそうだ。
kono@Azure:~/ansible_pj$ ls -l /opt/ansible/bin/ | grep python ... lrwxrwxrwx 1 root root 7 Jun 15 19:04 python -> python2 -rwxr-xr-x 11 root root 3492656 Jun 15 19:04 python2 lrwxrwxrwx 1 root root 7 Jun 15 19:04 python2.7 -> python2 ... kono@Azure:~/ansible_pj$
おお。 python2
に全て集約されている!!
pip
系はどうだろう?
kono@Azure:~/ansible_pj$ ls -l /opt/ansible/bin/ | grep pip -rwxr-xr-x 11 root root 224 Jun 15 19:04 pip -rwxr-xr-x 11 root root 224 Jun 15 19:04 pip2 -rwxr-xr-x 11 root root 224 Jun 15 19:04 pip2.7 kono@Azure:~/ansible_pj$
pip
系はそのままなんだろうか。。。それぞれのバージョンを見てみよう。
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip -V pip 10.0.1 from /opt/ansible/local/lib/python2.7/site-packages/pip (python 2.7) kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip2 -V pip 10.0.1 from /opt/ansible/local/lib/python2.7/site-packages/pip (python 2.7) kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip2.7 -V pip 10.0.1 from /opt/ansible/local/lib/python2.7/site-packages/pip (python 2.7) kono@Azure:~/ansible_pj$
全部同じ出力である。同じ所を参照しているので問題なさそう。
pip
に関して問題ないことがわかったので、 python2
で import pexpect
テストを実施してみよう
kono@Azure:~/ansible_pj$ /opt/ansible/bin/python2 Python 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> try: ... import pexpect ... print True ... except ImportError: ... print False ... False >>>
なんだと。。。 python2
の起動 path が違うから別物を使っていたということか???
kono@Azure:~/ansible_pj$ whereis python2.7 python2: /usr/bin/python2.7 /usr/bin/python2 /usr/bin/python2.7-config /usr/lib/python2.7 /etc/python2.7 /usr/local/lib/python2.7 /usr/include/python2.7 /opt/ansible/bin/python2.7 /opt/ansible/bin/python2 /usr/share/man/man1/python2.1.gz kono@Azure:~/ansible_pj$
なるほど。PATH
は通っているけれど、$ python2.7
で呼び出した時は、 /usr/bin/python2.7
が呼び出され、$ /opt/ansible/bin/python2.7
では、そのとおりの path
の Python2.7
が起動したわけですね。
結果、同じように import pexpect
をしているけど、挙動が違うと。
では、 Ansible が参照する pip
で pexpect
をインストールしよう。
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip install pexpect --user virtualenv Can not perform a '--user' install. User site-packages are not visible in this virtualenv. kono@Azure:~/ansible_pj$
ダメなようですね。
ちなみに、本当に参照している先が違うのでしょうか。
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip show wheel ... Location: /opt/ansible/lib/python2.7/site-packages ... kono@Azure:~/ansible_pj$
これと
kono@Azure:~/ansible_pj$ pip2.7 show wheel ... Location: /usr/lib/python2.7/dist-packages ... kono@Azure:~/ansible_pj$
同じパッケージで目に入ったのが wheel
なので指定させて頂いた。
まるで使う場所が違いますね。
別のアプローチを考えよう。
Ansible が利用するデフォルトの Python
を指定するとか。
kono@Azure:~/ansible_pj$ pip2.7 list | wc -l 9 kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip list | wc -l 73 kono@Azure:~/ansible_pj$
この結果を見るとアプローチを変えるのは厳しそう。
/opt/ansible/lib/python2.7/site-packages
内に無理やり入れる方法を考えてみよう。
Azure にて、 /opt/ansible/lib/python2.7/site-package
に何かを入れられるとは思いがたい。。。
なにせ、Azure Cloud Shell の制限事項として、 sudo
がつかえないのである。
どこか詰んだ感じがしますね。
Ansible が使うパッケージの場所
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip show wheel | grep Location Location: /opt/ansible/lib/python2.7/site-packages kono@Azure:~/ansible_pj$
ロケーションのディレクトリのパーミッション及び、所有者:グループ
kono@Azure:~/ansible_pj$ ls -l /opt/ansible/lib/python2.7/ | grep site-packages -rw-r--r-- 11 root root 0 Jun 15 19:04 no-global-site-packages.txt drwxr-xr-x 120 root root 4096 Jun 18 20:26 site-packages kono@Azure:~/ansible_pj$
root:root でないとインストールできないことがわかります。
試しに、 /opt/ansible/bin/pip install pexpect
を実行
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip install pexpect Collecting pexpect Using cached https://files.pythonhosted.org/packages/89/e6/b5a1de8b0cc4e07ca1b305a4fcc3f9806025c1b651ea302646341222f88b/pexpect-4.6.0-py2.py3-none-any.whl Collecting ptyprocess>=0.5 (from pexpect) Using cached https://files.pythonhosted.org/packages/d1/29/605c2cc68a9992d18dada28206eeada56ea4bd07a239669da41674648b6f/ptyprocess-0.6.0-py2.py3-none-any.whl Installing collected packages: ptyprocess, pexpect Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/opt/ansible/lib/python2.7/site-packages/ptyprocess-0.6.0.dist-info' Consider using the `--user` option or check the permissions. kono@Azure:~/ansible_pj$
--user
をつけると
kono@Azure:~/ansible_pj$ /opt/ansible/bin/pip install pexpect --user Can not perform a '--user' install. User site-packages are not visible in this virtualenv. kono@Azure:~/ansible_pj$
Permission denied
権限がない。 sudo
をつけると、、、
kono@Azure:~/ansible_pj$ sudo /opt/ansible/bin/pip install pexpect --user bash: sudo: command not found kono@Azure:~/ansible_pj$
コマンドがない。 orz
ということで、 expect
モジュールですが、これは上手く出来た時に追記したいと思います。
非常に残念ですが、しょうが無いですね。
raw
raw - Executes a low-down and dirty SSH command — Ansible Documentation
純粋に ssh
コマンドを実行して何かを手で実施する時と同じことを実施してくれるモジュール。
playbook
kono@Azure:~/ansible_pj$ cat raw.yaml # Command modules test - hosts: any user: takashi #become: true tasks: - name: tail syslog raw: tail /var/log/syslog kono@Azure:~/ansible_pj$
ansible 実行
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts raw.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] TASK [tail syslog] ************************************************************************************************************************************************************************************************************************** changed: [40.74.67.49] PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.67.49 : ok=2 changed=1 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
これではよくわからないので、 -vvv
オプションをつけてみましょう。
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts raw.yaml -vvv ...json TASK [tail syslog] ************************************************************************************************************************************************************************************************************************** task path: /home/kono/ansible_pj/raw.yaml:6 <40.74.67.49> ESTABLISH SSH CONNECTION FOR USER: takashi <40.74.67.49> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile="/home/kono/.ssh/id_rsa"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=takashi -o ConnectTimeout=10 -o ControlPath=/home/kono/.ansible/cp/8aa58877c0 -tt 40.74.67.49 'tail /var/log/syslog' <40.74.67.49> (0, "Jun 24 01:36:11 test1 kernel: [ 62.830553] hv_balloon: Data Size is 8\r\nJun 24 02:05:11 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10\r\nJun 24 02:05:14 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/uname -a removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:16 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -h removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:19 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -i removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:21 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/usr/bin/free removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:24 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/sbin/ip a removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:26 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/netstat -nlt removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:29 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=which python3 removes=None creates=None chdir=None stdin=None\r\nJun 24 02:12:17 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10\r\n", 'Shared connection to 40.74.67.49 closed.\r\n') changed: [40.74.67.49] => { "changed": true, "rc": 0, "stderr": "Shared connection to 40.74.67.49 closed.\r\n", "stdout": "Jun 24 01:36:11 test1 kernel: [ 62.830553] hv_balloon: Data Size is 8\r\nJun 24 02:05:11 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10\r\nJun 24 02:05:14 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/uname -a removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:16 test1 ansible-command: Invoked with warn=True executable=None_uses_shell=False _raw_params=/bin/df -h removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:19 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -i removes=None creates=Nonechdir=None stdin=None\r\nJun 24 02:05:21 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/usr/bin/free removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:24 test1 ansible-command:Invoked with warn=True executable=None _uses_shell=False _raw_params=/sbin/ip a removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:26 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/netstat -nlt removes=None creates=None chdir=None stdin=None\r\nJun 24 02:05:29 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=which python3 removes=None creates=None chdir=None stdin=None\r\nJun 24 02:12:17 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10\r\n", "stdout_lines": [ "Jun 24 01:36:11 test1 kernel: [ 62.830553] hv_balloon: Data Size is 8", "Jun 24 02:05:11 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10", "Jun 24 02:05:14 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/uname -a removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:16 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -h removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:19 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -i removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:21 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/usr/bin/free removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:24 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/sbin/ip a removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:26 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/netstat -nlt removes=None creates=None chdir=None stdin=None", "Jun 24 02:05:29 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=which python3 removes=None creates=None chdir=None stdin=None", "Jun 24 02:12:17 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10" ] } META: ran handlers META: ran handlers PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.67.49 : ok=2 changed=1 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
コマンドでは以下と同じことを行っています。
kono@Azure:~/ansible_pj$ ssh takashi@40.74.67.49 tail /var/log/syslog Jun 24 02:05:14 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/uname -a removes=None creates=None chdir=None stdin=None Jun 24 02:05:16 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -h removes=None creates=None chdir=None stdin=None Jun 24 02:05:19 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/df -i removes=None creates=None chdir=None stdin=None Jun 24 02:05:21 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/usr/bin/free removes=None creates=None chdir=None stdin=None Jun 24 02:05:24 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/sbin/ip a removes=None creates=None chdir=None stdin=None Jun 24 02:05:26 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=/bin/netstat -nlt removes=None creates=None chdir=None stdin=None Jun 24 02:05:29 test1 ansible-command: Invoked with warn=True executable=None _uses_shell=False _raw_params=which python3 removes=None creates=None chdir=None stdin=None Jun 24 02:12:17 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10 Jun 24 02:13:10 test1 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10 Jun 24 02:17:01 test1 CRON[3938]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly) kono@Azure:~/ansible_pj$
ソースコードは以下。ドキュメントしか無いことがわかります。
ansible/raw.py at devel · ansible/ansible · GitHub
ssh
したあとのコマンドをしっかり記述することで、何でも出来そうですね。その反面べき等性は自分たちで実装する必要はあるのだと思います。
script
script - Runs a local script on a remote node after transferring it — Ansible Documentation
気になった特徴は以下の内容です。
This module does not require python on the remote system, much like the raw module.
つまり、 python
の入っていないようなネットワークデバイスでもスクリプトが使えるということなんだと思います。
とはいえ、サンプルに Shell Script
しか書かれていないので、心配になったため、Python
のスクリプトも準備する。
こんな感じで playbook
を書いてみました。
kono@Azure:~/ansible_pj$ cat script.yaml # Command modules test - hosts: any user: takashi #become: true tasks: - name: execute local shell script script: ./scripts/get_cwd.sh register: result - debug: var: result - name: execute local python script script: ./scripts/get_cwd.py register: result - debug: var: result kono@Azure:~/ansible_pj$
それぞれのスクリプトは以下の通り。
kono@Azure:~/ansible_pj$ cat ./scripts/get_cwd.sh echo `pwd` kono@Azure:~/ansible_pj$ cat ./scripts/get_cwd.py #!/usr/bin/python3 # coding: utf-8 import os print(os.getcwd()) kono@Azure:~/ansible_pj$
動かしてみましょう。
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts script.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] TASK [execute local shell script] *********************************************************************************************************************************************************************************************************** changed: [40.74.67.49] TASK [debug] ******************************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] => { "result": { "changed": true, "failed": false, "rc": 0, "stderr": "Shared connection to 40.74.67.49 closed.\r\n", "stdout": "/home/takashi\r\n", "stdout_lines": [ "/home/takashi" ] } } TASK [execute local python script] ********************************************************************************************************************************************************************************************************** changed: [40.74.67.49] TASK [debug] ******************************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] => { "result": { "changed": true, "failed": false, "rc": 0, "stderr": "Shared connection to 40.74.67.49 closed.\r\n", "stdout": "/home/takashi\r\n", "stdout_lines": [ "/home/takashi" ] } } PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.67.49 : ok=5 changed=2 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
どちらでも実行できましたね。
しかも、ローカルホストで作成しておいた Script
ファイルをリモートで実行してくれている。
raw
に似ていますね。
どうやって実現しているのか謎ですが、以外に便利な反面、冪等性の担保が難しそうです。
show run
取るくらいならこんな感じでいいかもしれませんけどね。
ソースコードは以下のリンクです。こちらも raw
同様、何もしていませんね。。。
ansible/script.py at devel · ansible/ansible · GitHub
shell
shell - Execute commands in nodes. — Ansible Documentation
次は、 shell
モジュールですね。
ドキュメントの中にもあるように、 command
モジュールライクらしいです。
The
shell
module takes the command name followed by a list of space-delimited arguments. It is almost exactly like the command module but runs the command through a shell (/bin/sh
) on the remote node.
このドキュメントだけではちょっと良くわからなかったのでググってみた結果
shell
モジュールは、&
,|
,>
等のシェルの機能が使えるが、command
モジュールでは使えないというのが最も大きな差であるようだ。
ということで、 Playbook を書いてみた。
kono@Azure:~/ansible_pj$ cat shell.yaml # Command modules test - hosts: any user: takashi #become: true tasks: - name: Execute the command in remote shell. shell: ls /var/log/ | wc -l register: result - debug: var: result kono@Azure:~/ansible_pj$
パイプでつなげているが、使えるだろうか。
kono@Azure:~/ansible_pj$ ansible-playbook -i hosts shell.yaml PLAY [any] ********************************************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] TASK [Execute the command in remote shell.] ************************************************************************************************************************************************************************************************* changed: [40.74.67.49] TASK [debug] ******************************************************************************************************************************************************************************************************************************** ok: [40.74.67.49] => { "result": { "changed": true, "cmd": "ls /var/log/ | wc -l", "delta": "0:00:00.004307", "end": "2018-06-24 03:57:31.229757", "failed": false, "rc": 0, "start": "2018-06-24 03:57:31.225450", "stderr": "", "stderr_lines": [], "stdout": "29", "stdout_lines": [ "29" ] } } PLAY RECAP ********************************************************************************************************************************************************************************************************************************** 40.74.67.49 : ok=3 changed=1 unreachable=0 failed=0 kono@Azure:~/ansible_pj$
きちんと出来ましたね。さすがです。 raw
モジュールとも似ているのでしょうかね。。。
ansible/shell.py at devel · ansible/ansible · GitHub
ソースコードを見ても、ドキュメントとサンプルしか無いような気が。。。
telnet
telnet - Executes a low-down and dirty telnet command — Ansible Documentation
raw
を ssh
ではなく telnet
で実行するという理解で合っているはず。
1時間くらい ubuntu で telnet
出来るように調べてみたけど、あまり進展がなかったので、このモジュールについては今後機会があれば追記するようにします。
最後に
今回はコマンドモジュールにフォーカスして使いかたを自分用の備忘録として書き留めました。
ここまで読んで力になれ無かったとしても。。。ごめんなさい。
というか、未来の自分にごめんなさいをしたい。。。意外と expect
を一番試してみたかったんですよね。そのため、結構試行錯誤したのですが、残念でした。
今度時間と環境を作ってリトライしようと思います。
以上です。