Apply CIB changes using patch method

Generate XML diff patch and apply it.

1) generate config changes in shadow
2) generate diff only for specific scope
3) apply it

This will not touch cluster attributes and
other stuff it should not touch, thus not
breaking functionality of OCF scripts using
CIB attributes.

Change-Id: Ibcfaa82707d1aed01b79c8307d17f4e71fd60906
Closes-bug: #1338594
This commit is contained in:
Vladimir Kuklin 2014-07-08 15:24:07 +04:00
parent fd5fd0d3f7
commit 03342f53fa
5 changed files with 97 additions and 12 deletions

View File

@ -70,4 +70,72 @@ class Puppet::Provider::Corosync < Puppet::Provider
debug(@property_hash.inspect)
!(@property_hash[:ensure] == :absent or @property_hash.empty?)
end
def get_scope(type)
case type
when 'resource'
scope='resources'
when /^(colocation|order|location)$/
scope='constraints'
when 'rsc_defaults'
scope='rsc_defaults'
else
fail('unknown resource type')
scope=nil
end
return scope
end
def apply_changes(res_name,tmpfile,res_type)
env={}
shadow_name="#{res_type}_#{res_name}"
original_cib="/tmp/#{shadow_name}_orig.xml"
new_cib="/tmp/#{shadow_name}_new.xml"
begin
debug('trying to delete old shadow if exists')
crm_shadow("-b","-f","-D",shadow_name)
rescue Puppet::ExecutionFailure
debug('delete failed but proceeding anyway')
end
crm_shadow("-b","-c",shadow_name)
env["CIB_shadow"] = shadow_name
exec_withenv("#{command(:crm)} configure load update #{tmpfile.path.to_s}",env)
if !get_scope(res_type).nil?
cibadmin_scope = "-o #{get_scope(res_type)}"
else
cibadmin_scope = nil
end
orig_status = exec_withenv("#{command(:cibadmin)} #{cibadmin_scope} -Q > /tmp/#{shadow_name}_orig.xml")
#cibadmin returns code 6 if scope is empty
#in this case write empty file
if orig_status == 6 or File.open("/tmp/#{shadow_name}_orig.xml").read.empty?
cur_scope=REXML::Element.new(get_scope(res_type)).to_s
emptydoc=REXML::Document.new(cur_scope)
emptydoc.write(File.new("/tmp/#{shadow_name}_orig.xml",'w'))
end
exec_withenv("#{command(:cibadmin)} #{cibadmin_scope} -Q > /tmp/#{shadow_name}_new.xml",env)
patch = Open3.popen3("#{command(:crm_diff)} --original #{original_cib} --new #{new_cib}")[1].read
if patch.empty?
debug("no difference - nothing to apply")
return
end
xml_patch = REXML::Document.new(patch)
wrap_cib=REXML::Element.new('cib')
wrap_configuration=REXML::Element.new('configuration')
wrap_cib.add_element(wrap_configuration)
wrap_cib_a=Marshal.load(Marshal.dump(wrap_cib))
wrap_cib_r=Marshal.load(Marshal.dump(wrap_cib))
diff_a=REXML::XPath.first(xml_patch,'//diff-added')
diff_r=REXML::XPath.first(xml_patch,'//diff-removed')
diff_a_elements=diff_a.elements
diff_r_elements=diff_r.elements
wrap_configuration_a=REXML::XPath.first(wrap_cib_a,'//configuration')
wrap_configuration_r=REXML::XPath.first(wrap_cib_r,'//configuration')
diff_a_elements.each {|element| wrap_configuration_a.add_element(element)}
diff_r_elements.each {|element| wrap_configuration_r.add_element(element)}
diff_a.add_element(wrap_cib_a)
diff_r.add_element(wrap_cib_r)
cibadmin '--patch', '--sync-call', '--xml-text', xml_patch
end
end

View File

