diff options
| author | Shwetha Panduranga <spandura@redhat.com> | 2017-03-03 18:54:54 +0530 | 
|---|---|---|
| committer | Shwetha Panduranga <spandura@redhat.com> | 2017-03-03 18:56:04 +0530 | 
| commit | a6ac5d251f446af5ffa9cc8af836be26f39532e4 (patch) | |
| tree | 15fe418a4a30fca7f8bc9ac04a57be04a5bc05d3 | |
| parent | e0405a0b7b41d7458a2bec15434a4e7f041c4a98 (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.py | 131 | ||||
| -rw-r--r-- | glustolibs-gluster/glustolibs/gluster/brick_ops.py | 47 | ||||
| -rw-r--r-- | glustolibs-gluster/glustolibs/gluster/volume_libs.py | 168 | ||||
| -rw-r--r-- | tests/functional/bvt/test_cvt.py | 214 | 
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)  | 
