Серверы 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-серверами, я написал новый марионеточный модуль, который вырезает последние две цифры имени хоста, и если это нечетное число, то /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, я добавил "делать", как вы показали, теперь ошибка такая:
[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
В этом случае вам может быть лучше подойдет шаблон. Что-то вроде...
# 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, чтобы определить, проходите ли вы по массиву (каждый) или поднимаетесь по нему (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
строк, как есть в массиве.
Я вижу, что вы пытаетесь сделать в Еврорадио, но я думаю, что вы слишком усложняете это. Вы кодируете логику локализации (nj vs ams vs lax) в самом ERB. Это можно сделать, но, возможно, вам больше повезет, если вы выполните эту часть кода марионетки. Более вероятно, что кто-то еще сможет его прочитать, если эта часть логики совпадает с кодом марионетки.
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 в том же классе, который вызывает шаблон.
Метапараметр «до» действительно говорит только о порядке выполнения ресурсов, а не о порядке строк в файле.
На вашем месте я бы стремился управлять resolv.conf с помощью конструктов марионеток первого класса: отдельного модуля, который управляет им как файловым ресурсом (их, вероятно, несколько в кузнице марионеток), или написать свой собственный небольшой шаблон, который явно упорядочивает указанные параметры сервера имен.
Другой вариант - указать оба сервера имен в одном ресурсе 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 (MAXNS в resolv.h), но с использованием только ресурсов file_line избежать этого может быть сложно или невозможно).
Так же after
Параметр относится к ресурсам file_line, подсказывая, куда вставить строку, и before
- общий параметр ресурса, говорящий об упорядочивании ресурсов.