"""Routines that get and change settings and information about gluster volumes

This exports:
  get_components - Used to add a set of IPs to the CTDB nodes file
  get_basic_volume_info_all - Gets the basic volume info for all the volumes except the integralview admin volume
  get_basic_volume_info - Gets the basic volume info for a specific volume
  get_volume_status - Gets the volume status for a specific volume
  get_volume_process_status - Gets the volume processes status for a specific volume
  get_volume_quota - Gets the volume quota for a specific volume
  get_complete_volume_info_all - Gets all the volume info and status for all the volumes except the integralview admin volume
  get_complete_volume_info - Gets all the volume info and status for a specific volume
  volume_exists -  Check if a volume by the specified name exists
  get_brick_hostname_list - Get all the hostnames of the all the bricks for a specific volume
  get_volumes_on_node - Get all the volumes that have a brick on the specified node
  get_snapshots - Get all the snapshots taken for a specific volume
  set_volume_options - Set a set of volume options
  _set_volume_option - Set a specific volume option
  build_create_or_expand_volume_command - Generate a command to automatically create or expand a volume based on passed in options.
  build_expand_volume_command - Generate a command to automatically expand a volume based on passed in options.
  build_create_volume_command - Generate a command to automatically create a volume based on passed in options.
  volume_stop_or_start - Start or stop a command.

"""

import re
import random
import sys
import os

from integralstor_utils import filesize, command, networking, config
from integralstor_gridcell import xml_parse


def get_components(brick):
    """Given a brick path, split and return the components

    Returns a dict with the host component, the rest of the path, the zfs pool the ondisk storage format - assumes that the dataset name is of the form <pool_name>/<ondisk_storage_format>/<vol_name> where ondisk_storage_format is either normal or compressed or deduplicated
    brick -- The brick path
    """
    d = None
    try:
        if not brick:
            raise Exception('Brick path not provided')
        l = brick.split(':')
        if not l or len(l) == 1:
            raise Exception('Invalid brick path : %s' % brick)
        d = {}
        d["host"] = l[0]
        d["path"] = l[1]
        l1 = l[1].split('/')
        if len(l1) == 1:
            raise Exception('Invalid brick path : %s' % brick)
        d["pool"] = l1[1]
        d["ondisk_storage"] = l1[2]
    except Exception, e:
        return None, 'Error getting brick components : %s' % str(e)
    else:
        return d, None


def get_basic_volume_info_all():
    """Returns the basic information about all the volumes except the integralview admin volume

    The return value is a list of dicts where each dict has all the info of one volume
    The information returned consists of all information returned by gluster volume info all which is : name, type, status code, status string, number of bricks, distcount, stripecount, replicacount, optcount, brick info, options info, protocols info..
    """
    vl = None
    try:
        d, err = xml_parse.run_gluster_command(
            '/usr/sbin/gluster volume info all --xml')
        if err:
            raise Exception(err)

        root = d["root"]

        # Get the admin vol name so it can be excluded from the list
        admin_vol_name, err = config.get_admin_vol_name()
        if err:
            raise Exception(err)

        # Now get the all the volume info for user created volumes
        vl, err = xml_parse.get_volume_info(root, admin_vol_name)
        if err:
            raise Exception(err)
    except Exception, e:
        return None, 'Error getting basic volume information for all volumes : %s' % str(e)
    else:
        return vl, None


def get_basic_volume_info(vol_name, vl=None):
    """Returns the basic information about all a specific volume 

    The return value is a volume dict which has all the info of the volume
    The information returned consists of all information returned by gluster volume info all which is : name, type, status code, status string, number of bricks, distcount, stripecount, replicacount, optcount, brick info, options info, protocols info..

    vol_name -- The volume name for which the info is needed.
    vl - The dict obtained from get_basic_volume_info_all if present. If not, we generate it.
    """
    return_dict = None
    try:
        vl, err = get_basic_volume_info_all()
        for v in vl:
            if v['name'] == vol_name:
                return_dict = v
                break
    except Exception, e:
        return None, 'Error getting basic volume information for a specific volume : %s' % str(e)
    else:
        return return_dict, None


def get_volume_status(vol_name, vol_info_dict=None):
    """Returns the volume status, brick status and volume usage details for a particular volume

    The return value is a dict which has all the info of the volume. The status info is only available for started volumes or else an error gets thrown.
    vol_name -- The name of the volume for which the status details is required.
    vol -- If the basic volume info dict is available then it can be passed here to avoid generating it again. If not, sigh.., we have to generate it.
    """
    return_dict = {}
    try:
        if not vol_info_dict:
            vol_info_dict, err = get_basic_volume_info(vol_name)
            if err:
                raise Exception(err)

        if vol_info_dict["status"] != 1:
            # Not running so dont try and get the status detail
            raise Exception('Cannot retrieve the status for stopped volumes.')

        d, err = xml_parse.run_gluster_command(
            "/usr/sbin/gluster volume status %s detail --xml" % vol_name)
        if err:
            raise Exception(err)

        if not d or "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
            err = "Error getting the volume status details: "
            if d:
                if "error_list" in d:
                    err += " ".join(d["error_list"])
                if "op_status" in d and "op_errstr" in d["op_status"]:
                    if d["op_status"]["op_errstr"]:
                        err += d["op_status"]["op_errstr"]
            raise Exception(err)
        vsd_root = d["root"]

        # Get the brick status and num good and bad bricks
        tup, err = xml_parse.get_brick_status(vsd_root)
        if err:
            raise Exception(err)
        if tup:
            (bd, num_up, num_down) = tup
        else:
            raise Exception('Error retrieving brick status')
        return_dict["brick_status"] = bd

        # Now calculate the size statistics for the volume from individual
        # bricks
        size_total = 0
        size_free = 0
        if vol_info_dict["replica_count"] > 1:
            replica_set_status = []
            for br in vol_info_dict["bricks"]:
                counted = False
                for b in br:
                    if b not in bd:
                        # Could happen if a brick is down
                        continue
                    if bd[b]["status"] == 1:
                        if not counted:
                            # Found one up replica so only consider size info
                            # for this. If all down then it does not count
                            size_free += bd[b]["size_free"]
                            size_total += bd[b]["size_total"]
                            counted = True
                    replica_set_status.append(num_down)
            # print replica_set_status
            if num_up == 0:
                return_dict["data_access_status"] = "Volume down. No data accessible!"
                return_dict["data_access_status_code"] = -1
            else:
                if max(replica_set_status) == vol_info_dict["replica_count"]:
                    return_dict["data_access_status"] = "Some data inaccessible"
                    return_dict["data_access_status_code"] = -1
                elif max(replica_set_status) > 0:
                    num_more = vol_info_dict["replica_count"] - \
                        max(replica_set_status)
                    return_dict["data_access_status"] = "Data accessible but vulnerable. Loss of %d more data locations will cause data loss" % num_more
                    return_dict["data_access_status_code"] = 1
                else:
                    return_dict["data_access_status"] = "Healthy"
                    return_dict["data_access_status_code"] = 0
        else:
            # Distributed so count em all
            for b in bd.keys():
                if bd[b]["status"] == 1:
                    size_free += bd[b]["size_free"]
                    size_total += bd[b]["size_total"]
            if num_down > 0:
                return_dict["data_access_status"] = "Some data inaccessible"
                return_dict["data_access_status_code"] = 1
            else:
                return_dict["data_access_status"] = "Healthy"
                return_dict["data_access_status_code"] = 0
        return_dict["size_total"] = filesize.get_naturalsize(
            size_total, binary=True)
        return_dict["size_used"] = filesize.get_naturalsize(
            size_total - size_free, binary=True)
        return_dict["size_free"] = filesize.get_naturalsize(
            size_free, binary=True)
        # print size_total-size_free
        #print (size_total-size_free)/float(size_total)
        if size_total > 0:
            return_dict["size_used_percent"] = int(
                ((size_total - size_free) / float(size_total)) * 100)
        else:
            return_dict["size_used_percent"] = -1
        # print vol_info_dict["size_used_percent"]

    except Exception, e:
        return None, 'Error getting volume status and usage : %s' % str(e)
    else:
        return return_dict, None