@ -9,8 +9,13 @@ Puppet::Type.type(:cs_colocation).provide(:crm, :parent => Puppet::Provider::Cor
# Path to the crm binary for interacting with the cluster configuration.
# Decided to just go with relative.
commands :cibadmin => 'cibadmin'
commands :crm_shadow => 'crm_shadow'
commands :crm => 'crm'
commands :crm_diff => 'crm_diff'
commands :crm_attribute => 'crm_attribute'
def self.instances
block_until_ready
@ -103,9 +108,7 @@ Puppet::Type.type(:cs_colocation).provide(:crm, :parent => Puppet::Provider::Cor
Tempfile.open('puppet_crm_update') do |tmpfile|
tmpfile.write(updated.rstrip)
tmpfile.flush
env = {}
env["CIB_shadow"] = @resource[:cib].to_s if !@resource[:cib].nil?
exec_withenv("#{command(:crm)} configure load update #{tmpfile.path.to_s}",env)
apply_changes(@resource[:name],tmpfile,'colocation')
end
end
end

View File

@ -9,8 +9,13 @@ Puppet::Type.type(:cs_location).provide(:crm, :parent => Puppet::Provider::Coros
# Path to the crm binary for interacting with the cluster configuration.
# Decided to just go with relative.
commands :cibadmin => 'cibadmin'
commands :crm_shadow => 'crm_shadow'
commands :crm => 'crm'
commands :crm_diff => 'crm_diff'
commands :crm_attribute => 'crm_attribute'
def self.instances
block_until_ready
@ -199,9 +204,7 @@ Puppet::Type.type(:cs_location).provide(:crm, :parent => Puppet::Provider::Coros
Tempfile.open('puppet_crm_update') do |tmpfile|
tmpfile.write(updated.rstrip)
tmpfile.flush
env = {}
env["CIB_shadow"] = @resource[:cib].to_s if !@resource[:cib].nil?
exec_withenv("#{command(:crm)} configure load update #{tmpfile.path.to_s}",env)
apply_changes(@resource[:name],tmpfile,'location')
end
end
end

View File

@ -8,8 +8,13 @@ Puppet::Type.type(:cs_order).provide(:crm, :parent => Puppet::Provider::Corosync
aspects.'
# Path to the crm binary for interacting with the cluster configuration.
commands :cibadmin => 'cibadmin'
commands :crm_shadow => 'crm_shadow'
commands :crm => 'crm'
commands :crm_diff => 'crm_diff'
commands :crm_attribute => 'crm_attribute'
def self.instances
block_until_ready
@ -111,9 +116,7 @@ Puppet::Type.type(:cs_order).provide(:crm, :parent => Puppet::Provider::Corosync
Tempfile.open('puppet_crm_update') do |tmpfile|
tmpfile.write(updated.rstrip)
tmpfile.flush
env = {}
env["CIB_shadow"] = @resource[:cib].to_s if !@resource[:cib].nil?
exec_withenv("#{command(:crm)} configure load update #{tmpfile.path.to_s}",env)
apply_changes(@resource[:name],tmpfile,'order')
end
end
end

View File

@ -11,8 +11,14 @@ Puppet::Type.type(:cs_resource).provide(:crm, :parent => Puppet::Provider::Coros
better model since these values can be almost anything.'
# Path to the crm binary for interacting with the cluster configuration.
commands :cibadmin => 'cibadmin'
commands :crm_shadow => 'crm_shadow'
commands :crm => 'crm'
commands :crm_diff => 'crm_diff'
commands :crm_attribute => 'crm_attribute'
def self.instances
block_until_ready
@ -125,6 +131,8 @@ Puppet::Type.type(:cs_resource).provide(:crm, :parent => Puppet::Provider::Coros
debug('Stopping primitive before removing it')
crm('resource', 'stop', @resource[:name])
debug('Removing primitive')
## FIXME(aglarendil): may be we need to apply crm_diff related approach
## FIXME(aglarendil): due to 1338594 bug and do this in flush section
try_command("delete",@resource[:name])
@property_hash.clear
end
@ -258,9 +266,9 @@ Puppet::Type.type(:cs_resource).provide(:crm, :parent => Puppet::Provider::Coros
Tempfile.open('puppet_crm_update') do |tmpfile|
tmpfile.write(updated)
tmpfile.flush
env = {}
env["CIB_shadow"] = @resource[:cib].to_s if !@resource[:cib].nil?
exec_withenv("#{command(:crm)} configure load update #{tmpfile.path.to_s}",env)
#env["CIB_shadow"] = @resource[:cib].to_s if !@resource[:cib].nil?
##LP1338594 part: should be put into separate method, I guess
apply_changes(@resource[:name],tmpfile,'resource')
end
end
end