Por que o Puppet (quase) sempre falha ao gravar no meu sistema de arquivos Gluster?

3

Estou usando o Puppet para gerenciar alguns arquivos que são compartilhados entre servidores, por meio do sistema de arquivos GlusterFS. (Os detalhes não devem importar, mas neste caso coisas como /etc/httpd/conf.d e / var / www / html são montadas na rede, via GlusterFS. Isso é nos servidores RHEL 6, com o Puppet 3.8 e o Gluster 3,5.)

O Puppet não tem problemas com arquivos que são locais para um determinado servidor, mas quando tento criar ou atualizar arquivos neste sistema de arquivos compartilhado, quase nunca funciona. Puppet vê que uma mudança precisa ser feita, mas então o arquivo falha na verificação subseqüente da soma de verificação. Aqui está um exemplo de Puppet tentando (e falhando) criar um arquivo:

change from absent to file failed: File written to disk did not match checksum; discarding changes ({md5}990680e579211b74e3a8b58a3f4d9814 vs {md5}d41d8cd98f00b204e9800998ecf8427e)

Veja um exemplo semelhante de edição de arquivo:

change from {md5}216751de84e40fc247cb02da3944b415 to {md5}261e86c60ce62a99e4b1b91611c1af0e failed: File written to disk did not match checksum; discarding changes ({md5}261e86c60ce62a99e4b1b91611c1af0e vs {md5}d41d8cd98f00b204e9800998ecf8427e)

Isso nem sempre acontece, mas nos meus sistemas de arquivos Gluster, eu diria que isso acontece pelo menos 90% do tempo.

A última soma de verificação (d41d8 ...) é a soma de verificação de um arquivo vazio. Então, acho que isso é o que está acontecendo: Puppet vê que a mudança precisa ser feita e faz a mudança. Mas ele faz o checksum do arquivo novamente antes que a gravação seja confirmada, portanto, não vê que a alteração foi feita com sucesso e, portanto, é revertida.

Duas perguntas, então. Primeiro: isso parece plausível e como posso testar / confirmar que esse é o caso? Segundo: Assumindo que isso é o que está acontecendo, como evitá-lo? A primeira coisa que vem à mente seria simplesmente dormir por algumas centenas de milissegundos após as operações de troca de arquivos, mas não sei imediatamente se isso é possível, muito menos sábio.

    
por David E. Smith 12.12.2015 / 05:01

1 resposta

0

Conciso

A soma de verificação do arquivo será verificada e subseqüentemente liberada. Esta soma de verificação será comparada com o arquivo que será gravado. Se houver uma discrepância, a gravação falhará.

Verbose

O erro é lançado pelo seguinte método, que é definido no arquivo. 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

e este método contém o seguinte método que reside na soma de verificação. rb :

  def sum_file(path)
    type = digest_algorithm()
    method = type.to_s + "_file"
    "{#{type}}" + send(method, path).to_s
  end

Como é calculado o checksum?

O método responsável por isso também reside no arquivo.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

O snippet que verifica a soma de verificação: 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

O seguinte snippet:

content_checksum = write_content(file)
file.flush
fail_if_checksum_is_wrong(file.path, content_checksum) if validate_checksum?

indica que há uma discrepância entre o arquivo que será gravado e realmente está escrito.

Discussão

The latter checksum (d41d8...) is the checksum of an empty file.

Como você verificou isso?

So I think this is what's happening: Puppet sees that the change needs to be made, and makes the change. But it checksums the file again before the write is committed, so it doesn't see that the change was successfully made, and so it rolls back.

O código, conforme explicado acima, funciona sempre como explicado e, de acordo com minha experiência, a verificação de checksum funciona.

Conclusão

Parece que há problemas com o GlusterFS, por exemplo O arquivo que foi implantado usando o Puppet foi alterado por algum motivo pelo GlusterFS.

Sugestão

Sugiro depurar o problema da seguinte forma:

  1. Implantar o arquivo 1 com o conteúdo X no Puppet
  2. Implemente este arquivo no GlusterFS usando o Puppet
  3. Verifique a soma de verificação do arquivo 1 que reside no servidor de puppets manualmente
  4. Verifique a soma de verificação do arquivo 1 que reside no GlusterFS manualmente
  5. Execute o Puppet no GlusterFS e verifique se o problema ocorre
por 15.12.2015 / 02:28