Module: Pacemaker::Status

Included in:
Puppet::Provider::PacemakerXML, Serverspec::Type::PacemakerXML
Defined in:
lib/pacemaker/xml/status.rb

Overview

functions related to the primitive and node status main structure “node_status”

Instance Method Summary collapse

Instance Method Details

#cib_section_lrm_resources(lrm) ⇒ REXML::Element

get lrm_rsc_ops section from lrm_resource section CIB section at /cib/status/node_state/lrm/lrm_resources/lrm_resource

Parameters:

  • lrm (REXML::Element)

Returns:

  • (REXML::Element)


24
25
26
27
# File 'lib/pacemaker/xml/status.rb', line 24

def cib_section_lrm_resources(lrm)
  return unless lrm.is_a? REXML::Element
  REXML::XPath.match lrm, 'lrm_resources/lrm_resource'
end

#cib_section_lrm_rsc_ops(lrm_resource) ⇒ REXML::Element

get lrm_rsc_ops section from lrm_resource section CIB section at /cib/status/node_state/lrm/lrm_resources/lrm_resource/lrm_rsc_op

Parameters:

  • lrm_resource (REXML::Element)

Returns:

  • (REXML::Element)


9
10
11
12
# File 'lib/pacemaker/xml/status.rb', line 9

def cib_section_lrm_rsc_ops(lrm_resource)
  return unless lrm_resource.is_a? REXML::Element
  REXML::XPath.match lrm_resource, 'lrm_rsc_op'
end

#cib_section_node_stateREXML::Element

get node_state CIB section

Returns:

  • (REXML::Element)

    at /cib/status/node_state



16
17
18
# File 'lib/pacemaker/xml/status.rb', line 16

def cib_section_node_state
  REXML::XPath.match cib, '//node_state'
end

#decode_lrm_resources(lrm_resources, node_name = nil) ⇒ Hash<String => Hash>

decode lrm_resources section of CIB

Parameters:

  • lrm_resources (REXML::Element)
  • node_name (String) (defaults to: nil)

Returns:

  • (Hash<String => Hash>)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pacemaker/xml/status.rb', line 89

def decode_lrm_resources(lrm_resources, node_name=nil)
  resources = {}
  lrm_resources.each do |lrm_resource|
    resource = attributes_to_hash lrm_resource
    id = resource['id']
    next unless id
    lrm_rsc_ops = cib_section_lrm_rsc_ops lrm_resource
    next unless lrm_rsc_ops
    ops = decode_lrm_rsc_ops lrm_rsc_ops
    resource.store 'ops', ops
    resource.store 'status', determine_primitive_status(ops)
    resource.store 'failed', failed_operations_found?(ops)
    debug resource_operations_report ops, resource, node_name if pacemaker_options[:debug_show_operations]
    resources.store id, resource
  end
  resources
end

#decode_lrm_rsc_ops(lrm_rsc_ops) ⇒ Array<Hash>

decode lrm_rsc_ops section of the resource’s CIB

Parameters:

  • lrm_rsc_ops (REXML::Element)

Returns:

  • (Array<Hash>)


110
111
112
113
114
115
116
117
118
# File 'lib/pacemaker/xml/status.rb', line 110

def decode_lrm_rsc_ops(lrm_rsc_ops)
  ops = []
  lrm_rsc_ops.each do |lrm_rsc_op|
    op = attributes_to_hash lrm_rsc_op
    next unless op['call-id']
    ops << op
  end
  ops.sort { |a, b| a['call-id'].to_i <=> b['call-id'].to_i }
end

#determine_primitive_status(ops) ⇒ 'start', ...

determine resource status by parsing its operations it goes from the first operation to the last updating status if it’s defined in the end there will be the actual status of this primitive nil means that the status is unknown

Parameters:

  • ops (Array<Hash>)

Returns:

  • ('start', 'stop', 'master', nil)


76
77
78
79
80
81
82
83
# File 'lib/pacemaker/xml/status.rb', line 76

def determine_primitive_status(ops)
  status = nil
  ops.each do |op|
    op_status = operation_status op
    status = op_status if op_status
  end
  status
end

#failed_operations_found?(ops) ⇒ TrueClass, FalseClass

check if operations have same failed operations that should be cleaned up later

Parameters:

  • ops (Array<Hash>)

Returns:

  • (TrueClass, FalseClass)


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/pacemaker/xml/status.rb', line 144

def failed_operations_found?(ops)
  ops.each do |op|
    # skip pending ops
    next if op['op-status'] == '-1'

    # skip useless ops
    next unless %w(start stop monitor promote).include? op['operation']

    # are there failed start, stop
    if %w(start stop promote).include? op['operation']
      return true if op['rc-code'] != '0'
    end

    # are there failed monitors
    if op['operation'] == 'monitor'
      return true unless %w(0 7 8).include? op['rc-code']
    end
  end
  false
end

#node_statusHash<String => Hash>

get nodes_status structure with resources and their statuses

Returns:

  • (Hash<String => Hash>)


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/pacemaker/xml/status.rb', line 122

def node_status
  return @node_status_structure if @node_status_structure
  @node_status_structure = {}
  cib_section_node_state.each do |node_state|
    node = attributes_to_hash node_state
    node_name = node['uname']
    next unless node_name
    lrm = node_state.elements['lrm']
    next unless lrm
    lrm_resources = cib_section_lrm_resources lrm
    next unless lrm_resources
    resources = decode_lrm_resources lrm_resources, node_name
    node.store 'primitives', resources
    @node_status_structure.store node_name, node
  end
  @node_status_structure
