在Chef中执行阶段分配变量值

46次阅读
没有评论

问题描述

在使用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 =那一行代码似乎没有被使用,如果后续不使用这个变量,可以将它从代码中删除。

这个解决方案应该能够解决你在编译阶段与执行阶段之间的问题,并确保正确地处理变量赋值和条件检查。这样你就能够在第一个资源执行后,根据这个变量的值来控制第二个资源的条件块是否执行。

正文完