├── README.md ├── LICENSE └── bareos-cleanup /README.md: -------------------------------------------------------------------------------- 1 | # bareos-cleaner 2 | 3 | BASH tools cleaning up Bareos database and file storage. 4 | 5 | This is a purely pragmatic toolset, i.e. no plans for making it a "product" of any kind for now! 6 | 7 | Current commands: 8 | 9 | 10 | -e 11 | delete empty (JobBytes=0) jobs 12 | -p 13 | prune all volumes 14 | -t 15 | update all volumes to "actiononpurge=Truncate" 16 | -n 17 | update all volumes to "actiononpurge=None" 18 | -Dc 19 | delete all jobs that have a copy job 20 | -Do 21 | delete obsolete volume files from the disk (those not listed in catalog) 22 | NOTE: this operation can take several minutes to complete 23 | -Dp 24 | delete all purged volumes from Bacula catalog 25 | -h 26 | print this screen 27 | 28 | ## USAGE: 29 | 30 | export BAREOS_POOLDIR=/mnt/bareos 31 | bareos-cleanup -e 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | -------------------------------------------------------------------------------- /bareos-cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | POOLDIR="$BAREOS_POOLDIR" 4 | if [ -z "$POOLDIR" ]; then 5 | POOLDIR="/mnt/raid/backup/bareos/storage" 6 | fi 7 | 8 | function print_usage() { 9 | echo " -e"; 10 | echo " delete empty (JobBytes=0) jobs"; 11 | echo " -p"; 12 | echo " prune all volumes "; 13 | echo " -t"; 14 | echo " update all volumes to \"actiononpurge=Truncate\""; 15 | echo " -n"; 16 | echo " update all volumes to \"actiononpurge=None\""; 17 | echo " -Dc"; 18 | echo " delete all jobs that have a copy job" 19 | echo " -Do"; 20 | echo " delete obsolete volume files from the disk (those not listed in catalog)" 21 | echo " NOTE: this operation can take several minutes to complete" 22 | echo " -Dp"; 23 | echo " delete all purged volumes from Bacula catalog" 24 | echo " -h"; 25 | echo " print this screen"; 26 | echo "" 27 | exit 0 28 | } 29 | 30 | if [ $# -lt 1 ]; then 31 | print_usage 32 | exit 3 33 | fi 34 | 35 | update_volume() { 36 | 37 | BACULA_BATCH="$(mktemp)" 38 | 39 | echo "" 40 | echo "updating all volumes to \"actiononpurge=$1\"..." 41 | echo "" 42 | 43 | cd "$POOLDIR" 44 | for i in *; do 45 | echo "update volume=$i ActionOnPurge=$1" >> $BACULA_BATCH; 46 | done 47 | bconsole < $BACULA_BATCH | grep $1 48 | rm -f $BACULA_BATCH 49 | } 50 | 51 | del_empty() { 52 | BACULA_BATCH="$(mktemp)" 53 | 54 | echo "" 55 | echo "deleting all empty T/f status jobs..." 56 | echo "" 57 | 58 | while read jid; do 59 | echo "delete jobid=$jid" >> $BACULA_BATCH; 60 | done < <(echo "select jobid from Job where JobBytes=0 and JobFiles=0 and (JobStatus='T' or JobStatus='f' or JobStatus='A' or JobStatus='E');" | mysql --batch --skip-column-names bareos) 61 | 62 | bconsole < $BACULA_BATCH 63 | rm -f $BACULA_BATCH 64 | } 65 | 66 | del_copied_jobs() { 67 | BACULA_BATCH="$(mktemp)" 68 | 69 | echo "" 70 | echo "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, Job.JobId AS CopyJobId, Media.MediaType FROM Job JOIN JobMedia USING (JobId) JOIN Media USING (MediaId) WHERE Job.Type = 'C' ORDER BY Job.PriorJobId DESC;" | mysql -t bareos 71 | echo "" 72 | echo "This will delete jobs from the first column above." 73 | echo -n "Are you sure ? (yes|no): " 74 | read response 75 | if [ "$response" = "yes" ]; then 76 | while read jid; do 77 | echo "delete jobid=$jid" >> $BACULA_BATCH; 78 | done < <(echo "SELECT DISTINCT Job.PriorJobId AS JobId FROM Job JOIN JobMedia USING (JobId) JOIN Media USING (MediaId) WHERE Job.Type = 'C' ORDER BY Job.PriorJobId DESC;" | mysql --batch --skip-column-names bareos) 79 | bconsole < $BACULA_BATCH 80 | fi 81 | rm -f $BACULA_BATCH 82 | } 83 | 84 | prune_all() { 85 | 86 | BACULA_BATCH="$(mktemp)" 87 | 88 | echo "" 89 | echo "pruning all volumes and let Bacula mark them as purged once the retention periods are expired..." 90 | echo "" 91 | 92 | cd "$POOLDIR" 93 | for i in *; do 94 | echo "prune volume=$i" >> $BACULA_BATCH; 95 | echo "yes" >> $BACULA_BATCH; 96 | done 97 | bconsole < $BACULA_BATCH | grep -i "marking it purged" 98 | rm -f $BACULA_BATCH 99 | } 100 | 101 | delete_obsolete_volumes() { 102 | 103 | VOLUMES_TO_DELETE="$(mktemp)" 104 | 105 | echo "" 106 | echo "searching for obsolete files on disk. These could be some old volumes deleted from catalog manually..." 107 | echo "" 108 | 109 | cd "$POOLDIR" 110 | for i in *; do 111 | echo "list volume=$i" | bconsole | if grep --quiet "No results to list"; then 112 | echo "$i is ready to be deleted" 113 | echo "$POOLDIR/$i" >> $VOLUMES_TO_DELETE 114 | fi 115 | done 116 | 117 | # Check whether we have found some volumes(files) to delete 118 | if [ `wc -l $VOLUMES_TO_DELETE | awk {'print $1'}` -gt 0 ]; then 119 | 120 | echo "" 121 | echo -n "Are you sure you want to delete these volumes(files) from the disk ? (yes|no): " 122 | read response 123 | 124 | if [ "$response" = "yes" ]; then 125 | cat $VOLUMES_TO_DELETE | while read I; do 126 | rm -f "$I" 127 | done 128 | 129 | echo "" 130 | echo "DONE: following files were deleted: " 131 | cat $VOLUMES_TO_DELETE 132 | fi 133 | 134 | else 135 | echo "No volumes to delete found on disk" 136 | 137 | fi 138 | 139 | rm -f $VOLUMES_TO_DELETE 140 | 141 | } 142 | 143 | delete_purged_volumes() { 144 | 145 | echo "" 146 | echo "searching for all purged volumes to be deleted..." 147 | echo "" 148 | 149 | PURGED_VOLUMES=`echo "list volumes" | bconsole | grep "Purged.*File" | awk {'print $4'}` 150 | echo "$PURGED_VOLUMES" 151 | 152 | echo "" 153 | echo -n "Are you sure you want to delete all these purged volumes from Bacula catalog ? (yes|no): " 154 | read response 155 | 156 | cd "$POOLDIR" 157 | LOGFILE="/tmp/delete-purged-volumes.log" 158 | 159 | if [ "$response" = "yes" ]; then 160 | BACULA_BATCH="$(mktemp)" 161 | rm -f "$LOGFILE" 162 | echo "@output $LOGFILE" > $BACULA_BATCH 163 | echo "$PURGED_VOLUMES" | while read I; do 164 | echo "delete volume=$I" >> $BACULA_BATCH 165 | echo "yes" >> $BACULA_BATCH 166 | done 167 | 168 | bconsole < $BACULA_BATCH 169 | rm -f $BACULA_BATCH 170 | echo "Done. See the log file $LOGFILE" 171 | fi 172 | } 173 | 174 | # Parse parameters 175 | while [ $# -gt 0 ]; do 176 | case "$1" in 177 | -h | --help) 178 | print_usage 179 | exit 0 180 | ;; 181 | -e) 182 | shift 183 | del_empty 184 | exit 0 185 | ;; 186 | -p) 187 | shift 188 | prune_all 189 | exit 0 190 | ;; 191 | -t) 192 | shift 193 | update_volume Truncate 194 | exit 0 195 | ;; 196 | -n) 197 | shift 198 | update_volume None 199 | exit 0 200 | ;; 201 | -Dc) 202 | shift 203 | del_copied_jobs 204 | exit 0 205 | ;; 206 | -Do) 207 | shift 208 | delete_obsolete_volumes 209 | exit 0 210 | ;; 211 | -Dp) 212 | shift 213 | delete_purged_volumes 214 | exit 0 215 | ;; 216 | *) echo "Unknown argument: $1" 217 | print_usage 218 | exit 3 219 | ;; 220 | esac 221 | done 222 | exit 1 223 | --------------------------------------------------------------------------------