View Single Post
  #86 (permalink)  
Old 09-17-2006, 03:20 AM
czaveri czaveri is offline
Former Zimbran
 
Posts: 294
Default Cold or Off-line backup script

I thought better to start with Off-line backup script. Here's one. I have tested this on my system running CentOS 4.3 and ZCS 4.0.0 GA. I also restored the entire /opt/zimbra directory from the backup and am now running on it now ...

I have around 20 users on the system and approx. 3,000 emails in all. All contacts, calendars, wiki, and everything is intact and working well.

Attached the script with README: zimbraColdBackup-Ver0.01beta-Rev15.tgz

Code:
#!/usr/bin/perl -w
use strict;
use POSIX;
use Proc::ProcessTable;
use File::Path;
use File::Rsync;
use Mail::Mailer;
my $version = "0.01beta";       # version of this program
my $revision = "15";            # revision of this program
# License
my $license = qq(
###########################################################################
# Program Name: zimbraColdBackup Ver $version Rev $revision                      #
#                                                                         #
# This script can be used to backup Zimbra Collaboration Suite 4.0.0 GA   #
#                                                                         #
# Copyright (C) 2006 Chintan Zaveri                                       #
# E-mail: smile\@sis.net.in                                                #
#                                                                         #
# This program is free software; you can redistribute it and/or modify    #
# it under the terms of the GNU General Public License version 2, as      #
# published by the Free Software Foundation                               #
#                                                                         #
# 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, write to the Free Software Foundation, Inc., #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.             #
###########################################################################
);

###########################################################################
# Make changes BELOW this line to suit your environment / requirement     #
###########################################################################

# Change the following to the path to your backup directory. This directory must exist on your system.
my $backup_directory = '/backup';

# Change the following to the path to "rsync"
my $path_to_rsync = '/usr/bin/rsync';

# Do you want to rotate backups?
my $rotate_backups = 1; # "1" for yes, and "0" for no

# If you want to rotate backups, please specify the number of days after which it should be rotated
my $rotation_days = 7;

# You must not need to change the following, but just in case
# Specify the path to zimbra
my $zimbra_path = '/opt/zimbra';

# zimbra user
my $zimbra_user = 'zimbra';

# Do you want this script to send an e-mail after backup is done?
my $to_email = 0; # 1 for yes, 0 for no

# If you specified 1 above, please provide your email address below
my $email_address = 'you@yourdomain.com';

###########################################################################
# DON'T MAKE CHANGES BELOW THIS LINE - unless you know what you are doing #
###########################################################################
my $prog_name = $0;             # name of this program
my $option = shift;             # the first parameter passed to this program

# If any useless parameters are provided to script give error.
# We are checking only the first param
usage("Invalid parameter(s)") if (($option) && ($option ne "--help") && ($option ne "?") && ($option ne "help") && ($option ne "--confirm") && ($option ne "confirm"));

# do we need to print help?
if (! defined($option)) { $option = "nevermind"; } # This is necessary so that perl does not complain about use of uninitialized value

help("Help Screen") if ($option =~ /--help|help|\?/);

usage("Usage") if (($option ne "confirm") && ($option ne "--confirm"));

# Validate Inputs
if (($rotate_backups !~ /^\d+$/) || ($rotate_backups < 0) || ($rotate_backups > 1)) {
        die "The variable \$rotate_backups can only contain either 0 or 1";
}

if (($rotation_days !~ /^\d{1,3}$/) || ($rotation_days < 1)) {
        die "The variable \$rotation_days must contain only, either 1, 2 or 3, digits - you can't leave this blank even if you are not rotating backups";
}

