Puppet Function: pacemaker_cluster_nodes

Defined in:
lib/puppet/parser/functions/pacemaker_cluster_nodes.rb
Function type:
Ruby 3.x API

Overview

pacemaker_cluster_nodes()Any

Convert different forms of node list to the required form.

Input data can be:

  • String ‘n1 n2a,n2b n3’

  • Array [‘n1’, [‘n2a’,‘n2b’], ‘n3’]

  • Hash { ‘name’ => ‘n1’, ‘ring0’ => ‘192.168.0.1’ }

Hash can have optional keys: name, id, ip, votes,

Node id will be autogenerated unless id key is provided.

Internal nodes structure example:

```
[
  {
    name: 'node1',
    id: '1',
    votes: '2',
    ring0: '192.168.0.1',
    ring1: '172.16.0.1',
  },
  {
    name: 'node2',
    id: '2',
    votes: '1',
    ring0: '192.168.0.2',
    ring1: '172.16.0.2',
  },
  {
    name: 'node3',
    id: '3',
    votes: '1',
    ring0: '192.168.0.3',
    ring1: '172.16.0.3',
  }
]
# All fields except at least one ring address are optional
```

If neither ‘ring0’ nor ‘ring1’ are found fields ‘ip’ and ‘name’ will be used.

Output forms:

  • hash - output the hash of the node ids and their data (used for corosync config template)

  • list - output the space ad comma separated nodes and interfaces (used for “pcs cluster setup”)

  • array - output the plain array of nodes (used for pacemaker_auth or “pcs cluster auth”)

Returns:

  • (Any)


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/puppet/parser/functions/pacemaker_cluster_nodes.rb', line 2

newfunction(
    :pacemaker_cluster_nodes,
    type: :rvalue,
    arity: -2,
    doc: <<-eof
Convert different forms of node list to the required form.

Input data can be:
* String 'n1 n2a,n2b n3'
* Array ['n1', ['n2a','n2b'], 'n3']
* Hash { 'name' => 'n1', 'ring0' => '192.168.0.1' }

Hash can have optional keys: name, id, ip, votes,

Node id will be autogenerated unless id key is provided.

Internal nodes structure example:
```
[
  {
    name: 'node1',
    id: '1',
    votes: '2',
    ring0: '192.168.0.1',
    ring1: '172.16.0.1',
  },
  {
    name: 'node2',
    id: '2',
    votes: '1',
    ring0: '192.168.0.2',
    ring1: '172.16.0.2',
  },
  {
    name: 'node3',
    id: '3',
    votes: '1',
    ring0: '192.168.0.3',
    ring1: '172.16.0.3',
  }
]
# All fields except at least one ring address are optional
```

If neither 'ring0' nor 'ring1' are found fields 'ip' and 'name' will be used.

Output forms:
* hash - output the hash of the node ids and their data (used for corosync config template)
* list - output the space ad comma separated nodes and interfaces (used for "pcs cluster setup")
* array - output the plain array of nodes (used for pacemaker_auth or "pcs cluster auth")
    eof
) do |args|
  nodes = args[0]
  form = args[1] || 'hash'
  form = form.to_s.downcase
  raise(Puppet::Error, 'Nodes are not provided!') if [String, Hash, Array].include? nodes.class and nodes.empty?
  forms = %w(list array hash)
  raise(Puppet::Error, "Unknown form: '#{form}'") unless forms.include? form

  array_formatter = lambda do |structure|
    list = []
    structure.each do |node|
      next unless node.is_a? Hash
      list << node['ring0'] if node['ring0']
      list << node['ring1'] if node['ring1']
    end
    list.flatten.compact.uniq
  end

  list_formatter = lambda do |structure|
    list = []
    structure.each do |node|
      node_rings = []
      node_rings[0] = node['ring0'] if node['ring0']
      node_rings[1] = node['ring1'] if node['ring1']
      list << node_rings.join(',')
    end
    list.join ' '
  end

  hash_formatter = lambda do |structure|
    hash = {}
    structure.each do |node|
      id = node['id']
      next unless id
      hash[id] = node
    end
    hash
  end

  node_split_to_rings = lambda do |node|
    node = node.to_s.chomp.strip
    rings = node.split ','
    node_hash = {}
    node_hash['ring0'] = rings[0].to_s if rings[0] and rings[0] != ''
    node_hash['ring1'] = rings[1].to_s if rings[1] and rings[1] != ''
    node_hash
  end

  node_hash_process = lambda do |node|
    ring0 = node['ring0']
    ring1 = node['ring1']
    ring0 = node['ip'] if node['ip'] and not ring0
    ring0 = node['name'] if node['name'] and not ring0
    node_hash = {}
    node_hash['ring0'] = ring0.to_s if ring0
    node_hash['ring1'] = ring1.to_s if ring1
    node_hash['name'] = node['name'].to_s if node['name']
    node_hash['id'] = node['id'].to_s if node['id']
    node_hash['vote'] = node['vote'].to_s if node['vote']
    node_hash
  end

  string_parser = lambda do |string|
    string = string.to_s.chomp.strip
    node_list = []
    string.split.each do |node|
      node_hash = node_split_to_rings.call node
      next unless node_hash['ring0'] or node_hash['ring1']
      node_list << node_hash
    end
    node_list
  end

  array_parser = lambda do |array|
    array = [array] unless array.is_a? Array
    node_list = []
    array.each do |node|
      if node.is_a? Array
        node_hash = {}
        node_hash['ring0'] = node[0].to_s if node[0]
        node_hash['ring1'] = node[1].to_s if node[1]
      elsif node.is_a? Hash
        node_hash = node_hash_process.call node
      else
        node_hash = node_split_to_rings.call node.to_s
      end
      next unless node_hash['ring0'] or node_hash['ring1']
      node_list << node_hash
    end
    node_list
  end

  hash_parser = lambda do |hash|
    raise(Puppet::Error, "Data is not a hash: #{hash.inspect}") unless hash.is_a? Hash
    node_list = []
    hash.each do |node_name, node|
      node = node.dup
      node['name'] = node_name if node_name and not node['name']
      node_hash = node_hash_process.call node
      next unless node_hash['ring0'] or node_hash['ring1']
      node_list << node_hash
    end
    node_list
  end

  set_node_ids = lambda do |structure|
    next_id = 1
    structure.each do |node|
      unless node['id']
        node['id'] = next_id.to_s
        next_id += 1
      end
    end
  end

  structure = []

  if nodes.is_a? String
    structure = string_parser.call nodes
  elsif nodes.is_a? Array
    structure = array_parser.call nodes
  elsif nodes.is_a? Hash
    structure = hash_parser.call nodes
  else
    raise(Puppet::Error, "Got unsupported nodes input data: #{nodes.inspect}")
  end

  set_node_ids.call structure

  if form == 'hash'
    hash_formatter.call structure
  elsif form == 'list'
    list_formatter.call structure
  elsif form == 'array'
    array_formatter.call structure
  end

end