module Pacemaker # contains functions that can be included to the pacemaker types module Type # output IS and SHOULD values for debugging # @param is [Object] the current value of the parameter # @param should [Object] the catalog value of the parameter # @param tag [String] log tag comment to trace calls def insync_debug(is, should, tag = nil) debug "insync?: #{tag}" if tag debug "IS: #{is.inspect} #{is.class}" debug "SH: #{should.inspect} #{should.class}" end # return inspected data structure, used in should_to_s and is_to_s functions # @param data [Object] # @return [String] def inspect_to_s(data) data.inspect end # convert data structure's keys and values to strings # @param data [Object] # @return [Object] def stringify_data(data) if data.is_a? Hash new_data = {} data.each do |key, value| new_data.store stringify_data(key), stringify_data(value) end data.clear data.merge! new_data elsif data.is_a? Array data.map! do |element| stringify_data element end elsif data.is_a? Set raise "unexpected Set data: #{data}" else data.to_s end end # Maintains an array of operation hashes as if it was a sorted set. These # are in Array-of-Hash format ({ 'name' => 'monitor', 'interval' => ...}), # not { 'monitor' => {...} } ones. The unicity is done on the name and # interval operation keys. The input is expected to have been stringified # and munged. # # Modifies the operations argument and returns it. # # We can't use a real Set as it doesn't serialize correctly in Puppet's # transaction store. This datastructure is always small, so performance # is irrelevant. def add_to_operations_array(operations, new_op) operations.delete_if { |op| op['name'] == new_op['name'] && op['interval'] == new_op['interval'] } operations << new_op operations.sort_by! { |op| "#{op['name']} #{op['interval']}" } end # Munges the input into an Array of munged operations. # @param [Hash,Array] operations_input parameter value from catalog def munge_operations_array(operations_input) operations_input = stringify_data(operations_input) operations_input = [operations_input] unless operations_input.is_a? Array operations = [] operations_input.each do |operation| # operations were provided as an array of hashes if operation.is_a? Hash and operation['name'] munge_operation operation add_to_operations_array(operations, operation) elsif operation.is_a? Hash # operations were provided as a hash of hashes operation.each do |operation_name, operation_data| raise "invalid operation in a hash of hashes: #{operation_data}" unless operation_data.is_a? Hash operation = {} if operation_name.include? ':' operation_name_array = operation_name.split(':') operation_name = operation_name_array[0] if not operation_data['role'] and operation_name_array[1] operation_data['role'] = operation_name_array[1] end end operation['name'] = operation_name operation.merge! operation_data munge_operation operation add_to_operations_array(operations, operation) if operation.any? end else raise "invalid pacemaker_resource.operations input: #{operations_input}" end end operations end # munge a single operations hash # @param [Hash] operation def munge_operation(operation) raise "invalid pacemaker_resource.operations element: #{operation}" unless operation.is_a? Hash operation['name'] = 'monitor' unless operation['name'] operation['interval'] = '0' unless operation['name'] == 'monitor' operation['interval'] = '0' unless operation['interval'] operation['role'].capitalize! if operation['role'] operation end # compare meta_attribute hashes excluding status meta attributes # @param is [Hash] # @param should [Hash] # @return [TrueClass,FalseClass] def compare_meta_attributes(is, should) return unless is.is_a?(Hash) && should.is_a?(Hash) is_without_state = is.reject do |k, _v| pacemaker_options[:status_meta_attributes].include? k.to_s end should_without_state = should.reject do |k, _v| pacemaker_options[:status_meta_attributes].include? k.to_s end result = is_without_state == should_without_state debug "compare_meta_attributes: #{result}" result end # sort operations array before insync? # to make different order and same data arrays equal # @param is [Array] # @param should [Array] # @return [TrueClass,FalseClass] def compare_operations(is, should) is = is.first if is.is_a? Array should = should.first if should.is_a? Array result = (is == should) debug "compare_operations: #{result}" result end # remove status related meta attributes # from the meta attributes hash # @param attributes_from [Hash] # @return [Hash] def munge_meta_attributes(attributes_from) attributes_to = {} attributes_from.each do |name, parameters| next if pacemaker_options[:status_meta_attributes].include? name attributes_to.store name, parameters end attributes_to end # normalize a single location rule # @param rule [Hash] rule structure # @param rule_number [Integer] rule index number # @param title [String] constraint name # @return [Hash] normalized rule structure def munge_rule(rule, rule_number, title) rule['id'] = "#{title}-rule-#{rule_number}" unless rule['id'] rule['boolean-op'] = 'or' unless rule['boolean-op'] rule['score'].gsub! 'inf', 'INFINITY' if rule['score'] if rule['expressions'] unless rule['expressions'].is_a? Array expressions_array = [] expressions_array << rule['expressions'] rule['expressions'] = expressions_array end expression_number = 0 rule['expressions'].each do |expression| unless expression['id'] expression['id'] = "#{title}-rule-#{rule_number}-expression-#{expression_number}" end expression_number += 1 end end rule end # remove "-clone" or "-master" suffix # and "role" suffix (:Master, :Slave) from a primitive's name # @param primitive [String] # @return [String] def primitive_base_name(primitive) primitive = primitive.split(':').first primitive.gsub(/-clone$|-master$/, '') end end end