我公司的 Linux 服务器由 Puppet 管理。
有一个 DNS 模块,它/etc/resolv.conf
根据配置为值的物理位置在所有服务器上进行配置facter
。
正如您所知,/etc/resolv.conf
文件如下所示:
search domain.local
nameserver 1.1.1.1
nameserver 2.2.2.2
公司内所有服务器的主机名都以两位数字结尾,例如:
proxy73
为了在两个 DNS 服务器之间分割 DNS 网络流量,我编写了一个新的 puppet 模块,它会截断主机名的最后两位数字,如果它是一个奇数,那么文件/etc/resolv.conf
应该如上所示,但如果数字产生了一个奇数,那么文件/etc/resolv.conf
应该如下所示:
search domain.local
nameserver 2.2.2.2
nameserver 1.1.1.1
但我的问题是,无论我如何编写清单,这些行的顺序总是先是第一个服务器,然后是第二个服务器,而不是先是第二个服务器,然后是第一个服务器。
我编写的清单的相关部分如下所示(请参阅下一部分,if $::oddip == false
因为那是不起作用的部分):
class dns_new::config {
case $::dcd {
'ny4': {
if $::oddip == 'true' {
file_line { "ny4 search domain":
ensure => present,
line => "${::dns_new::params::searchdomny4}",
path => "/etc/resolv.conf",
}
file_line { "ny4dns1 first":
ensure => present,
line => "${::dns_new::params::ny4dns1}",
path => "/etc/resolv.conf",
}
file_line { "ny4dns2 second":
ensure => present,
line => "${::dns_new::params::ny4dns2}",
path => "/etc/resolv.conf",
}
}
elsif $::oddip == 'false' {
file_line { "ny4 search domain":
ensure => present,
line => "${::dns_new::params::searchdomny4}",
path => "/etc/resolv.conf",
}
file_line { "ny4dns2 first":
ensure => present,
line => "${::dns_new::params::ny4dns2}",
path => "/etc/resolv.conf",
require => File_line["ny4 search domain"],
before => File_line["ny4dns1 second"],
}
file_line { "ny4dns1 second":
ensure => present,
line => "${::dns_new::params::ny4dns1}",
path => "/etc/resolv.conf",
require => File_line["ny4dns2 first"],
}
}
}
您可以看到我已尝试使用指令设置顺序before
。
这是关于设置新服务器的全部内容,但是如何设置已安装服务器的行顺序?
编辑#2:
sysadmin1183,我按照您说的添加了“do”,现在的错误是这样的:
[root@nyproxy33 ~]# puppet agent -t
Info: Retrieving plugin
Info: Loading facts
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: compile error
/etc/puppet/environments/production/modules/dns_new/templates/resolv.conf.erb:27: syntax error, unexpected $end, expecting kEND
; _erbout
^
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
第27行是:
<% end %>
尝试将其编辑为:
<% end -%>
但得到相同的输出...
编辑#3:
config.pp
看起来像这样:
class dns_new::config {
file { "/etc/resolv.conf":
path => '/etc/resolv.conf',
ensure => present,
owner => "root",
group => "root",
mode => "775",
content => template("dns_new/resolv.conf.erb"),
}
case $::dcd {
'ny4': {
$search_dom = $::dns_new::params::searchdomny4
if $::oddip == 'true' {
$dns_list = [ "${::dns_new::params::ny4dns1}", "${::dns_new::params::ny4dns2}" ]
}
elsif $::oddip == 'false' {
$dns_list = [ "${::dns_new::params::ny4dns2}", "${::dns_new::params::ny4dns1}" ]
}
}
该resolv.conf.erb
文件如下所示:
search <%= @search_dom %>
<% dns_list.each do |serv| -%>
nameserver <%= serv %>
<% end -%>
奔跑木偶:
[root@nyproxy33 ~]# puppet agent -t
Info: Retrieving plugin
Info: Loading facts
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Failed to parse template dns_new/resolv.conf.erb:
Filepath: /usr/lib/ruby/site_ruby/1.8/puppet/parser/templatewrapper.rb
Line: 81
Detail: Could not find value for 'dns_list' at /etc/puppet/environments/production/modules/dns_new/templates/resolv.conf.erb:2
at /etc/puppet/environments/production/modules/dns_new/manifests/config.pp:8 on node nyproxy33.ny4.peer39.com
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
答案1
在这种情况下,使用模板可能会更好。例如...
# This is done to bring the variable into scope.
$search_dom = $::dns_new::params::searchdomny4
if $::oddip == 'true' {
$dns_order = [ '1.1.1.1', '2.2.2.2' ]
} elsif $::oddip == 'false' {
$dns_order = [ '2.2.2.2', '1.1.1.1' ]
}
file { '/etc/resolv.conf':
[usual stuff]
content => template('dns_new/resolv.conf.erb'),
}
ERB 模板如下所示:
new_dns/templates/resolv.conf.erb
:
search <%= @search_dom %>
<% @dns_order.each do |serv| %>
nameserver <%= serv %>
<% end -%>
它应该按照您想要的顺序发出 resolv.conf 文件。
另一种选择是仅在模块中编码 DNS 服务器列表,并使用 ERB 模板中的 ruby 代码来确定是向下遍历数组 (each) 还是向上遍历数组 (reverse.each)。看起来如下:
$search_dom = $::dns_new::params::searchdomny4
$dns_list = $::dns_new::params::dnslist
$oddip = $::oddip
file { '/etc/resolv.conf':
[usual stuff]
content => template('dns_new/resolv.conf.erb')
}
使用更复杂的 ERB 格式,例如:
search <%= @search_dom %>
<% if @odd_ip == 'true' %>
<% @dns_list.each do |srv| -%>
nameserver <%= srv %>
<% end -%>
<% elsif @odd_ip == 'false' -%>
<% @dns_list.reverse.each do |srv| -%>
nameserver <%= srv %>
<% end -%>
<% end -%>
如果你以前没有做过模板,标记的关键大致如下:
<% : Here is ruby code.
<%= : Here is an evaluated value. Replace this block with the
result, or enter a blank line.
-%> : End a block. Don't render a blank line if it doesn't evaluate to anything.
模板将逐行评估。第一行很简单,删除了 resolv conf 的“服务器”部分。第二行变得更复杂:我们调用 ruby 函数。这使我们能够删除nameserver
数组中尽可能多的行。
我知道你想在 ERB 中做什么,但我认为你把它复杂化了。你在 ERB 本身中编码了本地化逻辑(nj vs ams vs lax)。这可以做到,但你可能更愿意在 puppet-code 中完成这部分。如果这部分逻辑与 puppet 代码一起,其他人就更有可能读懂。
dns_new/manifests/config.pp
:
case $::dcd {
'ny4': {
$search_domain = $::dns_new::params::searchdomny4
$dns_list = [ "${::dns_new::params::ny4dns1}", "${::dns_new::params::ny4dns2}" ]
}
'nj': {
$search_domain = $::dns_new::params::searchdomnj
$dns_list = [ "${::dns_new::params::njdns1}", "${::dns_new::params::njdns2}" ]
}
'ams2': {
$search_domain = $::dns_new::params::searchdomams2
$dns_list = [ "${::dns_new::params::ams2dns1}", "${::dns_new::params::ams2dns2}" ]
}
}
file { '/etc/resolv.conf':
[the usual stuff]
content = template('dns_new/resolv.conf.erb')
}
现在,您需要在 ERB 中处理两个变量。search_domain
和dns_list
。 这大大缩短了 ERB:
dns_new/templates/resolv.conf.erb
:
search <%= @search_domain %>
<% dns_list.each do |serv| -%>
nameserver <%= serv %>
<% end -%>
如果您想知道为什么我要在类中分配变量并在 ERB 中使用这些变量,而不是使用 params 类中的变量,这是因为超出范围的变量在 ERB 文件中的工作方式不直观。在调用模板的同一个类中分配将在 ERB 文件中使用的变量要容易得多,而且风格也很好。
答案2
“before”元参数实际上只说明了资源的执行顺序,而不是文件中行的顺序。
如果我是你,我会尝试使用一流的 puppet 构造来管理 resolv.conf:一个将其作为文件资源进行管理的单独模块(puppet forge 上可能有几个),或者编写你自己的小模板,明确地对指定的名称服务器参数进行排序。
另一个选择是在一个 file_line 资源中指定两个名称服务器,并使用\n
以下方式将它们分开:
file_line { "ny4dns2 first":
ensure => present,
line => "${::dns_new::params::ny4dns1}\n${::dns_new::params::ny4dns2}",
path => "/etc/resolv.conf",
require => File_line["ny4 search domain"],
after => "${::dns_new::params::searchdomny4}"
}
如果它们的顺序错误,它将不会重新排序,但至少会以正确的顺序将它们添加到搜索语句的正下方(可能列出 4 个名称服务器,超过 3 个(resolv.h 中的 MAXNS),但仅使用 file_line 资源来避免这种情况可能很难或不可能)。
此外,该after
参数特定于 file_line 资源,提示在何处插入行,并且before
是一个谈论资源排序的一般资源参数。