前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Puppet使用ENC报’Could not load external node results for’

Puppet使用ENC报’Could not load external node results for’

作者头像
星哥玩云
发布2022-07-03 15:57:01
4300
发布2022-07-03 15:57:01
举报
文章被收录于专栏:开源部署开源部署

这个问题出现有一段时间了,最开始的时候从一天3-5次左右到最近的一天出现10多次的告警邮件...

因为Puppet同步采取了主动触发和定时同步两种策略,几乎每次的报错都是在定时同步时出现...

Puppet Server采用双主结构,Web ui使用Foreman,为了确定这个报错是出现在那台服务器上, 通过对源代码的log增加主机标记最终定位到了这个错误只是出现在一台服务器上...,出现的很偶然,但所有的错误标记中,都是它....

Level? Resource? ? message

err Puppet? Could not retrieve catalog from remote server: Error 400 on SERVER: Failed when searching for node xxx: 001。,Could not load external node results for xxx: ?developer/article/2038890/undefined method `inject' for false:FalseClass ::--- false

notice? Puppet? Using cached catalog

err Puppet? Could not retrieve catalog; skipping run

最后面的 :: --- false? ? 其中::是在log中追加的分解符,方便区分, --- false 是返回的output的信息..

在Puppet源代码中 , 通过indirector与enc相关的find方法中可以看到这个find方法接受一个参数 request

?indirector/node/exec.rb

? def find(request)

? ? output = super or return nil

? ? # Translate the output to ruby.

? ? result = translate(request.key, output)

? ? create_node(request.key, result)

? end

output 是调用父方法的find

父方法的find会调用enc脚本获取返回值,如果失败或调用不成功则为Nil..

这时会继续通过translate方法,将yaml输出转为ruby的对象

如果output为nil,这时yaml在读取这个数据的时候就会抛出异常,异常就是收到的Puppet邮件告警的内容了。

? def translate(name, output)

? ? YAML.load(output).inject({}) do |hash, data|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? case data[0]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? when String? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? hash[data[0].intern] = data[1]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? when Symbol? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? hash[data[0]] = data[1]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? raise Puppet::Error, "key is a #{data[0].class}, not a string or symbol"? ? ? ? ? ?

? ? ? end? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? hash? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? end? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? rescue => detail? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? raise Puppet::Error, "001,Could not load external node results for #{name}: #{detail} ::#{output} "

? end

罗嗦了一大堆,其实就是node.rb的脚本在通过api取参数的时候,没有获得200...导致的。

通过指向一个错误的WEB服务器地址,可以看到 开头--- false。。。。

[root@test puppet]# ruby node1.rb test

--- false

Error retrieving node test: Net::HTTPNotFound?

分析node.rb

def enc(certname)

? foreman_url? ? ? = "#{url}/node/#{certname}?format=yml"

? uri? ? ? ? ? ? ? = URI.parse(foreman_url)

? req? ? ? ? ? ? ? = Net::HTTP::Get.new(uri.request_uri)

? http? ? ? ? ? ? = Net::HTTP.new(uri.host, uri.port)

? http.use_ssl? ? = uri.scheme == 'https'

? if http.use_ssl?

? ? if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?

? ? ? http.ca_file = SETTINGS[:ssl_ca]

? ? ? http.verify_mode = OpenSSL::SSL::VERIFY_PEER

? ? else

? ? ? http.verify_mode = OpenSSL::SSL::VERIFY_NONE

? ? end

? ? if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?

? ? ? http.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))

? ? ? http.key? = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)

? ? end

? end

? res = http.start { |http| http.request(req) }

? raise "Error retrieving node #{certname}: #{res.class}" unless res.code == "200"

? res.body

end

脚本的前面都是在构造一个http的对象...,直接看倒数第三行

可以清楚的看到一个判断,然后抛出异常,没有任何的重试机制....,为此我很确信我的web,它如果能有一次重试的机会,那么下一次一定能正常获得返回值,? 然后我就给了它很多次的机会。。。

? #raise "Error retrieving node #{certname}: #{res.class}" unless res.code == "200"

? while res.code != "200"

? ? res = http.start { |http| http.request(req) }

? ? puts "Error retrieving node #{certname}: #{res.class}"? ? sleep 3

? end

这时有些人可能会想,while 循环,加3秒重试,,如果一直不成功怎么办?

在脚本最开头会有配置timeout的地方,在timeout到了之后,会关闭http连接,然后读取cache。

? ? ? # query External node

? ? ? begin

? ? ? ? result = ""

? ? ? ? timeout(tsecs) do

? ? ? ? ? result = enc(certname)

? ? ? ? ? cache(certname, result)

? ? ? ? end

? ? ? rescue TimeoutError, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED

? ? ? ? # Read from cache, we got some sort of an error.

? ? ? ? result = read_cache(certname)

这段代码可以很清晰的看出,在timeout没超时时会调用enc这个方法返回结果,然后在调用cache方法写入到cache文件

如果超时或http错误,则读取cache,但是这里的异常不包括...,HTTP的...,如果如果是4XX的错误,不会触发读取cache的异常..

Puppet 学习系列:

Puppet 学习一:安装及简单实例应用 http://www.linuxidc.com/Linux/2013-08/88710.htm

Puppet学习二:简单模块配置和应用 http://www.linuxidc.com/Linux/2013-08/88711.htm

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com