Skip to content
Snippets Groups Projects
Select Git revision
  • c517940459816ebcee4250d967676e245f21eb52
  • master default protected
  • simple-task/7248-eol-check-add-node-22
  • 6877_check_iml_deployment
4 results

check_ceph_osd.md

Blame
  • localdump.sh 23.68 KiB
    #!/bin/bash
    # ======================================================================
    #
    # BACKUP SCRIPTS - CREATE LOCAL DUMPS
    #
    # ----------------------------------------------------------------------
    # ah - Axel Hahn <axel.hahn@iml.unibe.ch>
    # ds - Daniel Schueler <daniel.schueler@iml.unibe.ch>
    #
    # 2016-11-04  ah,ds  created
    # 2016-11-10  .....  v1.0
    # 2017-03-27  .....  added first param for mode backup|restore
    # 2018-02-09  .....  fix: restore-selection of target uses default on return only
    # 2021-05-18  .....  move supported backup types to plugins/localdump/[service].sh
    # 2021-07-13  .....  remove leading ./ in localdump.sh restore
    # 2022-02-18  .....  WIP: use class like functions
    # 2022-03-17  .....  WIP: add lines with prefix __DB__
    # 2022-11-04  ah     rename hooks
    # 2024-03-14  ah     v2.0: use profiles for local and remote databases
    # ======================================================================
    
    # --- variables:
    # ARCHIVE_BASEDIR     {string}  base directory for db archive (couchdb2 only)
    # BACKUP_BASEDIR      {string}  base directory for db dumps
    # BACKUP_DATE         {string}  string with current timestamp; will be part of filename for backups
    # BACKUP_KEEP_DAYS    {int}     count of days how long to keep db dumps below $BACKUP_BASEDIR
    # BACKUP_PLUGINDIR    {string}  scripts for supported databases; [APP]/plugins/localdump
    # BACKUP_SCRIPT       {string}  script name of db service
    # BACKUP_TARGETDIR    {string}  target directory db dumps of current service
    # SERVICENAME         {string}  name of db service (one of mysql|pgsql|...)
    
    # ----------------------------------------------------------------------
    # CONFIG VARS
    # ----------------------------------------------------------------------
    
        . $(dirname $0)/vendor/ini.class.sh    || exit 1
        . $(dirname $0)/vendor/color.class.sh  || exit 1
    
        . $(dirname $0)/includes/jobhelper.sh  || exit 1
        . $(dirname $0)/includes/inc_bash.sh   || exit 1
    
        . $(dirname $0)/includes/dbdetect.class.sh || exit 1
    
        if [ ! -r "${JOBFILE}" ]; then
            color.echo error "ERROR: missing config file ${JOBFILE}."
            exit 1
        fi
    
        LOCALDUMP_LOADED=1
    
        ARCHIVE_BASEDIR=
        BACKUP_BASEDIR=
        BACKUP_PLUGINDIR=
    
        DBD_DEBUG=0
    
        # Cleanup local dumps older N days
        typeset -i BACKUP_KEEP_DAYS=0
    
        BACKUP_DATE=
        LASTINPUT=
    
    # ----------------------------------------------------------------------
    # FUNCTIONS 4 DB-WRAPPER
    # ----------------------------------------------------------------------
    
    
        # helpfer function for SERVICENAME.backup
        # it is called after the service specific dump was done.
        # param  {string}  filename of created dump file
        function db._compressDumpfile(){
            local _outfile=$1
    
            # $myrc is last returncode - set in fetchrc
            if [ $myrc -eq 0 ]; then
                echo -n "gzip $_outfile ... "
                gzip -9 -f "${_outfile}"
                fetchrc
            else
                color.echo error "ERROR occured while dumping - no gzip of $_outfile"
            fi
            # echo -n "__DB__$SERVICENAME INFO: backup to " 
            # ls -l "$_outfile"* 2>&1
            # echo
        }
    
    # ----------------------------------------------------------------------
    # FUNCTIONS 4 BACKUP
    # ----------------------------------------------------------------------
    
    
        # ------------------------------------------------------------
        # cleanup a backup dir: remove old files and delete empty dirs
        function cleanup_backup_target(){
            if [ -d "${BACKUP_TARGETDIR}" ]; then
                h3 "CLEANUP ${BACKUP_TARGETDIR} older $BACKUP_KEEP_DAYS days ..."
    
                echo find "${BACKUP_TARGETDIR}" -mtime +$BACKUP_KEEP_DAYS -delete -print
                color.preset cmd
                find "${BACKUP_TARGETDIR}" -mtime +$BACKUP_KEEP_DAYS -delete -print
                color.reset
    
                if [ $(find "${BACKUP_TARGETDIR}" -type f | wc -l) -eq 0 ]; then
                    echo "INFO: the directory is empty - deleting it"
                    rm -rf "${BACKUP_TARGETDIR}"
                fi
            fi
        }
    
        # ------------------------------------------------------------
        # compress a file
        # shared function in localdump_*
        # param  string  filename of uncompressed output file
        function compress_file(){
            echo -n compressing $1 ...
            gzip -9 -f "${1}"
            fetchrc
        }
    
        # ------------------------------------------------------------
        # create a backup directory with name of service
        # shared function in localdump_*
        function create_targetdir(){
            mkdir -p "${BACKUP_TARGETDIR}" 2>/dev/null
            if [ ! -d "${BACKUP_TARGETDIR}" ]; then
                color.echo "error" "FATAL ERROR: directory ${BACKUP_TARGETDIR} was not created"
                exit 1
            fi
        }
    
    
        # ------------------------------------------------------------
        # generate a base filename for backup dump based on on db name
        # ... and added timestamp
        # param  string  name of database schema
        # --> see listBackupedDBs() and guessDB() - these function must be able to split this
        function get_outfile(){
            echo $*__${BACKUP_DATE}
        }
    
        # ------------------------------------------------------------
        # get name of a service script
        # param  string  name of a service 
        function get_service_script(){
            local _service=$1
            local _type; _type=$( dbdetect.getType "$_service" )
            ls -1 ${BACKUP_PLUGINDIR}/${_type}.sh 2>/dev/null
        }
    
        # ------------------------------------------------------------
        # get a list of existing database profiles
        function get_database_profiles(){
            for config in $(dbdetect.getConfigs); do
                if dbdetect.exists "$config"; then
                    echo "$( dbdetect.getProfile $config )"
                fi
            done
        }
    
        # ------------------------------------------------------------
        # show directory infos with count of files and used space
        # show used space and count of files and dirs
        function show_info_backup_target(){
          if [ -d "${BACKUP_TARGETDIR}" ]; then
            h3 "INFO about backup target ${BACKUP_TARGETDIR}"
      
            echo -n "used space: "
            du -hs "${BACKUP_TARGETDIR}"
      
            echo -n "subdirs   : "
            find "${BACKUP_TARGETDIR}" -type d | wc -l
      
            echo -n "files     : "
            find "${BACKUP_TARGETDIR}" -type f | wc -l
      
            echo -n "free space: "
            df -h "${BACKUP_TARGETDIR}" | tail -1 | awk '{ print $4 }'
            echo
          fi
        }
    
    # ----------------------------------------------------------------------
    # FUNCTIONS 4 RESTORE
    # ----------------------------------------------------------------------
    
        # ------------------------------------------------------------
        # restore: show profiles from that exist backups
        # global  string  BACKUP_BASEDIR  base directory of all backups
        function listBackupedServices(){
            (
                test -n "${BACKUP_BASEDIR}" && test -d "${BACKUP_BASEDIR}" \
                    && find "${BACKUP_BASEDIR}" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;
                test -n "${ARCHIVE_BASEDIR}" && test -d "${ARCHIVE_BASEDIR}" \
                    && find "${ARCHIVE_BASEDIR}" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;
            ) | sort -u
        }
    
        # ------------------------------------------------------------
        # restore: show databases or dumps of a given database that can be restored
        # global  string  BACKUP_BASEDIR  base directory of all backups of selected dbprofile
        # param  string  optional: DB-Name for file filter to select from existing dumps;
        function listBackupedDBs(){
            if [ -d "${BACKUP_TARGETDIR}" ]; then
                if [ -z $1 ]; then
                    # list all databases
                    find "${BACKUP_TARGETDIR}" -mindepth 1 -maxdepth 1 -type f -exec basename {} \; \
                        | sed "s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g" \
                        | sed "s#\..*##g" \
                        | sort -ud| sed "s#^\./##g"
                else
                    # list dumps of a database
                    ls -ltr ${BACKUP_TARGETDIR}/${1}*gz | sed "s,${BACKUP_TARGETDIR}/,,g"
                fi
            else
                color.echo error "ERROR: ${BACKUP_TARGETDIR} does not exist - here are no backups to restore."
                echo
                echo "You can try to restore dumps:"
                echo "1) Restore dump files from a backup set"
                echo "     $(dirname $0)/restore.sh $BACKUP_BASEDIR"
                echo "2) Copy restored dumps into $BACKUP_TARGETDIR"
                echo "3) Start database restore again"
                echo "     $(dirname $0)/localdump.sh restore [profile]"
                echo
                exit 1
            fi
        }
    
    
        # ------------------------------------------------------------
        # guess name of the database file
        # param  string  filename of db dump; can be full path or not
        function guessDB(){
            dumpfile=$1
      
            # the metafile is written in sqlite backup to store full path
            metafile=${BACKUP_TARGETDIR}/${dumpfile}.meta
            if [ -f $metafile ]; then
                grep "^/" "$metafile" || grep "^  File: " "$metafile" | cut -c 9-
            else
                sBasename=$(basename $1)
                sDb=$(echo ${sBasename} | sed "s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g" | sed "s#\.couchdbdump\.gz##g" )
                #                                   ^                                                                   ^
                #        timestamp in backup file __/                               for couchdb2 restore from archive __/
                if [ -z $sDb ]; then
                    color.echo error "ERROR: db name was not detected from file $1"
                    exit 1
                fi
                echo $sDb
            fi
        }
    
        # ------------------------------------------------------------
        # show a selection + a prompt and read the input
        # - If the selection is just 1 line it will be returned
        # - If the user presses just return the script will exit
        # param  string  selection of items to select from
        # param  string  prompt to show
        function showSelectAndInput(){
            local _selection="$1"
            local _prompt="$2"
        
            local _lines
            typeset -i _lines; _lines=$( grep -c "." <<< "$_selection" )
        
            case $_lines in
                0)
                    color.echo error "ERROR: No data found for a selection. Aborting."
                    echo
                    exit 1
                    ;;
                1) 
                    echo "INFO: No interaction on a single choice. Using '$_selection'"
                    LASTINPUT="$_selection"
                    return 0
                    ;;
                *)
                echo "$_selection"
                color.print input "${_prompt} >"
                read -r LASTINPUT
                if [ -z "$LASTINPUT" ]; then
                    echo "No input given. Aborting."
                    exit 1
                fi
                ;;
            esac  
        }
    
        # ------------------------------------------------------------
        # read .meta file (that contains output of stats) and restore last owner and file permissions
        # param  string  filename of db dump
        # param  string  restored database file
        function restorePermissions(){
            local sMyMeta="${1}.meta"
            local sTargetfile="$2"
            if [ -f "${sMyMeta}" ]; then
    
                # Access: (0674/-rw-rwxr--)  Uid: ( 1000/    axel)   Gid: ( 1000/    axel)
                #          ^                                 ^                       ^
                #          _sPerm                            _sUser                  _sGroup
                local _sPerm=$(  grep "^Access: (" "${sMyMeta}" | cut -f 2 -d '(' | cut -f 1 -d '/')
                if [ -n "$_sPerm" ]; then
    
                    local _sUser=$(  grep "^Access: (" "${sMyMeta}" | cut -f 3 -d '(' | cut -f 1 -d '/' | tr -d ' ')
                    local _sGroup=$( grep "^Access: (" "${sMyMeta}" | cut -f 4 -d '(' | cut -f 1 -d '/' | tr -d ' ')
    
                    echo -n "Restoring file owner $_sUser:$_sGroup and permissions $_sPerm ... "
                    chown "$_sUser:$_sGroup" "${sTargetfile}" && chmod "$_sPerm" "${sTargetfile}"
                    fetchrc
                fi
            fi
        }
    
        # ------------------------------------------------------------
        # show help
        # ------------------------------------------------------------
        function showhelp(){
            local _self
            _self=$( basename "$0" )
            cat <<EOH
    
    LOCALDUMP detects existing local databases and dumps them locally.
    It is included in the backup.sh to dump all before a file backup will store 
    them. It can be started seperately for manual database backups or for restore.
    
    SYNTAX:
        $_self [OPTIONS] <operation> <profile [more_profiles]>
    
    OPTIONS:
        -h|--help   show this help
    
    PARAMETERS:"
        operation   - one of check|backup|restore; optional parameter
                          backup   dump all databases/ schemes of a given service
                          check    show info only if the service is available
                          restore  import a dump into same or new database
                                   Without a filename it starts an interactive mode
        profile     - name of database profiles
                      You get a list of all available services without parameter
                      Use ALL for bulk command
        file        - filename of db dump to restore to origin database scheme
    
    EXAMPLES:
        $_self backup
        $_self backup ALL
                     Backup all databases of all found services
        $_self backup mysql
                     Backup all Mysql databases.
    
        $_self restore
                     Start interactive restore of a database of any service.
        $_self restore sqlite
                     Start interactive restore of an sqlite database.
        $_self restore <file-to-restore> [<database-name>]
                     Restore a given dump file to the origin database scheme or
                     to a new/ other database with the given name.
    
    EOH
        }
    
    
    # ----------------------------------------------------------------------
    # INIT
    # ----------------------------------------------------------------------
    
        while [[ "$#" -gt 0 ]]; do case $1 in
            -h|--help)      showhelp; exit 0;;
            *) if grep "^-" <<< "$1" >/dev/null ; then
                    echo; color.echo error "ERROR: Unknown parameter: $1"; echo; showhelp; exit 2
                fi
                break;
                ;;
        esac; done
    
        mode=""
        case "$1" in
            backup|check|restore|shell)
                mode=$1
                shift 1
                ;;
        esac
    
        if [ -z "$mode" ]; then
            color.echo error "ERROR: missing parameter for operation."
            echo
            showhelp
            echo
            echo "Hint: On this machine working profiles:"
            get_database_profiles | nl
            echo
            exit 1
        fi
    
        # ----- init vars
        BACKUP_BASEDIR=$(_j_getvar "${JOBFILE}" "dir-localdumps")
    
        # check
        if [ -z "$BACKUP_BASEDIR" ]; then
            color.echo error "ERROR: missing config for backup target."
            echo There must be an entry dir-localdumps in ${JOBFILE}
            exit 1
        fi
        ARCHIVE_BASEDIR=$(_j_getvar "${JOBFILE}" dir-dbarchive)
    
        BACKUP_PLUGINDIR=$(dirname $0)/plugins/localdump
        DBD_BASEDIR=$BACKUP_PLUGINDIR/profiles
    
        BACKUP_KEEP_DAYS=$(_j_getvar ${JOBFILE} "keep-days")
    
        if [ $BACKUP_KEEP_DAYS -eq 0 ]; then
            BACKUP_KEEP_DAYS=7
        fi
        BACKUP_DATE=$(/bin/date +%Y%m%d-%H%M)
    
        # ----- checks
    
        # . /usr/local/bin/inc_cronfunctions.sh
        j_requireUser "root"
    
        h1 $(date) IML BACKUP :: LOCALDUMP
    
    
        export SERVICENAME=$1
        # BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${SERVICENAME}
        # BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
      
        case "$mode" in
            # ------------------------------------------------------------
            check)
                DBD_DEBUG=1
                for PROFILENAME in $(dbdetect.getConfigs)
                do
                    echo "----- $PROFILENAME"
                    dbdetect.exists "${PROFILENAME}"
                    echo
                done
                # . $BACKUP_SCRIPT $mode
                ;;
          # ------------------------------------------------------------
          backup)
            if [ "$1" = "ALL" ] || [ -z "$1" ]; then
      
                profiles2run=$(get_database_profiles)
                echo "INFO: Calling local backup scripts for all active profiles"
                echo "$profiles2run" | nl
            else
                profiles2run=$*
                echo "INFO: I try to dump the profiles you gave as parameter: $profiles2run"
                echo
            fi
      
            iProfilesFound=$( grep -c . <<< "$profiles2run" )
            test "$iProfilesFound" -eq "0" && echo "INFO: No match - no database dumps needed."
            typeset -i iProfileCounter=0
    
            # ----- GO
            # PROFILENAME    mysql_localhost_13306
            # SERVICENAME    mysql
            #
            for PROFILENAME in $profiles2run
            do
      
                iProfileCounter+=1
    
                if dbdetect.setProfile "${PROFILENAME}"; then
                    h2 "START PROFILE $iProfileCounter of $iProfilesFound [${PROFILENAME}]"
      
                    SERVICENAME=$( dbdetect.getType "$PROFILENAME" )
                    BACKUP_PARAMS=$( dbdetect.getParams )
      
                    BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${PROFILENAME}
                    ARCHIVE_DIR=${ARCHIVE_BASEDIR}/${PROFILENAME}
                    BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
        
      
                    # ------ set env
                    # echo "BACKUP_PARAMS = $BACKUP_PARAMS"
                    # dbdetect.setenv
                    eval $( dbdetect.setenv )
      
                    _j_runHooks "200-before-db-service"
      
                    h3 "BACKUP [${PROFILENAME}] -> ${SERVICENAME}"
                    . $BACKUP_SCRIPT $mode
      
                    test $rc -gt 0 && j_notify "db ${SERVICENAME}" "$BACKUP_SCRIPT $mode was finished with rc=$rc" $rc
                    _j_runHooks "230-after-db-service" "$rc"
      
                    # ------ unset env
                    eval $( dbdetect.unssetenv )
      
                    # ----- post jobs: cleanup
                    cleanup_backup_target
                    show_info_backup_target
        
                else
      
                    echo "SKIP: profile $iProfileCounter of $iProfilesFound '$PROFILENAME' "
      
                    # see why it is not active
                    DBD_DEBUG=1; dbdetect.setProfile "${PROFILENAME}"; echo; DBD_DEBUG=0
      
                fi
      
                # just to have it in the output
                dbdetect.validate
      
            done
            ;;
      
          # ------------------------------------------------------------
          restore)
      
            h1 "RESTORE DATABASE"
      
            if ! listBackupedServices | grep -q . ; then
                color.echo error "ERROR: No database dump was found in [${BACKUP_BASEDIR}] nor [${ARCHIVE_BASEDIR}]."
                exit 1
            fi
      
            if [ -z $1 ] || [ ! -f "$1" ]; then
      
                parService="$1"
      
              # ----- interactive selections
      
                h2 "Select profile that has a dump"
      
                if [ -z "${parService}" ]; then
                    showSelectAndInput "$( listBackupedServices )" "Restore for profile name"
                    parService="$LASTINPUT"
                else
                    echo "Taken from command line: $parService"
                fi
      
                # ----- check if profile exists
                if ! dbdetect.setProfile "${parService}"; then
                    color.echo error "ERROR: profile [${parService}] is not known here (or database service is stopped)."
                    echo
                    exit 1
                fi
      
                # ----- check if dump exists in archive and in backup
                if [ -d "${BACKUP_BASEDIR}/${parService}" ] && [ -d "${ARCHIVE_BASEDIR}/${parService}" ]; then
                    echo
                    showSelectAndInput "$(echo "${BACKUP_BASEDIR}"; echo "${ARCHIVE_BASEDIR}")" "Select a source directory"
                    BACKUP_BASEDIR="$LASTINPUT"
                else
                    # just one test needed because BACKUP_BASEDIR is BACKUP_BASEDIR
                    test -d "${ARCHIVE_BASEDIR}/${parService}" && BACKUP_BASEDIR="${ARCHIVE_BASEDIR}"
                fi
      
                # ----- check if target dir with profile exists
                if [ ! -d "${BACKUP_BASEDIR}/${parService}" ]; then
                    color.echo error "ERROR: Directory does not exist '${BACKUP_BASEDIR}/${parService}'."
                    exit 1
                fi
      
                BACKUP_TARGETDIR="${BACKUP_BASEDIR}/${parService}"
      
                h2 "Select a database schema"
                showSelectAndInput "$(listBackupedDBs)" "Name of database to restore"
                fileprefix="$LASTINPUT"
                echo
      
                h2 "Select a specific dump for that database"
                showSelectAndInput "$(listBackupedDBs $fileprefix)" "Backupset to import"
                dbfile="$LASTINPUT"
    
                # if there is a single dump in backup folder: 
                # '-rw-r--r-- 1 root root 481 Mar 13 12:27 ahcrawler__20240313-1227.sql.gz'
                # --> take the last part behind the last space to get a filename
                grep "^-[rwxsSt\-]* " <<< "$LASTINPUT" && dbfile="$(rev <<< \'"$LASTINPUT"\' | cut -d ' ' -f 1 | rev)"
                echo
      
                sTargetDb=$(guessDB ${dbfile})
                color.print input "New database name [$sTargetDb] >"
                read -r sTargetDb
                if [ -z $sTargetDb ]; then
                    sTargetDb=$(guessDB ${dbfile})
                fi
                echo
      
                sDumpfile="${BACKUP_TARGETDIR}/${dbfile}"
            else
                sDumpfile=$1
                sTargetDb=$2
            fi
            shift 2
      
            # ----- start restore
      
            if [ ! -f "${sDumpfile}" ]; then
                color.echo error "ERROR: [${sDumpfile}] is not a file"
                rc=$rc+1
            else
      
                PROFILENAME="${sDumpfile//${BACKUP_BASEDIR}/}"
                PROFILENAME="$( echo $PROFILENAME | sed "s,^/*,," | cut -f 1 -d '/')"
      
                if dbdetect.setProfile "${PROFILENAME}"; then
      
                    SERVICENAME=$( dbdetect.getType "$PROFILENAME" )
    
                    BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${PROFILENAME}
                    BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
                    ARCHIVE_DIR=${ARCHIVE_BASEDIR}/${PROFILENAME}
      
                    BACKUP_PARAMS=$( dbdetect.getParams )
                    eval $( dbdetect.setenv )
                    . $BACKUP_SCRIPT $mode "${sDumpfile}" "${sTargetDb}"
      
                    if [ $? -ne 0 -o $rc -ne 0 ]; then
                        color.echo error "ERROR: $mode failed. See ouput above. :-/"
                    else
                        color.echo ok "OK, $mode was successful."
                    fi
      
                    # ------ unset env
                    eval $( dbdetect.unssetenv )
                else
                    color.echo error "ERROR: Profile $PROFILENAME was detected but its database service is not available."
                fi
      
            fi
            ;;
            # ------------------------------------------------------------
            # shell)
        
            #   export BACKUP_TARGETDIR
            #   . $BACKUP_SCRIPT
            #   ( 
            #     mycmd=
            #     echo
            #     echo "Starting interactive shell..."
            #     echo
            #     echo "STATUS: STILL ALPHA as long existing db plugins are not rewritten."
            #     echo
            #     echo "INFO: Try ${SERVICENAME}.help to see database specific commands."
            #     echo "INFO: Type exit and return to leave the shell."
            #     echo
            #     while [ ! "$mycmd" = "exit" ]; do
            #       echo -n "[${SERVICENAME}]"
            #       color.print input " $( pwd )"
            #       echo -n " % "
            #       read -r mycmd
            #       if [ ! "$mycmd" = "exit" ];then
            #         color.preset cmd
            #         eval $mycmd
            #         color.reset
            #       fi
            #     done
            #   )
            #   ;;
            
            # ----- start restore
            *)
                color.echo error "ERROR: unknown command [$mode]"
                ;;
        esac
      
        echo _______________________________________________________________________________
        echo STATUS $0 exit with final returncode rc=$rc
        exit $rc
        
    # ----------------------------------------------------------------------