def get_volume_process_status(vol_name, vol_info_dict=None, vol_status_dict=None):
    """Returns the volume process status for a particular volume

    The return value is a dict which has a flag to say if all the processes are ok or not and for each brick, it has the appropriate process status
    vol_name -- The name of the volume for which the status details is required.
    vol_info_dict -- The dict returned from get_volume_info for that volume - we can get it if None
    vol_status_dict -- The dict returned from get_volume_status for that volume - we can get it if None
    """
    return_dict = {}
    try:

        if not vol_info_dict:
            vol_info_dict, err = get_basic_volume_info(vol_name)
            if err:
                raise Exception(err)

        if not vol_status_dict:
            vol_status_dict, err = get_volume_status(vol_name, vol_info_dict)
            if err:
                raise Exception(err)

        # Now get the status of the self heal and NFS servers for each node
        d, err = xml_parse.run_gluster_command(
            "/usr/sbin/gluster volume status %s --xml" % vol_name)
        if err:
            raise Exception(err)

        return_dict, err = xml_parse.get_volume_process_status(
            d['root'], vol_info_dict, vol_status_dict)
        if err:
            raise Exception(err)
    except Exception, e:
        return None, 'Error getting volume process status : %s' % str(e)
    else:
        return return_dict, None


def get_volume_quota(vol_name, vol_info_dict=None):
    """Returns the volume quota information for a particular volume

    The return value is a dict which has the quota 
    vol_name -- The name of the volume for which the status details is required.
    vol_info_dict -- The dict returned from get_volume_info for that volume - we can get it if None
    """
    return_dict = {}
    try:
        if not vol_info_dict:
            vol_info_dict, err = get_basic_volume_info(vol_name)
            if err:
                raise Exception(err)
        no_quotas_set = False
        if "options" in vol_info_dict:
            for o in vol_info_dict["options"]:
                if "features.quota" == o["name"]:
                    if o["value"] == "on" and vol_info_dict['status'] == 1:
                        # Now get the status of the self heal and NFS servers
                        # for each node
                        d, err = xml_parse.run_gluster_command(
                            'gluster volume quota %s list --xml' % (vol_name))
                        if err:
                            # print d
                            # print d['op_status']['op_errstr']
                            if (not d) or (('op_status' in d) and d['op_status'] and ('op_errstr' in d['op_status']) and ('No quota configured' in d['op_status']['op_errstr'])):
                                no_quotas_set = True
                            else:
                                raise Exception(err)
                        # print no_quotas_set
                        if not no_quotas_set:
                            return_dict, err = xml_parse.get_vol_quotas(
                                d['root'])
                            if err:
                                raise Exception(err)
    except Exception, e:
        return None, 'Error getting volume quota information: %s' % str(e)
    else:
        return return_dict, None


def get_complete_volume_info(vol_name, vol_info_dict=None):
    """Returns all the information and status about a specific volume 

    The return value is a dict which has all the info and status of the volume.
    This should be called carefully as it results in multiple underlying gluster calls.

    vol_name - The name of the volume for which info is needed.
    vol_info_dict - The basic volume info dict. If not passed, we generate it.
    """
    return_dict = {}
    try:
        if not vol_info_dict:
            vol_info_dict, err = get_basic_volume_info(vol_name)
            if err:
                raise Exception(err)

        return_dict = vol_info_dict

        vol_status_dict = {}
        if vol_info_dict['status'] == 1:
            vol_status_dict, err = get_volume_status(
                vol_info_dict['name'], vol_info_dict)
            if err:
                raise Exception(err)

        if vol_info_dict['status'] == 1:
            if vol_status_dict:
                # Add the status and usage info
                return_dict.update(vol_status_dict)
            vol_process_dict, err = get_volume_process_status(
                vol_name, vol_info_dict, vol_status_dict)
            if err:
                raise Exception(err)

            return_dict['processes_ok'] = vol_process_dict['processes_ok']

            for br in return_dict['brick_status']:
                if br in vol_process_dict['brick_status']:
                    return_dict['brick_status'][br].update(
                        vol_process_dict['brick_status'][br])

        quotas, err = get_volume_quota(vol_name, vol_info_dict)
        if err:
            raise Exception(err)
        return_dict['quotas'] = quotas

    except Exception, e:
        return None, 'Error getting complete volume information : %s' % str(e)
    else:
        return return_dict, None


def get_complete_volume_info_all():
    """Returns all the information and status about all the volumes except the integralview admin volume

    This should be called carefully as it results in multiple underlying gluster calls.

    The return value is a list or dicts where each dict has all the info and status of all volumes.
    """

    return_list = []
    try:
        vl, err = get_basic_volume_info_all()
        if err:
            raise Exception(err)
        # print 'vl is', vl

        if vl:
            for vol_info_dict in vl:

                rd, err = get_complete_volume_info(
                    vol_info_dict['name'], vol_info_dict)
                if err:
                    raise Exception(err)

                return_list.append(rd)

    except Exception, e:
        return None, 'Error getting complete volume information for all volumes: %s' % str(e)
    else:
        return return_list, None


