summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShwetha Panduranga <spandura@redhat.com>2017-03-03 18:54:54 +0530
committerShwetha Panduranga <spandura@redhat.com>2017-03-03 18:56:04 +0530
commita6ac5d251f446af5ffa9cc8af836be26f39532e4 (patch)
tree15fe418a4a30fca7f8bc9ac04a57be04a5bc05d3
parente0405a0b7b41d7458a2bec15434a4e7f041c4a98 (diff)
Adding a test for Gluster Basic Component Verification Sanity Suite.
- expanding the volume i.e test add-brick is successful on the volume. Change-Id: I8110eea97cf46e3ccc24156d6c67cae0cbf5a7c1 Signed-off-by: Shwetha Panduranga <spandura@redhat.com>
-rw-r--r--glustolibs-gluster/glustolibs/gluster/brick_libs.py131
-rw-r--r--glustolibs-gluster/glustolibs/gluster/brick_ops.py47
-rw-r--r--glustolibs-gluster/glustolibs/gluster/volume_libs.py168
-rw-r--r--tests/functional/bvt/test_cvt.py214
4 files changed, 429 insertions, 131 deletions
diff --git a/glustolibs-gluster/glustolibs/gluster/brick_libs.py b/glustolibs-gluster/glustolibs/gluster/brick_libs.py
index 508eae6a9..a67ef1d7e 100644
--- a/glustolibs-gluster/glustolibs/gluster/brick_libs.py
+++ b/glustolibs-gluster/glustolibs/gluster/brick_libs.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# Copyright (C) 2015-2016 Red Hat, Inc. <http://www.redhat.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -15,9 +14,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-"""
- Description: Module for gluster brick related helper functions.
-"""
+""" Description: Module for gluster brick related helper functions. """
import random
from glusto.core import Glusto as g
@@ -39,7 +36,7 @@ def get_all_bricks(mnode, volname):
"""
volinfo = get_volume_info(mnode, volname)
if volinfo is None:
- g.log.error("Unable to get the volinfo of %s." % volname)
+ g.log.error("Unable to get the volinfo of %s.", volname)
return None
if 'Tier' in volinfo[volname]['typeStr']:
@@ -63,15 +60,15 @@ def get_all_bricks(mnode, volname):
all_bricks.append(brick['name'])
else:
g.log.error("brick %s doesn't have the key 'name' "
- "for the volume: %s" % (brick, volname))
+ "for the volume: %s", brick, volname)
return None
return all_bricks
else:
g.log.error("Bricks not found in Bricks section of volume "
- "info for the volume %s" % volname)
+ "info for the volume %s", volname)
return None
else:
- g.log.error("Bricks not found for the volume %s" % volname)
+ g.log.error("Bricks not found for the volume %s", volname)
return None
@@ -88,11 +85,11 @@ def get_hot_tier_bricks(mnode, volname):
"""
volinfo = get_volume_info(mnode, volname)
if volinfo is None:
- g.log.error("Unable to get the volinfo of %s." % volname)
+ g.log.error("Unable to get the volinfo of %s.", volname)
return None
if 'Tier' not in volinfo[volname]['typeStr']:
- g.log.error("Volume %s is not a tiered volume" % volname)
+ g.log.error("Volume %s is not a tiered volume", volname)
return None
hot_tier_bricks = []
@@ -104,15 +101,15 @@ def get_hot_tier_bricks(mnode, volname):
hot_tier_bricks.append(brick['name'])
else:
g.log.error("brick %s doesn't have the key 'name' "
- "for the volume: %s" % (brick, volname))
+ "for the volume: %s", brick, volname)
return None
else:
g.log.error("Bricks not found in hotBricks section of volume "
- "info for the volume %s" % volname)
+ "info for the volume %s", volname)
return None
return hot_tier_bricks
else:
- g.log.error("Bricks not found for the volume %s" % volname)
+ g.log.error("Bricks not found for the volume %s", volname)
return None
@@ -129,11 +126,11 @@ def get_cold_tier_bricks(mnode, volname):
"""
volinfo = get_volume_info(mnode, volname)
if volinfo is None:
- g.log.error("Unable to get the volinfo of %s." % volname)
+ g.log.error("Unable to get the volinfo of %s.", volname)
return None
if 'Tier' not in volinfo[volname]['typeStr']:
- g.log.error("Volume %s is not a tiered volume" % volname)
+ g.log.error("Volume %s is not a tiered volume", volname)
return None
cold_tier_bricks = []
@@ -145,20 +142,20 @@ def get_cold_tier_bricks(mnode, volname):
cold_tier_bricks.append(brick['name'])
else:
g.log.error("brick %s doesn't have the key 'name' "
- "for the volume: %s" % (brick, volname))
+ "for the volume: %s", brick, volname)
return None
else:
g.log.error("Bricks not found in coldBricks section of volume "
- "info for the volume %s" % volname)
+ "info for the volume %s", volname)
return None
return cold_tier_bricks
else:
- g.log.error("Bricks not found for the volume %s" % volname)
+ g.log.error("Bricks not found for the volume %s", volname)
return None
def bring_bricks_offline(volname, bricks_list,
- bring_bricks_offline_methods=['service_kill']):
+ bring_bricks_offline_methods=None):
"""Bring the bricks specified in the bricks_list offline.
Args:
@@ -176,7 +173,12 @@ def bring_bricks_offline(volname, bricks_list,
bool : True on successfully bringing all bricks offline.
False otherwise
"""
- rc = True
+ if bring_bricks_offline_methods is None:
+ bring_bricks_offline_methods = ['service_kill']
+ elif isinstance(bring_bricks_offline_methods, str):
+ bring_bricks_offline_methods = [bring_bricks_offline_methods]
+
+ _rc = True
failed_to_bring_offline_list = []
for brick in bricks_list:
bring_brick_offline_method = (random.choice
@@ -189,26 +191,25 @@ def bring_bricks_offline(volname, bricks_list,
(volname, brick_node, brick_path))
ret, _, _ = g.run(brick_node, kill_cmd)
if ret != 0:
- g.log.error("Unable to kill the brick %s" % brick)
+ g.log.error("Unable to kill the brick %s", brick)
failed_to_bring_offline_list.append(brick)
- rc = False
+ _rc = False
else:
- g.log.error("Invalid method '%s' to bring brick offline" %
+ g.log.error("Invalid method '%s' to bring brick offline",
bring_brick_offline_method)
return False
- if not rc:
- g.log.error("Unable to bring some of the bricks %s offline" %
+ if not _rc:
+ g.log.error("Unable to bring some of the bricks %s offline",
failed_to_bring_offline_list)
return False
- g.log.info("All the bricks : %s are brought offline" % bricks_list)
+ g.log.info("All the bricks : %s are brought offline", bricks_list)
return True
def bring_bricks_online(mnode, volname, bricks_list,
- bring_bricks_online_methods=['glusterd_restart',
- 'volume_start_force']):
+ bring_bricks_online_methods=None):
"""Bring the bricks specified in the bricks_list online.
Args:
@@ -230,39 +231,45 @@ def bring_bricks_online(mnode, volname, bricks_list,
bool : True on successfully bringing all bricks online.
False otherwise
"""
- rc = True
+ if bring_bricks_online_methods is None:
+ bring_bricks_online_methods = ['glusterd_restart',
+ 'volume_start_force']
+ elif isinstance(bring_bricks_online_methods, str):
+ bring_bricks_online_methods = [bring_bricks_online_methods]
+
+ _rc = True
failed_to_bring_online_list = []
for brick in bricks_list:
bring_brick_online_method = random.choice(bring_bricks_online_methods)
if bring_brick_online_method == 'glusterd_restart':
bring_brick_online_command = "service glusterd restart"
- brick_node, brick_path = brick.split(":")
+ brick_node, _ = brick.split(":")
ret, _, _ = g.run(brick_node, bring_brick_online_command)
if ret != 0:
- g.log.error("Unable to restart glusterd on node %s" %
- (brick_node))
- rc = False
+ g.log.error("Unable to restart glusterd on node %s",
+ brick_node)
+ _rc = False
failed_to_bring_online_list.append(brick)
elif bring_brick_online_method == 'volume_start_force':
bring_brick_online_command = ("gluster volume start %s force" %
volname)
ret, _, _ = g.run(mnode, bring_brick_online_command)
if ret != 0:
- g.log.error("Unable to start the volume %s with force option" %
- (volname))
- rc = False
+ g.log.error("Unable to start the volume %s with force option",
+ volname)
+ _rc = False
else:
break
else:
- g.log.error("Invalid method '%s' to bring brick online" %
+ g.log.error("Invalid method '%s' to bring brick online",
bring_brick_online_method)
return False
- if not rc:
- g.log.error("Unable to bring some of the bricks %s online" %
+ if not _rc:
+ g.log.error("Unable to bring some of the bricks %s online",
failed_to_bring_online_list)
return False
- g.log.info("All the bricks : %s are brought online" % bricks_list)
+ g.log.info("All the bricks : %s are brought online", bricks_list)
return True
@@ -278,26 +285,26 @@ def are_bricks_offline(mnode, volname, bricks_list):
bool : True if all bricks offline. False otherwise.
NoneType: None on failure in getting volume status
"""
- rc = True
+ _rc = True
online_bricks_list = []
volume_status = get_volume_status(mnode, volname)
if not volume_status:
- g.log.error("Unable to check if bricks are offline for the volume %s" %
+ g.log.error("Unable to check if bricks are offline for the volume %s",
volname)
return None
for brick in bricks_list:
brick_node, brick_path = brick.split(":")
status = int(volume_status[volname][brick_node][brick_path]['status'])
if status != 0:
- g.log.error("BRICK : %s is not offline" % (brick))
+ g.log.error("BRICK : %s is not offline", brick)
online_bricks_list.append(brick)
- rc = False
- if not rc:
- g.log.error("Some of the bricks %s are not offline" %
+ _rc = False
+ if not _rc:
+ g.log.error("Some of the bricks %s are not offline",
online_bricks_list)
return False
- g.log.info("All the bricks in %s are offline" % bricks_list)
+ g.log.info("All the bricks in %s are offline", bricks_list)
return True
@@ -313,27 +320,27 @@ def are_bricks_online(mnode, volname, bricks_list):
bool : True if all bricks online. False otherwise.
NoneType: None on failure in getting volume status
"""
- rc = True
+ _rc = True
offline_bricks_list = []
volume_status = get_volume_status(mnode, volname)
if not volume_status:
- g.log.error("Unable to check if bricks are online for the volume %s" %
+ g.log.error("Unable to check if bricks are online for the volume %s",
volname)
return None
for brick in bricks_list:
brick_node, brick_path = brick.split(":")
status = int(volume_status[volname][brick_node][brick_path]['status'])
if status != 1:
- g.log.error("BRICK : %s is not online" % (brick))
+ g.log.error("BRICK : %s is not online", brick)
offline_bricks_list.append(brick)
- rc = False
+ _rc = False
- if not rc:
- g.log.error("Some of the bricks %s are not online" %
+ if not _rc:
+ g.log.error("Some of the bricks %s are not online",
offline_bricks_list)
return False
- g.log.info("All the bricks %s are online" % bricks_list)
+ g.log.info("All the bricks %s are online", bricks_list)
return True
@@ -351,7 +358,7 @@ def get_offline_bricks_list(mnode, volname):
offline_bricks_list = []
volume_status = get_volume_status(mnode, volname)
if not volume_status:
- g.log.error("Unable to get offline bricks_list for the volume %s" %
+ g.log.error("Unable to get offline bricks_list for the volume %s",
volname)
return None
@@ -379,7 +386,7 @@ def get_online_bricks_list(mnode, volname):
online_bricks_list = []
volume_status = get_volume_status(mnode, volname)
if not volume_status:
- g.log.error("Unable to get online bricks_list for the volume %s" %
+ g.log.error("Unable to get online bricks_list for the volume %s",
volname)
return None
@@ -402,13 +409,13 @@ def delete_bricks(bricks_list):
Returns:
bool : True if all the bricks are deleted. False otherwise.
"""
- rc = True
+ _rc = True
for brick in bricks_list:
brick_node, brick_path = brick.split(":")
_, _, _ = g.run(brick_node, "rm -rf %s" % brick_path)
- ret, out, err = g.run(brick_node, "ls %s" % brick_path)
+ ret, _, _ = g.run(brick_node, "ls %s" % brick_path)
if ret == 0:
- g.log.error("Unable to delete brick %s on node %s" %
- (brick_path, brick_node))
- rc = False
- return rc
+ g.log.error("Unable to delete brick %s on node %s",
+ brick_path, brick_node)
+ _rc = False
+ return _rc
diff --git a/glustolibs-gluster/glustolibs/gluster/brick_ops.py b/glustolibs-gluster/glustolibs/gluster/brick_ops.py
index 61c86fa75..016569f15 100644
--- a/glustolibs-gluster/glustolibs/gluster/brick_ops.py
+++ b/glustolibs-gluster/glustolibs/gluster/brick_ops.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# Copyright (C) 2015-2016 Red Hat, Inc. <http://www.redhat.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -15,14 +14,12 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-"""
- Description: Module for gluster brick operations
-"""
+""" Description: Module for gluster brick operations """
from glusto.core import Glusto as g
-def add_brick(mnode, volname, bricks_list, replica=None):
+def add_brick(mnode, volname, bricks_list, force=False, **kwargs):
"""Add Bricks specified in the bricks_list to the volume.
Args:
@@ -31,8 +28,14 @@ def add_brick(mnode, volname, bricks_list, replica=None):
bricks_list (list): List of bricks to be added
Kwargs:
- replica (int): Replica count to increase the replica count of
- the volume.
+ force (bool): If this option is set to True, then add brick command
+ will get executed with force option. If it is set to False,
+ then add brick command will get executed without force option
+
+ **kwargs
+ The keys, values in kwargs are:
+ - replica_count : (int)|None
+ - arbiter_count : (int)|None
Returns:
tuple: Tuple containing three elements (ret, out, err).
@@ -45,17 +48,32 @@ def add_brick(mnode, volname, bricks_list, replica=None):
The third element 'err' is of type 'str' and is the stderr value
of the command execution.
"""
- if replica is None:
- cmd = ("gluster volume add-brick %s %s" %
- (volname, ' '.join(bricks_list)))
- else:
- cmd = ("gluster volume add-brick %s replica %d %s" %
- (volname, int(replica), ' '.join(bricks_list)))
+ replica_count = arbiter_count = None
+
+ if 'replica_count' in kwargs:
+ replica_count = int(kwargs['replica_count'])
+
+ if 'arbiter_count' in kwargs:
+ arbiter_count = int(kwargs['arbiter_count'])
+
+ replica = arbiter = ''
+
+ if replica_count is not None:
+ replica = "replica %d" % replica_count
+
+ if arbiter_count is not None:
+ arbiter = "arbiter %d" % arbiter_count
+
+ force_value = ''
+ if force:
+ force_value = "force"
+
+ cmd = ("gluster volume add-brick %s %s %s %s %s" %
+ (volname, replica, arbiter, ' '.join(bricks_list), force_value))
return g.run(mnode, cmd)
-# remove_brick
def remove_brick(mnode, volname, bricks_list, option, replica=None):
"""Remove bricks specified in the bricks_list from the volume.
@@ -94,7 +112,6 @@ def remove_brick(mnode, volname, bricks_list, option, replica=None):
return g.run(mnode, cmd)
-# replace_brick
def replace_brick(mnode, volname, src_brick, dst_brick):
"""Replace src brick with dst brick from the volume.
diff --git a/glustolibs-gluster/glustolibs/gluster/volume_libs.py b/glustolibs-gluster/glustolibs/gluster/volume_libs.py
index 6a3f80ac3..22ac7e375 100644
--- a/glustolibs-gluster/glustolibs/gluster/volume_libs.py
+++ b/glustolibs-gluster/glustolibs/gluster/volume_libs.py
@@ -14,9 +14,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-"""
- Description: Module for gluster volume related helper functions.
-"""
+""" Description: Module for gluster volume related helper functions. """
from glusto.core import Glusto as g
@@ -26,7 +24,8 @@ from glustolibs.gluster.volume_ops import (volume_create, volume_start,
set_volume_options, get_volume_info,
volume_stop, volume_delete,
volume_info, volume_status,
- get_volume_options)
+ get_volume_options,
+ get_volume_list)
from glustolibs.gluster.tiering_ops import (add_extra_servers_to_cluster,
tier_attach,
is_tier_process_running)
@@ -36,6 +35,29 @@ from glustolibs.gluster.uss_ops import enable_uss, is_uss_enabled
from glustolibs.gluster.snap_ops import snap_delete_by_volumename
from glustolibs.gluster.brick_libs import are_bricks_online, get_all_bricks
from glustolibs.gluster.heal_libs import are_all_self_heal_daemons_are_online
+from glustolibs.gluster.brick_ops import add_brick
+
+
+def volume_exists(mnode, volname):
+ """Check if volume already exists
+
+ Args:
+ mnode (str): Node on which commands has to be executed
+ volname (str): Name of the volume.
+
+ Returns:
+ NoneType: If there are errors
+ bool : True if volume exists. False Otherwise
+ """
+ volume_list = get_volume_list(mnode)
+ if volume_list is None:
+ g.log.error("'gluster volume list' on node %s Failed", mnode)
+ return None
+
+ if volname in volume_list:
+ return True
+ else:
+ return False
def setup_volume(mnode, all_servers_info, volume_config, force=False):
@@ -482,6 +504,7 @@ def get_subvols(mnode, volname):
"""
subvols = {
+ 'is_tier': False,
'hot_tier_subvols': [],
'cold_tier_subvols': [],
'volume_subvols': []
@@ -490,6 +513,9 @@ def get_subvols(mnode, volname):
if volinfo is not None:
voltype = volinfo[volname]['typeStr']
if voltype == 'Tier':
+ # Set is_tier to True
+ subvols['is_tier'] = True
+
# Get hot tier subvols
hot_tier_type = (volinfo[volname]["bricks"]
['hotBricks']['hotBrickType'])
@@ -1093,3 +1119,137 @@ def enable_and_validate_volume_options(mnode, volname, volume_options_list,
time.sleep(time_delay)
return True
+
+
+def expand_volume(mnode, volname, servers, all_servers_info, force=False,
+ add_to_hot_tier=False, **kwargs):
+ """Forms list of bricks to add and adds those bricks to the volume.
+
+ Args:
+ mnode (str): Node on which commands has to be executed
+ volname (str): volume name
+ servers (list): List of servers in the storage pool.
+ all_servers_info (dict): Information about all servers.
+ example :
+ all_servers_info = {
+ 'abc.lab.eng.xyz.com': {
+ 'host': 'abc.lab.eng.xyz.com',
+ 'brick_root': '/bricks',
+ 'devices': ['/dev/vdb', '/dev/vdc', '/dev/vdd', '/dev/vde']
+ },
+ 'def.lab.eng.xyz.com':{
+ 'host': 'def.lab.eng.xyz.com',
+ 'brick_root': '/bricks',
+ 'devices': ['/dev/vdb', '/dev/vdc', '/dev/vdd', '/dev/vde']
+ }
+ }
+ Kwargs:
+ force (bool): If this option is set to True, then add-brick command
+ will get executed with force option. If it is set to False,
+ then add-brick command will get executed without force option
+
+ add_to_hot_tier (bool): True If bricks are to be added to hot_tier.
+ False otherwise. Defaults to False.
+
+ **kwargs
+ The keys, values in kwargs are:
+ - replica_count : (int)|None
+ - arbiter_count : (int)|None
+ - distribute_count: (int)|None
+
+ Returns:
+ bool: True of expanding volumes is successful.
+ False otherwise.
+ """
+ # Check whether we need to increase the replica count of the volume
+ if 'replica_count' in kwargs:
+ new_replica_count = int(kwargs['replica_count'])
+
+ # Get replica count info.
+ replica_count_info = get_replica_count(mnode, volname)
+
+ # Get Subvols
+ subvols_info = get_subvols(mnode, volname)
+
+ # Calculate number of bricks to add
+ if subvols_info['is_tier']:
+ if add_to_hot_tier:
+ num_of_subvols = len(subvols_info['hot_tier_subvols'])
+ current_replica_count = (
+ int(replica_count_info['hot_tier_replica_count']))
+ else:
+ num_of_subvols = len(subvols_info['cold_tier_subvols'])
+ current_replica_count = (
+ int(replica_count_info['cold_tier_replica_count']))
+ else:
+ num_of_subvols = len(subvols_info['volume_subvols'])
+ current_replica_count = (
+ int(replica_count_info['volume_replica_count']))
+
+ if num_of_subvols == 0:
+ g.log.error("No Sub-Volumes available for the volume %s."
+ "Hence cannot proceed with add-brick", volname)
+ return False
+
+ if new_replica_count <= current_replica_count:
+ g.log.error("Provided replica count '%d' is less than or equal to "
+ "the Existing replica count '%d' of the volume %s. "
+ "Hence cannot proceed with add-brick",
+ new_replica_count, current_replica_count, volname)
+ return False
+
+ num_of_bricks_to_add = (
+ (new_replica_count - current_replica_count) * num_of_subvols)
+
+ else:
+ # Check if the volume has to be expanded by n distribute count.
+ if 'distribute_count' in kwargs:
+ distribute_count_to_add = int(kwargs['distribute_count'])
+ else:
+ distribute_count_to_add = 1
+
+ # Get Number of bricks per subvolume.
+ bricks_per_subvol_dict = get_num_of_bricks_per_subvol(mnode, volname)
+
+ # Get number of bricks to add.
+ if bricks_per_subvol_dict['is_tier']:
+ if add_to_hot_tier:
+ num_of_bricks_per_subvol = (
+ bricks_per_subvol_dict['hot_tier_num_of_bricks_per_subvol']
+ )
+ else:
+ num_of_bricks_per_subvol = (
+ bricks_per_subvol_dict
+ ['cold_tier_num_of_bricks_per_subvol']
+ )
+ else:
+ num_of_bricks_per_subvol = (
+ bricks_per_subvol_dict['volume_num_of_bricks_per_subvol'])
+
+ if num_of_bricks_per_subvol is None:
+ g.log.error("Number of bricks per subvol is None. "
+ "Something majorly went wrong on the voluem %s",
+ volname)
+ return False
+
+ num_of_bricks_to_add = (
+ num_of_bricks_per_subvol * distribute_count_to_add)
+
+ # Form bricks list to add bricks to the volume.
+ bricks_list = form_bricks_list(mnode=mnode, volname=volname,
+ number_of_bricks=num_of_bricks_to_add,
+ servers=servers,
+ servers_info=all_servers_info)
+ if not bricks_list:
+ g.log.error("Number of bricks is greater than the unused bricks on "
+ "servers. Hence failed to perform add-brick operation")
+ return False
+
+ # Add bricks to the volume
+ ret, out, err = add_brick(mnode, volname, bricks_list, force=force,
+ **kwargs)
+ if ret != 0:
+ g.log.error("Failed to add bricks to the volume: %s", err)
+ return False
+ g.log.info("Successfully added bricks to the volume: %s", out)
+ return True
diff --git a/tests/functional/bvt/test_cvt.py b/tests/functional/bvt/test_cvt.py
index d2d88f44b..bc6634bb2 100644
--- a/tests/functional/bvt/test_cvt.py
+++ b/tests/functional/bvt/test_cvt.py
@@ -14,7 +14,23 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-""" Description: BVT-Component Verification Tests (CVT) """
+""" Build Verification Tests (BVT) : Component Verification Tests (CVT)
+ Test Cases in this module tests the basic gluster operations sanity
+ while IO is in progress. These tests verifies basic gluster features
+ which should not be broken at all.
+
+ Basic Gluster Operations tested:
+ - add-brick
+ - rebalance
+ - set volume options which changes the client graphs
+ TODO:
+ - remove-brick
+ - n/w failure followed by heal
+ - replace-brick
+ - enable quota
+ - collecting snapshot
+ - attach-tier, detach-tier
+"""
import pytest
import time
@@ -22,6 +38,13 @@ from glusto.core import Glusto as g
from glustolibs.gluster.gluster_base_class import (GlusterVolumeBaseClass,
runs_on)
from glustolibs.gluster.volume_libs import enable_and_validate_volume_options
+from glustolibs.gluster.volume_libs import (
+ verify_all_process_of_volume_are_online)
+from glustolibs.gluster.volume_libs import (log_volume_info_and_status,
+ expand_volume)
+from glustolibs.gluster.rebalance_ops import (rebalance_start,
+ wait_for_rebalance_to_complete,
+ rebalance_status)
from glustolibs.misc.misc_libs import upload_scripts
from glustolibs.io.utils import (validate_io_procs, log_mounts_info,
list_all_files_and_dirs_mounts,
@@ -29,24 +52,8 @@ from glustolibs.io.utils import (validate_io_procs, log_mounts_info,
from glustolibs.gluster.exceptions import ExecutionError
-@runs_on([['replicated', 'distributed', 'distributed-replicated',
- 'dispersed', 'distributed-dispersed'],
- ['glusterfs', 'nfs', 'cifs']])
-class TestGlusterBasicFeaturesSanity(GlusterVolumeBaseClass):
- """ TestGlusterBasicFeaturesSanity contains tests which verifies basic
- gluster features which should not be broken at all.
- This covers testing gluster operations while IO is in progress.
- - set volume options which changes the client graphs
- TODO:
- - add-brick
- - rebalance
- - remove-brick
- - n/w failure followed by heal
- - replace-brick
- - enable quota
- - collecting snapshot
- - attach-tier, detach-tier
- """
+class GlusterBasicFeaturesSanityBaseClass(GlusterVolumeBaseClass):
+ """ BaseClass for all the gluster basic features sanity tests. """
@classmethod
def setUpClass(cls):
"""Setup Volume, Create Mounts and upload the necessary scripts to run
@@ -93,7 +100,7 @@ class TestGlusterBasicFeaturesSanity(GlusterVolumeBaseClass):
cmd = ("python %s create_deep_dirs_with_files "
"--dirname-start-num %d "
"--dir-depth 2 "
- "--dir-length 10 "
+ "--dir-length 15 "
"--max-num-of-dirs 5 "
"--num-of-files 5 %s" % (self.script_upload_path,
self.counter,
@@ -108,12 +115,144 @@ class TestGlusterBasicFeaturesSanity(GlusterVolumeBaseClass):
# 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")
+ GlusterVolumeBaseClass.tearDown.im_func(self)
+
+ @classmethod
+ def tearDownClass(cls):
+ """Cleanup data from mount and cleanup volume.
+ """
+ # Log Mounts info
+ g.log.info("Log mounts info")
+ log_mounts_info(cls.mounts)
+
+ GlusterVolumeBaseClass.tearDownClass.im_func(cls)
+
+
+@runs_on([['replicated', 'distributed', 'distributed-replicated',
+ 'dispersed', 'distributed-dispersed'],
+ ['glusterfs', 'nfs', 'cifs']])
+class TestGlusterExpandVolumeSanity(GlusterBasicFeaturesSanityBaseClass):
+ """Sanity tests for Expanding Volume"""
+ @pytest.mark.bvt_cvt
+ def test_expanding_volume_when_io_in_progress(self):
+ """Test expanding volume (Increase distribution) using existing
+ servers bricks when IO is in progress.
+
+ Description:
+ - add bricks
+ - starts rebalance
+ - wait for rebalance to complete
+ - validate IO
+ """
+ # Log Volume Info and Status before expanding the volume.
+ g.log.info("Logging volume info and Status before expanding volume")
+ ret = log_volume_info_and_status(self.mnode, self.volname)
+ self.assertTrue(ret, ("Logging volume info and status failed on "
+ "volume %s", self.volname))
+ g.log.info("Successful in logging volume info and status of volume %s",
+ self.volname)
+
+ # Expanding volume by adding bricks to the volume when IO in progress
+ g.log.info("Start adding bricks to volume when IO in progress")
+ ret = expand_volume(self.mnode, self.volname, self.servers,
+ self.all_servers_info)
+ self.assertTrue(ret, ("Failed to expand the volume when IO in "
+ "progress on volume %s", self.volname))
+ g.log.info("Expanding volume when IO in progress is successful on "
+ "volume %s", self.volname)
+
+ # Wait for gluster processes to come online
+ time.sleep(30)
+
+ # Log Volume Info and Status after expanding the volume
+ g.log.info("Logging volume info and Status after expanding volume")
+ ret = log_volume_info_and_status(self.mnode, self.volname)
+ self.assertTrue(ret, ("Logging volume info and status failed on "
+ "volume %s", self.volname))
+ g.log.info("Successful in logging volume info and status of volume %s",
+ self.volname)
+
+ # Verify volume's all process are online
+ g.log.info("Verifying volume's all process are online")
+ ret = verify_all_process_of_volume_are_online(self.mnode, self.volname)
+ self.assertTrue(ret, ("Volume %s : All process are not online",
+ self.volname))
+ g.log.info("Volume %s : All process are online", self.volname)
+
+ # Start Rebalance
+ g.log.info("Starting Rebalance on the volume")
+ ret, _, _ = rebalance_start(self.mnode, self.volname)
+ self.assertEqual(ret, 0, ("Failed to start rebalance on the volume "
+ "%s", self.volname))
+ g.log.info("Successfully started rebalance on the volume %s",
+ self.volname)
+
+ # Check Rebalance status
+ g.log.info("Checking Rebalance status")
+ ret, _, _ = rebalance_status(self.mnode, self.volname)
+ self.assertEqual(ret, 0, ("Failed to get rebalance status for the "
+ "volume %s", self.volname))
+ g.log.info("Successfully got rebalance status of the volume %s",
+ self.volname)
+
+ # Wait for rebalance to complete
+ g.log.info("Waiting for rebalance to complete")
+ ret = wait_for_rebalance_to_complete(self.mnode, self.volname)
+ self.assertTrue(ret, ("Rebalance is not yet complete on the volume "
+ "%s", self.volname))
+ g.log.info("Rebalance is successfully complete on the volume %s",
+ self.volname)
+
+ # Check Rebalance status after rebalance is complete
+ g.log.info("Checking Rebalance status")
+ ret, _, _ = rebalance_status(self.mnode, self.volname)
+ self.assertEqual(ret, 0, ("Failed to get rebalance status for the "
+ "volume %s", self.volname))
+ g.log.info("Successfully got rebalance status of the volume %s",
+ self.volname)
+
+ # Validate IO
+ g.log.info("Wait for IO to complete and validate IO ...")
+ ret = validate_io_procs(self.all_mounts_procs, self.mounts)
+ self.io_validation_complete = True
+ self.assertTrue(ret, "IO failed on some of the clients")
+ g.log.info("IO is successful on all mounts")
+
+ # List all files and dirs created
+ g.log.info("List all files and directories:")
+ ret = list_all_files_and_dirs_mounts(self.mounts)
+ self.assertTrue(ret, "Failed to list all files and dirs")
+ g.log.info("Listing all files and directories is successful")
+
+
+@runs_on([['replicated', 'distributed', 'distributed-replicated',
+ 'dispersed', 'distributed-dispersed'],
+ ['glusterfs', 'nfs', 'cifs']])
+class TestGlusterVolumeSetSanity(GlusterBasicFeaturesSanityBaseClass):
+ """ Sanity tests for Volume Set operation
+ """
@pytest.mark.bvt_cvt
def test_volume_set_when_io_in_progress(self):
- """Set Volume options while IO is in progress.
- Volume Options:
- - uss
- - shard
+ """Set Volume options which changes the client graphs while IO is
+ in progress.
+
+ Description:
+ - set volume option uss, shard to 'enable' and
+ validate it is successful
+ - validate IO to be successful
"""
# List of volume options to set
volume_options_list = ["features.uss", "features.shard"]
@@ -122,7 +261,7 @@ class TestGlusterBasicFeaturesSanity(GlusterVolumeBaseClass):
g.log.info("Setting the volume options: %s", volume_options_list)
ret = enable_and_validate_volume_options(self.mnode, self.volname,
volume_options_list,
- time_delay=10)
+ time_delay=30)
self.assertTrue(ret, ("Unable to enable the volume options: %s",
volume_options_list))
g.log.info("Successfully enabled all the volume options: %s",
@@ -140,28 +279,3 @@ class TestGlusterBasicFeaturesSanity(GlusterVolumeBaseClass):
ret = list_all_files_and_dirs_mounts(self.mounts)
self.assertTrue(ret, "Failed to list all files and dirs")
g.log.info("Listing all files and directories is successful")
-
- 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")
- GlusterVolumeBaseClass.tearDown.im_func(self)
-
- @classmethod
- def tearDownClass(cls):
- """Cleanup data from mount and cleanup volume.
- """
- # Log Mounts info
- g.log.info("Log mounts info")
- log_mounts_info(cls.mounts)
-
- GlusterVolumeBaseClass.tearDownClass.im_func(cls)