diff options
Diffstat (limited to 'extras')
58 files changed, 3869 insertions, 286 deletions
diff --git a/extras/LinuxRPM/Makefile.am b/extras/LinuxRPM/Makefile.am new file mode 100644 index 000000000..1dafa982b --- /dev/null +++ b/extras/LinuxRPM/Makefile.am @@ -0,0 +1,57 @@ + +GFS_TAR = ../../glusterfs-$(VERSION).tar.gz + +.PHONY: all + +all: + @echo "To build RPMS run 'make glusterrpms'" + +.PHONY: glusterrpms prep srcrpm testsrpm clean + +glusterrpms: prep srcrpm rpms + -rm -rf rpmbuild + +prep: + if [ ! -e $(GFS_TAR) ]; then \ + $(MAKE) -C ../.. dist; \ + fi + -mkdir -p rpmbuild/SPECS + -mkdir -p rpmbuild/RPMS + -mkdir -p rpmbuild/SRPMS + -rm -rf rpmbuild/SOURCES + @if [ -d /d/cache/glusterfs -a -e /d/cache/glusterfs/sources ]; then \ + echo "copying glusterfs rpm files from local cache..." ; \ + mkdir -p ./rpmbuild/SOURCES; \ + cp /d/cache/glusterfs/* ./rpmbuild/SOURCES/ ; \ + elif [ -x /usr/bin/git ]; then \ + echo "fetching glusterfs rpm files from fedora git repo..."; \ + cd ./rpmbuild && git clone git://pkgs.fedoraproject.org/glusterfs.git > /dev/null && mv glusterfs SOURCES; \ + else \ + echo "glusterfs rpm files not fetched, you don't have git installed!" ; \ + exit 1 ; \ + fi + cp ../../*.tar.gz ./rpmbuild/SOURCES + cp ../../glusterfs.spec ./rpmbuild/SPECS + +srcrpm: + rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bs rpmbuild/SPECS/glusterfs.spec + mv rpmbuild/SRPMS/* . + +rpms: + rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bb rpmbuild/SPECS/glusterfs.spec + mv rpmbuild/RPMS/*/* . + +# EPEL-5 does not like new versions of rpmbuild and requires some +# _source_* defines + +testsrpm: prep + rpmbuild --define '_topdir $(shell pwd)/rpmbuild' \ + --define '_source_payload w9.gzdio' \ + --define '_source_filedigest_algorithm 1' \ + -bs rpmbuild/SPECS/glusterfs.spec + mv rpmbuild/SRPMS/* ../.. + -rm -rf rpmbuild + +clean: + -rm -rf rpmbuild + -rm -f *.rpm diff --git a/extras/Makefile.am b/extras/Makefile.am index 5c77ce73d..cf619329b 100644 --- a/extras/Makefile.am +++ b/extras/Makefile.am @@ -1,12 +1,20 @@ -docdir = $(datadir)/doc/glusterfs/ -EditorModedir = $(docdir)/ +EditorModedir = $(docdir) EditorMode_DATA = glusterfs-mode.el glusterfs.vim -SUBDIRS = init.d benchmarking +SUBDIRS = init.d systemd benchmarking hook-scripts $(OCF_SUBDIR) LinuxRPM geo-rep + +confdir = $(sysconfdir)/glusterfs +conf_DATA = glusterfs-logrotate gluster-rsyslog-7.2.conf gluster-rsyslog-5.8.conf \ + logger.conf.example glusterfs-georep-logrotate + +voldir = $(sysconfdir)/glusterfs +vol_DATA = glusterd.vol EXTRA_DIST = specgen.scm MacOSX/Portfile glusterfs-mode.el glusterfs.vim \ migrate-unify-to-distribute.sh backend-xattr-sanitize.sh \ backend-cleanup.sh disk_usage_sync.sh quota-remove-xattr.sh \ - quota-metadata-cleanup.sh glusterfs-logrotate - + quota-metadata-cleanup.sh glusterfs-logrotate clear_xattrs.sh \ + group-virt.example glusterd-sysconfig gluster-rsyslog-7.2.conf \ + gluster-rsyslog-5.8.conf logger.conf.example glusterd.vol \ + glusterfs-georep-logrotate diff --git a/extras/Ubuntu/README.Ubuntu b/extras/Ubuntu/README.Ubuntu index 651bd046e..0c5b7828d 100644 --- a/extras/Ubuntu/README.Ubuntu +++ b/extras/Ubuntu/README.Ubuntu @@ -1,20 +1,24 @@ -Bug 3282 - Mounting from localhost in fstab fails at boot on ubuntu -(http://bugs.gluster.com/show_bug.cgi?id=3282) +Bug 765014 - Mounting from localhost in fstab fails at boot on ubuntu +(https://bugzilla.redhat.com/show_bug.cgi?id=765014) +(https://bugs.launchpad.net/ubuntu/+source/glusterfs/+bug/876648) Ubuntu uses upstart instead of init to bootstrap the system and it has a unique -way of handling fstab, using a program called mountall(8). As a result, -glusterfs mounts in fstab are tried before the glusterd service is running. In -the case where the client is also a server and the volume is mounted from -localhost, the mount fails at boot time. An upstart job for glusterd is needed -to correct this. +way of handling fstab, using a program called mountall(8). As a result of using +a debian initscript to start glusterd, glusterfs mounts in fstab are tried before +the glusterd service is running. In the case where the client is also a server +and the volume is mounted from localhost, the mount fails at boot time. To +correct this we need to launch glusterd using upstart and block the glusterfs +mounting event until glusterd is started. The glusterd.conf file contains the necessary configuration for upstart to manage the glusterd service. It should be placed in /etc/init/glusterd.conf on Ubuntu systems, and then the old initscript /etc/init.d/glusterd can be -removed. +removed. An additional upstart job, mounting-glusterfs.conf, is also required +to block mounting glusterfs volumes until the glusterd service is available. +Both of these upstart jobs need to be placed in /etc/init to resolve the issue. -It can also be added to Ubuntu deb packages by placing it in debian/upstart -inside the source package (or debian/glusterd.upstart if the source package -builds multiple binary packages.) +Starting with Ubuntu 12.04, Precise Pangolin, these upstart jobs will be +included with the glusterfs-server package in the Ubuntu repository. -This affects all versions of glusterfs on the ubuntu platform. +This affects all versions of glusterfs on the Ubuntu platform since at least +10.04, Lucid Lynx. diff --git a/extras/Ubuntu/glusterd.conf b/extras/Ubuntu/glusterd.conf index b987ffa13..aa99502b0 100644 --- a/extras/Ubuntu/glusterd.conf +++ b/extras/Ubuntu/glusterd.conf @@ -1,17 +1,10 @@ -# glusterd service upstart job -# -# Author: Louis Zuckerman <me@louiszuckerman.com> +author "Louis Zuckerman <me@louiszuckerman.com>" +description "GlusterFS Management Daemon" -description "GlusterFS Management Daemon" - -start on (local-filesystems and net-device-up IFACE=lo and net-device-up IFACE=eth0) or (mounting TYPE=glusterfs) +start on runlevel [2345] stop on runlevel [016] -respawn - -exec /usr/sbin/glusterd -N -p /var/run/glusterd.pid +expect fork -post-start script - sleep 1 -end script +exec /usr/sbin/glusterd -p /var/run/glusterd.pid diff --git a/extras/Ubuntu/mounting-glusterfs.conf b/extras/Ubuntu/mounting-glusterfs.conf new file mode 100644 index 000000000..3c59c0f63 --- /dev/null +++ b/extras/Ubuntu/mounting-glusterfs.conf @@ -0,0 +1,7 @@ +author "Louis Zuckerman <me@louiszuckerman.com>" +description "Block the mounting event for glusterfs filesystems until glusterd is running" + +start on mounting TYPE=glusterfs +task +exec start wait-for-state WAIT_FOR=glusterd WAITER=mounting-glusterfs + diff --git a/extras/benchmarking/Makefile.am b/extras/benchmarking/Makefile.am index 04cc06182..bfcc59277 100644 --- a/extras/benchmarking/Makefile.am +++ b/extras/benchmarking/Makefile.am @@ -1,7 +1,5 @@ -docdir = $(datadir)/doc/$(PACKAGE_NAME)/benchmarking - -benchmarkingdir = $(docdir) +benchmarkingdir = $(docdir)/benchmarking benchmarking_DATA = rdd.c glfs-bm.c README launch-script.sh local-script.sh diff --git a/extras/benchmarking/glfs-bm.c b/extras/benchmarking/glfs-bm.c index 035d055df..dc717f33c 100644 --- a/extras/benchmarking/glfs-bm.c +++ b/extras/benchmarking/glfs-bm.c @@ -1,21 +1,12 @@ -/* - Copyright (c) 2008-2011 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - #define _GNU_SOURCE #define __USE_FILE_OFFSET64 #define _FILE_OFFSET_BITS 64 diff --git a/extras/benchmarking/rdd.c b/extras/benchmarking/rdd.c index b06333370..a667c6a1d 100644 --- a/extras/benchmarking/rdd.c +++ b/extras/benchmarking/rdd.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2008-2011 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> diff --git a/extras/generate-xdr-files.sh b/extras/generate-xdr-files.sh index e52321cd3..bc02f77c9 100755 --- a/extras/generate-xdr-files.sh +++ b/extras/generate-xdr-files.sh @@ -22,22 +22,13 @@ append_licence_header () cat >$dst_file <<EOF /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include "xdr-common.h" diff --git a/extras/geo-rep/Makefile.am b/extras/geo-rep/Makefile.am new file mode 100644 index 000000000..fc5f56d54 --- /dev/null +++ b/extras/geo-rep/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = gsync-sync-gfid.c gsync-upgrade.sh generate-gfid-file.sh \ + get-gfid.sh slave-upgrade.sh diff --git a/extras/geo-rep/generate-gfid-file.sh b/extras/geo-rep/generate-gfid-file.sh new file mode 100644 index 000000000..c6739fbf1 --- /dev/null +++ b/extras/geo-rep/generate-gfid-file.sh @@ -0,0 +1,53 @@ +#!/bin/bash +#Usage: generate-gfid-file.sh <master-volfile-server:master-volume> <path-to-get-gfid.sh> <output-file> + +function get_gfids() +{ + GET_GFID_CMD=$1 + OUTPUT_FILE=$2 + find . -exec $GET_GFID_CMD {} \; > $OUTPUT_FILE +} + +function mount_client() +{ + local T; # temporary mount + local i; # inode number + + VOLFILE_SERVER=$1; + VOLUME=$2; + GFID_CMD=$3; + OUTPUT=$4; + + T=$(mktemp -d); + + glusterfs -s $VOLFILE_SERVER --volfile-id $VOLUME $T; + + i=$(stat -c '%i' $T); + + [ "x$i" = "x1" ] || fatal "could not mount volume $MASTER on $T"; + + cd $T; + + get_gfids $GFID_CMD $OUTPUT + + cd -; + + umount $T || fatal "could not umount $MASTER from $T"; + + rmdir $T || warn "rmdir of $T failed"; +} + + +function main() +{ + SLAVE=$1 + GET_GFID_CMD=$2 + OUTPUT=$3 + + VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'` + VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'` + + mount_client $VOLFILE_SERVER $VOLUME_NAME $GET_GFID_CMD $OUTPUT +} + +main "$@"; diff --git a/extras/geo-rep/get-gfid.sh b/extras/geo-rep/get-gfid.sh new file mode 100755 index 000000000..a4d609b0b --- /dev/null +++ b/extras/geo-rep/get-gfid.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ATTR_STR=`getfattr -h $1 -n glusterfs.gfid.string` +GLFS_PATH=`echo $ATTR_STR | sed -e 's/# file: \(.*\) glusterfs.gfid.string*/\1/g'` +GFID=`echo $ATTR_STR | sed -e 's/.*glusterfs.gfid.string="\(.*\)"/\1/g'` + +echo "$GFID $GLFS_PATH" diff --git a/extras/geo-rep/gsync-sync-gfid.c b/extras/geo-rep/gsync-sync-gfid.c new file mode 100644 index 000000000..601f4720e --- /dev/null +++ b/extras/geo-rep/gsync-sync-gfid.c @@ -0,0 +1,106 @@ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <attr/xattr.h> +#include <libgen.h> +#include <ctype.h> +#include <stdlib.h> + +#ifndef UUID_CANONICAL_FORM_LEN +#define UUID_CANONICAL_FORM_LEN 36 +#endif + +#ifndef GF_FUSE_AUX_GFID_HEAL +#define GF_FUSE_AUX_GFID_HEAL "glusterfs.gfid.heal" +#endif + +#define GLFS_LINE_MAX (PATH_MAX + (2 * UUID_CANONICAL_FORM_LEN)) + +int +main (int argc, char *argv[]) +{ + char *file = NULL; + char *tmp = NULL; + char *tmp1 = NULL; + char *parent_dir = NULL; + char *gfid = NULL; + char *bname = NULL; + int ret = -1; + int len = 0; + FILE *fp = NULL; + char line[GLFS_LINE_MAX] = {0,}; + char *path = NULL; + void *blob = NULL; + void *tmp_blob = NULL; + + if (argc != 2) { + /* each line in the file has the following format + * uuid-in-canonical-form path-relative-to-gluster-mount. + * Both uuid and relative path are from master mount. + */ + fprintf (stderr, "usage: %s <file-of-paths-to-be-synced>\n", + argv[0]); + goto out; + } + + file = argv[1]; + + fp = fopen (file, "r"); + if (fp == NULL) { + fprintf (stderr, "cannot open %s for reading (%s)\n", + file, strerror (errno)); + goto out; + } + + while (fgets (line, GLFS_LINE_MAX, fp) != NULL) { + tmp = line; + path = gfid = line; + + path += UUID_CANONICAL_FORM_LEN + 1; + + while(isspace (*path)) + path++; + + if ((strlen (line) < GLFS_LINE_MAX) && + (line[strlen (line) - 1] == '\n')) + line[strlen (line) - 1] = '\0'; + + line[UUID_CANONICAL_FORM_LEN] = '\0'; + + tmp = strdup (path); + tmp1 = strdup (path); + parent_dir = dirname (tmp); + bname = basename (tmp1); + + /* gfid + '\0' + bname + '\0' */ + len = UUID_CANONICAL_FORM_LEN + 1 + strlen (bname) + 1; + + blob = calloc (1, len); + + memcpy (blob, gfid, UUID_CANONICAL_FORM_LEN); + + tmp_blob = blob + UUID_CANONICAL_FORM_LEN + 1; + + memcpy (tmp_blob, bname, strlen (bname)); + + ret = setxattr (parent_dir, GF_FUSE_AUX_GFID_HEAL, blob, len, + 0); + if (ret < 0) { + fprintf (stderr, "setxattr on %s/%s failed (%s)\n", + parent_dir, bname, strerror (errno)); + } + memset (line, 0, GLFS_LINE_MAX); + + free (blob); + free (tmp); free (tmp1); + blob = NULL; + } + + ret = 0; +out: + return ret; +} + diff --git a/extras/geo-rep/gsync-upgrade.sh b/extras/geo-rep/gsync-upgrade.sh new file mode 100644 index 000000000..b17948736 --- /dev/null +++ b/extras/geo-rep/gsync-upgrade.sh @@ -0,0 +1,123 @@ +#!/bin/bash +#usage: gsync-upgrade.sh <slave-volfile-server:slave-volume> <gfid-file> +# <path-to-gsync-sync-gfid> <ssh-identity-file> +#<slave-volfile-server>: a machine on which gluster cli can fetch slave volume info. +# slave-volfile-server defaults to localhost. +# +#<gfid-file>: a file containing paths and their associated gfids +# on master. The paths are relative to master mount point +# (not absolute). An example extract of <gfid-file> can be, +# +# <extract> +# 22114455-57c5-46e9-a783-c40f83a72b09 /dir +# 25772386-3eb8-4550-a802-c3fdc938ca80 /dir/file +# </extract> +# +#<ssh-identity-file>: file from which the identity (private key) for public key authentication is read. + +SLAVE_MOUNT='/tmp/glfs_slave' + +function SSH() +{ + HOST=$1 + SSHKEY=$2 + + shift 2 + + ssh -qi $SSHKEY \ + -oPasswordAuthentication=no \ + -oStrictHostKeyChecking=no \ + "$HOST" "$@"; +} + +function get_bricks() +{ + SSHKEY=$3 + + SSH $1 $SSHKEY "gluster volume info $2" | grep -E 'Brick[0-9]+' | sed -e 's/[^:]*:\(.*\)/\1/g' +} + +function cleanup_brick() +{ + HOST=$1 + BRICK=$2 + SSHKEY=$3 + + # TODO: write a C program to receive a list of files and does cleanup on + # them instead of spawning a new setfattr process for each file if + # performance is bad. + SSH -i $SSHKEY $HOST "rm -rf $BRICK/.glusterfs/* && find $BRICK -exec setfattr -x trusted.gfid {} \;" +} + +function cleanup_slave() +{ + SSHKEY=$2 + + VOLFILE_SERVER=`echo $1 | sed -e 's/\(.*\):.*/\1/'` + VOLUME_NAME=`echo $1 | sed -e 's/.*:\(.*\)/\1/'` + + BRICKS=`get_bricks $VOLFILE_SERVER $VOLUME_NAME $SSHKEY` + + for i in $BRICKS; do + HOST=`echo $i | sed -e 's/\(.*\):.*/\1/'` + BRICK=`echo $i | sed -e 's/.*:\(.*\)/\1/'` + cleanup_brick $HOST $BRICK $SSHKEY + done + + SSH -i $SSHKEY $VOLFILE_SERVER "gluster --mode=script volume stop $VOLUME_NAME; gluster volume start $VOLUME_NAME"; + +} + +function mount_client() +{ + local T; # temporary mount + local i; # inode number + GFID_FILE=$3 + SYNC_CMD=$4 + + T=$(mktemp -d); + + glusterfs --aux-gfid-mount -s $1 --volfile-id $2 $T; + + i=$(stat -c '%i' $T); + + [ "x$i" = "x1" ] || fatal "could not mount volume $MASTER on $T"; + + cd $T; + + $SYNC_CMD $GFID_FILE + + cd -; + + umount -l $T || fatal "could not umount $MASTER from $T"; + + rmdir $T || warn "rmdir of $T failed"; +} + +function sync_gfids() +{ + SLAVE=$1 + GFID_FILE=$2 + + SLAVE_VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'` + SLAVE_VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'` + + if [ "x$SLAVE_VOLFILE_SERVER" = "x" ]; then + SLAVE_VOLFILE_SERVER="localhost" + fi + + mount_client $SLAVE_VOLFILE_SERVER $SLAVE_VOLUME_NAME $GFID_FILE $3 +} + +function upgrade() +{ + SLAVE=$1 + GFID_FILE=$2 + SYNC_CMD=$3 + SSHKEY=$4 + + cleanup_slave $SLAVE $SSHKEY + sync_gfids $SLAVE $GFID_FILE $SYNC_CMD +} + +upgrade "$@" diff --git a/extras/geo-rep/slave-upgrade.sh b/extras/geo-rep/slave-upgrade.sh new file mode 100644 index 000000000..6198f408a --- /dev/null +++ b/extras/geo-rep/slave-upgrade.sh @@ -0,0 +1,102 @@ +#!/bin/bash +#usage: slave-upgrade.sh <volfile-server:volname> <gfid-file> +# <path-to-gsync-sync-gfid> +#<slave-volfile-server>: a machine on which gluster cli can fetch slave volume info. +# slave-volfile-server defaults to localhost. +# +#<gfid-file>: a file containing paths and their associated gfids +# on master. The paths are relative to master mount point +# (not absolute). An example extract of <gfid-file> can be, +# +# <extract> +# 22114455-57c5-46e9-a783-c40f83a72b09 /dir +# 25772386-3eb8-4550-a802-c3fdc938ca80 /dir/file +# </extract> + +function get_bricks() +{ + gluster volume info $1 | grep -E 'Brick[0-9]+' | sed -e 's/[^:]*:\(.*\)/\1/g' +} + +function cleanup_brick() +{ + HOST=$1 + BRICK=$2 + + # TODO: write a C program to receive a list of files and does cleanup on + # them instead of spawning a new setfattr process for each file if + # performance is bad. + ssh $HOST "rm -rf $BRICK/.glusterfs/* && find $BRICK -exec setfattr -x trusted.gfid {} \; 2>/dev/null" +} + +function cleanup_slave() +{ + VOLUME_NAME=`echo $1 | sed -e 's/.*:\(.*\)/\1/'` + + BRICKS=`get_bricks $VOLUME_NAME` + + for i in $BRICKS; do + HOST=`echo $i | sed -e 's/\(.*\):.*/\1/'` + BRICK=`echo $i | sed -e 's/.*:\(.*\)/\1/'` + cleanup_brick $HOST $BRICK + done + + # Now restart the volume + gluster --mode=script volume stop $VOLUME_NAME; + gluster volume start $VOLUME_NAME; +} + +function mount_client() +{ + local T; # temporary mount + local i; # inode number + + VOLUME_NAME=$2; + GFID_FILE=$3 + SYNC_CMD=$4 + + T=$(mktemp -d); + + glusterfs --aux-gfid-mount -s $1 --volfile-id $VOLUME_NAME $T; + + i=$(stat -c '%i' $T); + + cd $T; + + $SYNC_CMD $GFID_FILE + + cd -; + + umount $T || fatal "could not umount $MASTER from $T"; + + rmdir $T || warn "rmdir of $T failed"; +} + +function sync_gfids() +{ + SLAVE=$1 + GFID_FILE=$2 + SYNC_CMD=$3 + + SLAVE_VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'` + SLAVE_VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'` + + if [ "x$SLAVE_VOLFILE_SERVER" = "x" ]; then + SLAVE_VOLFILE_SERVER="localhost" + fi + + mount_client $SLAVE_VOLFILE_SERVER $SLAVE_VOLUME_NAME $GFID_FILE $SYNC_CMD +} + +function upgrade() +{ + SLAVE=$1 + GFID_FILE=$2 + SYNC_CMD=$3 + + cleanup_slave $SLAVE + + sync_gfids $SLAVE $GFID_FILE $SYNC_CMD +} + +upgrade "$@" diff --git a/extras/gluster-rsyslog-5.8.conf b/extras/gluster-rsyslog-5.8.conf new file mode 100644 index 000000000..2519999bc --- /dev/null +++ b/extras/gluster-rsyslog-5.8.conf @@ -0,0 +1,51 @@ +##### gluster.conf ##### + +# +## If you want to log every message to the log file instead of +## intelligently suppressing repeated messages, set off to +## RepeatedMsgReduction. This change requires rsyslog restart +## (eg. run 'service rsyslog restart') +# +#$RepeatedMsgReduction off +$RepeatedMsgReduction on + +# +## The mmcount module provides the capability to count log messages by +## severity or json property of given app-name. The count value is added +## into the log message as json property named '$msgid' +# +$ModLoad mmcount +$mmcountKey gf_code # start counting value of gf_code + +$template Glusterfsd_dynLogFile,"/var/log/glusterfs/bricks/%app-name%.log" +$template Gluster_dynLogFile,"/var/log/glusterfs/%app-name%.log" + +$template GLFS_Template,"%msgid%/%syslogfacility-text:::uppercase%/%syslogseverity-text:::uppercase% [%TIMESTAMP:::date-rfc3339%] %msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" + +# +## Pass logs to mmcount if app-name is 'gluster' +# +if $app-name contains 'gluster' then :mmcount: + +if $app-name contains 'glusterfsd' then ?Glusterfsd_dynLogFile;GLFS_Template +if $app-name contains 'gluster' and not ( $app-name contains 'glusterfsd' ) then ?Gluster_dynLogFile;GLFS_Template + +# +## Sample configuration to send a email alert for every 50th mmcount +# +#$ModLoad ommail +#$ActionMailSMTPServer smtp.example.com +#$ActionMailFrom rsyslog@example.com +#$ActionMailTo glusteradmin@example.com +#$template mailSubject,"50th message of gf_code=9999 on %hostname%" +#$template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'" +#$ActionMailSubject mailSubject +#$ActionExecOnlyOnceEveryInterval 30 +#if $app-name == 'glusterfsd' and $msgid != 0 and $msgid % 50 == 0 \ +#then :ommail:;RSYSLOG_SyslogProtocol23Format +# + +# +## discard logs where app-name is 'gluster' as we processed already +# +if $app-name contains 'gluster' then ~ diff --git a/extras/gluster-rsyslog-7.2.conf b/extras/gluster-rsyslog-7.2.conf new file mode 100644 index 000000000..8b2841543 --- /dev/null +++ b/extras/gluster-rsyslog-7.2.conf @@ -0,0 +1,76 @@ +##### gluster.conf ##### +# +## If you want to log every message to the log file instead of +## intelligently suppressing repeated messages, set off to +## RepeatedMsgReduction. This change requires rsyslog restart +## (eg. run 'service rsyslog restart') +# +#$RepeatedMsgReduction off +$RepeatedMsgReduction on + +$ModLoad mmjsonparse +*.* :mmjsonparse: + +# +## The mmcount module provides the capability to count log messages by +## severity or json property of given app-name. The count value is added +## into the log message as json property named 'mmcount' +## +## More info at http://www.rsyslog.com/doc/mmcount.html +# +#module(load="mmcount") +#action(type="mmcount" appname="glusterd" key="!gf_code") # count each value of gf_code of appname glusterd +#action(type="mmcount" appname="glusterfsd" key="!gf_code") # count each value of gf_code of appname glusterfsd +#action(type="mmcount" appname="glusterfs" key="!gf_code") # count each value of gf_code of appname glusterfs + +template (name="Glusterfsd_dynLogFile" type="string" string="/var/log/glusterfs/bricks/%app-name%.log") +template (name="Gluster_dynLogFile" type="string" string="/var/log/glusterfs/%app-name%.log") + +template(name="GLFS_template" type="list") { + property(name="$!mmcount") + constant(value="/") + property(name="syslogfacility-text" caseConversion="upper") + constant(value="/") + property(name="syslogseverity-text" caseConversion="upper") + constant(value=" ") + constant(value="[") + property(name="timereported" dateFormat="rfc3339") + constant(value="] ") + constant(value="[") + property(name="$!gf_code") + constant(value="] ") + constant(value="[") + property(name="$!gf_message") + constant(value="] ") + property(name="$!msg") + constant(value="\n") +} + +if $app-name contains 'glusterfsd' then { + action(type="omfile" + DynaFile="Glusterfsd_dynLogFile" + Template="GLFS_template") + stop +} + +if $app-name contains 'gluster' then { + action(type="omfile" + DynaFile="Gluster_dynLogFile" + Template="GLFS_template") + stop +} + +# +## send email for every 50th mmcount +#$ModLoad ommail +#if $app-name == 'glusterfsd' and $!mmcount <> 0 and $!mmcount % 50 == 0 then { +# $ActionMailSMTPServer smtp.example.com +# $ActionMailFrom rsyslog@example.com +# $ActionMailTo glusteradmin@example.com +# $template mailSubject,"50th message of gf_code=9999 on %hostname%" +# $template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'" +# $ActionMailSubject mailSubject +# $ActionExecOnlyOnceEveryInterval 30 +# :ommail:;RSYSLOG_SyslogProtocol23Format +#} +# diff --git a/extras/glusterd-sysconfig b/extras/glusterd-sysconfig new file mode 100644 index 000000000..8237c5711 --- /dev/null +++ b/extras/glusterd-sysconfig @@ -0,0 +1,6 @@ +## Set custom log file and log level (bellow are defaults) +# LOG_FILE='/var/log/glusterfs/glusterd.log' +# LOG_LEVEL='INFO' + +## Set custom options for glusterd +# GLUSTERD_OPTIONS='' diff --git a/extras/glusterd.vol b/extras/glusterd.vol new file mode 100644 index 000000000..9bac52ab7 --- /dev/null +++ b/extras/glusterd.vol @@ -0,0 +1,9 @@ +volume management + type mgmt/glusterd + option working-directory /var/lib/glusterd + option transport-type socket,rdma + option transport.socket.keepalive-time 10 + option transport.socket.keepalive-interval 2 + option transport.socket.read-fail-log off +# option base-port 49152 +end-volume diff --git a/extras/glusterfs-georep-logrotate b/extras/glusterfs-georep-logrotate new file mode 100644 index 000000000..6a69ab1e3 --- /dev/null +++ b/extras/glusterfs-georep-logrotate @@ -0,0 +1,18 @@ + +rotate 52 +missingok + +compress +delaycompress +notifempty + +/var/log/glusterfs/geo-replication/*/*.log { +} + + +/var/log/glusterfs/geo-replication-slaves/*.log { +} + + +/var/log/glusterfs/geo-replication-slaves/*/*.log { +} diff --git a/extras/glusterfs.vim b/extras/glusterfs.vim index 62102c1ee..899cc6551 100644 --- a/extras/glusterfs.vim +++ b/extras/glusterfs.vim @@ -1,20 +1,11 @@ " glusterfs.vim: GNU Vim Syntax file for GlusterFS .vol specification -" Copyright (c) 2017-2011 Gluster, Inc. <http://www.gluster.com> -" This file is part of GlusterFS. +" Copyright (c) 2007777777Red Hat, Inc. <http://www.redhat.com> +" This file is part of GlusterFS. " -" GlusterFS is free software; you can redistribute it and/or modify -" it under the terms of the GNU General Public License as published -" by the Free Software Foundation; either version 3 of the License, -" or (at your option) any later version. -" -" GlusterFS 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 -" General Public License for more details. -" -" You should have received a copy of the GNU General Public License -" along with this program. If not, see -" <http://www.gnu.org/licenses/>. +" This file is licensed to you under your choice of the GNU Lesser +" General Public License, version 3 or any later version (LGPLv3 or +" later), or the GNU General Public License, version 2 (GPLv2), in all +" cases as published by the Free Software Foundation. " " Last Modified: Wed Aug 1 00:47:10 IST 2007 " Version: 0.8 diff --git a/extras/gnfs-loganalyse.py b/extras/gnfs-loganalyse.py index 6b24e5a71..71e79b6be 100644 --- a/extras/gnfs-loganalyse.py +++ b/extras/gnfs-loganalyse.py @@ -1,21 +1,13 @@ #!/bin/python """ - Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. """ import os diff --git a/extras/group-virt.example b/extras/group-virt.example new file mode 100644 index 000000000..7dc777f2d --- /dev/null +++ b/extras/group-virt.example @@ -0,0 +1,6 @@ +quick-read=off +read-ahead=off +io-cache=off +stat-prefetch=off +eager-lock=enable +remote-dio=enable diff --git a/extras/hook-scripts/Makefile.am b/extras/hook-scripts/Makefile.am new file mode 100644 index 000000000..f6bded20c --- /dev/null +++ b/extras/hook-scripts/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = S29CTDBsetup.sh S30samba-start.sh S30samba-stop.sh S30samba-set.sh S56glusterd-geo-rep-create-post.sh diff --git a/extras/hook-scripts/S29CTDBsetup.sh b/extras/hook-scripts/S29CTDBsetup.sh new file mode 100644 index 000000000..e256be1f3 --- /dev/null +++ b/extras/hook-scripts/S29CTDBsetup.sh @@ -0,0 +1,69 @@ +#! /bin/bash +#non-portable - RHS-2.0 only +# - The script mounts the 'meta-vol' on start 'event' on a known +# directory (eg. /gluster/lock) +# - Adds the necessary configuration changes for ctdb in smb.conf and +# restarts smb service. +# - P.S: There are other 'tasks' that need to be done outside this script +# to get CTDB based failover up and running. + +SMB_CONF=/etc/samba/smb.conf + +CTDB_MNT=/gluster/lock +PROGNAME="ctdb" +OPTSPEC="volname:" +VOL= +# $META is the volume that will be used by CTDB as a shared filesystem. +# It is not desirable to use this volume for storing 'data' as well. +# META is set to 'all' (viz. a keyword and hence not a legal volume name) +# to prevent the script from running for volumes it was not intended. +# User needs to set META to the volume that serves CTDB lockfile. +META="all" + +function sighup_samba () { + pid=`cat /var/run/smbd.pid` + if [ $pid != " " ] + then + kill -HUP $pid; + else + /etc/init.d/smb start + fi +} + +function parse_args () { + ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@) + eval set -- "$ARGS" + + while true; do + case $1 in + --volname) + shift + VOL=$1 + ;; + + *) + shift + break + ;; + + esac + + shift + done +} + +function add_glusterfs_ctdb_options () { + PAT="Share Definitions" + GLUSTER_CTDB_CONFIG="# ctdb config for glusterfs\n\tclustering = yes\n\tidmap backend = tdb2\n\tprivate dir = "$CTDB_MNT"\n" + + sed -i /"$PAT"/i\ "$GLUSTER_CTDB_CONFIG" $SMB_CONF +} + +parse_args $@ +if [ "$META" = "$VOL" ] +then + add_glusterfs_ctdb_options + sighup_samba + mount -t glusterfs `hostname`:$VOL "$CTDB_MNT" & +fi + diff --git a/extras/hook-scripts/S30samba-set.sh b/extras/hook-scripts/S30samba-set.sh new file mode 100755 index 000000000..6b11f5a4f --- /dev/null +++ b/extras/hook-scripts/S30samba-set.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +#Need to be copied to hooks/<HOOKS_VER>/set/post/ + +#TODO: All gluster and samba paths are assumed for fedora like systems. +#Some efforts are required to make it work on other distros. + +#The preferred way of creating a smb share of a gluster volume has changed. +#The old method was to create a fuse mount of the volume and share the mount +#point through samba. +# +#New method eliminates the requirement of fuse mount and changes in fstab. +#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume. +# +#This hook script enables user to enable or disable smb share by volume set +#option. Keys "user.cifs" and "user.smb" both are valid, but user.smb is +#preferred. + + +PROGNAME="Ssamba-set" +OPTSPEC="volname:" +VOL= + +enable_smb="" + +function parse_args () { + ARGS=$(getopt -l $OPTSPEC -o "o" -name $PROGNAME $@) + eval set -- "$ARGS" + + while true; do + case $1 in + --volname) + shift + VOL=$1 + ;; + *) + shift + for pair in $@; do + read key value < <(echo "$pair" | tr "=" " ") + case "$key" in + "user.cifs") + enable_smb=$value + ;; + "user.smb") + enable_smb=$value + ;; + *) + ;; + esac + done + + shift + break + ;; + esac + shift + done +} + +function add_samba_share () { + volname=$1 + STRING="\n[gluster-$volname]\n" + STRING+="comment = For samba share of volume $volname\n" + STRING+="vfs objects = glusterfs\n" + STRING+="glusterfs:volume = $volname\n" + STRING+="glusterfs:logfile = /var/log/samba/glusterfs-$volname.%%M.log\n" + STRING+="glusterfs:loglevel = 7\n" + STRING+="path = /\n" + STRING+="read only = no\n" + STRING+="guest ok = yes\n" + printf "$STRING" >> /etc/samba/smb.conf +} + +function sighup_samba () { + pid=`cat /var/run/smbd.pid` + if [ "x$pid" != "x" ] + then + kill -HUP "$pid"; + else + /etc/init.d/smb start + fi +} + +function del_samba_share () { + volname=$1 + sed -i "/\[gluster-$volname\]/,/^$/d" /etc/samba/smb.conf +} + +function is_volume_started () { + volname=$1 + echo "$(grep status /var/lib/glusterd/vols/"$volname"/info |\ + cut -d"=" -f2)" +} + +parse_args $@ +if [ "0" = $(is_volume_started "$VOL") ]; then + exit 0 +fi + +if [ "$enable_smb" = "enable" ]; then + if ! grep --quiet "\[gluster-$VOL\]" /etc/samba/smb.conf ; then + add_samba_share $VOL + sighup_samba + fi + +elif [ "$enable_smb" = "disable" ]; then + del_samba_share $VOL + sighup_samba +fi diff --git a/extras/hook-scripts/S30samba-start.sh b/extras/hook-scripts/S30samba-start.sh new file mode 100755 index 000000000..34fde0ef8 --- /dev/null +++ b/extras/hook-scripts/S30samba-start.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +#Need to be copied to hooks/<HOOKS_VER>/start/post + +#TODO: All gluster and samba paths are assumed for fedora like systems. +#Some efforts are required to make it work on other distros. + +#The preferred way of creating a smb share of a gluster volume has changed. +#The old method was to create a fuse mount of the volume and share the mount +#point through samba. +# +#New method eliminates the requirement of fuse mount and changes in fstab. +#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume. +# +#This hook script automagically creates shares for volume on every volume start +#event by adding the entries in smb.conf file and sending SIGHUP to samba. +# +#In smb.conf: +#glusterfs vfs plugin has to be specified as required vfs object. +#Path value is relative to the root of gluster volume;"/" signifies complete +#volume. + +PROGNAME="Ssamba-start" +OPTSPEC="volname:" +VOL= +CONFIGFILE= +LOGFILEBASE= +PIDDIR= + +function parse_args () { + ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@) + eval set -- "$ARGS" + + while true; do + case $1 in + --volname) + shift + VOL=$1 + ;; + *) + shift + break + ;; + esac + shift + done +} + +function find_config_info () { + cmdout=`smbd -b | grep smb.conf` + if [ $? -ne 0 ];then + echo "Samba is not installed" + exit 1 + fi + CONFIGFILE=`echo $cmdout | awk {'print $2'}` + PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}` + LOGFILEBASE=`smbd -b | grep 'LOGFILEBASE' | awk '{print $2}'` +} + +function add_samba_share () { + volname=$1 + STRING="\n[gluster-$volname]\n" + STRING+="comment = For samba share of volume $volname\n" + STRING+="vfs objects = glusterfs\n" + STRING+="glusterfs:volume = $volname\n" + STRING+="glusterfs:logfile = $LOGFILEBASE/glusterfs-$volname.%%M.log\n" + STRING+="glusterfs:loglevel = 7\n" + STRING+="path = /\n" + STRING+="read only = no\n" + STRING+="guest ok = yes\n" + printf "$STRING" >> ${CONFIGFILE} +} + +function sighup_samba () { + pid=`cat ${PIDDIR}/smbd.pid` + if [ "x$pid" != "x" ] + then + kill -HUP "$pid"; + else + /etc/init.d/smb condrestart + fi +} + +function get_smb () { + volname=$1 + uservalue= + + usercifsvalue=$(grep user.cifs /var/lib/glusterd/vols/"$volname"/info |\ + cut -d"=" -f2) + usersmbvalue=$(grep user.smb /var/lib/glusterd/vols/"$volname"/info |\ + cut -d"=" -f2) + + if [[ $usercifsvalue = "disable" || $usersmbvalue = "disable" ]]; then + uservalue="disable" + fi + echo "$uservalue" +} + +parse_args $@ +if [ $(get_smb "$VOL") = "disable" ]; then + exit 0 +fi + +#Find smb.conf, smbd pid directory and smbd logfile path +find_config_info + +if ! grep --quiet "\[gluster-$VOL\]" ${CONFIGFILE} ; then + add_samba_share $VOL + sighup_samba +fi diff --git a/extras/hook-scripts/S30samba-stop.sh b/extras/hook-scripts/S30samba-stop.sh new file mode 100755 index 000000000..8950eea43 --- /dev/null +++ b/extras/hook-scripts/S30samba-stop.sh @@ -0,0 +1,71 @@ +#! /bin/bash + +#Need to be copied to hooks/<HOOKS_VER>/stop/pre + +#TODO: All gluster and samba paths are assumed for fedora like systems. +#Some efforts are required to make it work on other distros. + +#The preferred way of creating a smb share of a gluster volume has changed. +#The old method was to create a fuse mount of the volume and share the mount +#point through samba. +# +#New method eliminates the requirement of fuse mount and changes in fstab. +#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume. +# +#This hook script automagically removes shares for volume on every volume stop +#event by removing the volume related entries(if any) in smb.conf file. + +PROGNAME="Ssamba-stop" +OPTSPEC="volname:" +VOL= +CONFIGFILE= +PIDDIR= + +function parse_args () { + ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@) + eval set -- "$ARGS" + + while true; do + case $1 in + --volname) + shift + VOL=$1 + ;; + *) + shift + break + ;; + esac + shift + done +} + +function find_config_info () { + cmdout=`smbd -b | grep smb.conf` + if [ $? -ne 0 ];then + echo "Samba is not installed" + exit 1 + fi + CONFIGFILE=`echo $cmdout | awk {'print $2'}` + PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}` +} + +function del_samba_share () { + volname=$1 + sed -i "/\[gluster-$volname\]/,/^$/d" ${CONFIGFILE} +} + +function sighup_samba () { + pid=`cat ${PIDDIR}/smbd.pid` + if [ "x$pid" != "x" ] + then + kill -HUP $pid; + else + /etc/init.d/smb condrestart + fi +} + +parse_args $@ +find_config_info +del_samba_share $VOL +sighup_samba diff --git a/extras/hook-scripts/S40ufo-stop.py b/extras/hook-scripts/S40ufo-stop.py new file mode 100755 index 000000000..107f19683 --- /dev/null +++ b/extras/hook-scripts/S40ufo-stop.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import os +from optparse import OptionParser + +if __name__ == '__main__': + # check if swift is installed + try: + from gluster.swift.common.Glusterfs import get_mnt_point, unmount + except ImportError: + import sys + sys.exit("Openstack Swift does not appear to be installed properly"); + + op = OptionParser(usage="%prog [options...]") + op.add_option('--volname', dest='vol', type=str) + op.add_option('--last', dest='last', type=str) + (opts, args) = op.parse_args() + + + mnt_point = get_mnt_point(opts.vol) + if mnt_point: + unmount(mnt_point) + else: + sys.exit("get_mnt_point returned none for mount point") diff --git a/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh new file mode 100755 index 000000000..1369c22fc --- /dev/null +++ b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +key_val_pair1=`echo $2 | cut -d ' ' -f 1` +key_val_pair2=`echo $2 | cut -d ' ' -f 2` +key_val_pair3=`echo $2 | cut -d ' ' -f 3` + +key=`echo $key_val_pair1 | cut -d '=' -f 1` +val=`echo $key_val_pair1 | cut -d '=' -f 2` +if [ "$key" != "is_push_pem" ]; then + exit; +fi +if [ "$val" != '1' ]; then + exit; +fi + +key=`echo $key_val_pair2 | cut -d '=' -f 1` +val=`echo $key_val_pair2 | cut -d '=' -f 2` +if [ "$key" != "pub_file" ]; then + exit; +fi +if [ "$val" == "" ]; then + exit; +fi +pub_file=`echo $val` +pub_file_tmp=`echo $val`_tmp + +key=`echo $key_val_pair3 | cut -d '=' -f 1` +val=`echo $key_val_pair3 | cut -d '=' -f 2` +if [ "$key" != "slave_ip" ]; then + exit; +fi +if [ "$val" == "" ]; then + exit; +fi +slave_ip=`echo $val` + +if [ -f $pub_file ]; then + scp $pub_file $slave_ip:$pub_file_tmp + ssh $slave_ip "mv $pub_file_tmp $pub_file" + ssh $slave_ip "gluster system:: copy file /geo-replication/common_secret.pem.pub > /dev/null" + ssh $slave_ip "gluster system:: execute add_secret_pub > /dev/null" +fi diff --git a/extras/init.d/Makefile.am b/extras/init.d/Makefile.am index 66715f431..38898fddd 100644 --- a/extras/init.d/Makefile.am +++ b/extras/init.d/Makefile.am @@ -1,19 +1,22 @@ -EXTRA_DIST = glusterd-Debian glusterd-Redhat glusterd-SuSE glusterd.plist +EXTRA_DIST = glusterd-Debian glusterd-Redhat glusterd-SuSE glusterd.plist rhel5-load-fuse.modules CLEANFILES = -initdir = @initdir@ -launchddir = @launchddir@ +INIT_DIR = @initdir@ +SYSTEMD_DIR = @systemddir@ +LAUNCHD_DIR = @launchddir@ $(GF_DISTRIBUTION): - $(mkdir_p) $(DESTDIR)$(initdir) - $(INSTALL_PROGRAM) glusterd-$(GF_DISTRIBUTION) $(DESTDIR)$(initdir)/glusterd + @if [ ! -d $(SYSTEMD_DIR) ]; then \ + $(mkdir_p) $(DESTDIR)$(INIT_DIR); \ + $(INSTALL_PROGRAM) glusterd-$(GF_DISTRIBUTION) $(DESTDIR)$(INIT_DIR)/glusterd; \ + fi install-exec-local: $(GF_DISTRIBUTION) install-data-local: if GF_DARWIN_HOST_OS - $(mkdir_p) $(DESTDIR)$(launchddir) - $(INSTALL_PROGRAM) glusterd.plist $(DESTDIR)$(launchddir)/com.gluster.glusterd.plist + $(mkdir_p) $(DESTDIR)$(LAUNCHD_DIR) + $(INSTALL_PROGRAM) glusterd.plist $(DESTDIR)$(LAUNCHD_DIR)/com.gluster.glusterd.plist endif diff --git a/extras/init.d/glusterd-Redhat.in b/extras/init.d/glusterd-Redhat.in index cf9d390f0..e320708ae 100755 --- a/extras/init.d/glusterd-Redhat.in +++ b/extras/init.d/glusterd-Redhat.in @@ -1,89 +1,142 @@ #!/bin/bash # -# chkconfig: 35 20 80 -# description: Gluster File System service for volume management +# glusterd Startup script for the glusterfs server # +# chkconfig: - 20 80 +# description: Clustered file-system server -# Get function from functions library +### BEGIN INIT INFO +# Provides: glusterd +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Should-Start: +# Should-Stop: +# Default-Start: +# Default-Stop: 0 1 2 3 4 5 6 +# Short-Description: glusterfs server +# Description: Clustered file-system server +### END INIT INFO +# + +# Source function library. . /etc/rc.d/init.d/functions BASE=glusterd -PIDFILE=/var/run/$BASE.pid + +# Fedora File System Layout dictates /run +[ -e /run ] && RUNDIR="/run" +PIDFILE="${RUNDIR:-/var/run}/${BASE}.pid" + PID=`test -f $PIDFILE && cat $PIDFILE` + +# Overwriteable from sysconfig +LOG_LEVEL='' +LOG_FILE='' +GLUSTERD_OPTIONS='' +GLUSTERD_NOFILE='65536' + +[ -f /etc/sysconfig/${BASE} ] && . /etc/sysconfig/${BASE} + +[ ! -z $LOG_LEVEL ] && GLUSTERD_OPTIONS="${GLUSTERD_OPTIONS} --log-level ${LOG_LEVEL}" +[ ! -z $LOG_FILE ] && GLUSTERD_OPTIONS="${GLUSTERD_OPTIONS} --log-file ${LOG_FILE}" + GLUSTERFSD=glusterfsd GLUSTERFS=glusterfs GLUSTERD_BIN=@prefix@/sbin/$BASE -GLUSTERD_OPTS="--pid-file=$PIDFILE" +GLUSTERD_OPTS="--pid-file=$PIDFILE ${GLUSTERD_OPTIONS}" GLUSTERD="$GLUSTERD_BIN $GLUSTERD_OPTS" RETVAL=0 +LOCKFILE=/var/lock/subsys/${BASE} + # Start the service $BASE start() { - pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null - status=$? - if [ $status -eq 0 ]; then + if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then echo "glusterd service is already running with pid $PID" - exit 1 + return 0 else + ulimit -n $GLUSTERD_NOFILE echo -n $"Starting $BASE:" daemon $GLUSTERD RETVAL=$? echo - [ $RETVAL -ne 0 ] && exit $RETVAL + [ $RETVAL -eq 0 ] && touch $LOCKFILE + return $RETVAL fi - } # Stop the service $BASE stop() { echo -n $"Stopping $BASE:" - pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null - status=$? - if [ $status -eq 0 ]; then + if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then killproc -p $PIDFILE $BASE - [ -w $PIDFILE ] && rm -f $PIDFILE else killproc $BASE fi + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f $LOCKFILE + return $RETVAL +} - echo - pidof -c -o %PPID -x $GLUSTERFSD &> /dev/null - [ $? -eq 0 ] && killproc $GLUSTERFSD &> /dev/null +restart() +{ + stop + start +} - #pidof -c -o %PPID -x $GLUSTERFS &> /dev/null - #[ $? -eq 0 ] && killproc $GLUSTERFS &> /dev/null +reload() +{ + restart +} - if [ -f /etc/glusterd/nfs/run/nfs.pid ] ;then - pid=`cat /etc/glusterd/nfs/run/nfs.pid`; - cmd=`ps -p $pid -o comm=` +force_reload() +{ + restart +} - if [ $cmd == "glusterfs" ]; then - kill `cat /etc/glusterd/nfs/run/nfs.pid` - fi - fi +rh_status() +{ + status $BASE +} + +rh_status_q() +{ + rh_status &>/dev/null } ### service arguments ### case $1 in start) - start + rh_status_q && exit 0 + $1 ;; stop) - stop + rh_status_q || exit 0 + $1 + ;; + restart) + $1 + ;; + reload) + rh_status_q || exit 7 + $1 + ;; + force-reload) + force_reload ;; status) - status $BASE + rh_status ;; - restart) - $0 stop - $0 start + condrestart|try-restart) + rh_status_q || exit 0 + restart ;; *) - echo $"Usage: $0 {start|stop|status|restart}." + echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 1 esac -exit 0 +exit $? diff --git a/extras/init.d/glusterd-SuSE.in b/extras/init.d/glusterd-SuSE.in index 16cf8de6a..6259bab00 100755 --- a/extras/init.d/glusterd-SuSE.in +++ b/extras/init.d/glusterd-SuSE.in @@ -2,8 +2,8 @@ # ### BEGIN INIT INFO # Provides: glusterd -# Required-Start: $local_fs $network -# Required-Stop: +# Required-Start: $remote_fs $network +# Required-Stop: $remote_fs $network # Default-Start: 3 5 # Default-Stop: # Short-Description: Gluster File System service for volume management @@ -61,13 +61,17 @@ case $1 in fi rc_status -v ;; + reload) + rc_failed 3 + rc_status -v + ;; restart) $0 stop $0 start rc_status ;; *) - echo $"Usage: $0 {start|stop|status|restart}." + echo $"Usage: $0 {start|stop|status|reload|restart}." exit 1 esac diff --git a/extras/init.d/rhel5-load-fuse.modules b/extras/init.d/rhel5-load-fuse.modules new file mode 100755 index 000000000..ee194db99 --- /dev/null +++ b/extras/init.d/rhel5-load-fuse.modules @@ -0,0 +1,7 @@ +#!/bin/sh +# +# fusermount-glusterfs requires the /dev/fuse character device. The fuse module +# provides this and is loaded on demand in newer Linux distributions. +# + +[ -c /dev/fuse ] || /sbin/modprobe fuse diff --git a/extras/logger.conf.example b/extras/logger.conf.example new file mode 100644 index 000000000..248be5bda --- /dev/null +++ b/extras/logger.conf.example @@ -0,0 +1,13 @@ +# +# Sample logger.conf file to configure enhanced Logging in GlusterFS +# +# To enable enhanced logging capabilities, +# +# 1. rename this file to /etc/glusterfs/logger.conf +# +# 2. rename /etc/rsyslog.d/gluster.conf.example to +# /etc/rsyslog.d/gluster.conf +# +# This change requires restart of all gluster services/volumes and +# rsyslog. +# diff --git a/extras/ocf/Makefile.am b/extras/ocf/Makefile.am new file mode 100644 index 000000000..c49a835fb --- /dev/null +++ b/extras/ocf/Makefile.am @@ -0,0 +1,11 @@ +EXTRA_DIST = glusterd.in volume.in + +# The root of the OCF resource agent hierarchy +# Per the OCF standard, it's always "lib", +# not "lib64" (even on 64-bit platforms). +ocfdir = $(prefix)/lib/ocf + +# The ceph provider directory +radir = $(ocfdir)/resource.d/$(PACKAGE_NAME) + +ra_SCRIPTS = glusterd volume diff --git a/extras/ocf/glusterd.in b/extras/ocf/glusterd.in new file mode 100755 index 000000000..c119a285d --- /dev/null +++ b/extras/ocf/glusterd.in @@ -0,0 +1,212 @@ +#!/bin/sh +# +# glusterd +# +# Description: Manages a glusterd server as a (typically cloned) +# HA resource +# +# Authors: Florian Haas (hastexo Professional Services GmbH) +# +# License: GNU General Public License (GPL) + +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Convenience variables +# When sysconfdir and localstatedir aren't passed in as +# configure flags, they're defined in terms of prefix +prefix=@prefix@ +####################################################################### + + +OCF_RESKEY_binary_default="glusterd" +OCF_RESKEY_pid_default="@localstatedir@/run/glusterd.pid" +OCF_RESKEY_socket_default="" +OCF_RESKEY_additional_parameters_default="" + +: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} +: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} + +glusterd_meta_data() { + cat <<EOF +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="glusterd" version="0.1"> + <version>0.1</version> + <longdesc lang="en"> + </longdesc> + <shortdesc lang="en">Manages a Gluster server</shortdesc> + <parameters> + <parameter name="binary"> + <longdesc lang="en"> + Name of the glusterd executable. Specify a full absolute + path if the binary is not in your \$PATH. + </longdesc> + <shortdesc lang="en">glusterd executable</shortdesc> + <content type="string" default="$OCF_RESKEY_binary_default"/> + </parameter> + <parameter name="pid"> + <longdesc lang="en"> + Path to the glusterd PID file. + </longdesc> + <shortdesc lang="en">PID file</shortdesc> + <content type="string" default="$OCF_RESKEY_pid_default"/> + </parameter> + <parameter name="socket"> + <longdesc lang="en"> + Path to the glusterd UNIX socket file. If unspecified, + glusterd will not listen on any socket. + </longdesc> + <shortdesc lang="en">Socket file</shortdesc> + <content type="string"/> + </parameter> + </parameters> + <actions> + <action name="start" timeout="20" /> + <action name="stop" timeout="20" /> + <action name="monitor" timeout="20" interval="10" /> + <action name="reload" timeout="20" /> + <action name="meta-data" timeout="5" /> + <action name="validate-all" timeout="20" /> + </actions> +</resource-agent> +EOF + +} + +glusterd_start() { + local glusterd_options + # exit immediately if configuration is not valid + glusterd_validate_all || exit $? + + # if resource is already running, bail out early + if glusterd_monitor; then + ocf_log info "Resource is already running" + return $OCF_SUCCESS + fi + + # actually start up the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + glusterd_options="-p $OCF_RESKEY_pid" + if [ -n "$OCF_RESKEY_socket" ]; then + glusterd_options="$glusterd_options -S $OCF_RESKEY_socket" + fi + if [ -n "$OCF_RESKEY_additional_parameters" ]; then + glusterd_options="$glusterd_options $OCF_RESKEY_additional_parameters" + fi + + ocf_run $OCF_RESKEY_binary $glusterd_options || exit $OCF_ERR_GENERIC + + # After the resource has been started, check whether it started up + # correctly. If the resource starts asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # start up within the defined timeout, the cluster manager will + # consider the start action failed + while ! glusterd_monitor; do + ocf_log debug "Resource has not started yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS +} + +glusterd_stop() { + local rc + local pid + + # exit immediately if configuration is not valid + glusterd_validate_all || exit $? + + glusterd_monitor + rc=$? + case "$rc" in + "$OCF_SUCCESS") + # Currently running. Normal, expected behavior. + ocf_log debug "Resource is currently running" + ;; + "$OCF_NOT_RUNNING") + # Currently not running. Nothing to do. + ocf_log info "Resource is already stopped" + return $OCF_SUCCESS + ;; + esac + + # actually shut down the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + pid=`cat $OCF_RESKEY_pid` + ocf_run kill -s TERM $pid || exit OCF_ERR_GENERIC + + # After the resource has been stopped, check whether it shut down + # correctly. If the resource stops asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # shut down within the defined timeout, the cluster manager will + # consider the stop action failed + while glusterd_monitor; do + ocf_log debug "Resource has not stopped yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS + +} + +glusterd_monitor() { + local pid + + [ -e $OCF_RESKEY_pid ] || return $OCF_NOT_RUNNING + + pid=`cat $OCF_RESKEY_pid` + ocf_run kill -s 0 $pid || return $OCF_NOT_RUNNING + + ocf_log debug "$OCF_RESKEY_binary running with PID $pid" + return $OCF_SUCCESS +} + +glusterd_validate_all() { + # Test for required binaries + check_binary $OCF_RESKEY_binary + + return $OCF_SUCCESS +} + + + +# Make sure meta-data and usage always succeed +case $__OCF_ACTION in +meta-data) glusterd_meta_data + exit $OCF_SUCCESS + ;; +usage|help) glusterd_usage + exit $OCF_SUCCESS + ;; +esac + +# Anything other than meta-data and usage must pass validation +glusterd_validate_all || exit $? + +# Translate each action into the appropriate function call +case $__OCF_ACTION in +start) glusterd_start;; +stop) glusterd_stop;; +status|monitor) glusterd_monitor;; +reload) ocf_log info "Reloading..." + glusterd_start + ;; +validate-all) ;; +notify) exit $OCF_SUCCESS;; +*) glusterd_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac +rc=$? + +# The resource agent may optionally log a debug message +ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc" +exit $rc diff --git a/extras/ocf/volume.in b/extras/ocf/volume.in new file mode 100755 index 000000000..72fd1213a --- /dev/null +++ b/extras/ocf/volume.in @@ -0,0 +1,246 @@ +#!/bin/sh +# +# glusterd +# +# Description: Manages a glusterd server as a (typically cloned) +# HA resource +# +# Authors: Florian Haas (hastexo Professional Services GmbH) +# +# License: GNU General Public License (GPL) + +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Convenience variables +# When sysconfdir and localstatedir aren't passed in as +# configure flags, they're defined in terms of prefix +prefix=@prefix@ +SHORTHOSTNAME=`hostname -s` +####################################################################### + +OCF_RESKEY_binary_default="gluster" + +: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} + +volume_meta_data() { + cat <<EOF +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="volume" version="0.1"> + <version>0.1</version> + <longdesc lang="en"> +Manages a GlusterFS volume and monitors its bricks. When a resource of +this type is configured as a clone (as is commonly the case), then it +must have clone ordering enabled. + </longdesc> + <shortdesc lang="en">Manages a GlusterFS volume</shortdesc> + <parameters> + <parameter name="volname" required="1"> + <longdesc lang="en"> + The name of the volume to manage. + </longdesc> + <shortdesc lang="en">volume name</shortdesc> + <content type="string"/> + </parameter> + <parameter name="binary"> + <longdesc lang="en"> + Name of the gluster executable. Specify a full absolute + path if the binary is not in your \$PATH. + </longdesc> + <shortdesc lang="en">gluster executable</shortdesc> + <content type="string" default="$OCF_RESKEY_binary_default"/> + </parameter> + </parameters> + <actions> + <action name="start" timeout="20" /> + <action name="stop" timeout="20" /> + <action name="monitor" timeout="20" interval="10" /> + <action name="reload" timeout="20" /> + <action name="meta-data" timeout="5" /> + <action name="validate-all" timeout="20" /> + </actions> +</resource-agent> +EOF + +} + +volume_getdir() { + local voldir + voldir="@sysconfdir@/glusterd/vols/${OCF_RESKEY_volname}" + + [ -d ${voldir} ] || return 1 + + echo "${voldir}" + return 0 +} + +volume_getbricks() { + local infofile + local voldir + voldir=`volume_getdir` + infofile="${voldir}/info" + + [ -e ${infofile} ] || return 1 + + echo "`sed -n -e "s/^brick-.\+=${SHORTHOSTNAME}://p" < ${infofile}`" + return 0 +} + +volume_getpids() { + local bricks + local piddir + local pidfile + local infofile + local voldir + + voldir=`volume_getdir` + bricks=`volume_getbricks` + piddir="${voldir}/run" + + for brick in ${bricks}; do + pidfile="${piddir}/${SHORTHOSTNAME}${brick}.pid" + [ -e $pidfile ] || return 1 + cat $pidfile + done + + return 0 +} + +volume_start() { + local volume_options + + # exit immediately if configuration is not valid + volume_validate_all || exit $? + + # if resource is already running, bail out early + if volume_monitor; then + ocf_log info "Resource is already running" + return $OCF_SUCCESS + fi + + # actually start up the resource here + ocf_run "$OCF_RESKEY_binary" \ + volume start "$OCF_RESKEY_volname" force || exit $OCF_ERR_GENERIC + + # After the resource has been started, check whether it started up + # correctly. If the resource starts asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # start up within the defined timeout, the cluster manager will + # consider the start action failed + while ! volume_monitor; do + ocf_log debug "Resource has not started yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS +} + +volume_stop() { + local rc + local pid + + # exit immediately if configuration is not valid + volume_validate_all || exit $? + + volume_monitor + rc=$? + case "$rc" in + "$OCF_SUCCESS") + # Currently running. Normal, expected behavior. + ocf_log debug "Resource is currently running" + ;; + "$OCF_NOT_RUNNING") + # Currently not running. Nothing to do. + ocf_log info "Resource is already stopped" + return $OCF_SUCCESS + ;; + esac + + # actually shut down the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + pids=`volume_getpids` + for pid in $pids; do + ocf_run kill -s TERM $pid + done + + # After the resource has been stopped, check whether it shut down + # correctly. If the resource stops asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # shut down within the defined timeout, the cluster manager will + # consider the stop action failed + while volume_monitor; do + ocf_log debug "Resource has not stopped yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS + +} + +volume_monitor() { + local pid + + pids=`volume_getpids` || return $OCF_NOT_RUNNING + + for pid in $pids; do + ocf_run kill -s 0 $pid || return $OCF_NOT_RUNNING + done + + ocf_log debug "Local bricks for volume ${OCF_RESKEY_volname} running with PIDs $pids" + return $OCF_SUCCESS +} + +volume_validate_all() { + # Test for configuration errors first + if [ -z "${OCF_RESKEY_volname}" ]; then + ocf_log err 'Missing required parameter "volname"' + return $OCF_ERR_CONFIGURED + fi + + # Test for required binaries + check_binary $OCF_RESKEY_binary + + return $OCF_SUCCESS +} + + + +# Make sure meta-data and usage always succeed +case $__OCF_ACTION in +meta-data) volume_meta_data + exit $OCF_SUCCESS + ;; +usage|help) volume_usage + exit $OCF_SUCCESS + ;; +esac + +# Anything other than meta-data and usage must pass validation +volume_validate_all || exit $? + +# Translate each action into the appropriate function call +case $__OCF_ACTION in +start) volume_start;; +stop) volume_stop;; +status|monitor) volume_monitor;; +reload) ocf_log info "Reloading..." + volume_start + ;; +validate-all) ;; +notify) exit $OCF_SUCCESS;; +*) volume_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac +rc=$? + +# The resource agent may optionally log a debug message +ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc" +exit $rc diff --git a/extras/profiler/glusterfs-profiler b/extras/profiler/glusterfs-profiler index 042eadcf2..65d445864 100755 --- a/extras/profiler/glusterfs-profiler +++ b/extras/profiler/glusterfs-profiler @@ -1,22 +1,15 @@ #!/usr/bin/env python -# texttable - module for creating simple ASCII tables -# Copyright (C) 2003-2010 Gerome Fournier <jefke(at)free.fr> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. +# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> +# This file is part of GlusterFS. # -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. + +# texttable - module for creating simple ASCII tables # Incorporated from texttable.py downloaded from # http://jefke.free.fr/stuff/python/texttable/texttable-0.7.0.tar.gz diff --git a/extras/prot_filter.py b/extras/prot_filter.py new file mode 100755 index 000000000..7dccacf15 --- /dev/null +++ b/extras/prot_filter.py @@ -0,0 +1,144 @@ +#!/usr/bin/python + +""" + Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +""" + +""" + INSTRUCTIONS + Put this in /usr/lib64/glusterfs/$version/filter to have it run automatically, + or else you'll have to run it by hand every time you change the volume + configuration. Give it a list of volume names on which to enable the + protection functionality; it will deliberately ignore client volfiles for + other volumes, and all server volfiles. It *will* include internal client + volfiles such as those used for NFS or rebalance/self-heal; this is a + deliberate choice so that it will catch deletions from those sources as well. +""" + +volume_list = [ "jdtest" ] + +import copy +import string +import sys +import types + +class Translator: + def __init__ (self, name): + self.name = name + self.xl_type = "" + self.opts = {} + self.subvols = [] + self.dumped = False + def __repr__ (self): + return "<Translator %s>" % self.name + +def load (path): + # If it's a string, open it; otherwise, assume it's already a + # file-like object (most notably from urllib*). + if type(path) in types.StringTypes: + fp = file(path,"r") + else: + fp = path + all_xlators = {} + xlator = None + last_xlator = None + while True: + text = fp.readline() + if text == "": + break + text = text.split() + if not len(text): + continue + if text[0] == "volume": + if xlator: + raise RuntimeError, "nested volume definition" + xlator = Translator(text[1]) + continue + if not xlator: + raise RuntimeError, "text outside volume definition" + if text[0] == "type": + xlator.xl_type = text[1] + continue + if text[0] == "option": + xlator.opts[text[1]] = string.join(text[2:]) + continue + if text[0] == "subvolumes": + for sv in text[1:]: + xlator.subvols.append(all_xlators[sv]) + continue + if text[0] == "end-volume": + all_xlators[xlator.name] = xlator + last_xlator = xlator + xlator = None + continue + raise RuntimeError, "unrecognized keyword %s" % text[0] + if xlator: + raise RuntimeError, "unclosed volume definition" + return all_xlators, last_xlator + +def generate (graph, last, stream=sys.stdout): + for sv in last.subvols: + if not sv.dumped: + generate(graph,sv,stream) + print >> stream, "" + sv.dumped = True + print >> stream, "volume %s" % last.name + print >> stream, " type %s" % last.xl_type + for k, v in last.opts.iteritems(): + print >> stream, " option %s %s" % (k, v) + if last.subvols: + print >> stream, " subvolumes %s" % string.join( + [ sv.name for sv in last.subvols ]) + print >> stream, "end-volume" + +def push_filter (graph, old_xl, filt_type, opts={}): + new_type = "-" + filt_type.split("/")[1] + old_type = "-" + old_xl.xl_type.split("/")[1] + pos = old_xl.name.find(old_type) + if pos >= 0: + new_name = old_xl.name + old_name = new_name[:pos] + new_type + new_name[len(old_type)+pos:] + else: + new_name = old_xl.name + old_type + old_name = old_xl.name + new_type + new_xl = Translator(new_name) + new_xl.xl_type = old_xl.xl_type + new_xl.opts = old_xl.opts + new_xl.subvols = old_xl.subvols + graph[new_xl.name] = new_xl + old_xl.name = old_name + old_xl.xl_type = filt_type + old_xl.opts = opts + old_xl.subvols = [new_xl] + graph[old_xl.name] = old_xl + +if __name__ == "__main__": + path = sys.argv[1] + # Alow an override for debugging. + for extra in sys.argv[2:]: + volume_list.append(extra) + graph, last = load(path) + for v in volume_list: + if graph.has_key(v): + break + else: + print "No configured volumes found - aborting." + sys.exit(0) + for v in graph.values(): + if v.xl_type == "cluster/distribute": + push_filter(graph,v,"features/prot_dht") + elif v.xl_type == "protocol/client": + push_filter(graph,v,"features/prot_client") + # We push debug/trace so that every fop gets a real frame, because DHT + # gets confused if STACK_WIND_TAIL causes certain fops to be invoked + # from anything other than a direct child. + for v in graph.values(): + if v.xl_type == "features/prot_client": + push_filter(graph,v,"debug/trace") + generate(graph,last,stream=open(path,"w")) diff --git a/extras/rebalance.py b/extras/rebalance.py new file mode 100755 index 000000000..80c614c5d --- /dev/null +++ b/extras/rebalance.py @@ -0,0 +1,299 @@ +#!/usr/bin/python + +import atexit +import copy +import optparse +import os +import pipes +import shutil +import string +import subprocess +import sys +import tempfile +import volfilter + +# It's just more convenient to have named fields. +class Brick: + def __init__ (self, path, name): + self.path = path + self.sv_name = name + self.size = 0 + self.curr_size = 0 + self.good_size = 0 + def set_size (self, size): + self.size = size + def set_range (self, rs, re): + self.r_start = rs + self.r_end = re + self.curr_size = self.r_end - self.r_start + 1 + def __repr__ (self): + value = self.path[:] + value += "(%d," % self.size + if self.curr_size: + value += "0x%x,0x%x)" % (self.r_start, self.r_end) + else: + value += "-)" + return value + +def get_bricks (host, vol): + t = pipes.Template() + t.prepend("gluster --remote-host=%s system getspec %s"%(host,vol),".-") + return t.open(None,"r") + +def generate_stanza (vf, all_xlators, cur_subvol): + sv_list = [] + for sv in cur_subvol.subvols: + generate_stanza(vf,all_xlators,sv) + sv_list.append(sv.name) + vf.write("volume %s\n"%cur_subvol.name) + vf.write(" type %s\n"%cur_subvol.type) + for kvpair in cur_subvol.opts.iteritems(): + vf.write(" option %s %s\n"%kvpair) + if sv_list: + vf.write(" subvolumes %s\n"%string.join(sv_list)) + vf.write("end-volume\n\n") + + +def mount_brick (localpath, all_xlators, dht_subvol): + + # Generate a volfile. + vf_name = localpath + ".vol" + vf = open(vf_name,"w") + generate_stanza(vf,all_xlators,dht_subvol) + vf.flush() + vf.close() + + # Create a brick directory and mount the brick there. + os.mkdir(localpath) + subprocess.call(["glusterfs","-f",vf_name,localpath]) + +# We use the command-line tools because there's no getxattr support in the +# Python standard library (which is ridiculous IMO). Adding the xattr package +# from PyPI would create a new and difficult dependency because the bits to +# satisfy it don't seem to exist in Fedora. We already expect the command-line +# tools to be there, so it's safer just to rely on them. +# +# We might have to revisit this if we get as far as actually issuing millions +# of setxattr requests. Even then, it might be better to do that part with a C +# program which has only a build-time dependency. +def get_range (brick): + t = pipes.Template() + cmd = "getfattr -e hex -n trusted.glusterfs.dht %s 2> /dev/null" + t.prepend(cmd%brick,".-") + t.append("grep ^trusted.glusterfs.dht=","--") + f = t.open(None,"r") + try: + value = f.readline().rstrip().split('=')[1][2:] + except: + print "could not get layout for %s (might be OK)" % brick + return None + v_start = int("0x"+value[16:24],16) + v_end = int("0x"+value[24:32],16) + return (v_start, v_end) + +def calc_sizes (bricks, total): + leftover = 1 << 32 + for b in bricks: + if b.size: + b.good_size = (b.size << 32) / total + leftover -= b.good_size + else: + b.good_size = 0 + if leftover: + # Add the leftover to an old brick if we can. + for b in bricks: + if b.good_size: + b.good_size += leftover + break + else: + # Fine, just add it wherever. + bricks[0].good_size += leftover + +# Normalization means sorting the bricks by r_start and (b) ensuring that there +# are no gaps. +def normalize (in_bricks): + out_bricks = [] + curr_hash = 0 + used = 0 + while curr_hash < (1<<32): + curr_best = None + for b in in_bricks: + if b.r_start == curr_hash: + used += 1 + out_bricks.append(b) + in_bricks.remove(b) + curr_hash = b.r_end + 1 + break + else: + print "gap found at 0x%08x" % curr_hash + sys.exit(1) + return out_bricks + in_bricks, used + +def get_score (bricks): + score = 0 + curr_hash = 0 + for b in bricks: + if not b.curr_size: + curr_hash += b.good_size + continue + new_start = curr_hash + curr_hash += b.good_size + new_end = curr_hash - 1 + if new_start > b.r_start: + max_start = new_start + else: + max_start = b.r_start + if new_end < b.r_end: + min_end = new_end + else: + min_end = b.r_end + if max_start <= min_end: + score += (min_end - max_start + 1) + return score + +if __name__ == "__main__": + + my_usage = "%prog [options] server volume [directory]" + parser = optparse.OptionParser(usage=my_usage) + parser.add_option("-f", "--free-space", dest="free_space", + default=False, action="store_true", + help="use free space instead of total space") + parser.add_option("-l", "--leave-mounted", dest="leave_mounted", + default=False, action="store_true", + help="leave subvolumes mounted") + parser.add_option("-v", "--verbose", dest="verbose", + default=False, action="store_true", + help="verbose output") + options, args = parser.parse_args() + + if len(args) == 3: + fix_dir = args[2] + else: + if len(args) != 2: + parser.print_help() + sys.exit(1) + fix_dir = None + hostname, volname = args[:2] + + # Make sure stuff gets cleaned up, even if there are exceptions. + orig_dir = os.getcwd() + work_dir = tempfile.mkdtemp() + bricks = [] + def cleanup_workdir (): + os.chdir(orig_dir) + if options.verbose: + print "Cleaning up %s" % work_dir + for b in bricks: + subprocess.call(["umount",b.path]) + shutil.rmtree(work_dir) + if not options.leave_mounted: + atexit.register(cleanup_workdir) + os.chdir(work_dir) + + # Mount each brick individually, so we can issue brick-specific calls. + if options.verbose: + print "Mounting subvolumes..." + index = 0 + volfile_pipe = get_bricks(hostname,volname) + all_xlators, last_xlator = volfilter.load(volfile_pipe) + for dht_vol in all_xlators.itervalues(): + if dht_vol.type == "cluster/distribute": + break + else: + print "no DHT volume found" + sys.exit(1) + for sv in dht_vol.subvols: + #print "found subvol %s" % sv.name + lpath = "%s/brick%s" % (work_dir, index) + index += 1 + mount_brick(lpath,all_xlators,sv) + bricks.append(Brick(lpath,sv.name)) + if index == 0: + print "no bricks" + sys.exit(1) + + # Collect all of the sizes. + if options.verbose: + print "Collecting information..." + total = 0 + for b in bricks: + info = os.statvfs(b.path) + # We want a standard unit even if different bricks use + # different block sizes. The size is chosen to avoid overflows + # for very large bricks with very small block sizes, but also + # accommodate filesystems which use very large block sizes to + # cheat on benchmarks. + blocksper100mb = 104857600 / info[0] + if options.free_space: + size = info[3] / blocksper100mb + else: + size = info[2] / blocksper100mb + if size <= 0: + print "brick %s has invalid size %d" % (b.path, size) + sys.exit(1) + b.set_size(size) + total += size + + # Collect all of the layout information. + for b in bricks: + hash_range = get_range(b.path) + if hash_range is not None: + rs, re = hash_range + if rs > re: + print "%s has backwards hash range" % b.path + sys.exit(1) + b.set_range(hash_range[0],hash_range[1]) + + if options.verbose: + print "Calculating new layouts..." + calc_sizes(bricks,total) + bricks, used = normalize(bricks) + + # We can't afford O(n!) here, but O(n^2) should be OK and the result + # should be almost as good. + while used < len(bricks): + best_place = used + best_score = get_score(bricks) + for i in xrange(used): + new_bricks = bricks[:] + del new_bricks[used] + new_bricks.insert(i,bricks[used]) + new_score = get_score(new_bricks) + if new_score > best_score: + best_place = i + best_score = new_score + if best_place != used: + nb = bricks[used] + del bricks[used] + bricks.insert(best_place,nb) + used += 1 + + # Finalize whatever we decided on. + curr_hash = 0 + for b in bricks: + b.r_start = curr_hash + curr_hash += b.good_size + b.r_end = curr_hash - 1 + + print "Here are the xattr values for your size-weighted layout:" + for b in bricks: + print " %s: 0x0000000200000000%08x%08x" % ( + b.sv_name, b.r_start, b.r_end) + + if fix_dir: + if options.verbose: + print "Fixing layout for %s" % fix_dir + for b in bricks: + value = "0x0000000200000000%08x%08x" % ( + b.r_start, b.r_end) + path = "%s/%s" % (b.path, fix_dir) + cmd = "setfattr -n trusted.glusterfs.dht -v %s %s" % ( + value, path) + print cmd + + if options.leave_mounted: + print "The following subvolumes are still mounted:" + for b in bricks: + print "%s on %s" % (b.sv_name, b.path) + print "Don't forget to clean up when you're done." + diff --git a/extras/rpc-coverage.sh b/extras/rpc-coverage.sh index ebb92a2a1..9148a73e2 100755 --- a/extras/rpc-coverage.sh +++ b/extras/rpc-coverage.sh @@ -398,8 +398,7 @@ function test_getxattr() function test_removexattr() { setfattr -x trusted.testing $PFX/dir/file || fail "setfattr remove" - getfattr -n trusted.testing $PFX/dir/file 2>&1 | grep -q 'No such attribute' \ - || fail "getfattr" + getfattr -n trusted.testing $PFXf/dir/file 2>&1 | grep -q "No such attribute" } diff --git a/extras/stripe-merge.c b/extras/stripe-merge.c index 3f8e4b124..74bd47e30 100644 --- a/extras/stripe-merge.c +++ b/extras/stripe-merge.c @@ -1,48 +1,494 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* + * stripe-merge.c + * + * This program recovers an original file based on the striped files stored on + * the individual bricks of a striped volume. The file format and stripe + * geometry is validated through the extended attributes stored in the file. + * + * TODO: Support optional xattr recovery (i.e., user xattrs). Perhaps provide a + * command-line flag to toggle this behavior. + */ + #include <stdio.h> -#include <unistd.h> -#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> +#include <string.h> +#include <attr/xattr.h> +#include <fnmatch.h> -int -main (int argc, char *argv[]) +#define ATTRNAME_STRIPE_INDEX "trusted.*.stripe-index" +#define ATTRNAME_STRIPE_COUNT "trusted.*.stripe-count" +#define ATTRNAME_STRIPE_SIZE "trusted.*.stripe-size" +#define ATTRNAME_STRIPE_COALESCE "trusted.*.stripe-coalesce" + +#define INVALID_FD -1 +#define INVALID_MODE UINT32_MAX + +struct file_stripe_info { + int stripe_count; + int stripe_size; + int coalesce; + mode_t mode; + int fd[0]; +}; + +static int close_files(struct file_stripe_info *); + +static struct +file_stripe_info *alloc_file_stripe_info(int count) { - int fds[argc-1]; - char buf[argc-1][4096]; int i; - int max_ret, ret; + struct file_stripe_info *finfo; - if (argc < 2) { - printf ("Usage: %s file1 file2 ... >file\n", argv[0]); - return 1; + finfo = calloc(1, sizeof(struct file_stripe_info) + + (sizeof(int) * count)); + if (!finfo) + return NULL; + + for (i = 0; i < count; i++) + finfo->fd[i] = INVALID_FD; + + finfo->mode = INVALID_MODE; + finfo->coalesce = INVALID_FD; + + return finfo; +} + +/* + * Search for an attribute matching the provided pattern. Return a count for + * the total number of matching entries (including 0). Allocate a buffer for + * the first matching entry found. + */ +static int +get_stripe_attr_name(const char *path, const char *pattern, char **attrname) +{ + char attrbuf[4096]; + char *ptr, *match = NULL; + int len, r, match_count = 0; + + if (!path || !pattern || !attrname) + return -1; + + len = listxattr(path, attrbuf, sizeof(attrbuf)); + if (len < 0) + return len; + + ptr = attrbuf; + while (ptr) { + r = fnmatch(pattern, ptr, 0); + if (!r) { + if (!match) + match = ptr; + match_count++; + } else if (r != FNM_NOMATCH) { + return -1; + } + + len -= strlen(ptr) + 1; + if (len > 0) + ptr += strlen(ptr) + 1; + else + ptr = NULL; } - for (i=0; i<argc-1; i++) { - fds[i] = open (argv[i+1], O_RDONLY); - if (fds[i] == -1) { - perror (argv[i+1]); - return 1; + if (match) + *attrname = strdup(match); + + return match_count; +} + +/* + * Get the integer representation of a named attribute. + */ +static int +get_stripe_attr_val(const char *path, const char *attr, int *val) +{ + char attrbuf[4096]; + int len; + + if (!path || !attr || !val) + return -1; + + len = getxattr(path, attr, attrbuf, sizeof(attrbuf)); + if (len < 0) + return len; + + *val = atoi(attrbuf); + + return 0; +} + +/* + * Get an attribute name/value (assumed to be an integer) pair based on a + * specified search pattern. A buffer is allocated for the exact attr name + * returned. Optionally, skip the pattern search if a buffer is provided + * (which should contain an attribute name). + * + * Returns the attribute count or -1 on error. The value parameter is set only + * when a single attribute is found. + */ +static int +get_attr(const char *path, const char *pattern, char **buf, int *val) +{ + int count = 1; + + if (!buf) + return -1; + + if (!*buf) { + count = get_stripe_attr_name(path, pattern, buf); + if (count > 1) { + /* pattern isn't good enough */ + fprintf(stderr, "ERROR: duplicate attributes found " + "matching pattern: %s\n", pattern); + free(*buf); + *buf = NULL; + return count; + } else if (count < 1) { + return count; } } - max_ret = 0; + if (get_stripe_attr_val(path, *buf, val) < 0) + return -1; + + return count; +} + +/* + * validate_and_open_files() + * + * Open the provided source files and validate the extended attributes. Verify + * that the geometric attributes are consistent across all of the files and + * print a warning if any files are missing. We proceed without error in the + * latter case to support partial recovery. + */ +static struct +file_stripe_info *validate_and_open_files(char *paths[], int count) +{ + int i, val, tmp; + struct stat sbuf; + char *stripe_count_attr = NULL; + char *stripe_size_attr = NULL; + char *stripe_index_attr = NULL; + char *stripe_coalesce_attr = NULL; + struct file_stripe_info *finfo = NULL; + + for (i = 0; i < count; i++) { + if (!paths[i]) + goto err; + + /* + * Check the stripe count first so we can allocate the info + * struct with the appropriate number of fds. + */ + if (get_attr(paths[i], ATTRNAME_STRIPE_COUNT, + &stripe_count_attr, &val) != 1) { + fprintf(stderr, "ERROR: %s: attribute: '%s'\n", + paths[i], ATTRNAME_STRIPE_COUNT); + goto err; + } + if (!finfo) { + finfo = alloc_file_stripe_info(val); + if (!finfo) + goto err; + + if (val != count) + fprintf(stderr, "WARNING: %s: stripe-count " + "(%d) != file count (%d). Result may " + "be incomplete.\n", paths[i], val, + count); + + finfo->stripe_count = val; + } else if (val != finfo->stripe_count) { + fprintf(stderr, "ERROR %s: invalid stripe count: %d " + "(expected %d)\n", paths[i], val, + finfo->stripe_count); + goto err; + } + + /* + * Get and validate the chunk size. + */ + if (get_attr(paths[i], ATTRNAME_STRIPE_SIZE, &stripe_size_attr, + &val) != 1) { + fprintf(stderr, "ERROR: %s: attribute: '%s'\n", + paths[i], ATTRNAME_STRIPE_SIZE); + goto err; + } + + if (!finfo->stripe_size) { + finfo->stripe_size = val; + } else if (val != finfo->stripe_size) { + fprintf(stderr, "ERROR: %s: invalid stripe size: %d " + "(expected %d)\n", paths[i], val, + finfo->stripe_size); + goto err; + } + + /* + * stripe-coalesce is a backward compatible attribute. If the + * attribute does not exist, assume a value of zero for the + * traditional stripe format. + */ + tmp = get_attr(paths[i], ATTRNAME_STRIPE_COALESCE, + &stripe_coalesce_attr, &val); + if (!tmp) { + val = 0; + } else if (tmp != 1) { + fprintf(stderr, "ERROR: %s: attribute: '%s'\n", + paths[i], ATTRNAME_STRIPE_COALESCE); + goto err; + } + + if (finfo->coalesce == INVALID_FD) { + finfo->coalesce = val; + } else if (val != finfo->coalesce) { + fprintf(stderr, "ERROR: %s: invalid coalesce flag\n", + paths[i]); + goto err; + } + + /* + * Get/validate the stripe index and open the file in the + * appropriate fd slot. + */ + if (get_attr(paths[i], ATTRNAME_STRIPE_INDEX, + &stripe_index_attr, &val) != 1) { + fprintf(stderr, "ERROR: %s: attribute: '%s'\n", + paths[i], ATTRNAME_STRIPE_INDEX); + goto err; + } + if (finfo->fd[val] != INVALID_FD) { + fprintf(stderr, "ERROR: %s: duplicate stripe index: " + "%d\n", paths[i], val); + goto err; + } + + finfo->fd[val] = open(paths[i], O_RDONLY); + if (finfo->fd[val] < 0) + goto err; + + /* + * Get the creation mode for the file. + */ + if (fstat(finfo->fd[val], &sbuf) < 0) + goto err; + if (finfo->mode == INVALID_MODE) { + finfo->mode = sbuf.st_mode; + } else if (sbuf.st_mode != finfo->mode) { + fprintf(stderr, "ERROR: %s: invalid mode\n", paths[i]); + goto err; + } + } + + free(stripe_count_attr); + free(stripe_size_attr); + free(stripe_index_attr); + free(stripe_coalesce_attr); + + return finfo; +err: + + free(stripe_count_attr); + free(stripe_size_attr); + free(stripe_index_attr); + free(stripe_coalesce_attr); + + if (finfo) { + close_files(finfo); + free(finfo); + } + + return NULL; +} + +static int +close_files(struct file_stripe_info *finfo) +{ + int i, ret; + + if (!finfo) + return -1; + + for (i = 0; i < finfo->stripe_count; i++) { + if (finfo->fd[i] == INVALID_FD) + continue; + + ret = close(finfo->fd[i]); + if (ret < 0) + return ret; + } + + return ret; +} + +/* + * Generate the original file using files striped in the coalesced format. + * Data in the striped files is stored at a coalesced offset based on the + * stripe number. + * + * Walk through the finfo fds (which are already ordered) and and iteratively + * copy stripe_size bytes from the source files to the target file. If a source + * file is missing, seek past the associated stripe_size bytes in the target + * file. + */ +static int +generate_file_coalesce(int target, struct file_stripe_info *finfo) +{ + char *buf; + int ret = 0; + int r, w, i; + + buf = malloc(finfo->stripe_size); + if (!buf) + return -1; + + i = 0; + while (1) { + if (finfo->fd[i] == INVALID_FD) { + if (lseek(target, finfo->stripe_size, SEEK_CUR) < 0) + break; + + i = (i + 1) % finfo->stripe_count; + continue; + } + + r = read(finfo->fd[i], buf, finfo->stripe_size); + if (r < 0) { + ret = r; + break; + } + if (!r) + break; + + w = write(target, buf, r); + if (w < 0) { + ret = w; + break; + } + + i = (i + 1) % finfo->stripe_count; + } + + free(buf); + return ret; +} + +/* + * Generate the original file using files striped with the traditional stripe + * format. Data in the striped files is stored at the equivalent offset from + * the source file. + */ +static int +generate_file_traditional(int target, struct file_stripe_info *finfo) +{ + int i, j, max_ret, ret; + char buf[finfo->stripe_count][4096]; + do { char newbuf[4096] = {0, }; - int j; max_ret = 0; - for (i=0; i<argc-1; i++) { - memset (buf[i], 0, 4096); - ret = read (fds[i], buf[i], 4096); + for (i = 0; i < finfo->stripe_count; i++) { + memset(buf[i], 0, 4096); + ret = read(finfo->fd[i], buf[i], 4096); if (ret > max_ret) max_ret = ret; } - for (i=0; i<max_ret;i++) - for (j=0; j<argc-1; j++) + for (i = 0; i < max_ret; i++) + for (j = 0; j < finfo->stripe_count; j++) newbuf[i] |= buf[j][i]; - write (1, newbuf, max_ret); + write(target, newbuf, max_ret); } while (max_ret); return 0; } +static int +generate_file(int target, struct file_stripe_info *finfo) +{ + if (finfo->coalesce) + return generate_file_coalesce(target, finfo); + + return generate_file_traditional(target, finfo); +} + +static void +usage(char *name) +{ + fprintf(stderr, "Usage: %s [-o <outputfile>] <inputfile1> " + "<inputfile2> ...\n", name); +} + +int +main(int argc, char *argv[]) +{ + int file_count, opt; + char *opath = NULL; + int targetfd; + struct file_stripe_info *finfo; + + while ((opt = getopt(argc, argv, "o:")) != -1) { + switch (opt) { + case 'o': + opath = optarg; + break; + default: + usage(argv[0]); + return -1; + } + } + + file_count = argc - optind; + + if (!opath || !file_count) { + usage(argv[0]); + return -1; + } + + finfo = validate_and_open_files(&argv[optind], file_count); + if (!finfo) + goto err; + + targetfd = open(opath, O_RDWR|O_CREAT, finfo->mode); + if (targetfd < 0) + goto err; + + if (generate_file(targetfd, finfo) < 0) + goto err; + + if (fsync(targetfd) < 0) + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + if (close(targetfd) < 0) + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + + close_files(finfo); + free(finfo); + + return 0; + +err: + if (finfo) { + close_files(finfo); + free(finfo); + } + + return -1; +} + diff --git a/extras/systemd/Makefile.am b/extras/systemd/Makefile.am new file mode 100644 index 000000000..3fc656b82 --- /dev/null +++ b/extras/systemd/Makefile.am @@ -0,0 +1,11 @@ + +CLEANFILES = + +SYSTEMD_DIR = @systemddir@ + +install-exec-local: + @if [ -d $(SYSTEMD_DIR) ]; then \ + $(mkdir_p) $(DESTDIR)$(SYSTEMD_DIR); \ + $(INSTALL_PROGRAM) glusterd.service $(DESTDIR)$(SYSTEMD_DIR)/; \ + fi + diff --git a/extras/systemd/glusterd.service.in b/extras/systemd/glusterd.service.in new file mode 100644 index 000000000..fc8d8c9a2 --- /dev/null +++ b/extras/systemd/glusterd.service.in @@ -0,0 +1,14 @@ +[Unit] +Description=GlusterFS, a clustered file-system server +After=network.target rpcbind.service +Before=network-online.target + +[Service] +Type=forking +PIDFile=/run/glusterd.pid +LimitNOFILE=65536 +ExecStart=@prefix@/sbin/glusterd -p /run/glusterd.pid +KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/extras/test/bug-920583.t b/extras/test/bug-920583.t new file mode 100755 index 000000000..eedbb800a --- /dev/null +++ b/extras/test/bug-920583.t @@ -0,0 +1,50 @@ +#!/bin/bash + +##Copy this file to tests/bugs before running run.sh (cp extras/test/bug-920583.t tests/bugs/) + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; +logdir=`gluster --print-logdir` + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; + +## Verify volume is is created +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; + +## Start volume and verify +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +function log-file-name() +{ + logfilename=$M0".log" + echo ${logfilename:1} | tr / - +} + +log_file=$logdir"/"`log-file-name` + +lookup_unhashed_count=`grep "adding option 'lookup-unhashed'" $log_file | wc -l` +no_child_down_count=`grep "adding option 'assert-no-child-down'" $log_file | wc -l` +mount -t glusterfs $H0:/$V0 $M0 -o "xlator-option=*dht.assert-no-child-down=yes,xlator-option=*dht.lookup-unhashed=yes" +touch $M0/file1; + +new_lookup_unhashed_count=`grep "adding option 'lookup-unhashed'" $log_file | wc -l` +new_no_child_down_count=`grep "adding option 'assert-no-child-down'" $log_file | wc -l` +EXPECT "1" expr $new_lookup_unhashed_count - $lookup_unhashed_count +EXPECT "1" expr $new_no_child_down_count - $no_child_down_count + +## Finish up +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +cleanup; diff --git a/extras/test/gluster_commands.sh b/extras/test/gluster_commands.sh index e1e396020..cb2a55fd5 100755 --- a/extras/test/gluster_commands.sh +++ b/extras/test/gluster_commands.sh @@ -1,21 +1,13 @@ #!/bin/bash -# Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> -# This file is part of GlusterFS. -# GlusterFS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; either version 3 of the License, -# or (at your option) any later version. - -# GlusterFS 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 -# General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# <http://www.gnu.org/licenses/>. +# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> +# This file is part of GlusterFS. +# +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. # This script tests the basics gluster cli commands. @@ -54,13 +46,13 @@ gluster volume start vol gluster volume info sleep 1 mount -t glusterfs `hostname`:vol /mnt/client -sleep 1 +sleep 1 df -h echo "adding-brick......." gluster volume add-brick vol `hostname`:/exports/exp2 gluster volume info -sleep 1 +sleep 1 umount /mnt/client mount -t glusterfs `hostname`:vol /mnt/client df -h @@ -102,7 +94,7 @@ sleep 1 echo "removing brick......." gluster --mode=script volume remove-brick vol `hostname`:/exports/exp2 gluster volume info -sleep 1 +sleep 1 df -h sleep 1 @@ -127,7 +119,7 @@ sleep 1 echo "starting replicate volume......" gluster volume start mirror gluster volume info -sleep 1 +sleep 1 mount -t glusterfs `hostname`:mirror /mnt/client sleep 1 df -h @@ -136,7 +128,7 @@ sleep 1 echo "adding-brick......." gluster volume add-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4 gluster volume info -sleep 1 +sleep 1 df -h sleep 1 @@ -178,14 +170,14 @@ sleep 1 echo "removeing-brick....." gluster --mode=script volume remove-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4 gluster volume info -sleep 1 +sleep 1 df -h sleep 1 echo "stopping replicate volume....." gluster --mode=script volume stop mirror gluster volume info -sleep 1 +sleep 1 umount /mnt/client df -h @@ -206,14 +198,14 @@ gluster volume start str gluster volume info sleep 1 mount -t glusterfs `hostname`:str /mnt/client -sleep 1 +sleep 1 df -h sleep 1 echo "adding brick...." gluster volume add-brick str `hostname`:/exports/exp3 `hostname`:/exports/exp4 gluster volume info -sleep 1 +sleep 1 df -h sleep 1 diff --git a/extras/test/ld-preload-test/ld-preload-lib.c b/extras/test/ld-preload-test/ld-preload-lib.c index e17305a4a..88afd14c3 100644 --- a/extras/test/ld-preload-test/ld-preload-lib.c +++ b/extras/test/ld-preload-test/ld-preload-lib.c @@ -1,23 +1,13 @@ /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - /* LD PRELOAD'able library * A very simple library that intercepts booster supported system calls * and prints a log message to stdout. diff --git a/extras/test/ld-preload-test/ld-preload-test.c b/extras/test/ld-preload-test/ld-preload-test.c index 55dd98805..78772f598 100644 --- a/extras/test/ld-preload-test/ld-preload-test.c +++ b/extras/test/ld-preload-test/ld-preload-test.c @@ -1,23 +1,13 @@ /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - /* * LD PRELOAD Test Tool * diff --git a/extras/test/open-fd-tests.c b/extras/test/open-fd-tests.c new file mode 100644 index 000000000..4184079d0 --- /dev/null +++ b/extras/test/open-fd-tests.c @@ -0,0 +1,64 @@ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <attr/xattr.h> +#include <errno.h> +#include <string.h> + +int +main (int argc, char *argv[]) +{ + int ret = -1; + int fd = 0; + char *filename = NULL; + int loop = 0; + struct stat stbuf = {0,}; + char string[1024] = {0,}; + + if (argc > 1) + filename = argv[1]; + + if (!filename) + filename = "temp-fd-test-file"; + + fd = open (filename, O_RDWR|O_CREAT|O_TRUNC); + if (fd < 0) { + fd = 0; + fprintf (stderr, "open failed : %s\n", strerror (errno)); + goto out; + } + + while (loop < 1000) { + /* Use it as a mechanism to test time delays */ + memset (string, 0, 1024); + scanf ("%s", string); + + ret = write (fd, string, strlen (string)); + if (ret != strlen (string)) { + fprintf (stderr, "write failed : %s (%s %d)\n", + strerror (errno), string, loop); + goto out; + } + + ret = write (fd, "\n", 1); + if (ret != 1) { + fprintf (stderr, "write failed : %s (%d)\n", + strerror (errno), loop); + goto out; + } + + loop++; + } + + fprintf (stdout, "finishing the test after %d loops\n", loop); + + ret = 0; +out: + if (fd) + close (fd); + + return ret; +} diff --git a/extras/test/run.sh b/extras/test/run.sh index 2440af237..4b3839cf6 100755 --- a/extras/test/run.sh +++ b/extras/test/run.sh @@ -1,21 +1,12 @@ #!/bin/sh -# Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> -# This file is part of GlusterFS. - -# GlusterFS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; either version 3 of the License, -# or (at your option) any later version. - -# GlusterFS 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 -# General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# <http://www.gnu.org/licenses/>. +# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> +# This file is part of GlusterFS. +# +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. # Running gluster sanity test which starts glusterd and runs gluster commands, and exit at the first failure. $PWD/gluster_commands.sh diff --git a/extras/test/stop_glusterd.sh b/extras/test/stop_glusterd.sh index a84689beb..a2db13f42 100755 --- a/extras/test/stop_glusterd.sh +++ b/extras/test/stop_glusterd.sh @@ -1,21 +1,12 @@ #!/bin/bash -# Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> -# This file is part of GlusterFS. - -# GlusterFS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; either version 3 of the License, -# or (at your option) any later version. - -# GlusterFS 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 -# General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# <http://www.gnu.org/licenses/>. +# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> +# This file is part of GlusterFS. +# +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. #This script stops the glusterd running on the machine. Helpful for gluster sanity script diff --git a/extras/test/test-ffop.c b/extras/test/test-ffop.c index 2c47ab004..2d174d452 100644 --- a/extras/test/test-ffop.c +++ b/extras/test/test-ffop.c @@ -6,20 +6,82 @@ #include <attr/xattr.h> #include <errno.h> #include <string.h> +#include <dirent.h> + +int fd_based_fops_1 (char *filename); //for fd based fops after unlink +int fd_based_fops_2 (char *filename); //for fd based fops before unlink +int dup_fd_based_fops (char *filename); // fops based on fd after dup +int path_based_fops (char *filename); //for fops based on path +int dir_based_fops (char *filename); // for fops which operate on directory +int link_based_fops (char *filename); //for fops which operate in link files (symlinks) +int test_open_modes (char *filename); // to test open syscall with open modes available. +int generic_open_read_write (char *filename, int flag); // generic function which does open write and read. int main (int argc, char *argv[]) { - int ret = -1; - int fd = 0; - char *filename = NULL; - struct stat stbuf = {0,}; + int ret = -1; + char filename[255] = {0,}; if (argc > 1) - filename = argv[1]; + strcpy(filename, argv[1]); + else + strcpy(filename, "temp-xattr-test-file"); + + ret = fd_based_fops_1 (strcat(filename, "_1")); + if (ret < 0) + fprintf (stderr, "fd based file operation 1 failed\n"); + else + fprintf (stdout, "fd based file operation 1 passed\n"); + + ret = fd_based_fops_2 (strcat(filename, "_2")); + if (ret < 0) + fprintf (stderr, "fd based file operation 2 failed\n"); + else + fprintf (stdout, "fd based file operation 2 passed\n"); + + ret = dup_fd_based_fops (strcat (filename, "_3")); + if (ret < 0) + fprintf (stderr, "dup fd based file operation failed\n"); + else + fprintf (stdout, "dup fd based file operation passed\n"); - if (!filename) - filename = "temp-xattr-test-file"; + ret = path_based_fops (strcat (filename, "_4")); + if (ret < 0) + fprintf (stderr, "path based file operation failed\n"); + else + fprintf (stdout, "path based file operation passed\n"); + + ret = dir_based_fops (strcat (filename, "_5")); + if (ret < 0) + fprintf (stderr, "directory based file operation failed\n"); + else + fprintf (stdout, "directory based file operation passed\n"); + + ret = link_based_fops (strcat (filename, "_5")); + if (ret < 0) + fprintf (stderr, "link based file operation failed\n"); + else + fprintf (stdout, "link based file operation passed\n"); + + ret = test_open_modes (strcat (filename, "_5")); + if (ret < 0) + fprintf (stderr, "testing modes of 'open' call failed\n"); + else + fprintf (stdout, "testing modes of 'open' call passed\n"); + +out: + return ret; +} + +int +fd_based_fops_1 (char *filename) +{ + int fd = 0; + int ret = -1; + struct stat stbuf = {0,}; + char wstr[50] = {0,}; + char rstr[50] = {0,}; fd = open (filename, O_RDWR|O_CREAT); if (fd < 0) { @@ -34,6 +96,34 @@ main (int argc, char *argv[]) goto out; } + strcpy (wstr, "This is my string\n"); + ret = write (fd, wstr, strlen(wstr)); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "write failed: %s\n", strerror (errno)); + goto out; + } + + ret = lseek (fd, 0, SEEK_SET); + if (ret < 0) { + fprintf (stderr, "lseek failed: %s\n", strerror (errno)); + goto out; + } + + ret = read (fd, rstr, strlen(wstr)); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "read failed: %s\n", strerror (errno)); + goto out; + } + + ret = memcmp (rstr, wstr, strlen (wstr)); + if (ret != 0) { + ret = -1; + fprintf (stderr, "read returning junk\n"); + goto out; + } + ret = ftruncate (fd, 0); if (ret < 0) { fprintf (stderr, "ftruncate failed : %s\n", strerror (errno)); @@ -103,3 +193,678 @@ out: return ret; } + + +int +fd_based_fops_2 (char *filename) +{ + int fd = 0; + int ret = -1; + struct stat stbuf = {0,}; + char wstr[50] = {0,}; + char rstr[50] = {0,}; + + fd = open (filename, O_RDWR|O_CREAT); + if (fd < 0) { + fd = 0; + fprintf (stderr, "open failed : %s\n", strerror (errno)); + goto out; + } + + ret = ftruncate (fd, 0); + + if (ret < 0) { + fprintf (stderr, "ftruncate failed : %s\n", strerror (errno)); + goto out; + } + + strcpy (wstr, "This is my second string\n"); + ret = write (fd, wstr, strlen (wstr)); + if (ret < 0) { + ret = -1; + fprintf (stderr, "write failed: %s\n", strerror (errno)); + goto out; + } + + lseek (fd, 0, SEEK_SET); + if (ret < 0) { + fprintf (stderr, "lseek failed: %s\n", strerror (errno)); + goto out; + } + + ret = read (fd, rstr, strlen (wstr)); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "read failed: %s\n", strerror (errno)); + goto out; + } + + ret = memcmp (rstr, wstr, strlen (wstr)); + if (ret != 0) { + ret = -1; + fprintf (stderr, "read returning junk\n"); + goto out; + } + + ret = fstat (fd, &stbuf); + if (ret < 0) { + fprintf (stderr, "fstat failed : %s\n", strerror (errno)); + goto out; + } + + ret = fchmod (fd, 0640); + if (ret < 0) { + fprintf (stderr, "fchmod failed : %s\n", strerror (errno)); + goto out; + } + + ret = fchown (fd, 10001, 10001); + if (ret < 0) { + fprintf (stderr, "fchown failed : %s\n", strerror (errno)); + goto out; + } + + ret = fsync (fd); + if (ret < 0) { + fprintf (stderr, "fsync failed : %s\n", strerror (errno)); + goto out; + } + + ret = fsetxattr (fd, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf (stderr, "fsetxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fdatasync (fd); + if (ret < 0) { + fprintf (stderr, "fdatasync failed : %s\n", strerror (errno)); + goto out; + } + + ret = flistxattr (fd, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "flistxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fgetxattr (fd, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "fgetxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fremovexattr (fd, "trusted.xattr-test"); + if (ret < 0) { + fprintf (stderr, "fremovexattr failed : %s\n", strerror (errno)); + goto out; + } + +out: + if (fd) + close (fd); + unlink (filename); + + return ret; +} + +int +path_based_fops (char *filename) +{ + int ret = -1; + int fd = 0; + struct stat stbuf = {0,}; + char newfilename[255] = {0,}; + + fd = creat (filename, 0644); + if (fd < 0) { + fprintf (stderr, "creat failed: %s\n", strerror (errno)); + goto out; + } + + ret = truncate (filename, 0); + if (ret < 0) { + fprintf (stderr, "truncate failed: %s\n", strerror (errno)); + goto out; + } + + ret = stat (filename, &stbuf); + if (ret < 0) { + fprintf (stderr, "stat failed: %s\n", strerror (errno)); + goto out; + } + + ret = chmod (filename, 0640); + if (ret < 0) { + fprintf (stderr, "chmod failed: %s\n", strerror (errno)); + goto out; + } + + ret = chown (filename, 10001, 10001); + if (ret < 0) { + fprintf (stderr, "chown failed: %s\n", strerror (errno)); + goto out; + } + + ret = setxattr (filename, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf (stderr, "setxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = listxattr (filename, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "listxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = getxattr (filename, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "getxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = removexattr (filename, "trusted.xattr-test"); + if (ret < 0) { + fprintf (stderr, "removexattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = access (filename, R_OK|W_OK); + if (ret < 0) { + fprintf (stderr, "access failed: %s\n", strerror (errno)); + goto out; + } + + strcpy (newfilename, filename); + strcat(newfilename, "_new"); + ret = rename (filename, newfilename); + if (ret < 0) { + fprintf (stderr, "rename failed: %s\n", strerror (errno)); + goto out; + } + unlink (newfilename); + +out: + if (fd) + close (fd); + + unlink (filename); + return ret; +} + +int +dup_fd_based_fops (char *filename) +{ + int fd = 0; + int newfd = 0; + int ret = -1; + struct stat stbuf = {0,}; + char wstr[50] = {0,}; + char rstr[50] = {0,}; + + fd = open (filename, O_RDWR|O_CREAT); + if (fd < 0) { + fd = 0; + fprintf (stderr, "open failed : %s\n", strerror (errno)); + goto out; + } + + newfd = dup (fd); + if (newfd < 0) { + ret = -1; + fprintf (stderr, "dup failed: %s\n", strerror (errno)); + goto out; + } + + close (fd); + + strcpy (wstr, "This is my string\n"); + ret = write (newfd, wstr, strlen(wstr)); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "write failed: %s\n", strerror (errno)); + goto out; + } + + ret = lseek (newfd, 0, SEEK_SET); + if (ret < 0) { + fprintf (stderr, "lseek failed: %s\n", strerror (errno)); + goto out; + } + + ret = read (newfd, rstr, strlen(wstr)); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "read failed: %s\n", strerror (errno)); + goto out; + } + + ret = memcmp (rstr, wstr, strlen (wstr)); + if (ret != 0) { + ret = -1; + fprintf (stderr, "read returning junk\n"); + goto out; + } + + ret = ftruncate (newfd, 0); + if (ret < 0) { + fprintf (stderr, "ftruncate failed : %s\n", strerror (errno)); + goto out; + } + + ret = fstat (newfd, &stbuf); + if (ret < 0) { + fprintf (stderr, "fstat failed : %s\n", strerror (errno)); + goto out; + } + + ret = fchmod (newfd, 0640); + if (ret < 0) { + fprintf (stderr, "fchmod failed : %s\n", strerror (errno)); + goto out; + } + + ret = fchown (newfd, 10001, 10001); + if (ret < 0) { + fprintf (stderr, "fchown failed : %s\n", strerror (errno)); + goto out; + } + + ret = fsync (newfd); + if (ret < 0) { + fprintf (stderr, "fsync failed : %s\n", strerror (errno)); + goto out; + } + + ret = fsetxattr (newfd, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf (stderr, "fsetxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fdatasync (newfd); + if (ret < 0) { + fprintf (stderr, "fdatasync failed : %s\n", strerror (errno)); + goto out; + } + + ret = flistxattr (newfd, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "flistxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fgetxattr (newfd, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "fgetxattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = fremovexattr (newfd, "trusted.xattr-test"); + if (ret < 0) { + fprintf (stderr, "fremovexattr failed : %s\n", strerror (errno)); + goto out; + } + + ret = 0; +out: + if (newfd) + close (newfd); + ret = unlink (filename); + if (ret < 0) { + fprintf (stderr, "unlink failed : %s\n", strerror (errno)); + goto out; + } + + return ret; +} + +int +dir_based_fops (char *dirname) +{ + int ret = -1; + DIR *dp = NULL; + char buff[255] = {0,}; + struct dirent *dbuff = {0,}; + struct stat stbuff = {0,}; + char newdname[255] = {0,}; + char *cwd = NULL; + + ret = mkdir (dirname, 0755); + if (ret < 0) { + fprintf (stderr, "mkdir failed: %s\n", strerror (errno)); + goto out; + } + + dp = opendir (dirname); + if (dp == NULL) { + fprintf (stderr, "opendir failed: %s\n", strerror (errno)); + goto out; + } + + dbuff = readdir (dp); + if (NULL == dbuff) { + fprintf (stderr, "readdir failed: %s\n", strerror (errno)); + goto out; + } + + ret = closedir (dp); + if (ret < 0) { + fprintf (stderr, "closedir failed: %s\n", strerror (errno)); + goto out; + } + + ret = stat (dirname, &stbuff); + if (ret < 0) { + fprintf (stderr, "stat failed: %s\n", strerror (errno)); + goto out; + } + + ret = chmod (dirname, 0744); + if (ret < 0) { + fprintf (stderr, "chmod failed: %s\n", strerror (errno)); + goto out; + } + + ret = chown (dirname, 10001, 10001); + if (ret < 0) { + fprintf (stderr, "chmod failed: %s\n", strerror (errno)); + goto out; + } + + ret = setxattr (dirname, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf (stderr, "setxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = listxattr (dirname, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "listxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = getxattr (dirname, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf (stderr, "getxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = removexattr (dirname, "trusted.xattr-test"); + if (ret < 0) { + fprintf (stderr, "removexattr failed: %s\n", strerror (errno)); + goto out; + } + + strcpy (newdname, dirname); + strcat (newdname, "/../"); + ret = chdir (newdname); + if (ret < 0) { + fprintf (stderr, "chdir failed: %s\n", strerror (errno)); + goto out; + } + + cwd = getcwd (buff, 255); + if (NULL == cwd) { + fprintf (stderr, "getcwd failed: %s\n", strerror (errno)); + goto out; + } + + strcpy (newdname, dirname); + strcat (newdname, "new"); + ret = rename (dirname, newdname); + if (ret < 0) { + fprintf (stderr, "rename failed: %s\n", strerror (errno)); + goto out; + } + + ret = rmdir (newdname); + if (ret < 0) { + fprintf (stderr, "rmdir failed: %s\n", strerror (errno)); + return ret; + } + +out: + rmdir (dirname); + return ret; +} + +int +link_based_fops (char *filename) +{ + int ret = -1; + int fd = 0; + char newname[255] = {0,}; + char linkname[255] = {0,}; + struct stat lstbuf = {0,}; + + fd = creat (filename, 0644); + if (fd < 0) { + fd = 0; + fprintf (stderr, "creat failed: %s\n", strerror (errno)); + goto out; + } + + strcpy (newname, filename); + strcat (newname, "_hlink"); + ret = link (filename, newname); + if (ret < 0) { + fprintf (stderr, "link failed: %s\n", strerror (errno)); + goto out; + } + + ret = unlink (filename); + if (ret < 0) { + fprintf (stderr, "unlink failed: %s\n", strerror (errno)); + goto out; + } + + strcpy (linkname, filename); + strcat (linkname, "_slink"); + ret = symlink (newname, linkname); + if (ret < 0) { + fprintf (stderr, "symlink failed: %s\n", strerror (errno)); + goto out; + } + + ret = lstat (linkname, &lstbuf); + if (ret < 0) { + fprintf (stderr, "lstbuf failed: %s\n", strerror (errno)); + goto out; + } + + ret = lchown (linkname, 10001, 10001); + if (ret < 0) { + fprintf (stderr, "lchown failed: %s\n", strerror (errno)); + goto out; + } + + ret = lsetxattr (linkname, "trusted.lxattr-test", "working", 8, 0); + if (ret < 0) { + fprintf (stderr, "lsetxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = llistxattr (linkname, NULL, 0); + if (ret < 0) { + ret = -1; + fprintf (stderr, "llistxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = lgetxattr (linkname, "trusted.lxattr-test", NULL, 0); + if (ret < 0) { + ret = -1; + fprintf (stderr, "lgetxattr failed: %s\n", strerror (errno)); + goto out; + } + + ret = lremovexattr (linkname, "trusted.lxattr-test"); + if (ret < 0) { + fprintf (stderr, "lremovexattr failed: %s\n", strerror (errno)); + goto out; + } + + +out: + if (fd) + close(fd); + unlink (linkname); + unlink (newname); +} + +int +test_open_modes (char *filename) +{ + int ret = -1; + + ret = generic_open_read_write (filename, O_CREAT|O_WRONLY); + if (3 != ret) { + fprintf (stderr, "flag O_CREAT|O_WRONLY failed: \n"); + goto out; + } + + ret = generic_open_read_write (filename, O_CREAT|O_RDWR); + if (ret != 0) { + fprintf (stderr, "flag O_CREAT|O_RDWR failed\n"); + goto out; + } + + ret = generic_open_read_write (filename, O_CREAT|O_RDONLY); + if (ret != 0) { + fprintf (stderr, "flag O_CREAT|O_RDONLY failed\n"); + goto out; + } + + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_WRONLY); + if (3 != ret) { + fprintf (stderr, "flag O_WRONLY failed\n"); + goto out; + } + + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_RDWR); + if (0 != ret) { + fprintf (stderr, "flag O_RDWR failed\n"); + goto out; + } + + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_RDONLY); + if (0 != ret) { + fprintf (stderr, "flag O_RDONLY failed\n"); + goto out; + } + + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_TRUNC|O_WRONLY); + if (3 != ret) { + fprintf (stderr, "flag O_TRUNC|O_WRONLY failed\n"); + goto out; + } + +#if 0 /* undefined behaviour, unable to reliably test */ + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_TRUNC|O_RDONLY); + if (0 != ret) { + fprintf (stderr, "flag O_TRUNC|O_RDONLY failed\n"); + goto out; + } +#endif + + ret = generic_open_read_write (filename, O_CREAT|O_RDWR|O_SYNC); + if (0 != ret) { + fprintf (stderr, "flag O_CREAT|O_RDWR|O_SYNC failed\n"); + goto out; + } + + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_CREAT|O_EXCL); + if (0 != ret) { + fprintf (stderr, "flag O_CREAT|O_EXCL failed\n"); + goto out; + } + +out: + return ret; +} + +int generic_open_read_write (char *filename, int flag) +{ + int fd = 0; + int ret = -1; + char wstring[50] = {0,}; + char rstring[50] = {0,}; + + fd = open (filename, flag); + if (fd < 0) { + if (flag == O_CREAT|O_EXCL && errno == EEXIST) { + unlink (filename); + return 0; + } + else { + fd = 0; + fprintf (stderr, "open failed: %s\n", strerror (errno)); + return 1; + } + } + + strcpy (wstring, "My string to write\n"); + ret = write (fd, wstring, strlen(wstring)); + if (ret <= 0) { + if (errno != EBADF) { + fprintf (stderr, "write failed: %s\n", strerror (errno)); + close (fd); + unlink(filename); + return 2; + } + } + + ret = lseek (fd, 0, SEEK_SET); + if (ret < 0) { + close (fd); + unlink(filename); + return 4; + } + + ret = read (fd, rstring, strlen(wstring)); + if (ret < 0) { + close (fd); + unlink (filename); + return 3; + } + + /* Compare the rstring with wstring. But we do not want to return + * error when the flag is either O_RDONLY, O_CREAT|O_RDONLY or + * O_TRUNC|O_RDONLY. Because in that case we are not writing + * anything to the file.*/ + + ret = memcmp (wstring, rstring, strlen (wstring)); + if (0 != ret && !(flag == O_CREAT|O_RDONLY || flag == O_RDONLY ||\ + flag == O_TRUNC|O_RDONLY)) { + fprintf (stderr, "read is returning junk\n"); + close (fd); + unlink (filename); + return 4; + } + + close (fd); + unlink (filename); + return 0; +} diff --git a/extras/volfilter.py b/extras/volfilter.py new file mode 100644 index 000000000..0ca456a78 --- /dev/null +++ b/extras/volfilter.py @@ -0,0 +1,167 @@ +# Copyright (c) 2010-2011 Red Hat, Inc. +# +# This file is part of HekaFS. +# +# HekaFS is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License, version 3, as published by the Free +# Software Foundation. +# +# HekaFS 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License * along +# with HekaFS. If not, see <http://www.gnu.org/licenses/>. + +import copy +import string +import sys +import types + +good_xlators = [ + "cluster/afr", + "cluster/dht", + "cluster/distribute", + "cluster/replicate", + "cluster/stripe", + "debug/io-stats", + "features/access-control", + "features/locks", + "features/marker", + "features/uidmap", + "performance/io-threads", + "protocol/client", + "protocol/server", + "storage/posix", +] + +def copy_stack (old_xl,suffix,recursive=False): + if recursive: + new_name = old_xl.name + "-" + suffix + else: + new_name = suffix + new_xl = Translator(new_name) + new_xl.type = old_xl.type + # The results with normal assignment here are . . . amusing. + new_xl.opts = copy.deepcopy(old_xl.opts) + for sv in old_xl.subvols: + new_xl.subvols.append(copy_stack(sv,suffix,True)) + # Patch up the path at the bottom. + if new_xl.type == "storage/posix": + new_xl.opts["directory"] += ("/" + suffix) + return new_xl + +def cleanup (parent, graph): + if parent.type in good_xlators: + # Temporary fix so that HekaFS volumes can use the + # SSL-enabled multi-threaded socket transport. + if parent.type == "protocol/server": + parent.type = "protocol/server2" + parent.opts["transport-type"] = "ssl" + elif parent.type == "protocol/client": + parent.type = "protocol/client2" + parent.opts["transport-type"] = "ssl" + sv = [] + for child in parent.subvols: + sv.append(cleanup(child,graph)) + parent.subvols = sv + else: + parent = cleanup(parent.subvols[0],graph) + return parent + +class Translator: + def __init__ (self, name): + self.name = name + self.type = "" + self.opts = {} + self.subvols = [] + self.dumped = False + def __repr__ (self): + return "<Translator %s>" % self.name + +def load (path): + # If it's a string, open it; otherwise, assume it's already a + # file-like object (most notably from urllib*). + if type(path) in types.StringTypes: + fp = file(path,"r") + else: + fp = path + all_xlators = {} + xlator = None + last_xlator = None + while True: + text = fp.readline() + if text == "": + break + text = text.split() + if not len(text): + continue + if text[0] == "volume": + if xlator: + raise RuntimeError, "nested volume definition" + xlator = Translator(text[1]) + continue + if not xlator: + raise RuntimeError, "text outside volume definition" + if text[0] == "type": + xlator.type = text[1] + continue + if text[0] == "option": + xlator.opts[text[1]] = string.join(text[2:]) + continue + if text[0] == "subvolumes": + for sv in text[1:]: + xlator.subvols.append(all_xlators[sv]) + continue + if text[0] == "end-volume": + all_xlators[xlator.name] = xlator + last_xlator = xlator + xlator = None + continue + raise RuntimeError, "unrecognized keyword %s" % text[0] + if xlator: + raise RuntimeError, "unclosed volume definition" + return all_xlators, last_xlator + +def generate (graph, last, stream=sys.stdout): + for sv in last.subvols: + if not sv.dumped: + generate(graph,sv,stream) + print >> stream, "" + sv.dumped = True + print >> stream, "volume %s" % last.name + print >> stream, " type %s" % last.type + for k, v in last.opts.iteritems(): + print >> stream, " option %s %s" % (k, v) + if last.subvols: + print >> stream, " subvolumes %s" % string.join( + [ sv.name for sv in last.subvols ]) + print >> stream, "end-volume" + +def push_filter (graph, old_xl, filt_type, opts={}): + suffix = "-" + old_xl.type.split("/")[1] + if len(old_xl.name) > len(suffix): + if old_xl.name[-len(suffix):] == suffix: + old_xl.name = old_xl.name[:-len(suffix)] + new_xl = Translator(old_xl.name+suffix) + new_xl.type = old_xl.type + new_xl.opts = old_xl.opts + new_xl.subvols = old_xl.subvols + graph[new_xl.name] = new_xl + old_xl.name += ("-" + filt_type.split("/")[1]) + old_xl.type = filt_type + old_xl.opts = opts + old_xl.subvols = [new_xl] + graph[old_xl.name] = old_xl + +def delete (graph, victim): + if len(victim.subvols) != 1: + raise RuntimeError, "attempt to delete non-unary translator" + for xl in graph.itervalues(): + while xl.subvols.count(victim): + i = xl.subvols.index(victim) + xl.subvols[i] = victim.subvols[0] + +if __name__ == "__main__": + graph, last = load(sys.argv[1]) + generate(graph,last) diff --git a/extras/who-wrote-glusterfs/gitdm.aliases b/extras/who-wrote-glusterfs/gitdm.aliases new file mode 100644 index 000000000..784a3e3bc --- /dev/null +++ b/extras/who-wrote-glusterfs/gitdm.aliases @@ -0,0 +1,48 @@ +# +# This is the email aliases file, mapping secondary addresses onto a single, +# canonical address. This file should probably match the contents of .mailmap +# in the root of the git repository. +# +# Format: <alias> <real> + +amar@gluster.com amarts@redhat.com +amar@del.gluster.com amarts@redhat.com +avati@amp.gluster.com avati@redhat.com +avati@blackhole.gluster.com avati@redhat.com +avati@dev.gluster.com avati@redhat.com +avati@gluster.com avati@redhat.com +wheelear@gmail.com awheeler@redhat.com +anush@gluster.com ashetty@redhat.com +csaba@gluster.com csaba@redhat.com +csaba@lowlife.hu csaba@redhat.com +csaba@zresearch.com csaba@redhat.com +harsha@gluster.com fharshav@redhat.com +harsha@zresearch.com fharshav@redhat.com +harsha@dev.gluster.com fharshav@redhat.com +harsha@harshavardhana.net fharshav@redhat.com +kkeithle@f16node1.kkeithle.usersys.redhat.com kkeithle@redhat.com +kaushal@gluster.com kaushal@redhat.com +kaushikbv@gluster.com kbudiger@redhat.com +krishna@gluster.com ksriniva@redhat.com +krishna@zresearch.com ksriniva@redhat.com +krishna@guest-laptop ksriniva@redhat.com +kp@gluster.com kparthas@redhat.com +me@louiszuckerman.com louiszuckerman@gmail.com +msvbhat@gmail.com vbhat@redhat.com +vishwanath@gluster.com vbhat@redhat.com +pavan@dev.gluster.com pavan@gluster.com +zaitcev@yahoo.com zaitcev@kotori.zaitcev.us +pranithk@gluster.com pkarampu@redhat.com +raghavendrabhat@gluster.com raghavendra@redhat.com +raghavendra@gluster.com rgowdapp@redhat.com +raghavendra@zresearch.com rgowdapp@redhat.com +rahulcssjce@gmail.com rahulcs@redhat.com +rajesh@gluster.com rajesh@redhat.com +rajesh.amaravathi@gmail.com rajesh@redhat.com +shehjart@zresearch.com shehjart@gluster.com +venky@gluster.com vshankar@redhat.com +vijay@gluster.com vbellur@redhat.com +vijay@dev.gluster.com vbellur@redhat.com +vijaykumar.koppad@gmail.com vkoppad@redhat.com +vikas@zresearch.com vikas@gluster.com +shishirng@gluster.com sgowda@redhat.com diff --git a/extras/who-wrote-glusterfs/gitdm.config b/extras/who-wrote-glusterfs/gitdm.config new file mode 100644 index 000000000..e1ff2bd5b --- /dev/null +++ b/extras/who-wrote-glusterfs/gitdm.config @@ -0,0 +1,8 @@ +# +# This is the gitdm configuration file for GlusterFS. +# See the gitdm.config in the gitdm repositofy for additional options and +# comments. +# + +EmailAliases gitdm.aliases +EmailMap gitdm.domain-map diff --git a/extras/who-wrote-glusterfs/gitdm.domain-map b/extras/who-wrote-glusterfs/gitdm.domain-map new file mode 100644 index 000000000..f1c305898 --- /dev/null +++ b/extras/who-wrote-glusterfs/gitdm.domain-map @@ -0,0 +1,15 @@ +# +# Here is a set of mappings of domain names onto employer names. +# +active.by ActiveCloud +cern.ch CERN +gluster.com Red Hat +gooddata.com GoodData +hastexo.com hastexo +ibm.com IBM +linbit.com LINBIT +netbsd.org NetBSD +netdirect.ca Net Direct +redhat.com Red Hat +stepping-stone.ch stepping stone GmbH +zresearch.com Red Hat diff --git a/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh new file mode 100755 index 000000000..487f5874b --- /dev/null +++ b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Gather statistics on "Who wrote GlusterFS". The idea comes from the excellent +# articles on http://lwn.net/ named "Who wrote <linux-version>?". +# +# gitdm comes from git://git.lwn.net/gitdm.git by Jonathan Corbet. +# +# Confguration files used: +# - gitdm.config: main configuration file, pointing to the others +# - gitdm.aliases: merge users with different emailaddresses into one +# - gitdm.domain-map: map domain names from emailaddresses to companies +# + +DIRNAME=$(dirname $0) + +GITDM_REPO=git://git.lwn.net/gitdm.git +GITDM_DIR=${DIRNAME}/gitdm +GITDM_CMD="python ${GITDM_DIR}/gitdm" + +error() +{ + local ret=${?} + printf "${@}\n" > /dev/stderr + return ${ret} +} + +check_gitdm() +{ + if [ ! -e "${GITDM_DIR}/gitdm" ] + then + git clone --quiet git://git.lwn.net/gitdm.git ${DIRNAME}/gitdm + fi +} + +# The first argument is the revision-range (see 'git rev-list --help'). +# REV can be empty, and the statistics will be calculated over the whole +# current branch. +REV=${1} +shift +# all remaining options are passed to gitdm, see the gitdm script for an +# explanation of the accepted options. +GITDM_OPTS=${@} + +if ! check_gitdm +then + error "Could not find 'gitdm', exiting..." + exit 1 +fi + +git log --numstat -M ${REV} | ${GITDM_CMD} -b ${DIRNAME} -n ${GITDM_OPTS} |
