Support human-readable biconversion and in volumes
This commit is contained in:
parent
3d3fa1b99f
commit
867ad1fc1b
|
@ -1341,7 +1341,7 @@ def ceph_volume():
|
||||||
)
|
)
|
||||||
def ceph_volume_add(pool, name, size):
|
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)
|
zk_conn = pvc_common.startZKConnection(zk_host)
|
||||||
|
|
|
@ -70,34 +70,51 @@ def verifyOSDBlock(zk_conn, node, device):
|
||||||
return osd
|
return osd
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Format byte sizes in human-readable units
|
# Format byte sizes to/from human-readable units
|
||||||
def format_bytes(databytes):
|
unit_matrix = {
|
||||||
unit_matrix = {
|
'B': 1,
|
||||||
'K': 1024,
|
'K': 1024,
|
||||||
'M': 1024*1024,
|
'M': 1024*1024,
|
||||||
'G': 1024*1024*1024,
|
'G': 1024*1024*1024,
|
||||||
'T': 1024*1024*1024*1024,
|
'T': 1024*1024*1024*1024,
|
||||||
'P': 1024*1024*1024*1024*1024
|
'P': 1024*1024*1024*1024*1024
|
||||||
}
|
}
|
||||||
databytes_formatted = ''
|
def format_bytes_tohuman(databytes):
|
||||||
if databytes > 9999:
|
datahuman = ''
|
||||||
for unit in sorted(unit_matrix, key=unit_matrix.get, reverse=True):
|
for unit in sorted(unit_matrix, key=unit_matrix.get, reverse=True):
|
||||||
new_bytes = int(math.ceil(databytes / unit_matrix[unit]))
|
new_bytes = int(math.ceil(databytes / unit_matrix[unit]))
|
||||||
# Round up if 5 or more digits
|
# Round up if 5 or more digits
|
||||||
if new_bytes > 9999:
|
if new_bytes > 9999:
|
||||||
# We can jump down another level
|
# We can jump down another level
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# We're at the end, display with this size
|
# We're at the end, display with this size
|
||||||
databytes_formatted = '{}{}'.format(new_bytes, unit)
|
datahuman = '{}{}'.format(new_bytes, unit)
|
||||||
else:
|
|
||||||
databytes_formatted = '{}B'.format(databytes)
|
|
||||||
|
|
||||||
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
|
# 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):
|
def getClusterOSDList(zk_conn):
|
||||||
# Get a list of VNIs by listing the children of /networks
|
# Get a list of VNIs by listing the children of /networks
|
||||||
osd_list = zkhandler.listchildren(zk_conn, '/ceph/osds')
|
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))
|
osd_stats = dict(json.loads(osd_stats_raw))
|
||||||
# Deal with the size
|
# Deal with the size
|
||||||
databytes = osd_stats['kb'] * 1024
|
databytes = osd_stats['kb'] * 1024
|
||||||
databytes_formatted = format_bytes(databytes)
|
databytes_formatted = format_bytes_tohuman(databytes)
|
||||||
osd_stats['size'] = databytes_formatted
|
osd_stats['size'] = databytes_formatted
|
||||||
return osd_stats
|
return osd_stats
|
||||||
|
|
||||||
|
@ -117,6 +134,66 @@ def getCephOSDs(zk_conn):
|
||||||
osd_list = zkhandler.listchildren(zk_conn, '/ceph/osds')
|
osd_list = zkhandler.listchildren(zk_conn, '/ceph/osds')
|
||||||
return osd_list
|
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):
|
def formatOSDList(zk_conn, osd_list):
|
||||||
osd_list_output = []
|
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))
|
output_string = osd_list_output_header + '\n' + '\n'.join(sorted(osd_list_output))
|
||||||
return output_string
|
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):
|
def formatPoolList(zk_conn, pool_list):
|
||||||
pool_list_output = []
|
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))
|
output_string = pool_list_output_header + '\n' + '\n'.join(sorted(pool_list_output))
|
||||||
return output_string
|
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):
|
def formatVolumeList(zk_conn, volume_list):
|
||||||
volume_list_output = []
|
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))
|
output_string = volume_list_output_header + '\n' + '\n'.join(sorted(volume_list_output))
|
||||||
return output_string
|
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):
|
def formatSnapshotList(zk_conn, snapshot_list):
|
||||||
snapshot_list_output = []
|
snapshot_list_output = []
|
||||||
|
|
||||||
|
@ -809,9 +827,7 @@ def formatSnapshotList(zk_conn, snapshot_list):
|
||||||
#
|
#
|
||||||
# Direct functions
|
# Direct functions
|
||||||
#
|
#
|
||||||
def get_status(zk_conn):
|
def get_status(zk_conn, status_data, primary_node):
|
||||||
status_data = zkhandler.readdata(zk_conn, '/ceph').rstrip()
|
|
||||||
primary_node = zkhandler.readdata(zk_conn, '/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('{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(status_data)
|
||||||
click.echo('')
|
click.echo('')
|
||||||
|
@ -1127,7 +1143,8 @@ def get_list_pool(zk_conn, limit):
|
||||||
|
|
||||||
def add_volume(zk_conn, pool, name, size):
|
def add_volume(zk_conn, pool, name, size):
|
||||||
# Tell the cluster to create a new volume
|
# 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})
|
zkhandler.writedata(zk_conn, {'/ceph/cmd': add_volume_string})
|
||||||
# Wait 1/2 second for the cluster to get the message and start working
|
# Wait 1/2 second for the cluster to get the message and start working
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
@ -1137,7 +1154,7 @@ def add_volume(zk_conn, pool, name, size):
|
||||||
try:
|
try:
|
||||||
result = zkhandler.readdata(zk_conn, '/ceph/cmd').split()[0]
|
result = zkhandler.readdata(zk_conn, '/ceph/cmd').split()[0]
|
||||||
if result == 'success-volume_add':
|
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
|
success = True
|
||||||
else:
|
else:
|
||||||
message = 'ERROR: Failed to create new volume; check node logs for details.'
|
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')
|
logger.out('Creating new RBD volume {} on pool {}'.format(name, pool), state='i')
|
||||||
try:
|
try:
|
||||||
# Create the volume
|
# Create the volume
|
||||||
sizeMiB = int(size) * 1024
|
retcode, stdout, stderr = common.run_os_command('rbd create --size {} --image-feature layering,exclusive-lock {}/{}'.format(size, pool, name))
|
||||||
retcode, stdout, stderr = common.run_os_command('rbd create --size {} --image-feature layering,exclusive-lock {}/{}'.format(sizeMiB, pool, name))
|
|
||||||
if retcode:
|
if retcode:
|
||||||
print('rbd create')
|
print('rbd create')
|
||||||
print(stdout)
|
print(stdout)
|
||||||
|
|
Loading…
Reference in New Issue