我是 ansible 的新手,正在尝试自动化一些步骤。
此任务第一次运行很顺利。
# Copy Root ssh keys within all devices
- hosts: etall
tasks:
- name: ssh keygen
command: ssh-keygen -t rsa -f /root/.ssh/id_rsa -q -P ""
第二次收集事实后就挂了。设置ANSIBLE_DEBUG=1
显示步骤挂起在:
16584 1554867575.39541: _low_level_execute_command(): executing: /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1554867574.524454-229535370546451/AnsiballZ_command.py && sleep 0'
在客户端计算机上进行跟踪时:
/usr/bin/python -m trace --trace /root/.ansible/tmp/ansible-tmp-1554873279.0459487-106888464136363/AnsiballZ_command.py
<---output snippet---->
AnsiballZ_command.py(16): import base64
--- modulename: trace, funcname: _unsettrace
trace.py(80): sys.settrace(None)
Traceback (most recent call last):
File "/usr/lib64/python2.7/runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib64/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/usr/lib64/python2.7/trace.py", line 819, in <module>
main()
File "/usr/lib64/python2.7/trace.py", line 807, in main
t.runctx(code, globs, globs)
File "/usr/lib64/python2.7/trace.py", line 513, in runctx
exec cmd in globals, locals
File "/root/.ansible/tmp/ansible-tmp-1554873279.0459487-106888464136363/AnsiballZ_command.py", line 113, in <module>
_ansiballz_main()
File "/root/.ansible/tmp/ansible-tmp-1554873279.0459487-106888464136363/AnsiballZ_command.py", line 16, in _ansiballz_main
import base64
ImportError: No module named base64
我import base64
可以/usr/bin/python
首次运行时这不是问题。在客户端机器上重新安装操作系统后也可以正常工作。
版本:
ansible 2.7.6
config file = /user/user1/plays/ansible.cfg
configured module search path = ['/user/user1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /user/user1/p363/lib/python3.6/site-packages/ansible-2.7.6-py3.6.egg/ansible
executable location = /user/user1/p363/bin/ansible
python version = 3.6.3 (default, Jul 8 2018, 21:13:48) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
客户端机器中的 Python 版本是 2.7.5
配置ansible-config dump --only-changed
DEFAULT_FORKS(/user/user1/plays/ansible.cfg) = 1
DEFAULT_HOST_LIST(/user/user1/plays/ansible.cfg) = ['/user/user1/plays/hosts.ini']
DEFAULT_LOG_PATH(/user/user1/plays/ansible.cfg) = /user/user1/plays/ansible.log
DEFAULT_ROLES_PATH(/user/user1/plays/ansible.cfg) = ['/user/user1/plays/hosts']
RETRY_FILES_ENABLED(/user/user1/plays/ansible.cfg) = False
环境: ansible 主控
$ cat /etc/os-release
NAME="Red Hat Enterprise Linux Workstation"
VERSION="7.5 (Maipo)"
ID="rhel"
ID_LIKE="fedora"
VARIANT="Workstation"
VARIANT_ID="workstation"
VERSION_ID="7.5"
PRETTY_NAME="Red Hat Enterprise Linux"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:7.5:GA:workstation"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7"
REDHAT_BUGZILLA_PRODUCT_VERSION=7.5
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="7.5"
ansible 客户端
# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
剧本:
# Copy Root ssh keys within all machines
- hosts: etall
tasks:
- name: ssh keygen
command: ssh-keygen -t rsa -f /root/.ssh/id_rsa -q -P ""
- name: Fetch keyfile
fetch:
src: "~/.ssh/id_rsa.pub"
dest: "buffer/{{ ansible_hostname }}-id_rsa.pub"
flat: yes
- name: Copy keyfile to destination
authorized_key:
user: root
state: present
key: "{{ lookup('file','buffer/{{ item }}-id_rsa.pub') }}"
when: item != ansible_hostname
with_items:
- "{{ groups['etall'] }}"
- name: ssh keyscan
shell: ssh-keyscan {{ item }} >> /root/.ssh/known_hosts
when: item != ansible_hostname
with_items:
- "{{ groups['etall'] }}"
收集事实后的详细输出片段:
TASK [ssh keygen] *************************************************************************************************************************************************************************************************
task path: /user/user1/plays/auth_keys.yml:4
<linux-user5> ESTABLISH SSH CONNECTION FOR USER: root
<linux-user5> SSH: EXEC sshpass -d11 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o User=root -o ConnectTimeout=10 -o ControlPath=/user/user1/.ansible/cp/0969431db6 linux-user5 '/bin/sh -c '"'"'echo ~root && sleep 0'"'"''
<linux-user5> (0, b'/root\n', b'')
<linux-user5> ESTABLISH SSH CONNECTION FOR USER: root
<linux-user5> SSH: EXEC sshpass -d11 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o User=root -o ConnectTimeout=10 -o ControlPath=/user/user1/.ansible/cp/0969431db6 linux-user5 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890 `" && echo ansible-tmp-1554878730.6050982-46540706020890="` echo /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890 `" ) && sleep 0'"'"''
<linux-user5> (0, b'ansible-tmp-1554878730.6050982-46540706020890=/root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890\n', b'')
Using module file /user/user1/p363/lib/python3.6/site-packages/ansible-2.7.6-py3.6.egg/ansible/modules/commands/command.py
<linux-user5> PUT /user/user1/.ansible/tmp/ansible-local-312468ua784d6/tmp9l2vw34v TO /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890/AnsiballZ_command.py
<linux-user5> SSH: EXEC sshpass -d11 sftp -o BatchMode=no -b - -C -o ControlMaster=auto -o ControlPersist=60s -o User=root -o ConnectTimeout=10 -o ControlPath=/user/user1/.ansible/cp/0969431db6 '[linux-user5]'
<linux-user5> (0, b'sftp> put /user/user1/.ansible/tmp/ansible-local-312468ua784d6/tmp9l2vw34v /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890/AnsiballZ_command.py\n', b'')
<linux-user5> ESTABLISH SSH CONNECTION FOR USER: root
<linux-user5> SSH: EXEC sshpass -d11 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o User=root -o ConnectTimeout=10 -o ControlPath=/user/user1/.ansible/cp/0969431db6 linux-user5 '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890/ /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890/AnsiballZ_command.py && sleep 0'"'"''
<linux-user5> (0, b'', b'')
<linux-user5> ESTABLISH SSH CONNECTION FOR USER: root
<linux-user5> SSH: EXEC sshpass -d11 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o User=root -o ConnectTimeout=10 -o ControlPath=/user/user1/.ansible/cp/0969431db6 -tt linux-user5 '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1554878730.6050982-46540706020890/AnsiballZ_command.py && sleep 0'"'"''
收集事实后挂起。
第一次运行就顺利完成了。在客户端机器上重新安装操作系统后也成功了。
答案1
您是否尝试过手动运行ssh-keygen
两次命令?
第一次运行:
user@host:~$ ssh-keygen -t rsa -f /tmp/id_rsa -q -P ""
user@host:~$
第二次运行:
user@host:~$ ssh-keygen -t rsa -f /tmp/id_rsa -q -P ""
/tmp/id_rsa already exists.
Overwrite (y/n)?
你的命令只是永远等待着一个永远不会到来的答案。
解决方案 1:回答问题
您可以使用expect
模块来回答交互式提示(如果你事先知道的话)
- name: ssh keygen
expect:
command: ssh-keygen -t rsa -f /root/.ssh/id_rsa -q -P ""
responses:
Overwrite \(y/n\)\?: y
虽然这在每次运行时都有效,这是一个糟糕的解决方案,因为它不是幂等的:每次运行剧本时,服务器都会发生变化,尽管你的库存或变量没有任何变化
解决方案2:仅在需要时生成。
更好的方法是仅当密钥不存在或需要刷新时才创建密钥。有几种方法可以做到这一点,这在很大程度上取决于您的需求、您的愿望、服务器园区的大小……
对于相对较小的公园,您可以在本地生成密钥并将其存储在您的库存中(使用ansible-vault混淆私钥)。然后只需将文件复制到服务器即可。如果文件已经存在且内容相同,则不会进行任何更改。
如果公园更大,钥匙可以存放在 Hashicorp Vault、Cyberark 等处……
如果您仍想在每台服务器上创建密钥,以下是我以同样的方式执行的操作:
- name: remove key files if refresh was asked
file:
path: "/root/.ssh/id_rsa{{ item }}"
state: absent
loop:
- ""
- ".pub"
when: refresh_keys | default(false) | bool
- name: check if key exists
stat:
path: /root/.ssh/id_rsa
register: ssh_key_file
- name: generate keys if needed
command: ssh-keygen -t rsa -f /root/.ssh/id_rsa -q -P ""
when: not (ssh_key_file.stat.exists)
changed_when: true
现在,如果您正常运行剧本,则仅当密钥尚不存在时才会创建密钥。如果您想刷新已有密钥的服务器上的密钥,可以将额外的变量传递给剧本
ansible-playbook /your/inventory.ini your_playbook.yml -e refresh_keys=true