1
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
|
# GlusterFS module by James
# Copyright (C) 2010-2013+ James Shubin
# Written by James Shubin <james@shubin.ca>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
module Puppet::Parser::Functions
newfunction(:brick_layout_chained, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Return the complex chained brick list
Example:
$layout = brick_layout_chained($replica, $bricks)
notice("layout is: ${layout}")
This function is used internally for automatic brick layouts.
ENDHEREDOC
Puppet::Parser::Functions.function('warning') # load function
# signature: replica, bricks -> bricks
unless args.length == 2
raise Puppet::ParseError, "brick_layout_chained(): wrong number of arguments (#{args.length}; must be 2)"
end
if not(args[0].is_a?(Integer)) and not(args[0].is_a?(String))
# NOTE: strings that convert to int's with .to_i are ok
raise Puppet::ParseError, "brick_layout_chained(): expects the first argument to be an integer, got #{args[0].inspect} which is of type #{args[0].class}"
end
unless args[1].is_a?(Array)
raise Puppet::ParseError, "brick_layout_chained(): expects the second argument to be an array, got #{args[1].inspect} which is of type #{args[1].class}"
end
replica = args[0].to_i # convert from string if needed
bricks = args[1]
# TODO: these functions could be in separate puppet files
# eg: Puppet::Parser::Functions.function('myfunc')
# function_myfunc(...)
def brick_str_to_hash(bricks)
# this loop converts brick strings to brick dict's...
result = []
bricks.each do |x|
a = x.split(':')
#assert a.length == 2 # TODO
p = a[1]
p = ((p[-1, 1] == '/') ? p : (p+'/')) # endswith
result.push({'host'=> a[0], 'path'=> p})
end
return result
end
def get_hostlist(bricks)
hosts = []
bricks.each do |x|
key = x['host']
val = x['path']
if not hosts.include?(key)
hosts.push(key)
end
end
return hosts
end
def get_brickstacks(bricks, sort=false)
stacks = {}
hosts = get_hostlist(bricks)
bricks.each do |x|
key = x['host']
val = x['path']
if not stacks.include?(key); stacks[key] = []; end # initialize
stacks[key].push(val)
end
# optionally sort the paths in each individual host stack...
if sort
sorted_stacks = {}
stacks.each do |k, v|
# TODO: there should probably be a proper 'sorted' function for
# paths, in case they aren't numbered sanely _WITH_ padding.
sorted_stacks[k] = v.sort
end
return sorted_stacks
end
return stacks
end
final = []
pointer = 0
parsed = brick_str_to_hash(bricks)
# TODO: there should probably be a proper 'sorted' function for
# hostnames, in case they aren't numbered sanely _WITH_ padding.
hosts = get_hostlist(parsed).sort
brickstack = get_brickstacks(parsed, sort=true)
if bricks.length == 0; return []; end
# FIXME: this works with homogeneous volumes only!
while pointer < (hosts.length * brickstack[hosts[0]].length) do
start = hosts[pointer % hosts.length]
#puts "host is #{host}, pointer is: #{pointer}"
index = 0
while index < replica do
host = hosts[(pointer+index) % hosts.length]
#puts "host is #{host}, index is: #{index}"
index+= 1
path = brickstack[host].shift # yoink
if path.nil?
function_warning(["brick_layout_chained(): brick list is not valid"])
next
end
final.push({'host' => host, 'path' => path}) # save
end
pointer+=1
end
# build final result
result = final.collect {|x| x['host']+':'+x['path'] }
result # return
end
end
# vim: ts=8
|