end

#operation_status(op) ⇒ 'start', ...

determine the status of a single operation

Parameters:

  • op (Hash<String => String>)

Returns:

  • ('start', 'stop', 'master', nil)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pacemaker/xml/status.rb', line 32

def operation_status(op)
  # skip pendings ops
  # we should waqit until status becomes known
  return if op['op-status'] == '-1'

  if op['operation'] == 'monitor'
    # for monitor operation status is determined by its rc-code
    # 0 - start, 8 - master, 7 - stop, else - error
    case op['rc-code']
      when '0'
        'start'
      when '7'
        'stop'
      when '8'
        'master'
      else
        # not entirely correct but count failed monitor as 'stop'
        'stop'
    end
  elsif %w(start stop promote demote).include? op['operation']
    # if the operation was not successful the status is unknown
    # it will be determined by the next monitor
    # if Pacemaker is unable to bring the resource to a known state
    # it can use STONITH on this node if it's configured
    return unless op['rc-code'] == '0'
    # for a successful start/stop/promote/demote operations
    # we use use master instead of promote and start instead of demote
    if op['operation'] == 'promote'
      'master'
    elsif op['operation'] == 'demote'
      'start'
    else
      op['operation']
    end
  end
end

#primitive_has_failures?(primitive, node = nil) ⇒ TrueClass, FalseClass

does this primitive have failed operations?

Parameters:

  • primitive (String)

    primitive name

  • node (String) (defaults to: nil)

    on this node if given

Returns:

  • (TrueClass, FalseClass)


201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/pacemaker/xml/status.rb', line 201

def primitive_has_failures?(primitive, node = nil)
  return unless primitive_exists? primitive
  if node
    node_status
        .fetch(node, {})
        .fetch('primitives', {})
        .fetch(primitive, {})
        .fetch('failed', nil)
  else
    node_status.each do |_k, v|
      failed = v.fetch('primitives', {})
                   .fetch(primitive, {})
                   .fetch('failed', nil)
      return true if failed
    end
    false
  end
end

#primitive_has_master_running?(primitive, node = nil) ⇒ TrueClass, FalseClass

check if primitive is running as a master either anywhere or on the give node

Parameters:

  • primitive (String)

    primitive id

  • node (String) (defaults to: nil)

    on this node if given

Returns:

  • (TrueClass, FalseClass)


237
238
239
240
241
242
243
# File 'lib/pacemaker/xml/status.rb', line 237

def primitive_has_master_running?(primitive, node = nil)
  is_master = primitive_is_master? primitive
  return is_master unless is_master
  status = primitive_status primitive, node
  return status unless status
  status == 'master'
end

#primitive_has_status_on(primitive, expected_status = 'start') ⇒ Array<String>

Get the list on node names where this primitive has the specified status.

Parameters:

  • primitive (String)
  • expected_status (String, Symbol) (defaults to: 'start')

    (stop/start/master)

Returns:

  • (Array<String>)

    The array of node names where the primitive has this status



267
268
269
270
271
272
273
274
# File 'lib/pacemaker/xml/status.rb', line 267

def primitive_has_status_on(primitive, expected_status = 'start')
  expected_status = expected_status.to_s.downcase
  primitive_status_by_node = primitives_status_by_node[primitive]
  primitive_status_by_node.inject([]) do |found_nodes, node_and_status|
    next found_nodes unless node_and_status.last == expected_status
    found_nodes << node_and_status.first
  end
end

#primitive_is_running?(primitive, node = nil) ⇒ TrueClass, FalseClass

determine if a primitive is running on the entire cluster of on a node if node name param given

Parameters:

  • primitive (String)

    primitive id

  • node (String) (defaults to: nil)

    on this node if given

Returns:

  • (TrueClass, FalseClass)


225
226
227
228
229
230
# File 'lib/pacemaker/xml/status.rb', line 225

def primitive_is_running?(primitive, node = nil)
  return unless primitive_exists? primitive
  status = primitive_status primitive, node
  return status unless status
  %w(start master).include? status
end

#primitive_status(primitive, node = nil) ⇒ String

get a status of a primitive on the entire cluster of on a node if node name param given

Parameters:

  • primitive (String)
  • node (String) (defaults to: nil)

Returns:

  • (String)


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/pacemaker/xml/status.rb', line 170

def primitive_status(primitive, node = nil)
  if node
    node_status
        .fetch(node, {})
        .fetch('primitives', {})
        .fetch(primitive, {})
        .fetch('status', nil)
  else
    statuses = []
    node_status.each do |_node_name, node_status|
      status = node_status.fetch('primitives', {})
                   .fetch(primitive, {})
                   .fetch('status', nil)
      statuses << status
    end
    status_values = {
        'stop' => 0,
        'start' => 1,
        'master' => 2,
    }
    statuses.max_by do |status|
      return nil unless status
      status_values[status]
    end
  end
end

#primitives_status_by_nodeHash

generate the report of primitive statuses by node

Returns:

  • (Hash)


247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/pacemaker/xml/status.rb', line 247

def primitives_status_by_node
  report = {}
  return unless node_status.is_a? Hash
  node_status.each do |node_name, node_data|
    primitives_of_node = node_data['primitives']
    next unless primitives_of_node.is_a? Hash
    primitives_of_node.each do |primitive, primitive_data|
      primitive_status = primitive_data['status']
      report[primitive] = {} unless report[primitive].is_a? Hash
      report[primitive][node_name] = primitive_status
    end
  end
  report
end