Backup restoration and encryption
gitea/vn-vmware/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2020-05-22 19:00:26 +02:00
parent a39d7db316
commit 93b90cd24c
4 changed files with 81 additions and 8 deletions

View File

@ -8,15 +8,21 @@ log_file => '/var/log/vn-vmware.log',
datacenter => 'datacenter1',
# The datastore name where backups must be stored
backup_datastore => 'backups',
backup_datastore => 'backup',
# The local directory where backups datastore folder is mounted
# If it's mounted via NFS you have to disable caching for the mount
local_backup_dir => '/mnt/vm-backups',
local_backup_dir => '/mnt/backup',
# Directory where backups will be restored
restore_dir => '/mnt/backup',
# Number of processes used by pigz to compress backups
pigz_processes => 1,
# Whether to encrypt backups using gpg with passed passphrase file
passphrase_file => '/etc/vn-vmware/passphrase.gpg',
# The default rotation to use if none is specified on job
rotation => 'lastMonth',

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
vn-vmware (1.1.18) stable; urgency=low
vn-vmware (1.1.19) stable; urgency=low
* Initial Release.

1
debian/control vendored
View File

@ -10,6 +10,7 @@ Vcs-Git: https://git.verdnatura.es/vn-vmware
Package: vn-vmware
Architecture: all
Depends: perl, pigz, libsys-cpu-perl
Suggests: gpg
Section: misc
Priority: optional
Description: Maintenance scripts for VMWare

View File

@ -56,7 +56,7 @@ foreach my $vi_config_file (@vi_config_files) {
my %opts = (
'operation' => {
type => "=s",
help => "Operation to perform: none, backup-job, clone-job, backup, rotate, clone, snapshot, migrate",
help => "Operation to perform: none, backup-job, clone-job, backup, rotate, restore, clone, snapshot, migrate",
required => true
},
'job' => {
@ -68,6 +68,10 @@ my %opts = (
variable => "VM_NAME",
help => "Name of the virtual machine"
},
'passphrase-file' => {
type => "=s",
help => "Encrypt backup with passed passphrase file using gpg"
},
'rotation-days' => {
type => "=i",
help => "Rotation days for backups",
@ -82,6 +86,15 @@ my %opts = (
type => "=s",
help => "Regular expression used to archive and exclude backups from rotation"
},
'backup-file' => {
type => "=s",
help => "The path to the backup file that will be restored"
},
'restore-dir' => {
type => "=s",
help => "The backup directory where backup will be restored",
default => '.'
},
'dst-name' => {
type => "=s",
help => "Name of the new virtual machine"
@ -162,9 +175,12 @@ my $server = Opts::get_option('server');
my $operation = Opts::get_option('operation');
my $job = Opts::get_option('job');
my $vm_name = Opts::get_option('vm-name');
my $passphrase_file = Opts::get_option('passphrase-file');
my $rotation_days = Opts::get_option('rotation-days');
my $rotation_count = Opts::get_option('rotation-count');
my $archive_regex = Opts::get_option('archive-regex');
my $backup_file = Opts::get_option('backup-file');
my $restore_dir = Opts::get_option('restore-dir');
my $dst_name = Opts::get_option('dst-name');
my $dst_host = Opts::get_option('dst-host');
my $dst_datastore = Opts::get_option('dst-datastore');
@ -181,12 +197,16 @@ my $test = Opts::option_is_set('test');
my $snapshot_name = Opts::get_option('snapshot-name');
my $snapshot_desc = Opts::get_option('snapshot-desc');
if (!defined ($passphrase_file) && exists $config{passphrase_file}) {
$passphrase_file = $config{passphrase_file};
}
my $vm;
my $log_fh;
my $archive_fn;
my $backup_disks;
my $time_pattern = '%Y-%m-%d_%H-%M';
my $local_backup_dir = $config{local_backup_dir};
my $archive_fn = sub { return false; };
sub stringify_message {
my ($message) = @_;
@ -281,6 +301,9 @@ sub main {
when ('rotate') {
rotate_backup();
}
when ('restore') {
restore_backup();
}
when ('clone') {
open_machine();
clone_machine();
@ -583,14 +606,20 @@ sub backup_machine() {
}
$pigz_processes = max(1, $pigz_processes);
my $tar_command = "tar -I \"pigz -p $pigz_processes\" -cf $tar_file -C $local_tmp_dir .";
my $tar_command = "tar -I \"pigz -p $pigz_processes\" -c -C $local_tmp_dir .";
if (defined($passphrase_file)) {
my $gpg_command = "gpg -c --passphrase-file \"$passphrase_file\" --batch --yes -o $tar_file.gpg";
$tar_command = "$tar_command | $gpg_command";
} else {
$tar_command = "$tar_command -f $tar_file";
}
log_message "Compressing with Gzip (using $pigz_processes processes) to TAR file.";
log_message $tar_command;
unless ($test) {
my $tar_status = system($tar_command);
unless ($tar_status == 0) {
die "An error occurred when trying to compress '$vm_name' machine files.";
}
@ -631,7 +660,7 @@ sub rotate_backup() {
log_message "Rotating '$vm_name' backups.";
my $local_dir = "$local_backup_dir/$vm_name";
my $regex = qr/^\Q$vm_name\E_(\d{4}-\d{2}-\d{2}_\d{2}-\d{2})\.tar\.gz$/;
my $regex = qr/^\Q$vm_name\E_(\d{4}-\d{2}-\d{2}_\d{2}-\d{2})/;
my $now = Time::Piece->new;
my @archive_files;
@ -723,6 +752,43 @@ sub rotate_backup() {
closedir($dh);
}
sub restore_backup() {
log_message "Restoring backup file '$backup_file'.";
unless (-e $backup_file) {
die "Backup file doesn't exists: $backup_file"
}
if (!defined ($restore_dir) && exists $config{restore_dir}) {
$restore_dir = $config{restore_dir};
}
unless (defined($restore_dir)) {
die "Restore directory not defined."
}
unless (-e $restore_dir) {
die "Restore directory doesn't exists: $restore_dir"
}
my $tar_command = "tar xz -C \"$restore_dir\"";
if ($backup_file =~ qr/\.gpg$/) {
my $gpg_command = "gpg --decrypt --passphrase-file \"$passphrase_file\" --batch --yes \"$backup_file\"";
$tar_command = "$gpg_command | $tar_command";
} else {
$tar_command = "$tar_command -f \"$backup_file\"";
}
log_message $tar_command;
unless ($test) {
my $tar_status = system($tar_command);
unless ($tar_status == 0) {
die "An error occurred restoring backup $backup_file";
}
}
log_message "Backup restored successfully.";
}
sub clone_machine {
log_message "Cloning '$vm_name' to '$dst_name'.";
log_message "Doing some previous checkings.";