木偶:检查一组variables

编辑:我想出了我认为是这个最好的方法。 感谢人们回答我的问题 – 一路上有所帮助。 我要发布我的解决scheme,以便其他人可以find它,如果他们想要的。

原问题:

我想用puppet自动configuration一些我们的NFS文件系统。 但是,我希望清单能够确保在正确的networking上拥有知识产权。

Puppet通过interfacesipaddress_***事实有助于提供关于机器分配的IP的事实。 问题是我需要检查所有的接口(我宁愿不要假设它们是如何连接的)。

问题1:木偶可以通过事实列表循环吗? 例如:

 for $if in $interfaces { //do something } 

问题2:如果Puppet能够做到这一点,是否有一种方法来评估一个string作为一个variables。 interfaces提供了一个非常好的方法来知道有多lessipaddress_***network_***variables,但即使我可以循环它的值,我需要做一些事情:

 for $if in $interfaces { $net_var = eval("network_${if}") if $net_var = /^192\.168\.2\.0$/ { //do something } } 

这可能吗? 我是否完全错误(对木偶有点新鲜)?

我最终做了什么:

Puppet允许您为模块定义自定义分析器函数。 这些自定义函数只是ruby,所以你可以有效地做任何你想要的内容,包括循环。

你把它们放在<module_dir>/lib/puppet/parser/functions/ 。 为了做我想做的,我创build了<module_dir>/lib/puppet/parser/functions/has_network.rb以下内容:

 #has_network.rb require 'ipaddr' module Puppet::Parser::Functions newfunction(:has_network, :type => :rvalue) do |args| retcon = "" if not /^[0-9]{1,3}(\.[0-9]{1,3}){3}\/[0-2]?[0-9]$/.match(args[0]) then raise Puppet::ParseError, "Network provided was not valid. Provide 192.168.0.0/16 format" else requested_network = IPAddr.new(args[0]) interfaces_fact = lookupvar('interfaces') interfaces = interfaces_fact.split(",") interfaces.each do |interface| ip = IPAddr.new(lookupvar("ipaddress_#{interface}")) if requested_network.include?(ip) retcon = "true" end end end retcon end end 

这增加了一个新的函数,我可以在我的名为has_network的清单中使用。 如果机器的一个IP地址在提供给该function的networking上,则返回true。 现在我可以做如下的事情:

 if has_network("192.168.1.0/24"){ //do something } 

一些关于自定义函数的注释

  • 这些在主服务器上运行。 注意使用lookupvar来对Facter事实进行操作。 你不能在客户端上使用其中的一个来创build文件。
  • 当你改变function时,你必须重新启动puppetmaster。 如果你不这样做,傀儡大师将永远不会加载更新的function,你会很困惑。

正如@Zoredache提到的那样,Puppet中没有循环。 但是你可以通过使用一个定义来解决这个问题,例如:

 define show_ip { $inf = "ipaddress_${name}" $ip = inline_template('<%= scope.lookupvar(inf) %>') if $ip =~ /192\.168\.3.*/ { notify {"Found IP $ip": } } } $ifs = split($interfaces, ',') show_ip { $ifs: } 

当直接调用时,Belows是输出:

 # puppet manifests/defines/net.pp warning: Implicit invocation of 'puppet apply' by passing files (or flags) directly to 'puppet' is deprecated, and will be removed in the 2.8 series. Please invoke 'puppet apply' directly in the future. notice: Found IP 192.168.3.118 notice: /Stage[main]//Show_ip[eth1]/Notify[Found IP 192.168.3.118]/message: defined 'message' as 'Found IP 192.168.3.118' notice: Finished catalog run in 0.07 seconds 

资料来源: https : //blog.kumina.nl/tag/puppet-tips-and-tricks/

傀儡中没有循环或迭代。

多了一些,在这里有一个替代版本,应该适用于单个接口上的任意数量的ips,而不使用eval。 to_hash.keys返回所有variables名称的数组, find_all过滤基于正则expression式的列表, map ping用于查找variables的实际值,最后将结果合并回一个string。

 $iplist=inline_template('<%= scope.to_hash.keys.find_all{|i| i =~ /ipaddress_.*/}.map{|j| scope.lookupvar(j)}.join(",")%>') if $iplist =~ /10\.2\.93.*/ { notify {"found $iplist": } } # on the client with a matching address we see "notice: found 10.2.93.5,127.0.0.1" 

我有一些工作,但我不知道这是真正的最好的解决scheme,或安全。 基本上我想你可以使用inline_template。 在内联模板中,我们分离了接口事实,它是所有接口的列表。 我们使用一个映射来构build一个新的所有接口的IP地址数组,最后我们将数组重新join到一个string中。

我最担心的是我正在做一个基本上由客户端系统提供的东西。 我不完全确定这是多么的邪恶。

如果接口有多个地址,或者接口没有地址,这也会中断。 也许别人可以build议一些改进。 我只是在学习ruby。

 $iplist=inline_template('<%= interfaces.split(",").map{|x| eval ("ipaddress_"+x)}.join(",")%>') if $iplist =~ /10\.2\.93.*/ { notify {"found $iplist": } } # on the client with a matching address we see "notice: found 10.2.93.5,127.0.0.1"