def volume_exists(vil, vol_name):
    """Given a volume info list and a volume name, determine if a volume of that name already exists.

    Returns True if it exists and False if not or if an error occurred
    vil -- A list of dicts of currently existing volumes if already generated. If None, then we generate the list here.
    vol_name -- The name of the volume that we need to check on.
    """

    exists = False
    try:
        if not vil:
            vil, err = get_basic_volume_info_all()
            if err:
                raise Exception(err)
        if vil:
            for v in vil:
                if v["name"] == vol_name:
                    exists = True
    except Exception, e:
        return False, 'Error checking for volume existance : %s' % str(e)
    else:
        return exists, None


def get_brick_hostname_list(vol_info_dict):
    """Given a volume info dict, return all the hostnames on which the bricks reside.

    Returns a list of the hostnames on which the volume bricks reside.
    vol_info_dict -- The volume info dict of required volume.
    """

    l = []
    try:
        if not vol_info_dict:
            raise Exception('Required parameter not passed')
        if 'bricks' in vol_info_dict:
            for brick in vol_info_dict["bricks"]:
                for ib in brick:
                    h, b = ib.split(':')
                    if h and (h not in l):
                        l.append(h)
    except Exception, e:
        return None, 'Error getting volume brick hostnames: %s' % str(e)
    else:
        return l, None


def get_volumes_on_node(hostname, vil):
    """Returns a list of volume names on a node for display

    Returns a list of volume dicts of volumes that have a brick on that hostname.
    vil -- A list of vol_info_dicts of currently existing volumes if already generated. If None, then we generate the list here.
    hostname -- The hostname to check on..
    """
    # Returns a list of volume names on a node for display

    vol_list = []
    try:
        if not hostname:
            raise Exception('No GRIDCell name passed')

        if not vil:
            vil, err = get_basic_volume_info_all()
            if err:
                raise Exception(err)

        if vil:
            vol_list = []
            for vol_info_dict in vil:
                bl, err = get_brick_hostname_list(vol_info_dict)
                if err:
                    raise Exception(err)
                if bl and hostname in bl:
                    vol_list.append(vol_info_dict["name"])
    except Exception, e:
        return None, 'Error getting volumes on GRIDCell : %s' % str(e)
    else:
        return vol_list, None


def get_snapshots(vol_name):
    """Get all the created snapshots for the specified volume name.

    Returns a list of all the snapshots if any.
    vol_name -- The name of the volume that we need to check on.
    """

    l = None
    try:
        cmd = 'gluster snapshot info volume %s  --xml' % vol_name
        d, err = xml_parse.run_gluster_command(cmd)
        if err:
            raise Exception(err)
        if d:
            if d["op_status"]["op_ret"] == 0:
                l, err = xml_parse.get_snapshots(d["root"])
                if err:
                    raise Exception(err)
    except Exception, e:
        return None, 'Error getting volume snapshots: %s' % str(e)
    else:
        return l, None


def set_volume_options(cd):
    """Given a dict with the volume name and all the options that need to be set on that volume, this function will do the needful..

    Returns a list of results from each option setting operation.
    cd -- A dict with the volume name and all the options that needs to be set.
    """

    try:
        vol_name = cd["vol_name"]
        auth_allow = cd["auth_allow"]
        auth_reject = cd["auth_reject"]
        if "nfs_disable" in cd:
            nfs_disable = cd["nfs_disable"]
        else:
            nfs_disable = False
        if "enable_worm" in cd:
            enable_worm = cd["enable_worm"]
        else:
            enable_worm = False
        readonly = cd["readonly"]
        nfs_volume_access = cd["nfs_volume_access"]

        vol_info_dict, err = get_basic_volume_info(vol_name)
        if err:
            raise Exception(err)

        # set defaults first
        _auth_allow = "*"
        _auth_reject = "NONE"
        _readonly = "off"
        _nfs_disable = False
        _enable_worm = False
        _nfs_volume_access = "read-write"

        if "options" in vol_info_dict:
            for option in vol_info_dict["options"]:
                if option["name"] == "auth.allow":
                    _auth_allow = option["value"]
                if option["name"] == "auth.reject":
                    _auth_reject = option["value"]
                if option["name"] == "nfs.disable":
                    if option["value"].lower() == "off":
                        _nfs_disable = False
                    else:
                        _nfs_disable = True
                if option["name"] == "nfs.volume-access":
                    _nfs_volume_access = option["value"]
                if option["name"] == "features.read-only":
                    _readonly = option["value"]
                if option["name"] == "features.worm":
                    if option["value"].lower() == "enable":
                        _enable_worm = True
                    else:
                        _enable_worm = False

        # Now, for each option that has changed, set the parameter
        ret_list = []

        if _auth_allow != auth_allow:
            d, err = _set_volume_option(vol_name, "auth.allow", auth_allow)
            if err:
                raise Exception(err)
            d['audit_str'] = "Setting option for permitted access IP addresses for %s to \'%s\'" % (
                vol_name, auth_allow)
            ret_list.append(d)

        if _auth_reject != auth_reject:
            d, err = _set_volume_option(vol_name, "auth.reject", auth_reject)
            if err:
                raise Exception(err)
            d['audit_str'] = "Setting option for denied access IP addresses for %s to \'%s\'" % (
                vol_name, auth_reject)
            ret_list.append(d)

        if _readonly != readonly:
            d, err = _set_volume_option(
                vol_name, "features.read-only", readonly)
            if err:
                raise Exception(err)
            d['audit_str'] = "Setting readonly mount access(for all access methods) for %s to \'%s\'" % (
                vol_name, readonly)
            ret_list.append(d)

        if readonly == "off":

            # All the rest applies only if volume access is read-write
            if _nfs_disable != nfs_disable:
                if nfs_disable:
                    p = "on"
                else:
                    p = "off"
                d, err = _set_volume_option(vol_name, "nfs.disable", p)
                if err:
                    raise Exception(err)
                d['audit_str'] = "Setting NFS disable for %s to \'%s\'" % (
                    vol_name, p)
                ret_list.append(d)

            if not nfs_disable:
                # print "in"
                if nfs_volume_access and _nfs_volume_access != nfs_volume_access:
                    d, err = _set_volume_option(
                        vol_name, "nfs.volume-access", nfs_volume_access)
                    if err:
                        raise Exception(err)
                    d['audit_str'] = "Setting NFS access type for %s to \'%s\'" % (
                        vol_name, nfs_volume_access)
                    ret_list.append(d)

            if _enable_worm != enable_worm:
                if enable_worm:
                    p = "enable"
                else:
                    p = "disable"
                d, err = _set_volume_option(vol_name, "features.worm", p)
                if err:
                    raise Exception(err)
                d['audit_str'] = "Setting feature WORM for %s to \'%s\'" % (
                    vol_name, p)
                ret_list.append(d)

    except Exception, e:
        return None, 'Error setting volume options: %s' % str(e)
    else:
        return ret_list, None


