cephfs: enhance tracevol.py script to work with cephfs

tracevol.py script traces a RBD PVC to its RADOS map, key and image.
The script is enhanced to provide the same functionality for cephfs now.

Signed-off-by: Mudit Agarwal <muagarwa@redhat.com>
This commit is contained in:
Mudit Agarwal 2020-05-29 07:06:55 +05:30 committed by mergify[bot]
parent 78963737d3
commit e9082768b6
2 changed files with 204 additions and 82 deletions

View File

@ -1 +1,2 @@
prettytable>=0.7.2
PTable>=0.9.2

View File

@ -15,8 +15,10 @@ python tool to trace backend image name from pvc
Note: For the script to work properly python>=3.x is required
sample input:
python -c oc -k /home/.kube/config -n default -rn rook-ceph -id admin -key
adminkey
adminkey -cm ceph-csi-config
Sample output:
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| RBD |
+----------+------------------------------------------+----------------------------------------------+-----------------+--------------+------------------+
| PVC Name | PV Name | Image
Name | PV name in omap | Image ID in omap | Image in cluster |
@ -24,6 +26,13 @@ Name | PV name in omap | Image ID in omap | Image in cluster |
| rbd-pvc | pvc-f1a501dd-03f6-45c9-89f4-85eed7a13ef2 | csi-vol-1b00f5f8-b1c1-11e9-8421-9243c1f659f0 | True | True | False |
| rbd-pvcq | pvc-09a8bceb-0f60-4036-85b9-dc89912ae372 | csi-vol-b781b9b1-b1c5-11e9-8421-9243c1f659f0 | True | True | True |
+----------+------------------------------------------+----------------------------------------------+-----------------+--------------+------------------+
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CephFS |
+----------------+------------------------------------------+----------------------------------------------+-----------------+----------------------+----------------------+
| PVC Name | PV Name | Subvolume Name | PV name in omap | Subvolume ID in omap | Subvolume in cluster |
+----------------+------------------------------------------+----------------------------------------------+-----------------+----------------------+----------------------+
| csi-cephfs-pvc | pvc-b3492186-73c0-4a4e-a810-0d0fa0daf709 | csi-vol-6f283b82-a09d-11ea-81a7-0242ac11000f | True | True | True |
+----------------+------------------------------------------+----------------------------------------------+-----------------+----------------------+----------------------+
"""
import argparse
@ -52,16 +61,24 @@ PARSER.add_argument("-id", "--userid",
default="admin", help="user ID to connect to ceph cluster")
PARSER.add_argument("-key", "--userkey",
default="", help="user password to connect to ceph cluster")
PARSER.add_argument("-cm", "--configmap", default="ceph-csi-config",
help="configmap name which holds the cephcsi configuration")
def list_pvc_vol_name_mapping(arg):
"""
list pvc and volume name mapping
"""
table = prettytable.PrettyTable(
["PVC Name", "PV Name", "Image Name", "PV name in omap",
table_rbd = prettytable.PrettyTable()
table_rbd.title = "RBD"
table_rbd.field_names = ["PVC Name", "PV Name", "Image Name", "PV name in omap",
"Image ID in omap", "Image in cluster"]
)
table_cephfs = prettytable.PrettyTable()
table_cephfs.title = "CephFS"
table_cephfs.field_names = ["PVC Name", "PV Name", "Subvolume Name", "PV name in omap",
"Subvolume ID in omap", "Subvolume in cluster"]
cmd = [arg.command]
if arg.kubeconfig != "":
@ -86,16 +103,31 @@ def list_pvc_vol_name_mapping(arg):
except ValueError as err:
print(err, stdout)
sys.exit()
format_and_print_tables(arg, pvcs, table_rbd, table_cephfs)
def format_and_print_tables(arg, pvcs, table_rbd, table_cephfs):
"""
format and print tables with all relevant information.
"""
if arg.pvcname != "":
format_table(arg, pvcs, table)
pvname = pvcs['spec']['volumeName']
if is_rbd_pv(arg, pvname):
format_table(arg, pvcs, table_rbd, True)
else:
format_table(arg, pvcs, table_cephfs, False)
else:
for pvc in pvcs['items']:
format_table(arg, pvc, table)
print(table)
pvname = pvc['spec']['volumeName']
if is_rbd_pv(arg, pvname):
format_table(arg, pvc, table_rbd, True)
else:
format_table(arg, pvc, table_cephfs, False)
print(table_rbd)
print(table_cephfs)
def format_table(arg, pvc_data, table):
def format_table(arg, pvc_data, table, is_rbd):
"""
format table for pvc and image information
format tables for pvc and image information
"""
# pvc name
pvcname = pvc_data['metadata']['name']
@ -108,7 +140,7 @@ def format_table(arg, pvc_data, table):
table.add_row([pvcname, "", "", False,
False, False])
return
pool_name = get_pool_name(arg, volume_name)
pool_name = get_pool_name(arg, volume_name, is_rbd)
if pool_name == "":
table.add_row([pvcname, pvname, "", False,
False, False])
@ -119,27 +151,28 @@ def format_table(arg, pvc_data, table):
table.add_row([pvcname, pvname, "", False,
False, False])
return
# check image details present rados omap
pv_present, uuid_present = validate_volume_in_rados(
arg, image_id, pvname, pool_name)
image_in_cluster = check_image_in_cluster(arg, image_id, pool_name)
# check image/subvolume details present rados omap
pv_present, uuid_present = validate_volume_in_rados(arg, image_id, pvname, pool_name, is_rbd)
present_in_cluster = False
if is_rbd:
present_in_cluster = check_image_in_cluster(arg, image_id, pool_name)
else:
subvolname = "csi-vol-%s" % image_id
present_in_cluster = check_subvol_in_cluster(arg, subvolname)
image_name = "csi-vol-%s" % image_id
table.add_row([pvcname, pvname, image_name, pv_present,
uuid_present, image_in_cluster])
uuid_present, present_in_cluster])
def validate_volume_in_rados(arg, image_id, pvc_name, pool_name):
def validate_volume_in_rados(arg, image_id, pvc_name, pool_name, is_rbd):
"""
validate volume information in rados
"""
pv_present = check_pv_name_in_rados(arg, image_id, pvc_name, pool_name)
uuid_present = check_image_uuid_in_rados(
arg, image_id, pvc_name, pool_name)
pv_present = check_pv_name_in_rados(arg, image_id, pvc_name, pool_name, is_rbd)
uuid_present = check_image_uuid_in_rados(arg, image_id, pvc_name, pool_name, is_rbd)
return pv_present, uuid_present
def check_pv_name_in_rados(arg, image_id, pvc_name, pool_name):
def check_pv_name_in_rados(arg, image_id, pvc_name, pool_name, is_rbd):
"""
validate pvc information in rados
"""
@ -148,17 +181,11 @@ def check_pv_name_in_rados(arg, image_id, pvc_name, pool_name):
omapkey, "--pool", pool_name]
if not arg.userkey:
cmd += ["--id", arg.userid, "--key", arg.userkey]
if not is_rbd:
cmd += ["--namespace", "csi"]
if arg.toolboxdeployed is True:
tool_box_name = get_tool_box_pod_name(arg)
kube = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
kube += ["--config", arg.kubeconfig]
else:
kube += ["--kubeconfig", arg.kubeconfig]
kube += ['exec', '-it', tool_box_name, '-n',
arg.rooknamespace, '--']
cmd = kube+cmd
kube = get_cmd_prefix(arg)
cmd = kube + cmd
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
@ -182,7 +209,6 @@ def check_pv_name_in_rados(arg, image_id, pvc_name, pool_name):
return False
return True
def check_image_in_cluster(arg, image_uuid, pool_name):
"""
validate pvc information in ceph backend
@ -192,16 +218,8 @@ def check_image_in_cluster(arg, image_uuid, pool_name):
if not arg.userkey:
cmd += ["--id", arg.userid, "--key", arg.userkey]
if arg.toolboxdeployed is True:
tool_box_name = get_tool_box_pod_name(arg)
kube = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
kube += ["--config", arg.kubeconfig]
else:
kube += ["--kubeconfig", arg.kubeconfig]
kube += ['exec', '-it', tool_box_name, '-n',
arg.rooknamespace, '--']
cmd = kube+cmd
kube = get_cmd_prefix(arg)
cmd = kube + cmd
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
@ -217,8 +235,7 @@ def check_image_in_cluster(arg, image_uuid, pool_name):
return False
return True
#pylint: disable=too-many-branches
def check_image_uuid_in_rados(arg, image_id, pvc_name, pool_name):
def check_image_uuid_in_rados(arg, image_id, pvc_name, pool_name, is_rbd):
"""
validate image uuid in rados
"""
@ -226,18 +243,11 @@ def check_image_uuid_in_rados(arg, image_id, pvc_name, pool_name):
cmd = ['rados', 'getomapval', omapkey, "csi.volname", "--pool", pool_name]
if not arg.userkey:
cmd += ["--id", arg.userid, "--key", arg.userkey]
if not is_rbd:
cmd += ["--namespace", "csi"]
if arg.toolboxdeployed is True:
kube = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
kube += ["--config", arg.kubeconfig]
else:
kube += ["--kubeconfig", arg.kubeconfig]
tool_box_name = get_tool_box_pod_name(arg)
kube += ['exec', '-it', tool_box_name, '-n',
arg.rooknamespace, '--']
cmd = kube+cmd
kube = get_cmd_prefix(arg)
cmd = kube + cmd
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
@ -265,6 +275,20 @@ def check_image_uuid_in_rados(arg, image_id, pvc_name, pool_name):
return True
def get_cmd_prefix(arg):
"""
Returns command prefix
"""
kube = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
kube += ["--config", arg.kubeconfig]
else:
kube += ["--kubeconfig", arg.kubeconfig]
tool_box_name = get_tool_box_pod_name(arg)
kube += ['exec', '-it', tool_box_name, '-n', arg.rooknamespace, '--']
return kube
def get_image_uuid(volume_handler):
"""
fetch image uuid from volume handler
@ -332,43 +356,37 @@ def get_tool_box_pod_name(arg):
return ""
#pylint: disable=too-many-branches
def get_pool_name(arg, vol_id):
def get_pool_name(arg, vol_id, is_rbd):
"""
get pool name from ceph backend
"""
if is_rbd:
cmd = ['ceph', 'osd', 'lspools', '--format=json']
else:
cmd = ['ceph', 'fs', 'ls', '--format=json']
if not arg.userkey:
cmd += ["--id", arg.userid, "--key", arg.userkey]
if arg.toolboxdeployed is True:
kube = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
kube += ["--config", arg.kubeconfig]
else:
kube += ["--kubeconfig", arg.kubeconfig]
tool_box_name = get_tool_box_pod_name(arg)
kube += ['exec', '-it', tool_box_name, '-n',
arg.rooknamespace, '--']
cmd = kube+cmd
kube = get_cmd_prefix(arg)
cmd = kube + cmd
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, stderr = out.communicate()
if stderr is not None:
if arg.debug:
print("failed to pool name %s", stderr)
print("failed to get the pool name %s", stderr)
return ""
try:
pools = json.loads(stdout)
except ValueError as err:
if arg.debug:
print("failed to pool name %s", err)
print("failed to get the pool name %s", err)
return ""
if is_rbd:
pool_id = vol_id.split('-')
if len(pool_id) < 4:
if arg.debug:
print("pood id not in proper format", pool_id)
return ""
raise Exception("pool id not in the proper format")
if pool_id[3] in arg.rooknamespace:
pool_id = pool_id[4]
else:
@ -376,8 +394,111 @@ def get_pool_name(arg, vol_id):
for pool in pools:
if int(pool_id) is int(pool['poolnum']):
return pool['poolname']
else:
for pool in pools:
return pool['metadata_pool']
return ""
def check_subvol_in_cluster(arg, subvol_name):
"""
Checks if subvolume exists in cluster or not.
"""
# check if user has specified subvolumeGroup
subvol_group = get_subvol_group(arg)
if subvol_group == "":
# default subvolumeGroup
subvol_group = "csi"
return check_subvol_path(arg, subvol_name, subvol_group)
def check_subvol_path(arg, subvol_name, subvol_group):
"""
Returns True if subvolume path exists in the cluster.
"""
cmd = ['ceph', 'fs', 'subvolume', 'getpath',
'myfs', subvol_name, subvol_group]
if not arg.userkey:
cmd += ["--id", arg.userid, "--key", arg.userkey]
if arg.toolboxdeployed is True:
kube = get_cmd_prefix(arg)
cmd = kube + cmd
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, stderr = out.communicate()
if stderr is not None:
if arg.debug:
print("failed to get toolbox %s", stderr)
return False
if b"Error" in stdout:
if arg.debug:
print("subvolume not found in cluster", stdout)
return False
return True
def get_subvol_group(arg):
"""
Returns sub volume group from configmap.
"""
cmd = [arg.command]
if arg.kubeconfig != "":
if arg.command == "oc":
cmd += ["--config", arg.kubeconfig]
else:
cmd += ["--kubeconfig", arg.kubeconfig]
cmd += ['get', 'cm', arg.configmap, '-o', 'json']
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, stderr = out.communicate()
if stderr is not None:
if arg.debug:
print("failed to get configmap %s", stderr)
sys.exit()
try:
config_map = json.loads(stdout)
except ValueError as err:
print(err, stdout)
sys.exit()
cm_data = config_map['data']['config.json']
subvol_group = ""
if "subvolumeGroup" in cm_data:
try:
cm_data_json = json.loads(cm_data)
except ValueError as err:
print(err, stdout)
sys.exit()
for data in cm_data_json:
subvol_group = data['cephFS']['subvolumeGroup']
return subvol_group
def is_rbd_pv(arg, pvname):
"""
Checks if volume attributes in a pv has an attribute named 'fsname'.
If it has, returns False else return True.
"""
cmd = [arg.command]
if arg.kubeconfig != "":
cmd += ["--config", arg.kubeconfig]
else:
cmd += ["--kubeconfig", arg.kubeconfig]
cmd += ['get', 'pv', pvname, '-o', 'json']
out = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, stderr = out.communicate()
if stderr is not None:
if arg.debug:
print("failed to get pv %s", stderr)
sys.exit()
try:
pvdata = json.loads(stdout)
volume_attr = pvdata['spec']['csi']['volumeAttributes']
key = 'fsName'
if key in volume_attr.keys():
return False
except ValueError as err:
if arg.degug:
print("failed to get pv %s", err)
sys.exit()
return True
if __name__ == "__main__":
ARGS = PARSER.parse_args()