ottijp blog

scriptコマンドが動いているとansibleがAnsiballZ_hogeの実行でフリーズする

2022-07-09ansiblesshbash

tl;dr

  • /etc/profile.d/*.shは非ログインシェルでも(/etc/bashrcから)呼ばれる
  • scriptコマンドが動いていると,ansibleがタイムアウトせずにフリーズする
  • /etc/profileでscriptコマンドを実行するようにすることで,ansibleの実行でscriptコマンドが動かず問題が起きなくなった

環境

  • コントロールノード
    • macOS 12.3
    • ansible 2.13
  • マネージドノード
    • CentOS 7.9
    • bash 3.2
    • script 2.23

背景

マネージドノードにsshで入って作業した記録するために,/etc/profile.d/record.shに以下のようなスクリプトを書いていました.

/etc/profile.d/record.sh
tty -s
if [ $? == 0 ]; then
    if [ "x$session_record" = "x" ]
    then
        timestamp=`date "+%Y%m%d%H%M"`
        output=/var/log/session/session.$USER.$$.$timestamp
        session_record=started
        export session_record
        script -t -f -q 2>${output}.timing $output
        exit
    fi
fi

スクリプトはこちらを参考にしました.

cf. How to Automatically Record the Terminal Session Activity of All Users on Linux | 2DayGeek

ターミナルの有無を評価しているのは,scp等の場合は操作が記録されないようにしたかったからです. しかし,scpの場合は/etc/profileが読み込まれないようなので,これは必要ありませんでした(後述).

問題

この状態でマネージドノードに対してansibleを実行すると,AnsiballZ_hoge(実行するモジュールによってAnsiballZ_pingだったりAnsiballZ_setupだったり)がフリーズする現象が起きました(タイムアウトもしない).

$ ansible -vvv -i hosts -m ping target
ansible [core 2.13.1]
  config file = None
  configured module search path = ['/Users/username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/Cellar/ansible/6.0.0/libexec/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/username/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.10.5 (main, Jun 23 2022, 17:15:25) [Clang 13.1.6 (clang-1316.0.21.2.5)]
  jinja version = 3.1.2
  libyaml = True
No config file found; using defaults
host_list declined parsing /Users/username/Downloads/ansigle-script/hosts as it did not pass its verify_file() method
script declined parsing /Users/username/Downloads/ansigle-script/hosts as it did not pass its verify_file() method
auto declined parsing /Users/username/Downloads/ansigle-script/hosts as it did not pass its verify_file() method
Parsed /Users/username/Downloads/ansigle-script/hosts inventory source with ini plugin
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
META: ran handlers
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' target '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
<target> (0, b'/home/vagrant\n', b'')
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' target '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/vagrant/.ansible/tmp `"&& mkdir "` echo /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000 `" && echo ansible-tmp-1657341680.9266748-42824-188038444489000="` echo /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000 `" ) && sleep 0'"'"''
<target> (0, b'ansible-tmp-1657341680.9266748-42824-188038444489000=/home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000\n', b'')
<target> Attempting python interpreter discovery
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' target '/bin/sh -c '"'"'echo PLATFORM; uname; echo FOUND; command -v '"'"'"'"'"'"'"'"'python3.10'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.9'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.8'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.7'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.6'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.5'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'/usr/bin/python3'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'/usr/libexec/platform-python'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python2.7'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'/usr/bin/python'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python'"'"'"'"'"'"'"'"'; echo ENDFOUND && sleep 0'"'"''
<target> (0, b'PLATFORM\nLinux\nFOUND\n/usr/libexec/platform-python\n/usr/bin/python2.7\n/usr/bin/python\n/usr/bin/python\nENDFOUND\n', b'')
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' target '/bin/sh -c '"'"'/usr/libexec/platform-python && sleep 0'"'"''
<target> (0, b'{"osrelease_content": "NAME=\\"CentOS Linux\\"\\nVERSION=\\"7 (Core)\\"\\nID=\\"centos\\"\\nID_LIKE=\\"rhel fedora\\"\\nVERSION_ID=\\"7\\"\\nPRETTY_NAME=\\"CentOS Linux 7 (Core)\\"\\nANSI_COLOR=\\"0;31\\"\\nCPE_NAME=\\"cpe:/o:centos:centos:7\\"\\nHOME_URL=\\"https://www.centos.org/\\"\\nBUG_REPORT_URL=\\"https://bugs.centos.org/\\"\\n\\nCENTOS_MANTISBT_PROJECT=\\"CentOS-7\\"\\nCENTOS_MANTISBT_PROJECT_VERSION=\\"7\\"\\nREDHAT_SUPPORT_PRODUCT=\\"centos\\"\\nREDHAT_SUPPORT_PRODUCT_VERSION=\\"7\\"\\n\\n", "platform_dist_result": ["centos", "7.8.2003", "Core"]}\n', b'')
Using module file /usr/local/Cellar/ansible/6.0.0/libexec/lib/python3.10/site-packages/ansible/modules/ping.py
<target> PUT /Users/username/.ansible/tmp/ansible-local-42822e1dxayu5/tmpyb2fl1hk TO /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000/AnsiballZ_ping.py
<target> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' '[target]'
<target> (0, b'sftp> put /Users/username/.ansible/tmp/ansible-local-42822e1dxayu5/tmpyb2fl1hk /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000/AnsiballZ_ping.py\n', b'')
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' target '/bin/sh -c '"'"'chmod u+x /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000/ /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000/AnsiballZ_ping.py && sleep 0'"'"''
<target> (0, b'', b'')
<target> ESTABLISH SSH CONNECTION FOR USER: None
<target> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/Users/username/.ansible/cp/ecebe3fde6"' -tt target '/bin/sh -c '"'"'/usr/bin/python /home/vagrant/.ansible/tmp/ansible-tmp-1657341680.9266748-42824-188038444489000/AnsiballZ_ping.py && sleep 0'"'"''

最後の行が出力されたところでフリーズします.

原因

  1. ansible実行時(非ログインシェル)にロードされないと思っていた/etc/profile.d/record.shがロードされていた(/etc/bashrcから呼ばれていた・・・).
  2. scriptコマンドを実行していると,ansibleが上記のようにフリーズしてしまう(なぜそうなるのかは不明).

解決方法

ansibleによる操作を記録する必要はそもそもなかったので,scriptコマンドの実行は/etc/profile.d/record.shではなく,/etc/profileに書くように変更しました.

/etc/profileがロードされるパターン

下記のとおりだったので,/etc/profileでターミナルの有無を評価してscriptコマンドの実行を制御する必要はないと思います.

パターン ロード
ssh される
ssh(コマンドパラメタあり) されない
scp されない
sftp されない
ansible されない

Satoshi SAKAO (@ottijp)

都内でアプリケーションエンジニアをしています

...
© 2022, ottijp