-
-
Notifications
You must be signed in to change notification settings - Fork 75
/
volume.pp
281 lines (255 loc) · 9.83 KB
/
volume.pp
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
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# @summary Create GlusterFS volumes, and maybe extend them
#
# @param ensure
# whether volume should be created ('present') or removed ('absent')
# @param stripe
# the stripe count to use for a striped volume
# @param replica
# the replica count to use for a replica volume
# @param arbiter
# the arbiter count to use for a replica volume
# @param transport
# the transport to use. Defaults to tcp
# @param rebalance
# whether to rebalance a volume when new bricks are added
# @param heal
# whether to heal a replica volume when adding bricks
# @param bricks
# an array of bricks to use for this volume
# @param options
# an array of volume options for the volume
# @param remove_options
# whether to permit the removal of active options that are not defined for
# this volume.
#
# @see https://github.com/gluster/glusterfs/blob/master/doc/admin-guide/en-US/markdown/admin_managing_volumes.md#tuning-options
#
# @example
# gluster::volume { 'storage1':
# replica => 2,
# bricks => [
# 'srv1.local:/export/brick1/brick',
# 'srv2.local:/export/brick1/brick',
# 'srv1.local:/export/brick2/brick',
# 'srv2.local:/export/brick2/brick',
# ],
# options => [
# 'server.allow-insecure: on',
# 'nfs.ports-insecure: on',
# ],
# }
#
# @author Scott Merrill <smerrill@covermymeds.com>
# @note Copyright 2014 CoverMyMeds, unless otherwise noted
#
define gluster::volume (
Array[String, 1] $bricks,
Enum['present', 'absent'] $ensure = 'present',
Boolean $force = false,
Enum['tcp', 'rdma', 'tcp,rdma'] $transport = 'tcp',
Boolean $rebalance = true,
Boolean $heal = true,
Boolean $remove_options = false,
Optional[Array] $options = undef,
Optional[Integer] $stripe = undef,
Optional[Integer] $replica = undef,
Optional[Integer] $arbiter = undef,
) {
$_force = if $force {
'force'
} else {
''
}
if $stripe {
$_stripe = "stripe ${stripe}"
} else {
$_stripe = ''
}
$_replica = if $replica {
"replica ${replica}"
} else {
''
}
$_transport = "transport ${transport}"
if $options and ! empty( $options ) {
$_options = sort( $options )
} else {
$_options = undef
}
if $arbiter {
$_arbiter = "arbiter ${arbiter}"
} else {
$_arbiter = ''
}
$_bricks = join( $bricks, ' ' )
$cmd_args = [
$_stripe,
$_replica,
$_arbiter,
$_transport,
$_bricks,
$_force,
]
$args = join(delete($cmd_args, ''), ' ')
if getvar('gluster_binary') {
# we need the Gluster binary to do anything!
if $facts['gluster_volume_list'] and member( split( $facts['gluster_volume_list'], ',' ), $title ) {
$already_exists = true
} else {
$already_exists = false
}
if $already_exists == false {
# this volume has not yet been created
# nothing to do if volume does not exist and it should be absent
if $ensure == 'present' {
exec { "gluster create volume ${title}":
command => "${facts['gluster_binary']} volume create ${title} ${args}",
}
# if we have volume options, activate them now
#
# Note: $options is an array, but create_resources requires
# a hash of hashes. We do some contortions to get the
# array into the hash of hashes that looks like:
#
# option.name:
# value: value
#
# Note 2: we're using the $_options variable, which contains the
# sorted list of options.
if $_options {
# first we need to prefix each array element with the volume name
# so that we match the gluster::volume::option title format of
# volume:option
$vol_opts = prefix( $_options, "${title}:" )
# now we make some YAML, and then parse that to get a Puppet hash
$yaml = join( regsubst( $vol_opts, ': ', ":\n value: ", 'G'), "\n")
$hoh = parseyaml($yaml)
# safety check
assert_type(Hash, $hoh)
# we need to ensure that these are applied AFTER the volume is created
# but BEFORE the volume is started
$new_volume_defaults = {
require => Exec["gluster create volume ${title}"],
before => Exec["gluster start volume ${title}"],
}
create_resources(::gluster::volume::option, $hoh, $new_volume_defaults)
}
# don't forget to start the new volume!
exec { "gluster start volume ${title}":
command => "${facts['gluster_binary']} volume start ${title}",
require => Exec["gluster create volume ${title}"],
}
}
} elsif $already_exists and "gluster_volume_${title}_bricks" in $facts {
# this volume exists
if $ensure == 'present' {
# our fact lists bricks comma-separated, but we need an array
$vol_bricks = split( $facts["gluster_volume_${title}_bricks"], ',')
if $bricks != $vol_bricks {
# this resource's list of bricks does not match the existing
# volume's list of bricks
$new_bricks = difference($bricks, $vol_bricks)
$vol_count = count($vol_bricks)
if count($bricks) > $vol_count {
# adding bricks
# if we have a stripe or replica volume, make sure the
# number of bricks to add is a factor of that value
if $stripe {
if ( count($new_bricks) % $stripe ) != 0 {
fail("Number of bricks to add is not a multiple of stripe count ${stripe}")
}
$s = "stripe ${stripe}"
} else {
$s = ''
}
if $replica {
if $arbiter and $arbiter != 0 {
$r = "replica ${replica} arbiter ${arbiter}"
} else {
if ( count($bricks) % $replica ) != 0 {
fail("Number of bricks to add is not a multiple of replica count ${replica}")
}
$r = "replica ${replica}"
}
} else {
$r = ''
}
$new_bricks_list = join($new_bricks, ' ')
exec { "gluster add bricks to ${title}":
command => "${facts['gluster_binary']} volume add-brick ${title} ${s} ${r} ${new_bricks_list} ${_force}",
}
if $rebalance {
exec { "gluster rebalance ${title}":
command => "${facts['gluster_binary']} volume rebalance ${title} start",
require => Exec["gluster add bricks to ${title}"],
}
}
if $replica and $heal {
# there is a delay after which a brick is added before
# the self heal daemon comes back to life.
# as such, we sleep 5 here before starting the heal
exec { "gluster heal ${title}":
command => "/bin/sleep 5; ${facts['gluster_binary']} volume heal ${title} full",
require => Exec["gluster add bricks to ${title}"],
}
}
} elsif count($bricks) < $vol_count {
# removing bricks
notice("removing bricks is not currently supported.\nDefined: ${_bricks}\nCurrent: ${vol_bricks}")
} else {
notice("unable to resolve brick changes for Gluster volume ${title}!\nDefined: ${_bricks}\nCurrent: ${vol_bricks}")
}
}
# did the options change?
$current_options_hash = pick(fact("gluster_volumes.${title}.options"), {})
$_current = sort(join_keys_to_values($current_options_hash, ': '))
if $_current != $_options {
#
# either of $current_options or $_options may be empty.
# we need to account for this situation
#
if $_current =~ Array and $_options =~ Array {
$to_remove = difference($_current, $_options)
$to_add = difference($_options, $_current)
} else {
if $_current =~ Array {
# $_options is not an array, so remove all currently set options
$to_remove = $_current
} elsif $_options =~ Array {
# $current_options is not an array, so add all our defined options
$to_add = $_options
}
}
if ! empty($to_remove) {
# we have some options active that are not defined here. Remove them
#
# the syntax to remove gluster::volume::options is a little different
# so build up the hash correctly
#
$remove_opts = prefix( $to_remove, "${title}:" )
$remove_yaml = join( regsubst( $remove_opts, ': .+$', ":\n ensure: absent", 'G' ), "\n" )
$remove = parseyaml($remove_yaml)
if $remove_options {
create_resources( gluster::volume::option, $remove )
} else {
$remove_str = join( keys($remove), ', ' )
notice("NOT REMOVING the following options for volume ${title}: ${remove_str}.")
}
}
if ! empty($to_add) {
# we have some options defined that are not active. Add them
$add_opts = prefix( $to_add, "${title}:" )
$add_yaml = join( regsubst( $add_opts, ': ', ":\n value: ", 'G' ), "\n" )
$add = parseyaml($add_yaml)
create_resources( gluster::volume::option, $add )
}
}
} else {
# stop and remove volume
exec { "gluster stop and remove ${title}":
command => "/bin/yes | ( ${facts['gluster_binary']} volume stop ${title} force && ${facts['gluster_binary']} volume delete ${title} )",
}
}
}
}
}