Files
puppet-pacemaker/lib/puppet/provider/pcmk_common.rb
Michele Baldessari fe4d448938 Remove spurious CIB backup files
There are some situations where we did not clean up CIB backup files
correctly:
1) When a pcs show command was invoked
2) When we hit the maximum number of retries.
3) When the original file and the copy cib file are identical and we
   still called push_config() (very unlikely but we best clean that up)

Let's remove these files in both of these cases.

Closes-Bug: #1667145

Change-Id: I41404d569d81973c4b9531266c7a6c09904d1baf
2017-02-23 00:25:00 +01:00

123 lines
4.3 KiB
Ruby

require 'digest'
# backs up the current cib and returns the temporary file name where it
# was stored. Besides the temporary file it also makes an identical copy
# called temporary file + ".orig"
def backup_cib()
# We use the pacemaker CIB folder because of its restricted access permissions
cib = Dir::Tmpname.make_tmpname "/var/lib/pacemaker/cib/puppet-cib-backup", nil
cmd = "/usr/sbin/pcs cluster cib #{cib}"
output = `#{cmd}`
ret = $?
if not ret.success?
msg = "backup_cib: Running: #{cmd} failed with code: #{ret.exitstatus} -> #{output}"
FileUtils.rm(cib, :force => true)
raise Puppet::Error, msg
end
Puppet.debug("backup_cib: #{cmd} returned #{output}")
FileUtils.cp cib, "#{cib}.orig"
return cib
end
# Pushes the cib file back to the cluster and removes the cib files
# returns the pcs cluster cib-push return code. If the cib file and its
# original counterpart are the exact same push_cib() is a no-op.
# The pcs cluster-cib syntax with "diff-against" is used only if pcs supports
# it (it helps to minimize the chances that a cib-push might fail due
# to us trying to push a too old CIB)
def push_cib(cib)
cib_digest = Digest::SHA2.file(cib)
cib_orig_digest = Digest::SHA2.file("#{cib}.orig")
if cib_digest == cib_orig_digest
Puppet.debug("push_cib: #{cib} and #{cib}.orig were identical, skipping")
FileUtils.rm(cib, :force => true)
FileUtils.rm("#{cib}.orig", :force => true)
return 0
end
has_diffagainst = `/usr/sbin/pcs cluster cib-push --help`.include? 'diff-against'
cmd = "/usr/sbin/pcs cluster cib-push #{cib}"
if has_diffagainst
cmd += " diff-against=#{cib}.orig"
end
output = `#{cmd}`
ret = $?
FileUtils.rm(cib, :force => true)
FileUtils.rm("#{cib}.orig", :force => true)
if not ret.success?
msg = "push_cib: Running: #{cmd} failed with code: #{ret.exitstatus} -> #{output}"
Puppet.debug("push_cib failed: #{msg}")
end
Puppet.debug("push_cib: #{cmd} returned #{ret.exitstatus} -> #{output}")
return ret.exitstatus
end
def pcs(name, resource_name, cmd, tries=1, try_sleep=0,
verify_on_create=false, post_success_sleep=0)
if name.start_with?("create") && verify_on_create
return pcs_create_with_verify(name, resource_name, cmd, tries, try_sleep)
end
max_tries = name.include?('show') ? 1 : tries
max_tries.times do |try|
cib = backup_cib()
try_text = max_tries > 1 ? "try #{try+1}/#{max_tries}: " : ''
Puppet.debug("#{try_text}/usr/sbin/pcs -f #{cib} #{cmd}")
pcs_out = `/usr/sbin/pcs -f #{cib} #{cmd} 2>&1`
if name.include?('show')
FileUtils.rm(cib, :force => true)
FileUtils.rm("#{cib}.orig", :force => true)
# return output for good exit or false for failure.
return $?.exitstatus == 0 ? pcs_out : false
end
if $?.exitstatus == 0
# If push_cib failed, we stay in the loop and keep trying
if push_cib(cib) == 0
sleep post_success_sleep
return pcs_out
end
end
Puppet.debug("Error: #{pcs_out}")
if try == max_tries-1
FileUtils.rm(cib, :force => true)
FileUtils.rm("#{cib}.orig", :force => true)
pcs_out_line = pcs_out.lines.first ? pcs_out.lines.first.chomp! : ''
raise Puppet::Error, "pcs -f #{cib} #{name} failed: #{pcs_out_line}"
end
if try_sleep > 0
Puppet.debug("Sleeping for #{try_sleep} seconds between tries")
sleep try_sleep
end
end
end
def pcs_create_with_verify(name, resource_name, cmd, tries=1, try_sleep=0)
max_tries = tries
max_tries.times do |try|
try_text = max_tries > 1 ? "try #{try+1}/#{max_tries}: " : ''
Puppet.debug("#{try_text}/usr/sbin/pcs #{cmd}")
pcs_out = `/usr/sbin/pcs #{cmd} 2>&1`
if $?.exitstatus == 0
sleep try_sleep
cmd_show = "/usr/sbin/pcs resource show " + resource_name
Puppet.debug("Verifying with: "+cmd_show)
`#{cmd_show}`
if $?.exitstatus == 0
return pcs_out
else
Puppet.debug("Warning: verification of pcs resource creation failed")
end
else
Puppet.debug("Error: #{pcs_out}")
sleep try_sleep
end
if try == max_tries-1
pcs_out_line = pcs_out.lines.first ? pcs_out.lines.first.chomp! : ''
raise Puppet::Error, "pcs #{name} failed: #{pcs_out_line}"
end
end
end
def not_empty_string(p)
p && p.kind_of?(String) && ! p.empty?
end