Support human-readable biconversion and in volumes
This commit is contained in:
		@@ -1341,7 +1341,7 @@ def ceph_volume():
 | 
			
		||||
)
 | 
			
		||||
def ceph_volume_add(pool, name, size):
 | 
			
		||||
    """
 | 
			
		||||
    Add a new Ceph RBD volume with name NAME and size SIZE [GiB] to pool POOL.
 | 
			
		||||
    Add a new Ceph RBD volume with name NAME and size SIZE [in human units, e.g. 1024M, 20G, etc.] to pool POOL.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    zk_conn = pvc_common.startZKConnection(zk_host)
 | 
			
		||||
 
 | 
			
		||||
@@ -70,17 +70,17 @@ def verifyOSDBlock(zk_conn, node, device):
 | 
			
		||||
            return osd
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
# Format byte sizes in human-readable units
 | 
			
		||||
def format_bytes(databytes):
 | 
			
		||||
# Format byte sizes to/from human-readable units
 | 
			
		||||
unit_matrix = {
 | 
			
		||||
    'B': 1,
 | 
			
		||||
    'K': 1024,
 | 
			
		||||
    'M': 1024*1024,
 | 
			
		||||
    'G': 1024*1024*1024,
 | 
			
		||||
    'T': 1024*1024*1024*1024,
 | 
			
		||||
    'P': 1024*1024*1024*1024*1024
 | 
			
		||||
}
 | 
			
		||||
    databytes_formatted = ''
 | 
			
		||||
    if databytes > 9999:
 | 
			
		||||
def format_bytes_tohuman(databytes):
 | 
			
		||||
    datahuman = ''
 | 
			
		||||
    for unit in sorted(unit_matrix, key=unit_matrix.get, reverse=True):
 | 
			
		||||
        new_bytes = int(math.ceil(databytes / unit_matrix[unit]))
 | 
			
		||||
        # Round up if 5 or more digits
 | 
			
		||||
@@ -89,15 +89,32 @@ def format_bytes(databytes):
 | 
			
		||||
            continue
 | 
			
		||||
        else:
 | 
			
		||||
            # We're at the end, display with this size
 | 
			
		||||
                databytes_formatted = '{}{}'.format(new_bytes, unit)
 | 
			
		||||
    else:
 | 
			
		||||
        databytes_formatted = '{}B'.format(databytes)
 | 
			
		||||
            datahuman = '{}{}'.format(new_bytes, unit)
 | 
			
		||||
 | 
			
		||||
    return databytes_formatted
 | 
			
		||||
    return datahuman
 | 
			
		||||
 | 
			
		||||
def format_bytes_fromhuman(datahuman):
 | 
			
		||||
    databytes = ''
 | 
			
		||||
    for unit in sorted(unit_matrix, key=unit_matrix.get, reverse=True):
 | 
			
		||||
        new_bytes = int(math.ceil(datahuman * unit_matrix[unit]))
 | 
			
		||||
        # Round up if 5 or more digits
 | 
			
		||||
        if new_bytes < 9999:
 | 
			
		||||
            # We can jump down another level
 | 
			
		||||
            continue
 | 
			
		||||
        else:
 | 
			
		||||
            # We're at the end, display with this size
 | 
			
		||||
            databytes = '{}{}'.format(new_bytes, unit)
 | 
			
		||||
 | 
			
		||||
    return databytes
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Cluster search functions
 | 
			
		||||
#
 | 
			
		||||
def getCephStatus():
 | 
			
		||||
    status_data = zkhandler.readdata(zk_conn, '/ceph').rstrip()
 | 
			
		||||
    primary_node = zkhandler.readdata(zk_conn, '/primary_node')
 | 
			
		||||
    return status_data, primary_node
 | 
			
		||||
 | 
			
		||||
def getClusterOSDList(zk_conn):
 | 
			
		||||
    # Get a list of VNIs by listing the children of /networks
 | 
			
		||||
    osd_list = zkhandler.listchildren(zk_conn, '/ceph/osds')
 | 
			
		||||
@@ -109,7 +126,7 @@ def getOSDInformation(zk_conn, osd_id):
 | 
			
		||||
    osd_stats = dict(json.loads(osd_stats_raw))
 | 
			
		||||
    # Deal with the size
 | 
			
		||||
    databytes = osd_stats['kb'] * 1024
 | 
			
		||||
    databytes_formatted = format_bytes(databytes)
 | 
			
		||||
    databytes_formatted = format_bytes_tohuman(databytes)
 | 
			
		||||
    osd_stats['size'] = databytes_formatted
 | 
			
		||||
    return osd_stats
 | 
			
		||||
 | 
			
		||||
@@ -117,6 +134,66 @@ def getCephOSDs(zk_conn):
 | 
			
		||||
    osd_list = zkhandler.listchildren(zk_conn, '/ceph/osds')
 | 
			
		||||
    return osd_list
 | 
			
		||||
 | 
			
		||||
def getClusterPoolList(zk_conn):
 | 
			
		||||
    # Get a list of pools under /ceph/pools
 | 
			
		||||
    pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    return pool_list
 | 
			
		||||
 | 
			
		||||
def getPoolInformation(zk_conn, name):
 | 
			
		||||
    # Parse the stats data
 | 
			
		||||
    pool_stats_raw = zkhandler.readdata(zk_conn, '/ceph/pools/{}/stats'.format(name))
 | 
			
		||||
    pool_stats = dict(json.loads(pool_stats_raw))
 | 
			
		||||
    # Deal with the size issues
 | 
			
		||||
    for datatype in 'size_bytes', 'read_bytes', 'write_bytes':
 | 
			
		||||
        databytes = pool_stats[datatype]
 | 
			
		||||
        databytes_formatted = format_bytes_tohuman(databytes)
 | 
			
		||||
        new_name = datatype.replace('bytes', 'formatted')
 | 
			
		||||
        pool_stats[new_name] = databytes_formatted
 | 
			
		||||
    return pool_stats
 | 
			
		||||
 | 
			
		||||
def getCephPools(zk_conn):
 | 
			
		||||
    pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    return pool_list
 | 
			
		||||
 | 
			
		||||
def getCephVolumes(zk_conn, pool):
 | 
			
		||||
    volume_list = list()
 | 
			
		||||
    if pool == 'all':
 | 
			
		||||
        pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    else:
 | 
			
		||||
        pool_list = [ pool ]
 | 
			
		||||
 | 
			
		||||
    for pool_name in pool_list:
 | 
			
		||||
        for volume_name in zkhandler.listchildren(zk_conn, '/ceph/volumes/{}'.format(pool_name)):
 | 
			
		||||
            volume_list.append('{}/{}'.format(pool_name, volume_name))
 | 
			
		||||
 | 
			
		||||
    return volume_list
 | 
			
		||||
 | 
			
		||||
def getVolumeInformation(zk_conn, pool, name):
 | 
			
		||||
    # Parse the stats data
 | 
			
		||||
    volume_stats_raw = zkhandler.readdata(zk_conn, '/ceph/volumes/{}/{}/stats'.format(pool, name))
 | 
			
		||||
    volume_stats = dict(json.loads(volume_stats_raw))
 | 
			
		||||
    # Format the size to something nicer
 | 
			
		||||
    volume_stats['size'] = format_bytes_tohuman(volume_stats['size'])
 | 
			
		||||
    return volume_stats
 | 
			
		||||
 | 
			
		||||
def getCephSnapshots(zk_conn, pool, volume):
 | 
			
		||||
    snapshot_list = list()
 | 
			
		||||
    volume_list = list()
 | 
			
		||||
 | 
			
		||||
    volume_list = getCephVolumes(zk_conn, pool)
 | 
			
		||||
    if volume != 'all':
 | 
			
		||||
        for volume_entry in volume_list:
 | 
			
		||||
            volume_pool, volume_name = volume_entry.split('/')
 | 
			
		||||
            if volume_name == volume:
 | 
			
		||||
                volume_list = [ '{}/{}'.format(volume_pool, volume_name) ]
 | 
			
		||||
 | 
			
		||||
    for volume_entry in volume_list:
 | 
			
		||||
        for snapshot_name in zkhandler.listchildren(zk_conn, '/ceph/snapshots/{}'.format(volume_entry)):
 | 
			
		||||
            snapshot_list.append('{}@{}'.format(volume_entry, snapshot_name))
 | 
			
		||||
 | 
			
		||||
    return snapshot_list
 | 
			
		||||
 | 
			
		||||
# Formatting functions (for CLI client)
 | 
			
		||||
def formatOSDList(zk_conn, osd_list):
 | 
			
		||||
    osd_list_output = []
 | 
			
		||||
 | 
			
		||||
@@ -374,27 +451,6 @@ Wr: {osd_wrops: <{osd_wrops_length}} \
 | 
			
		||||
    output_string = osd_list_output_header + '\n' + '\n'.join(sorted(osd_list_output))
 | 
			
		||||
    return output_string
 | 
			
		||||
 | 
			
		||||
def getClusterPoolList(zk_conn):
 | 
			
		||||
    # Get a list of pools under /ceph/pools
 | 
			
		||||
    pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    return pool_list
 | 
			
		||||
 | 
			
		||||
def getPoolInformation(zk_conn, name):
 | 
			
		||||
    # Parse the stats data
 | 
			
		||||
    pool_stats_raw = zkhandler.readdata(zk_conn, '/ceph/pools/{}/stats'.format(name))
 | 
			
		||||
    pool_stats = dict(json.loads(pool_stats_raw))
 | 
			
		||||
    # Deal with the size issues
 | 
			
		||||
    for datatype in 'size_bytes', 'read_bytes', 'write_bytes':
 | 
			
		||||
        databytes = pool_stats[datatype]
 | 
			
		||||
        databytes_formatted = format_bytes(databytes)
 | 
			
		||||
        new_name = datatype.replace('bytes', 'formatted')
 | 
			
		||||
        pool_stats[new_name] = databytes_formatted
 | 
			
		||||
    return pool_stats
 | 
			
		||||
 | 
			
		||||
def getCephPools(zk_conn):
 | 
			
		||||
    pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    return pool_list
 | 
			
		||||
 | 
			
		||||
def formatPoolList(zk_conn, pool_list):
 | 
			
		||||
    pool_list_output = []
 | 
			
		||||
 | 
			
		||||
@@ -580,27 +636,6 @@ Wr: {pool_write_ops: <{pool_write_ops_length}} \
 | 
			
		||||
    output_string = pool_list_output_header + '\n' + '\n'.join(sorted(pool_list_output))
 | 
			
		||||
    return output_string
 | 
			
		||||
 | 
			
		||||
def getCephVolumes(zk_conn, pool):
 | 
			
		||||
    volume_list = list()
 | 
			
		||||
    if pool == 'all':
 | 
			
		||||
        pool_list = zkhandler.listchildren(zk_conn, '/ceph/pools')
 | 
			
		||||
    else:
 | 
			
		||||
        pool_list = [ pool ]
 | 
			
		||||
 | 
			
		||||
    for pool_name in pool_list:
 | 
			
		||||
        for volume_name in zkhandler.listchildren(zk_conn, '/ceph/volumes/{}'.format(pool_name)):
 | 
			
		||||
            volume_list.append('{}/{}'.format(pool_name, volume_name))
 | 
			
		||||
 | 
			
		||||
    return volume_list
 | 
			
		||||
 | 
			
		||||
def getVolumeInformation(zk_conn, pool, name):
 | 
			
		||||
    # Parse the stats data
 | 
			
		||||
    volume_stats_raw = zkhandler.readdata(zk_conn, '/ceph/volumes/{}/{}/stats'.format(pool, name))
 | 
			
		||||
    volume_stats = dict(json.loads(volume_stats_raw))
 | 
			
		||||
    # Format the size to something nicer
 | 
			
		||||
    volume_stats['size'] = format_bytes(volume_stats['size'])
 | 
			
		||||
    return volume_stats
 | 
			
		||||
 | 
			
		||||
def formatVolumeList(zk_conn, volume_list):
 | 
			
		||||
    volume_list_output = []
 | 
			
		||||
 | 
			
		||||
@@ -725,23 +760,6 @@ def formatVolumeList(zk_conn, volume_list):
 | 
			
		||||
    output_string = volume_list_output_header + '\n' + '\n'.join(sorted(volume_list_output))
 | 
			
		||||
    return output_string
 | 
			
		||||
 | 
			
		||||
def getCephSnapshots(zk_conn, pool, volume):
 | 
			
		||||
    snapshot_list = list()
 | 
			
		||||
    volume_list = list()
 | 
			
		||||
 | 
			
		||||
    volume_list = getCephVolumes(zk_conn, pool)
 | 
			
		||||
    if volume != 'all':
 | 
			
		||||
        for volume_entry in volume_list:
 | 
			
		||||
            volume_pool, volume_name = volume_entry.split('/')
 | 
			
		||||
            if volume_name == volume:
 | 
			
		||||
                volume_list = [ '{}/{}'.format(volume_pool, volume_name) ]
 | 
			
		||||
 | 
			
		||||
    for volume_entry in volume_list:
 | 
			
		||||
        for snapshot_name in zkhandler.listchildren(zk_conn, '/ceph/snapshots/{}'.format(volume_entry)):
 | 
			
		||||
            snapshot_list.append('{}@{}'.format(volume_entry, snapshot_name))
 | 
			
		||||
 | 
			
		||||
    return snapshot_list
 | 
			
		||||
 | 
			
		||||
def formatSnapshotList(zk_conn, snapshot_list):
 | 
			
		||||
    snapshot_list_output = []
 | 
			
		||||
 | 
			
		||||
@@ -809,9 +827,7 @@ def formatSnapshotList(zk_conn, snapshot_list):
 | 
			
		||||
#
 | 
			
		||||
# Direct functions
 | 
			
		||||
#
 | 
			
		||||
def get_status(zk_conn):
 | 
			
		||||
    status_data = zkhandler.readdata(zk_conn, '/ceph').rstrip()
 | 
			
		||||
    primary_node = zkhandler.readdata(zk_conn, '/primary_node')
 | 
			
		||||
def get_status(zk_conn, status_data, primary_node):
 | 
			
		||||
    click.echo('{bold}Ceph cluster status (primary node {end}{blue}{primary}{end}{bold}){end}\n'.format(bold=ansiprint.bold(), end=ansiprint.end(), blue=ansiprint.blue(), primary=primary_node))
 | 
			
		||||
    click.echo(status_data)
 | 
			
		||||
    click.echo('')
 | 
			
		||||
@@ -1127,7 +1143,8 @@ def get_list_pool(zk_conn, limit):
 | 
			
		||||
 | 
			
		||||
def add_volume(zk_conn, pool, name, size):
 | 
			
		||||
    # Tell the cluster to create a new volume
 | 
			
		||||
    add_volume_string = 'volume_add {},{},{}'.format(pool, name, size) 
 | 
			
		||||
    databytes = format_bytes_fromhuman(size)
 | 
			
		||||
    add_volume_string = 'volume_add {},{},{}'.format(pool, name, databytes)
 | 
			
		||||
    zkhandler.writedata(zk_conn, {'/ceph/cmd': add_volume_string})
 | 
			
		||||
    # Wait 1/2 second for the cluster to get the message and start working
 | 
			
		||||
    time.sleep(0.5)
 | 
			
		||||
@@ -1137,7 +1154,7 @@ def add_volume(zk_conn, pool, name, size):
 | 
			
		||||
        try:
 | 
			
		||||
            result = zkhandler.readdata(zk_conn, '/ceph/cmd').split()[0]
 | 
			
		||||
            if result == 'success-volume_add':
 | 
			
		||||
                message = 'Created new RBD volume {} of size {} GiB on pool {}.'.format(name, size, pool)
 | 
			
		||||
                message = 'Created new RBD volume {} of size {} on pool {}.'.format(name, size, pool)
 | 
			
		||||
                success = True
 | 
			
		||||
            else:
 | 
			
		||||
                message = 'ERROR: Failed to create new volume; check node logs for details.'
 | 
			
		||||
 
 | 
			
		||||
@@ -483,8 +483,7 @@ def add_volume(zk_conn, logger, pool, name, size):
 | 
			
		||||
    logger.out('Creating new RBD volume {} on pool {}'.format(name, pool), state='i')
 | 
			
		||||
    try:
 | 
			
		||||
        # Create the volume
 | 
			
		||||
        sizeMiB = int(size) * 1024
 | 
			
		||||
        retcode, stdout, stderr = common.run_os_command('rbd create --size {} --image-feature layering,exclusive-lock {}/{}'.format(sizeMiB, pool, name))
 | 
			
		||||
        retcode, stdout, stderr = common.run_os_command('rbd create --size {} --image-feature layering,exclusive-lock {}/{}'.format(size, pool, name))
 | 
			
		||||
        if retcode:
 | 
			
		||||
            print('rbd create')
 | 
			
		||||
            print(stdout)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user