diff --git a/manifests/volume.pp b/manifests/volume.pp index 5344067a..09c955d8 100644 --- a/manifests/volume.pp +++ b/manifests/volume.pp @@ -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 @@ -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, @@ -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} )", } } }