if (($backup_directory eq "") || ($backup_directory !~ /^\//)) {
        die "You need to specify an absolute path to backup directory";
}

if (! (-d $backup_directory)) {
        die "There is no such directory as $backup_directory";
}

if (! (-d $zimbra_path)) {
        die "There is no such directory as $zimbra_path";
}

if (! (-e $path_to_rsync)) {
        die "The path to 'rsync' provided by you as $path_to_rsync seems wrong. Please check.";
}

if (($to_email !~ /^\d+$/) || ($to_email < 0) || ($to_email > 1)) {
        die "The variable \$to_email can only contain either 0 or 1";
}

if (! $email_address) {
        die "Please enter a valid email address";
}

# Define an array to store the status of various actions of this script. This will be sent by email.
my @results;

# Stop Zimbra
my $zimbra_stop_status = system ("su - zimbra -c '$zimbra_path/bin/zmcontrol stop'");
if ($zimbra_stop_status) {
        warn "Something was not right when trying to stop Zimbra";
        push (@results, "Stopping Zimbra: Something was not right when trying to stop Zimbra");
} else {
        push (@results, "Stopping Zimbra: Success");
}
die "Error stopping Zimbra" if ($zimbra_stop_status == -1);

# Kill all lingering Zimbra processes
my $zimbra_uid = getpwnam($zimbra_user);

my $process_table = Proc::ProcessTable->new;

# Gracefully kill lingering processes: kill -15, sleep, kill -9
foreach my $process ( @{$process_table->table} ) {
        if (($process->uid eq $zimbra_uid) || (($process->cmndline =~ /$zimbra_user/) && ($process->cmndline !~ /$prog_name/))) {
                kill -15,$process->pid; # thanks, merlyn
                sleep 10; # not sure if there'll be buffering. If you know, please improve.
                kill -9,$process->pid;
        }
}

my $current_time = POSIX::strftime('%a-%d-%b-%Y-%H-%M', localtime(time)); # current day, date, month, time, ...
my $since_epoch = time();       # seconds since epoch

# Backup Zimbra using "rsync"
my $rsync_obj = File::Rsync->new( {
        'rsync-path'    => $path_to_rsync,
        'archive'       => 1,
        'recursive'     => 1,
        'links'         => 1,
        'hard-links'    => 1,
        'keep-dirlinks' => 1,
        'perms'         => 1,
        'owner'         => 1,
        'group'         => 1,
        'devices'       => 1,
        'times'         => 1
} );
$rsync_obj->exec( { src => "$zimbra_path/", dest => "$backup_directory/$since_epoch-$current_time-zcsColdBackup" } ) or warn "rsync failed\n";

push (@results, "Backup using Rsync: Successfully created $backup_directory/$since_epoch-$current_time-zcsColdBackup");

# Now that backup is done, start Zimbra
my $zimbra_start_status = system ("su - zimbra -c '$zimbra_path/bin/zmcontrol start'");
if ($zimbra_start_status) {
        warn "Something was not right when trying to start Zimbra";
        push (@results, "Starting Zimbra: Something was not right when trying to start Zimbra");
} else {
        push (@results, "Starting Zimbra: Success");
}

# Rotate backups
if ($rotate_backups) {
        # get a list of all files from the backup directory
        opendir (DIR, $backup_directory) or die "can't opendir $backup_directory: $!";
        while (defined(my $filename = readdir(DIR))) { # actually, $filename is the name of all rsynced directories
                next if ($filename !~ /-zcsColdBackup/); # if it is not a cold backup directory, ignore it
                # if $filename is older than $rotation_days then delete it
                my @filename_parts = split("-",$filename); # cutting from hyphens
                my $allowed_age = $since_epoch - (60 * 60 * 24 * $rotation_days); # allowed age is converted to seconds
                if ($filename_parts[0] < $allowed_age) { # if the first part of $filename is not equal to or more than the allowed age
                        rmtree ("$backup_directory/$filename") || die "Cannot delete $filename"; # delete it
                        push (@results, "Backup Rotation: Removed $backup_directory/$filename");
                }
        }
        closedir (DIR);
}

if ($to_email) {
        my $email_body = join("\n", @results);
        my $mailer = Mail::Mailer->new("sendmail");
        $mailer->open( {
                'From'          =>      'root@localhost',
                'To'            =>      $email_address,
                'Subject'       =>      'Results of zimbraColdBackup'
        } ) or die "Can't open: $!\n";
        print $mailer "Date: ", $current_time, "\n\n";
        print $mailer $email_body, "\n";
        $mailer->close();
}

sub usage {
# what to print when usage is incorrect
my $options = qq(
Usage: $prog_name [--help|?|help] [--confirm]

  --help|?|help         display help
  --confirm|confirm     run script

If no parameters are provided then the script will display usage.

Please edit this file to suit your system before using it.
);

die @_, $license, $options;
}

sub help {
my $help_txt = qq(
1. OVERVIEW:

This script can help in taking cold or off-line backups of Zimbra Collaboration Suite.

2. FEATURES:

a. Take cold or off-line backups of Zimbra Collaboration Suite
b. Rotate backups
c. E-mail backup reports

3. INSTALLATION:

This script relies on the following Perl modules:

POSIX, Proc::ProcessTable, File::Path, File::Rsync, Mail::Mailer

Please ensure that these modules are available on your system before you execute the script.

These can be downloaded from http://cpan.org

Once the modules are installed edit the zimbraColdBackup.pl script to match your system / requirements.

chmod this script to 755

chown this script to root:root

Done!
);

die @_, $license, $help_txt;
}
Attached Files
File Type: tgz zimbraColdBackup-Ver0.01beta-Rev15.tgz (9.9 KB, 136 views)
__________________
Regards,

Chintan Zaveri
(Yet another ZIMBRAN!)

"Dhundhne par Bhagwan bhi ..."
Reply With Quote