From 51fea724f4b606326489636a0ffb7e9673600f9b Mon Sep 17 00:00:00 2001 From: James Shubin Date: Tue, 21 Jan 2014 05:02:58 -0500 Subject: Add client mounting and associated magic. * Rename gluster::client to gluster::mount * Add support to gluster::mount * Add client machines and mounts to vagrant setup * Fixed version interface for gluster::mount and gluster::server * Improved firewall support for gluster::mount * Update examples to use gluster::mount instead of gluster::client * Update documentation * Other small fixes --- manifests/client.pp | 79 ---------------------- manifests/client/base.pp | 53 --------------- manifests/mount.pp | 171 +++++++++++++++++++++++++++++++++++++++++++++++ manifests/mount/base.pp | 79 ++++++++++++++++++++++ manifests/repo.pp | 4 +- manifests/rulewrapper.pp | 47 +++++++++++++ manifests/server.pp | 35 +++------- manifests/volume.pp | 7 ++ 8 files changed, 317 insertions(+), 158 deletions(-) delete mode 100644 manifests/client.pp delete mode 100644 manifests/client/base.pp create mode 100644 manifests/mount.pp create mode 100644 manifests/mount/base.pp create mode 100644 manifests/rulewrapper.pp (limited to 'manifests') diff --git a/manifests/client.pp b/manifests/client.pp deleted file mode 100644 index 5ffe054..0000000 --- a/manifests/client.pp +++ /dev/null @@ -1,79 +0,0 @@ -# GlusterFS module by James -# Copyright (C) 2010-2013+ James Shubin -# Written by James Shubin -# -# 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 . - -# XXX: try mounting with: glusterfs --volfile-server= --volfile-id= --xlator-option='*dht*.assert-no-child-down=yes' # TODO: quotes or not? -define gluster::client( - $server, # NOTE: use a vip as server hostname - $rw = false, # mount read only (true) or rw (false) -# $suid = false, # mount with suid (true) or nosuid (false) # TODO: will this work with gluster ? - $mounted = true # useful if we want to pull in the group - # defs, but not actually mount (testing) -) { - #mount -t glusterfs brick1.example.com:/test /test - include gluster::client::base - - $rw_bool = $rw ? { - true => 'rw', - default => 'ro', - } - - # TODO: will this work with gluster ? - #$suid_bool = $suid ? { - # true => 'suid', - # default => 'nosuid', - #} - - $mounted_bool = $mounted ? { - true => mounted, - default => unmounted, - } - - # make an empty directory for the mount point - file { "${name}": - 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 - } - - # Mount Options: - # * backupvolfile-server=server-name - # * fetch-attempts=N (where N is number of attempts) - # * log-level=loglevel - # * log-file=logfile - # * direct-io-mode=[enable|disable] - # * ro (for readonly mounts) - # * acl (for enabling posix-ACLs) - # * worm (making the mount WORM - Write Once, Read Many type) - # * selinux (enable selinux on GlusterFS mount - mount { "${name}": - atboot => true, - ensure => $mounted_bool, - device => "${server}", - fstype => 'glusterfs', - options => "defaults,_netdev,${rw_bool}", # TODO: will $suid_bool work with gluster ? - dump => '0', # fs_freq: 0 to skip file system dumps - pass => '0', # fs_passno: 0 to skip fsck on boot - require => [ - Package[['glusterfs', 'glusterfs-fuse']], - File["${name}"], # the mountpoint - Exec['gluster-fuse'], # ensure fuse is loaded - ], - } -} - -# vim: ts=8 diff --git a/manifests/client/base.pp b/manifests/client/base.pp deleted file mode 100644 index 9ec232b..0000000 --- a/manifests/client/base.pp +++ /dev/null @@ -1,53 +0,0 @@ -# GlusterFS module by James -# Copyright (C) 2010-2013+ James Shubin -# Written by James Shubin -# -# 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 . - -class gluster::client::base { - # TODO: ensure these are from our 'gluster' repo - package { ['glusterfs', 'glusterfs-fuse']: - ensure => present, - } - - # FIXME: choose a reliable and correct way to ensure fuse is loaded - # dmesg | grep -i fuse - # modprobe fuse - # dmesg | grep -i fuse - #fuse init (API version 7.13) - # - - # modprobe fuse if it's missing - exec { '/sbin/modprobe fuse': - logoutput => on_failure, - onlyif => '/usr/bin/test -z "`/bin/dmesg | /bin/grep -i fuse`"', - alias => 'gluster-fuse', - } - #exec { '/sbin/modprobe fuse': - # logoutput => on_failure, - # unless => "/sbin/lsmod | /bin/grep -q '^fuse'", - # alias => 'gluster-modprobe-fuse', - #} - - # TODO: will this autoload the fuse module? - #file { '/etc/modprobe.d/fuse.conf': - # content => "fuse\n", # TODO: "install fuse /sbin/modprobe --ignore-install fuse ; /bin/true\n" ? - # owner => root, - # group => root, - # mode => 644, # u=rw,go=r - # ensure => present, - #} -} - -# vim: ts=8 diff --git a/manifests/mount.pp b/manifests/mount.pp new file mode 100644 index 0000000..27b6baa --- /dev/null +++ b/manifests/mount.pp @@ -0,0 +1,171 @@ +# GlusterFS module by James +# Copyright (C) 2010-2013+ James Shubin +# Written by James Shubin +# +# 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 . + +# XXX: try mounting with: glusterfs --volfile-server= --volfile-id= --xlator-option='*dht*.assert-no-child-down=yes' # TODO: quotes or not? +define gluster::mount( + $server, # NOTE: use a vip as server hostname + $rw = false, # mount read only (true) or rw (false) +# $suid = false, # mount with suid (true) or nosuid (false) # TODO: will this work with gluster ? + $mounted = true, # useful if we want to pull in the group + # defs, but not actually mount (testing) + $repo = true, # add a repo automatically? true or false + $version = '', # pick a specific version (defaults to latest) + $ip = '', # you can specify which ip address to use (if multiple) + $shorewall = false +) { + #mount -t glusterfs brick1.example.com:/test /test + #include gluster::mount::base + #class { '::gluster::mount::base': + # repo => $repo, + # version => $version, + #} + $params = { + 'repo' => $repo, + 'version' => $version, + } + # because multiple gluster::mount types are allowed on the same server, + # we include with the ensure_resource function to avoid identical calls + ensure_resource('class', '::gluster::mount::base', $params) + + # eg: vip:/volume + $split = split($server, ':') # do some $server parsing + $host = $split[0] # host fqdn or ip (eg: vip) + # 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] # volume + # TODO: create substring function + $path = inline_template("<%= '${server}'.slice('${host}'.length+1, '${server}'.length-'${host}'.length-1) %>") + $short_path = sprintf("%s", regsubst($path, '\/$', '')) # no trailing + #$valid_path = sprintf("%s/", regsubst($path, '\/$', '')) + $volume = sprintf("%s", regsubst($short_path, '^\/', '')) # no leading + + if ! ( "${host}:${path}" == "${server}" ) { + fail('The $server must match a $host:$path pattern.') + } + + if ! ( "${host}:/${volume}" == "${server}" ) { + fail('The $server must match a $host:/$volume pattern.') + } + + $short_name = sprintf("%s", regsubst("${name}", '\/$', '')) # no trailing + $long_name = sprintf("%s/", regsubst("${name}", '\/$', '')) # trailing... + + $valid_ip = "${ip}" ? { + '' => "${::gluster_host_ip}" ? { # smart fact... + '' => "${::ipaddress}", # puppet picks! + default => "${::gluster_host_ip}", # smart + }, + default => "${ip}", # user selected + } + if "${valid_ip}" == '' { + fail('No valid IP exists!') + } + + if $shorewall { + $safename = regsubst("${name}", '/', '_', 'G') # make /'s safe + @@shorewall::rule { "glusterd-management-${fqdn}-${safename}": + #@@shorewall::rule { "glusterd-management-${volume}-${fqdn}": + action => 'ACCEPT', + source => '', # override this on collect... + source_ips => ["${valid_ip}"], + dest => '$FW', + proto => 'tcp', + port => '24007', + comment => 'Allow incoming tcp:24007 from each glusterd.', + tag => 'gluster_firewall_management', + ensure => present, + } + + # wrap shorewall::rule in a fake type so that we can add $match + #@@shorewall::rule { "gluster-volume-${fqdn}-${safename}": + @@gluster::rulewrapper { "gluster-volume-${fqdn}-${safename}": + action => 'ACCEPT', + source => '', # override this on collect... + source_ips => ["${valid_ip}"], + dest => '$FW', + proto => 'tcp', + port => '', # override this on collect... + #comment => "${fqdn}", + comment => 'Allow incoming tcp port from glusterfsds.', + tag => 'gluster_firewall_volume', + match => "${volume}", # used for collection + ensure => present, + } + } + + $rw_bool = $rw ? { + true => 'rw', + default => 'ro', + } + + # TODO: will this work with gluster ? + #$suid_bool = $suid ? { + # true => 'suid', + # default => 'nosuid', + #} + + $mounted_bool = $mounted ? { + false => unmounted, + default => mounted, + } + + # ensure parent directories exist + exec { "gluster-mount-mkdir-${name}": + command => "/bin/mkdir -p '${long_name}'", + creates => "${long_name}", + logoutput => on_failure, + before => File["${long_name}"], + } + + # make an empty directory for the mount point + file { "${long_name}": # ensure a trailing slash + 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 + alias => "${short_name}", # don't allow duplicates name's + } + + # Mount Options: + # * backupvolfile-server=server-name + # * fetch-attempts=N (where N is number of attempts) + # * log-level=loglevel + # * log-file=logfile + # * direct-io-mode=[enable|disable] + # * ro (for readonly mounts) + # * acl (for enabling posix-ACLs) + # * worm (making the mount WORM - Write Once, Read Many type) + # * selinux (enable selinux on GlusterFS mount) + # XXX: consider mounting only if some exported resource, collected and turned into a fact shows that the volume is available... + # XXX: or something... consider adding the notify => Poke[] functionality + mount { "${short_name}": + atboot => true, + ensure => $mounted_bool, + device => "${server}", + fstype => 'glusterfs', + options => "defaults,_netdev,${rw_bool}", # TODO: will $suid_bool work with gluster ? + dump => '0', # fs_freq: 0 to skip file system dumps + pass => '0', # fs_passno: 0 to skip fsck on boot + require => [ + Package[['glusterfs', 'glusterfs-fuse']], + File["${long_name}"], # the mountpoint + Exec['gluster-fuse'], # ensure fuse is loaded! + ], + } +} + +# vim: ts=8 diff --git a/manifests/mount/base.pp b/manifests/mount/base.pp new file mode 100644 index 0000000..441ebe5 --- /dev/null +++ b/manifests/mount/base.pp @@ -0,0 +1,79 @@ +# GlusterFS module by James +# Copyright (C) 2010-2013+ James Shubin +# Written by James Shubin +# +# 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 . + +class gluster::mount::base( + $repo = true, # add a repo automatically? true or false + $version = '' # pick a specific version (defaults to latest) +) { + include gluster::vardir + #$vardir = $::gluster::vardir::module_vardir # with trailing slash + $vardir = regsubst($::gluster::vardir::module_vardir, '\/$', '') + + # if we use ::mount and ::server on the same machine, this could clash, + # so we use the ensure_resource function to allow identical duplicates! + $rname = "${version}" ? { + '' => 'gluster', + default => "gluster-${version}", + } + if $repo { + $params = { + 'version' => "${version}", + } + ensure_resource('gluster::repo', "${rname}", $params) + } + + package { ['glusterfs', 'glusterfs-fuse']: + ensure => "${version}" ? { + '' => present, + default => "${version}", + }, + require => $repo ? { + false => undef, + default => Gluster::Repo["${rname}"], + }, + } + + # FIXME: choose a reliable and correct way to ensure fuse is loaded + # dmesg | grep -i fuse + # modprobe fuse + # dmesg | grep -i fuse + #fuse init (API version 7.13) + # + + # modprobe fuse if it's missing + exec { '/sbin/modprobe fuse': + logoutput => on_failure, + onlyif => '/usr/bin/test -z "`/bin/dmesg | /bin/grep -i fuse`"', + alias => 'gluster-fuse', + } + #exec { '/sbin/modprobe fuse': + # logoutput => on_failure, + # unless => "/sbin/lsmod | /bin/grep -q '^fuse'", + # alias => 'gluster-modprobe-fuse', + #} + + # TODO: will this autoload the fuse module? + #file { '/etc/modprobe.d/fuse.conf': + # content => "fuse\n", # TODO: "install fuse /sbin/modprobe --ignore-install fuse ; /bin/true\n" ? + # owner => root, + # group => root, + # mode => 644, # u=rw,go=r + # ensure => present, + #} +} + +# vim: ts=8 diff --git a/manifests/repo.pp b/manifests/repo.pp index ca5cecf..3c45ee0 100644 --- a/manifests/repo.pp +++ b/manifests/repo.pp @@ -15,7 +15,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -class gluster::repo( +define gluster::repo( # if you specify 'x.y', it will find the latest x.y.* # if you specify 'x.y.z', it will stick to that version # anything omitted is taken to mean "latest" @@ -96,7 +96,7 @@ class gluster::repo( include ::yum #yum::repos::repo { "gluster-${arch}": - yum::repos::repo { 'gluster': + yum::repos::repo { "${name}": baseurl => "${base_arch}${arch}/", enabled => true, gpgcheck => true, diff --git a/manifests/rulewrapper.pp b/manifests/rulewrapper.pp new file mode 100644 index 0000000..4ac6419 --- /dev/null +++ b/manifests/rulewrapper.pp @@ -0,0 +1,47 @@ +# GlusterFS module by James +# Copyright (C) 2012-2013+ James Shubin +# Written by James Shubin +# +# 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 . + +# NOTE: this wraps shorewall::rule so that we can add on additional fake 'tags' +define gluster::rulewrapper( + $action = '', + $source = '', + $source_ips = [], + $dest = '', + $dest_ips = [], + $proto = '', + $port = [], + $sport = [], + $original = [], + $comment = '', + $ensure = present, + $match = '' # additional tag parameter +) { + shorewall::rule { "${name}": + action => "${action}", + source => "${source}", + source_ips => $source_ips, + dest => "${dest}", + dest_ips => $dest_ips, + proto => "${proto}", + port => $port, + sport => $sport, + comment => "${comment}", + ensure => $ensure, + } +} + +# vim: ts=8 diff --git a/manifests/server.pp b/manifests/server.pp index 158f873..247f4d4 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -29,30 +29,17 @@ class gluster::server( ) { $FW = '$FW' # make using $FW in shorewall easier - # $gluster_package_version is a fact; commonly set by vagrant - if "${version}" == '' and "${gluster_package_version}" == '' { - $valid_version = '' - } else { - if "${version}" != '' and "${gluster_package_version}" != '' { - warning('Requested GlusterFS version specified twice!') - if "${version}" != "${gluster_package_version}" { - fail('Requested GlusterFS version mismatch!') - } - $valid_version = "${version}" - } elsif "${version}" != '' { - $valid_version = "${version}" - } elsif "${gluster_package_version}" != '' { - $valid_version = "${gluster_package_version}" - } else { - fail('Programming error!') - } + # if we use ::mount and ::server on the same machine, this could clash, + # so we use the ensure_resource function to allow identical duplicates! + $rname = "${version}" ? { + '' => 'gluster', + default => "gluster-${version}", } - - # ensure these are from a gluster repo if $repo { - class { '::gluster::repo': - version => "${valid_version}", + $params = { + 'version' => "${version}", } + ensure_resource('gluster::repo', "${rname}", $params) } package { 'moreutils': # for scripts needing: 'sponge' @@ -61,13 +48,13 @@ class gluster::server( } package { 'glusterfs-server': - ensure => "${valid_version}" ? { + ensure => "${version}" ? { '' => present, - default => "${valid_version}", + default => "${version}", }, require => $repo ? { false => undef, - default => Class['::gluster::repo'], + default => Gluster::Repo["${rname}"], }, } diff --git a/manifests/volume.pp b/manifests/volume.pp index 01ef8c5..513a431 100644 --- a/manifests/volume.pp +++ b/manifests/volume.pp @@ -346,6 +346,13 @@ define gluster::volume( source => "${zone}", # use our source zone before => Service['glusterd'], } + + Gluster::Rulewrapper <<| tag == 'gluster_firewall_volume' and match == "${name}" |>> { + #Shorewall::Rule <<| tag == 'gluster_firewall_volume' and match == "${name}" |>> { + source => "${zone}", # use our source zone + port => "${port}", # comma separated string or list + before => Service['glusterd'], + } } # fsm variables and boilerplate -- cgit