#!/bin/bash # remove_changelog: emergency remove changelog files from server. # # This is emergency tool to cleanup changelogs in server if changelog # records cannot be removed by regular means, e.g. due to llog corruptions # # Tool goes through changelog_catalog and removes all plain llogs listed # then removes changelog_catalog itself and changelog_users # Script accept single parameter which is mount point of server FS mounted # locally, script accepts also --dry-run option to emulate files removal # # Steps to cleanup problematic llogs: # # 1. mount MDT filesystem locally on server as ldiskfs mount # 2. run script first in dry-run mode to make sure it parses llogs as needed: # # bash remove_changelog -n # 3. save all llogs for analysis: # # bash remove_changelog -n -z /tmp/llogs_saved # 4. check that /tmp/llogs_saved.tar.gz exists and has all llogs inside: # # ls -ali /tmp/llogs_saved.tar.gz # # tar -tf /tmp/llog_saved.tar.gz # 5. finally run script to delete all llogs: # # bash remove_changelog # # For better llogs compression xz can be used as well, pass it to the script # via GZIP env variable: # # GZIP=xz bash remove_changelog -n -z /tmp/llogs_saved # Archive name will ends with .xz in that case instead of .gz ECHO=echo PROG=$(basename $0) LLOG_READER=${LLOG_READER:-llog_reader} GZIP=${GZIP:-gzip} usage() { cat -- <&2 usage: remove_changelog [--dry-run|-n] [--help|-h] [--quiet|-q] [--zip}-z] --help|-h show this usage message --dry-run|-n only print the names of files to be removed --quiet|-q run quietly (don't print filenames or status) --zip|-z save all llogs into compressed tar archive with given name prefix using gzip by default. Other compression tools can be used via GZIP env variable. The 'localmount' argument should be an ldiskfs mounted MDT device mountpoint. Examples: remove_changelog /mnt/mdt0 remove_changelog --dry-run /mnt/mdt0 remove_changelog -z /tmp/llogs /mnt/mdt0 USAGE exit 1 } OPT_DRYRUN=false OPT_ARCH="" OPT_MOUNT="" # Examine any long options and arguments while [ -n "$*" ]; do arg="$1" case "$arg" in -h|--help) usage;; -n|--dry-run) OPT_DRYRUN=true;; -q|--quiet) ECHO=:;; -z|--zip) OPT_ARCH="$2.tar"; shift;; *) [ -e "$arg" ] && OPT_MOUNT="$arg" && break esac shift done remove_changelog() { local mntpoint=$OPT_MOUNT local catalog=${mntpoint}/changelog_catalog local users=${mntpoint}/changelog_users local arch=$OPT_ARCH if [[ -z $(df -t ldiskfs $mntpoint 2>/dev/null) ]] ; then echo "$PROG: '$mntpoint' is not ldiskfs mount." exit 1 fi if $OPT_DRYRUN; then $ECHO "Dry run was requested, no changes will be applied" fi $ECHO "Scan changelog_catalog at '$mntpoint':" if [[ ! -f $catalog ]] ; then echo "$PROG: $catalog doesn't exist already." else if [[ ! $(which $LLOG_READER 2>/dev/null) ]] ; then echo "$PROG: $LLOG_READER is missing." exit 1 fi [[ -z $arch ]] || tar -cf $arch $catalog 2>/dev/null if (( $(stat -c %s $catalog) >= 8192 )) ; then while read -r path ; do [[ -z $arch ]] || tar -rf $arch ${mntpoint}/$path 2>/dev/null $ECHO "rm ${mntpoint}/$path" $OPT_DRYRUN || rm -f ${mntpoint}/$path done < <($LLOG_READER $catalog | awk -F "path=" '/path=/ { print $2 }') else echo "$PROG: $catalog is too small." fi $ECHO "> $catalog" $OPT_DRYRUN || > $catalog fi if [[ -f $users ]] ; then [[ -z $arch ]] || tar -rf $arch $users 2>/dev/null $ECHO "> $users" $OPT_DRYRUN || > $users else echo "$PROG: $user doesn't exist." fi if [[ "$arch" ]] ; then $GZIP -3 $arch $ECHO "llog archive was created by $GZIP" fi } if [ -z $OPT_MOUNT ] ; then echo "Mount is not specified, exiting" exit 1 fi remove_changelog