Skip to content

Commit

Permalink
Merge pull request #219 from glorpen/ensure_volume
Browse files Browse the repository at this point in the history
Make volume ensurable
  • Loading branch information
ekohl authored Aug 28, 2020
2 parents b78e9f3 + 48ea44c commit ae43a34
Showing 1 changed file with 136 additions and 123 deletions.
259 changes: 136 additions & 123 deletions manifests/volume.pp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @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
Expand Down Expand Up @@ -43,6 +45,7 @@
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,
Expand Down Expand Up @@ -110,157 +113,167 @@
if $already_exists == false {
# this volume has not yet been created

exec { "gluster create volume ${title}":
command => "${::gluster_binary} volume create ${title} ${args}",
}
# nothing to do if volume does not exist and it should be absent
if $ensure == 'present' {
exec { "gluster create volume ${title}":
command => "${::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)
# 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}"],
}
# 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)
}
create_resources(::gluster::volume::option, $hoh, $new_volume_defaults)
}

# don't forget to start the new volume!
exec { "gluster start volume ${title}":
command => "${::gluster_binary} volume start ${title}",
require => Exec["gluster create volume ${title}"],
# don't forget to start the new volume!
exec { "gluster start volume ${title}":
command => "${::gluster_binary} volume start ${title}",
require => Exec["gluster create volume ${title}"],
}
}
} elsif $already_exists {
# this volume exists

# our fact lists bricks comma-separated, but we need an array
$vol_bricks = split( getvar( "::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)
if $ensure == 'present' {
# our fact lists bricks comma-separated, but we need an array
$vol_bricks = split( getvar( "::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
$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}")
# 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 = ''
}
$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}")
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}"
}
$r = "replica ${replica}"
} else {
$r = ''
}
} else {
$r = ''
}

$new_bricks_list = join($new_bricks, ' ')
exec { "gluster add bricks to ${title}":
command => "${::gluster_binary} volume add-brick ${title} ${s} ${r} ${new_bricks_list} ${_force}",
}
$new_bricks_list = join($new_bricks, ' ')
exec { "gluster add bricks to ${title}":
command => "${::gluster_binary} volume add-brick ${title} ${s} ${r} ${new_bricks_list} ${_force}",
}

if $rebalance {
exec { "gluster rebalance ${title}":
command => "${::gluster_binary} volume rebalance ${title} start",
require => Exec["gluster add bricks to ${title}"],
if $rebalance {
exec { "gluster rebalance ${title}":
command => "${::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; ${::gluster_binary} volume heal ${title} full",
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; ${::gluster_binary} volume heal ${title} full",
require => Exec["gluster add bricks to ${title}"],
}
}
} elsif count($bricks) < $vol_count {
# removing bricks
notify { 'removing bricks is not currently supported.': }
} else {
notify { "unable to resolve brick changes for Gluster volume ${title}!\nDefined: ${_bricks}\nCurrent: ${vol_bricks}": }
}
} elsif count($bricks) < $vol_count {
# removing bricks
notify { 'removing bricks is not currently supported.': }
} else {
notify { "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, ': '))
# 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 is_array($_current) and is_array($_options) {
$to_remove = difference($_current, $_options)
$to_add = difference($_options, $_current)
} else {
if is_array($_current) {
# $_options is not an array, so remove all currently set options
$to_remove = $_current
} elsif is_array($_options) {
# $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
if $_current != $_options {
#
# the syntax to remove ::gluster::volume::options is a little different
# so build up the hash correctly
# either of $current_options or $_options may be empty.
# we need to account for this situation
#
$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 )
if is_array($_current) and is_array($_options) {
$to_remove = difference($_current, $_options)
$to_add = difference($_options, $_current)
} else {
$remove_str = join( keys($remove), ', ' )
notice("NOT REMOVING the following options for volume ${title}: ${remove_str}.")
if is_array($_current) {
# $_options is not an array, so remove all currently set options
$to_remove = $_current
} elsif is_array($_options) {
# $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 )
}
}
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 | ( ${::gluster_binary} volume stop ${title} force && ${::gluster_binary} volume delete ${title} )",
}
}
}
Expand Down

0 comments on commit ae43a34

Please sign in to comment.