Resolving Gluster GFIDs back to real files and directories (BASH)

When dealing with Gluster, you'll inevitably stumble across output which provides a Gluster File ID (GFID) rather than a real path - whether that's when dealing with a split-brain or when checking logs.

This script can be used to turn a GFID (such as 54fa66cc-ccdd-42f4-8eb2-6083e9121de5) back into a more recognisable path (such as /brick1/gluster/foo/bar.jpg), this can then be used to help resolve split-brain issues etc.

Details

Snippet

#!/bin/bash
# 
# Copyright (C) 2019 B Tasker
#
# resolve-gfid.sh
#
# Take a brick path and a GFID and work out the path it represents (i.e.
# where it points to if you were accessing via GlusterFS).
#
# Adaptation based on the logic in https://gist.github.com/louiszuckerman/4392640
# essentially fixes some bugs related to Gluster breakage, adds comments
# and tidies code formatting a bit
#
#

if [[ "$#" -lt "2" || "$#" -gt "3" ]]
then
cat << END
Glusterfs GFID resolver -- turns a GFID into a real file path

Usage: $0 <brick-path> <gfid> [-q]

<brick-path> : the path to your glusterfs brick (required)

<gfid> : the gfid you wish to resolve to a real path (required)

-q : quieter output (optional)
    with this option only the actual resolved path is printed.
    without this option $0 will print the GFID, 
    whether it identifies a file or directory, and the resolved
    path to the real file or directory.

Theory:
The .glusterfs directory in the brick root has files named by GFIDs
If the GFID identifies a directory, then this file is a symlink to the
actual directory.  If the GFID identifies a file then this file is a
hard link to the actual file.

END

exit

fi

# Get brick and GFID from the cmdline
BRICK="$1"
GFID="$2"
QUIET="$3"

# Directories are named based on the first chars of the gfid
# e.g. f6/b7/f6b763ec-a996-4f2a-adc9-89635b7e12dc
#
GP1=`cut -c 1-2 <<<"$GFID"`
GP2=`cut -c 3-4 <<<"$GFID"`

# Start building the path to the GFID symlink's parent directory
GFIDPRE="$BRICK"/.glusterfs/"$GP1"/"$GP2"

# Append the GFID
GFIDPATH="$GFIDPRE"/"$GFID"

if [ ! "$QUIET" == "-q" ]; then
    echo -ne "$GFID\t==\t"
fi

# Does the path exist, and is it a symbolic link?
if [ -h "$GFIDPATH" ]; then
    if [ ! "$QUIET" == "-q" ]; then
        echo -ne "Directory:\t"
    fi
    DIRPATH="$GFIDPRE"/`readlink "$GFIDPATH"`

    # Calculate the "real" pathname
    #
    # The script this is based on tried to cd and pwd it
    # this resulted in the script failing with "Too many levels of symbolic links"
    # whenever Gluster was having one of it's moments
    #
    echo $(readlink -f `dirname "$DIRPATH"`)/$(basename "$DIRPATH")

else
    # Not a symlink - means it's a file and the path we're looking at
    # will be a hardlink back to the file wherever on the brick it actually lives
    if [ ! "$QUIET" == "-q" ]; then
        echo -ne "File:\t"
    fi
    INUM=`ls -i "$GFIDPATH" | cut -f 1 -d \ `  
    if [ "$INUM" == "" ]
    then
        echo "Unable to get inode number for file. Do you lack appropriate permissions?"
        exit 1
    fi

    find "$BRICK" -inum "$INUM" ! -path \*.glusterfs/\*
fi

Usage Example

./resolv-gfid.sh /brick1/gluster 54fa66cc-ccdd-42f4-8eb2-6083e9121de5
54fa66cc-ccdd-42f4-8eb2-6083e9121de5    ==    Directory:    /brick1/gluster/sharedfile/jpgs/034