Skip to content

Instantly share code, notes, and snippets.

Created November 1, 2010 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/658992 to your computer and use it in GitHub Desktop.
Save anonymous/658992 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl -w
use strict;
use DBI;
use Net::FTP;
use Switch;
use POSIX qw(strftime);
use Text::Wrap;
$Text::Wrap::columns = 120;
our %remote_login; #ftp or scp log in information
our $remote_type; #is it ftp or scp?
our $day; #day the cron will be run
our $correct;
our $backup;
our $db_backup;
our $db_ref = {};
our @db_list;
our %db = (); #database log in information
our $yes;#text for positive response for $correct
our $correct_me; #name of function &correct is running
our $connect;
our $cron_login; #holds log in info for cron
our $crondate; #holds info about the date that will be set in the cron
our $cron_connect = "";
our $tmpdir = '/tmp';
our $profile;
our $backup_path;
our $save_path;
our $cron_path;
our $backup_command;
our $create_tar = "tar --create --listed-incremental ";
our $db_dump = "/usr/bin/mysqldump --add-drop-table";
our $dump = \$db_dump;
our $tar = \$create_tar;
our $cron_order = $$tar; #backing up files, datebases, or both, and set the order so databases are dumped first
our $location;
our $create_original;
#Initial Warning
print wrap("\n","","This script is designed to allow users of the (dv) Dedicated-Virtual Server an alternative option when making backups. Once completed, it should set up an rsync run by a cron which will back up site files and/or databases locally or remotely. It can be run to generate a single backup for all domains at once, or single domains.\n\n");
print "BEWARE:\n";
print wrap("","","This script will not delete backups either locally or on remote servers. You will need to monitor your disk space to ensure you do not exceed any limitations on your server.\n\n");
my $date_string = 'date +%b-%d-%Y_%H-%M';
chomp (our $date = `$date_string`);
print "\n\n" . `date +%b-%d-%Y_%H-%M` . "\n\n";
$profile = &create_profile;
&set_temp_dir;
our $backup_type = &select_type;
our $save_location = &get_save_location;
if ($location == 1){
$create_tar = "tar --create --listed-incremental=$save_path/mt-backup-$profile.bak --file=$save_path/mt-backup-$profile.\$DATE.tar " . $backup_path
}
if ($location == 2){
$create_tar = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.\$DATE.tar " . $backup_path;
}
$cron_order = $db_dump . $$tar;
our $when = &when;
unless ($backup_type eq 'files') {
my @dump_args = ("/usr/bin/mysqldump --add-drop-table -u $db{'user'} -p$db{'pass'} --database @db_list > $tmpdir/mt-backup-$profile.$date.sql");
my $doit = system(@dump_args);
if ($location == 1){
$create_original = "tar -P --create --listed-incremental=$save_path/mt-backup-$profile.bak --file=$save_path/mt-backup-$profile.$date.tar $backup_path && rm $tmpdir/mt-backup-$profile.$date.sql";
}
if ($location == 2){
if ($remote_login{'pass'} eq ""){
$create_original = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.$date.tar $backup_path && rm $tmpdir/mt-backup-$profile.$date.sql && $remote_type $tmpdir/mt-backup-$profile.bak $cron_connect:$remote_login{'path'} && $remote_type $tmpdir/mt-backup-$profile.$date.tar $cron_connect:$remote_login{'path'} && rm -f $tmpdir/mt-backup-$profile*";
}
else {
$create_original = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.$date.tar $backup_path && rm $tmpdir/mt-backup-$profile.$date.sql && /usr/bin/ftp -inv $remote_login{'host'}<<FTP\nuser $remote_login{'user'} $remote_login{'pass'}\ncd $remote_login{'path'}\nbin\nlcd $tmpdir\n put mt-backup-$profile.bak\nput mt-backup-$profile.$date.tar\nbye\nFTP\nrm -f $tmpdir/mt-backup-$profile*";
}
}
}
else {
if ($location == 1){
$create_original = "tar -P --create --listed-incremental=$save_path/mt-backup-$profile.bak --file=$save_path/mt-backup-$profile.$date.tar $backup_path && rm $tmpdir/mt-backup-$profile.$date.sql";
}
if ($location == 2){ if ($remote_login{'pass'} eq ""){
$create_original = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.$date.tar $backup_path && $remote_type $tmpdir/mt-backup-$profile.bak $cron_connect:$remote_login{'path'} && $remote_type $tmpdir/mt-backup-$profile.$date.tar $cron_connect:$remote_login{'path'} && rm -f $tmpdir/mt-backup-$profile*"; }
else {
$create_original = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.$date.tar $backup_path && /usr/bin/ftp -inv $remote_login{'host'}<<FTP\nuser $remote_login{'user'} $remote_login{'pass'}\ncd $remote_login{'path'}\nbin\nlcd $tmpdir\n put mt-backup-$profile.bak\nput mt-backup-$profile.$date.tar\nbye\nFTP\nrm -f $tmpdir/mt-backup-$profile*";
}
}
}
system($create_original);
print "\nNevermind this diagnostic information\nprofile: $profile\ncrondate: $crondate\ncron order: $cron_order\nremote type: $remote_type\ntmp dir: $tmpdir\ncron connect: $cron_connect\n";
$backup_path =~ s/$date/\$DATE/g;
print "\n\nThe current backup path is: $backup_path\n\n";
$create_tar = "tar -P --create --listed-incremental=$tmpdir/mt-backup-$profile.bak --file=$tmpdir/mt-backup-$profile.\$DATE.tar " . $backup_path;
if ($location == 1){
$create_tar =~ s/$tmpdir/$save_path/g;
}
$cron_order = $db_dump . $$tar;
open (CRON, ">/root/mt-backup-$profile");
if ($location == 1){
print CRON "#!/bin/bash\nDATE=`date +%b-%d-%Y_%H-%M`\n$cron_order && rm -f $tmpdir/mt-backup-$profile.\$DATE.sql\n";
}
system ("chmod 750 /root/mt-backup-$profile");
if ($location == 2){
if ($remote_login{'pass'} eq ""){
print CRON "#!/bin/bash\nDATE=`date +%b-%d-%Y_%H-%M`; $remote_type $cron_connect:$remote_login{'path'}/mt-backup-$profile.bak $tmpdir && $cron_order && rm -f $tmpdir/mt-backup-$profile.\$DATE.sql && $remote_type $tmpdir/mt-backup-$profile* $cron_connect:$remote_login{'path'} && rm -f $tmpdir/mt-backup-$profile*\n";
}
else {
print CRON "#!/bin/bash\nDATE=`date +%b-%d-%Y_%H-%M`; /usr/bin/ftp -inv $remote_login{'host'}<<FTP\nuser $remote_login{'user'} $remote_login{'pass'}\ncd $remote_login{'path'}\nbin\nlcd $tmpdir\nget mt-backup-$profile.bak\nbye\nFTP\n$cron_order && rm -f $tmpdir/mt-backup-$profile.\$DATE.sql && /usr/bin/ftp -inv $remote_login{'host'}<<FTP\nuser $remote_login{'user'} $remote_login{'pass'}\ncd $remote_login{'path'}\nbin\nlcd $tmpdir\nput mt-backup-$profile.bak\nput mt-backup-$profile.\$DATE.tar\nbye\nFTP\nrm -f $tmpdir/mt-backup-$profile.*";
}
}
close (CRON);
open (CRONTAB, '>>/etc/cron.d/mt-backup');
print CRONTAB "#<$profile>\n$crondate /root/mt-backup-$profile\n#</$profile>\n";
close (CRONTAB);
print "\n\nYour backups will now be taken automatically.\n\n";
sub create_profile {
print wrap("","","In order to prevent overwriting, this script will create a profile for each backup. Please give this backup profile a name: ");
chomp (our $profile = <STDIN>);
print "\n";
if (-e "/etc/cron.d/mt-backup"){
open (CRON, "/etc/cron.d/mt-backup") or my $cron_firstrun = 1;
unless ($cron_firstrun = 0){
my @cron_text = <CRON>;
close (CRON);
foreach (@cron_text){
if ($_ eq "#<$profile>\n"){
print "That name matches a current profile. ";
return &create_profile;
}
}
print "profilename = $profile\n";
return $profile;
}
}
else {print "profilename2 = $profile\n";return $profile};
}
sub set_temp_dir {
print "\nThe current path for temporary files is /tmp. Would you like to change that? ";
chomp (my $change_tmp = <STDIN>);
switch ($change_tmp){
case /y/i {print "Please enter the new temporary file path: ";
chomp (our $tmpdir = <STDIN>);
if ($tmpdir eq "") {print "That can't be empty."; return &set_temp_dir;}
print "\nYour temporary directory is now $tmpdir.\n";
}
case /n/i {print "Temp directory unchanged.\n";}
else {print "That is not a valid option\n"; &set_temp_dir;}
}
}
sub select_type {
print "Please enter the number for the type of back up you'd like.\n 1. Site files\n 2. Databases\n 3. Both\n";
chomp ($backup_type = <STDIN>);
switch ($backup_type) {
case 1 { print "This will only back up your site files.\n"; $backup_type = 'files'; &get_backup_path($backup_type);}
case 2 { print "This will only back up your databases.\n"; $backup_type = 'databases'; &get_backup_path($backup_type);}
case 3 { print "This will back up site files and databases.\n"; $backup_type = 'files and databases'; &get_backup_path($backup_type);}
else { print "That is not a valid option. "; &select_type;}
}
$yes = "Backing up.\n";
$correct_me = \&select_type;
&correct ($yes);
return $backup_type;
}
sub get_backup_path {
my $dberror;
my $dbc;
our %db = ();
my $db_query = 'SHOW DATABASES;'; #get only domains that are listed as active
switch ($_[0]) {
case "files" {
our $db_dump = "";
print "\n Current orders are: $cron_order\n\n";
print wrap("","","Please type the path to the directory you would like backed up. The default path to the website document root on the (dv) Dedicated-Virtual Server is /var/www/vhosts/\n");
chomp ($backup_path = <STDIN>);
$backup_path = '/var/www/vhosts' if ($backup_path eq "");
$yes = "Backing up the files at " . $backup_path;
print "This will back up $backup_type at the path $backup_path. "; $correct_me = \&get_backup_path; &correct($yes);
}
case "databases" {
$backup_path = "$tmpdir/mt-backup-$profile.$date.sql";
$cron_path = " $tmpdir/mt-backup-$profile.\$DATE.sql";
print "Is Plesk installed on this server? [y/n] ";
chomp (my $plesk = <STDIN>);
print "\n$plesk\n";
switch ($plesk) {
case m/y/i {
open (DBPASS, "/etc/psa/.psa.shadow") or die $!; #get db password
$db{'pass'} = <DBPASS>;
close (DBPASS);
chomp $db{'pass'};
$db{'user'} = 'admin';
$dbc = DBI->connect('DBI:mysql:host=localhost', $db{'user'}, $db{'pass'}) or $dberror = DBI->errstr . "\n";
$db_ref = $dbc->selectcol_arrayref($db_query);
my $listed = 0;
$dbc->disconnect;
print "These databases were found in Plesk.\n";
$db{'pass'} = '`cat /etc/psa/.psa.shadow`';
}
case m/n/i {
print "Please enter your database connection information.\nUsername: ";
$db{'user'} = <STDIN>;
chomp $db{'user'};
print "\nPassword: ";
$db{'pass'} = <STDIN>;
chomp $db{'pass'};
$dbc = DBI->connect('DBI:mysql:host=localhost', $db{'user'}, $db{'pass'}) or $dberror = DBI->errstr ."\n";
$db_ref = $dbc->selectcol_arrayref($db_query);
$dbc->disconnect;
}
else {return &get_backup_path($backup_type);}
}
foreach (@$db_ref) {
print "$_\n";
}
return &select_db(@$db_ref);
}
case "files and databases" {
print wrap ("","","Please type the path to the directory you would like backed up. The default path to the website document root on the (dv) Dedic
ated-Virtual Server is /var/www/vhosts/\n");
chomp ($backup_path = <STDIN>);
$backup_path = '/var/www/vhosts' if ($backup_path eq "");
$yes = "Backing up the files at " . $backup_path;
print "This will back up files at the path $backup_path. "; $correct_me = \&get_backup_path; &correct($yes);
$backup_path = $backup_path . " $tmpdir/mt-backup-$profile.$date.sql";
$cron_path = $backup_path . " $tmpdir/mt-backup-$profile.\$DATE.sql";
$backup_command = "tar --listed-incremental $profile.bak";
#databases
print "Is Plesk installed on this server? [y/n] ";
chomp (my $plesk = <STDIN>);
print "\n$plesk\n";
switch ($plesk) {
case m/y/i {
$db{'user'} = 'admin';
open (DBPASS, "/etc/psa/.psa.shadow") or die $!; #get db password
$db{'pass'} = <DBPASS>;
close (DBPASS);
chomp $db{'pass'};
$dbc = DBI->connect('DBI:mysql:host=localhost', $db{'user'}, $db{'pass'}) or $dberror = DBI->errstr . "\n";
$db_ref = $dbc->selectcol_arrayref($db_query);
my $listed = 0;
$dbc->disconnect;
print "These databases were found in Plesk.\n";
$db{'pass'} = '`cat /etc/psa/.psa.shadow`';
}
case m/n/i {
print "Please enter your database connection information.\nUsername: ";
$db{'user'} = <STDIN>;
chomp $db{'user'};
print "\nPassword: ";
$db{'pass'} = <STDIN>;
chomp $db{'pass'};
$dbc = DBI->connect('DBI:mysql:host=localhost', $db{'user'}, $db{'pass'}) or $dberror = DBI->errstr ."\n";
$db_ref = $dbc->selectcol_arrayref($db_query);
$dbc->disconnect;
}
else {return &get_backup_path($backup_type);}
}
foreach (@$db_ref) {
print "$_\n";
}
return &select_db(@$db_ref);
}
}
}
sub select_db {
print "Please type the exact database name as it appears above, or type ALL to back up all databases.\n";
$db_backup = <STDIN>;
chomp $db_backup;
switch ($db_backup) {
case "ALL" {
local $" = ", ";
$yes = "Backing up @_";
$db_backup = @$db_ref;
foreach (@$db_ref){push (@db_list, $_);}
}
case "" {print "It appears you entered a blank line. Please type in the database as it appears above.\n";}
else {
my $db_found = 0;
foreach (@$db_ref){
if ($_ eq $db_backup) {
print "$_.\n";
$db_found = 1;
}
}
if ($db_found == 0) {
print "Sorry, that database was not found. ";
return &select_db(@$db_ref);
}
else {
print "You\'ve entered: $db_backup. ";
$correct_me = \&select_db;
$yes = "Backing up $db_backup.";
return &correct ($yes);
}
}
}
return &db_backup_command(@db_list);
}
sub db_backup_command {
foreach (@_) {
print "$_\n";
}
$db_dump = "/usr/bin/mysqldump --add-drop-table -u $db{'user'} -p$db{'pass'} --databases @db_list > $tmpdir/mt-backup-$profile." . '$DATE.sql && ';
$cron_order = $db_dump . $$tar;
return $backup_path;
}
sub correct {
my $correct = 0;
print "Is this correct? [y/n] ";
chomp ($correct = <STDIN>);
switch ($correct) {
case /y/i {print "$_[0]\n";}
case /n/i {print "You indicated that was incorrect. "; return &$correct_me;}
else {print "That is not a valid option. Please type y for yes or n for no.\n"; &correct;}
}
}
sub get_save_location{
$location = "0";
print "\nDo you want to save the files on this server, or automatically transfer them to another server?\n 1. Local Server\n 2. Remote Server\n";
chomp ($location = <STDIN>);
switch ($location) {
case "1" {
$save_path = "/var/www/vhosts/backup/"; #$domain";
print "This will save the backup locally. The default path is $save_path. Would you like to change that path? [y/n]\n";
my $change_path = "";
$change_path = <STDIN>;
switch ($change_path) {
case /y/i {
print "Please type the path your backup should be saved to.\n";
chomp ($save_path = <STDIN>);
if ($save_path eq $tmpdir) { print wrap("\n","","Your backup directory cannot be the same as your temporary directory. Please select an appropriate backup location."); return &get_save_location;}
unless ($save_path eq "") {
print "You entered $save_path. ";
$yes = "Your $backup_type will be saved to $backup_path.\n"; $correct_me = \&get_save_location; correct ($yes);
}
else { print "That path is not valid."; &get_save_location;}
}
case /n/i { print "Your $backup_type will be saved to $save_path\n";}
else { print "Please indicate where you'd like your $backup_type saved.\n"; return &get_save_location;}
}
print "\nChecking your backup path.\n";
unless (-e $save_path){
print "That directory does not appear to exist on the server. Please select a new backup path"; return &get_save_location;}
}
case "2" {
print wrap("","",'While FTP is provided as an option, we strongly urge you to use rsync in order to transfer the file if the remote host offers it. This method is far more secure. You may also generate SSH keys, which allow you to connect securely without a password. Information on that can be found here: http://kb.mediatemple.net/questions/1626/') . "\n\n";
&remote_info;
}
else { print "That is not a valid option, please try again."; return &get_save_location; }
}
return $backup_path
}
sub remote_info{
our $remote_type;
print "If using rsync, please leave out the password. An SSH key will be required. ";
print "Please provide your log in information for the remote server.\n";
print "Hostname: ";
$remote_login{'host'} = <STDIN>;
chomp $remote_login{'host'};
print "\nUsername: ";
$remote_login{'user'} = <STDIN>;
chomp $remote_login{'user'};
print "\nPassword: ";
$remote_login{'pass'} = <STDIN>;
chomp $remote_login{'pass'};
print "\nRemote path: ";
$remote_login{'path'} = <STDIN>;
chomp $remote_login{'path'};
#connect to remote server to verify login info
if ($remote_login{'pass'} eq ""){
$remote_type = 'rsync --compress';
}
else { $remote_type = 'ftp'; }
&remote_connect($remote_type);
}
sub remote_connect{
print "\n\nRunning remote connect\n\n $_[0]\n\n";
$connect = 0;
switch ($_[0]) {
case 'ftp' {
$cron_connect = "$remote_login{'user'}:$remote_login{'pass'}\@$remote_login{'host'}";
print "Connecting to $remote_login{'host'} with username $remote_login{'user'} and password $remote_login{'pass'}";
my $remoteConnect = Net::FTP->new($remote_login{'host'}) or $connect = 1;
$remoteConnect->login($remote_login{'user'}, $remote_login{'pass'}) or $connect = 2;
switch ($connect) {
case 1 {print "Could not connect to $remote_login{'host'}."; &remote_info;}
case 2 {print "Access Denied. \nThe error received was: \n" . $remoteConnect->message; &remote_info;}
else {print "The FTP connection appears to have been successful.\n";}
}
$remoteConnect->cwd($remote_login{'path'}) or $connect = 3;
my $pwd = $remoteConnect->pwd();
if ($connect == 3) {print "The path to the folder you would like to upload to does not appear to be valid. The path entered was $remote_login{'path'} ", $remoteConnect->message;
print "Please select a new path.\n";
$remote_login{'path'} = <STDIN>;
&remote_connect;
}
else {print "The path to $remote_login{'path'} appears valid. I was able to enter the directory $pwd.\n";}
$remoteConnect->quit;
return $connect;
}
case 'rsync --compress' {
$cron_connect = "$remote_login{'user'}\@$remote_login{'host'}";
print "Connecting to $remote_login{'host'} using SSH keys with user $remote_login{'user'}. \n";
system ("touch backup_test.file");
print "Putting ";
if (my $rsyncput = system("$remote_type ./backup_test.file $cron_connect\:$remote_login{'path'}")){ $connect = 1;}
print "Getting ";
if (my $rsyncget = system("$remote_type $cron_connect:$remote_login{'path'}\/backup_test.file ./")){ $connect = 2};
switch ($connect) {
case 1 {print "It appears the file was unable to be put on the server. Please check your settings.\n"; &remote_info;}
case 2 {print "It appears the file was written to the server, but could not be retrieved.\n"; &remote_info;}
case 0 {print wrap ("","","The rsync appears to have been successful. If you received errors about a possible break in attempt, your DNS may be mis-configured. This should not be a fatal problem. Please check the remote server to confirm that the file \"backup_test.file\" exists there.\n");}
}
}
}
}
sub when{
our $day = "1";
our $day_of_week = "1";
our $day_of_month = "25";
$correct = 0;
print "When would you like the backup to run?\n1. Daily\n2. Weekly\n3. Monthly\n";
$day = <STDIN>;
chomp $day;
print "You entered $day\n";
switch ($day) {
case "1" {print "Your files will be backed up every day.\n"; $day = "daily"; $day_of_week = "*"; $day_of_month = "*";}
case "2" {
$day = "weekly";
print "Your files will be backed up once per week. Which day would you like them backed up on?\n";
print "1. Sunday \n2. Monday \n3. Tuesday \n4. Wednesday \n5. Thursday \n6. Friday \n7. Saturday\n";
$day_of_week = <STDIN>;
chomp $day_of_week;
$day_of_week = $day_of_week - 1;
my @days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
print "Backups will occur every $days[$day_of_week] ";
$day = "*"; $day_of_month = "*";
}
case "3" {
print "Your files will be backed up once per month.\n"; $day = "monthly";
print "What day of the month would you like the files backed up? ";
$day_of_month = <STDIN>;
chomp $day_of_month;
unless ($day_of_month =~ /\d{1,2}/) {print "\nDays of the month must always be a one or two digit number. "; return &when;}
if ($day_of_month > 31) {
print "That date is not valid.\n";
&when;
}
print "\n";
$day = "*"; $day_of_week = "*";
}
else {print "That is not a valid answer\n"; &when;}
}
&time($day_of_week, $day_of_month);
}
sub time {
print wrap ("","","What time of day should this be done? Please format your answer as HHMM. This will be done at the server time. The time now is ") .
localtime() . "\n";
our $time = <STDIN>;
chomp $time;
$time =~ s/\://;
unless ($time =~ /\d{4}/) {print "That is not a valid time. "; return &time;}
our $hour = substr($time, 0,2);
if ($hour > 23){
print "That time is invalid, please enter a new time.\n";
&time;
}
print "Hour $hour\n";
our $minute = substr($time, 2,2);
if ($minute > 60){
print "That time is invalid, please enter a new time.\n";
&time;
}
print "Minute $minute\n";
our $crondate = "$minute $hour $_[1] * $_[0] root";
return $crondate;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment