diff options
Diffstat (limited to 'tests/features')
28 files changed, 2903 insertions, 48 deletions
diff --git a/tests/features/delay-gen.t b/tests/features/delay-gen.t new file mode 100755 index 00000000000..72e6dbb7697 --- /dev/null +++ b/tests/features/delay-gen.t @@ -0,0 +1,52 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 + +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume set $V0 delay-gen posix +TEST $CLI volume set $V0 delay-gen.delay-duration 1000000 +TEST $CLI volume set $V0 delay-gen.delay-percentage 100 +TEST $CLI volume set $V0 delay-gen.enable read,write + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +TEST $CLI volume profile $V0 start +## Mount FUSE with caching disabled (read-write) +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +TEST dd if=/dev/zero of=$M0/1 count=1 bs=128k oflag=sync + +#Write should take at least a second +write_max_latency=$($CLI volume profile $V0 info | grep WRITE | awk 'BEGIN {max = 0} {if ($6 > max) max=$6;} END {print max}' | cut -d. -f 1 | egrep "[0-9]{7,}") + +#Create should not take a second +create_max_latency=$($CLI volume profile $V0 info | grep CREATE | awk 'BEGIN {max = 0} {if ($6 > max) max=$6;} END {print max}' | cut -d. -f 1 | egrep "[0-9]{7,}") + +TEST [ ! -z $write_max_latency ]; +TEST [ -z $create_max_latency ]; + +# Not providing a particular fop will make it test everything +TEST $CLI volume reset $V0 delay-gen.enable +TEST $CLI volume set $V0 delay-gen.delay-duration 100 + +cp $(dirname ${0})/../basic/gfapi/glfsxmp-coverage.c glfsxmp.c +build_tester ./glfsxmp.c -lgfapi +./glfsxmp $V0 $H0 >/dev/null +cleanup_tester ./glfsxmp +rm ./glfsxmp.c + +$(dirname $0)/../basic/rpc-coverage.sh $M0 >/dev/null + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=1501397 diff --git a/tests/features/dh1024.pem b/tests/features/dh1024.pem new file mode 100644 index 00000000000..fe514bd4ee5 --- /dev/null +++ b/tests/features/dh1024.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAL2k+efZ6g50PpL41G96IaRw2OTH921yhHMNSXBE/K+R6oTkJFcNJs1N +q+a1Ko2xCBDa5MgvudqWep6PvE06rzEaJPW8ITdu8j3Eo9T1rorJ3CctpE/CaRl2 +7v4DNe+Mho6q1MPlG5PfXEZWgbT7tjn/Y6lwD/B2CoMzAx+4DXgbAgEC +-----END DH PARAMETERS----- diff --git a/tests/features/fdl-overflow.t b/tests/features/fdl-overflow.t new file mode 100644 index 00000000000..34b941d2f2a --- /dev/null +++ b/tests/features/fdl-overflow.t @@ -0,0 +1,72 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../fdl.rc + +_check_sizes () { + local n=0 + local sz + local total_sz=0 + + # We don't care about the sizes of the meta files. That would be + # embedding too much of the implementation into the test. + n=$(ls ${log_base}/${log_id}-meta-*.jnl | wc -l) + [ $n = 2 ] || return 1 + + # We *do* care about the sizes of the data files, which should exactly + # reflect the amount of data written via dd. + n=0 + while read sz name; do + G_LOG "found journal ${name} size ${sz}MB" + n=$((n+1)) + total_sz=$((total_sz+sz)) + done < <(du -sm ${log_base}/${log_id}-data-*.jnl) + [ $n = 2 ] || return 1 + # On our CentOS and NetBSD regression-test systems, but not on my Fedora + # development system, each file ends up being slightly larger than its + # data size because of metadata, and 'du' rounds that up to a full extra + # megabyte. We'll allow either result, because what we're really + # looking for is a complete failure to roll over from one file to + # another at the appropriate size. + [ $total_sz = 20 -o $total_sz = $((n+20)) ] || return 1 + + return 0 +} + +check_sizes () { + set -x + _check_sizes + ret=$? + set +x + return ret +} + +if [ x"$OSTYPE" = x"NetBSD" ]; then + CREAT_OFLAG="creat," +else + CREAT_OFLAG="" +fi + +TEST rm -f ${log_base}/${log_id}-*.log +TEST glusterd +TEST pidof glusterd + +# Get a simple volume set up and mounted with FDL active. +TEST $CLI volume create $V0 ${H0}:${B0}/${V0}-0 +TEST $CLI volume set $V0 changelog.changelog off +TEST $CLI volume set $V0 features.fdl on +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +# Generate some I/O and unmount/stop so we can see log sizes. +TEST dd if=/dev/zero of=$M0/twentyMB bs=1048576 count=20 \ + oflag=${CREAT_OFLAG}sync +TEST umount $M0 +TEST $CLI volume stop $V0 + +TEST _check_sizes + +cleanup +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=1385758 +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1385758 diff --git a/tests/features/fdl.t b/tests/features/fdl.t new file mode 100644 index 00000000000..5a3c13fc850 --- /dev/null +++ b/tests/features/fdl.t @@ -0,0 +1,44 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../fdl.rc + +if [ x"$OSTYPE" = x"NetBSD" ]; then + CREAT_OFLAG="creat," +else + CREAT_OFLAG="" +fi + +TEST rm -f $FDL_META_FILE $FDL_DATA_FILE +TEST glusterd +TEST pidof glusterd + +# Get a simple volume set up and mounted with FDL active. +TEST $CLI volume create $V0 ${H0}:${B0}/${V0}-0 +TEST $CLI volume set $V0 changelog.changelog off +TEST $CLI volume set $V0 features.fdl on +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +# Generate some I/O and unmount. +TEST mkdir -p $M0/abc/def +TEST dd if=/dev/zero of=$M0/abc/def/ghi bs=128 count=2 \ + oflag=${CREAT_OFLAG}sync +TEST chmod 314 $M0/abc/def/ghi +TEST rm -rf $M0/abc +TEST umount $M0 + +# Check that gf_logdump works, and shows the ops we just issued. There will be +# more SETATTR ops than the one corresponding to our chmod, because some are +# issued internally. We have to guess a bit about where the log will be. +TEST check_logfile GF_FOP_MKDIR 2 +TEST check_logfile GF_FOP_CREATE 1 +TEST check_logfile GF_FOP_WRITE 2 +TEST check_logfile GF_FOP_SETATTR 1 +TEST check_logfile GF_FOP_UNLINK 1 +TEST check_logfile GF_FOP_RMDIR 2 + +cleanup +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=1385758 +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1385758 diff --git a/tests/features/flock_interrupt.t b/tests/features/flock_interrupt.t new file mode 100644 index 00000000000..b8717e30dfb --- /dev/null +++ b/tests/features/flock_interrupt.t @@ -0,0 +1,32 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 $H0:$B0/${V0}0; + +## 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'; + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST touch $M0/testfile; + +echo > got_lock +flock $M0/testfile sleep 6 & { sleep 0.3; flock -w 2 $M0/testfile true; echo ok > got_lock; } & + +EXPECT_WITHIN 4 ok cat got_lock; + +## Finish up +rm -f got_lock; +cleanup; diff --git a/tests/features/fuse-lru-limit.t b/tests/features/fuse-lru-limit.t new file mode 100644 index 00000000000..dd6be2d5397 --- /dev/null +++ b/tests/features/fuse-lru-limit.t @@ -0,0 +1,43 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST glusterfs -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "2" online_brick_count + +EXPECT "1" get_mount_active_size_value $V0 $M0 +EXPECT "0" get_mount_lru_size_value $V0 $M0 + +mkdir ${M0}/dir-{1..9} +for i in {1..9}; do + for j in {1..1000}; do + echo "Test file" > ${M0}/dir-$i/file-$j; + done; +done +lc=$(get_mount_lru_size_value $V0 ${M0}) +# ideally it should be 9000+ +TEST [ $lc -ge 9000 ] + +TEST umount $M0 + +TEST glusterfs -s $H0 --volfile-id $V0 --lru-limit 1000 $M0 + +TEST find $M0 +lc=$(get_mount_lru_size_value $V0 ${M0}) +# ideally it should be <1000 +# Not sure if there are any possibilities of buffer need. +TEST [ $lc -le 1000 ] + +TEST rm -rf $M0/* + +EXPECT "1" get_mount_active_size_value $V0 $M0 +EXPECT "0" get_mount_lru_size_value $V0 $M0 + +cleanup diff --git a/tests/features/glfs-lease-recall.c b/tests/features/glfs-lease-recall.c new file mode 100644 index 00000000000..9a60f9beec1 --- /dev/null +++ b/tests/features/glfs-lease-recall.c @@ -0,0 +1,372 @@ +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> + +/* Few rules: + * 1. A client may have multiple lease keys, but a lease key cannot be shared by + * multiple clients. + * 2. Lease key can be set before open, or in glfs_lease request. A lease key + * set like this is valid for the lifetime of the fd, i.e. a fd cannot have + * multiple lease key. But a lease key can be shared across multiple fds. + */ +glfs_t *client1 = NULL, *client2 = NULL; +glfs_fd_t *fd1 = NULL; +FILE *log_file = NULL; +char lid1[GLFS_LEASE_ID_SIZE] = "lid1-clnt1", + lid2[GLFS_LEASE_ID_SIZE] = "lid2-clnt2"; +char lid3[GLFS_LEASE_ID_SIZE] = "lid3-clnt2", lid4[GLFS_LEASE_ID_SIZE] = { + 0, +}; +char *volname = NULL, *glfs_log_file = NULL; +int upcall_recv = 0; + +#define MAX_CLIENTS 4 +#define MAX_FDS 4 +#define TEST_FILE "/test/lease" +#define SHUD_PASS 0 +#define SHUD_FAIL -1 +#define NONE 0 + +static void +recall_cbk(struct glfs_lease lease, void *data); + +static int +set_read_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, fd); + if (ret < 0) { + fprintf(log_file, "\n RD_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Took RD_LEASE"); + return ret; +} + +static int +set_write_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RW_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n RW_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Took RW_LEASE"); + return ret; +} + +static int +get_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_GET_LEASE; + lease.lease_type = -1; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n GET_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + if (lease.lease_type == GLFS_RD_LEASE) + fprintf(log_file, "\n Esisting Lease: RD_LEASE"); + else if (lease.lease_type == GLFS_RW_LEASE) + fprintf(log_file, "\n Esisting Lease: RW_LEASE"); + else if (lease.lease_type == 3) + fprintf(log_file, "\n Esisting Lease: RD_LEASE|RW_LEASE"); + else if (lease.lease_type == 0) + fprintf(log_file, "\n Esisting Lease: NONE"); + else + fprintf(log_file, "\n Existing lease type:%d", lease.lease_type); + return lease.lease_type; +} + +static int +unlk_write_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_UNLK_LEASE; + lease.lease_type = GLFS_RW_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n Unlock RW_LESAE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Unlocked RW_LEASE"); + return ret; +} + +static int +unlk_read_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_UNLK_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n Unlock RD_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Unlocked RD_LEASE"); + return ret; +} + +void +up_async_lease_recall(struct glfs_upcall *up_arg, void *data) +{ + struct glfs_upcall_lease *in_arg = NULL; + enum glfs_upcall_reason reason = 0; + struct glfs_object *object = NULL; + uint64_t flags = 0; + uint64_t expire = 0; + + if (!up_arg) + return; + + reason = glfs_upcall_get_reason(up_arg); + + /* Expect 'GLFS_UPCALL_RECALL_LEASE' upcall event. */ + + if (reason == GLFS_UPCALL_RECALL_LEASE) { + in_arg = glfs_upcall_get_event(up_arg); + + object = glfs_upcall_lease_get_object(in_arg); + + fprintf(log_file, + " upcall event type - %d," + " object(%p)\n", + reason, object); + upcall_recv = 1; + } + + glfs_free(up_arg); + return; +} + +glfs_t * +setup_new_client(char *volname, char *log_fileile) +{ + int ret = 0; + glfs_t *fs = NULL; + int up_events = GLFS_EVENT_ANY; + + fs = glfs_new(volname); + if (!fs) { + fprintf(log_file, "\nglfs_new: returned NULL (%s)\n", strerror(errno)); + goto error; + } + + ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); + if (ret < 0) { + fprintf(log_file, "\nglfs_set_volfile_server failed ret:%d (%s)\n", ret, + strerror(errno)); + goto error; + } + + ret = glfs_set_logging(fs, log_fileile, 7); + if (ret < 0) { + fprintf(log_file, "\nglfs_set_logging failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(log_file, "\nglfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + + /* Register Upcalls */ + ret = glfs_upcall_register(fs, up_events, up_async_lease_recall, NULL); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_RECALL_LEASE)) { + fprintf(stderr, + "glfs_upcall_register return doesn't contain" + " upcall event - GLFS_EVENT_RECALL_LEASE\n"); + goto error; + } + + return fs; +error: + if (fs) + glfs_fini(fs); + return NULL; +} + +#define OPEN(client, flags, fd, lease_id) \ + do { \ + int ret_val = 0; \ + ret_val = glfs_setfsleaseid(lease_id); \ + if (ret_val) { \ + fprintf(log_file, \ + "\nglfs_setfsleaseid failed with ret: %d (%s)\n", ret, \ + strerror(errno)); \ + return -1; \ + } \ + fd = glfs_open(client, TEST_FILE, flags); \ + if (fd == NULL) { \ + fprintf(log_file, "\nglfs_open failed with ret: %d (%s)\n", ret, \ + strerror(errno)); \ + return -1; \ + } \ + } while (0) + +#define VERIFY_RESULT(test_case, ret, value) \ + do { \ + if (ret != value) { \ + fprintf(log_file, \ + "\n Testcase %d failed, ret = %d, value=%d\n", \ + test_case, ret, value); \ + goto error; /*test unsuccessful*/ \ + } \ + fprintf(log_file, "\n Testcase %d Succeeded\n", test_case); \ + } while (0) + +static void +recall_cbk(struct glfs_lease lease, void *data) +{ + int ret = -1; + char ld[GLFS_LEASE_ID_SIZE] = ""; + + fprintf(log_file, "\nRECALL received on lease_id:(%s)", lease.lease_id); + memcpy(ld, lease.lease_id, GLFS_LEASE_ID_SIZE); + ret = unlk_write_lease((glfs_fd_t *)data, ld); + VERIFY_RESULT(500, ret, SHUD_PASS); +error: + return; +} + +static int +testcase_recall_conflict_lease() +{ + struct glfs_object *obj = NULL; + glfs_fd_t *fd1 = NULL; + int ret = 0; + struct glfs_lease lease = { + 0, + }; + + fprintf(log_file, + "\n Basic test case for conflicting lease causing recall"); + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, lid2, GLFS_LEASE_ID_SIZE); + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDWR, fd1, lid1); + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + /* reset counter */ + upcall_recv = 0; + + obj = glfs_h_lookupat(client2, NULL, TEST_FILE, NULL, 0); + ret = glfs_h_lease(client2, obj, &lease); + VERIFY_RESULT(2, ret, SHUD_FAIL); + + sleep(3); + /* should recv upcall */ + VERIFY_RESULT(6, !upcall_recv, SHUD_PASS); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = glfs_h_close(obj); + VERIFY_RESULT(3, ret, SHUD_PASS); + ret = glfs_close(fd1); + VERIFY_RESULT(4, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + int i = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd1 = NULL; + char *topdir = "topdir", *filename = "file1"; + char *buf = NULL; + int x = 0; + ssize_t xattr_size = -1; + + if (argc != 4) { + fprintf(stderr, + "Expect following args %s <Vol> <glfs client log file> " + "<testcase log file>\n", + argv[0]); + return -1; + } + + log_file = fopen(argv[3], "w"); + if (!log_file) + goto error; + + volname = argv[1]; + glfs_log_file = argv[2]; + + /* Setup 2 clients */ + client1 = setup_new_client(volname, glfs_log_file); + client2 = setup_new_client(volname, glfs_log_file); + + ret = testcase_recall_conflict_lease(); + VERIFY_RESULT(101, ret, SHUD_PASS); + + glfs_fini(client1); + glfs_fini(client2); + + fclose(log_file); + return 0; +error: + return -1; +} diff --git a/tests/features/glfs-lease.c b/tests/features/glfs-lease.c new file mode 100644 index 00000000000..e82cd875b38 --- /dev/null +++ b/tests/features/glfs-lease.c @@ -0,0 +1,717 @@ +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> + +/* Few rules: + * 1. A client may have multiple lease keys, but a lease key cannot be shared by + * multiple clients. + * 2. Lease key can be set before open, or in glfs_lease request. A lease key + * set like this is valid for the lifetime of the fd, i.e. a fd cannot have + * multiple lease key. But a lease key can be shared across multiple fds. + */ +glfs_t *client1 = NULL, *client2 = NULL, *client3 = NULL, *client4 = NULL; +glfs_fd_t *fd1 = NULL, *fd2 = NULL, *fd3 = NULL, *fd4 = NULL; +FILE *log_file = NULL; +char lid1[GLFS_LEASE_ID_SIZE] = "lid1-clnt1", + lid2[GLFS_LEASE_ID_SIZE] = "lid2-clnt2"; +char lid3[GLFS_LEASE_ID_SIZE] = "lid3-clnt2", lid4[GLFS_LEASE_ID_SIZE] = { + 0, +}; +char *volname = NULL, *glfs_log_file = NULL; + +#define MAX_CLIENTS 4 +#define MAX_FDS 4 +#define TEST_FILE "/test/lease" +#define SHUD_PASS 0 +#define SHUD_FAIL -1 +#define NONE 0 + +static void +recall_cbk(struct glfs_lease lease, void *data); + +static int +set_read_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, fd); + if (ret < 0) { + fprintf(log_file, "\n RD_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Took RD_LEASE"); + return ret; +} + +static int +set_write_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RW_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n RW_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Took RW_LEASE"); + return ret; +} + +static int +get_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_GET_LEASE; + lease.lease_type = -1; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n GET_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + if (lease.lease_type == GLFS_RD_LEASE) + fprintf(log_file, "\n Esisting Lease: RD_LEASE"); + else if (lease.lease_type == GLFS_RW_LEASE) + fprintf(log_file, "\n Esisting Lease: RW_LEASE"); + else if (lease.lease_type == 3) + fprintf(log_file, "\n Esisting Lease: RD_LEASE|RW_LEASE"); + else if (lease.lease_type == 0) + fprintf(log_file, "\n Esisting Lease: NONE"); + else + fprintf(log_file, "\n Existing lease type:%d", lease.lease_type); + return lease.lease_type; +} + +static int +unlk_write_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_UNLK_LEASE; + lease.lease_type = GLFS_RW_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n Unlock RW_LESAE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Unlocked RW_LEASE"); + return ret; +} + +static int +unlk_read_lease(glfs_fd_t *fd, char ld[]) +{ + struct glfs_lease lease = { + 0, + }; + int ret = 0; + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_UNLK_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, ld, GLFS_LEASE_ID_SIZE); + + ret = glfs_lease(fd, &lease, &recall_cbk, NULL); + if (ret < 0) { + fprintf(log_file, "\n Unlock RD_LEASE failed with ret: %d (%s)", ret, + strerror(errno)); + return -1; + } + fprintf(log_file, "\n Unlocked RD_LEASE"); + return ret; +} + +glfs_t * +setup_new_client(char *volname, char *log_fileile) +{ + int ret = 0; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + fprintf(log_file, "\nglfs_new: returned NULL (%s)\n", strerror(errno)); + goto error; + } + + ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); + if (ret < 0) { + fprintf(log_file, "\nglfs_set_volfile_server failed ret:%d (%s)\n", ret, + strerror(errno)); + goto error; + } + + ret = glfs_set_logging(fs, log_fileile, 7); + if (ret < 0) { + fprintf(log_file, "\nglfs_set_logging failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(log_file, "\nglfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + return fs; +error: + return NULL; +} + +#define OPEN(client, flags, fd, lease_id) \ + do { \ + int ret_val = 0; \ + ret_val = glfs_setfsleaseid(lease_id); \ + if (ret_val) { \ + fprintf(log_file, \ + "\nglfs_setfsleaseid failed with ret: %d (%s)\n", ret, \ + strerror(errno)); \ + return -1; \ + } \ + fd = glfs_open(client, TEST_FILE, flags); \ + if (fd == NULL) { \ + fprintf(log_file, "\nglfs_open failed with ret: %d (%s)\n", ret, \ + strerror(errno)); \ + return -1; \ + } \ + } while (0) + +#define VERIFY_RESULT(test_case, ret, value) \ + do { \ + if (ret != value) { \ + fprintf(log_file, \ + "\n Testcase %d failed, ret = %d, value=%d\n", \ + test_case, ret, value); \ + goto error; /*test unsuccessful*/ \ + } \ + fprintf(log_file, "\n Testcase %d Succeeded\n", test_case); \ + } while (0) + +static void +recall_cbk(struct glfs_lease lease, void *data) +{ + int ret = -1; + char ld[GLFS_LEASE_ID_SIZE] = ""; + + fprintf(log_file, "\nRECALL received on lease_id:(%s)", lease.lease_id); + memcpy(ld, lease.lease_id, GLFS_LEASE_ID_SIZE); + ret = unlk_write_lease((glfs_fd_t *)data, ld); + VERIFY_RESULT(500, ret, SHUD_PASS); +error: + return; +} + +static int +testcase1_rd_lease() +{ + glfs_fd_t *fd1 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for Read lease:"); + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDONLY, fd1, lid1); + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_FAIL); + + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(3, ret, GLFS_RD_LEASE); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(4, ret, SHUD_FAIL); + + ret = unlk_read_lease(fd1, lid1); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(6, ret, NONE); + + ret = unlk_read_lease(fd1, lid1); + VERIFY_RESULT(7, ret, SHUD_PASS); + + ret = glfs_close(fd1); + VERIFY_RESULT(8, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase2_wr_lease() +{ + glfs_fd_t *fd1 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for Write lease:"); + /* Open fd on client 1 in WRonly mode */ + OPEN(client1, O_WRONLY, fd1, lid1); + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_FAIL); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(3, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(4, ret, GLFS_RW_LEASE); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(6, ret, NONE); + + ret = unlk_read_lease(fd1, lid1); + VERIFY_RESULT(7, ret, SHUD_FAIL); + + ret = glfs_close(fd1); + VERIFY_RESULT(8, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase3_rd_wr_lease() +{ + glfs_fd_t *fd1 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for Read Write lease:"); + /* Open fd on client 1 in WRonly mode */ + OPEN(client1, O_RDWR, fd1, lid1); + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(3, ret, (GLFS_RW_LEASE | GLFS_RD_LEASE)); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(5, ret, GLFS_RD_LEASE); + + ret = unlk_read_lease(fd1, lid1); + VERIFY_RESULT(6, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(7, ret, NONE); + + ret = glfs_close(fd1); + VERIFY_RESULT(8, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase4_rd_lease_multi_clnt() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for multi client Read lease:"); + + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDONLY, fd1, lid1); + + /* Open fd on client 2 in RW mode */ + OPEN(client2, O_RDONLY, fd2, lid2); + + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + ret = set_read_lease(fd2, lid2); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(3, ret, GLFS_RD_LEASE); + + ret = unlk_read_lease(fd1, lid1); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = unlk_read_lease(fd2, lid2); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(6, ret, NONE); + + ret = get_lease(fd2, lid2); + VERIFY_RESULT(7, ret, NONE); + + ret = glfs_close(fd1); + VERIFY_RESULT(8, ret, SHUD_PASS); + + ret = glfs_close(fd2); + VERIFY_RESULT(9, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase5_openfd_multi_lid() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + glfs_fd_t *fd3 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for multi lid openfd check:"); + + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDONLY, fd1, lid1); + + /* Open fd on client 2 in RW mode */ + OPEN(client2, O_RDWR, fd2, lid2); + OPEN(client2, O_RDWR, fd3, lid2); + + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT( + 1, ret, + SHUD_FAIL); /*As there are other openfds in WR mode from diff lid*/ + + ret = set_write_lease(fd2, lid2); + VERIFY_RESULT( + 2, ret, SHUD_FAIL); /*As thers is another fd in RD mode from diff lid */ + + ret = glfs_close(fd1); + VERIFY_RESULT(3, ret, SHUD_PASS); + + ret = set_write_lease(fd2, lid2); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = unlk_write_lease(fd2, lid2); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = glfs_close(fd2); + VERIFY_RESULT(6, ret, SHUD_PASS); + + ret = glfs_close(fd3); + VERIFY_RESULT(7, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase6_openfd_same_lid() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + glfs_fd_t *fd3 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for same lid openfd check:"); + + /* Open fd on client 2 in RW mode */ + OPEN(client1, O_RDWR, fd1, lid2); + OPEN(client1, O_RDWR, fd2, lid2); + + ret = set_write_lease(fd1, lid2); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = set_write_lease(fd2, lid2); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = set_read_lease(fd2, lid2); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = unlk_write_lease(fd1, lid2); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = unlk_read_lease(fd2, lid2); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = unlk_write_lease(fd2, lid2); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = glfs_close(fd1); + VERIFY_RESULT(6, ret, SHUD_PASS); + + ret = glfs_close(fd2); + VERIFY_RESULT(7, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase7_rd_multi_lid() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for multi lease id Read lease:"); + + /* Open fd on client 1 in RD mode */ + OPEN(client2, O_RDONLY, fd1, lid2); + + /* Open fd on client 2 in RD mode */ + OPEN(client2, O_RDONLY, fd2, lid3); + + ret = set_read_lease(fd1, lid2); + VERIFY_RESULT(1, ret, SHUD_PASS); + + ret = set_read_lease(fd2, lid3); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = get_lease(fd1, lid2); + VERIFY_RESULT(3, ret, GLFS_RD_LEASE); + + ret = unlk_read_lease(fd1, lid2); + VERIFY_RESULT(4, ret, SHUD_PASS); + + ret = unlk_read_lease(fd2, lid3); + VERIFY_RESULT(5, ret, SHUD_PASS); + + ret = get_lease(fd1, lid2); + VERIFY_RESULT(6, ret, NONE); + + ret = get_lease(fd2, lid3); + VERIFY_RESULT(7, ret, NONE); + + ret = glfs_close(fd1); + VERIFY_RESULT(8, ret, SHUD_PASS); + + ret = glfs_close(fd2); + VERIFY_RESULT(9, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase8_client_disconnect() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for client disconnect cleanup"); + + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDWR, fd1, lid1); + + ret = set_read_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(2, ret, GLFS_RD_LEASE); + + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(3, ret, SHUD_PASS); + + ret = get_lease(fd1, lid1); + VERIFY_RESULT(4, ret, (GLFS_RD_LEASE | GLFS_RW_LEASE)); + + ret = glfs_fini(client1); + VERIFY_RESULT(5, ret, SHUD_PASS); + + /* Open fd on client 2 in RD mode */ + OPEN(client2, O_RDONLY, fd2, lid3); + + ret = get_lease(fd2, lid3); + VERIFY_RESULT(6, ret, NONE); + + ret = glfs_close(fd2); + VERIFY_RESULT(7, ret, SHUD_PASS); + + client1 = setup_new_client(volname, glfs_log_file); + + return 0; +error: + return -1; +} + +static int +testcase9_recall_conflict_lease() +{ + struct glfs_object *obj = NULL; + glfs_fd_t *fd1 = NULL; + int ret = 0; + struct glfs_lease lease = { + 0, + }; + + fprintf(log_file, + "\n Basic test case for conflicting lease causing recall"); + + memset(&lease, 0, sizeof(lease)); + lease.cmd = GLFS_SET_LEASE; + lease.lease_type = GLFS_RD_LEASE; + memcpy(&lease.lease_id, lid2, GLFS_LEASE_ID_SIZE); + /* Open fd on client 1 in RD mode */ + OPEN(client1, O_RDWR, fd1, lid1); + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + obj = glfs_h_lookupat(client2, NULL, TEST_FILE, NULL, 0); + ret = glfs_h_lease(client2, obj, &lease); + VERIFY_RESULT(2, ret, SHUD_FAIL); + + ret = unlk_write_lease(fd1, lid1); + VERIFY_RESULT(5, ret, SHUD_PASS); + + sleep(3); + ret = glfs_h_close(obj); + VERIFY_RESULT(3, ret, SHUD_PASS); + ret = glfs_close(fd1); + VERIFY_RESULT(4, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +static int +testcase10_recall_open_conflict() +{ + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + int ret = 0; + + fprintf(log_file, "\n Basic test case for conflicting open causing recall"); + + /* Open fd on client 1 in RW mode */ + OPEN(client1, O_RDWR, fd1, lid1); + + ret = set_write_lease(fd1, lid1); + VERIFY_RESULT(1, ret, SHUD_PASS); + + /* Open fd on client 1 in RW mode */ + OPEN(client2, O_RDWR, fd2, lid2); + + /* TODO: Check for recall cbk functionality */ + ret = glfs_close(fd1); + VERIFY_RESULT(2, ret, SHUD_PASS); + + ret = glfs_close(fd2); + VERIFY_RESULT(3, ret, SHUD_PASS); + + return 0; +error: + return -1; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + int i = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd1 = NULL; + char *topdir = "topdir", *filename = "file1"; + char *buf = NULL; + int x = 0; + ssize_t xattr_size = -1; + + if (argc != 4) { + fprintf(stderr, + "Expect following args %s <Vol> <glfs client log file> " + "<testcase log file>\n", + argv[0]); + return -1; + } + + log_file = fopen(argv[3], "w"); + if (!log_file) + goto error; + + volname = argv[1]; + glfs_log_file = argv[2]; + + /* Setup 3 clients */ + client1 = setup_new_client(volname, glfs_log_file); + client2 = setup_new_client(volname, glfs_log_file); + client3 = setup_new_client(volname, glfs_log_file); + + ret = testcase1_rd_lease(); + VERIFY_RESULT(101, ret, SHUD_PASS); + + ret = testcase2_wr_lease(); + VERIFY_RESULT(102, ret, SHUD_PASS); + + ret = testcase3_rd_wr_lease(); + VERIFY_RESULT(103, ret, SHUD_PASS); + + ret = testcase4_rd_lease_multi_clnt(); + VERIFY_RESULT(104, ret, SHUD_PASS); + + ret = testcase5_openfd_multi_lid(); + VERIFY_RESULT(105, ret, SHUD_PASS); + + ret = testcase6_openfd_same_lid(); + VERIFY_RESULT(106, ret, SHUD_PASS); + + ret = testcase7_rd_multi_lid(); + VERIFY_RESULT(107, ret, SHUD_PASS); + + ret = testcase8_client_disconnect(); + VERIFY_RESULT(108, ret, SHUD_PASS); + + ret = testcase9_recall_conflict_lease(); + VERIFY_RESULT(109, ret, SHUD_PASS); + + ret = testcase10_recall_open_conflict(); + VERIFY_RESULT(110, ret, SHUD_PASS); + + glfs_fini(client1); + glfs_fini(client2); + glfs_fini(client3); + + fclose(log_file); + return 0; +error: + return -1; +} diff --git a/tests/features/glfs-lease.t b/tests/features/glfs-lease.t new file mode 100755 index 00000000000..6ef6da05043 --- /dev/null +++ b/tests/features/glfs-lease.t @@ -0,0 +1,31 @@ +#!/bin/bash +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/${V0}; +TEST $CLI volume set $V0 leases on +TEST $CLI volume set $V0 open-behind off +TEST $CLI volume set $V0 write-behind on +TEST $CLI volume start $V0 + +logdir=`gluster --print-logdir` +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST mkdir $M0/test +TEST touch $M0/test/lease + +build_tester $(dirname $0)/glfs-lease.c -lgfapi +build_tester $(dirname $0)/glfs-lease-recall.c -lgfapi +TEST $(dirname $0)/glfs-lease $V0 $logdir/glfs-lease.log $logdir/lease-test.log +TEST $(dirname $0)/glfs-lease-recall $V0 $logdir/glfs-lease-recall.log $logdir/lease-test-recall.log + +TEST $CLI volume set $V0 leases off + +cleanup_tester $(dirname $0)/glfs-lease +cleanup; diff --git a/tests/features/glupy.t b/tests/features/glupy.t deleted file mode 100755 index 8b79a148d4d..00000000000 --- a/tests/features/glupy.t +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc -. $(dirname $0)/../volume.rc - -echo $PYTHON_PATH >&2 -cleanup; - -TEST mkdir -p $B0/glupytest -cat > $B0/glupytest.vol <<EOF -volume vol-posix - type storage/posix - option directory $B0/glupytest -end-volume - -volume vol-glupy - type features/glupy - option module-name helloworld - subvolumes vol-posix -end-volume -EOF - -TEST glusterfs -f $B0/glupytest.vol $M0; - -TEST touch $M0/filename; -EXPECT "filename" ls $M0 -TEST rm -f $M0/filename; - -EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0; - -cleanup; diff --git a/tests/features/interrupt.t b/tests/features/interrupt.t new file mode 100644 index 00000000000..067eb1b7486 --- /dev/null +++ b/tests/features/interrupt.t @@ -0,0 +1,71 @@ +#!/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 + +TESTS_EXPECTED_IN_LOOP=4 + +cleanup; +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/open_and_sleep.c + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6,7,8,9}; + +## 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` + +function test_interrupt { + local handlebool="$1" + local logpattern="$2" + + TEST $GFS --volfile-id=$V0 --volfile-server=$H0 --fuse-flush-handle-interrupt=$handlebool --log-level=DEBUG $M0 + + # If the test helper fails (which is considered a setup error, not failure of the test + # case itself), kill will be invoked without argument, and that will be the actual + # error which is caught. + TEST "./$(dirname $0)/open_and_sleep $M0/testfile-$handlebool | { sleep 0.1; xargs -n1 kill -INT; }" + + TEST "grep -E '$logpattern' $log_file" + # Basic sanity check, making sure filesystem has not crashed. + TEST test -f $M0/testfile-$handlebool +} + +# Theoretically FLUSH might finish before INTERRUPT is handled, +# in which case we'd get the "no handler found" message instead of +# "interrupt handler triggered" (but it's unlikely). +# If that's observed, the pattern can be changed to +# 'FLUSH.*interrupt handler triggered|[I]NTERRUPT.*no handler found' +# to fix the test. +test_interrupt yes '[F]LUSH.*interrupt handler triggered' +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +test_interrupt no '[I]NTERRUPT.*no handler found' + +## Finish up +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +cleanup_tester $(dirname $0)/open_and_sleep; +cleanup; diff --git a/tests/features/ipc.t b/tests/features/ipc.t new file mode 100755 index 00000000000..5c92287eaa1 --- /dev/null +++ b/tests/features/ipc.t @@ -0,0 +1,38 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=GH269 +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=GH269 + +cleanup; +mkdir -p $B0/1 +mkdir -p $M0 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/1 +TEST $CLI volume start $V0 + +# Find OS-dependent EOPNOTSUPP value from system headers +EOPNOTSUPP=$( echo '#include <errno.h>\\EOPNOTSUPP\\' | tr '\\' '\n' | \ + cc -E -c - | tail -1 ) + +# liglusterfs embbeds its own UUID implementation. The function name +# may be the same as in built(in implementation from libc, but with +# different prototype. In that case, we must make sure python will +# use libglusterfs's version, and dlopen() does not make any guarantee +# on this. By preloading libglusterfs.so before launching python, we +# ensure libglusterfs's UUID functions will be used. +LD_PRELOAD=${prefix}/lib/libglusterfs.so +export LD_PRELOAD + +# This is a pretty lame test. Basically we just want to make sure that we +# get all the way through the translator stacks on client and server to get a +# simple error (EOPNOTSUPP) instead of a crash, RPC error, etc. +EXPECT ${EOPNOTSUPP} $PYTHON $(dirname $0)/ipctest.py $H0 $V0 + +unset LD_PRELOAD +cleanup; diff --git a/tests/features/ipctest.py b/tests/features/ipctest.py new file mode 100755 index 00000000000..f6f699cf5c4 --- /dev/null +++ b/tests/features/ipctest.py @@ -0,0 +1,28 @@ + +from __future__ import print_function +import ctypes + +api = ctypes.CDLL("libgfapi.so", mode=ctypes.RTLD_GLOBAL) + +api.glfs_ipc.argtypes = [ ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p ] +api.glfs_ipc.restype = ctypes.c_int + +def do_ipc (host, volume): + fs = api.glfs_new(volume) + #api.glfs_set_logging(fs, "/dev/stderr", 7) + api.glfs_set_volfile_server(fs, "tcp", host, 24007) + + api.glfs_init(fs) + ret = api.glfs_ipc(fs, 1470369258, 0, 0) + api.glfs_fini(fs) + + return ret + +if __name__ == "__main__": + import sys + + try: + res = do_ipc(*sys.argv[1:3]) + print(res) + except: + print("IPC failed (volume not started?)") diff --git a/tests/features/lock_revocation.t b/tests/features/lock_revocation.t new file mode 100644 index 00000000000..67bc13159f9 --- /dev/null +++ b/tests/features/lock_revocation.t @@ -0,0 +1,54 @@ +#!/bin/bash +logdir=$(gluster --print-logdir) +BRICK_LOGFILES="$logdir/bricks/d-backends-brick?.log" +rm -f $BRICK_LOGFILES &> /dev/null + +# Test that lock revocation works + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +cleanup; + +function deadlock_fop() { + local MNT=$1 + for i in {1..1000}; do + dd if=/dev/zero of=$MNT/testfile bs=1k count=10 &> /dev/null + if grep "MONKEY LOCKING" $BRICK_LOGFILES &> /dev/null; then + break + fi + done +} + +function monkey_unlock() { + grep "MONKEY LOCKING" $BRICK_LOGFILES &> /dev/null && echo SUCCESS + return 0 +} + +function append_to_file() { + local FILE_PATH=$1 + echo "hello" >> $FILE_PATH + return 0 +} + +#Init +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 features.locks-monkey-unlocking on +TEST $CLI volume set $V0 features.locks-revocation-secs 2 +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 -s $H0 $M0; +TEST $GFS --volfile-id=$V0 -s $H0 $M1; + +# Deadlock writes to a file using monkey unlocking +deadlock_fop $M0 & +EXPECT_WITHIN 60 "SUCCESS" monkey_unlock + +# Sleep > unlock timeout and attempt to write to the file +sleep 3 +TEST append_to_file $M1/testfile + +cleanup +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1369401 +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=1448364 diff --git a/tests/features/mandatory-lock-forced.c b/tests/features/mandatory-lock-forced.c new file mode 100644 index 00000000000..4028d6c6eaf --- /dev/null +++ b/tests/features/mandatory-lock-forced.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> + +#define LOG_ERR(func, err) \ + do { \ + fprintf(stderr, "%s : returned error (%s)\n", func, strerror(err)); \ + exit(err); \ + } while (0) + +int fd; +struct flock lock; +char *buf = "ten bytes!"; +char *fname = "/mnt/glusterfs/0/mand.lock"; +int open_flags, child, err, status, blocked = 0; + +int +do_child(char *argv[]) +{ + /* Initialize file open flags */ + if (strcmp(argv[2], "BLOCK") == 0) + open_flags = O_RDWR; + else if (strcmp(argv[2], "TRUNC") == 0) + open_flags = O_RDWR | O_TRUNC | O_NONBLOCK; + else if (strcmp(argv[2], "NONE") == 0) + open_flags = O_RDWR | O_NONBLOCK; + else + LOG_ERR("Invalid option:", EINVAL); + + /* Open the file */ + fd = open(fname, open_flags); + if (fd == -1) + LOG_ERR("Child open", errno); + + /* Perform the file operation*/ + if (strcmp(argv[3], "READ") == 0) { + buf = NULL; + err = read(fd, buf, 10); + if (err == -1) + LOG_ERR("Child read", errno); + } else if (strcmp(argv[3], "WRITE") == 0) { + err = write(fd, buf, 10); + if (err == -1) + LOG_ERR("Child write", errno); + } else if (strcmp(argv[3], "FTRUNCATE") == 0) { + err = ftruncate(fd, 5); + if (err) + LOG_ERR("Child ftruncate", errno); + } else + LOG_ERR("Invalid operation:", EINVAL); + + /* Close child fd */ + err = close(fd); + if (err) + LOG_ERR("Child close", errno); + + /* Exit success */ + exit(0); +} + +int +main(int argc, char *argv[]) +{ + if (argc < 4) { + fprintf(stderr, + "Wrong usage: Use as ./mandatory-lock " + "<RD_LCK/WR_LCK> <BLOCK/TRUNC/NONE> " + "<READ/WRITE/FTRUNCATE\n"); + exit(EINVAL); + } + /* Create an empty lock file */ + fd = open(fname, O_CREAT | O_RDWR, 0755); + if (fd == -1) + LOG_ERR("Parent create", errno); + + /* Determine the type of lock */ + if (strcmp(argv[1], "RD_LCK") == 0) + lock.l_type = F_RDLCK; + else if (strcmp(argv[1], "WR_LCK") == 0) + lock.l_type = F_WRLCK; + else + LOG_ERR("Parent lock type", EINVAL); + + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 0L; + + /* Let parent acquire the initial lock */ + err = fcntl(fd, F_SETLK, &lock); + if (err) + LOG_ERR("Parent lock", errno); + + /* Now fork a child */ + child = fork(); + if (child == 0) + /* Perform the child operations */ + do_child(argv); + else { + /* If blocking mode, then sleep for 2 seconds + * and wait for the child */ + if (strcmp(argv[2], "NONE") != 0) { + sleep(2); + if (waitpid(child, &status, WNOHANG) == 0) + blocked = 1; + /* Release the parent lock so that the + * child can terminate */ + lock.l_type = F_UNLCK; + err = fcntl(fd, F_SETLK, &lock); + if (err) + LOG_ERR("Parent unlock", errno); + } + + /* Wait for child to finish */ + waitpid(child, &status, 0); + + /* Close the parent fd */ + err = close(fd); + if (err) + LOG_ERR("Parent close", errno); + + /* Remove the lock file*/ + err = unlink(fname); + if (err) + LOG_ERR("Parent unlink", errno); + + /* If not blocked, exit with child exit status*/ + errno = WEXITSTATUS(status); + + /* If blocked, exit with corresponding + * error code */ + if (blocked) + errno = EWOULDBLOCK; + + if (errno != 0) + printf("%s\n", strerror(errno)); + + exit(errno); + } +} diff --git a/tests/features/mandatory-lock-forced.t b/tests/features/mandatory-lock-forced.t new file mode 100644 index 00000000000..563669c6774 --- /dev/null +++ b/tests/features/mandatory-lock-forced.t @@ -0,0 +1,80 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; +# Start glusterd [1] +TEST glusterd + +# Create and verify the volume information [2-4] +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2}; +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; + +# Turn off the performance translators [5-9] +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.read-ahead off + +# Start and mount the volume [10-11] +TEST $CLI volume start $V0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +build_tester $(dirname $0)/mandatory-lock-forced.c -o $(dirname $0)/mandatory-lock + +# Various read/write tests without enabling mandatory-locking [12-18] +$(dirname $0)/mandatory-lock RD_LCK NONE READ +TEST [ $? -eq 0 ] + +$(dirname $0)/mandatory-lock RD_LCK NONE WRITE +TEST [ $? -eq 0 ] + +$(dirname $0)/mandatory-lock WR_LCK NONE READ +TEST [ $? -eq 0 ] + +$(dirname $0)/mandatory-lock WR_LCK NONE WRITE +TEST [ $? -eq 0 ] + +# Specifies O_TRUNC during open +$(dirname $0)/mandatory-lock RD_LCK TRUNC READ +TEST [ $? -eq 0 ] + +$(dirname $0)/mandatory-lock RD_LCK NONE FTRUNCATE +TEST [ $? -eq 0 ] + +$(dirname $0)/mandatory-lock RD_LCK BLOCK WRITE +TEST [ $? -eq 0 ] + +# Enable mandatory-locking [19] +TEST $CLI volume set $V0 mandatory-locking forced + +# Restart the volume to take the change into effect [20-23] +TEST umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +# Repeat the above tests with mandatory-locking [24-30] +$(dirname $0)/mandatory-lock RD_LCK NONE READ +TEST [ $? -eq 0 ] + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock RD_LCK NONE WRITE + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock WR_LCK NONE READ + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock WR_LCK NONE WRITE + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock RD_LCK TRUNC READ + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock RD_LCK NONE FTRUNCATE + +EXPECT "Resource temporarily unavailable" $(dirname $0)/mandatory-lock RD_LCK BLOCK WRITE + +rm -rf $(dirname $0)/mandatory-lock + +cleanup + +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1326464 diff --git a/tests/features/nuke.t b/tests/features/nuke.t new file mode 100755 index 00000000000..f1f5f9f90ab --- /dev/null +++ b/tests/features/nuke.t @@ -0,0 +1,41 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +create_files () { + mkdir $1 + for i in $(seq 0 99); do + mkdir $1/dir$i + for j in $(seq 0 99); do + touch $1/dir$i/file$j + done + done +} + +count_files () { + ls $1 | wc -l +} + +LANDFILL=$B0/${V0}1/.glusterfs/landfill + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2} +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +TEST create_files $M0/foo +TEST [ $(count_files $LANDFILL) = "0" ] + +# This should immediately send the whole directory to the landfill. +TEST setfattr -n glusterfs.dht.nuke -v trinity $M0/foo + +# Make sure the directory's not visible on the mountpoint, and is visible in +# the brick's landfill. +TEST ! ls $M0/foo +TEST [ $(count_files $LANDFILL) = "1" ] + +# Make sure the janitor thread cleans it up in a timely fashion. +EXPECT_WITHIN 60 "0" count_files $LANDFILL + +cleanup diff --git a/tests/features/open_and_sleep.c b/tests/features/open_and_sleep.c new file mode 100644 index 00000000000..7d0e22a2503 --- /dev/null +++ b/tests/features/open_and_sleep.c @@ -0,0 +1,27 @@ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> + +int +main(int argc, char **argv) +{ + pid_t pid; + int fd; + + if (argc >= 2) { + fd = open(argv[1], O_RDWR | O_CREAT, 0644); + if (fd == -1) { + fprintf(stderr, "cannot open/create %s\n", argv[1]); + return 1; + } + } + + pid = getpid(); + printf("%d\n", pid); + fflush(stdout); + + for (;;) + sleep(1); + + return 0; +} diff --git a/tests/features/openssl.cnf.in b/tests/features/openssl.cnf.in new file mode 100644 index 00000000000..1fce34b11b9 --- /dev/null +++ b/tests/features/openssl.cnf.in @@ -0,0 +1,41 @@ +[ req ] +distinguished_name = req_distinguished_name +x509_extensions = v3_ca +[ req_distinguished_name ] +commonName = Common Name +commonName_max = 64 +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = CA:true +[ ca ] +default_ca = CA_default +[ CA_default ] +dir = @TMPDIR@ +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subjecta = no +new_certs_dir = $dir/newcerts +certificate = $dir/ca.crt +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/self.key +x509_extensions = usr_cert +name_opt = ca_default +cert_opt = ca_default +default_days = 365 +default_crl_days = 30 +crl_extensions = crl_ext +default_md = sha256 +preserve = no +policy = policy_test +[ policy_test ] +commonName = supplied +[ usr_cert ] +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +crlDistributionPoints = URI:file://@TMPDIR@/crl.pem +[ crl_ext ] +authorityKeyIdentifier = keyid:always,issuer:always diff --git a/tests/features/recon.t b/tests/features/recon.t new file mode 100644 index 00000000000..82ef6fd755d --- /dev/null +++ b/tests/features/recon.t @@ -0,0 +1,59 @@ +#!/bin/bash + +. $(dirname $0)/../traps.rc +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../fdl.rc + +tmpdir=$(mktemp -d -t ${0##*/}.XXXXXX) +push_trapfunc "rm -rf $tmpdir" + +write_file () { + echo "peekaboo" > $1 +} + +TEST rm -f $FDL_META_FILE $FDL_DATA_FILE +TEST glusterd +TEST pidof glusterd + +# Get a simple volume set up and mounted with FDL active. +TEST $CLI volume create $V0 ${H0}:${B0}/${V0}-0 +TEST $CLI volume set $V0 features.fdl on +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +# Generate some I/O and then copy off the journal files for later. +TEST mkdir -p $M0/abc/def +TEST write_file $M0/abc/def/ghi +#EST chmod 314 $M0/abc/def/ghi +cp ${FDL_META_FILE} ${FDL_DATA_FILE} ${tmpdir} + +# Get back to an empty state and unmount. +TEST rm -rf $M0/abc +TEST umount $M0 + +# Make sure we really are in an empty state. Otherwise the tests below could +# pass just because we never cleaned up in the first place. +TEST [ ! -d ${B0}/${V0}-0/abc ] + +# Create a stub volfile. +vol_file=${GLUSTERD_WORKDIR}/vols/${V0}/${V0}.${H0}.${log_id}.vol +vol_id_line=$(grep volume-id ${vol_file}) +cat > ${tmpdir}/recon.vol << EOF +volume recon-posix + type storage/posix + option directory ${B0}/${V0}-0 +${vol_id_line} +end-volume +EOF + +TEST gf_recon ${tmpdir}/recon.vol ${tmpdir}/$(basename ${FDL_META_FILE}) \ + ${tmpdir}/$(basename ${FDL_DATA_FILE}) + +TEST [ -d ${B0}/${V0}-0/abc/def ] +EXPECT "peekaboo" cat ${B0}/${V0}-0/abc/def/ghi +# TBD: test permissions, xattrs + +cleanup +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=1385758 +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1385758 diff --git a/tests/features/ssl-authz.t b/tests/features/ssl-authz.t index 17ae356717c..497083e5a3a 100755 --- a/tests/features/ssl-authz.t +++ b/tests/features/ssl-authz.t @@ -25,6 +25,7 @@ TEST glusterd TEST pidof glusterd TEST $CLI volume info; +TEST $CLI v set all cluster.brick-multiplex on # Construct a cipher list that excludes CBC because of POODLE. # http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3566 # @@ -41,16 +42,16 @@ function valid_ciphers { -e '/:$/s///' } -TEST openssl genrsa -out $SSL_KEY 1024 +TEST openssl genrsa -out $SSL_KEY 2048 TEST openssl req -new -x509 -key $SSL_KEY -subj /CN=Anyone -out $SSL_CERT ln $SSL_CERT $SSL_CA -TEST $CLI volume create $V0 $H0:$B0/1 +TEST $CLI volume create $V0 replica 3 $H0:$B0/{1,2,3} force TEST $CLI volume set $V0 server.ssl on TEST $CLI volume set $V0 client.ssl on -#EST $CLI volume set $V0 ssl.cipher-list $(valid_ciphers) +TEST $CLI volume set $V0 ssl.cipher-list $(valid_ciphers) TEST $CLI volume start $V0 -EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" online_brick_count # This mount should SUCCEED because ssl-allow=* by default. This effectively # disables SSL authorization, though authentication and encryption might still @@ -59,11 +60,28 @@ TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0 TEST ping_file $M0/before EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +glusterfsd_pid=`pgrep glusterfsd` +TEST [ $glusterfsd_pid != 0 ] +start=`pmap -x $glusterfsd_pid | grep total | awk -F " " '{print $4}'` +echo "Memory consumption for glusterfsd process" +for i in $(seq 1 100); do + gluster v heal $V0 info >/dev/null +done +#Wait to cleanup memory +sleep 10 +end=`pmap -x $glusterfsd_pid | grep total | awk -F " " '{print $4}'` +diff=$((end-start)) + +# If memory consumption is more than 15M some leak in SSL code path + +TEST [ $diff -lt 15000 ] + + # Set ssl-allow to a wildcard that includes our identity. TEST $CLI volume stop $V0 TEST $CLI volume set $V0 auth.ssl-allow Any* TEST $CLI volume start $V0 -EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" online_brick_count # This mount should SUCCEED because we match the wildcard. TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0 diff --git a/tests/features/ssl-ciphers.t b/tests/features/ssl-ciphers.t new file mode 100644 index 00000000000..b70fe360e02 --- /dev/null +++ b/tests/features/ssl-ciphers.t @@ -0,0 +1,244 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +brick_port() { + $CLI --xml volume status $1 | sed -n '/.*<port>\([0-9]*\).*/s//\1/p' +} + +wait_mount() { + i=1 + while [ $i -lt $CONFIG_UPDATE_TIMEOUT ] ; do + sleep 1 + i=$(( $i + 1 )) + mounted=`mount|awk -v m=$1 ' + BEGIN {r = "N";} + ($3 == m) {r = "Y"; exit;} + END {print r;} + '` + if [ "x${mounted}" = "xY" ] ; then + ls $M0 2>/dev/null || continue + break; + fi + done + + if [ "x${mounted}" = "xY" ] ; then + ls $M0 2>/dev/null || mounted="N" + fi + + echo $mounted +} + +openssl_connect() { + ssl_opt="-verify 3 -verify_return_error -CAfile $SSL_CA" + ssl_opt="$ssl_opt -crl_check_all -CApath $TMPDIR" + cmd="echo "" | openssl s_client $ssl_opt $@ 2>/dev/null" + CIPHER=$(eval $cmd | awk -F "Cipher is" '{print $2}' | tr -d '[:space:]' | awk -F " " '{print $1}') + if [ "x${CIPHER}" = "x" -o "x${CIPHER}" = "x0000" -o "x${CIPHER}" = "x(NONE)" ] ; then + echo "N" + else + echo "Y" + fi +} + +#Validate the cipher to pass EXPECT test case before call openssl_connect +check_cipher() { + cmd="echo "" | openssl s_client $@ 2> /dev/null" + cipher=$(eval $cmd |awk -F "Cipher is" '{print $2}' | tr -d '[:space:]' | awk -F " " '{print $1}') + if [ "x${cipher}" = "x" -o "x${cipher}" = "x0000" -o "x${cipher}" = "x(NONE)" ] ; then + echo "N" + else + echo "Y" + fi +} + +cleanup; +mkdir -p $B0 +mkdir -p $M0 + +TMPDIR=`mktemp -d /tmp/${0##*/}.XXXXXX` +TEST test -d $TMPDIR + +SSL_KEY=$TMPDIR/self.key +SSL_CSR=$TMPDIR/self.csr +SSL_CERT=$TMPDIR/self.crt +SSL_CA=$TMPDIR/ca.crt +SSL_CFG=$TMPDIR/openssl.cnf +SSL_CRL=$TMPDIR/crl.pem + +sed "s|@TMPDIR@|${TMPDIR}|" `pwd`/`dirname $0`/openssl.cnf.in > $SSL_CFG + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST openssl genrsa -out $SSL_KEY 2048 2>/dev/null +TEST openssl req -config $SSL_CFG -new -key $SSL_KEY -x509 \ + -subj /CN=CA -out $SSL_CA +TEST openssl req -config $SSL_CFG -new -key $SSL_KEY \ + -subj /CN=$H0 -out $SSL_CSR + +echo "01" > $TMPDIR/serial +TEST touch $TMPDIR/index.txt $TMPDIR/index.txx.attr +TEST mkdir -p $TMPDIR/certs $TMPDIR/newcerts $TMPDIR/crl +TEST openssl ca -batch -config $SSL_CFG -in $SSL_CSR -out $SSL_CERT 2>&1 + +touch $SSL_CRL +CRLHASH=`openssl x509 -hash -fingerprint -noout -in $SSL_CA|sed -n '1s/$/.r0/p'` +ln -sf $SSL_CRL $TMPDIR/$CRLHASH +TEST openssl ca -config $SSL_CFG -gencrl -out $SSL_CRL 2>&1 + + +TEST $CLI volume create $V0 $H0:$B0/1 +TEST $CLI volume set $V0 server.ssl on +TEST $CLI volume set $V0 client.ssl on +TEST $CLI volume set $V0 ssl.private-key $SSL_KEY +TEST $CLI volume set $V0 ssl.own-cert $SSL_CERT +TEST $CLI volume set $V0 ssl.ca-list $SSL_CA +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +BRICK_PORT=`brick_port $V0` + +# Test we can connect +EXPECT "Y" openssl_connect -connect $H0:$BRICK_PORT + +# Test SSLv2 protocol fails +EXPECT "N" openssl_connect -ssl2 -connect $H0:$BRICK_PORT + +# Test SSLv3 protocol fails +EXPECT "N" openssl_connect -ssl3 -connect $H0:$BRICK_PORT + +# Test TLSv1 protocol based on openssl version +cmd="openssl version" +ver=$(eval $cmd | awk -F " " '{print $2}' | grep "^1.1") +if [ "x${ver}" = "x" ]; then + supp="N" +else + supp="Y" +fi +EXPECT "${supp}" openssl_connect -tls1 -connect $H0:$BRICK_PORT + +# Test a HIGH CBC cipher +cph=`check_cipher -cipher AES256-SHA -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT + +# Test EECDH +cph=`check_cipher -cipher EECDH -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT + +# test MD5 fails +cph=`check_cipher -cipher DES-CBC3-MD5 -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher DES-CBC3-MD5 -connect $H0:$BRICK_PORT + +# test RC4 fails +cph=`check_cipher -cipher RC4-SHA -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher RC4-SHA -connect $H0:$BRICK_PORT + +# test eNULL fails +cph=`check_cipher -cipher NULL-SHA256 -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher NULL-SHA256 -connect $H0:$BRICK_PORT + +# test SHA2 +cph=`check_cipher -cipher AES256-SHA256 -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES256-SHA256 -connect $H0:$BRICK_PORT + +# test GCM +cph=`check_cipher -cipher AES256-GCM-SHA384 -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES256-GCM-SHA384 -connect $H0:$BRICK_PORT + +# Test DH fails without DH params +cph=`check_cipher -cipher EDH -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher EDH -connect $H0:$BRICK_PORT + +# Test DH with DH params +TEST $CLI volume set $V0 ssl.dh-param `pwd`/`dirname $0`/dh1024.pem +EXPECT "`pwd`/`dirname $0`/dh1024.pem" volume_option $V0 ssl.dh-param +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +BRICK_PORT=`brick_port $V0` +EXPECT "Y" openssl_connect -cipher EDH -connect $H0:$BRICK_PORT + +# Test the cipher-list option +TEST $CLI volume set $V0 ssl.cipher-list AES256-SHA +EXPECT AES256-SHA volume_option $V0 ssl.cipher-list +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +BRICK_PORT=`brick_port $V0` +cph=`check_cipher -cipher AES256-SHA -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT +cph=`check_cipher -cipher AES128-SHA -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES128-SHA -connect $H0:$BRICK_PORT + +# Test the ec-curve option +TEST $CLI volume set $V0 ssl.cipher-list EECDH:EDH:!TLSv1 +EXPECT EECDH:EDH:!TLSv1 volume_option $V0 ssl.cipher-list +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +BRICK_PORT=`brick_port $V0` +cph=`check_cipher -cipher AES256-SHA -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT +cph=`check_cipher -cipher EECDH -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT + +TEST $CLI volume set $V0 ssl.ec-curve invalid +EXPECT invalid volume_option $V0 ssl.ec-curve +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +BRICK_PORT=`brick_port $V0` +cph=`check_cipher -cipher EECDH -connect $H0:$BRICK_PORT` +EXPECT "$cph" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT + +TEST $CLI volume set $V0 ssl.ec-curve secp521r1 +EXPECT secp521r1 volume_option $V0 ssl.ec-curve +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count +BRICK_PORT=`brick_port $V0` +EXPECT "Y" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT + +# test revocation +TEST $CLI volume set $V0 ssl.crl-path $TMPDIR +EXPECT $TMPDIR volume_option $V0 ssl.crl-path +$GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +EXPECT "Y" wait_mount $M0 +TEST_FILE=`mktemp $M0/${0##*/}.XXXXXX` +TEST test -f $TEST_FILE +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST openssl ca -batch -config $SSL_CFG -revoke $SSL_CERT 2>&1 +TEST openssl ca -config $SSL_CFG -gencrl -out $SSL_CRL 2>&1 + +# Failed once revoked +# Although client fails to mount without restarting the server after crl-path +# is set when no actual crl file is found on the client, it would also fail +# when server is restarted for the same reason. Since the socket initialization +# code is the same for client and server, the crl verification flags need to +# be turned off for the client to avoid SSL searching for CRLs in the +# ssl.crl-path. If no CRL files are found in the ssl.crl-path, SSL fails the +# connect() attempt on the client. +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +$GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +EXPECT "N" wait_mount $M0 +TEST ! test -f $TEST_FILE +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Succeed with CRL disabled +TEST $CLI volume stop $V0 +TEST $CLI volume set $V0 ssl.crl-path NULL +EXPECT NULL volume_option $V0 ssl.crl-path +TEST $CLI volume start $V0 +$GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +EXPECT "Y" wait_mount $M0 +TEST test -f $TEST_FILE + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +rm -rf $TMPDIR +cleanup; diff --git a/tests/features/subdir-mount.t b/tests/features/subdir-mount.t new file mode 100644 index 00000000000..a02bd6befc4 --- /dev/null +++ b/tests/features/subdir-mount.t @@ -0,0 +1,121 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../nfs.rc + +cleanup; + +## Start and create a volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}; + +## Start volume and verify +TEST $CLI volume start $V0; + +## Mount FUSE with caching disabled (read-write) +TEST $GFS -s $H0 --volfile-id $V0 --volume-name ${V0}-dht $M0; + +TEST ! stat $M0/subdir1; +TEST mkdir $M0/subdir1; +TEST ! stat $M0/subdir2; +TEST mkdir $M0/subdir2; +TEST ! stat $M0/subdir1/subdir1.1; +TEST mkdir $M0/subdir1/subdir1.1; +TEST ! stat $M0/subdir1/subdir1.1/subdir1.2; +TEST mkdir $M0/subdir1/subdir1.1/subdir1.2; + +# mount volume/subdir1 +TEST $GFS --subdir-mount /subdir1 -s $H0 --volfile-id $V0 --volume-name ${V0}-dht $M1; + +TEST touch $M0/topfile; +TEST ! stat $M1/topfile; + +TEST touch $M1/subdir1_file; +TEST ! stat $M0/subdir1_file; +TEST stat $M0/subdir1/subdir1_file; + +# mount volume/subdir2 +TEST $GFS --subdir-mount /subdir2 -s $H0 --volfile-id $V0 $M2; + +TEST ! stat $M2/topfile; + +TEST touch $M2/subdir2_file; +TEST ! stat $M0/subdir2_file; +TEST ! stat $M1/subdir2_file; +TEST stat $M0/subdir2/subdir2_file; + +# umount $M1 / $M2 +TEST umount $M1 +TEST umount $M2 + +# mount non-existing subdir ; this works with mount.glusterfs, +# but with glusterfs, the script doesn't returns error. +#TEST ! $GFS --subdir-mount subdir_not_there -s $H0 --volfile-id $V0 $M1; + +# mount subdir with depth +TEST $GFS --subdir-mount /subdir1/subdir1.1/subdir1.2 -s $H0 --volfile-id $V0 $M2; +TEST ! stat $M2/topfile; +TEST touch $M2/subdir1.2_file; +TEST ! stat $M0/subdir1.2_file; +TEST stat $M0/subdir1/subdir1.1/subdir1.2/subdir1.2_file; + +TEST umount $M2 + +# Lets validate the options # Not having '*' in here as there was some +# problem with option validation with this +TEST $CLI volume set $V0 auth.allow 192.168.1.1 + +TEST $CLI volume set $V0 auth.allow "192.168.1.1,10.10.\*.\*,::1" + +TEST $CLI volume set $V0 auth.allow "/subdir1\(1.2.3.4\),/\(192.168.10.2\|192.168.11.1\),/subdir2\(1.2.3.4\)" + +# directories should be absolute +TEST ! $CLI volume set $V0 auth.allow "subdir2\(1.2.3.4\)" + +# support subdir inside subdir +TEST $CLI volume set $V0 auth.allow '/subdir1/subdir1.1/subdir1.2/\(1.2.3.4\|::1\),/\(192.168.10.1\|192.168.11.1\),/subdir2\(1.2.3.4\)' + +TEST $CLI volume stop $V0 + +TEST $CLI volume start $V0 + +TEST $GFS --subdir-mount /subdir1/subdir1.1/subdir1.2 -s $H0 --volfile-id $V0 $M2 +TEST stat $M2 + +initcnt=`grep -i create-subdir-mounts /var/log/glusterfs/glusterd.log | wc -l` +# mount shouldn't fail even after add-brick +TEST $CLI volume add-brick $V0 replica 2 $H0:$B0/${V0}{5,6}; + +# Wait to execute create-subdir-mounts.sh script by glusterd +newcnt=`grep -i create-subdir-mounts /var/log/glusterfs/glusterd.log | wc -l` +while [ $newcnt -eq $initcnt ] +do + newcnt=`grep -i create-subdir-mounts /var/log/glusterfs/glusterd.log | wc -l` + sleep 1 +done + +# Existing mount should still be active +mount_inode=$(stat --format "%i" "$M2") +TEST test "$mount_inode" == "1" + +TEST umount $M2 + +# Now the exported subdirs should be automatically healed due to +# hook scripts. Check if the mount is successful. +TEST $GFS --subdir-mount /subdir2 -s $H0 --volfile-id $V0 $M2 +mount_inode=$(stat --format "%i" "$M2") +TEST test "$mount_inode" == "1" + +TEST umount $M0 +TEST umount $M2 + + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +## This should clean the mountpoints +cleanup; diff --git a/tests/features/trash.t b/tests/features/trash.t new file mode 100755 index 00000000000..da5b50bc85a --- /dev/null +++ b/tests/features/trash.t @@ -0,0 +1,247 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../dht.rc + +cleanup + +test_mount() { + volume=$1 + mount=$2 + test_dir=$3 + RETVAL=0 + glusterfs -s $H0 --volfile-id $volume $mount --attribute-timeout=0 + + if [ "x$test_dir" = "x" ] ; then return $RETVAL; fi + + timeout=0 + while [ $timeout -lt $PROCESS_UP_TIMEOUT ] ; do + timeout=$(( $timeout + 1 )) + test -d $test_dir + RETVAL=$? + if [ $RETVAL -eq 0 ] ; then break ; fi + sleep 1 + done + + return $RETVAL +} + +start_vol() { + volume=$1 + mount=$2 + test_dir=$3 + $CLI volume start $volume + test_mount $volume $mount $test_dir + RETVAL=$? + return $RETVAL +} + +create_files() { + echo 'Hi' > $1 + echo 'Hai' > $2 +} + +file_exists () { + vol=$1 + shift + for file in `ls $B0/${vol}1/$@ 2> /dev/null` ; do + test -e ${file} && return 0 + done + for file in `ls $B0/${vol}2/$@ 2> /dev/null` ; do + test -e ${file} && return 0 + done + + return 1 +} + +unlink_op() { + + rm -f $M0/$1 + ls $M0/.trashcan/1/2/3 &> /dev/null + sleep 2 + + test ! -e $M0/$1 + wildcard_exists $M0/.trashcan/$1* + + # remove from trashcan + rm -f $M0/.trashcan/$1* + wildcard_not_exists $M0/.trashcan/$1* +} + +truncate_op() { + truncate -s 2 $M0/$1 + ls $M0/.trashcan/1/2/3 &> /dev/null + sleep 2 + + test -e $M0/$1 + test $(ls -l $M0/$1 | awk '{print $5}') -eq 2 &> /dev/null + wildcard_exists $M0/.trashcan/$1* + test $(ls -l $M0/.trashcan/$1*|awk '{print $5}') -eq $2 &> /dev/null + + # truncate from trashcan + truncate -s 1 $M0/.trashcan/$1* + test $(ls $M0/.trashcan/$1* | wc -l) -eq 1 +} + +wildcard_exists() { + test -e $1 + if [ $? -eq 0 ]; then echo "Y"; else echo "N"; fi +} + +wildcard_not_exists() { + test ! -e $1 + if [ $? -eq 0 ]; then echo "Y"; else echo "N"; fi +} + +# testing glusterd +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +# creating distributed volume +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2} + +# checking volume status +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' +EXPECT '2' brick_count $V0 + +# test without enabling trash translator +TEST start_vol $V0 $M0 + +# test on enabling trash translator +TEST $CLI volume set $V0 features.trash on +EXPECT 'on' volinfo_field $V0 'features.trash' + +# files directly under mount point +create_files $M0/file1 $M0/file2 +TEST file_exists $V0 file1 file2 + +# perform unlink +TEST unlink_op file1 + +# perform truncate +TEST truncate_op file2 4 + +# create files directory hierarchy and check +mkdir -p $M0/1/2/3 +create_files $M0/1/2/3/foo1 $M0/1/2/3/foo2 +TEST file_exists $V0 1/2/3/foo1 1/2/3/foo2 + +# perform unlink +TEST unlink_op 1/2/3/foo1 + +# perform truncate +TEST truncate_op 1/2/3/foo2 4 + +# create a directory for eliminate pattern +mkdir $M0/a + +# set the eliminate pattern +TEST $CLI volume set $V0 features.trash-eliminate-path /a +EXPECT '/a' volinfo_field $V0 'features.trash-eliminate-path' + +# create two files and check +create_files $M0/a/test1 $M0/a/test2 +TEST file_exists $V0 a/test1 a/test2 + +# remove from eliminate pattern +rm -f $M0/a/test1 +EXPECT "Y" wildcard_not_exists $M0/.trashcan/a/test1* + +# truncate from eliminate path +truncate -s 2 $M0/a/test2 +TEST [ -e $M0/a/test2 ] +TEST [ `ls -l $M0/a/test2 | awk '{print $5}'` -eq 2 ] +EXPECT "Y" wildcard_not_exists $M0/.trashcan/a/test2* + +# set internal op on +TEST $CLI volume set $V0 features.trash-internal-op on +EXPECT 'on' volinfo_field $V0 'features.trash-internal-op' + +# again create two files and check +create_files $M0/inop1 $M0/inop2 +TEST file_exists $V0 inop1 inop2 + +# perform unlink +TEST unlink_op inop1 + +# perform truncate +TEST truncate_op inop2 4 + +# remove one brick and restart the volume +TEST $CLI volume remove-brick $V0 $H0:$B0/${V0}2 force +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume stop $V0 +TEST start_vol $V0 $M0 $M0/.trashcan + +# again create two files and check +create_files $M0/rebal1 $M0/rebal2 +TEST file_exists $V0 rebal1 rebal2 + +# add one brick +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}3 +TEST [ -d $B0/${V0}3 ] + + +# perform rebalance +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "0" rebalance_completed + +#Find out which file was migrated to the new brick +file_name=$(ls $B0/${V0}3/rebal*| xargs basename) + +# check whether rebalance was succesful +EXPECT "Y" wildcard_exists $B0/${V0}3/$file_name* +EXPECT "Y" wildcard_exists $B0/${V0}1/.trashcan/internal_op/$file_name* + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# force required in case rebalance is not over +TEST $CLI volume stop $V0 force + +# create a replicated volume +TEST $CLI volume create $V1 replica 2 $H0:$B0/${V1}{1,2} + +# checking volume status +EXPECT "$V1" volinfo_field $V1 'Volume Name' +EXPECT 'Replicate' volinfo_field $V1 'Type' +EXPECT 'Created' volinfo_field $V1 'Status' +EXPECT '2' brick_count $V1 + +# enable trash with options and start the replicate volume by disabling automatic self-heal +TEST $CLI volume set $V1 features.trash on +TEST $CLI volume set $V1 features.trash-internal-op on +EXPECT 'on' volinfo_field $V1 'features.trash' +EXPECT 'on' volinfo_field $V1 'features.trash-internal-op' +TEST start_vol $V1 $M1 $M1/.trashcan + +# mount and check for trash directory +TEST [ -d $M1/.trashcan/internal_op ] + +# create a file and check +touch $M1/self +TEST [ -e $B0/${V1}1/self -a -e $B0/${V1}2/self ] + +# kill one brick and delete the file from mount point +kill_brick $V1 $H0 $B0/${V1}1 +EXPECT_WITHIN ${PROCESS_UP_TIMEOUT} "1" online_brick_count +rm -f $M1/self +EXPECT "Y" wildcard_exists $B0/${V1}2/.trashcan/self* + +# check renaming of trash directory through cli +TEST $CLI volume set $V0 trash-dir abc +TEST start_vol $V0 $M0 $M0/abc +TEST [ -e $M0/abc -a ! -e $M0/.trashcan ] +EXPECT "Y" wildcard_exists $B0/${V0}1/abc/internal_op/rebal* + +# ensure that rename and delete operation on trash directory fails +rm -rf $M0/abc/internal_op +TEST [ -e $M0/abc/internal_op ] +rm -rf $M0/abc/ +TEST [ -e $M0/abc ] +mv $M0/abc $M0/trash +TEST [ -e $M0/abc ] + +cleanup diff --git a/tests/features/unhashed-auto.t b/tests/features/unhashed-auto.t new file mode 100755 index 00000000000..0a6bbfbb07d --- /dev/null +++ b/tests/features/unhashed-auto.t @@ -0,0 +1,125 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../dht.rc + +NFILES=100 + +touch_files () { + for i in $(seq 1 $NFILES); do + touch $(printf $M0/dir/file%02d $i) + done +} + +count_files () { + found=0 + for i in $(seq 1 $NFILES); do + if [ -f $(printf $M0/dir/file%02d $i) ]; then + found=$((found+1)) + fi + done + echo "found $found files" > /dev/tty + echo $found +} + +wait_for_rebalance () { + while true; do + tmp=$(rebalance_completed) + if [ $tmp -eq 1 ]; then + sleep 1 + else + break + fi + done +} + +get_xattr () { + cmd="getfattr --absolute-names --only-values -n trusted.glusterfs.dht" + $cmd $1 | od -tx1 -An | tr -d ' ' +} + +get_xattr_hash () { + cmd="getfattr --absolute-names --only-values -n trusted.glusterfs.dht" + $cmd $1 | od -tx1 -An | awk '{printf("%s%s%s%s\n", $1, $2, $3, $4);}' +} + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2} +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume set $V0 cluster.lookup-optimize ON + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +# Create some files for later tests. +TEST $GFS -s $H0 --volfile-id $V0 $M0 +TEST mkdir $M0/dir +TEST touch_files +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Add a brick and do the fix-layout part of rebalance to update directory layouts +# (including their directory commit hashes). +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}3 +EXPECT '3' brick_count $V0 +TEST $CLI volume rebalance $V0 fix-layout start +TEST wait_for_rebalance + +# Now for the sneaky part. *Undo* the part of rebalance that updated the volume +# commit hash, forcing a false match between that and the directory commit hashes. +TEST setfattr -x trusted.glusterfs.dht.commithash $B0/${V0}1 +TEST setfattr -x trusted.glusterfs.dht.commithash $B0/${V0}2 +TEST setfattr -x trusted.glusterfs.dht.commithash $B0/${V0}3 + +# Mount and check that we do *not* see all of the files. This indicates that we +# correctly skipped the broadcast lookup that would have found them. +TEST $GFS -s $H0 --volfile-id $V0 $M0 +TEST [ $(count_files) -ne 100 ] +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Do the fix-layout again to generate a new volume commit hash. +TEST $CLI volume rebalance $V0 fix-layout start +TEST wait_for_rebalance + +# Mount and check that we *do* see all of the files. This indicates that we saw +# the mismatch and did the broadcast lookup this time. +TEST $GFS -s $H0 --volfile-id $V0 $M0 +TEST [ $(count_files) -eq 100 ] +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Do a *full* rebalance and verify that the directory commit hash changed. +old_val=$(get_xattr $B0/${V0}1/dir) +TEST $CLI volume rebalance $V0 start +TEST wait_for_rebalance +new_val=$(get_xattr $B0/${V0}1/dir) +TEST [ ! x"$old_val" = x"$new_val" ] + +# Force an anomoly on an existing layout and heal it +## The healed layout should not carry a commit-hash (or should carry 1 in the +## commit-hash) +TEST setfattr -x trusted.glusterfs.dht $B0/${V0}1/dir +TEST $GFS -s $H0 --volfile-id $V0 $M0 +TEST [ -d $M0/dir ] +new_hash=$(get_xattr_hash $B0/${V0}1/dir) +TEST [ x"$new_hash" = x"00000001" ] +new_hash=$(get_xattr_hash $B0/${V0}2/dir) +TEST [ x"$new_hash" = x"00000001" ] + +# Unset the option and check that newly created directories get 1 in the +# disk layout +TEST $CLI volume set $V0 cluster.lookup-optimize off +TEST mkdir $M0/dir1 +new_hash=$(get_xattr_hash $B0/${V0}1/dir1) +TEST [ x"$new_hash" = x"00000001" ] +new_hash=$(get_xattr_hash $B0/${V0}2/dir1) +TEST [ x"$new_hash" = x"00000001" ] + + +cleanup diff --git a/tests/features/weighted-rebalance.t b/tests/features/weighted-rebalance.t index fbda32e50a2..0d730406fd0 100755 --- a/tests/features/weighted-rebalance.t +++ b/tests/features/weighted-rebalance.t @@ -22,17 +22,6 @@ count_files () { echo $found } -wait_for_rebalance () { - while true; do - rebalance_completed - if [ $? -eq 1 ]; then - sleep 1 - else - break - fi - done -} - get_xattr () { cmd="getfattr --absolute-names --only-values -n trusted.glusterfs.dht" $cmd $1 | od -tx1 -An | tr -d ' ' @@ -77,7 +66,7 @@ TEST $CLI volume set $V0 cluster.weighted-rebalance off # Rebalance again and check that the distribution is even again. TEST $CLI volume rebalance $V0 start force -TEST wait_for_rebalance +EXPECT_WITHIN $REBALANCE_TIMEOUT "0" rebalance_completed nfiles=$(count_files ${B0}/${V0}2) #echo $nfiles $(get_xattr ${B0}/${V0}1) $(get_xattr ${B0}/${V0}2) 3>&2 2>&1 1>&3 3>&- TEST [ $nfiles -le 580 ] diff --git a/tests/features/worm.t b/tests/features/worm.t new file mode 100755 index 00000000000..40b08cdee02 --- /dev/null +++ b/tests/features/worm.t @@ -0,0 +1,117 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 + +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +## Mount FUSE with caching disabled (read-write) +TEST $GFS -s $H0 --volfile-id $V0 $M0 + +## Tests for the volume level WORM +TEST `echo "File 1" > $M0/file1` +TEST touch $M0/file2 + +## Enable the volume level WORM +TEST $CLI volume set $V0 features.worm 1 +TEST ! mv $M0/file1 $M0/file11 +TEST `echo "block" > $M0/file2` + +## Disable the volume level WORM and delete the legacy files +TEST $CLI volume set $V0 features.worm 0 +TEST rm -f $M0/* + +## Enable file level WORM +TEST $CLI volume set $V0 features.worm-file-level 1 +TEST $CLI volume set $V0 features.default-retention-period 10 +TEST $CLI volume set $V0 features.auto-commit-period 5 + +## Tests for manual transition to WORM/Retained state +TEST `echo "worm 1" > $M0/file1` +TEST chmod 0444 $M0/file1 +sleep 5 +TEST `echo "line 1" > $M0/file1` +TEST ! mv $M0/file1 $M0/file2 +sleep 10 +TEST ! link $M0/file1 $M0/file2 +sleep 5 +TEST rm -f $M0/file1 + +## Test for mv over WORM/Reatined state +TEST `echo "worm 1" > $M0/file1` +TEST chmod 0444 $M0/file1 +TEST `echo "worm 2" > $M0/file2` +TEST ! mv $M0/file2 $M0/file1 +TEST rm -f $M0/file2 +sleep 10 +TEST rm -f $M0/file1 + +## Test for state transition over write. +TEST `echo "worm 1" > $M0/file3` +sleep 5 +TEST `echo "worm 2" >> $M0/file3` +EXPECT 'worm 1' cat $M0/file3 +TEST ! rm -f $M0/file3 + +## Test for checking if Worm files are undeletable after setting worm-files-deletable as 0. +TEST $CLI volume set $V0 features.worm-files-deletable 0 +TEST `echo "worm 1" > $M0/file4` +TEST chmod 0444 $M0/file4 +sleep 10 +TEST `echo "worm 1" >> $M0/file4` +TEST ! rm -f $M0/file4 + +## Test for state transition if auto-commit-period is 0 +TEST $CLI volume set $V0 features.auto-commit-period 0 +TEST `echo "worm 1" > $M0/file5` +EXPECT '3/10/0' echo $(getfattr -e text --absolute-names --only-value -n "trusted.reten_state" $B0/${V0}1/file5) +EXPECT 'worm 1' cat $M0/file5 +TEST ! rm -f $M0/file5 +TEST $CLI volume set $V0 features.auto-commit-period 5 + +## Test for checking if retention-period is updated on increasing the access time of a WORM-RETAINED file. +TEST $CLI volume set $V0 features.worm-files-deletable 1 +TEST `echo "worm 1" >> $M0/file1` +initial_timestamp=$(date +%s) +current_time_seconds=$(date +%S | sed 's/^0*//' ); +TEST chmod 0444 $M0/file1 +EXPECT '3/10/5' echo $(getfattr -e text --absolute-names --only-value -n "trusted.reten_state" $B0/${V0}1/file1) +changed_timestamp=$(date +%Y%m%d%H%M --date '60 seconds'); +seconds_diff=`expr 60 - $((current_time_seconds))` +TEST `touch -a -t "${changed_timestamp}" $M0/file1` +EXPECT "3/$seconds_diff/5" echo $(getfattr -e text --absolute-names --only-value -n "trusted.reten_state" $B0/${V0}1/file1) +sleep $seconds_diff +TEST `echo "worm 2" >> $M0/file1` +EXPECT "$initial_timestamp" echo $(stat --printf %X $M0/file1) + + +## Test for checking if retention-period is updated on decreasing the access time of a WORM-RETAINED file +TEST $CLI volume set $V0 features.default-retention-period 120 +initial_timestamp=$(date +%s) +current_time_seconds=$(date +%S | sed 's/^0*//' ); +TEST chmod 0444 $M0/file1 +EXPECT '3/120/5' echo $(getfattr -e text --absolute-names --only-value -n "trusted.reten_state" $B0/${V0}1/file1) +changed_timestamp=$(date +%Y%m%d%H%M --date '60 seconds'); +seconds_diff=`expr 60 - $((current_time_seconds))` +TEST `touch -a -t "${changed_timestamp}" $M0/file1` +EXPECT "3/$seconds_diff/5" echo $(getfattr -e text --absolute-names --only-value -n "trusted.reten_state" $B0/${V0}1/file1) +sleep $seconds_diff +TEST `echo "worm 4" >> $M0/file1` +EXPECT "$initial_timestamp" echo $(stat --printf %X $M0/file1) +TEST rm -f $M0/file1 + +TEST $CLI volume stop $V0 +EXPECT 'Stopped' volinfo_field $V0 'Status' + +cleanup; diff --git a/tests/features/worm_sh.t b/tests/features/worm_sh.t new file mode 100644 index 00000000000..da7afc084b2 --- /dev/null +++ b/tests/features/worm_sh.t @@ -0,0 +1,75 @@ +#!/bin/bash +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off + +TEST $CLI volume set $V0 self-heal-daemon off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +## Enable file level WORM +TEST $CLI volume set $V0 features.worm-file-level 1 +TEST $CLI volume set $V0 features.default-retention-period 100 +TEST $CLI volume set $V0 features.auto-commit-period 5 + +## Tests for manual transition to WORM/Retained state +TEST `echo "worm1" > $M0/file1` +TEST chmod 0444 $M0/file1 +sleep 5 +TEST `echo "worm2" > $M0/file2` +TEST chmod 0444 $M0/file2 +sleep 5 +TEST `echo "worm3" > $M0/file3` +TEST chmod 0444 $M0/file3 +sleep 5 + +## Stopp one of the bricks +TEST kill_brick $V0 $H0 $B0/${V0}1 + +## Manipulate the WORMed-Files +TEST $CLI volume set $V0 features.worm-file-level 0 +sleep 5 + +TEST chmod 0777 $M0/file1 +TEST `echo "test" >> $M0/file1` +TEST `echo "test" >> $M0/file3` +TEST `rm -rf $M0/file2` + +## Metadata changes +TEST setfattr -n user.test -v qwerty $M0/file3 +sleep 5 + +## Enable file level WORM again +TEST $CLI volume set $V0 features.worm-file-level 1 + +## Restart volume and trigger self-heal +TEST $CLI volume stop $V0 force +TEST $CLI volume start $V0 force +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1 | sort) + +# Test if data was healed +TEST diff $B0/${V0}0/file1 $B0/${V0}1/file1 +TEST diff $B0/${V0}0/file3 $B0/${V0}1/file3 + +# Test if metadata was healed and exists on both the bricks +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}1/file3 +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}0/file3 + +cleanup; |
