如何为自定义Facts添加依赖,使其在FTP下载exec命令后执行
解决Puppet中Facts提前执行的时序问题
这是个非常典型的Puppet核心机制问题——咱们得先搞清楚为什么会出现这个情况,再针对性解决:
问题根源:Puppet的编译阶段 vs 应用阶段
Puppet的自定义Facts是在编译Catalog阶段就运行的(不管是master编译还是agent本地编译),而你写的exec资源是在Catalog应用阶段才会执行。简单说就是:Facts先跑完收集信息,Puppet才会去执行下载文件的命令,所以Facts自然拿不到下载后的文件列表。这是Puppet的设计逻辑,没法直接让Facts等exec执行完再跑。
解决方案分两种场景:
场景1:后续处理不需要依赖Facts,直接在Puppet里完成
如果你的文件处理逻辑可以直接写成Puppet资源,那完全不用绕Facts,直接给后续资源加依赖就行。比如用另一个exec来处理文件,让它必须等下载的exec完成后再执行:
exec{"download from ftp ${value}": command => "wget -r --user=${ftp_username} --password=${ftp_password} ${value}/* -P ${patch_download_path}", path => ['/usr/bin', '/usr/sbin'], timeout => 1800, user =>'root', } # 处理下载文件的exec,明确依赖下载任务 exec{"process downloaded files": command => "your_processing_script.sh ${patch_download_path}", path => ['/usr/bin', '/usr/sbin'], require => Exec["download from ftp ${value}"], # 关键:指定依赖 onlyif => "test -d ${patch_download_path} && test -n \"$(ls -A ${patch_download_path})\"", # 确保有文件才执行 }
场景2:必须用Facts传递文件列表(比如其他模块要用到)
如果一定要让Facts能获取到下载后的文件,那得把操作分成两次Puppet运行:
- 第一次运行:执行FTP下载的exec
- 第二次运行:Facts收集已经下载好的文件列表
实现方式有两种:
- 方式一:在下载完成后自动触发第二次Puppet run
给下载的exec加个后续命令,下载完成后立刻让agent再运行一次,这样第二次运行时Facts就能拿到文件了。注意加个判断避免无限循环:
exec{"download from ftp ${value}": command => "wget -r --user=${ftp_username} --password=${ftp_password} ${value}/* -P ${patch_download_path} && puppet agent -t", path => ['/usr/bin', '/usr/sbin'], timeout => 1800, user =>'root', unless => "test -d ${patch_download_path} && test -n \"$(ls -A ${patch_download_path})\"", # 路径非空就不执行 }
- 方式二:用External Fact动态检测
写一个脚本作为External Fact(放在/etc/puppetlabs/facter/facts.d/目录下,后缀为.sh或.rb),脚本逻辑是:检查${patch_download_path}是否有文件,如果有就输出文件列表作为fact值。这样每次Puppet run的编译阶段都会执行这个脚本,第一次run时路径是空的,fact返回空;第二次run时文件已经下载,fact就能拿到列表了。
举个简单的shell脚本示例(命名为listdirectory.sh):
#!/bin/bash if [ -d "${patch_download_path}" ] && [ -n "$(ls -A "${patch_download_path}")" ]; then echo "listdirectory=$(ls -1 "${patch_download_path}" | tr '\n' ',')" else echo "listdirectory=" fi
重要提醒
别强行让Facts在应用阶段执行,这违背了Puppet的设计原则——Facts是用来收集系统静态/预存在的信息的,动态生成的内容(比如刚下载的文件)应该放在应用阶段的资源里处理,或者通过两次run来衔接。
内容的提问来源于stack exchange,提问作者ksa
相关产品推荐
相关产品推荐

