为什么Puppet(几乎)总是无法写入我的Gluster文件系统?

我使用Puppet来pipe理一些在服务器之间共享的文件,通过GlusterFS文件系统。 (具体应该没有关系,但是在这种情况下,像/etc/httpd/conf.d和/ var / www / html这样的东西通过GlusterFS被安装在networking上,在RHEL 6服务器上,使用Puppet 3.8和Gluster 3.5。)

Puppet对于给定服务器本地的文件没有问题,但是当我尝试在这个共享文件系统上创build或更新文件时,它几乎不能工作。 Puppet认为需要进行更改,但是文件在随后的校验和检查中失败。 下面是Puppet尝试(和失败)创build一个文件的例子:

从缺席变为文件失败:写入磁盘的文件与校验和不匹配; 丢弃更改({md5} 990680e579211b74e3a8b58a3f4d9814 vs {md5} d41d8cd98f00b204e9800998ecf8427e)

这里有一个类似的文件编辑的例子:

从{md5} 216751de84e40fc247cb02da3944b415更改为{md5} 261e86c60ce62a99e4b1b91611c1af0e失败:写入磁盘的文件与校验和不匹配; 丢弃更改({md5} 261e86c60ce62a99e4b1b91611c1af0e vs {md5} d41d8cd98f00b204e9800998ecf8427e)

这并不总是发生,但在我的Gluster文件系统上,至less有90%的时间会发生这种情况。

后面的校验和(d41d8 …)是一个空文件的校验和。 所以我认为这就是发生了什么事情:Puppet认为需要做出改变,并做出改变。 但是在提交写入之前它会再次校验文件,所以它没有看到更改已成功完成,因此它会回滚。

那么两个问题。 首先:这似乎是有道理的,我如何testing/确认情况如此? 第二:假设这是发生了什么,我该如何预防呢? 首先想到的就是在文件更改操作之后几百毫秒的时间内hibernate,但是我不能立即知道这是否可能,更不明智。

简洁

文件的校验和将被检查并随后刷新。 该校验和将与将被写入的文件进行比较。 如果有差异,写入将会失败。

详细

该错误是由file.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 

并且此方法包含驻留在checksum.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存在问题,例如GlusterFS出于某种原因更改了使用Puppet部署的文件。

build议

我build议如下debugging问题:

  1. 在Puppet上部署带有内容X的文件1
  2. 在GlusterFS上使用Puppet部署这个文件
  3. 手动检查驻留在puppetserver上的文件1的校验和
  4. 手动检查驻留在GlusterFS上的文件1的校验和
  5. 在GlusterFS上运行Puppet并检查问题是否发生