Назад | Перейти на главную страницу

Почему Puppet (почти) всегда не записывает в мою файловую систему Gluster?

Я использую 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.

Предложение

Предлагаю устранить проблему следующим образом:

  1. Развернуть файл 1 с содержимым X на Puppet
  2. Разверните этот файл в GlusterFS с помощью Puppet
  3. Проверьте контрольную сумму файла 1, который находится на марионеточном сервере, вручную.
  4. Проверьте контрольную сумму файла 1, который находится на GlusterFS, вручную
  5. Запустите Puppet на GlusterFS и проверьте, возникает ли проблема.