summaryrefslogtreecommitdiffstats
path: root/glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py
diff options
context:
space:
mode:
Diffstat (limited to 'glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py')
-rw-r--r--glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py497
1 files changed, 497 insertions, 0 deletions
diff --git a/glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py b/glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py
new file mode 100644
index 000000000..23f187912
--- /dev/null
+++ b/glustolibs-gluster/glustolibs/gluster/nfs_ganesha_libs.py
@@ -0,0 +1,497 @@
+#!/usr/bin/env python
+# Copyright (C) 2016-2017 Red Hat, Inc. <http://www.redhat.com>
+#
+# 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.
+
+"""
+ Description: nfs ganesha base classes.
+ Pre-requisite: Please install gdeploy package on the glusto-tests
+ management node.
+"""
+
+from glusto.core import Glusto as g
+from glustolibs.gluster.nfs_ganesha_ops import (
+ is_nfs_ganesha_cluster_exists,
+ is_nfs_ganesha_cluster_in_healthy_state,
+ teardown_nfs_ganesha_cluster,
+ create_nfs_ganesha_cluster,
+ export_nfs_ganesha_volume,
+ unexport_nfs_ganesha_volume,
+ set_nfs_ganesha_client_configuration)
+from glustolibs.gluster.gluster_base_class import GlusterBaseClass
+from glustolibs.gluster.exceptions import ExecutionError, ConfigError
+from glustolibs.gluster.peer_ops import peer_probe_servers, peer_status
+from glustolibs.gluster.volume_ops import volume_info
+from glustolibs.gluster.volume_libs import (setup_volume, cleanup_volume,
+ log_volume_info_and_status,
+ get_volume_options,
+ is_volume_exported)
+from glustolibs.gluster.mount_ops import create_mount_objs
+from glustolibs.io.utils import log_mounts_info, wait_for_io_to_complete
+from glustolibs.misc.misc_libs import upload_scripts
+import time
+import socket
+import re
+
+
+class NfsGaneshaClusterSetupClass(GlusterBaseClass):
+ """Creates nfs ganesha cluster
+ """
+ @classmethod
+ def setUpClass(cls):
+ """Setup nfs-ganesha cluster
+ tests.
+ """
+
+ # Check if gdeploy is installed on glusto-tests management node.
+ ret, _, _ = g.run_local("gdeploy --version")
+ if ret != 0:
+ raise ConfigError("Please install gdeploy to run the scripts")
+
+ GlusterBaseClass.setUpClass.im_func(cls)
+
+ # Check if enable_nfs_ganesha is set in config file
+ if not cls.enable_nfs_ganesha:
+ raise ConfigError("Please enable nfs ganesha in config")
+
+ # Read num_of_nfs_ganesha_nodes from config file and create
+ # nfs ganesha cluster accordingly
+ cls.num_of_nfs_ganesha_nodes = int(cls.num_of_nfs_ganesha_nodes)
+ cls.servers_in_nfs_ganesha_cluster = (
+ cls.servers[:cls.num_of_nfs_ganesha_nodes])
+ cls.vips_in_nfs_ganesha_cluster = (
+ cls.vips[:cls.num_of_nfs_ganesha_nodes])
+
+ # Create nfs ganesha cluster if not exists already
+ if (is_nfs_ganesha_cluster_exists(
+ cls.servers_in_nfs_ganesha_cluster[0])):
+ if is_nfs_ganesha_cluster_in_healthy_state(
+ cls.servers_in_nfs_ganesha_cluster[0]):
+ g.log.info("Nfs-ganesha Cluster exists and is in healthy "
+ "state. Skipping cluster creation...")
+ else:
+ g.log.info("Nfs-ganesha Cluster exists and is not in "
+ "healthy state.")
+ g.log.info("Tearing down existing cluster which is not in "
+ "healthy state")
+ ganesha_ha_file = ("/var/run/gluster/shared_storage/"
+ "nfs-ganesha/ganesha-ha.conf")
+
+ g.log.info("Collecting server details of existing "
+ "nfs ganesha cluster")
+ conn = g.rpyc_get_connection(
+ cls.servers_in_nfs_ganesha_cluster[0], user="root")
+ if conn is None:
+ tmp_node = cls.servers_in_nfs_ganesha_cluster[0]
+ raise ExecutionError("Unable to get connection to 'root' "
+ " of node %s "
+ % tmp_node)
+ if not conn.modules.os.path.exists(ganesha_ha_file):
+ raise ExecutionError("Unable to locate %s"
+ % ganesha_ha_file)
+ with conn.builtin.open(ganesha_ha_file, "r") as fh:
+ ganesha_ha_contents = fh.read()
+ g.rpyc_close_connection(
+ host=cls.servers_in_nfs_ganesha_cluster[0], user="root")
+ servers_in_existing_cluster = re.findall('VIP_(.*)\=.*',
+ ganesha_ha_contents)
+
+ ret = teardown_nfs_ganesha_cluster(
+ servers_in_existing_cluster, force=True)
+ if not ret:
+ raise ExecutionError("Failed to teardown nfs "
+ "ganesha cluster")
+ g.log.info("Existing cluster got teardown successfully")
+ g.log.info("Creating nfs-ganesha cluster of %s nodes"
+ % str(cls.num_of_nfs_ganesha_nodes))
+ g.log.info("Nfs-ganesha cluster node info: %s"
+ % cls.servers_in_nfs_ganesha_cluster)
+ g.log.info("Nfs-ganesha cluster vip info: %s"
+ % cls.vips_in_nfs_ganesha_cluster)
+ ret = create_nfs_ganesha_cluster(
+ cls.servers_in_nfs_ganesha_cluster,
+ cls.vips_in_nfs_ganesha_cluster)
+ if not ret:
+ raise ExecutionError("Failed to create "
+ "nfs-ganesha cluster")
+ else:
+ g.log.info("Creating nfs-ganesha cluster of %s nodes"
+ % str(cls.num_of_nfs_ganesha_nodes))
+ g.log.info("Nfs-ganesha cluster node info: %s"
+ % cls.servers_in_nfs_ganesha_cluster)
+ g.log.info("Nfs-ganesha cluster vip info: %s"
+ % cls.vips_in_nfs_ganesha_cluster)
+ ret = create_nfs_ganesha_cluster(
+ cls.servers_in_nfs_ganesha_cluster,
+ cls.vips_in_nfs_ganesha_cluster)
+ if not ret:
+ raise ExecutionError("Failed to create "
+ "nfs-ganesha cluster")
+
+ if is_nfs_ganesha_cluster_in_healthy_state(
+ cls.servers_in_nfs_ganesha_cluster[0]):
+ g.log.info("Nfs-ganesha Cluster exists is in healthy state")
+ else:
+ raise ExecutionError("Nfs-ganesha Cluster setup Failed")
+
+ ret = set_nfs_ganesha_client_configuration(cls.clients)
+ if not ret:
+ raise ExecutionError("Failed to do client nfs ganesha "
+ "configuration")
+
+ for server in cls.servers:
+ for client in cls.clients:
+ cmd = ("if [ -z \"$(grep -R \"%s\" /etc/hosts)\" ]; then "
+ "echo \"%s %s\" >> /etc/hosts; fi"
+ % (client, socket.gethostbyname(client), client))
+ ret, _, _ = g.run(server, cmd)
+ if ret != 0:
+ g.log.error("Failed to add entry of client %s in "
+ "/etc/hosts of server %s"
+ % (client, server))
+
+ for client in cls.clients:
+ for server in cls.servers:
+ cmd = ("if [ -z \"$(grep -R \"%s\" /etc/hosts)\" ]; then "
+ "echo \"%s %s\" >> /etc/hosts; fi"
+ % (server, socket.gethostbyname(server), server))
+ ret, _, _ = g.run(client, cmd)
+ if ret != 0:
+ g.log.error("Failed to add entry of server %s in "
+ "/etc/hosts of client %s"
+ % (server, client))
+
+ def setUp(self):
+ """setUp required for tests
+ """
+ GlusterBaseClass.setUp.im_func(self)
+
+ def tearDown(self):
+ """tearDown required for tests
+ """
+ GlusterBaseClass.tearDown.im_func(self)
+
+ @classmethod
+ def tearDownClass(cls, delete_nfs_ganesha_cluster=True):
+ """Teardown nfs ganesha cluster.
+ """
+ GlusterBaseClass.tearDownClass.im_func(cls)
+
+ if delete_nfs_ganesha_cluster:
+ ret = teardown_nfs_ganesha_cluster(
+ cls.servers_in_nfs_ganesha_cluster)
+ if not ret:
+ g.log.error("Teardown got failed. Hence, cleaning up "
+ "nfs-ganesha cluster forcefully")
+ ret = teardown_nfs_ganesha_cluster(
+ cls.servers_in_nfs_ganesha_cluster, force=True)
+ if not ret:
+ raise ExecutionError("Force cleanup of nfs-ganesha "
+ "cluster failed")
+ g.log.info("Teardown nfs ganesha cluster succeeded")
+ else:
+ g.log.info("Skipping teardown nfs-ganesha cluster...")
+
+
+class NfsGaneshaVolumeBaseClass(NfsGaneshaClusterSetupClass):
+ """Sets up the nfs ganesha cluster, volume for testing purposes.
+ """
+ @classmethod
+ def setUpClass(cls):
+ """Setup volume exports volume with nfs-ganesha,
+ mounts the volume.
+ """
+ NfsGaneshaClusterSetupClass.setUpClass.im_func(cls)
+
+ # Peer probe servers
+ ret = peer_probe_servers(cls.mnode, cls.servers)
+ if not ret:
+ raise ExecutionError("Failed to peer probe servers")
+
+ g.log.info("All peers are in connected state")
+
+ # Peer Status from mnode
+ peer_status(cls.mnode)
+
+ for server in cls.servers:
+ mount_info = [
+ {'protocol': 'glusterfs',
+ 'mountpoint': '/run/gluster/shared_storage',
+ 'server': server,
+ 'client': {'host': server},
+ 'volname': 'gluster_shared_storage',
+ 'options': ''}]
+
+ mount_obj = create_mount_objs(mount_info)
+ if not mount_obj[0].is_mounted():
+ ret = mount_obj[0].mount()
+ if not ret:
+ raise ExecutionError("Unable to mount volume '%s:%s' "
+ "on '%s:%s'"
+ % (mount_obj.server_system,
+ mount_obj.volname,
+ mount_obj.client_system,
+ mount_obj.mountpoint))
+
+ # Setup Volume
+ ret = setup_volume(mnode=cls.mnode,
+ all_servers_info=cls.all_servers_info,
+ volume_config=cls.volume, force=True)
+ if not ret:
+ raise ExecutionError("Setup volume %s failed", cls.volume)
+ time.sleep(10)
+
+ # Export volume with nfs ganesha, if it is not exported already
+ vol_option = get_volume_options(cls.mnode, cls.volname,
+ option='ganesha.enable')
+ if vol_option is None:
+ raise ExecutionError("Failed to get ganesha.enable volume option "
+ "for %s " % cls.volume)
+ if vol_option['ganesha.enable'] != 'on':
+ ret, out, err = export_nfs_ganesha_volume(
+ mnode=cls.mnode, volname=cls.volname)
+ if ret != 0:
+ raise ExecutionError("Failed to export volume %s "
+ "as NFS export", cls.volname)
+ time.sleep(5)
+ else:
+ g.log.info("Volume %s is exported already"
+ % cls.volname)
+
+ _, _, _ = g.run(cls.mnode, "showmount -e")
+
+ # Log Volume Info and Status
+ ret = log_volume_info_and_status(cls.mnode, cls.volname)
+ if not ret:
+ raise ExecutionError("Logging volume %s info and status failed",
+ cls.volname)
+
+ # Create Mounts
+ _rc = True
+ for mount_obj in cls.mounts:
+ ret = mount_obj.mount()
+ if not ret:
+ g.log.error("Unable to mount volume '%s:%s' on '%s:%s'",
+ mount_obj.server_system, mount_obj.volname,
+ mount_obj.client_system, mount_obj.mountpoint)
+ _rc = False
+ if not _rc:
+ raise ExecutionError("Mounting volume %s on few clients failed",
+ cls.volname)
+
+ # Get info of mount before the IO
+ log_mounts_info(cls.mounts)
+
+ @classmethod
+ def tearDownClass(cls, umount_vol=True, cleanup_vol=True,
+ teardown_nfs_ganesha_cluster=True):
+ """Teardown the export, mounts and volume.
+ """
+
+ # Unmount volume
+ if umount_vol:
+ _rc = True
+ for mount_obj in cls.mounts:
+ ret = mount_obj.unmount()
+ if not ret:
+ g.log.error("Unable to unmount volume '%s:%s' on '%s:%s'",
+ mount_obj.server_system, mount_obj.volname,
+ mount_obj.client_system, mount_obj.mountpoint)
+ _rc = False
+ if not _rc:
+ raise ExecutionError("Unmount of all mounts are not "
+ "successful")
+
+ # Cleanup volume
+ if cleanup_vol:
+
+ # Unexport volume, if it is not unexported already
+ vol_option = get_volume_options(cls.mnode, cls.volname,
+ option='ganesha.enable')
+ if vol_option is None:
+ raise ExecutionError("Failed to get ganesha.enable volume "
+ " option for %s " % cls.volume)
+ if vol_option['ganesha.enable'] != 'off':
+ if is_volume_exported(cls.mnode, cls.volname, "nfs"):
+ ret, out, err = unexport_nfs_ganesha_volume(
+ mnode=cls.mnode, volname=cls.volname)
+ if ret != 0:
+ raise ExecutionError("Failed to unexport volume %s "
+ % cls.volname)
+ time.sleep(5)
+ else:
+ g.log.info("Volume %s is unexported already"
+ % cls.volname)
+
+ _, _, _ = g.run(cls.mnode, "showmount -e")
+
+ ret = cleanup_volume(mnode=cls.mnode, volname=cls.volname)
+ if not ret:
+ raise ExecutionError("cleanup volume %s failed", cls.volname)
+
+ # All Volume Info
+ volume_info(cls.mnode)
+
+ (NfsGaneshaClusterSetupClass.
+ tearDownClass.
+ im_func(cls,
+ delete_nfs_ganesha_cluster=teardown_nfs_ganesha_cluster))
+
+
+class NfsGaneshaIOBaseClass(NfsGaneshaVolumeBaseClass):
+ """ Nfs Ganesha IO base class to run the tests when IO is in progress """
+
+ @classmethod
+ def setUpClass(cls):
+
+ NfsGaneshaVolumeBaseClass.setUpClass.im_func(cls)
+
+ # Upload io scripts for running IO on mounts
+ script_local_path = ("/usr/share/glustolibs/io/scripts/"
+ "file_dir_ops.py")
+ cls.script_upload_path = ("/usr/share/glustolibs/io/scripts/"
+ "file_dir_ops.py")
+ ret = upload_scripts(cls.clients, script_local_path)
+ if not ret:
+ raise ExecutionError("Failed to upload IO scripts")
+
+ cls.counter = 1
+
+ def setUp(self):
+ """setUp starts the io from all the mounts.
+ IO creates deep dirs and files.
+ """
+
+ NfsGaneshaVolumeBaseClass.setUp.im_func(self)
+
+ # Start IO on mounts
+ g.log.info("Starting IO on all mounts...")
+ self.all_mounts_procs = []
+ for mount_obj in self.mounts:
+ cmd = ("python %s create_deep_dirs_with_files "
+ "--dirname-start-num %d "
+ "--dir-depth 2 "
+ "--dir-length 15 "
+ "--max-num-of-dirs 5 "
+ "--num-of-files 10 %s" % (self.script_upload_path,
+ self.counter,
+ mount_obj.mountpoint))
+ proc = g.run_async(mount_obj.client_system, cmd,
+ user=mount_obj.user)
+ self.all_mounts_procs.append(proc)
+ self.counter = self.counter + 10
+ self.io_validation_complete = False
+
+ # Adding a delay of 15 seconds before test method starts. This
+ # is to ensure IO's are in progress and giving some time to fill data
+ time.sleep(15)
+
+ def tearDown(self):
+ """If test method failed before validating IO, tearDown waits for the
+ IO's to complete and checks for the IO exit status
+ """
+
+ # Wait for IO to complete if io validation is not executed in the
+ # test method
+ if not self.io_validation_complete:
+ g.log.info("Wait for IO to complete as IO validation did not "
+ "succeed in test method")
+ ret = wait_for_io_to_complete(self.all_mounts_procs, self.mounts)
+ if not ret:
+ raise ExecutionError("IO failed on some of the clients")
+ g.log.info("IO is successful on all mounts")
+ NfsGaneshaVolumeBaseClass.tearDown.im_func(self)
+
+ @classmethod
+ def tearDownClass(cls, umount_volume=True, cleanup_volume=True,
+ teardown_nfsganesha_cluster=True):
+ """Cleanup data from mount, cleanup volume and delete nfs ganesha
+ cluster.
+ """
+ # Log Mounts info
+ g.log.info("Log mounts info")
+ log_mounts_info(cls.mounts)
+
+ (NfsGaneshaVolumeBaseClass.
+ tearDownClass.
+ im_func(cls,
+ umount_vol=umount_volume, cleanup_vol=cleanup_volume,
+ teardown_nfs_ganesha_cluster=teardown_nfsganesha_cluster))
+
+
+def wait_for_nfs_ganesha_volume_to_get_exported(mnode, volname, timeout=120):
+ """Waits for the nfs ganesha volume to get exported
+
+ Args:
+ mnode (str): Node on which command has to be executed.
+ volname (str): volume name
+
+ Kwargs:
+ timeout (int): timeout value in seconds to wait for volume
+ to get exported
+
+ Returns:
+ True on success, False otherwise
+
+ Examples:
+ >>> wait_for_volume_to_get_exported("abc.com", "testvol")
+ """
+ count = 0
+ flag = 0
+ while (count < timeout):
+ if is_volume_exported(mnode, volname, "nfs"):
+ flag = 1
+ break
+
+ time.sleep(10)
+ count = count + 10
+ if not flag:
+ g.log.error("Failed to export volume %s" % volname)
+ return False
+
+ return True
+
+
+def wait_for_nfs_ganesha_volume_to_get_unexported(mnode, volname, timeout=120):
+ """Waits for the nfs ganesha volume to get unexported
+
+ Args:
+ mnode (str): Node on which command has to be executed.
+ volname (str): volume name
+
+ Kwargs:
+ timeout (int): timeout value in seconds to wait for volume
+ to get unexported
+
+ Returns:
+ True on success, False otherwise
+
+ Examples:
+ >>> wait_for_volume_to_get_unexported("abc.com", "testvol")
+ """
+ count = 0
+ flag = 0
+ while (count < timeout):
+ if not is_volume_exported(mnode, volname, "nfs"):
+ flag = 1
+ break
+
+ time.sleep(10)
+ count = count + 10
+ if not flag:
+ g.log.error("Failed to unexport volume %s" % volname)
+ return False
+
+ return True