网络调试和故障排除指南
本节讨论如何在 Ansible 中调试和排查网络模块故障。
如何进行故障排除
Ansible 网络自动化错误通常归类于以下几种情况:
- 身份验证问题::
未正确指定凭据
远程设备(网络交换机/路由器)未回退到其他身份验证方法
SSH 密钥问题
- 超时问题::
在尝试提取大量数据时可能会发生
实际上可能掩盖了身份验证问题
- 剧本问题::
使用
delegate_to
而不是ProxyCommand
。有关更多信息,请参阅 网络代理指南。
警告
无法 打开 shell
无法 打开 shell
消息表示 ansible-connection
守护进程无法成功与远程网络设备通信。这通常表示存在身份验证问题。有关更多信息,请参阅本文档中的“身份验证和连接问题”部分。
启用网络日志记录以及如何读取日志文件
平台:任何平台
Ansible 包含日志记录功能,有助于诊断和排查与 Ansible 网络模块有关的问题。
由于日志记录非常详细,因此默认情况下处于禁用状态。可以使用 Ansible 控制节点上的 ANSIBLE_LOG_PATH
和 ANSIBLE_DEBUG
选项启用日志记录,即运行 ansible-playbook
的机器。
在运行 ansible-playbook
之前,运行以下命令以启用日志记录
# Specify the location for the log file
export ANSIBLE_LOG_PATH=~/ansible.log
# Enable Debug
export ANSIBLE_DEBUG=True
# Run with 4*v for connection level verbosity
ansible-playbook -vvvv ...
在 Ansible 完成运行后,您可以检查已在 Ansible 控制节点上创建的日志文件
less $ANSIBLE_LOG_PATH
2017-03-30 13:19:52,740 p=28990 u=fred | creating new control socket for host veos01:22 as user admin
2017-03-30 13:19:52,741 p=28990 u=fred | control socket path is /home/fred/.ansible/pc/ca5960d27a
2017-03-30 13:19:52,741 p=28990 u=fred | current working directory is /home/fred/ansible/test/integration
2017-03-30 13:19:52,741 p=28990 u=fred | using connection plugin network_cli
...
2017-03-30 13:20:14,771 paramiko.transport userauth is OK
2017-03-30 13:20:15,283 paramiko.transport Authentication (keyboard-interactive) successful!
2017-03-30 13:20:15,302 p=28990 u=fred | ssh connection done, setting terminal
2017-03-30 13:20:15,321 p=28990 u=fred | ssh connection has completed successfully
2017-03-30 13:20:15,322 p=28990 u=fred | connection established to veos01 in 0:00:22.580626
从日志中注意
p=28990
是ansible-connection
进程的 PID(进程 ID)u=fred
是 运行 ansible 的用户,而不是您尝试连接到的远程用户creating new control socket for host veos01:22 as user admin
主机:端口,作为用户control socket path is
磁盘上创建持久连接套接字的位置using connection plugin network_cli
表示正在使用持久连接connection established to veos01 in 0:00:22.580626
在远程设备上获取 shell 所花费的时间
注意
端口 None creating new control socket for host veos01:None
如果日志显示端口为 None
,则表示正在使用默认端口。Ansible 的未来版本将改进此消息,以便始终记录端口。
由于日志文件非常详细,因此可以使用 grep 查找特定信息。例如,在从 creating new control socket for host
行识别出 pid
后,您可以搜索其他连接日志条目
grep "p=28990" $ANSIBLE_LOG_PATH
启用网络设备交互日志记录
平台:任何平台
Ansible 包含设备交互日志记录功能,有助于诊断和排查与 Ansible 网络模块有关的问题。这些消息将记录在 Ansible 配置文件中的 log_path
配置选项指向的文件中,或者通过设置 ANSIBLE_LOG_PATH
指向的文件中。
警告
设备交互消息包括在目标设备上执行的命令以及返回的响应。由于此日志数据可能包含敏感信息(包括明文密码),因此默认情况下处于禁用状态。此外,为了防止意外数据泄露,在启用了此设置的每个任务中都会显示一条警告,说明启用了此设置的主机以及数据记录的位置。
务必充分了解启用此选项的安全隐患。可以通过在配置文件中设置全局启用设备交互日志记录,或者通过设置环境变量启用,或者通过将一个特殊变量传递给任务在每个任务的基础上启用。
在运行 ansible-playbook
之前,运行以下命令以启用日志记录
# Specify the location for the log file
export ANSIBLE_LOG_PATH=~/ansible.log
为特定任务启用设备交互日志记录
- name: get version information
cisco.ios.ios_command:
commands:
- show version
vars:
ansible_persistent_log_messages: True
要将其设置为全局设置,请在 ansible.cfg
文件中添加以下内容
[persistent_connection]
log_messages = True
或启用环境变量 ANSIBLE_PERSISTENT_LOG_MESSAGES
# Enable device interaction logging
export ANSIBLE_PERSISTENT_LOG_MESSAGES=True
如果任务在连接初始化本身时失败,则应全局启用此选项。如果某个特定任务间歇性地失败,则可以为该任务本身启用此选项以查找根本原因。
在 Ansible 完成运行后,您可以检查已在 Ansible 控制节点上创建的日志文件
注意
务必充分了解启用此选项的安全隐患,因为它可能会在日志文件中记录敏感信息,从而造成安全漏洞。
隔离错误
平台:任何平台
与任何故障排除工作一样,务必尽可能简化测试用例。
对于 Ansible,可以通过确保您只针对一个远程设备运行来实现此目的
使用
ansible-playbook --limit switch1.example.net...
使用 ad hoc
ansible
命令
ad hoc 指的是使用 /usr/bin/ansible
运行 Ansible 以执行某些快速命令,而不是使用编排语言,即 /usr/bin/ansible-playbook
。在这种情况下,我们可以尝试在远程设备上执行单个命令以确保连接性
ansible -m arista.eos.eos_command -a 'commands=?' -i inventory switch1.example.net -e 'ansible_connection=ansible.netcommon.network_cli' -u admin -k
在上面的示例中,我们
连接到库存文件
inventory
中指定的switch1.example.net
。使用模块
arista.eos.eos_command
。运行命令
?
。使用用户名
admin
连接。通过指定
-k
来告知ansible
命令提示输入 SSH 密码。
如果您已正确配置 SSH 密钥,则无需指定 -k
参数。
如果连接仍然失败,您可以将其与 enable_network_logging 参数结合使用。例如
# Specify the location for the log file
export ANSIBLE_LOG_PATH=~/ansible.log
# Enable Debug
export ANSIBLE_DEBUG=True
# Run with ``-vvvv`` for connection level verbosity
ansible -m arista.eos.eos_command -a 'commands=?' -i inventory switch1.example.net -e 'ansible_connection=ansible.netcommon.network_cli' -u admin -k
然后查看日志文件,并在本文档的其余部分中找到相关的错误消息。
排查套接字路径问题
平台:任何平台
消息 Socket path does not exist or cannot be found
和 Unable to connect to socket
表明用于与远程网络设备通信的套接字不可用或不存在。
例如
fatal: [spine02]: FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Traceback (most recent call last):\n File \"/tmp/ansible_TSqk5J/ansible_modlib.zip/ansible/module_utils/connection.py\", line 115, in _exec_jsonrpc\nansible.module_utils.connection.ConnectionError: Socket path XX does not exist or cannot be found. See Troubleshooting socket path issues in the Network Debug and Troubleshooting Guide\n",
"module_stdout": "",
"msg": "MODULE FAILURE",
"rc": 1
}
或
fatal: [spine02]: FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Traceback (most recent call last):\n File \"/tmp/ansible_TSqk5J/ansible_modlib.zip/ansible/module_utils/connection.py\", line 123, in _exec_jsonrpc\nansible.module_utils.connection.ConnectionError: Unable to connect to socket XX. See Troubleshooting socket path issues in Network Debug and Troubleshooting Guide\n",
"module_stdout": "",
"msg": "MODULE FAILURE",
"rc": 1
}
解决建议
验证您是否对错误消息中描述的套接字路径具有写入权限。
按照 启用网络日志 中详细介绍的步骤操作。
如果日志文件中识别的错误消息是
2017-04-04 12:19:05,670 p=18591 u=fred | command timeout triggered, timeout value is 30 secs
或
2017-04-04 12:19:05,670 p=18591 u=fred | persistent connection idle timeout triggered, timeout value is 30 secs
按照 超时问题 中详细介绍的步骤操作。
类别“无法打开 Shell”
平台:任何平台
消息 unable to open shell
表示 ansible-connection
守护进程无法成功与远程网络设备通信。这通常意味着存在身份验证问题。这是一个“通用”消息,这意味着您需要启用 日志记录 才能找到根本问题。
例如
TASK [prepare_eos_tests : enable cli on remote device] **************************************************
fatal: [veos01]: FAILED! => {"changed": false, "failed": true, "msg": "unable to open shell"}
或
TASK [ios_system : configure name_servers] *************************************************************
task path:
fatal: [ios-csr1000v]: FAILED! => {
"changed": false,
"failed": true,
"msg": "unable to open shell",
}
解决建议
按照 enable_network_logging 中详细介绍的步骤操作。
确定日志文件中的错误消息后,可以在本文档的其余部分中找到具体的解决方案。
错误:“[Errno -2] 名称或服务未知”
平台:任何平台
表示您尝试连接到的远程主机无法访问。
例如
2017-04-04 11:39:48,147 p=15299 u=fred | control socket path is /home/fred/.ansible/pc/ca5960d27a
2017-04-04 11:39:48,147 p=15299 u=fred | current working directory is /home/fred/git/ansible-inc/stable-2.3/test/integration
2017-04-04 11:39:48,147 p=15299 u=fred | using connection plugin network_cli
2017-04-04 11:39:48,340 p=15299 u=fred | connecting to host veos01 returned an error
2017-04-04 11:39:48,340 p=15299 u=fred | [Errno -2] Name or service not known
解决建议
如果您使用的是
provider:
选项,请确保其子选项host:
设置正确。如果您没有使用
provider:
或顶级参数,请确保您的库存文件正确。
错误:“身份验证失败”
平台:任何平台
如果传递给 ansible-connection
(通过 ansible
或 ansible-playbook
)的凭据(用户名、密码或 SSH 密钥)无法用于连接到远程设备,则会出现此问题。
例如
<ios01> ESTABLISH CONNECTION FOR USER: cisco on PORT 22 TO ios01
<ios01> Authentication failed.
解决建议
如果您通过 password:
(直接或通过 provider:
)或环境变量 ANSIBLE_NET_PASSWORD 指定凭据,则 paramiko
(Ansible 使用的 Python SSH 库)可能正在使用 SSH 密钥,因此您指定的凭据将被忽略。要确定是否为这种情况,请禁用“查找密钥”。可以像这样完成
export ANSIBLE_PARAMIKO_LOOK_FOR_KEYS=False
要将此更改为永久性更改,请将以下内容添加到您的 ansible.cfg
文件中
[paramiko_connection]
look_for_keys = False
错误:“连接到主机 <hostname> 返回错误”或“地址错误”
如果 SSH 指纹尚未添加到 Paramiko(Python SSH 库)的已知主机文件中,则可能会出现此问题。
在使用 Paramiko 的持久连接时,连接在后台进程中运行。如果主机没有有效的 SSH 密钥,默认情况下 Ansible 会提示添加主机密钥。这会导致在后台进程中运行的连接失败。
例如
2017-04-04 12:06:03,486 p=17981 u=fred | using connection plugin network_cli
2017-04-04 12:06:04,680 p=17981 u=fred | connecting to host veos01 returned an error
2017-04-04 12:06:04,682 p=17981 u=fred | (14, 'Bad address')
2017-04-04 12:06:33,519 p=17981 u=fred | number of connection attempts exceeded, unable to connect to control socket
2017-04-04 12:06:33,520 p=17981 u=fred | persistent_connect_interval=1, persistent_connect_retries=30
解决建议
使用 ssh-keyscan
预填充 known_hosts。您需要确保密钥正确。
ssh-keyscan veos01
或
您可以告诉 Ansible 自动接受密钥
环境变量方法
export ANSIBLE_PARAMIKO_HOST_KEY_AUTO_ADD=True
ansible-playbook ...
ansible.cfg
方法
ansible.cfg
[paramiko_connection]
host_key_auto_add = True
错误:“没有可用的身份验证方法”
例如
2017-04-04 12:19:05,670 p=18591 u=fred | creating new control socket for host veos01:None as user admin
2017-04-04 12:19:05,670 p=18591 u=fred | control socket path is /home/fred/.ansible/pc/ca5960d27a
2017-04-04 12:19:05,670 p=18591 u=fred | current working directory is /home/fred/git/ansible-inc/ansible-workspace-2/test/integration
2017-04-04 12:19:05,670 p=18591 u=fred | using connection plugin network_cli
2017-04-04 12:19:06,606 p=18591 u=fred | connecting to host veos01 returned an error
2017-04-04 12:19:06,606 p=18591 u=fred | No authentication methods available
2017-04-04 12:19:35,708 p=18591 u=fred | connect retry timeout expired, unable to connect to control socket
2017-04-04 12:19:35,709 p=18591 u=fred | persistent_connect_retry_timeout is 15 secs
解决建议
没有提供密码或 SSH 密钥
清除持久连接
平台:任何平台
在 Ansible 2.3 中,持久连接套接字存储在所有网络设备的 ~/.ansible/pc
中。当 Ansible 剧本运行时,如果指定了详细输出,则会显示持久套接字连接。
<switch> socket_path: /home/fred/.ansible/pc/f64ddfa760
要清除持久连接,在它超时之前(默认超时时间为 30 秒不活动),只需删除套接字文件即可。
超时问题
持久连接空闲超时
默认情况下,ANSIBLE_PERSISTENT_CONNECT_TIMEOUT
设置为 30(秒)。如果此值太低,您可能会看到以下错误
2017-04-04 12:19:05,670 p=18591 u=fred | persistent connection idle timeout triggered, timeout value is 30 secs
解决建议
增加持久连接空闲超时时间的值
export ANSIBLE_PERSISTENT_CONNECT_TIMEOUT=60
要将此更改为永久性更改,请将以下内容添加到您的 ansible.cfg
文件中
[persistent_connection]
connect_timeout = 60
命令超时
默认情况下,ANSIBLE_PERSISTENT_COMMAND_TIMEOUT
设置为 30(秒)。以前版本的 Ansible 默认将此值设置为 10 秒。如果此值太低,您可能会看到以下错误
2017-04-04 12:19:05,670 p=18591 u=fred | command timeout triggered, timeout value is 30 secs
解决建议
选项 1(全局命令超时设置):在配置文件中增加命令超时时间的值,或通过设置环境变量来增加。
export ANSIBLE_PERSISTENT_COMMAND_TIMEOUT=60
要将此更改为永久性更改,请将以下内容添加到您的
ansible.cfg
文件中[persistent_connection] command_timeout = 60
选项 2(按任务命令超时设置):按任务增加命令超时时间。所有网络模块都支持一个超时值,可以按任务设置。超时值控制命令未返回之前任务失败的时间量(以秒为单位)。
对于本地连接类型
解决建议
某些模块支持一个
timeout
选项,它与任务的timeout
关键字不同。- name: save running-config cisco.ios.ios_command: commands: copy running-config startup-config provider: "{{ cli }}" timeout: 30
解决建议
如果模块不支持
timeout
选项,大多数网络连接插件可以使用ansible_command_timeout
变量启用类似的功能。- name: save running-config cisco.ios.ios_command: commands: copy running-config startup-config vars: ansible_command_timeout: 60
某些操作的完成时间比默认的 30 秒长。一个很好的例子是在 IOS 设备上将当前运行配置保存到启动配置。在这种情况下,将超时值从默认的 30 秒更改为 60 秒将防止任务在命令成功完成之前失败。
持久连接重试超时
默认情况下,ANSIBLE_PERSISTENT_CONNECT_RETRY_TIMEOUT
设置为 15(秒)。如果此值太低,您可能会看到以下错误
2017-04-04 12:19:35,708 p=18591 u=fred | connect retry timeout expired, unable to connect to control socket
2017-04-04 12:19:35,709 p=18591 u=fred | persistent_connect_retry_timeout is 15 secs
解决建议
增加持久连接空闲超时时间的值。注意:此值应大于 SSH 超时值(配置文件 defaults 部分下的超时值),并且小于持久连接空闲超时时间(connect_timeout)。
export ANSIBLE_PERSISTENT_CONNECT_RETRY_TIMEOUT=30
要将此更改为永久性更改,请将以下内容添加到您的 ansible.cfg
文件中
[persistent_connection]
connect_retry_timeout = 30
剧本问题
本节详细介绍了由剧本本身问题引起的问题。
错误:“无法进入配置模式”
平台:Arista EOS 和 Cisco IOS
当您尝试在用户模式 shell 中运行需要特权模式的任务时,就会发生这种情况。
例如
TASK [ios_system : configure name_servers] *****************************************************************************
task path:
fatal: [ios-csr1000v]: FAILED! => {
"changed": false,
"failed": true,
"msg": "unable to enter configuration mode",
}
解决建议
使用
connection: ansible.netcommon.network_cli
和become: true
代理问题
delegate_to 与 ProxyCommand
为了通过 cli
传输使用堡垒机或中间跳跃主机连接到网络设备,网络模块支持使用 ProxyCommand
。
要使用 ProxyCommand
,请在 Ansible 清单文件中配置代理设置以指定代理主机。
[nxos]
nxos01
nxos02
[nxos:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q bastion01"'
使用上面的配置,只需像往常一样构建和运行剧本,无需进行任何其他更改。现在,网络模块将通过首先连接到在 ansible_ssh_common_args
中指定的主机(在上面的示例中为 bastion01
)来连接到网络设备。
您也可以使用环境变量为所有主机设置代理目标。
export ANSIBLE_SSH_ARGS='-o ProxyCommand="ssh -W %h:%p -q bastion01"'
使用堡垒机/跳跃主机与 netconf 连接
启用跳跃主机设置
- 可以通过以下方式启用堡垒机/跳跃主机与 netconf 连接
将 Ansible 变量
ansible_netconf_ssh_config
设置为True
或自定义 ssh 配置文件路径将环境变量
ANSIBLE_NETCONF_SSH_CONFIG
设置为True
或自定义 ssh 配置文件路径在
netconf_connection
部分中设置ssh_config = 1
或ssh_config = <ssh-file-path>
如果配置变量设置为 1,则代理命令和其他 ssh 变量将从默认 ssh 配置文件(~/.ssh/config)中读取。
如果配置变量设置为文件路径,则代理命令和其他 ssh 变量将从给定的自定义 ssh 文件路径中读取。
示例 ssh 配置文件 (~/.ssh/config)
Host jumphost
HostName jumphost.domain.name.com
User jumphost-user
IdentityFile "/path/to/ssh-key.pem"
Port 22
# Note: Due to the way that Paramiko reads the SSH Config file,
# you need to specify the NETCONF port that the host uses.
# In other words, it does not automatically use ansible_port
# As a result you need either:
Host junos01
HostName junos01
ProxyCommand ssh -W %h:22 jumphost
# OR
Host junos01
HostName junos01
ProxyCommand ssh -W %h:830 jumphost
# Depending on the netconf port used.
示例 Ansible 清单文件
[junos]
junos01
[junos:vars]
ansible_connection=ansible.netcommon.netconf
ansible_network_os=junipernetworks.junos.junos
ansible_user=myuser
ansible_password=!vault...
注意
通过变量使用 ProxyCommand
和密码
根据设计,SSH 不支持通过环境变量提供密码。这样做是为了防止秘密泄露,例如在 ps
输出中。
我们建议尽可能使用 SSH 密钥,并在需要时使用 ssh-agent,而不是密码。
杂项问题
使用 ansible.netcommon.network_cli
连接类型时出现间歇性故障
如果在 ansible.netcommon.network_cli
连接插件中未正确匹配响应中收到的命令提示符,则任务可能会间歇性地失败,并出现截断响应或错误消息 operation requires privilege escalation
。从 2.7.1 开始,添加了一个新的缓冲区读取计时器以确保正确匹配提示并完整地将响应发送到输出。计时器默认值为 0.2 秒,可以在每个任务的基础上调整,也可以以秒为单位全局设置。
示例按任务计时器设置
- name: gather ios facts
cisco.ios.ios_facts:
gather_subset: all
register: result
vars:
ansible_buffer_read_timeout: 2
要将其设置为全局设置,请在 ansible.cfg
文件中添加以下内容
[persistent_connection]
buffer_read_timeout = 2
可以通过将值设置为零来禁用在远程主机上执行的每个命令的此计时器延迟。
由于命令响应中错误正则表达式不匹配导致任务失败,使用 ansible.netcommon.network_cli
连接类型
在 Ansible 2.9 及更高版本中,添加了 ansible.netcommon.network_cli
连接插件配置选项以处理 stdout 和 stderr 正则表达式,以识别命令执行响应是否包含正常响应或错误响应。这些选项可以设置为组/主机变量或任务变量。
示例:对于错误响应不匹配
- name: fetch logs from remote host
cisco.ios.ios_command:
commands:
- show logging
剧本运行输出
TASK [first fetch logs] ********************************************************
fatal: [ios01]: FAILED! => {
"changed": false,
"msg": "RF Name:\r\n\r\n <--nsip-->
\"IPSEC-3-REPLAY_ERROR: Test log\"\r\n*Aug 1 08:36:18.483: %SYS-7-USERLOG_DEBUG:
Message from tty578(user id: ansible): test\r\nan-ios-02#"}
解决建议
修改单个任务的错误正则表达式。
- name: fetch logs from remote host
cisco.ios.ios_command:
commands:
- show logging
vars:
ansible_terminal_stderr_re:
- pattern: 'connection timed out'
flags: 're.I'
终端插件正则表达式选项 ansible_terminal_stderr_re
和 ansible_terminal_stdout_re
具有 pattern
和 flags
作为键。flags
键的值应为 re.compile
python 方法接受的值。
由于网络或远程目标主机较慢而使用 ansible.netcommon.network_cli
连接类型时出现间歇性故障
在 Ansible 2.9 及更高版本中,添加了 ansible.netcommon.network_cli
连接插件配置选项以控制连接到远程主机的尝试次数。默认尝试次数为 3。在每次重试尝试后,重试之间的延迟将以秒为单位增加 2 的幂,直到尝试次数达到最大值或 persistent_command_timeout
或 persistent_connect_timeout
计时器被触发为止。
要将其设置为全局设置,请在 ansible.cfg
文件中添加以下内容
[persistent_connection]
network_cli_retries = 5