def _set_volume_option(vol_name, option, value):
    """Given a volume name, an option name and an option value, it will do the actual work of setting that option.

    Returns the gluster return codes after executing that operation.
    vol_name -- The name of the volume that we need to operate on.
    option -- The option that needs to be set.
    value -- The value for the selected option that needs to be set.
    """
    d = None
    try:
        cmd = 'gluster volume set %s %s %s --xml' % (vol_name, option, value)
        d, err = xml_parse.run_gluster_command(cmd)
        if err:
            raise Exception(err)
    except Exception, e:
        return None, 'Error setting specific volume option: %s' % str(e)
    else:
        return d, None


def build_create_or_expand_volume_command(cmd, si, anl, vol_type, ondisk_storage, repl_count, vol_name):
    """Determine on which nodes and bricks the volume expansion/creation should happen onto and create the appropriate command to make it happen.

    Returns a dict with the command, the node list, the dataset list and a count that will be used by the caller to create the appropriate datasets, etc..

    cmd - The initial part of the command that is populated elsewhere - basically says create or expand
    si - The system info dict that has all the information about the current state of the grid.
    anl - The allowable node list - basically which nodes can the expansion/creation happen on.
    vol_type - The type of volume that is being expanded or created. Will determine brick placement.
    ondisk_storage - Used to create the brick names. Tells us if it is to be placed on normal/compressed/deduplicated datasets.
    repl_count - The replication count for replicated volumes.
    vol_name -- The name of the volume that we need to operate on.
    """

    return_dict = {}
    try:
        node_list = []

        if (not si) or (not vol_type) or (not ondisk_storage) or (not vol_name):
            raise Exception('Required parameter not passed')

        if (vol_type.lower() != 'distributed') and (not repl_count):
            raise Exception('Invalid replication count')

        if not anl:
            raise Exception(
                'No available GRIDCells to expand/create the volume.')

        num_nodes = len(anl)

        for n in anl:
            if "pools" not in si[n]:
                raise Exception(
                    "There are no storage pools on some GRIDCells so volume creation cannot proceeded.")

        num_pools = len(si[anl[0]]["pools"])
        dataset_list = []

        count = 0
        if vol_type.lower() == "distributed":
            for hostname in anl:
                for i, pool in enumerate(si[hostname]["pools"]):
                    node_list.append(["%s %s" % (hostname, pool["pool_name"])])
                    brick = "%s:/%s/%s/%s" % (hostname,
                                              pool["pool_name"], ondisk_storage, vol_name)
                    dataset_name = "%s/%s/%s" % (pool["pool_name"],
                                                 ondisk_storage, vol_name)
                    dataset_list.append({hostname: dataset_name})
                    count += 1
                    cmd = cmd + brick + " "
        else:
            # Replicated
            if num_nodes < repl_count:
                raise Exception(
                    "Insufficient number of GRIDCells to make the replica pairs")
            pool_num = 1
            first_node = 1
            second_node = first_node + 1
            init_node = 1

            if num_nodes % 2 == 0:
                # Even number of nodes
                while True:
                    pool_num = 1
                    nl = []
                    while pool_num <= num_pools:
                        node_name = anl[first_node - 1]
                        node = si[anl[first_node - 1]]
                        nl = []
                        a = "GRIDCells %s %s" % (
                            node_name, node["pools"][pool_num - 1]["pool_name"])
                        # print a
                        nl.append(a)
                        brick = "%s:/%s/%s/%s" % (
                            node_name, node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                        cmd = cmd + brick + " "
                        dataset_name = "%s/%s/%s" % (
                            node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                        dataset_list.append({node_name: dataset_name})
                        count += 1

                        node_name = anl[second_node - 1]
                        node = si[anl[second_node - 1]]
                        brick = "%s:/%s/%s/%s" % (
                            node_name, node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                        cmd = cmd + brick + " "
                        dataset_name = "%s/%s/%s" % (
                            node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                        dataset_list.append({node_name: dataset_name})
                        a = "GRIDCells %s pool %s" % (
                            node_name, node["pools"][pool_num - 1]["pool_name"])
                        # print a
                        nl.append(a)
                        count += 1
                        pool_num += 1

                        print "------------"

                    node_list.append(nl)

                    first_node = 1 if first_node == num_nodes else first_node + 2
                    second_node = 1 if second_node == num_nodes else second_node + 2

                    if second_node == 1:
                        break
            else:
                # Odd number of nodes
                tl = []
                while True:
                    nl = []
                    node_name = anl[first_node - 1]
                    node = si[anl[first_node - 1]]
                    brick = "%s:/%s/%s/%s" % (
                        node_name, node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                    a = "GRIDCell %s pool %s" % (
                        node_name, node["pools"][pool_num - 1]["pool_name"])
                    if a in tl:
                        break
                    cmd = cmd + brick + " "
                    dataset_name = "%s/%s/%s" % (
                        node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                    dataset_list.append({node_name: dataset_name})
                    count += 1
                    tl.append(a)
                    # print a

                    nl.append(a)

                    #disk_num = 1 if disk_num == num_disks else disk_num + 1
                    node_name = anl[second_node - 1]
                    node = si[anl[second_node - 1]]
                    brick = "%s:/%s/%s/%s" % (
                        node_name, node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                    cmd = cmd + brick + " "
                    dataset_name = "%s/%s/%s" % (
                        node["pools"][pool_num - 1]["pool_name"], ondisk_storage, vol_name)
                    dataset_list.append({node_name: dataset_name})
                    a = "GRIDCell %s pool %s" % (
                        node_name, node["pools"][pool_num - 1]["pool_name"])
                    # print a
                    count += 1
                    tl.append(a)
                    nl.append(a)
                    node_list.append(nl)
                    pool_num = 1 if pool_num == num_pools else pool_num + 1
                    # print "------------"

                    if second_node + 1 > num_nodes:
                        first_node = second_node
                        second_node = init_node
                    else:
                        first_node = second_node
                        second_node = second_node + 1
        return_dict["cmd"] = cmd
        return_dict["dataset_list"] = dataset_list
        return_dict["count"] = count
        return_dict["node_list"] = node_list

    except Exception, e:
        return None, 'Error building create or expand volume command : %s' % str(e)
    else:
        return return_dict, None


def _get_allowable_node_list(si, vol_name=None):
    """Determine which nodes can be used to expand or create a volume based on the system state.

    Returns a dict with the the allowable node list

    vol_name - If we are checking for an existing volume, then we need its name
    si - The system info dict that has all the information about the current state of the grid.
    """
    anl = []
    try:
        for hostname in si.keys():
            # Volumes can only be placed on nodes that are ok and are part of
            # the storage pool
            if si[hostname]["node_status"] != 0 or si[hostname]["in_cluster"] == False:
                continue
            if vol_name and (vol_name in si[hostname]["volume_list"]):
                continue
            anl.append(hostname)
    except Exception, e:
        return None, 'Error building allowable node list: %s' % str(e)
    else:
        return anl, None


def build_expand_volume_command(vol_info_dict, si):
    """Build a command to expand an existing volume based on its type and the current system state. Uses build_create_or_expand_volume_command to do most of the work.

    Returns a dict with the command, the node list, the dataset list and a count that will be used by the caller to create the appropriate datasets, etc..

    vol_info_dict - The basic vol info dict for the volume that needs to be expanded.
    si - The system info dict that has all the information about the current state of the grid.
    """

    return_dict = None
    try:
        # First get all the node/disk combinations where the volume is not
        # present
        anl = []
        num_nodes = 0

        ondisk_storage = "normal"
        if "compressed" in vol_info_dict['bricks'][0]:
            ondisk_storage = "compressed"
        elif "deduplicated" in vol_info_dict['bricks'][0]:
            ondisk_storage = "deduplicated"

        anl, err = _get_allowable_node_list(si, vol_info_dict['name'])
        if err:
            raise Exception(err)

        cmd = 'gluster volume add-brick %s  ' % vol_info_dict["name"]

        repl_count = 0

        if 'replicate' in vol_info_dict['type'].lower():
            vol_type = "replicated"
            repl_count = int(vol_info_dict["replica_count"])
        else:
            vol_type = "distributed"

        return_dict, err = build_create_or_expand_volume_command(
            cmd, si, anl, vol_type, ondisk_storage, repl_count, vol_info_dict["name"])
        if err:
            raise Exception(err)

        if "cmd" in return_dict:
            return_dict["cmd"] = return_dict["cmd"] + " force --xml"
    except Exception, e:
        return None, 'Error building expand volume command: %s' % str(e)
    else:
        return return_dict, None


def build_create_volume_command(vol_name, vol_type, ondisk_storage, repl_count, transport, si):
    """Build a command to create a new volume based on the required type and the current system state. Uses build_create_or_expand_volume_command to do most of the work.

    Returns a dict with the command, the node list, the dataset list and a count that will be used by the caller to create the appropriate datasets, etc..

    vol_info_dict - The basic vol info dict for the volume that needs to be expanded.
    si - The system info dict that has all the information about the current state of the grid.
    """

    return_dict = None
    try:
        # Now build the command based on parameters provided
        cmd = 'gluster volume create %s ' % vol_name
        if 'replicate' in vol_type.lower():
            cmd = cmd + ' replica %d ' % repl_count
            vol_type = "replicated"
        cmd = cmd + ' transport %s ' % transport

        anl, err = _get_allowable_node_list(si)
        if err:
            raise Exception(err)

        d = {}
        if not anl:
            raise Exception(
                "No appropriate storage available to create the volume")

        d, err = build_create_or_expand_volume_command(
            cmd, si, anl, vol_type, ondisk_storage, repl_count, vol_name)
        if err:
            raise Exception(err)
        if "cmd" in d:
            d["cmd"] = d["cmd"] + " --xml"
    except Exception, e:
        return None, 'Error building create volume command: %s' % str(e)
    else:
        return d, None


def volume_stop_or_start(vol_name, op):
    """Start or stop a gluster volume.

    Returns a dict with the result and the xml root.

    vol_name - The name of the volume
    op - Either 'start' or 'stop'
    """

    return_dict = None
    try:
        cmd = 'gluster --mode=script volume %s %s --xml' % (op, vol_name)
        return_dict, err = xml_parse.run_gluster_command(cmd)
        if err:
            raise Exception(err)
    except Exception, e:
        return None, 'Error stopping/starting volume : %s' % str(e)
    else:
        return return_dict, None


def restart_all_volumes():
    try:
        vols, err = get_basic_volume_info_all()
        if err:
            raise Exception(err)
        if vols:
            for vol in vols:
                print 'Stopping volume ', vol['name']

                ret, err = volume_stop_or_start(vol['name'], 'stop')
                # Dont check the error for stop in case its already stopped.
                print 'Starting volume ', vol['name']
                ret, err = volume_stop_or_start(vol['name'], 'start')
                if err:
                    raise Exception(err)
    except Exception, e:
        return False, 'Error restarting all volumes : %s' % str(e)
    else:
        return True, None


def main():

    #vl = get_volume_list()
    # print "Volume list :"
    # print vl
    # get_volume_status("test")
    # print get_volume_info(None, 'replvol')[0]['bricks']
    # print get_volume_info_all()[0][0]['bricks']
    # print get_components('host:/frzpool/normal/vol1')
    # print get_basic_volume_info_all()
    print restart_all_volumes()
    pass


if __name__ == "__main__":
    main()


'''
def get_removable_sled_list(scl, vil):
  #Return a list of sleds that can be chosen to be removed - a sled can be removed if both its nodes are in the cluster and no volumes have bricks on either node
  i = 0
  sl = []
  while i < len(scl):
    free_sled = True
    if len(get_volumes_on_node(scl[i], vil))>0 or len(get_volumes_on_node(scl[i+1], vil))>0:
      free_sled = False
    if free_sled and ((scl[i]["in_cluster"]) or (scl[i+1]["in_cluster"])):
      sl.append((i/2) +1)
    i = i+2
  return sl
def get_expandable_node_list(si, vol, replicated, replica_count):

  # If distributed then return all nodes where volume is not present
  # If replicated, then return sets of nodes where the volume is not present

  d = {}
  nl = []
  dl = []
  if replicated:
    pass
  else:
    for hostname in si.keys():
      if si[hostname]["node_status"] != 0:
        continue
      if vol["name"] in si[hostname][volume_list]:
        continue
      nl.append(hostname)
  d["node_list"]
  return nl
  
def get_expandable_lists(scl, vol, count):
  #Returns a list of nodes and sleds that qualify for expansion of a volume

  if not scl:
    scl, err = system_info.load_system_config()
    if err:
      raise Exception(err)

  node_list = []
  sled_list = []
  for i in xrange(0, len(scl), 2):
    if not scl[i]["in_cluster"]:
      continue
    part_of_vol = False
    for j in xrange(2):
      for brick in vol["bricks"]:
        if "hostname" in scl[i+j] and brick["host"] == scl[i+j]["hostname"]:
          part_of_vol = True
          break
      if part_of_vol:
        break
    if not part_of_vol:
      sled_list.append(i)

  # Randomly try and use the sleds from either direction to increase uniformity. This is because the spare sled may leave one sled out
  toss = random.randint(0,1)
  if toss == 0:
    sled_list = sled_list[::-1]

  # Can only expand if there are a multiple of count sleds. Otherwise do not allow
  expandable = True
  if len(sled_list) == 0:
    expandable = False

  if vol["type"] == "Replicate":
    if len(sled_list) == 0 or len(sled_list)/count == 0:
      expandable = False


  if not expandable:
    return None

  if vol["type"] == "Distribute":
    for i in xrange(len(sled_list)):
      if "hostname" in scl[sled_list[i]] and  "hostname" in scl[sled_list[i]+1] :
        node_list.append(scl[sled_list[i]]["hostname"])
        node_list.append(scl[sled_list[i]+1]["hostname"])
  else:
    base = 1
    end = base + count -1
    while end <= len(sled_list) :
      node = random.randint(0,1)
      for i in xrange(count):
        if "hostname" in scl[sled_list[base-1+i]+node]:
          b = scl[sled_list[base-1+i]+node]["hostname"]
          node_list.append(b)
      base = base + count
      end = end + count

  d = {}
  d["node_list"] = node_list
  d["sled_list"] = sled_list
  return d

def get_replacement_sled_info(scl, vil):

  #Fill src_sled_list and dest_sled_list
  i = 0
  src_sled_list = []
  dest_sled_list = []
  while i < len(scl):
    vols_in_sled = False
    if (not scl[i]["active"]) or (not scl[i+1]["active"]) or (not scl[i]["in_cluster"]) or (not scl[i+1]["in_cluster"]):
      i = i+2
      continue
    for vol in vil:
      for brick in vol["bricks"]:
        if "hostname" in scl[i] and  "hostname" in scl[i+1] :
          if brick["host"] in [scl[i]["hostname"], scl[i+1]["hostname"]]:
            vols_in_sled = True
            break
      if vols_in_sled:
        break
    if not vols_in_sled:
      dest_sled_list.append((i/2) + 1)
    else:
      src_sled_list.append((i/2) + 1)
    i = i+2
  d = {}
  d["src_sled_list"] = src_sled_list
  d["dest_sled_list"] = dest_sled_list
  return d
'''
'''
  Code from _get_volume_list() before refactoring
    #Refactored code below was put in in order to minimize the number of gluster calls but fails if a node is now so reverting to the old code for now
    if vl:

      #First get all the info from the status detail...
      d, err = xml_parse.run_gluster_command("/usr/sbin/gluster volume status all detail --xml", "%s/b.xml"%devel_files_path, "Getting volume info")
      if err:
        raise Exception(err)
      if not d or  "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
        err = "Error getting the volume infomation : "
        if d:
          if "error_list" in d:
            err += " ".join(d["error_list"])
          if "op_status" in d and "op_errstr" in d["op_status"]:
            if d["op_status"]["op_errstr"]:
              err += d["op_status"]["op_errstr"]
        raise Exception(err)
      vsda_all_tree = d["tree"]
      vsda_tree_heads, err = xml_parse.get_volume_status_tree_heads(vsda_all_tree)
      if err:
        raise Exception(err)
      for vsda_tree in vsda_tree_heads:
        #print vsda_tree
        _vol_name, err = xml_parse.get_subnode_text(vsda_tree, "volName")
        if err:
          raise Exception('Error reading volume name from volume status detail XML')
        if _vol_name == admin_vol_name:
          continue
        #print '_vol name is ', _vol_name
        for vol in vl:
          #print '---', vol['name']
          if vol['name'] == _vol_name:
            break
        #print 'vol name is ', vol['name']
        #print 'vol bricks are ', vol['bricks']
        if vol["status"] != 1:
          continue      
        #The following call signature has changed so no longer valid!!            
        tup, err = xml_parse.get_brick_status(vsda_tree, get_root = False)
        if err:
          raise Exception(err)
        if tup:
          (bd, num_up, num_down) = tup
        else:
          raise Exception('Error retrieving brick status')
        #print 'bd ', bd
        vol["brick_status"] = bd

        size_total = 0
        size_free = 0
        if vol["replica_count"] > 1:
          replica_set_status = []
          for br in vol["bricks"] :
            counted = False
            num_down = 0
            num_up = 0
            for  b in br:
              #print 'b is ', b
              #print 'bd is ', bd
              if b not in bd:
                #Could happen if a brick is down
                continue
              if bd[b]["status"] == 1:
                num_up += 1
                if not counted:
                  #Found one up replica so only consider size info for this. If all down then it does not count
                  size_free += bd[b]["size_free"]
                  size_total += bd[b]["size_total"]
                  counter = True
              else:
                num_down += 1
              replica_set_status.append(num_down)
          #print replica_set_status
          if num_up == 0:
            vol["data_access_status"] = "Volume down. No data accessible!"
            vol["data_access_status_code"] = -1
          else:
            if max(replica_set_status) == vol["replica_count"]:
              vol["data_access_status"] = "Some data inaccessible"
              vol["data_access_status_code"] = -1
            elif max(replica_set_status) > 0:
              num_more = vol["replica_count"] - max(replica_set_status)
              vol["data_access_status"] = "Data accessible but vulnerable. Loss of %d more data locations will cause data loss"%num_more
              vol["data_access_status_code"] = 1
            else:
              vol["data_access_status"] = "Healthy"
              vol["data_access_status_code"] = 0
        else:
          #Distributed so count em all
          num_down = 0
          for b in bd.keys():
            if bd[b]["status"] == 1:
              num_up += 1
              size_free += bd[b]["size_free"]
              size_total += bd[b]["size_total"]
            else:
              num_down += 1
          if num_down > 0:
            vol["data_access_status"] = "Some data inaccessible"
            vol["data_access_status_code"] = 1
          else:
            vol["data_access_status"] = "Healthy"
            vol["data_access_status_code"] = 0
        vol["size_total"] = filesize.get_naturalsize(size_total, binary=True)
        vol["size_used"] = filesize.get_naturalsize(size_total-size_free, binary=True)
        vol["size_free"] = filesize.get_naturalsize(size_free, binary=True)
        #print size_total-size_free
        #print (size_total-size_free)/float(size_total)
        if size_total > 0:
          vol["size_used_percent"] = int(((size_total-size_free)/float(size_total)) * 100)
        else:
          vol["size_used_percent"] = -1
        #print vol["size_used_percent"]

      # Now get the status of the self heal and NFS servers for each node
      d, err = xml_parse.run_gluster_command("/usr/sbin/gluster volume status all --xml", "%s/volume_status.xml"%devel_files_path, "Getting volume status")
      if err:
        raise Exception(err)
      if not d or  "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
        err = "Error getting the volume status : "
        if d:
          if "error_list" in d:
            err += " ".join(d["error_list"])
          if "op_status" in d and "op_errstr" in d["op_status"]:
            if d["op_status"]["op_errstr"]:
              err += d["op_status"]["op_errstr"]
        raise Exception(err)
      vsd_all_tree = d["tree"]
      vsd_tree_heads, err = xml_parse.get_volume_status_tree_heads(vsd_all_tree)
      if err:
        raise Exception(err)
      for vsd_tree in vsd_tree_heads:
        _vol_name, err = xml_parse.get_subnode_text(vsd_tree, "volName")
        if err:
          raise Exception('Error reading volume name from volume status detail XML')
        if _vol_name == admin_vol_name:
          continue
        for vol in vl:
          if vol['name'] == _vol_name:
            break
        if vol["status"] != 1:
          continue      
        vol, err = xml_parse.get_volume_process_status(vsd_tree, vol, get_root=False)
        if err:
          raise Exception(err)

'''
'''
def _get_volume_info_all():
  """Returns all the information about all the volumes except the integralview admin volume

  The return value is a list or dicts where each dict has all the info of one volume
  """

  vl = None
  try:
    d, err = xml_parse.run_gluster_command('/usr/sbin/gluster volume info all --xml')
    if err:
      raise Exception(err)

    if not d or  "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
      err = "Error getting volume infomation : "
      if d:
        if "error_list" in d:
          err += " ".join(d["error_list"])
        if "op_status" in d and "op_errstr" in d["op_status"]:
          if d["op_status"]["op_errstr"]:
            err += d["op_status"]["op_errstr"]
      raise Exception(err)

    via_tree = d["tree"]
    admin_vol_name, err = config.get_admin_vol_name()
    if err:
      raise Exception(err)
    vl, err = xml_parse.get_volume_info(via_tree, admin_vol_name)
    if err:
      raise Exception(err)
    #print 'vl is', vl


    if vl:
      for vol in vl:
        if vol["status"] != 1:
          continue      
        d, err = xml_parse.run_gluster_command("/usr/sbin/gluster volume status %s detail --xml"%vol["name"])
        if err:
          raise Exception(err)
        if not d or  "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
          err = "Error getting the volume status details: "
          if d:
            if "error_list" in d:
              err += " ".join(d["error_list"])
            if "op_status" in d and "op_errstr" in d["op_status"]:
              if d["op_status"]["op_errstr"]:
                err += d["op_status"]["op_errstr"]
          raise Exception(err)
        vsd_tree = d["tree"]
        tup, err = xml_parse.get_brick_status(vsd_tree)
        if err:
          raise Exception(err)
        if tup:
          (bd, num_up, num_down) = tup
        else:
          raise Exception('Error retrieving brick status')
        vol["brick_status"] = bd

        size_total = 0
        size_free = 0
        if vol["replica_count"] > 1:
          replica_set_status = []
          for br in vol["bricks"] :
            counted = False
            num_down = 0
            num_up = 0
            for  b in br:
              if b not in bd:
                #Could happen if a brick is down
                continue
              if bd[b]["status"] == 1:
                num_up += 1
                if not counted:
                  #Found one up replica so only consider size info for this. If all down then it does not count
                  size_free += bd[b]["size_free"]
                  size_total += bd[b]["size_total"]
                  counter = True
              else:
                num_down += 1
              replica_set_status.append(num_down)
          #print replica_set_status
          if num_up == 0:
            vol["data_access_status"] = "Volume down. No data accessible!"
            vol["data_access_status_code"] = -1
          else:
            if max(replica_set_status) == vol["replica_count"]:
              vol["data_access_status"] = "Some data inaccessible"
              vol["data_access_status_code"] = -1
            elif max(replica_set_status) > 0:
              num_more = vol["replica_count"] - max(replica_set_status)
              vol["data_access_status"] = "Data accessible but vulnerable. Loss of %d more data locations will cause data loss"%num_more
              vol["data_access_status_code"] = 1
            else:
              vol["data_access_status"] = "Healthy"
              vol["data_access_status_code"] = 0
        else:
          #Distributed so count em all
          num_down = 0
          for b in bd.keys():
            if bd[b]["status"] == 1:
              num_up += 1
              size_free += bd[b]["size_free"]
              size_total += bd[b]["size_total"]
            else:
              num_down += 1
          if num_down > 0:
            vol["data_access_status"] = "Some data inaccessible"
            vol["data_access_status_code"] = 1
          else:
            vol["data_access_status"] = "Healthy"
            vol["data_access_status_code"] = 0
        vol["size_total"] = filesize.get_naturalsize(size_total, binary=True)
        vol["size_used"] = filesize.get_naturalsize(size_total-size_free, binary=True)
        vol["size_free"] = filesize.get_naturalsize(size_free, binary=True)
        #print size_total-size_free
        #print (size_total-size_free)/float(size_total)
        if size_total > 0:
          vol["size_used_percent"] = int(((size_total-size_free)/float(size_total)) * 100)
        else:
          vol["size_used_percent"] = -1
        #print vol["size_used_percent"]


        # Now get the status of the self heal and NFS servers for each node
        d, err = xml_parse.run_gluster_command("/usr/sbin/gluster volume status %s --xml"%vol["name"])
        if err:
          raise Exception(err)
        if not d or  "op_status" not in d or ("op_status" in d and d["op_status"]["op_ret"] != 0):
          err = "Error getting the volume status : "
          if d:
            if "error_list" in d:
              err += " ".join(d["error_list"])
            if "op_status" in d and "op_errstr" in d["op_status"]:
              if d["op_status"]["op_errstr"]:
                err += d["op_status"]["op_errstr"]
          raise Exception(err)
        vs_tree = d["tree"]
        vol, err = xml_parse.get_volume_process_status(vs_tree, vol)
        if err:
          raise Exception(err)

  except Exception, e:
    return None, 'Error getting complete volume list : %s'%str(e)
  else:
    return vl, None

def get_volume_info(vil, vol_name):
  """Given a volume info list and a volume name, return the dict corresponding to that volume name

  Returns the dict if the volume exists, else None
  vil -- A list of dicts of currently existing volumes if already generated. If None, then we generate the list here.
  vol_name -- The name of the volume that we need to check on.
  """

  vol = None
  try:
    if not vil:
      vil, err = get_volume_info_all()
      if err:
        raise Exception(err)
    vol = None
    if vil:
      for v in vil:
        if v["name"] == vol_name:
          vol = v
          break
  except Exception, e:
    return None, 'Error getting volume info : %s'%str(e)
  else:
    return vol, None
'''


'''
    if vol_type.lower() == "distributed":
      if raid:
        #One pool per NODE so apportion accordingly
        for hostname in anl:
          node_list.append(["%s %s"%(hostname, si[hostname]["raid_pool_name"])])
          brick = "%s:/%s/%s/%s"%(hostname, si[hostname]["raid_pool_name"], ondisk_storage, vol_name)
          count += 1
          cmd = cmd + brick + " "
      else:
        #One pool per DISK so apportion accordingly
        for hostname in anl:
          for i, disk in enumerate(si[hostname]["disks"]):
            node_list.append(["%s %s"%(hostname, disk["pool"])])
            brick = "%s:/%s/%s/%s"%(hostname, disk["pool"], ondisk_storage, vol_name)
            count += 1
            cmd = cmd + brick + " "
    else:
      #Replicated volume

      if num_nodes < repl_count:
        d["error"] = "Insufficient number of GRIDCells to make the replica pairs"
        return d

      if raid:
        #One pool per NODE so apportion accordingly
        if num_nodes % 2 != 0:
          d["error"] = "Insufficient number of nodes to make the replica pairs. Nodes can only be added in pairs."
          return d
        disk_num = 1
        first_node = 1
        second_node = first_node + 1
        init_node = 1

        while True:
          nl = []
          node_name = anl[first_node-1]
          node = si[anl[first_node-1]]
          nl = []
          a = "node %s %s"%(node_name, node["raid_pool_name"])
          print a
          nl.append(a)
          brick = "%s:/%s/%s/%s"%(node_name, node["raid_pool_name"], ondisk_storage, vol_name)
          cmd = cmd + brick + " "
          count += 1

          node_name = anl[second_node-1]
          node = si[anl[second_node-1]]
          brick = "%s:/%s/%s/%s"%(node_name, node["rai_pool_name"], ondisk_storage, vol_name)
          cmd = cmd + brick + " "
          brick = "%s:/%s/%s/%s"%(node_name, node["raid_pool_name"], ondisk_storage, vol_name)
          print a
          nl.append(a)
          count += 1

          node_list.append(nl)

          first_node = 1 if first_node == num_nodes else first_node + 2
          second_node = 1 if second_node == num_nodes else second_node + 2

          if second_node == 1:
            break
      else:
        #One pool per DISK so apportion accordingly

        disk_num = 1
        first_node = 1
        second_node = first_node + 1
        init_node = 1

        if num_nodes %2 == 0:
          while True:
            disk_num = 1
            nl = []
            while disk_num <= num_disks:
              node_name = anl[first_node-1]
              node = si[anl[first_node-1]]
              nl = []
              a = "node %s %s"%(node_name, node["disk"][disk_num-1]["pool"])
              print a
              nl.append(a)
              brick = "%s:/%s/%s/%s"%(node_name, node["disks"][disk_num-1]["pool"], ondisk_storage, vol_name)
              cmd = cmd + brick + " "
              count += 1

              node_name = anl[second_node-1]
              node = si[anl[second_node-1]]
              brick = "%s:/%s/%s/%s"%(node_name, node["disks"][disk_num-1]["pool"], ondisk_storage, vol_name)
              cmd = cmd + brick + " "
              a = "node %s disk %s"%(node_name, node["disks"][disk_num-1]["pool"])
              print a
              nl.append(a)
              count += 1
              disk_num += 1

              print "------------"

            node_list.append(nl)

            first_node = 1 if first_node == num_nodes else first_node + 2
            second_node = 1 if second_node == num_nodes else second_node + 2

            if second_node == 1:
              break
        else:
          tl = []
          while True:
            nl = []
            node_name = anl[first_node-1]
            node = si[anl[first_node-1]]
            brick = "%s:/%s/%s/%s"%(node_name, node["disks"][disk_num-1]["pool"], ondisk_storage, vol_name)
            a = "node %s disk %s"%(node_name, node["disks"][disk_num-1]["pool"])
            if a in tl:
              break
            cmd = cmd + brick + " "
            count += 1
            tl.append(a)
            print a

            nl.append(a)

            disk_num = 1 if disk_num == num_disks else disk_num + 1
            node_name = anl[second_node-1]
            node = si[anl[second_node-1]]
            brick = "%s:/%s/%s/%s"%(node_name, node["disks"][disk_num-1]["pool"], ondisk_storage, vol_name)
            cmd = cmd + brick + " "
            a = "node %s disk %s"%(node_name, node["disks"][disk_num-1]["pool"])
            print a
            count += 1
            tl.append(a)
            nl.append(a)
            node_list.append(nl)
            disk_num = 1 if disk_num == num_disks else disk_num + 1
            print "------------"

            if second_node + 1 > num_nodes:
              first_node = second_node
              second_node = init_node
            else:
              first_node = second_node
              second_node = second_node + 1
'''

# vim: tabstop=8 softtabstop=0 expandtab ai shiftwidth=4 smarttab
