Ansible调用expect执行AD域加入脚本时RPM安装异常中断问题
故障根因
故障完全是expect配置错误导致的,核心问题有4个:
- 超时时间设置过短:你写的
set timeout 10代表expect只要10秒没收到脚本的任何输出,就会直接终止spawn拉起的进程。yum安装RPM包过程中,大包解压、依赖校验、事务提交阶段经常会出现十几秒到几十秒不等的无输出窗口,这就是为什么安装会无规律卡在17、42、46个包的位置——卡在哪完全取决于当时哪个安装步骤的无输出时长超过了10秒阈值。 - 执行逻辑错误:你直接把expect语法写在了
ansible.builtin.shell模块的执行块里,但shell模块默认调用bash解释器,根本识别不了spawn、expect这些expect专属语法,相当于你写的expect逻辑根本没按预期跑。 - 匹配逻辑冗余且脆弱:你加的3段
expect -exact "\r"完全没有必要,输入回车后脚本不会单独返回一个\r字符供你匹配;同时用-exact做精确匹配容错性极差,只要提示语前后多一个空格、换行或者终端控制字符就会匹配失败。 - 缺少伪终端配置:sudo默认要求执行环境提供tty,你没给spawn的进程分配伪终端,也可能导致输出截断、进程异常挂死。
修正方案
直接替换成下面的Ansible任务配置即可,已经把上述问题全部修复:
- name: Joining of system to the domain ansible.builtin.shell: | /usr/bin/expect << 'EOF' # 超时设置为300秒(5分钟),足够覆盖全量RPM安装流程,安装速度慢的环境可以改成-1表示永不超时 set timeout 300 # 分配伪终端,适配sudo的tty校验要求 spawn -pty sudo ./addto-AD match_max 100000 # 匹配位置输入提示,加超时、提前退出的异常捕获 expect { "*Please Enter the Environment*" { send -- "Seattle\r" } timeout { puts "ERR: 等待位置输入提示超时"; exit 1 } eof { puts "ERR: 脚本在输入位置前异常退出"; exit 1 } } # 匹配提权用户名输入提示 expect { "*Enter Elevated AD Username*" { send -- "{{ elevated }}\r" } timeout { puts "ERR: 等待用户名输入提示超时"; exit 1 } eof { puts "ERR: 脚本在输入用户名前异常退出"; exit 1 } } # 匹配密码输入提示 expect { "*Enter Password for User*" { send -- "{{ elevated_pass }}\r" } timeout { puts "ERR: 等待密码输入提示超时"; exit 1 } eof { puts "ERR: 脚本在输入密码前异常退出"; exit 1 } } # 等待脚本执行完成,透传脚本的退出码给Ansible expect eof catch wait result set exit_code [lindex $result 3] exit $exit_code EOF args: # 替换成你addto-AD脚本实际存放的目录 chdir: /your/script/path register: ad_join_res failed_when: ad_join_res.rc != 0
补充说明
- 如果你的Ansible远程用户执行sudo时需要输入密码,需要在
spawn -pty sudo ./addto-AD下面新增一段密码匹配逻辑,发送Ansible配置里的sudo密码即可。 - 提示语匹配用
*关键词*的通配模式替换原来的精确匹配,能兼容提示语前后的不可见控制字符、空格、换行,不会因为微小的输出格式差异导致匹配失败。 - 手动执行脚本正常、Ansible调度异常的核心差异就是:手动操作时你会一直等脚本跑完,不会因为暂时没输出就杀进程;expect默认的超时机制会在无输出时主动终止进程,刚好命中了yum安装时的无输出窗口。
内容的提问来源于stack exchange,提问作者HBach
相关产品推荐
相关产品推荐

