Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- #
- # A simple rotational wrapper for innobackupex
- #
- # Version 1.0
- #
- # By Dean M Rantala - drantala@ena.com / deanrantala@gmail.com
- #
- # Special credit: a huge thanks goes to Education Networks of America
- # for allowing me to develop free software on company dime!
- #
- # http://www.ena.com
- #
- #
- # <Released under the GPL license>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- use strict;
- use File::Path qw(make_path remove_tree);
- #
- #
- # -------------
- # CONFIGURATION
- # -------------
- # How many full backups should always be kept?
- my $full_backup_retention = 7;
- # How many incremental backups should we perform
- # between each full backup? (0=disable incremental)
- my $incremental_backups = 23;
- # Full path to your backup directory
- # WITHOUT LEADING SLASH!
- my $backup_dir = '/mnt/archive/mysql';
- # Database user/pass credentials
- my $dbuser = 'perconaXB';
- my $dbpass = 'perconaXB';
- # This stuff should never change, but in case it does...
- my $timestamp_regexp = '^\d{4}\-\d{2}\-\d{2}_\d{2}\-\d{2}\-\d{2}$';
- my $checkpoint_file = 'xtrabackup_checkpoints';
- # Full path to the innobackupex script
- my $innobackupex = '/usr/bin/innobackupex';
- # --------------------------------------------------------------
- # NO NEED TO EDIT BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING!
- # --------------------------------------------------------------
- # ---------------------------------------------
- # Inspect a backup directory and determine
- # if it is a full backup or an incremental
- # backup. Return the status. Returns
- # 'unknown' if a checkpoint file is not found.
- #
- sub determine_backup_type
- {
- my $checkpoint_file = shift;
- my $type = 'unknown';
- if(-f $checkpoint_file)
- {
- open(my $fh, "<$checkpoint_file") or die("Could not open file $checkpoint_file: $!");
- while(my $line = <$fh>)
- {
- chomp $line;
- if($line =~ m/^backup_type/)
- {
- $line =~ s/^backup_type = //g;
- if($line eq 'full-backuped')
- {
- $type = 'full';
- last;
- }
- if($line eq 'incremental')
- {
- $type = 'incremental';
- last;
- }
- }
- }
- close($fh);
- }
- print "Backup type determined to be: $type\n\n";
- return $type;
- }
- #
- # --------------------------------------------
- # ---------------------------------------------
- # List the contents of a directory
- # This is meant to simplify and centralize
- # some re-usable logic.
- # @param $directory (directory to generate listing for)
- # @param $order (asc|desc, optional, listing order)
- # @param $filter (REGEXP, optional, regex filter folders must match to be listed)
- # @returns @array
- #
- sub list_directory
- {
- my $directory = shift;
- my $order = shift || 'asc';
- my $filter = shift || '.*';
- my @entries = ();
- opendir(my $dh,$directory) || die("Unable to open directory: $directory");
- while(readdir($dh))
- {
- chomp $_;
- $_ =~ s/^\s+|\s+$//g;
- if( $_ =~ /$filter/g )
- {
- push @entries, $_;
- }
- }
- closedir($dh);
- if($order eq 'desc')
- {
- @entries = sort {$b cmp $a} @entries;
- }
- else
- {
- @entries = sort @entries;
- }
- return @entries;
- }
- #
- # --------------------------------------------
- # Let's centralize the username/password and any general options
- # that should be passed to innobackupex
- $innobackupex = "nice -n 10 $innobackupex --user=$dbuser --password=$dbpass --throttle=20";
- print "Starting...\n\n";
- my $cmd_to_execute = '';
- if($incremental_backups == 0)
- {
- # Incrementals are disabled, just create a fresh full-backup
- print "Incrementals disabled.\n";
- $cmd_to_execute = "$innobackupex $backup_dir";
- }
- else
- {
- print "Incrementals have been defined.\n";
- # Incremental backups have been defined, so lets determine what we
- # need to perform for this backup.
- my @entries = list_directory($backup_dir,'desc',$timestamp_regexp);
- my $incrementals_found = 0;
- my $most_recent_backup = '';
- my $pass = 0;
- foreach(@entries)
- {
- my $backup_type = determine_backup_type("$backup_dir/$_/$checkpoint_file");
- # We ignore folders that cannot be determined
- if($backup_type eq 'unknown')
- {
- next;
- }
- # Capture the first iteration as this is the most recent backup
- # that has been made.
- if($pass==0)
- {
- $most_recent_backup = $_;
- }
- $pass++;
- if($backup_type eq 'full')
- {
- # Perform an incremental
- $cmd_to_execute = "$innobackupex --incremental $backup_dir --incremental-basedir=$backup_dir/$most_recent_backup";
- last;
- }
- if($backup_type eq 'incremental')
- {
- $incrementals_found++;
- }
- if($incrementals_found==$incremental_backups)
- {
- # Perform a full backup
- $cmd_to_execute = "$innobackupex $backup_dir";
- last;
- }
- }
- if($pass>0 && $cmd_to_execute eq '')
- {
- # We obviously have no existing backups, so this
- # must be a full backup we need to run.
- print "No existing backups, full one must be run.\n";
- $cmd_to_execute = "$innobackupex $backup_dir";
- }
- }
- if($cmd_to_execute ne '')
- {
- print "EXECUTING: $cmd_to_execute\n";
- system $cmd_to_execute;
- }
- else
- {
- print "No command to execute, sorry.\n";
- print "You might want to run a full backup; have at it:\n";
- $cmd_to_execute = "$innobackupex $backup_dir";
- print $cmd_to_execute . "\n";
- }
- # Time to cycle out the oldest folders based on our retention policy.
- #
- # This logic is simple: start counting the number of full backups found
- # (from newest to oldest) until we count as many as are defined in the
- # $full_backup_retention variable and start deleting everything else
- # we find moving backwards.
- #
- my @entries = list_directory($backup_dir,'desc',$timestamp_regexp);
- my $full_backups_found = 0;
- my $start_deleting = 0;
- foreach(@entries)
- {
- my $backup_type = determine_backup_type("$backup_dir/$_/$checkpoint_file");
- # We ignore folders that cannot be determined
- if($backup_type eq 'unknown')
- {
- next;
- }
- if($backup_type eq 'full')
- {
- $full_backups_found++;
- if($full_backups_found==$full_backup_retention)
- {
- $start_deleting = 1;
- next;
- }
- }
- if($start_deleting==1)
- {
- # Delete this backup!
- print "REMOVING: $backup_dir/$_\n\n";
- remove_tree("$backup_dir/$_");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement