diff options
Diffstat (limited to 'glustolibs-gluster/glustolibs/gluster/brick_libs.py')
-rw-r--r-- | glustolibs-gluster/glustolibs/gluster/brick_libs.py | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/glustolibs-gluster/glustolibs/gluster/brick_libs.py b/glustolibs-gluster/glustolibs/gluster/brick_libs.py new file mode 100644 index 000000000..617419d9e --- /dev/null +++ b/glustolibs-gluster/glustolibs/gluster/brick_libs.py @@ -0,0 +1,414 @@ +#!/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 +# 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: Module for gluster brick related helper functions. +""" + +import random +from glusto.core import Glusto as g +from glustolibs.gluster.volume_ops import (get_volume_info, get_volume_status) +from glustolibs.gluster.volume_libs import get_subvols + + +def get_all_bricks(mnode, volname): + """Get list of all the bricks of the specified volume. + If the volume is 'Tier' volume, the list will contian both + 'hot tier' and 'cold tier' bricks. + + Args: + mnode (str): Node on which command has to be executed + volname (str): Name of the volume + + Returns: + list: List of all the bricks of the volume on Success. + NoneType: None on failure. + """ + volinfo = get_volume_info(mnode, volname) + if volinfo is None: + g.log.error("Unable to get the volinfo of %s." % volname) + return None + + if 'Tier' in volinfo[volname]['typeStr']: + # Get bricks from hot-tier in case of Tier volume + hot_tier_bricks = get_hot_tier_bricks(mnode, volname) + if hot_tier_bricks is None: + return None + # Get cold-tier bricks in case of Tier volume + cold_tier_bricks = get_cold_tier_bricks(mnode, volname) + if cold_tier_bricks is None: + return None + + return hot_tier_bricks + cold_tier_bricks + + # Get bricks from a non Tier volume + all_bricks = [] + if 'bricks' in volinfo[volname]: + if 'brick' in volinfo[volname]['bricks']: + for brick in volinfo[volname]['bricks']['brick']: + if 'name' in brick: + all_bricks.append(brick['name']) + else: + g.log.error("brick %s doesn't have the key 'name' " + "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) + return None + else: + g.log.error("Bricks not found for the volume %s" % volname) + return None + + +def get_hot_tier_bricks(mnode, volname): + """Get list of hot-tier bricks of the specified volume + + Args: + mnode (str): Node on which command has to be executed + volname (str): Name of the volume + + Returns: + list : List of hot-tier bricks of the volume on Success. + NoneType: None on failure. + """ + volinfo = get_volume_info(mnode, volname) + if volinfo is None: + 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) + return None + + hot_tier_bricks = [] + if 'bricks' in volinfo[volname]: + if 'hotBricks' in volinfo[volname]['bricks']: + if 'brick' in volinfo[volname]['bricks']['hotBricks']: + for brick in volinfo[volname]['bricks']['hotBricks']['brick']: + if 'name' in brick: + hot_tier_bricks.append(brick['name']) + else: + g.log.error("brick %s doesn't have the key 'name' " + "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) + return None + return hot_tier_bricks + else: + g.log.error("Bricks not found for the volume %s" % volname) + return None + + +def get_cold_tier_bricks(mnode, volname): + """Get list of cold-tier bricks of the specified volume + + Args: + mnode (str): Node on which command has to be executed + volname (str): Name of the volume + + Returns: + list : List of cold-tier bricks of the volume on Success. + NoneType: None on failure. + """ + volinfo = get_volume_info(mnode, volname) + if volinfo is None: + 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) + return None + + cold_tier_bricks = [] + if 'bricks' in volinfo[volname]: + if 'coldBricks' in volinfo[volname]['bricks']: + if 'brick' in volinfo[volname]['bricks']['coldBricks']: + for brick in volinfo[volname]['bricks']['coldBricks']['brick']: + if 'name' in brick: + cold_tier_bricks.append(brick['name']) + else: + g.log.error("brick %s doesn't have the key 'name' " + "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) + return None + return cold_tier_bricks + else: + 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 the bricks specified in the bricks_list offline. + + Args: + volname (str): Name of the volume + bricks_list (list): List of bricks to bring them offline. + + Kwargs: + bring_bricks_offline_methods (list): List of methods using which bricks + will be brought offline. The method to bring a brick offline is + randomly selected from the bring_bricks_offline_methods list. + By default all bricks will be brought offline with + 'service_kill' method. + + Returns: + bool : True on successfully bringing all bricks offline. + False otherwise + """ + rc = True + failed_to_bring_offline_list = [] + for brick in bricks_list: + bring_brick_offline_method = (random.choice + (bring_bricks_offline_methods)) + if bring_brick_offline_method == 'service_kill': + brick_node, brick_path = brick.split(":") + brick_path = brick_path.replace("/", "-") + kill_cmd = ("pid=`cat /var/lib/glusterd/vols/%s/run/%s%s.pid` &&" + "kill -15 $pid || kill -9 $pid" % + (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) + failed_to_bring_offline_list.append(brick) + rc = False + else: + 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" % + failed_to_bring_offline_list) + return False + + 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 the bricks specified in the bricks_list online. + + Args: + mnode (str): Node on which commands will be executed. + volname (str): Name of the volume. + bricks_list (list): List of bricks to bring them online. + + Kwargs: + bring_bricks_online_methods (list): List of methods using which bricks + will be brought online. The method to bring a brick online is + randomly selected from the bring_bricks_online_methods list. + By default all bricks will be brought online with + ['glusterd_restart', 'volume_start_force'] methods. + If 'volume_start_force' command is randomly selected then all the + bricks would be started with the command execution. Hence we break + from bringing bricks online individually + + Returns: + bool : True on successfully bringing all bricks online. + False otherwise + """ + rc = True + failed_to_brick_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(":") + 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 + 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 + else: + break + else: + 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" % + failed_to_bring_online_list) + return False + + g.log.info("All the bricks : %s are brought online" % bricks_list) + return True + + +def are_bricks_offline(mnode, volname, bricks_list): + """Verify all the specified list of bricks are offline. + + Args: + mnode (str): Node on which commands will be executed. + volname (str): Name of the volume. + bricks_list (list): List of bricks to verify offline status. + + Returns: + bool : True if all bricks offline. False otherwise. + NoneType: None on failure in getting volume status + """ + 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" % + 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)) + online_bricks_list.append(brick) + 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) + return True + + +def are_bricks_online(mnode, volname, bricks_list): + """Verify all the specified list of bricks are online. + + Args: + mnode (str): Node on which commands will be executed. + volname (str): Name of the volume. + bricks_list (list): List of bricks to verify online status. + + Returns: + bool : True if all bricks online. False otherwise. + NoneType: None on failure in getting volume status + """ + 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" % + 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)) + offline_bricks_list.append(brick) + rc = False + + 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) + return True + +def get_offline_bricks_list(mnode, volname): + """Get list of bricks which are offline. + + Args: + mnode (str): Node on which commands will be executed. + volname (str): Name of the volume. + + Returns: + list : List of bricks in the volume which are offline. + NoneType: None on failure in getting volume status + """ + 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" % + volname) + return None + + bricks_list = get_all_bricks(mnode, volname) + for brick in bricks_list: + brick_node, brick_path = brick.split(":") + status = int(volume_status[volname][brick_node][brick_path]['status']) + if status != 1: + offline_bricks_list.append(brick) + + return offline_bricks_list + + +def get_online_bricks_list(mnode, volname): + """Get list of bricks which are online. + + Args: + mnode (str): Node on which commands will be executed. + volname (str): Name of the volume. + + Returns: + list : List of bricks in the volume which are online. + NoneType: None on failure in getting volume status + """ + 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" % + volname) + return None + + bricks_list = get_all_bricks(mnode, volname) + for brick in bricks_list: + brick_node, brick_path = brick.split(":") + status = int(volume_status[volname][brick_node][brick_path]['status']) + if status == 1: + online_bricks_list.append(brick) + + return online_bricks_list + + +def delete_bricks(bricks_list): + """Deletes list of bricks specified from the brick nodes. + + Args: + bricks_list (list): List of bricks to be deleted. + + Returns: + bool : True if all the bricks are deleted. False otherwise. + """ + 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) + if ret == 0: + g.log.error("Unable to delete brick %s on node %s" % + (brick_path, brick_node)) + rc = False + return rc |