我使用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议如下debugging问题: