Я использую Puppet для управления некоторыми файлами, которые используются серверами совместно с файловой системой GlusterFS. (Специфика не имеет значения, но в этом случае такие вещи, как /etc/httpd/conf.d и / var / www / html, монтируются по сети через GlusterFS. Это на серверах RHEL 6 с Puppet 3.8 и Gluster 3.5.)
У Puppet нет проблем с файлами, которые являются локальными для данного сервера, но когда я пытаюсь создать или обновить файлы в этой общей файловой системе, он почти никогда не работает. Puppet видит, что необходимо внести изменение, но затем файл не проходит последующую проверку контрольной суммы. Вот пример того, как Puppet пытается (и не может) создать файл:
изменение с отсутствующего на файл не выполнено: файл, записанный на диск, не соответствует контрольной сумме; отмена изменений ({md5} 990680e579211b74e3a8b58a3f4d9814 vs {md5} d41d8cd98f00b204e9800998ecf8427e)
Вот аналогичный пример редактирования файла:
изменение с {md5} 216751de84e40fc247cb02da3944b415 на {md5} 261e86c60ce62a99e4b1b91611c1af0e не удалось: файл, записанный на диск, не соответствует контрольной сумме; отмена изменений ({md5} 261e86c60ce62a99e4b1b91611c1af0e vs {md5} d41d8cd98f00b204e9800998ecf8427e)
Это не всегда происходит, но в моих файловых системах Gluster, я бы сказал, что это происходит как минимум в 90% случаев.
Последняя контрольная сумма (d41d8 ...) - это контрольная сумма пустого файла. Итак, я думаю, вот что происходит: Puppet видит, что изменение необходимо внести, и вносит изменения. Но он снова проверяет сумму файла перед фиксацией записи, поэтому он не видит, что изменение было успешно выполнено, и поэтому откатывается.
Тогда два вопроса. Во-первых: кажется ли это правдоподобным и как мне проверить / подтвердить, что это так? Во-вторых: если предположить, что именно это происходит, как мне это предотвратить? Первое, что приходит в голову, это просто спать в течение нескольких сотен миллисекунд после операций изменения файла, но я не сразу знаю, возможно ли это вообще, тем более что разумно.
Контрольная сумма файла будет проверена и впоследствии сброшена. Эта контрольная сумма будет сравниваться с файлом, который будет записан. Если есть несоответствие, запись не удастся.
Ошибка вызывается следующим методом, который определен в файл.rb:
# Make sure the file we wrote out is what we think it is.
def fail_if_checksum_is_wrong(path, content_checksum)
newsum = parameter(:checksum).sum_file(path)
return if [:absent, nil, content_checksum].include?(newsum)
self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})"
end
и этот метод содержит следующий метод, который находится в контрольная сумма.rb:
def sum_file(path)
type = digest_algorithm()
method = type.to_s + "_file"
"{#{type}}" + send(method, path).to_s
end
Как рассчитывается контрольная сумма?
Метод, отвечающий за это, также находится в файле file.rb:
def write(property)
remove_existing(:file)
mode = self.should(:mode) # might be nil
mode_int = mode ? symbolic_mode_to_int(mode, Puppet::Util::DEFAULT_POSIX_MODE) : nil
if write_temporary_file?
Puppet::Util.replace_file(self[:path], mode_int) do |file|
file.binmode
content_checksum = write_content(file)
file.flush
fail_if_checksum_is_wrong(file.path, content_checksum) if validate_checksum?
if self[:validate_cmd]
output = Puppet::Util::Execution.execute(self[:validate_cmd].gsub(self[:validate_replacement], file.path), :failonfail => true, :combine => true)
output.split(/\n/).each { |line|
self.debug(line)
}
end
end
else
umask = mode ? 000 : 022
Puppet::Util.withumask(umask) { ::File.open(self[:path], 'wb', mode_int ) { |f| write_content(f) } }
end
# make sure all of the modes are actually correct
property_fix
end
Фрагмент, проверяющий контрольную сумму: content_checksum = write_content(file)
:
# write the current content. Note that if there is no content property
# simply opening the file with 'w' as done in write is enough to truncate
# or write an empty length file.
def write_content(file)
(content = property(:content)) && content.write(file)
end
Следующий фрагмент:
content_checksum = write_content(file)
file.flush
fail_if_checksum_is_wrong(file.path, content_checksum) if validate_checksum?
указывает, что есть несоответствие между файлом, который будет записан, и фактически записанным.
Последняя контрольная сумма (d41d8 ...) - это контрольная сумма пустого файла.
Как ты это проверял?
Итак, я думаю, вот что происходит: Puppet видит, что изменение необходимо внести, и вносит изменения. Но он снова проверяет сумму файла перед фиксацией записи, поэтому он не видит, что изменение было успешно выполнено, и поэтому откатывается.
Код, описанный выше, всегда работает так же, как объяснено, и по моему опыту проверка контрольной суммы работает.
Похоже, есть проблемы с GlusterFS, например файл, который был развернут с помощью Puppet, был по какой-то причине изменен GlusterFS.
Предлагаю устранить проблему следующим образом: