最近在Windows上使用Puppet,总是遇到一个诡异的问题:在某些机器上无法获得ipaddress这个fact,直接使用facter命令行也不行,而且显得完全没有规律。
具体情况是:
- facter 在所有机器上可以获得ipaddress
- facter –puppet 在部分机器上出现 invalid address 错误
ipaddress这个fact是在facter/lib/facter/ipaddress.rb添加进来的。关键代码是:
1 2 3 4 5 6 7 |
|
发现是IPSocket.getaddress函数不起作用,于是又把问题定位在Puppet自带的Ruby环境中的ipaddr.rb中,发现以下代码在某些机器上无法获得IP。
1 2 3 4 5 6 7 8 |
|
一开始没发现哪有问题,后来仔细看了下valid中的正则表达式,发现不允许hostname中出现下划线。
之前一直没注意过这问题,所以测试主机的hostname都是随意命名的,所以才会出现部分主机可以通过验证,部分不行的情况。
不过也是现在才知道原来主机名规范有一条是不能带下划线。
Windows命名的时候完全没这个限制,但是在Ubuntu里使用hostname命令修改时,如果带下划线会直接提示错误。
很奇怪自己以前在Ubuntu上怎么没遇到过这个错误,难道就鬼使神差的从没使用过带下划线的主机名?
但是现在问题又来了,为什么facter都可以,facter –puppet就不行呢?
于是又研究了一遍facter的加载机制,在facter取值的部分折腾好久,最后发现和这部分没关系。是因为执行facter时没有加载facter/lib/facter/ipaddr.rb,ipaddr.rb中对IPSocket#getaddress的重写未生效,直接使用了Puppet自带Ruby中的socket.so中定义的IPSocket#getaddress,这个函数定义里面就没有对主机名的正则验证。
想来Puppet也是为了做多平台支持,所以加了一个MonkeyPatch,对主机名做了验证。
现在又绕回来了,–puppet 到底干了啥?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
根据代码来看,只是把Puppet的libdir加入了\$LOAD_PATH。
这个libdir里面都是些自定义的facter、tyep和provider,似乎和ipaddr.rb完全没关系。
又卡在这儿想了半天,才发现思路错了。
ipaddr.rb虽然在lib目录下,但是不会自动加载,需要显式require。
于是注释掉
1
|
|
使用facter –puppet也就和正常一样了。