summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Shubin <james@shubin.ca>2014-03-13 11:45:26 -0400
committerJames Shubin <james@shubin.ca>2014-03-16 22:39:08 -0400
commitc7a6ef2c0267540ab2b272872648476255557dc6 (patch)
treefb8c109ded939d3092bccc91a0456f4e92e62d46
parent05576cd410bb2616ce72e3e9e24850f911cbb6dc (diff)
downloadpuppet-gluster-c7a6ef2c0267540ab2b272872648476255557dc6.tar.gz
puppet-gluster-c7a6ef2c0267540ab2b272872648476255557dc6.tar.xz
puppet-gluster-c7a6ef2c0267540ab2b272872648476255557dc6.zip
Add automatic generation of fs UUID's per brick filesystem.
This automatically generates UUID's for each physical filesystem, or alternatively, you can specify one manually with the $fsuuid argument. This will make a _big_ difference when using gluster::simple to automatically deploy a large cluster of physical machines, since you don't have to manually generate one uuid per device (which is time consuming and could be a lot to do and a lot to maintain).
-rw-r--r--lib/facter/gluster_fsuuid.rb144
-rw-r--r--manifests/brick.pp91
-rw-r--r--manifests/brick/base.pp9
3 files changed, 224 insertions, 20 deletions
diff --git a/lib/facter/gluster_fsuuid.rb b/lib/facter/gluster_fsuuid.rb
new file mode 100644
index 0000000..4ed48dc
--- /dev/null
+++ b/lib/facter/gluster_fsuuid.rb
@@ -0,0 +1,144 @@
+# 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/>.
+
+require 'facter'
+require 'digest/sha1'
+
+# TODO: the ruby uuid method can be used when newer ruby versions are used here
+# require 'securerandom'
+# SecureRandom.uuid
+
+# uuid regexp
+regexp = /^[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}$/
+fqdn = Facter.value('fqdn') # this could be nil !
+
+# find the module_vardir
+dir = Facter.value('puppet_vardirtmp') # nil if missing
+if dir.nil? # let puppet decide if present!
+ dir = Facter.value('puppet_vardir')
+ if dir.nil?
+ var = nil
+ else
+ var = dir.gsub(/\/$/, '')+'/'+'tmp/' # ensure trailing slash
+ end
+else
+ var = dir.gsub(/\/$/, '')+'/'
+end
+
+if var.nil?
+ # if we can't get a valid vardirtmp, then we can't continue
+ module_vardir = nil
+ valid_brickdir = nil
+ uuiddir = nil
+else
+ module_vardir = var+'gluster/'
+ valid_brickdir = module_vardir.gsub(/\/$/, '')+'/brick/'
+ uuiddir = valid_brickdir+'fsuuid/' # safe dir that won't get purged...
+end
+
+# NOTE: module specific mkdirs, needed to ensure there is no blocking/deadlock!
+if not(var.nil?) and not File.directory?(var)
+ Dir::mkdir(var)
+end
+
+if not(module_vardir.nil?) and not File.directory?(module_vardir)
+ Dir::mkdir(module_vardir)
+end
+
+found = {}
+
+# generate uuid and parent directory if they don't already exist...
+if not(module_vardir.nil?) and File.directory?(module_vardir)
+ if not File.directory?(uuiddir)
+ Dir::mkdir(uuiddir)
+ end
+
+ # loop through brick dir, looking for brick names to make fsuuid's for!
+ if not(valid_brickdir.nil?) and File.directory?(valid_brickdir) and File.directory?(uuiddir)
+ Dir.glob(valid_brickdir+'*.*').each do |f|
+ b = File.basename(f)
+ g = b.split('.') # $name.group
+
+ group = g.pop() # pop off suffix (the group name)
+
+ if g.length >= 1
+ # NOTE: some of this code is unnecessary, but i
+ # kept it because it matches the brick parsing.
+
+ x = g.join('.') # in case value had dots in it.
+
+ brick = File.open(f, 'r').read.strip # read into str
+ # eg: annex1.example.com:/storage1a
+ split = brick.split(':') # do some $name parsing
+ host = split[0] # host fqdn
+ # NOTE: technically $path should be everything BUT split[0]. This
+ # lets our $path include colons if for some reason they're needed.
+ #path = split[1] # brick mount or storage path
+ path = brick.slice(host.length+1, brick.length-host.length-1)
+
+ # if fqdn is nil, generate for everyone...
+ # (other hosts data will just be unused...)
+ if not(fqdn.nil?)
+ # otherwise, skip hosts that aren't us!
+ if host != fqdn
+ next
+ end
+ end
+
+ uuidfile = uuiddir + b
+ # we sha1 to prevent weird characters in facter
+ key = Digest::SHA1.hexdigest(host + ':' + path + '.' + group)
+
+ # create an fsuuid for each brick and store it
+ # in our vardir if it doesn't already exist...
+ if not File.exist?(uuidfile)
+ result = system("/usr/bin/uuidgen > '" + uuidfile + "'")
+ if not(result)
+ # TODO: print warning
+ end
+ end
+
+ # create facts from all the uuid files found...
+ uuid = File.open(uuidfile, 'r').read.strip.downcase # read into str
+ if uuid.length == 36 and regexp.match(uuid)
+ # avoid: http://projects.puppetlabs.com/issues/22455
+ found[key] = uuid
+ # TODO: print warning on else...
+ end
+ end
+ end
+ end
+end
+
+found.keys.each do |x|
+ Facter.add('gluster_brick_fsuuid_'+x) do
+ #confine :operatingsystem => %w{CentOS, RedHat, Fedora}
+ setcode {
+ found[x]
+ }
+ end
+end
+
+# list of generated gluster_brick_fsuuid's
+Facter.add('gluster_brick_fsuuid_facts') do
+ #confine :operatingsystem => %w{CentOS, RedHat, Fedora}
+ setcode {
+ found.keys.collect {|x| 'gluster_brick_fsuuid_'+x }.join(',')
+ }
+end
+
+# vim: ts=8
diff --git a/manifests/brick.pp b/manifests/brick.pp
index d753d5f..a44ce2e 100644
--- a/manifests/brick.pp
+++ b/manifests/brick.pp
@@ -39,6 +39,7 @@ define gluster::brick(
$comment = ''
) {
include gluster::brick::base
+ include gluster::again
include gluster::vardir
#$vardir = $::gluster::vardir::module_vardir # with trailing slash
@@ -73,6 +74,42 @@ define gluster::brick(
}
#
+ # fsuuid...
+ #
+ if ("${fsuuid}" != '') and "${fsuuid}" =~ /^[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}$/ {
+ fail("The chosen fs uuid: '${fsuuid}' is not valid.")
+ }
+
+ # if we manually *pick* a uuid, then store it too, so that it
+ # sticks if we ever go back to using automatic uuids. this is
+ # useful if a user wants to initially import uuids by picking
+ # them manually, and then letting puppet take over afterwards
+ if "${fsuuid}" != '' {
+ # $group is unnecessary, but i left it in for consistency...
+ file { "${vardir}/brick/fsuuid/${safename}.${group}":
+ content => "${fsuuid}\n",
+ owner => root,
+ group => root,
+ mode => 600, # might as well...
+ ensure => present,
+ require => File["${vardir}/brick/fsuuid/"],
+ }
+ }
+
+ # we sha1 to prevent weird characters in facter
+ $fsuuid_safename = sha1("${name}.${group}")
+ $valid_fsuuid = "${fsuuid}" ? {
+ # fact from the data generated in: ${vardir}/brick/fsuuid/*
+ '' => getvar("gluster_brick_fsuuid_${fsuuid_safename}"), # fact!
+ default => "${fsuuid}",
+ }
+
+ # you might see this on first run if the fsuuid isn't generated yet
+ if (type($dev) != 'boolean') and ("${valid_fsuuid}" == '') {
+ warning('An $fsuuid must be specified or generated.')
+ }
+
+ #
# raid...
#
# TODO: check inputs for sanity and auto-detect if one is empty
@@ -218,7 +255,7 @@ define gluster::brick(
$xfs_cmd = join(delete($xfs_cmdlist, ''), ' ')
# TODO: xfs_admin doesn't have a --quiet flag. silence it...
- $xfs_admin = "/usr/sbin/xfs_admin -U '${fsuuid}' ${dev2}"
+ $xfs_admin = "/usr/sbin/xfs_admin -U '${valid_fsuuid}' ${dev2}"
# mkfs w/ uuid command
$mkfs_exec = "${xfs_cmd} && ${xfs_admin}"
@@ -257,7 +294,7 @@ define gluster::brick(
$exec_requires = [Package['e2fsprogs']]
# mkfs w/ uuid command
- $mkfs_exec = "/sbin/mkfs.${valid_fstype} -U '${fsuuid}' ${dev2}"
+ $mkfs_exec = "/sbin/mkfs.${valid_fstype} -U '${valid_fsuuid}' ${dev2}"
# mount options
$options_list = [] # TODO
@@ -340,7 +377,8 @@ define gluster::brick(
exec { "${lvm_lvcreate}":
logoutput => on_failure,
unless => [ # if one element is true, this *doesn't* run
- "/sbin/lvdisplay ${lvm_lvname}",
+ #"/sbin/lvdisplay ${lvm_lvname}", # nope!
+ "/sbin/lvs --separator ':' | /usr/bin/tr -d ' ' | /bin/awk -F ':' '{print \$1}' | /bin/grep -q '${lvm_lvname}'",
'/bin/false', # TODO: add more criteria
],
require => $exec_requires,
@@ -355,13 +393,24 @@ define gluster::brick(
notify { "noop for mkfs: ${name}":
message => "${mkfs_exec}",
}
+ } else {
+ # if valid_fsuuid isn't ready, trigger an exec again...
+ exec { "gluster-brick-fsuuid-execagain-${name}":
+ command => '/bin/true', # do nothing but notify
+ logoutput => on_failure,
+ onlyif => "/usr/bin/test -z '${valid_fsuuid}'",
+ notify => Common::Again::Delta['gluster-exec-again'],
+ # this (optional) require makes it more logical
+ require => File["${vardir}/brick/fsuuid/"],
+ }
}
# mkfs...
exec { "${mkfs_exec}":
logoutput => on_failure,
+ onlyif => "/usr/bin/test -n '${valid_fsuuid}'",
unless => [ # if one element is true, this *doesn't* run
- "/usr/bin/test -e /dev/disk/by-uuid/${fsuuid}",
+ "/usr/bin/test -e /dev/disk/by-uuid/${valid_fsuuid}",
'/bin/false', # TODO: add more criteria
],
require => $exec_requires,
@@ -380,22 +429,24 @@ define gluster::brick(
}
# mount points don't seem to like trailing slashes...
- mount { "${short_path}":
- atboot => true,
- ensure => mounted,
- device => "UUID=${fsuuid}",
- fstype => "${valid_fstype}",
- # noatime,nodiratime to save gluster from silly updates
- options => "${mount_options},${ro_bool},noatime,nodiratime,noexec", # TODO: is nodev? nosuid? noexec? a good idea?
- dump => '0', # fs_freq: 0 to skip file system dumps
- # NOTE: technically this should be '2', to `fsck.xfs`
- # after the rootfs ('1'), but fsck.xfs actually does
- # 'nothing, successfully', so it's irrelevant, because
- # xfs uses xfs_check and friends only when suspect.
- pass => '2', # fs_passno: 0 to skip fsck on boot
- require => [
- File["${valid_path}"],
- ],
+ if "${valid_fsuuid}" != '' { # in case fsuuid isn't ready yet
+ mount { "${short_path}":
+ atboot => true,
+ ensure => mounted,
+ device => "UUID=${valid_fsuuid}",
+ fstype => "${valid_fstype}",
+ # noatime,nodiratime to save gluster from silly updates
+ options => "${mount_options},${ro_bool},noatime,nodiratime,noexec", # TODO: is nodev? nosuid? noexec? a good idea?
+ dump => '0', # fs_freq: 0 to skip file system dumps
+ # NOTE: technically this should be '2', to `fsck.xfs`
+ # after the rootfs ('1'), but fsck.xfs actually does
+ # 'nothing, successfully', so it's irrelevant, because
+ # xfs uses xfs_check and friends only when suspect.
+ pass => '2', # fs_passno: 0 to skip fsck on boot
+ require => [
+ File["${valid_path}"],
+ ],
+ }
}
} elsif ((type($dev) == 'boolean') and (! $dev)) and ("${fqdn}" == "${host}") {
diff --git a/manifests/brick/base.pp b/manifests/brick/base.pp
index 83398e2..c39cb3f 100644
--- a/manifests/brick/base.pp
+++ b/manifests/brick/base.pp
@@ -28,5 +28,14 @@ class gluster::brick::base {
force => true, # don't purge subdirs and links
require => File["${vardir}/"],
}
+
+ # don't purge the fsuuid file's generated within
+ file { "${vardir}/brick/fsuuid/":
+ ensure => directory, # make sure this is a directory
+ recurse => false, # don't recurse into directory
+ purge => false, # don't purge unmanaged files
+ force => false, # don't purge subdirs and links
+ require => File["${vardir}/brick/"],
+ }
}
# vim: ts=8