From 7936283847db39070d760f79f0af1804be7f6744 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 4 Nov 2020 13:40:32 +0530 Subject: [Test] Add test to verify lock behaviour from 2 diff clients Test to verify whether the lock is being granted to two diff clients at the same time. - Take lock from client 1 => Lock is acquired - Try taking lock from client 2 - Release lock from client1 - Take lock from client2 - Again try taking lock from client 1 Also, verifying the behaviour with eagerlock and other eagerlock set of on and off. Change-Id: Ie839f893f7a4f9b2c6fc9375cdf9ee8a27fad13b Signed-off-by: Pranav --- glustolibs-io/shared_files/scripts/file_lock.py | 51 ++++++++ ..._ec_check_lock_granted_to_2_different_client.py | 135 +++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 glustolibs-io/shared_files/scripts/file_lock.py create mode 100755 tests/functional/disperse/test_ec_check_lock_granted_to_2_different_client.py diff --git a/glustolibs-io/shared_files/scripts/file_lock.py b/glustolibs-io/shared_files/scripts/file_lock.py new file mode 100644 index 000000000..e29fd1b1d --- /dev/null +++ b/glustolibs-io/shared_files/scripts/file_lock.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Copyright (C) 2020 Red Hat, Inc. +# +# This program 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 2 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from fcntl import flock, LOCK_EX, LOCK_NB, LOCK_UN +from time import sleep +from argparse import ArgumentParser + + +def get_file_lock(args): + """ + Gets the lock to a file and releases it after timeout + """ + file_name = args.f + timeout = args.t + f = open(file_name, 'w') + flock(f.fileno(), LOCK_EX | LOCK_NB) + sleep(int(timeout)) + flock(f.fileno(), LOCK_UN) + + +if __name__ == "__main__": + file_lock_parser = ArgumentParser( + prog="file_lock.py", description="Program to validate file lock ops") + + file_lock_req_args = file_lock_parser.add_argument_group( + 'required named arguments') + file_lock_req_args.add_argument( + '-f', type=str, required=True, + help="File on which lock has to be applied") + file_lock_req_args.add_argument( + '-t', help="time for which lock has to be retained", type=int, + required=True) + + file_lock_parser.set_defaults(func=get_file_lock) + + args = file_lock_parser.parse_args() + rc = args.func(args) diff --git a/tests/functional/disperse/test_ec_check_lock_granted_to_2_different_client.py b/tests/functional/disperse/test_ec_check_lock_granted_to_2_different_client.py new file mode 100755 index 000000000..dd5f3b6da --- /dev/null +++ b/tests/functional/disperse/test_ec_check_lock_granted_to_2_different_client.py @@ -0,0 +1,135 @@ +# Copyright (C) 2020 Red Hat, Inc. +# +# This program 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 2 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +import time +import itertools +from glusto.core import Glusto as g +from glustolibs.gluster.exceptions import ExecutionError +from glustolibs.gluster.gluster_base_class import (GlusterBaseClass, runs_on) +from glustolibs.misc.misc_libs import upload_scripts +from glustolibs.gluster.volume_ops import (set_volume_options, + get_volume_options) + + +@runs_on([['dispersed', 'distributed-dispersed'], ['glusterfs']]) +class EcVerifyLock(GlusterBaseClass): + + @classmethod + def setUpClass(cls): + # Calling GlusterBaseClass setUpClass + cls.get_super_method(cls, 'setUpClass')() + cls.script = "/usr/share/glustolibs/io/scripts/file_lock.py" + if not upload_scripts(cls.clients, [cls.script]): + raise ExecutionError("Failed to upload IO scripts to clients %s" + % cls.clients) + g.log.info("Successfully uploaded IO scripts to clients %s", + cls.clients) + + def setUp(self): + # Setup Volume and Mount Volume + if not self.setup_volume_and_mount_volume(mounts=self.mounts): + raise ExecutionError("Failed to Setup_Volume and Mount_Volume") + g.log.info("Successful in Setup Volume and Mount Volume") + + def test_verify_lock_granted_from_2_clients(self): + """ + - Create disperse volume and mount it to 2 clients` + - Create file from 1 client on mount point + - Take lock from client 1 => Lock is acquired + - Try taking lock from client 2=> Lock is blocked (as already + being taken by client 1) + - Release lock from client1=> Lock is released + - Take lock from client2 + - Again try taking lock from client 1 + - verify test with once, by disabling eagerlock and other eager lock + and once by leaving eager and other eagerlock enabled(by default) + """ + mpoint = self.mounts[0].mountpoint + + # Create a file on client 1 + cmd = "touch {}/test_file".format(mpoint) + ret, _, _ = g.run(self.mounts[0].client_system, cmd) + self.assertEqual(ret, 0, "Failed to create file on client 1") + + # Verifying OCL as ON + option = "optimistic-change-log" + option_dict = get_volume_options(self.mnode, self.volname, option) + self.assertIsNotNone(option_dict, ("Failed to get %s volume option" + " for volume %s" + % (option, self.volname))) + self.assertEqual(option_dict['disperse.optimistic-change-log'], 'on', + ("%s is not ON for volume %s" % (option, + self.volname))) + g.log.info("Succesfully verified %s value for volume %s", + option, self.volname) + + # Repeat the test with eager-lock and other-eager-lock 'on' & 'off' + for lock_status in ('on', 'off'): + options = {'disperse.eager-lock': lock_status, + 'disperse.other-eager-lock': lock_status} + ret = set_volume_options(self.mnode, self.volname, options) + + self.assertTrue(ret, ("failed to set eagerlock and other " + "eagerlock value as %s " % lock_status)) + g.log.info("Successfully set eagerlock and other eagerlock value" + " to %s", lock_status) + + # Repeat the test for both the combinations of clients + for client_1, client_2 in list(itertools.permutations( + [self.mounts[0].client_system, + self.mounts[1].client_system], r=2)): + # Get lock to file from one client + lock_cmd = ("/usr/bin/env python {} -f {}/" + "test_file -t 30".format(self.script, mpoint)) + proc = g.run_async(client_1, lock_cmd) + time.sleep(5) + + # As the lock is been acquired by one client, + # try to get lock from the other + ret, _, _ = g.run(client_2, lock_cmd) + self.assertEqual(ret, 1, ("Unexpected: {} acquired the lock " + "before been released by {}" + .format(client_2, client_1))) + g.log.info("Expected : Lock can't be acquired by %s before " + "being released by %s", client_2, client_1) + + # Wait for first client to release the lock. + ret, _, _ = proc.async_communicate() + self.assertEqual(ret, 0, ("File lock process failed on %s:%s", + client_1, mpoint)) + + # Try taking the lock from other client and releasing it + lock_cmd = ("/usr/bin/env python {} -f " + "{}/test_file -t 1".format(self.script, mpoint)) + ret, _, _ = g.run(client_2, lock_cmd) + self.assertEqual(ret, 0, + ("Unexpected:{} Can't acquire the lock even " + "after its been released by {}" + .format(client_2, client_1))) + g.log.info("Successful, Lock acquired by %s after being " + "released by %s", client_2, client_1) + + def tearDown(self): + # Stopping the volume + ret = self.unmount_volume_and_cleanup_volume(mounts=self.mounts) + if not ret: + raise ExecutionError("Failed to Unmount Volume and Cleanup " + "Volume") + g.log.info("Successful in Unmount Volume and Cleanup Volume") + + # Calling GlusterBaseClass tearDown + self.get_super_method(self, 'tearDown')() -- cgit