问题描述
在使用Chef创建配方时,有一个问题是如何在执行阶段(converge phase)为变量赋值。具体来说,用户在一个配方中有两个资源。初始VPN IP地址是一个空字符串。在执行第一个资源时,会设置一个在10.12.xx.xx范围内的IP地址。然后,会执行第二个资源,其中有一个条件块(guard block),用于检查VPN IP地址。
用户在一个Chef配方中遇到了一些问题,他希望能够在执行阶段为变量赋值,以便在第一个资源执行后,可以在第二个资源的条件块中检查这个变量的值。由于某些代码在编译阶段执行,导致问题出现。用户试图将代码放入一个ruby_block
中来解决这个问题,但是他不确定如何正确地在执行阶段后检查这个变量的值。
解决方案
在Chef中,遇到编译阶段与执行阶段的时间差问题时,可以使用ruby_block
结构以及node.run_state
哈希来解决。这样可以确保在执行阶段正确地处理变量赋值和检查。
以下是一个重写后的配方示例,这个配方应该能够解决你的问题:
## Cookbook:: test_cookbook
# Recipe:: check-vpn-ip
## Copyright:: 2019, The Authors, All Rights Reserved.
# 获取IP地址,使用ruby的Socket类
ip_list = Socket.ip_address_list
vpn_ip_list = ip_list.select{ |ip| ip.ip_address.match(/^10.12/) }
vpn_ip_list.empty? ? ip_addr = "" : ip_addr = vpn_ip_list.first.ip_address
execute 'manually_start_open_vpn' do
command "sudo openvpn #{node['openvpn-conf-path']}/#{host}.conf &"
action :nothing
only_if { ip_addr.length.eql?(0) }
end
ruby_block 'check_vpn_ip_list' do
block do
new_ip_list = Socket.ip_address_list
new_vpn_ip_list = new_ip_list.select{ |ip| ip.ip_address.match(/^10.12/) }
node.run_state['newvpn_ip_addr'] = new_vpn_ip_list.empty? ? "" : new_vpn_ip_list.first.ip_address
end
end
ruby_block 'chat-bot' do
block do
machine_data = {
text: "OpenVPN IP not assigned to #{host} \n software_version: 18.4.4 \n This is a test message please ignore @all"
}.to_json
header = {'Content-Type': 'text/json'}
http = Net::HTTP.new(google_chat_uri.host, google_chat_uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(google_chat_uri.request_uri, header)
request.body = machine_data
response = http.request(request)
end
only_if { node.run_state['newvpn_ip_addr'].length.eql?(0) }
action :nothing
end
在上面的配方示例中,我们使用了两个ruby_block
结构来确保在执行阶段进行变量赋值和检查。node.run_state
哈希用于在不同的资源之间共享数据。
请注意,上述代码中的response =
那一行代码似乎没有被使用,如果后续不使用这个变量,可以将它从代码中删除。
这个解决方案应该能够解决你在编译阶段与执行阶段之间的问题,并确保正确地处理变量赋值和条件检查。这样你就能够在第一个资源执行后,根据这个变量的值来控制第二个资源的条件块是否执行。
正文完