📄 mmm_restore
字号:
#!/usr/bin/env perl# Use mandatory external modulesuse strict;use Cwd;use File::Basename;use Data::Dumper;use POSIX;use Config;use Getopt::Long;# Determine installation dir nameour $SELF_DIR = dirname(dirname(Cwd::abs_path(__FILE__)));# Include parts of the systemrequire $SELF_DIR . '/lib/config.pm';require $SELF_DIR . '/lib/log.pm';require $SELF_DIR . '/lib/db.pm';#-----------------------------------------------------------------#Parse optionsmy $config_file = "mmm_lvm.conf";my $backup_dir;my $restore_mode = "single-single";my $version = '';my $override_destdir = '';my $skip_mysqld = 0;my $dry_run = 0;GetOptions("config=s" => \$config_file, "backup-dir=s" => \$backup_dir, "mode=s" => \$restore_mode, "data-dir=s" => \$override_destdir, "version=s" => \$version, "dry-run" => \$dry_run);$skip_mysqld = 1 if ($restore_mode eq 'data-only');my @known_modes = qw( data-only single-single slave-single master-single master-slave slave-slave);#-----------------------------------------------------------------# Read config fileour $config = ReadConfig($config_file);# Parse clone dirsmy @clone_dirs : shared = split(/\s*\,\s*/, $config->{clone_dirs});$config->{clone_dirs} = \@clone_dirs;# Override datadir$config->{dest_dir} = $override_destdir if ($override_destdir ne '');# Check bak dirPrintUsage("Invalid backup directory!") unless (CheckBackupDir($backup_dir));# Check modePrintUsage("Invalid restore mode!") unless (grep(/^$restore_mode$/, @known_modes));# Print infoLogNotice("Backup directory: '$backup_dir'");LogNotice("DataDir: '$config->{dest_dir}'");LogNotice("Dry Run: " . ($dry_run ? 'yes' : 'no'));LogNotice("Incremental Version: $version") if ($version ne '');LogNotice("Dirs to restore: '" . join(', ', @clone_dirs) . "'");LogNotice("Restore mode: '$restore_mode'");LogNotice("Skip mysqld operations: " . ($skip_mysqld ? 'yes' : 'no'));#-----------------------------------------------------------------# Create config shortcutsmy $this = $config->{this};my $host = $config->{host}->{$this};LogNotice("-----------------------------------------------------------------");#Loading status info from data dirmy $status = {};my $res = LoadStatusInfo(\$status);unless ($res =~ /^OK/) { LogError("Error: Can't load status info from backup data dir: $res"); exit(1);}LogDebug("Status: " . Dumper($status));my $backup_method = $status->{copy_method};my $copy_method = $config->{copy_method}->{$backup_method};unless ($copy_method) { LogError("Unsupported backup method!"); exit(0);} LogNotice("-----------------------------------------------------------------");if ($version eq 'list') { ListIncrementalVersions(); exit(0);}if ($dry_run) { LogNotice("Exiting - Dry Run..."); exit(0);}LogNotice("-----------------------------------------------------------------");# Check local mysql process and shutdown it if it is runningunless ($skip_mysqld) { my $res = ShutdownLocalMysql(); unless ($res =~ /^OK/) { LogError("Can't stop local mysql daemon: $res"); exit(1); }} else { LogNotice("Skipping MySQL operations...");}LogNotice("-----------------------------------------------------------------");my $res = system("mkdir -p $config->{dest_dir}");if ($res) { LogError("Can't access datadir: $!"); exit(1);}if ($version ne '') { my $res = RestoreDataFilesFromIncremental($version); unless ($res =~ /^OK/) { LogError("Error: Can't restore data files from incremental backup: $res"); exit(1); }} else { my $res = RestoreDataFiles(); unless ($res =~ /^OK/) { LogError("Error: Can't copy data files from backup: $res"); exit(1); }}LogNotice("-----------------------------------------------------------------");# Cleaning dump from master.info and binary logsmy $res = CleanupDataDir();unless ($res =~ /^OK/) { LogError("Error: Can't cleanup data dir: $res"); exit(1);}LogNotice("-----------------------------------------------------------------");# Run local local mysql processunless ($skip_mysqld) { my $res = StartLocalMysql(); unless ($res =~ /^OK/) { LogError("Can't start local mysql daemon: $res"); exit(1); }} else { LogNotice("Not starting mysqld - skipped...");}LogNotice("-----------------------------------------------------------------");LogNotice("Setting up replication if needed...");unless ($skip_mysqld) { my $res = SetupReplication(); unless ($res =~ /^OK/) { LogError("Replication setup error: $res"); exit(1); }} else { LogNotice("Replication setup skipped!");}LogNotice("-----------------------------------------------------------------");LogNotice("Restore process done!\n\n\n");exit(0);#-----------------------------------------------------------------sub PrintUsage($) { my $error = shift; print "ERROR: $error\n\n"; print "Usage: $0 [--config <config file>] --backup-dir <dir> [--mode <mode>] [--data-dir <dir>] [--version <version | list>] --dry-run\n"; print "Where:\n"; print " Backup Dir: directory where backup resides\n"; print " Data Dir: datadir of local mysql installation\n"; print " Mode: " . join(', ', @known_modes) . "\n"; print " Version: \n"; print " - when run with 'list' parameter, displays available versions of incremental backups\n"; print " - if version is specified, tries to restore backup for specified version of datadir\n"; print " Dry-run: check everything and exit without any changes\n\n"; exit(1);}#-----------------------------------------------------------------sub CheckBackupDir($) { my $dir = shift; return 0 unless $dir; print "Checking Directory ('$dir'):\n"; print "Check name..."; return 0 unless ($dir); print "OK\n"; print "Check permissions..."; return 0 unless (-d $dir && -r $dir && -x $dir); print "OK\n"; print "Check if empty..."; return 0 unless (scalar(glob("$dir/*"))); print "OK\n"; print "Check _mmm dir..."; return 0 unless (-d "$dir/_mmm" && -r "$dir/_mmm" && -x "$dir/_mmm"); print "OK\n"; print "Check _mmm/status.txt file..."; return 0 unless (-f "$dir/_mmm/status.txt" && -r "$dir/_mmm/status.txt"); print "OK\n"; print "Check _mmm/copy_method.txt file..."; return 0 unless (-f "$dir/_mmm/copy_method.txt" && -r "$dir/_mmm/copy_method.txt"); print "OK\n"; print "\n\n"; return 1;}#-----------------------------------------------------------------sub LoadStatusInfo($) { my $status_info = shift; LogDebug("Loading status info..."); my $status_file = $backup_dir . "/_mmm/status.txt"; unless (-f $status_file && -r $status_file) { return "ERROR: Status file ($status_file) does not exists or is not readable!"; } my $status_data = `cat $status_file`; my $VAR1; eval($status_data); if ($@) { return "ERROR: Can't parse status info: $@"; } $$status_info = $VAR1; my $method_file = $backup_dir . "/_mmm/copy_method.txt"; chomp(my $copy_method = `cat $method_file`); $$status_info->{copy_method} = $copy_method; return "OK!";}#-----------------------------------------------------------------sub ListIncrementalVersions() { unless ($copy_method->{incremental} eq 'yes') { LogError("Invalid backup directory for incremental operations"); exit(0); } #FIXME: Need to add support for other incremental methods except rdiff if ($backup_method ne 'rdiff') { LogError('Only rdiff backup method supports version lists now. Sorry.'); exit(0); } # List versions my $res = open(RDIFF, "rdiff-backup --parsable-output -l '$backup_dir'|"); unless ($res) { LogError("Can't start rdiff-backup to read versions info from backup!"); exit(1); } print "Following backup versions are available:\n"; print " Version | Date\n"; print "-----------|---------------------\n"; while(<RDIFF>) { chomp; my ($ts, $type) = split /\s+/; print("$ts | " . localtime($ts) . "\n"); } close(RDIFF);}#-----------------------------------------------------------------sub ShutdownLocalMysql() { my $pid_file = $host->{pid_file}; # Check pid file if ($pid_file eq "") { LogWarn("Warining: Can't find pid-file option in config file."); $pid_file = "/var/run/mysqld/mysqld.pid";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -