According to Chef's two pass model any code inside ruby-block, guard blocks and lazy are executed only during run time.
I have a recipe with three resources.
Variables whose values are assigned during compile phase.
#
# Cookbook:: test_cookbook
# Recipe:: check-vpn-ip
#
# Copyright:: 2019, The Authors, All Rights Reserved.
#Getting the IP address using the ruby's Socket class.
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 = ""
1st resource - Checks if desired VPN IP address is assigned using code in guard block and if not assigned downloads the conf file and notifies 2nd service resource to restart openvpn. The values for variables inside guard block are obtained during compiled phase.
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
2nd resource - Restarts the openvpn service. By this time the VPN IP is assigned to system.
service 'openvpn' do
supports :status => true, :restart => true, :start => true, :stop => true
action :nothing
Chef::Log.info ("\n \t *********Restarting OPEN-VPN*********")
end
Since the above service is executed during the converge phase, the VPN ip address should have been assigned based on the downloaded configuration file.
3rd resource - If the VPN IP is not assigned by the time of execution of 2nd resource, this places a request for new vpn conf file.
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
The VPN IP assigned is checked by the code in guard block only_if { Socket.ip_address_list.select{ |ip| ip.ip_address.match(/^10.12/) }.size.eql?(0) }
and is supposed to be executed only at run time. By the end of 2nd resource execution the VPN IP is assigned for sure but code inside the above guard could not detect it.
I have used Pry debugger at the end of recipe within a test ruby block to verify that IP is assigned post the execution of 2nd service restart resource. Wondering why code inside the guard block of Chef is not able to detect the VPN assigned by the previous resource execution.