# Copyright 1999-2017. Parallels IP Holdings GmbH. All Rights Reserved. package Storage::ArchiveStorage; use strict; use warnings; use File::Basename qw(basename); use IPC::Run; use HelpFuncs; use Logging; use Storage::Storage; use vars qw|@ISA|; @ISA = qw|Storage::Storage|; sub _init { my ($self, %options) = @_; $self->SUPER::_init(%options); $self->{exportDir} = $options{'export-dir'}; $self->{ftp} = $options{'ftp'}; $self->{sessionPath} = $options{'session-path'}; $self->{verbose} = $options{'verbose'}; $self->{cmd} = undef; $self->{cmdInput} = ''; if ($self->{sessionPath}) { $self->{cmdOutputPath} = $self->{sessionPath} . '/export-dump-result'; } else { $self->{cmdOutputPath} = HelpFuncs::mktemp(AgentConfig::getBackupTmpDir() . '/pmm-export-dump-result-XXXXXXXX'); } $self->{keepLocalBackup} = $options{'keep-local-backup'}; Logging::debug("-" x 60); Logging::debug("ARCHIVE storage initialized."); Logging::debug("Base directory: $self->{output_dir}"); Logging::debug("Space reserved: $self->{space_reserved}"); Logging::debug("Gzip bundles: " . ($self->{gzip_bundle} ? "yes" : "no")); Logging::debug("Bundle split size: " . ($self->{split_size} || "do not split")); Logging::debug("-" x 60); $self->reserveSpace(); } sub DESTROY { my $self = shift; unlink($self->{cmdOutputPath}); $self->SUPER::DESTROY(); } sub finishExport { my $self = shift; my $mainDumpFile = $self->getMainDumpXmlRelativePath(); if ($mainDumpFile) { my $mainDumpFileName = basename($mainDumpFile); Logging::debug("Add file $mainDumpFileName to archive"); $self->{cmdInput} .= "$mainDumpFileName\n"; eval { IPC::Run::pump($self->_getCmd()); }; if ($@) { Logging::debug($@); } } eval { $self->_finishCmd(); }; if ($@) { if ($self->{keepLocalBackup}) { Logging::warning($@, undef, 'step' => 'upload-to-ftp'); } else { die($@); } } } sub writeDiscovered{ my $self = shift; $self->_writeDiscovered(@_); } sub moveFileToDiscovered { my $self = shift; $self->_moveFileToDiscovered(@_); } sub addTar { my $self = shift; my ($ret) = @{$self->_addTar(@_)}; return $ret; } sub onVolumeCreate() { my ($self, $destDir, $fileName) = @_; my $file; eval { my $dumpStorage = $self->{mainDumpRootPath} ? sprintf('%s/%s', $self->{output_dir}, $self->{mainDumpRootPath}) : $self->{output_dir}; my $destDirRelativePath = substr($destDir, length($dumpStorage)); $destDirRelativePath =~ s/^\/+//; $file = $destDirRelativePath ? sprintf('%s/%s', $destDirRelativePath, $fileName) : $fileName; Logging::debug("Add file $file to archive"); $self->{cmdInput} .= "$file\n"; IPC::Run::pump($self->_getCmd()); }; if ($@) { Logging::debug($@); if (!$self->{keepLocalBackup}) { Logging::error(sprintf('Unable to upload the archive %s to the FTP storage: %s', $file, $self->_getCmdOutput()), undef, 'step' => 'upload-to-ftp'); if ($self->{sessionPath}) { Logging::serializeXmlLog("$self->{sessionPath}/migration.result"); } exit(0); } } } sub _getCmd { my $self = shift; if (!$self->{cmd}) { my $command = [AgentConfig::pmmRasBin(), '--export-dump-as-file']; if ($self->{ftp}) { $ENV{'DUMP_STORAGE_PASSWD'} = $self->{ftp}->{password}; push(@{$command}, '--dump-file-specification', sprintf('%s/%s', HelpFuncs::getStorageUrlFromFtpSettings($self->{ftp}), $self->{exportFileName})); push(@{$command}, '--use-ftp-passive-mode') if exists($self->{ftp}->{'passive'}); } else { push(@{$command}, '--dump-file-specification', sprintf('%s/%s', $self->{exportDir}, $self->{exportFileName})); } push(@{$command}, '--dump-storage', sprintf('%s/%s', $self->{output_dir}, $self->{mainDumpRootPath})); push(@{$command}, '--split-size', $self->{split_size}) if $self->{split_size}; push(@{$command}, '--session-path', $self->{sessionPath}) if $self->{sessionPath}; push(@{$command}, '--debug', '--verbose') if $self->{verbose}; Logging::debug('Start: ' . join(' ', @{$command})); $self->{cmd} = IPC::Run::start($command, \$self->{cmdInput}, "1>$self->{cmdOutputPath}", '2>/dev/null'); } return $self->{cmd}; } sub _finishCmd { my $self = shift; if ($self->{cmd}) { my @createdVolumes = (); eval { $self->{cmd}->finish(); }; if ($@) { Logging::debug($@); } if ($@ || $self->{cmd}->result()) { die(sprintf('Unable to upload the backup to the FTP storage: %s', $self->_getCmdOutput())); } my $cmdOutput = $self->_getCmdOutput(); @createdVolumes = split("\n", $cmdOutput) if $cmdOutput; $self->{cmd} = undef; $self->{cmdInput} = ''; unlink($self->{cmdOutputPath}); $self->{createdVolumes} = \@createdVolumes; } } sub _getCmdOutput { my $self = shift; my $cmdOutput = ''; if (open(RESULT, $self->{cmdOutputPath})) { while () { $cmdOutput .= $_; } close RESULT; } return $cmdOutput; } 1;