Add separate OSD DB device support
Adds in three parts: 1. Create an API endpoint to create OSD DB volume groups on a device. Passed through to the node via the same command pipeline as creating/removing OSDs, and creates a volume group with a fixed name (osd-db). 2. Adds API support for specifying whether or not to use this DB volume group when creating a new OSD via the "ext_db" flag. Naming and sizing is fixed for simplicity and based on Ceph recommendations (5% of OSD size). The Zookeeper schema tracks the block device to use during removal. 3. Adds CLI support for the new and modified API endpoints, as well as displaying the block device and DB block device in the OSD list. While I debated supporting adding a DB device to an existing OSD, in practice this ended up being a very complex operation involving stopping the OSD and setting some options, so this is not supported; this can be specified during OSD creation only. Closes #142
This commit is contained in:
@ -149,6 +149,31 @@ def format_raw_output(status_data):
|
||||
return '\n'.join(ainformation)
|
||||
|
||||
|
||||
#
|
||||
# OSD DB VG functions
|
||||
#
|
||||
def ceph_osd_db_vg_add(config, node, device):
|
||||
"""
|
||||
Add new Ceph OSD database volume group
|
||||
|
||||
API endpoint: POST /api/v1/storage/ceph/osddb
|
||||
API arguments: node={node}, device={device}
|
||||
API schema: {"message":"{data}"}
|
||||
"""
|
||||
params = {
|
||||
'node': node,
|
||||
'device': device
|
||||
}
|
||||
response = call_api(config, 'post', '/storage/ceph/osddb', params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
retstatus = True
|
||||
else:
|
||||
retstatus = False
|
||||
|
||||
return retstatus, response.json().get('message', '')
|
||||
|
||||
|
||||
#
|
||||
# OSD functions
|
||||
#
|
||||
@ -197,18 +222,19 @@ def ceph_osd_list(config, limit):
|
||||
return False, response.json().get('message', '')
|
||||
|
||||
|
||||
def ceph_osd_add(config, node, device, weight):
|
||||
def ceph_osd_add(config, node, device, weight, ext_db_flag):
|
||||
"""
|
||||
Add new Ceph OSD
|
||||
|
||||
API endpoint: POST /api/v1/storage/ceph/osd
|
||||
API arguments: node={node}, device={device}, weight={weight}
|
||||
API arguments: node={node}, device={device}, weight={weight}, ext_db={ext_db_flag}
|
||||
API schema: {"message":"{data}"}
|
||||
"""
|
||||
params = {
|
||||
'node': node,
|
||||
'device': device,
|
||||
'weight': weight
|
||||
'weight': weight,
|
||||
'ext_db': ext_db_flag
|
||||
}
|
||||
response = call_api(config, 'post', '/storage/ceph/osd', params=params)
|
||||
|
||||
@ -312,13 +338,15 @@ def format_list_osd(osd_list):
|
||||
osd_list_output = []
|
||||
|
||||
osd_id_length = 3
|
||||
osd_node_length = 5
|
||||
osd_device_length = 6
|
||||
osd_db_device_length = 9
|
||||
osd_up_length = 4
|
||||
osd_in_length = 4
|
||||
osd_size_length = 5
|
||||
osd_weight_length = 3
|
||||
osd_reweight_length = 5
|
||||
osd_pgs_length = 4
|
||||
osd_node_length = 5
|
||||
osd_used_length = 5
|
||||
osd_free_length = 6
|
||||
osd_util_length = 6
|
||||
@ -358,10 +386,21 @@ def format_list_osd(osd_list):
|
||||
if _osd_id_length > osd_id_length:
|
||||
osd_id_length = _osd_id_length
|
||||
|
||||
# Set the OSD node length
|
||||
_osd_node_length = len(osd_information['stats']['node']) + 1
|
||||
if _osd_node_length > osd_node_length:
|
||||
osd_node_length = _osd_node_length
|
||||
|
||||
# Set the OSD device length
|
||||
_osd_device_length = len(osd_information['device']) + 1
|
||||
if _osd_device_length > osd_device_length:
|
||||
osd_device_length = _osd_device_length
|
||||
|
||||
# Set the OSD db_device length
|
||||
_osd_db_device_length = len(osd_information['db_device']) + 1
|
||||
if _osd_db_device_length > osd_db_device_length:
|
||||
osd_db_device_length = _osd_db_device_length
|
||||
|
||||
# Set the size and length
|
||||
_osd_size_length = len(str(osd_information['stats']['size'])) + 1
|
||||
if _osd_size_length > osd_size_length:
|
||||
@ -422,12 +461,12 @@ def format_list_osd(osd_list):
|
||||
osd_list_output.append('{bold}{osd_header: <{osd_header_length}} {state_header: <{state_header_length}} {details_header: <{details_header_length}} {read_header: <{read_header_length}} {write_header: <{write_header_length}}{end_bold}'.format(
|
||||
bold=ansiprint.bold(),
|
||||
end_bold=ansiprint.end(),
|
||||
osd_header_length=osd_id_length + osd_node_length + 1,
|
||||
osd_header_length=osd_id_length + osd_node_length + osd_device_length + osd_db_device_length + 3,
|
||||
state_header_length=osd_up_length + osd_in_length + 1,
|
||||
details_header_length=osd_size_length + osd_pgs_length + osd_weight_length + osd_reweight_length + osd_used_length + osd_free_length + osd_util_length + osd_var_length + 7,
|
||||
read_header_length=osd_rdops_length + osd_rddata_length + 1,
|
||||
write_header_length=osd_wrops_length + osd_wrdata_length + 1,
|
||||
osd_header='OSDs ' + ''.join(['-' for _ in range(5, osd_id_length + osd_node_length)]),
|
||||
osd_header='OSDs ' + ''.join(['-' for _ in range(5, osd_id_length + osd_node_length + osd_device_length + osd_db_device_length + 2)]),
|
||||
state_header='State ' + ''.join(['-' for _ in range(6, osd_up_length + osd_in_length)]),
|
||||
details_header='Details ' + ''.join(['-' for _ in range(8, osd_size_length + osd_pgs_length + osd_weight_length + osd_reweight_length + osd_used_length + osd_free_length + osd_util_length + osd_var_length + 6)]),
|
||||
read_header='Read ' + ''.join(['-' for _ in range(5, osd_rdops_length + osd_rddata_length)]),
|
||||
@ -437,6 +476,8 @@ def format_list_osd(osd_list):
|
||||
osd_list_output.append('{bold}\
|
||||
{osd_id: <{osd_id_length}} \
|
||||
{osd_node: <{osd_node_length}} \
|
||||
{osd_device: <{osd_device_length}} \
|
||||
{osd_db_device: <{osd_db_device_length}} \
|
||||
{osd_up: <{osd_up_length}} \
|
||||
{osd_in: <{osd_in_length}} \
|
||||
{osd_size: <{osd_size_length}} \
|
||||
@ -456,6 +497,8 @@ def format_list_osd(osd_list):
|
||||
end_bold=ansiprint.end(),
|
||||
osd_id_length=osd_id_length,
|
||||
osd_node_length=osd_node_length,
|
||||
osd_device_length=osd_device_length,
|
||||
osd_db_device_length=osd_db_device_length,
|
||||
osd_up_length=osd_up_length,
|
||||
osd_in_length=osd_in_length,
|
||||
osd_size_length=osd_size_length,
|
||||
@ -472,6 +515,8 @@ def format_list_osd(osd_list):
|
||||
osd_rddata_length=osd_rddata_length,
|
||||
osd_id='ID',
|
||||
osd_node='Node',
|
||||
osd_device='Block',
|
||||
osd_db_device='DB Block',
|
||||
osd_up='Up',
|
||||
osd_in='In',
|
||||
osd_size='Size',
|
||||
@ -500,10 +545,16 @@ def format_list_osd(osd_list):
|
||||
osd_util = round(osd_information['stats']['utilization'], 2)
|
||||
osd_var = round(osd_information['stats']['var'], 2)
|
||||
|
||||
osd_db_device = osd_information['db_device']
|
||||
if not osd_db_device:
|
||||
osd_db_device = 'N/A'
|
||||
|
||||
# Format the output header
|
||||
osd_list_output.append('{bold}\
|
||||
{osd_id: <{osd_id_length}} \
|
||||
{osd_node: <{osd_node_length}} \
|
||||
{osd_device: <{osd_device_length}} \
|
||||
{osd_db_device: <{osd_db_device_length}} \
|
||||
{osd_up_colour}{osd_up: <{osd_up_length}}{end_colour} \
|
||||
{osd_in_colour}{osd_in: <{osd_in_length}}{end_colour} \
|
||||
{osd_size: <{osd_size_length}} \
|
||||
@ -524,6 +575,8 @@ def format_list_osd(osd_list):
|
||||
end_colour=ansiprint.end(),
|
||||
osd_id_length=osd_id_length,
|
||||
osd_node_length=osd_node_length,
|
||||
osd_device_length=osd_device_length,
|
||||
osd_db_device_length=osd_db_device_length,
|
||||
osd_up_length=osd_up_length,
|
||||
osd_in_length=osd_in_length,
|
||||
osd_size_length=osd_size_length,
|
||||
@ -540,6 +593,8 @@ def format_list_osd(osd_list):
|
||||
osd_rddata_length=osd_rddata_length,
|
||||
osd_id=osd_information['id'],
|
||||
osd_node=osd_information['stats']['node'],
|
||||
osd_device=osd_information['device'],
|
||||
osd_db_device=osd_db_device,
|
||||
osd_up_colour=osd_up_colour,
|
||||
osd_up=osd_up_flag,
|
||||
osd_in_colour=osd_in_colour,
|
||||
|
@ -2583,6 +2583,38 @@ def ceph_osd():
|
||||
pass
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc storage osd create-db-vg
|
||||
###############################################################################
|
||||
@click.command(name='create-db-vg', short_help='Create new OSD database volume group.')
|
||||
@click.argument(
|
||||
'node'
|
||||
)
|
||||
@click.argument(
|
||||
'device'
|
||||
)
|
||||
@click.option(
|
||||
'-y', '--yes', 'confirm_flag',
|
||||
is_flag=True, default=False,
|
||||
help='Confirm the creation'
|
||||
)
|
||||
@cluster_req
|
||||
def ceph_osd_create_db_vg(node, device, confirm_flag):
|
||||
"""
|
||||
Create a new Ceph OSD database volume group on node NODE with block device DEVICE.
|
||||
|
||||
This volume group will be used for Ceph OSD database functionality if the '--ext-db' flag is passed to newly-created OSDs during 'pvc storage osd add'. DEVICE should be an extremely fast SSD device (NVMe, Intel Optane, etc.) which is significantly faster than the normal OSD disks and with very high write endurance. Only one OSD database volume group on a single physical device is supported per node, so it must be fast and large enough to act as an effective OSD database device for all OSDs on the node; the database volume for each OSD is fixed to 5% of the OSD's size. Attempting to add additional database volume groups after the first will fail.
|
||||
"""
|
||||
if not confirm_flag and not config['unsafe']:
|
||||
try:
|
||||
click.confirm('Destroy all data and create a new OSD database volume group on {}:{}'.format(node, device), prompt_suffix='? ', abort=True)
|
||||
except Exception:
|
||||
exit(0)
|
||||
|
||||
retcode, retmsg = pvc_ceph.ceph_osd_db_vg_add(config, node, device)
|
||||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc storage osd add
|
||||
###############################################################################
|
||||
@ -2598,15 +2630,22 @@ def ceph_osd():
|
||||
default=1.0, show_default=True,
|
||||
help='Weight of the OSD within the CRUSH map.'
|
||||
)
|
||||
@click.option(
|
||||
'-d', '--ext-db', 'ext_db_flag',
|
||||
is_flag=True, default=False,
|
||||
help='Use an external database logical volume for this OSD.'
|
||||
)
|
||||
@click.option(
|
||||
'-y', '--yes', 'confirm_flag',
|
||||
is_flag=True, default=False,
|
||||
help='Confirm the removal'
|
||||
help='Confirm the creation'
|
||||
)
|
||||
@cluster_req
|
||||
def ceph_osd_add(node, device, weight, confirm_flag):
|
||||
def ceph_osd_add(node, device, weight, ext_db_flag, confirm_flag):
|
||||
"""
|
||||
Add a new Ceph OSD on node NODE with block device DEVICE.
|
||||
|
||||
If '--ext-db' is specified, the existing OSD database volume group on NODE will be used; it must exist first or OSD creation will fail. See the 'pvc storage osd create-db-vg' command for more details.
|
||||
"""
|
||||
if not confirm_flag and not config['unsafe']:
|
||||
try:
|
||||
@ -2614,7 +2653,7 @@ def ceph_osd_add(node, device, weight, confirm_flag):
|
||||
except Exception:
|
||||
exit(0)
|
||||
|
||||
retcode, retmsg = pvc_ceph.ceph_osd_add(config, node, device, weight)
|
||||
retcode, retmsg = pvc_ceph.ceph_osd_add(config, node, device, weight, ext_db_flag)
|
||||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
@ -4856,6 +4895,7 @@ ceph_benchmark.add_command(ceph_benchmark_run)
|
||||
ceph_benchmark.add_command(ceph_benchmark_info)
|
||||
ceph_benchmark.add_command(ceph_benchmark_list)
|
||||
|
||||
ceph_osd.add_command(ceph_osd_create_db_vg)
|
||||
ceph_osd.add_command(ceph_osd_add)
|
||||
ceph_osd.add_command(ceph_osd_remove)
|
||||
ceph_osd.add_command(ceph_osd_in)
|
||||
|
Reference in New Issue
Block a user