Last active
August 31, 2024 10:22
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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