mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-01-18 04:58:51 +02:00
Working on more robust file functions.
This commit is contained in:
parent
85f591f801
commit
0338369193
@ -34,6 +34,7 @@ IPC::System::Simple
|
||||
Net::OpenSSH
|
||||
JSON
|
||||
IPC::Open3
|
||||
Digest::SHA
|
||||
|
||||
## release notes
|
||||
|
||||
|
145
bin/pg_backrest_command.pl
Executable file
145
bin/pg_backrest_command.pl
Executable file
@ -0,0 +1,145 @@
|
||||
#!/usr/bin/perl
|
||||
####################################################################################################################################
|
||||
# pg_backrest_command.pl - Simple Postgres Backup and Restore Command Helper
|
||||
####################################################################################################################################
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings;
|
||||
use english;
|
||||
|
||||
use File::Basename;
|
||||
use Getopt::Long;
|
||||
use Carp;
|
||||
|
||||
use lib dirname($0) . '/..';
|
||||
use pg_backrest_utility;
|
||||
use pg_backrest_file;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants - basic operations that are allowed in backrest command
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
OP_LIST => "list",
|
||||
OP_EXISTS => "exists",
|
||||
OP_HASH => "hash",
|
||||
OP_REMOVE => "remove",
|
||||
OP_MANIFEST => "manifest"
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# Command line parameters
|
||||
####################################################################################################################################
|
||||
my $bIgnoreMissing = false; # Ignore errors due to missing file
|
||||
my $strExpression = undef; # Expression to use for filtering
|
||||
my $strSort = undef; # Sort order (undef = forward)
|
||||
|
||||
GetOptions ("ignore-missing" => \$bIgnoreMissing,
|
||||
"expression=s" => \$strExpression,
|
||||
"sort=s" => \$strSort)
|
||||
or die("Error in command line arguments\n");
|
||||
|
||||
####################################################################################################################################
|
||||
# START MAIN
|
||||
####################################################################################################################################
|
||||
# Turn off logging
|
||||
log_level_set(OFF, OFF);
|
||||
|
||||
# Get the operation
|
||||
my $strOperation = $ARGV[0];
|
||||
|
||||
# Validate the operation
|
||||
if (!defined($strOperation))
|
||||
{
|
||||
confess &log(ERROR, "operation is not defined");
|
||||
}
|
||||
|
||||
if ($strOperation ne OP_LIST &&
|
||||
$strOperation ne OP_EXISTS &&
|
||||
$strOperation ne OP_HASH &&
|
||||
$strOperation ne OP_REMOVE &&
|
||||
$strOperation ne OP_MANIFEST)
|
||||
{
|
||||
confess &log(ERROR, "invalid operation ${strOperation}");
|
||||
}
|
||||
|
||||
# Create the file object
|
||||
my $oFile = pg_backrest_file->new();
|
||||
|
||||
####################################################################################################################################
|
||||
# LIST Command
|
||||
####################################################################################################################################
|
||||
if ($strOperation eq OP_LIST)
|
||||
{
|
||||
my $strPath = $ARGV[1];
|
||||
|
||||
if (!defined($strPath))
|
||||
{
|
||||
confess "path must be specified for list operation";
|
||||
}
|
||||
|
||||
my $bFirst = true;
|
||||
|
||||
foreach my $strFile ($oFile->list(PATH_ABSOLUTE, $strPath, $strExpression, $strSort))
|
||||
{
|
||||
$bFirst ? $bFirst = false : print "\n";
|
||||
|
||||
print $strFile;
|
||||
}
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# EXISTS Command
|
||||
####################################################################################################################################
|
||||
if ($strOperation eq OP_EXISTS)
|
||||
{
|
||||
my $strFile = $ARGV[1];
|
||||
|
||||
if (!defined($strFile))
|
||||
{
|
||||
confess "filename must be specified for exist operation";
|
||||
}
|
||||
|
||||
print $oFile->exists(PATH_ABSOLUTE, $strFile) ? "Y" : "N";
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# HASH Command
|
||||
####################################################################################################################################
|
||||
if ($strOperation eq OP_HASH)
|
||||
{
|
||||
my $strFile = $ARGV[1];
|
||||
|
||||
if (!defined($strFile))
|
||||
{
|
||||
confess "filename must be specified for hash operation";
|
||||
}
|
||||
|
||||
print $oFile->hash(PATH_ABSOLUTE, $strFile);
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# REMOVE Command
|
||||
####################################################################################################################################
|
||||
if ($strOperation eq OP_REMOVE)
|
||||
{
|
||||
my $strFile = $ARGV[1];
|
||||
|
||||
if (!defined($strFile))
|
||||
{
|
||||
confess "Filename must be specified for remove operation";
|
||||
}
|
||||
|
||||
print $oFile->remove(PATH_ABSOLUTE, $strFile, undef, $bIgnoreMissing) ? "Y" : "N";
|
||||
|
||||
exit 0;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
[global:command]
|
||||
backrest_command=
|
||||
#compress=pigz --rsyncable --best --stdout %file% # Ubuntu Linux
|
||||
compress=/usr/bin/gzip --stdout %file%
|
||||
decompress=/usr/bin/gzip -dc %file%
|
||||
|
@ -230,6 +230,7 @@ if ($strOperation eq OP_ARCHIVE_GET)
|
||||
strBackupUser => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_USER),
|
||||
strBackupHost => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST),
|
||||
strBackupPath => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
strCommand => $0,
|
||||
strCommandDecompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, true)
|
||||
);
|
||||
|
||||
@ -308,6 +309,7 @@ if ($strOperation eq OP_ARCHIVE_PUSH || $strOperation eq OP_ARCHIVE_PULL)
|
||||
strBackupUser => config_load($strSection, CONFIG_KEY_USER),
|
||||
strBackupHost => config_load($strSection, CONFIG_KEY_HOST),
|
||||
strBackupPath => config_load($strSection, CONFIG_KEY_PATH, true),
|
||||
strCommand => $0,
|
||||
strCommandChecksum => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_CHECKSUM, $bChecksum),
|
||||
strCommandCompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_COMPRESS, $bCompress),
|
||||
strCommandDecompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, $bCompress)
|
||||
@ -378,6 +380,7 @@ if ($strOperation eq OP_ARCHIVE_PUSH || $strOperation eq OP_ARCHIVE_PULL)
|
||||
strBackupUser => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_USER),
|
||||
strBackupHost => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST),
|
||||
strBackupPath => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
strCommand => $0,
|
||||
strCommandChecksum => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_CHECKSUM, $bChecksum),
|
||||
strCommandCompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_COMPRESS, $bCompress),
|
||||
strCommandDecompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, $bCompress),
|
||||
@ -418,6 +421,7 @@ if ($strOperation eq OP_ARCHIVE_PUSH || $strOperation eq OP_ARCHIVE_PULL)
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => false,
|
||||
strBackupPath => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
strCommand => $0,
|
||||
strCommandChecksum => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_CHECKSUM, $bChecksum),
|
||||
strCommandCompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_COMPRESS, $bCompress),
|
||||
strCommandDecompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, $bCompress),
|
||||
@ -504,6 +508,7 @@ my $oFile = pg_backrest_file->new
|
||||
strBackupPath => config_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
strDbUser => config_load(CONFIG_SECTION_STANZA, CONFIG_KEY_USER),
|
||||
strDbHost => config_load(CONFIG_SECTION_STANZA, CONFIG_KEY_HOST),
|
||||
strCommand => $0,
|
||||
strCommandChecksum => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_CHECKSUM, $bChecksum),
|
||||
strCommandCompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_COMPRESS, $bCompress),
|
||||
strCommandDecompress => config_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, $bCompress),
|
||||
|
@ -13,12 +13,13 @@ use Net::OpenSSH;
|
||||
use IPC::Open3;
|
||||
use File::Basename;
|
||||
use IPC::System::Simple qw(capture);
|
||||
use Digest::SHA;
|
||||
|
||||
use lib dirname($0);
|
||||
use pg_backrest_utility;
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw(PATH_DB PATH_DB_ABSOLUTE PATH_BACKUP PATH_BACKUP_ABSOLUTE PATH_BACKUP_CLUSTER PATH_BACKUP_TMP PATH_BACKUP_ARCHIVE);
|
||||
our @EXPORT = qw(PATH_ABSOLUTE PATH_DB PATH_DB_ABSOLUTE PATH_BACKUP PATH_BACKUP_ABSOLUTE PATH_BACKUP_CLUSTER PATH_BACKUP_TMP PATH_BACKUP_ARCHIVE);
|
||||
|
||||
# Extension and permissions
|
||||
has strCompressExtension => (is => 'ro', default => 'gz');
|
||||
@ -26,6 +27,7 @@ has strDefaultPathPermission => (is => 'bare', default => '0750');
|
||||
has strDefaultFilePermission => (is => 'ro', default => '0640');
|
||||
|
||||
# Command strings
|
||||
has strCommand => (is => 'bare');
|
||||
has strCommandChecksum => (is => 'bare');
|
||||
has strCommandCompress => (is => 'bare');
|
||||
has strCommandDecompress => (is => 'bare');
|
||||
@ -55,11 +57,21 @@ has bNoCompression => (is => 'bare');
|
||||
has strStanza => (is => 'bare');
|
||||
has iThreadIdx => (is => 'bare');
|
||||
|
||||
####################################################################################################################################
|
||||
# COMMAND Error Constants
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
COMMAND_ERR_FILE_MISSING => 1,
|
||||
COMMAND_ERR_FILE_READ => 2
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# PATH_GET Constants
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
PATH_ABSOLUTE => 'absolute',
|
||||
PATH_DB => 'db',
|
||||
PATH_DB_ABSOLUTE => 'db:absolute',
|
||||
PATH_BACKUP => 'backup',
|
||||
@ -78,14 +90,12 @@ sub BUILD
|
||||
my $self = shift;
|
||||
|
||||
# Make sure the backup path is defined
|
||||
if (!defined($self->{strBackupPath}))
|
||||
if (defined($self->{strBackupPath}))
|
||||
{
|
||||
confess &log(ERROR, "common:backup_path undefined");
|
||||
# Create the backup cluster path
|
||||
$self->{strBackupClusterPath} = $self->{strBackupPath} . "/" . $self->{strStanza};
|
||||
}
|
||||
|
||||
# Create the backup cluster path
|
||||
$self->{strBackupClusterPath} = $self->{strBackupPath} . "/" . $self->{strStanza};
|
||||
|
||||
# Create the ssh options string
|
||||
if (defined($self->{strBackupHost}) || defined($self->{strDbHost}))
|
||||
{
|
||||
@ -139,15 +149,14 @@ sub clone
|
||||
strCompressExtension => $self->{strCompressExtension},
|
||||
strDefaultPathPermission => $self->{strDefaultPathPermission},
|
||||
strDefaultFilePermission => $self->{strDefaultFilePermission},
|
||||
strCommand => $self->{strCommand},
|
||||
strCommandChecksum => $self->{strCommandChecksum},
|
||||
strCommandCompress => $self->{strCommandCompress},
|
||||
strCommandDecompress => $self->{strCommandDecompress},
|
||||
strCommandCat => $self->{strCommandCat},
|
||||
strCommandManifest => $self->{strCommandManifest},
|
||||
# oDbSSH => $self->{strDbSSH},
|
||||
strDbUser => $self->{strDbUser},
|
||||
strDbHost => $self->{strDbHost},
|
||||
# oBackupSSH => $self->{strBackupSSH},
|
||||
strBackupUser => $self->{strBackupUser},
|
||||
strBackupHost => $self->{strBackupHost},
|
||||
strBackupPath => $self->{strBackupPath},
|
||||
@ -223,6 +232,12 @@ sub path_get
|
||||
confess &log(ASSERT, "temp file not supported on path " . $strType);
|
||||
}
|
||||
|
||||
# Get absolute path
|
||||
if ($strType eq PATH_ABSOLUTE)
|
||||
{
|
||||
return $strFile;
|
||||
}
|
||||
|
||||
# Get absolute db path
|
||||
if ($strType eq PATH_DB_ABSOLUTE)
|
||||
{
|
||||
@ -760,47 +775,73 @@ sub file_copy
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# FILE_HASH_GET
|
||||
# HASH
|
||||
####################################################################################################################################
|
||||
sub file_hash_get
|
||||
sub hash
|
||||
{
|
||||
my $self = shift;
|
||||
my $strPathType = shift;
|
||||
my $strFile = shift;
|
||||
my $strHashType = shift;
|
||||
|
||||
# For now this operation is not supported remotely. Not currently needed.
|
||||
if ($self->is_remote($strPathType))
|
||||
{
|
||||
confess &log(ASSERT, "remote operation not supported");
|
||||
}
|
||||
|
||||
if (!defined($self->{strCommandChecksum}))
|
||||
{
|
||||
confess &log(ASSERT, "\$strCommandChecksum not defined");
|
||||
}
|
||||
|
||||
my $strHash;
|
||||
my $strErrorPrefix = "File->hash";
|
||||
my $bRemote = $self->is_remote($strPathType);
|
||||
my $strPath = $self->path_get($strPathType, $strFile);
|
||||
my $strCommand;
|
||||
|
||||
if (-e $strPath)
|
||||
&log(TRACE, "${strErrorPrefix}: " . ($bRemote ? "remote" : "local") . " ${strPathType}:${strPath}");
|
||||
|
||||
if ($bRemote)
|
||||
{
|
||||
$strCommand = $self->{strCommandChecksum};
|
||||
$strCommand =~ s/\%file\%/${strPath}/g;
|
||||
}
|
||||
elsif (-e $strPath . ".$self->{strCompressExtension}")
|
||||
{
|
||||
$strCommand = $self->{strCommandDecompress};
|
||||
$strCommand =~ s/\%file\%/${strPath}/g;
|
||||
$strCommand .= " | " . $self->{strCommandChecksum};
|
||||
$strCommand =~ s/\%file\%//g;
|
||||
# Run remotely
|
||||
my $oSSH = $self->remote_get($strPathType);
|
||||
my $strOutput = $oSSH->capture($self->{strCommand} . " hash ${strPath}");
|
||||
|
||||
# Capture any errors
|
||||
if ($oSSH->error)
|
||||
{
|
||||
confess &log(ERROR, "${strErrorPrefix} remote: " . (defined($strOutput) ? $strOutput : $oSSH->error));
|
||||
}
|
||||
|
||||
$strHash = $strOutput;
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ASSERT, "unable to find $strPath(.$self->{strCompressExtension}) for checksum");
|
||||
my $hFile;
|
||||
|
||||
if (!open($hFile, "<", $strPath))
|
||||
{
|
||||
my $strError = "${strPath} could not be read" . $!;
|
||||
my $iErrorCode = 2;
|
||||
|
||||
unless (-e $strPath)
|
||||
{
|
||||
$strError = "${strPath} does not exist";
|
||||
$iErrorCode = 1;
|
||||
}
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit ($iErrorCode);
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
|
||||
my $oSHA = Digest::SHA->new(defined($strHashType) ? $strHashType : 'sha1');
|
||||
|
||||
$oSHA->addfile($hFile);
|
||||
|
||||
close($hFile);
|
||||
|
||||
$strHash = $oSHA->hexdigest();
|
||||
}
|
||||
|
||||
return trim(capture($strCommand)) or confess &log(ERROR, "unable to checksum ${strPath}");
|
||||
return $strHash;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# FILE_COMPRESS
|
||||
####################################################################################################################################
|
||||
@ -832,9 +873,9 @@ sub file_compress
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# FILE_LIST_GET
|
||||
# LIST
|
||||
####################################################################################################################################
|
||||
sub file_list_get
|
||||
sub list
|
||||
{
|
||||
my $self = shift;
|
||||
my $strPathType = shift;
|
||||
@ -843,161 +884,206 @@ sub file_list_get
|
||||
my $strSortOrder = shift;
|
||||
|
||||
# Get the root path for the file list
|
||||
my $strPathList = $self->path_get($strPathType, $strPath);
|
||||
my @stryFileList;
|
||||
my $strErrorPrefix = "File->list";
|
||||
my $bRemote = $self->is_remote($strPathType);
|
||||
my $strPathOp = $self->path_get($strPathType, $strPath);
|
||||
|
||||
# Builds the file list command
|
||||
# my $strCommand = "ls ${strPathList} | egrep \"$strExpression\"";
|
||||
my $strCommand = "ls -1 ${strPathList}";
|
||||
|
||||
# Run the file list command
|
||||
my $strFileList = "";
|
||||
&log(TRACE, "${strErrorPrefix}: " . ($bRemote ? "remote" : "local") . " ${strPathType}:${strPathOp}" .
|
||||
", expression " . (defined($strExpression) ? $strExpression : "[UNDEF]") .
|
||||
", sort " . (defined($strSortOrder) ? $strSortOrder : "[UNDEF]"));
|
||||
|
||||
# Run remotely
|
||||
if ($self->is_remote($strPathType))
|
||||
{
|
||||
&log(TRACE, "file_list_get: remote ${strPathType}:${strPathList} ${strCommand}");
|
||||
my $strCommand = $self->{strCommand} .
|
||||
(defined($strSortOrder) && $strSortOrder eq "reverse" ? " --sort=reverse" : "") .
|
||||
(defined($strExpression) ? " --expression=\"" . $strExpression . "\"" : "") .
|
||||
" list ${strPathOp}";
|
||||
|
||||
# Run via SSH
|
||||
my $oSSH = $self->remote_get($strPathType);
|
||||
$strFileList = $oSSH->capture($strCommand);
|
||||
|
||||
my $strOutput = $oSSH->capture($strCommand);
|
||||
|
||||
# Handle any errors
|
||||
if ($oSSH->error)
|
||||
{
|
||||
confess &log(ERROR, "unable to execute file list (${strCommand}): " . $self->error_get());
|
||||
confess &log(ERROR, "${strErrorPrefix} remote (${strCommand}): " . (defined($strOutput) ? $strOutput : $oSSH->error));
|
||||
}
|
||||
|
||||
@stryFileList = split(/\n/, $strOutput);
|
||||
}
|
||||
# Run locally
|
||||
else
|
||||
{
|
||||
&log(TRACE, "file_list_get: local ${strPathType}:${strPathList} ${strCommand}");
|
||||
$strFileList = capture($strCommand);
|
||||
my $hPath;
|
||||
|
||||
if (!opendir($hPath, $strPathOp))
|
||||
{
|
||||
my $strError = "${strPathOp} could not be read:" . $!;
|
||||
my $iErrorCode = 2;
|
||||
|
||||
unless (-e $strPath)
|
||||
{
|
||||
$strError = "${strPathOp} does not exist";
|
||||
$iErrorCode = 1;
|
||||
}
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit ($iErrorCode);
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
|
||||
@stryFileList = grep(!/^(\.)|(\.\.)$/i, readdir($hPath));
|
||||
|
||||
close($hPath);
|
||||
|
||||
if (defined($strExpression))
|
||||
{
|
||||
@stryFileList = grep(/$strExpression/i, @stryFileList);
|
||||
}
|
||||
|
||||
# Reverse sort
|
||||
if (defined($strSortOrder) && $strSortOrder eq "reverse")
|
||||
{
|
||||
@stryFileList = sort {$b cmp $a} @stryFileList;
|
||||
}
|
||||
# Normal sort
|
||||
else
|
||||
{
|
||||
@stryFileList = sort @stryFileList;
|
||||
}
|
||||
}
|
||||
|
||||
# Split the files into an array
|
||||
my @stryFileList;
|
||||
|
||||
if (defined($strExpression))
|
||||
{
|
||||
@stryFileList = grep(/$strExpression/i, split(/\n/, $strFileList));
|
||||
}
|
||||
else
|
||||
{
|
||||
@stryFileList = split(/\n/, $strFileList);
|
||||
}
|
||||
|
||||
# Return the array in reverse order if specified
|
||||
if (defined($strSortOrder) && $strSortOrder eq "reverse")
|
||||
{
|
||||
return sort {$b cmp $a} @stryFileList;
|
||||
}
|
||||
|
||||
# Return in normal sorted order
|
||||
return sort @stryFileList;
|
||||
# Return file list
|
||||
return @stryFileList;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# FILE_EXISTS
|
||||
# EXISTS - Checks for the existence of a file, but does not imply that the file is readable/writeable.
|
||||
#
|
||||
# Return: true if file exists, false otherwise
|
||||
####################################################################################################################################
|
||||
sub file_exists
|
||||
sub exists
|
||||
{
|
||||
my $self = shift;
|
||||
my $strPathType = shift;
|
||||
my $strPath = shift;
|
||||
|
||||
# Get the root path for the manifest
|
||||
my $strPathExists = $self->path_get($strPathType, $strPath);
|
||||
# Set error prefix, remote, and path
|
||||
my $bExists = false;
|
||||
my $strErrorPrefix = "File->exists";
|
||||
my $bRemote = $self->is_remote($strPathType);
|
||||
my $strPathOp = $self->path_get($strPathType, $strPath);
|
||||
|
||||
&log(TRACE, "file_exists: " . ($self->is_remote($strPathType) ? "remote" : "local") . " ${strPathType}:${strPathExists}");
|
||||
&log(TRACE, "${strErrorPrefix}: " . ($bRemote ? "remote" : "local") . " ${strPathType}:${strPathOp}");
|
||||
|
||||
# Run remotely
|
||||
if ($self->is_remote($strPathType))
|
||||
if ($bRemote)
|
||||
{
|
||||
# Builds the exists command
|
||||
my $strCommand = "ls ${strPathExists}";
|
||||
|
||||
# Run the file exists command
|
||||
my $strExists;
|
||||
my $strError;
|
||||
|
||||
&log(TRACE, "file_exists: command: ${strCommand}");
|
||||
|
||||
# Build the command
|
||||
my $strCommand = $self->{strCommand} . " exists ${strPathOp}";
|
||||
|
||||
# Run it remotely
|
||||
my $oSSH = $self->remote_get($strPathType);
|
||||
$strExists = $oSSH->capture({stderr_file => $self->path_get(PATH_LOCK_ERR, "file")}, $strCommand);
|
||||
|
||||
&log(TRACE, "file_exists: search = ${strPathExists}, result = " . (defined($strExists) ? $strExists : "<undef>"));
|
||||
my $strOutput = $oSSH->capture($strCommand);
|
||||
|
||||
# Capture any errors
|
||||
if ($oSSH->error)
|
||||
{
|
||||
my $strError = $self->error_get();
|
||||
&log(TRACE, "error detected: $strError");
|
||||
|
||||
if ($strError =~ /.*ls.*No such file or directory.*/)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
confess &log(ERROR, "unable to execute file exists (${strCommand}): " . $strError);
|
||||
confess &log(ERROR, "${strErrorPrefix} remote (${strCommand}): " . (defined($strOutput) ? $strOutput : $oSSH->error));
|
||||
}
|
||||
|
||||
# If the return from ls eq strPathExists then true
|
||||
return trim($strExists) eq $strPathExists;
|
||||
$bExists = $strOutput eq "Y";
|
||||
}
|
||||
# Run locally
|
||||
else
|
||||
{
|
||||
if (-e $strPathExists)
|
||||
if (-e $strPathOp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
$bExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
confess &log(ASSERT, "file_exists: true or false should have been returned");
|
||||
return $bExists;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# FILE_REMOVE
|
||||
# REMOVE
|
||||
####################################################################################################################################
|
||||
sub file_remove
|
||||
sub remove
|
||||
{
|
||||
my $self = shift;
|
||||
my $strPathType = shift;
|
||||
my $strPath = shift;
|
||||
my $bTemp = shift;
|
||||
my $bErrorIfNotExists = shift;
|
||||
my $bIgnoreMissing = shift;
|
||||
|
||||
if (!defined($bErrorIfNotExists))
|
||||
if (!defined($bIgnoreMissing))
|
||||
{
|
||||
$bErrorIfNotExists = false;
|
||||
$bIgnoreMissing = true;
|
||||
}
|
||||
|
||||
# Get the root path for the manifest
|
||||
my $strPathRemove = $self->path_get($strPathType, $strPath, $bTemp);
|
||||
my $bRemoved = true;
|
||||
my $strErrorPrefix = "File->remove";
|
||||
my $bRemote = $self->is_remote($strPathType);
|
||||
my $strPathOp = $self->path_get($strPathType, $strPath, $bTemp);
|
||||
|
||||
# Builds the exists command
|
||||
my $strCommand = "rm -f ${strPathRemove}";
|
||||
&log(TRACE, "${strErrorPrefix}: " . ($bRemote ? "remote" : "local") . " ${strPathType}:${strPathOp}");
|
||||
|
||||
# Run remotely
|
||||
if ($self->is_remote($strPathType))
|
||||
if ($bRemote)
|
||||
{
|
||||
&log(TRACE, "file_remove: remote ${strPathType}:${strPathRemove}");
|
||||
|
||||
my $oSSH = $self->remote_get($strPathType);
|
||||
$oSSH->system($strCommand) or $bErrorIfNotExists ? confess &log(ERROR, "unable to remove remote ${strPathType}:${strPathRemove}") : true;
|
||||
# Build the command
|
||||
my $strCommand = $self->{strCommand} . ($bIgnoreMissing ? " --ignore-missing" : "") . " remove ${strPathOp}";
|
||||
|
||||
# Run it remotely
|
||||
my $oSSH = $self->remote_get($strPathType);
|
||||
my $strOutput = $oSSH->capture($strCommand);
|
||||
|
||||
if ($oSSH->error)
|
||||
{
|
||||
confess &log(ERROR, "unable to execute file_remove (${strCommand}): " . $self->error_get());
|
||||
confess &log(ERROR, "${strErrorPrefix} remote (${strCommand}): " . (defined($strOutput) ? $strOutput : $oSSH->error));
|
||||
}
|
||||
|
||||
$bRemoved = $strOutput eq "Y";
|
||||
}
|
||||
# Run locally
|
||||
else
|
||||
{
|
||||
&log(TRACE, "file_remove: local ${strPathType}:${strPathRemove}");
|
||||
system($strCommand) == 0 or $bErrorIfNotExists ? confess &log(ERROR, "unable to remove local ${strPathType}:${strPathRemove}") : true;
|
||||
if (unlink($strPathOp) != 1)
|
||||
{
|
||||
$bRemoved = false;
|
||||
|
||||
if (-e $strPathOp || !$bIgnoreMissing)
|
||||
{
|
||||
my $strError = "${strPathOp} could not be removed: " . $!;
|
||||
my $iErrorCode = 2;
|
||||
|
||||
unless (-e $strPathOp)
|
||||
{
|
||||
$strError = "${strPathOp} does not exist";
|
||||
$iErrorCode = 1;
|
||||
}
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit ($iErrorCode);
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bRemoved;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -1046,4 +1132,4 @@ sub manifest_get
|
||||
}
|
||||
|
||||
no Moose;
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
|
@ -25,85 +25,285 @@ sub BackRestTestFile
|
||||
{
|
||||
my $strLockPath = dirname(abs_path($0)) . "/lock";
|
||||
my $strTestPath = dirname(abs_path($0)) . "/test";
|
||||
my $iRun = 0;
|
||||
|
||||
log_level_set(OFF, OFF);
|
||||
my $iRun;
|
||||
|
||||
# !!! NEED TO TEST WHERE LOCK PATH IS UNDEF
|
||||
my $strStanza = "db";
|
||||
my $strCommand = "/Users/dsteele/pg_backrest/bin/pg_backrest_command.pl";
|
||||
my $strHost = "127.0.0.1";
|
||||
my $strUser = "dsteele";
|
||||
|
||||
log_level_set(TRACE, TRACE);
|
||||
|
||||
# Test list()
|
||||
$iRun = 0;
|
||||
|
||||
print "\ntest File->list()\n";
|
||||
|
||||
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
|
||||
{
|
||||
my $oFile = pg_backrest_file->new
|
||||
(
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => true,
|
||||
strCommand => $strCommand,
|
||||
strBackupClusterPath => ${strTestPath},
|
||||
strBackupPath => ${strTestPath},
|
||||
strBackupHost => $bRemote ? $strHost : undef,
|
||||
strBackupUser => $bRemote ? $strUser : undef
|
||||
);
|
||||
|
||||
# Loop through exists
|
||||
for (my $bSort = 0; $bSort <= 1; $bSort++)
|
||||
{
|
||||
my $strSort = $bSort ? undef : "reverse";
|
||||
|
||||
# Loop through expression
|
||||
for (my $iExpression = 0; $iExpression <= 2; $iExpression++)
|
||||
{
|
||||
my $strExpression;
|
||||
|
||||
# Expression tha returns results
|
||||
if ($iExpression == 1)
|
||||
{
|
||||
$strExpression = "^test2\\..*\$";
|
||||
}
|
||||
# Expression that does not return results
|
||||
elsif ($iExpression == 2)
|
||||
{
|
||||
$strExpression = "^du\$";
|
||||
}
|
||||
|
||||
# Loop through exists
|
||||
for (my $bExists = 0; $bExists <= 1; $bExists++)
|
||||
{
|
||||
$iRun++;
|
||||
|
||||
print "run ${iRun} - " .
|
||||
"remote $bRemote, exists $bExists, " .
|
||||
"expression " . (defined($strExpression) ? $strExpression : "[undef]") . ", " .
|
||||
"sort " . (defined($strSort) ? $strSort : "[undef]") . "\n";
|
||||
|
||||
my $strPath = "${strTestPath}";
|
||||
|
||||
# Drop the old test directory and create a new one
|
||||
system("rm -rf test");
|
||||
|
||||
if ($bExists)
|
||||
{
|
||||
system("mkdir test") == 0 or confess "Unable to create test directory";
|
||||
system("echo 'TESTDATA' > ${strPath}/test.txt");
|
||||
system("echo 'TESTDATA2' > ${strPath}/test2.txt");
|
||||
}
|
||||
|
||||
my @stryFileCompare = split(/\n/, "test.txt\ntest2.txt");
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
my @stryFileList = $oFile->list(PATH_BACKUP_ABSOLUTE, $strPath, $strExpression, $strSort);
|
||||
|
||||
if (defined($strExpression))
|
||||
{
|
||||
@stryFileCompare = grep(/$strExpression/i, @stryFileCompare);
|
||||
}
|
||||
|
||||
if (defined($strSort))
|
||||
{
|
||||
@stryFileCompare = sort {$b cmp $a} @stryFileCompare;
|
||||
}
|
||||
|
||||
my $strFileList = sprintf("@stryFileList");
|
||||
my $strFileCompare = sprintf("@stryFileCompare");
|
||||
|
||||
if ($strFileList ne $strFileCompare)
|
||||
{
|
||||
confess "list (${strFileList})[" . @stryFileList .
|
||||
"] does not match compare (${strFileCompare})[" . @stryFileCompare . "]";
|
||||
}
|
||||
};
|
||||
|
||||
if ($@ && $bExists)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Test remove()
|
||||
$iRun = 0;
|
||||
print "test File->remove()\n";
|
||||
|
||||
# Test file_exists()
|
||||
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
|
||||
{
|
||||
my $strHost = $bRemote ? "127.0.0.1" : undef;
|
||||
my $strUser = $bRemote ? "dsteele" : undef;
|
||||
|
||||
system("rm -rf lock");
|
||||
system("mkdir -p lock") == 0 or confess "Unable to create lock directory";
|
||||
|
||||
my $oFile = pg_backrest_file->new
|
||||
(
|
||||
strStanza => "db",
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => true,
|
||||
strCommand => ${strCommand},
|
||||
strBackupClusterPath => ${strTestPath},
|
||||
strBackupPath => ${strTestPath},
|
||||
strBackupHost => $strHost,
|
||||
strBackupUser => $strUser,
|
||||
strLockPath => $strLockPath
|
||||
strBackupHost => $bRemote ? $strHost : undef,
|
||||
strBackupUser => $bRemote ? $strUser : undef
|
||||
);
|
||||
|
||||
# Loop through exists
|
||||
for (my $bExists = 0; $bExists <= 1; $bExists++)
|
||||
{
|
||||
# Loop through error
|
||||
for (my $bError = 0; $bError <= $bRemote ? 1 : 0; $bError++)
|
||||
# Loop through temp
|
||||
for (my $bTemp = 0; $bTemp <= 1; $bTemp++)
|
||||
{
|
||||
$iRun++;
|
||||
# Loop through ignore missing
|
||||
for (my $bIgnoreMissing = 0; $bIgnoreMissing <= 1; $bIgnoreMissing++)
|
||||
{
|
||||
$iRun++;
|
||||
|
||||
print "run ${iRun} - " .
|
||||
"rmt $bRemote, exist $bExists, error $bError\n";
|
||||
print "run ${iRun} - " .
|
||||
"remote ${bRemote}, exists ${bExists}, temp ${bTemp}, ignore missing ${bIgnoreMissing}\n";
|
||||
|
||||
# Drop the old test directory and create a new one
|
||||
system("rm -rf test");
|
||||
system("mkdir test") == 0 or confess "Unable to create test directory";
|
||||
# Drop the old test directory and create a new one
|
||||
system("rm -rf test");
|
||||
system("mkdir test") == 0 or confess "Unable to create test directory";
|
||||
|
||||
my $strFile = "${strTestPath}/test.txt";
|
||||
my $strFile = "${strTestPath}/test.txt";
|
||||
|
||||
if ($bExists)
|
||||
{
|
||||
system("echo 'TESTDATA' > ${strFile}" . ($bTemp ? ".backrest.tmp" : ""));
|
||||
}
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
if ($oFile->remove(PATH_BACKUP_ABSOLUTE, $strFile, $bTemp, $bIgnoreMissing) != $bExists)
|
||||
{
|
||||
confess "hash did not match expected";
|
||||
}
|
||||
};
|
||||
|
||||
if ($@ && $bExists)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
}
|
||||
|
||||
if (-e ($strFile . ($bTemp ? ".backrest.tmp" : "")))
|
||||
{
|
||||
confess "file still exists";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Test hash()
|
||||
$iRun = 0;
|
||||
|
||||
print "\ntest File->hash()\n";
|
||||
|
||||
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
|
||||
{
|
||||
my $oFile = pg_backrest_file->new
|
||||
(
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => true,
|
||||
strCommand => $strCommand,
|
||||
strBackupClusterPath => ${strTestPath},
|
||||
strBackupPath => ${strTestPath},
|
||||
strBackupHost => $bRemote ? $strHost : undef,
|
||||
strBackupUser => $bRemote ? $strUser : undef
|
||||
);
|
||||
|
||||
# Loop through exists
|
||||
for (my $bExists = 0; $bExists <= 1; $bExists++)
|
||||
{
|
||||
$iRun++;
|
||||
|
||||
print "run ${iRun} - " .
|
||||
"remote $bRemote, exists $bExists\n";
|
||||
|
||||
# Drop the old test directory and create a new one
|
||||
system("rm -rf test");
|
||||
system("mkdir test") == 0 or confess "Unable to create test directory";
|
||||
|
||||
my $strFile = "${strTestPath}/test.txt";
|
||||
|
||||
if ($bExists)
|
||||
{
|
||||
system("echo 'TESTDATA' > ${strFile}");
|
||||
}
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
if ($oFile->hash(PATH_BACKUP_ABSOLUTE, $strFile) ne '06364afe79d801433188262478a76d19777ef351')
|
||||
{
|
||||
confess "bExists is set to ${bExists}, but exists() returned " . !$bExists;
|
||||
}
|
||||
};
|
||||
|
||||
if ($@)
|
||||
{
|
||||
if ($bExists)
|
||||
{
|
||||
system("echo 'TESTDATA' > ${strFile}");
|
||||
confess " error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bError)
|
||||
# Test exists()
|
||||
$iRun = 0;
|
||||
|
||||
print "\ntest File->exists()\n";
|
||||
|
||||
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
|
||||
{
|
||||
my $oFile = pg_backrest_file->new
|
||||
(
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => true,
|
||||
strCommand => $strCommand,
|
||||
strBackupClusterPath => ${strTestPath},
|
||||
strBackupPath => ${strTestPath},
|
||||
strBackupHost => $bRemote ? $strHost : undef,
|
||||
strBackupUser => $bRemote ? $strUser : undef
|
||||
);
|
||||
|
||||
# Loop through exists
|
||||
for (my $bExists = 0; $bExists <= 1; $bExists++)
|
||||
{
|
||||
$iRun++;
|
||||
|
||||
print "run ${iRun} - " .
|
||||
"remote $bRemote, exists $bExists\n";
|
||||
|
||||
# Drop the old test directory and create a new one
|
||||
system("rm -rf test");
|
||||
system("mkdir test") == 0 or confess "Unable to create test directory";
|
||||
|
||||
my $strFile = "${strTestPath}/test.txt";
|
||||
|
||||
if ($bExists)
|
||||
{
|
||||
system("echo 'TESTDATA' > ${strFile}");
|
||||
}
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
if ($oFile->exists(PATH_BACKUP_ABSOLUTE, $strFile) != $bExists)
|
||||
{
|
||||
$strFile = "--backrest-error " . $strFile;
|
||||
}
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
if ($oFile->file_exists(PATH_BACKUP_ABSOLUTE, $strFile) != $bExists)
|
||||
{
|
||||
confess "bExists is set to $bExists, but file_exists() returned " . !$bExists;
|
||||
}
|
||||
};
|
||||
|
||||
if ($@)
|
||||
{
|
||||
if (!$bError)
|
||||
{
|
||||
confess 'error was returned but no error generated';
|
||||
}
|
||||
|
||||
my $strError = $oFile->error_get();
|
||||
|
||||
if (!defined($strError) || ($strError eq ''))
|
||||
{
|
||||
confess 'no error message returned';
|
||||
}
|
||||
|
||||
print " error raised: ${strError}\n";
|
||||
next;
|
||||
confess "bExists is set to ${bExists}, but exists() returned " . !$bExists;
|
||||
}
|
||||
};
|
||||
|
||||
if ($@)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ use BackRestTest::FileTest;
|
||||
####################################################################################################################################
|
||||
BackRestTestFile();
|
||||
|
||||
print "TEST COMPLETED SUCCESSFULLY (DESPITE ANY ERROR MESSAGES YOU SAW)\n";
|
||||
print "\nTEST COMPLETED SUCCESSFULLY (DESPITE ANY ERROR MESSAGES YOU SAW)\n";
|
||||
|
Loading…
Reference in New Issue
Block a user