summaryrefslogtreecommitdiff
path: root/byteback-prune
diff options
context:
space:
mode:
authorMatthew Bloch <matthew@bytemark.co.uk>2014-11-05 14:00:45 +0000
committerMatthew Bloch <matthew@bytemark.co.uk>2014-11-05 14:00:45 +0000
commitc88333e19b459685f57ba3f246c3fdd684681542 (patch)
tree3be762cf0a9ebb57c8a8528bcf98433434d371ad /byteback-prune
parentf6c155ff0b261f23b6fc9465b7f2e6d85bab573a (diff)
Split out -prune from -snapshot, tested the latter on various live setups.
Diffstat (limited to 'byteback-prune')
-rwxr-xr-xbyteback-prune112
1 files changed, 112 insertions, 0 deletions
diff --git a/byteback-prune b/byteback-prune
new file mode 100755
index 0000000..ed5bf0c
--- /dev/null
+++ b/byteback-prune
@@ -0,0 +1,112 @@
+#!/usr/bin/ruby
+#
+# Program to prune a byteback installation
+
+$LOAD_PATH.unshift("/usr/lib/byteback")
+require 'trollop'
+require 'byteback'
+require 'sys/filesystem'
+include Byteback
+include Byteback::Log
+include Byteback::Util
+
+opts = Trollop::options do
+
+ banner "Prune old backup directories to ensure there's enough space"
+
+ opt :minpercent, "Start prune when disk has less than this %age free",
+ :type => :integer,
+ :default => 5
+
+ opt :maxpercent, "Stop prune when disk has more than this %age free",
+ :type => :integer,
+ :default => 10
+
+ opt :list, "List backups in pruning order, no other action"
+
+ opt :prune, "Prune the next backup if necessary"
+
+ opt :order, "Order backups by 'age' or 'importance'",
+ :type => :string,
+ :default => "importance"
+
+ opt :verbose, "Show debugging messages"
+
+end
+
+@order = opts[:order]
+@verbose = opts[:verbose]
+@do_list = opts[:list]
+@do_prune = opts[:prune]
+@minpercent = opts[:minpercent]
+@maxpercent = opts[:maxpercent]
+
+fatal("Must specify one of --prune or --list") unless
+ (@do_prune || @do_list) &&
+ !(@do_prune && @do_list)
+
+fatal("Must specify --order as 'age' or 'importance'") unless
+ @order == 'age' || @order == 'importance'
+
+if BackupDirectory.all.empty?
+ fatal("No backup directories found, need to run byteback-snapshot")
+end
+
+@df_history = DiskFreeHistory.new(ENV['HOME'])
+@df_history.new_reading!
+
+# Don't do anything if we've not got two hours of readings
+#
+if @df_history.list.last.time - @df_history.list.first.time < 7200
+ warn("Not enough disc space history to make a decision")
+ exit 0
+end
+
+gradient_30m = @df_history.gradient(1800)
+debug("Disc space gradient over 30m = #{gradient_30m}")
+exit
+
+# Check whether we should still be pruning
+#
+@free = @df_history.list.last.percent_free
+PRUNING_FLAG = "#{ENV['HOME']}/.byteback.pruning"
+
+if @free <= @minpercent && !File.exists?(PRUNING_FLAG)
+ warn("Starting prune, #{@free}% free (aiming for #{@maxpercent})")
+ File.write(PRUNING_FLAG,"")
+elsif @free >= @maxpercent && File.exists?(PRUNING_FLAG)
+ warn("Stopping prune, #{@free}% free")
+ File.unlink(PRUNING_FLAG)
+elsif File.exists?(PRUNING_FLAG)
+ warn("Continuing prune, #{@free}% free (aiming for #{@maxpercent})")
+end
+
+def snapshots_in_order
+ list = BackupDirectory.all_snapshots
+ if list.empty?
+ warn("Couldn't find any snapshots (yet?)")
+ end
+ if @order == 'importance'
+ Snapshot.sort_by_importance(list)
+ elsif @order == 'age'
+ list.sort.reverse
+ else
+ raise ArgumentError.new("Unknown snapshot sort method #{method}")
+ end
+end
+
+snapshots = snapshots_in_order
+
+if @do_list
+ print "Backups by #{@order}:\n"
+ snapshots.each_with_index do |snapshot, index|
+ print "#{sprintf('% 3d',index)}: #{snapshot.path}\n"
+ end
+end
+
+exit 0 unless File.exists?(PRUNING_FLAG) && @do_prune
+
+exit 0 if gradient_30m != 0
+
+info("Deleting #{snapshots.last.path}")
+log_system("sudo btrfs subvolume delete #{snapshots.last.path}")