厨师卫队块红宝石代码在运行时不执行

时间:2019-03-06 16:21:54

标签: ruby chef chef-recipe chef-solo

根据Chef的两遍模型,在ruby-block,guard块和lazy中的任何代码仅在运行时执行。

我有一个包含三种资源的食谱。

在编译阶段分配值的变量。

require 'socket'
require 'down'
require 'net/http'

conf = `hostname`.chomp
vpn_ip_list = Socket.ip_address_list.select{ |ip| ip.ip_address.match(/^10.12/) }
!vpn_ip_list.empty? ? ip_addr = vpn_ip_list.first.ip_address : ip_addr = ""

第一资源-检查是否使用保护块中的代码分配了所需的VPN IP地址,如果未分配,则下载conf文件并通知第二服务资源重新启动openvpn。保护块内部变量的值是在编译阶段获得的。

ruby_block 'download_openvpn_conf' do
block do 
    attempt = 2
    begin
        retries ||= 0
        tempfile = Down.download("http://some-url1/#{conf}",max_redirects: 0)
        FileUtils.mv tempfile.path, "#{node['openvpn-conf-path']}/#{tempfile.original_filename}"
        FileUtils.chmod 0644, "#{node['openvpn-conf-path']}/#{tempfile.original_filename}"
    rescue Down::Error => e
        node.run_state['error'] = e.to_s
        puts e
        Chef::Log.warn ("\n \t ***********#{e}***********")
        retry if (retries += 1) < 1
    end 
end
only_if {vpn_ip_list.size.eql?(0) || vpn_ip_list.size >= 2}
action :run
notifies :restart, 'service[openvpn]', :immediately
notifies :delete, "file[#{node['openvpn-conf-path']}/#{conf}]", :before
end

第二资源-重新启动openvpn服务。此时,VPN IP已分配给系统。

service 'openvpn' do
supports :status => true, :restart => true, :start => true, :stop => true
action :nothing
Chef::Log.info ("\n \t *********Restarting OPEN-VPN*********")
end

由于上述服务是在融合阶段执行的,因此应该已经基于下载的配置文件分配了VPN ip地址。

第3个资源-如果在第2个资源执行时未分配VPN IP,则将请求新的vpn conf文件。

ruby_block 'manual_vpn' do
block do
    if node.run_state['error'] == "file not found"
        Chef::Log.info ("\n \t ******** VPN IP has not been assigned. File may be corrupted & initiating re-run********")
        uri = URI.parse("http://some-url2=#{host}&action=create")
        Chef::Log.info (uri)
        http = Net::HTTP.new(uri.host,uri.port)
        request = Net::HTTP::Get.new(uri.request_uri)
        response = http.request(request)
        case response.body
        when "error"
            Chef::Log.info ("\n \t Website reported an Error. Config for the given serial number could have already been generated")
        when "Request for vpn successfully added."  
            Chef::Log.warn ("\n \t **** Inside response processing => Request Accepted **")
            Chef::Log.warn ("\n \t *** New vpn config request has been accepted. Waiting for 3 minutes ***")
            sleep 180
        else
            Chef::Log.info ("\n \t Nothing to do - Extra option for future")    
        end 
    else 
        puts "Config file exists and hence not downloading"
    end     
end 
notifies :run, 'ruby_block[re-download-vpn-conf]', :delayed
only_if { Socket.ip_address_list.select{ |ip| ip.ip_address.match(/^10.12/) }.size.eql?(0) }
not_if {node.run_state['error'].eql?("too many redirects")}
end 

分配的VPN IP由保护块only_if { Socket.ip_address_list.select{ |ip| ip.ip_address.match(/^10.12/) }.size.eql?(0) }中的代码检查,并且应该仅在运行时执行。在第二次资源执行结束时,已确定已分配VPN IP,但上述防护中的代码无法检测到它。

我在测试ruby块内的配方末尾使用了Pry调试器,以验证在执行第二个服务重启资源后是否分配了IP。想知道为什么Chef的保护块中的代码无法检测到先前资源执行所分配的VPN。

1 个答案:

答案 0 :(得分:0)

基本上,问题是Chef不等待服务后资源执行系统的状态。 Chef不会理会服务是否已启动并且正在运行,它只关心服务的执行。

这是比赛条件的经典示例,厨师动摇头以执行下一个资源。为了避免这种情况,我必须在红宝石块中引入所需的睡眠时间。另一种方法是添加一个until true条件,但是在我的情况下该方法不起作用,因为服务已启动并正在运行,但厨师中的红宝石块被无限卡住了。

service 'openvpn' do
   supports :status => true, :restart => true, :start => true, :stop => true
   action :nothing
   Chef::Log.info ("\n \t *********Restarting OPEN-VPN*********")
end


ruby_block 'wait for vpn ip' do
    block do
        Chef::Log.warn ("****************** Sleep block starts ********************")
        sleep 30
        Chef::Log.warn ("****************** Sleep block exits ********************")
    end 
    action :run
end

ruby_block 'manual_vpn' do
block do
    if node.run_state['error'] == "file not found"
        Chef::Log.info ("\n \t ******** VPN IP has not been assigned. File may be corrupted & initiating re-run********")
        uri = URI.parse("http://some-url2=#{host}&action=create")
        Chef::Log.info (uri)
        http = Net::HTTP.new(uri.host,uri.port)
        request = Net::HTTP::Get.new(uri.request_uri)
        response = http.request(request)
        case response.body
        when "error"
            Chef::Log.info ("\n \t Website reported an Error. Config for the given serial number could have already been generated")
        when "Request for vpn successfully added."  
            Chef::Log.warn ("\n \t **** Inside response processing => Request Accepted **")
            Chef::Log.warn ("\n \t *** New vpn config request has been accepted. Waiting for 3 minutes ***")
            sleep 180
        else
            Chef::Log.info ("\n \t Nothing to do - Extra option for future")    
        end 
    else 
        puts "Config file exists and hence not downloading"
    end     
end 
notifies :run, 'ruby_block[re-download-vpn-conf]', :delayed
only_if { Socket.ip_address_list.select{ |ip| ip.ip_address.match(/^10.12/) }.size.eql?(0) }
not_if {node.run_state['error'].eql?("too many redirects")}
end