Skip to content

Instantly share code, notes, and snippets.

@pulecp
Last active April 11, 2022 14:25
Show Gist options
  • Save pulecp/99f3b89c2c5f3c4ff0fa052b4531cdf2 to your computer and use it in GitHub Desktop.
Save pulecp/99f3b89c2c5f3c4ff0fa052b4531cdf2 to your computer and use it in GitHub Desktop.
This script looks for gluster volumes, checks their heal statuses and tries to fix all the unhealed files/dirs.
#!/bin/bash
# thanks to Niels de Vos (https://gist.github.com/nixpanic/5460521), this script
# is based on his one
RED='\033[1;31m'
GREEN='\033[1;32m'
NC='\033[0m' # No Color
# trap ctrl-c and call ctrl_c()
trap ctrl_c INT
function ctrl_c() {
echo -e "${RED}You interrupted the running scripts. Check manually
if there are no mounts of glusterfs left${NC}"
echo 'There is list of mount with fuse.glusterfs:'
mount | grep glusterfs
exit 1
}
if [[ "$#" > "1" ]]; then
cat <<END
Glusterfs healer -- this script will touch all the unhealed files/dirs
over Glusterfs mount.
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.
This script goes through the all unhealed files/dirs. According to the
theory in previous paragraph, it will filter out all the directories and
tries to list them by 'ls' in glusterfs mount. The gluster filesystem is
mounted locally by this script. The touch of directory through the gluster
mount will heal the directory.
The heal of directories will resolve the rest of the GFIDs in
'gluster volume heal <volume_name> status' output from GFID to real path
in gluster mount. The rest of GFIDs are only files. So it's pretty simple
to touch these files through the gluster mount. The touch of the files
will also heal them.
NOTES:
The initial idea of the heal of files was to find the i-node of each
file and then recursively find the same i-node in the gluster brick. But
it was time demanding operation. You can see the commented implementation
below.
I'm also not sure why gluster does not do something similar during the heal
or full heal itself. It can be just bug which will be removed in the future.
END
exit
fi
volumes=$(gluster volume list)
echo "List of volumes: ${volumes}"
for volume in $volumes;do
mount_point=$(mktemp -d)
mount -t glusterfs "${HOSTNAME}:/${volume}" "$mount_point"
echo -e "\n\n\nProcessing volume: ${volume}"
brick_path=$(gluster volume info "$volume" |
grep "Brick.*${HOSTNAME}" |
cut -d':' -f3)
echo "Brick path: ${brick_path}"
echo -n "Gettins gfids..."
gfids=$(gluster volume heal "$volume" info |
grep gfid |
cut -d ':' -f 2 |
cut -d '>' -f 1)
echo 'done'
# array
directories=()
inums=()
for gfid in $gfids;do
gp1=$(cut -c 1-2 <<<"$gfid")
gp2=$(cut -c 3-4 <<<"$gfid")
gfidpre="$brick_path"/.glusterfs/"$gp1"/"$gp2"
gfidpath="$gfidpre"/"$gfid"
if [[ -h "$gfidpath" ]]; then
# directories
dirpath="$gfidpre"/$(readlink "$gfidpath")
dir=$(echo $(cd $(dirname $dirpath); pwd -P)/$(basename $dirpath))
directories+=("$dir")
else
# files
inums+=("$(stat --format=%i $gfidpath)")
fi
done
# print directories
if [[ -n "$directories" ]];then
echo -e "Healing directories\n"
for dir in "${directories[@]}";do
echo -en "\n ${dir/$brick_path//}"
echo -en ' ...healing'
ls "${mount_point}${dir/$brick_path//}" &>/dev/null
if [[ "$?" -eq 0 ]];then
echo -en "...${GREEN}ok${NC}"
else
echo -en "...${RED}failed${NC}"
fi
done
else
echo -e "No directory to heal\n"
fi
### comment to the commented code below:
### The code below was recursively looking for the inode in the brick
### directory. It took a lot of time. I found solution for that.
###
### When you heal all directories at first then all gfids in output of:
###
### gluster volume heal data info
###
### are changed to real paths. So you can just touch them in linear
### time.
###
###
### # find and print files
### if [[ -n "$inums" ]];then
### find_argument_with_inums="-inum ${inums[0]}"
### echo -e "\n\nList of files (it will take some time):\n"
###
### for inum in "${inums[@]:1}";do # array without first element added above
### find_argument_with_inums+=" -o -inum ${inum}"
### done
###
### find "$brick_path"/* $find_argument_with_inums |
### while read file;do
### echo -en "\n ${file}"
### echo -en ' ...healing'
### touch -a --no-create "${mount_point}${file/$brick_path//}"
### if [[ "$?" -eq 0 ]];then
### echo -en "...${GREEN}ok${NC}"
### else
### echo -en "...${RED}failed${NC}"
### fi
### done
### #end of find
### fi
# heal files
echo -e "\n\nHealing files:\n"
gluster volume heal "$volume" info | grep '^/' |
while read file;do
echo -en "\n ${file}"
echo -en ' ...healing'
touch -a --no-create "${mount_point}${file}"
if [[ "$?" -eq 0 ]];then
echo -en "...${GREEN}ok${NC}"
else
echo -en "...${RED}failed${NC}"
fi
done
echo -e "\n\n\n\n"
umount "$mount_point"
if [[ "$?" -eq 0 ]];then
echo -e "${GREEN}Temporary mount succesfully unmounted${NC}"
else
echo -e "${RED}Unmounting of temporary mount failed! Check mounts!${NC}"
fi
rmdir "$mount_point"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment