mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-04-15 11:36:40 +02:00
Remove LibC.
This was the interface between Perl and C introduced in 36a5349b but since f0ef73db has only been used by the Perl integration tests. This is expensive code to maintain just for testing. The main dependency was the interface to storage, no matter where it was located, e.g. S3. Replace this with the new-introduced repo commands (d3c83453) that allow access to repo storage via the command line. The other dependency was on various cfgOption* functions and CFGOPT_ constants that were convenient but not necessary. Replace these with hard-coded strings in most places and create new constants for commonly used values. Remove all auto-generated Perl code. This means that the error list will no longer be maintained automatically so copy used errors to Common::Exception.pm. This file will need to be maintained manually going forward but there is not likely to be much churn as the Perl integration tests are being retired. Update test.pl and related code to remove LibC builds. Ding, dong, LibC is dead.
This commit is contained in:
parent
d3c83453de
commit
79cfd3aebf
@ -730,9 +730,6 @@
|
||||
<execute user="root" show="n">
|
||||
<exe-cmd>mkdir -p /build/pgbackrest-release-{[version]}</exe-cmd>
|
||||
</execute>
|
||||
<execute user="root" show="n">
|
||||
<exe-cmd>cp -r {[pgbackrest-repo-path]}/libc /build/pgbackrest-release-{[version]}</exe-cmd>
|
||||
</execute>
|
||||
<execute user="root" show="n">
|
||||
<exe-cmd>cp -r {[pgbackrest-repo-path]}/src /build/pgbackrest-release-{[version]}</exe-cmd>
|
||||
</execute>
|
||||
|
@ -17,8 +17,6 @@ use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
|
@ -19,13 +19,11 @@ use File::Basename qw(dirname basename);
|
||||
|
||||
use pgBackRest::Archive::Common;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
@ -95,9 +93,9 @@ sub new
|
||||
# Init object and store variables
|
||||
eval
|
||||
{
|
||||
$self = $class->SUPER::new($strArchiveInfoFile, {bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing,
|
||||
oStorage => storageRepo(), strCipherPass => storageRepo()->cipherPassUser(),
|
||||
strCipherPassSub => $strCipherPassSub});
|
||||
$self = $class->SUPER::new(
|
||||
storageRepo(), $strArchiveInfoFile,
|
||||
{bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => $strCipherPassSub});
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
|
@ -14,10 +14,8 @@ use File::Basename;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
# Latest backup link constant
|
||||
@ -25,6 +23,13 @@ use pgBackRest::Manifest;
|
||||
use constant LINK_LATEST => 'latest';
|
||||
push @EXPORT, qw(LINK_LATEST);
|
||||
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_FULL => 'full';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_FULL);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_DIFF);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_INCR => 'incr';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_INCR);
|
||||
|
||||
####################################################################################################################################
|
||||
# backupRegExpGet
|
||||
#
|
||||
@ -200,6 +205,7 @@ sub backupLabel
|
||||
(
|
||||
$strOperation,
|
||||
$oStorageRepo,
|
||||
$strRepoBackupPath,
|
||||
$strType,
|
||||
$strBackupLabelLast,
|
||||
$lTimestampStart
|
||||
@ -208,6 +214,7 @@ sub backupLabel
|
||||
(
|
||||
__PACKAGE__ . '::backupLabelFormat', \@_,
|
||||
{name => 'oStorageRepo', trace => true},
|
||||
{name => 'strRepoBackupPath', trace => true},
|
||||
{name => 'strType', trace => true},
|
||||
{name => 'strBackupLabelLast', required => false, trace => true},
|
||||
{name => 'lTimestampStart', trace => true}
|
||||
@ -221,15 +228,15 @@ sub backupLabel
|
||||
# clocks. In practice this is most useful for making offline testing faster since it allows the wait after manifest build to
|
||||
# be skipped by dealing with any backup label collisions here.
|
||||
if ($oStorageRepo->list(
|
||||
STORAGE_REPO_BACKUP,
|
||||
$strRepoBackupPath,
|
||||
{strExpression =>
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)$')}) ||
|
||||
$oStorageRepo->list(
|
||||
STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStart),
|
||||
"${strRepoBackupPath}/" . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStart),
|
||||
{strExpression =>
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)\.manifest\.' . COMPRESS_EXT . qw{$}),
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)\.manifest\.gz$'),
|
||||
bIgnoreMissing => true}))
|
||||
{
|
||||
waitRemainder();
|
||||
|
@ -19,10 +19,8 @@ use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
@ -137,9 +135,9 @@ sub new
|
||||
# Init object and store variables
|
||||
eval
|
||||
{
|
||||
$self = $class->SUPER::new($strBackupInfoFile, {bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing,
|
||||
oStorage => $oStorage, strCipherPass => $oStorage->cipherPassUser(),
|
||||
strCipherPassSub => $strCipherPassSub});
|
||||
$self = $class->SUPER::new(
|
||||
$oStorage, $strBackupInfoFile,
|
||||
{bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => $strCipherPassSub});
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
|
@ -12,12 +12,98 @@ use Scalar::Util qw(blessed);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::ExceptionAuto;
|
||||
####################################################################################################################################
|
||||
# Error Definitions
|
||||
####################################################################################################################################
|
||||
use constant ERROR_MINIMUM => 25;
|
||||
push @EXPORT, qw(ERROR_MINIMUM);
|
||||
use constant ERROR_MAXIMUM => 125;
|
||||
push @EXPORT, qw(ERROR_MAXIMUM);
|
||||
|
||||
####################################################################################################################################
|
||||
# Export error constants
|
||||
####################################################################################################################################
|
||||
push(@EXPORT, @pgBackRest::Common::ExceptionAuto::EXPORT);
|
||||
use constant ERROR_ASSERT => 25;
|
||||
push @EXPORT, qw(ERROR_ASSERT);
|
||||
use constant ERROR_CHECKSUM => 26;
|
||||
push @EXPORT, qw(ERROR_CHECKSUM);
|
||||
use constant ERROR_CONFIG => 27;
|
||||
push @EXPORT, qw(ERROR_CONFIG);
|
||||
use constant ERROR_FILE_INVALID => 28;
|
||||
push @EXPORT, qw(ERROR_FILE_INVALID);
|
||||
use constant ERROR_FORMAT => 29;
|
||||
push @EXPORT, qw(ERROR_FORMAT);
|
||||
use constant ERROR_OPTION_INVALID_VALUE => 32;
|
||||
push @EXPORT, qw(ERROR_OPTION_INVALID_VALUE);
|
||||
use constant ERROR_POSTMASTER_RUNNING => 38;
|
||||
push @EXPORT, qw(ERROR_POSTMASTER_RUNNING);
|
||||
use constant ERROR_PATH_NOT_EMPTY => 40;
|
||||
push @EXPORT, qw(ERROR_PATH_NOT_EMPTY);
|
||||
use constant ERROR_FILE_OPEN => 41;
|
||||
push @EXPORT, qw(ERROR_FILE_OPEN);
|
||||
use constant ERROR_FILE_READ => 42;
|
||||
push @EXPORT, qw(ERROR_FILE_READ);
|
||||
use constant ERROR_ARCHIVE_MISMATCH => 44;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_MISMATCH);
|
||||
use constant ERROR_ARCHIVE_DUPLICATE => 45;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_DUPLICATE);
|
||||
use constant ERROR_PATH_CREATE => 47;
|
||||
push @EXPORT, qw(ERROR_PATH_CREATE);
|
||||
use constant ERROR_LOCK_ACQUIRE => 50;
|
||||
push @EXPORT, qw(ERROR_LOCK_ACQUIRE);
|
||||
use constant ERROR_BACKUP_MISMATCH => 51;
|
||||
push @EXPORT, qw(ERROR_BACKUP_MISMATCH);
|
||||
use constant ERROR_PATH_OPEN => 53;
|
||||
push @EXPORT, qw(ERROR_PATH_OPEN);
|
||||
use constant ERROR_PATH_SYNC => 54;
|
||||
push @EXPORT, qw(ERROR_PATH_SYNC);
|
||||
use constant ERROR_FILE_MISSING => 55;
|
||||
push @EXPORT, qw(ERROR_FILE_MISSING);
|
||||
use constant ERROR_DB_CONNECT => 56;
|
||||
push @EXPORT, qw(ERROR_DB_CONNECT);
|
||||
use constant ERROR_DB_QUERY => 57;
|
||||
push @EXPORT, qw(ERROR_DB_QUERY);
|
||||
use constant ERROR_DB_MISMATCH => 58;
|
||||
push @EXPORT, qw(ERROR_DB_MISMATCH);
|
||||
use constant ERROR_PATH_REMOVE => 61;
|
||||
push @EXPORT, qw(ERROR_PATH_REMOVE);
|
||||
use constant ERROR_STOP => 62;
|
||||
push @EXPORT, qw(ERROR_STOP);
|
||||
use constant ERROR_FILE_WRITE => 64;
|
||||
push @EXPORT, qw(ERROR_FILE_WRITE);
|
||||
use constant ERROR_FEATURE_NOT_SUPPORTED => 67;
|
||||
push @EXPORT, qw(ERROR_FEATURE_NOT_SUPPORTED);
|
||||
use constant ERROR_ARCHIVE_COMMAND_INVALID => 68;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_COMMAND_INVALID);
|
||||
use constant ERROR_LINK_EXPECTED => 69;
|
||||
push @EXPORT, qw(ERROR_LINK_EXPECTED);
|
||||
use constant ERROR_LINK_DESTINATION => 70;
|
||||
push @EXPORT, qw(ERROR_LINK_DESTINATION);
|
||||
use constant ERROR_PATH_MISSING => 73;
|
||||
push @EXPORT, qw(ERROR_PATH_MISSING);
|
||||
use constant ERROR_FILE_MOVE => 74;
|
||||
push @EXPORT, qw(ERROR_FILE_MOVE);
|
||||
use constant ERROR_PATH_TYPE => 77;
|
||||
push @EXPORT, qw(ERROR_PATH_TYPE);
|
||||
use constant ERROR_DB_MISSING => 80;
|
||||
push @EXPORT, qw(ERROR_DB_MISSING);
|
||||
use constant ERROR_DB_INVALID => 81;
|
||||
push @EXPORT, qw(ERROR_DB_INVALID);
|
||||
use constant ERROR_ARCHIVE_TIMEOUT => 82;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_TIMEOUT);
|
||||
use constant ERROR_ARCHIVE_DISABLED => 87;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_DISABLED);
|
||||
use constant ERROR_FILE_OWNER => 88;
|
||||
push @EXPORT, qw(ERROR_FILE_OWNER);
|
||||
use constant ERROR_PATH_EXISTS => 92;
|
||||
push @EXPORT, qw(ERROR_PATH_EXISTS);
|
||||
use constant ERROR_FILE_EXISTS => 93;
|
||||
push @EXPORT, qw(ERROR_FILE_EXISTS);
|
||||
use constant ERROR_CRYPTO => 95;
|
||||
push @EXPORT, qw(ERROR_CRYPTO);
|
||||
use constant ERROR_INVALID => 123;
|
||||
push @EXPORT, qw(ERROR_INVALID);
|
||||
use constant ERROR_UNHANDLED => 124;
|
||||
push @EXPORT, qw(ERROR_UNHANDLED);
|
||||
use constant ERROR_UNKNOWN => 125;
|
||||
push @EXPORT, qw(ERROR_UNKNOWN);
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
|
@ -1,183 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# COMMON EXCEPTION AUTO MODULE
|
||||
#
|
||||
# Automatically generated by Build.pm -- do not modify directly.
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Common::ExceptionAuto;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
####################################################################################################################################
|
||||
# Error Definitions
|
||||
####################################################################################################################################
|
||||
use constant ERROR_MINIMUM => 25;
|
||||
push @EXPORT, qw(ERROR_MINIMUM);
|
||||
use constant ERROR_MAXIMUM => 125;
|
||||
push @EXPORT, qw(ERROR_MAXIMUM);
|
||||
|
||||
use constant ERROR_ASSERT => 25;
|
||||
push @EXPORT, qw(ERROR_ASSERT);
|
||||
use constant ERROR_CHECKSUM => 26;
|
||||
push @EXPORT, qw(ERROR_CHECKSUM);
|
||||
use constant ERROR_CONFIG => 27;
|
||||
push @EXPORT, qw(ERROR_CONFIG);
|
||||
use constant ERROR_FILE_INVALID => 28;
|
||||
push @EXPORT, qw(ERROR_FILE_INVALID);
|
||||
use constant ERROR_FORMAT => 29;
|
||||
push @EXPORT, qw(ERROR_FORMAT);
|
||||
use constant ERROR_COMMAND_REQUIRED => 30;
|
||||
push @EXPORT, qw(ERROR_COMMAND_REQUIRED);
|
||||
use constant ERROR_OPTION_INVALID => 31;
|
||||
push @EXPORT, qw(ERROR_OPTION_INVALID);
|
||||
use constant ERROR_OPTION_INVALID_VALUE => 32;
|
||||
push @EXPORT, qw(ERROR_OPTION_INVALID_VALUE);
|
||||
use constant ERROR_OPTION_INVALID_RANGE => 33;
|
||||
push @EXPORT, qw(ERROR_OPTION_INVALID_RANGE);
|
||||
use constant ERROR_OPTION_INVALID_PAIR => 34;
|
||||
push @EXPORT, qw(ERROR_OPTION_INVALID_PAIR);
|
||||
use constant ERROR_OPTION_DUPLICATE_KEY => 35;
|
||||
push @EXPORT, qw(ERROR_OPTION_DUPLICATE_KEY);
|
||||
use constant ERROR_OPTION_NEGATE => 36;
|
||||
push @EXPORT, qw(ERROR_OPTION_NEGATE);
|
||||
use constant ERROR_OPTION_REQUIRED => 37;
|
||||
push @EXPORT, qw(ERROR_OPTION_REQUIRED);
|
||||
use constant ERROR_POSTMASTER_RUNNING => 38;
|
||||
push @EXPORT, qw(ERROR_POSTMASTER_RUNNING);
|
||||
use constant ERROR_PROTOCOL => 39;
|
||||
push @EXPORT, qw(ERROR_PROTOCOL);
|
||||
use constant ERROR_PATH_NOT_EMPTY => 40;
|
||||
push @EXPORT, qw(ERROR_PATH_NOT_EMPTY);
|
||||
use constant ERROR_FILE_OPEN => 41;
|
||||
push @EXPORT, qw(ERROR_FILE_OPEN);
|
||||
use constant ERROR_FILE_READ => 42;
|
||||
push @EXPORT, qw(ERROR_FILE_READ);
|
||||
use constant ERROR_PARAM_REQUIRED => 43;
|
||||
push @EXPORT, qw(ERROR_PARAM_REQUIRED);
|
||||
use constant ERROR_ARCHIVE_MISMATCH => 44;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_MISMATCH);
|
||||
use constant ERROR_ARCHIVE_DUPLICATE => 45;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_DUPLICATE);
|
||||
use constant ERROR_VERSION_NOT_SUPPORTED => 46;
|
||||
push @EXPORT, qw(ERROR_VERSION_NOT_SUPPORTED);
|
||||
use constant ERROR_PATH_CREATE => 47;
|
||||
push @EXPORT, qw(ERROR_PATH_CREATE);
|
||||
use constant ERROR_COMMAND_INVALID => 48;
|
||||
push @EXPORT, qw(ERROR_COMMAND_INVALID);
|
||||
use constant ERROR_HOST_CONNECT => 49;
|
||||
push @EXPORT, qw(ERROR_HOST_CONNECT);
|
||||
use constant ERROR_LOCK_ACQUIRE => 50;
|
||||
push @EXPORT, qw(ERROR_LOCK_ACQUIRE);
|
||||
use constant ERROR_BACKUP_MISMATCH => 51;
|
||||
push @EXPORT, qw(ERROR_BACKUP_MISMATCH);
|
||||
use constant ERROR_FILE_SYNC => 52;
|
||||
push @EXPORT, qw(ERROR_FILE_SYNC);
|
||||
use constant ERROR_PATH_OPEN => 53;
|
||||
push @EXPORT, qw(ERROR_PATH_OPEN);
|
||||
use constant ERROR_PATH_SYNC => 54;
|
||||
push @EXPORT, qw(ERROR_PATH_SYNC);
|
||||
use constant ERROR_FILE_MISSING => 55;
|
||||
push @EXPORT, qw(ERROR_FILE_MISSING);
|
||||
use constant ERROR_DB_CONNECT => 56;
|
||||
push @EXPORT, qw(ERROR_DB_CONNECT);
|
||||
use constant ERROR_DB_QUERY => 57;
|
||||
push @EXPORT, qw(ERROR_DB_QUERY);
|
||||
use constant ERROR_DB_MISMATCH => 58;
|
||||
push @EXPORT, qw(ERROR_DB_MISMATCH);
|
||||
use constant ERROR_DB_TIMEOUT => 59;
|
||||
push @EXPORT, qw(ERROR_DB_TIMEOUT);
|
||||
use constant ERROR_FILE_REMOVE => 60;
|
||||
push @EXPORT, qw(ERROR_FILE_REMOVE);
|
||||
use constant ERROR_PATH_REMOVE => 61;
|
||||
push @EXPORT, qw(ERROR_PATH_REMOVE);
|
||||
use constant ERROR_STOP => 62;
|
||||
push @EXPORT, qw(ERROR_STOP);
|
||||
use constant ERROR_TERM => 63;
|
||||
push @EXPORT, qw(ERROR_TERM);
|
||||
use constant ERROR_FILE_WRITE => 64;
|
||||
push @EXPORT, qw(ERROR_FILE_WRITE);
|
||||
use constant ERROR_PROTOCOL_TIMEOUT => 66;
|
||||
push @EXPORT, qw(ERROR_PROTOCOL_TIMEOUT);
|
||||
use constant ERROR_FEATURE_NOT_SUPPORTED => 67;
|
||||
push @EXPORT, qw(ERROR_FEATURE_NOT_SUPPORTED);
|
||||
use constant ERROR_ARCHIVE_COMMAND_INVALID => 68;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_COMMAND_INVALID);
|
||||
use constant ERROR_LINK_EXPECTED => 69;
|
||||
push @EXPORT, qw(ERROR_LINK_EXPECTED);
|
||||
use constant ERROR_LINK_DESTINATION => 70;
|
||||
push @EXPORT, qw(ERROR_LINK_DESTINATION);
|
||||
use constant ERROR_HOST_INVALID => 72;
|
||||
push @EXPORT, qw(ERROR_HOST_INVALID);
|
||||
use constant ERROR_PATH_MISSING => 73;
|
||||
push @EXPORT, qw(ERROR_PATH_MISSING);
|
||||
use constant ERROR_FILE_MOVE => 74;
|
||||
push @EXPORT, qw(ERROR_FILE_MOVE);
|
||||
use constant ERROR_BACKUP_SET_INVALID => 75;
|
||||
push @EXPORT, qw(ERROR_BACKUP_SET_INVALID);
|
||||
use constant ERROR_TABLESPACE_MAP => 76;
|
||||
push @EXPORT, qw(ERROR_TABLESPACE_MAP);
|
||||
use constant ERROR_PATH_TYPE => 77;
|
||||
push @EXPORT, qw(ERROR_PATH_TYPE);
|
||||
use constant ERROR_LINK_MAP => 78;
|
||||
push @EXPORT, qw(ERROR_LINK_MAP);
|
||||
use constant ERROR_FILE_CLOSE => 79;
|
||||
push @EXPORT, qw(ERROR_FILE_CLOSE);
|
||||
use constant ERROR_DB_MISSING => 80;
|
||||
push @EXPORT, qw(ERROR_DB_MISSING);
|
||||
use constant ERROR_DB_INVALID => 81;
|
||||
push @EXPORT, qw(ERROR_DB_INVALID);
|
||||
use constant ERROR_ARCHIVE_TIMEOUT => 82;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_TIMEOUT);
|
||||
use constant ERROR_FILE_MODE => 83;
|
||||
push @EXPORT, qw(ERROR_FILE_MODE);
|
||||
use constant ERROR_OPTION_MULTIPLE_VALUE => 84;
|
||||
push @EXPORT, qw(ERROR_OPTION_MULTIPLE_VALUE);
|
||||
use constant ERROR_PROTOCOL_OUTPUT_REQUIRED => 85;
|
||||
push @EXPORT, qw(ERROR_PROTOCOL_OUTPUT_REQUIRED);
|
||||
use constant ERROR_LINK_OPEN => 86;
|
||||
push @EXPORT, qw(ERROR_LINK_OPEN);
|
||||
use constant ERROR_ARCHIVE_DISABLED => 87;
|
||||
push @EXPORT, qw(ERROR_ARCHIVE_DISABLED);
|
||||
use constant ERROR_FILE_OWNER => 88;
|
||||
push @EXPORT, qw(ERROR_FILE_OWNER);
|
||||
use constant ERROR_USER_MISSING => 89;
|
||||
push @EXPORT, qw(ERROR_USER_MISSING);
|
||||
use constant ERROR_OPTION_COMMAND => 90;
|
||||
push @EXPORT, qw(ERROR_OPTION_COMMAND);
|
||||
use constant ERROR_GROUP_MISSING => 91;
|
||||
push @EXPORT, qw(ERROR_GROUP_MISSING);
|
||||
use constant ERROR_PATH_EXISTS => 92;
|
||||
push @EXPORT, qw(ERROR_PATH_EXISTS);
|
||||
use constant ERROR_FILE_EXISTS => 93;
|
||||
push @EXPORT, qw(ERROR_FILE_EXISTS);
|
||||
use constant ERROR_MEMORY => 94;
|
||||
push @EXPORT, qw(ERROR_MEMORY);
|
||||
use constant ERROR_CRYPTO => 95;
|
||||
push @EXPORT, qw(ERROR_CRYPTO);
|
||||
use constant ERROR_PARAM_INVALID => 96;
|
||||
push @EXPORT, qw(ERROR_PARAM_INVALID);
|
||||
use constant ERROR_PATH_CLOSE => 97;
|
||||
push @EXPORT, qw(ERROR_PATH_CLOSE);
|
||||
use constant ERROR_FILE_INFO => 98;
|
||||
push @EXPORT, qw(ERROR_FILE_INFO);
|
||||
use constant ERROR_JSON_FORMAT => 99;
|
||||
push @EXPORT, qw(ERROR_JSON_FORMAT);
|
||||
use constant ERROR_KERNEL => 100;
|
||||
push @EXPORT, qw(ERROR_KERNEL);
|
||||
use constant ERROR_SERVICE => 101;
|
||||
push @EXPORT, qw(ERROR_SERVICE);
|
||||
use constant ERROR_EXECUTE => 102;
|
||||
push @EXPORT, qw(ERROR_EXECUTE);
|
||||
use constant ERROR_RUNTIME => 122;
|
||||
push @EXPORT, qw(ERROR_RUNTIME);
|
||||
use constant ERROR_INVALID => 123;
|
||||
push @EXPORT, qw(ERROR_INVALID);
|
||||
use constant ERROR_UNHANDLED => 124;
|
||||
push @EXPORT, qw(ERROR_UNHANDLED);
|
||||
use constant ERROR_UNKNOWN => 125;
|
||||
push @EXPORT, qw(ERROR_UNKNOWN);
|
||||
|
||||
1;
|
@ -74,17 +74,13 @@ sub new
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Load Storage::Helper module
|
||||
require pgBackRest::Storage::Helper;
|
||||
pgBackRest::Storage::Helper->import();
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oStorage},
|
||||
$self->{strFileName},
|
||||
my $bLoad,
|
||||
my $strContent,
|
||||
$self->{oStorage},
|
||||
$self->{iInitFormat},
|
||||
$self->{strInitVersion},
|
||||
my $bIgnoreMissing,
|
||||
@ -94,10 +90,10 @@ sub new
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oStorage', trace => true},
|
||||
{name => 'strFileName', trace => true},
|
||||
{name => 'bLoad', optional => true, default => true, trace => true},
|
||||
{name => 'strContent', optional => true, trace => true},
|
||||
{name => 'oStorage', optional => true, default => storageLocal(), trace => true},
|
||||
{name => 'iInitFormat', optional => true, default => REPOSITORY_FORMAT, trace => true},
|
||||
{name => 'strInitVersion', optional => true, default => PROJECT_VERSION, trace => true},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false, trace => true},
|
||||
@ -105,11 +101,6 @@ sub new
|
||||
{name => 'strCipherPassSub', optional => true, trace => true},
|
||||
);
|
||||
|
||||
if (defined($self->{oStorage}->cipherPassUser()) && !defined($self->{strCipherPass}))
|
||||
{
|
||||
confess &log(ERROR, 'passphrase is required when storage is encrypted', ERROR_CRYPTO);
|
||||
}
|
||||
|
||||
# Set changed to false
|
||||
$self->{bModified} = false;
|
||||
|
||||
@ -139,11 +130,6 @@ sub new
|
||||
{
|
||||
$self->set(INI_SECTION_CIPHER, INI_KEY_CIPHER_PASS, undef, $strCipherPassSub);
|
||||
}
|
||||
elsif ((defined($self->{strCipherPass}) && !defined($strCipherPassSub)) ||
|
||||
(!defined($self->{strCipherPass}) && defined($strCipherPassSub)))
|
||||
{
|
||||
confess &log(ASSERT, 'a user passphrase and sub passphrase are both required when encrypting');
|
||||
}
|
||||
}
|
||||
|
||||
return $self;
|
||||
|
192
lib/pgBackRest/Common/Io/Process.pm
Normal file
192
lib/pgBackRest/Common/Io/Process.pm
Normal file
@ -0,0 +1,192 @@
|
||||
####################################################################################################################################
|
||||
# Process Execution, Management, and IO
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Common::Io::Process;
|
||||
use parent 'pgBackRest::Common::Io::Filter';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use IPC::Open3 qw(open3);
|
||||
use POSIX qw(:sys_wait_h);
|
||||
use Symbol 'gensym';
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# Amount of time to attempt to retrieve errors when a process terminates unexpectedly
|
||||
####################################################################################################################################
|
||||
use constant IO_ERROR_TIMEOUT => 5;
|
||||
|
||||
####################################################################################################################################
|
||||
# new - use open3 to run the command and get the io handles
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oParent,
|
||||
$strCommand,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oParent', trace => true},
|
||||
{name => 'strCommand', trace => true},
|
||||
);
|
||||
|
||||
# Bless with new class
|
||||
my $self = $class->SUPER::new($oParent);
|
||||
bless $self, $class;
|
||||
|
||||
# Use open3 to run the command
|
||||
my ($iProcessId, $fhRead, $fhWrite, $fhReadError);
|
||||
$fhReadError = gensym;
|
||||
|
||||
$iProcessId = IPC::Open3::open3($fhWrite, $fhRead, $fhReadError, $strCommand);
|
||||
|
||||
# Set handles
|
||||
$self->handleReadSet($fhRead);
|
||||
$self->handleWriteSet($fhWrite);
|
||||
|
||||
# Set variables
|
||||
$self->{iProcessId} = $iProcessId;
|
||||
$self->{fhReadError} = $fhReadError;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# error - handle errors
|
||||
####################################################################################################################################
|
||||
sub error
|
||||
{
|
||||
my $self = shift;
|
||||
my $iCode = shift;
|
||||
my $strMessage = shift;
|
||||
my $strDetail = shift;
|
||||
my $bClose = shift;
|
||||
|
||||
if (defined($self->{iProcessId}))
|
||||
{
|
||||
my $oWait = waitInit(defined($iCode) ? IO_ERROR_TIMEOUT : 0);
|
||||
|
||||
do
|
||||
{
|
||||
# Check the result
|
||||
my $iResult = waitpid($self->{iProcessId}, $bClose ? 0 : WNOHANG);
|
||||
|
||||
# Error if the process exited unexpectedly
|
||||
if ($iResult != 0)
|
||||
{
|
||||
# Get the exit status
|
||||
$self->{iExitStatus} = $iResult == -1 ? 255 : ${^CHILD_ERROR_NATIVE} >> 8;
|
||||
|
||||
# Drain the stderr stream
|
||||
my $strError;
|
||||
my $oIoError = new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle($self->id(), $self->{fhReadError}), 5, $self->bufferMax());
|
||||
|
||||
while (defined(my $strLine = $oIoError->readLine(true, false)))
|
||||
{
|
||||
$strError .= (defined($strError) ? "\n" : '') . $strLine;
|
||||
}
|
||||
|
||||
delete($self->{iProcessId});
|
||||
|
||||
if ((!$bClose && $self->{iExitStatus} != 0) || defined($strError))
|
||||
{
|
||||
my $iErrorCode =
|
||||
$self->{iExitStatus} >= ERROR_MINIMUM && $self->{iExitStatus} <= ERROR_MAXIMUM ?
|
||||
$self->{iExitStatus} : ERROR_FILE_READ;
|
||||
|
||||
logErrorResult(
|
||||
$iErrorCode, $self->id() . ' terminated unexpectedly' .
|
||||
($self->{iExitStatus} != 255 ? sprintf(' [%03d]', $self->{iExitStatus}) : ''),
|
||||
$strError);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (waitMore($oWait));
|
||||
|
||||
if (defined($iCode))
|
||||
{
|
||||
$self->parent()->error($iCode, $strMessage, $strDetail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ASSERT, 'cannot call error() after process has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get process id
|
||||
####################################################################################################################################
|
||||
sub processId
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{iProcessId};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get exit status (after close() is called)
|
||||
####################################################################################################################################
|
||||
sub exitStatus
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{iExitStatus};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# writeLine - check for error before writing line
|
||||
####################################################################################################################################
|
||||
sub writeLine
|
||||
{
|
||||
my $self = shift;
|
||||
my $strBuffer = shift;
|
||||
|
||||
# Check if the process has exited abnormally (doesn't seem like we should need this, but the next syswrite does a hard
|
||||
# abort if the remote process has already closed)
|
||||
$self->error();
|
||||
|
||||
return $self->parent()->writeLine($strBuffer);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# close - check if the process terminated on error
|
||||
####################################################################################################################################
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if (defined($self->{iProcessId}))
|
||||
{
|
||||
$self->error(undef, undef, undef, true);
|
||||
|
||||
# Class parent close
|
||||
$self->parent()->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
1;
|
@ -1,453 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# CONFIG MODULE
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Config::Config;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use JSON::PP;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Io::Base;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::LibC qw(:config :configDefine);
|
||||
use pgBackRest::Version;
|
||||
|
||||
####################################################################################################################################
|
||||
# Export config constants and functions
|
||||
####################################################################################################################################
|
||||
push(@EXPORT, @{$pgBackRest::LibC::EXPORT_TAGS{config}});
|
||||
push(@EXPORT, @{$pgBackRest::LibC::EXPORT_TAGS{configDefine}});
|
||||
|
||||
####################################################################################################################################
|
||||
# SOURCE Constants
|
||||
####################################################################################################################################
|
||||
use constant CFGDEF_SOURCE_CONFIG => 'config';
|
||||
push @EXPORT, qw(CFGDEF_SOURCE_CONFIG);
|
||||
use constant CFGDEF_SOURCE_PARAM => 'param';
|
||||
push @EXPORT, qw(CFGDEF_SOURCE_PARAM);
|
||||
use constant CFGDEF_SOURCE_DEFAULT => 'default';
|
||||
push @EXPORT, qw(CFGDEF_SOURCE_DEFAULT);
|
||||
|
||||
####################################################################################################################################
|
||||
# Configuration section constants
|
||||
####################################################################################################################################
|
||||
use constant CFGDEF_SECTION_GLOBAL => 'global';
|
||||
push @EXPORT, qw(CFGDEF_SECTION_GLOBAL);
|
||||
use constant CFGDEF_SECTION_STANZA => 'stanza';
|
||||
push @EXPORT, qw(CFGDEF_SECTION_STANZA);
|
||||
|
||||
####################################################################################################################################
|
||||
# Module variables
|
||||
####################################################################################################################################
|
||||
my %oOption; # Option hash
|
||||
my $strCommand; # Command (backup, archive-get, ...)
|
||||
my $bInitLog = false; # Has logging been initialized yet?
|
||||
|
||||
####################################################################################################################################
|
||||
# configLogging - configure logging based on options
|
||||
####################################################################################################################################
|
||||
sub configLogging
|
||||
{
|
||||
my $bLogInitForce = shift;
|
||||
|
||||
if ($bInitLog || (defined($bLogInitForce) && $bLogInitForce))
|
||||
{
|
||||
logLevelSet(
|
||||
cfgOptionValid(CFGOPT_LOG_LEVEL_FILE) ? cfgOption(CFGOPT_LOG_LEVEL_FILE) : OFF,
|
||||
cfgOptionValid(CFGOPT_LOG_LEVEL_CONSOLE) ? cfgOption(CFGOPT_LOG_LEVEL_CONSOLE) : OFF,
|
||||
cfgOptionValid(CFGOPT_LOG_LEVEL_STDERR) ? cfgOption(CFGOPT_LOG_LEVEL_STDERR) : OFF,
|
||||
cfgOptionValid(CFGOPT_LOG_TIMESTAMP) ? cfgOption(CFGOPT_LOG_TIMESTAMP) : undef,
|
||||
cfgOptionValid(CFGOPT_PROCESS_MAX) ? cfgOption(CFGOPT_PROCESS_MAX) : undef);
|
||||
|
||||
$bInitLog = true;
|
||||
}
|
||||
}
|
||||
|
||||
push @EXPORT, qw(configLogging);
|
||||
|
||||
####################################################################################################################################
|
||||
# Load configuration
|
||||
#
|
||||
# Additional conditions that cannot be codified by the option definitions are also tested here.
|
||||
####################################################################################################################################
|
||||
sub configLoad
|
||||
{
|
||||
my $bInitLogging = shift;
|
||||
my $strBackRestBin = shift;
|
||||
my $strCommandName = shift;
|
||||
my $rstrConfigJson = shift;
|
||||
|
||||
# Set backrest bin
|
||||
projectBinSet($strBackRestBin);
|
||||
|
||||
# Set command
|
||||
$strCommand = $strCommandName;
|
||||
|
||||
eval
|
||||
{
|
||||
%oOption = %{(JSON::PP->new()->allow_nonref())->decode($$rstrConfigJson)};
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
confess &log(ASSERT, "unable to parse config JSON");
|
||||
};
|
||||
|
||||
# Load options into final option hash
|
||||
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
|
||||
{
|
||||
my $strOptionName = cfgOptionName($iOptionId);
|
||||
|
||||
# If option is defined it is valid
|
||||
if (defined($oOption{$strOptionName}))
|
||||
{
|
||||
# Convert JSON bool to standard bool that Perl understands
|
||||
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN && defined($oOption{$strOptionName}{value}))
|
||||
{
|
||||
$oOption{$strOptionName}{value} = $oOption{$strOptionName}{value} eq INI_TRUE ? true : false;
|
||||
}
|
||||
}
|
||||
# Else it is not valid
|
||||
else
|
||||
{
|
||||
$oOption{$strOptionName}{valid} = false;
|
||||
}
|
||||
}
|
||||
|
||||
# If this is not the remote and logging is allowed (to not overwrite log levels for tests) then set the log level so that
|
||||
# INFO/WARN messages can be displayed (the user may still disable them). This should be run before any WARN logging is
|
||||
# generated.
|
||||
if (!defined($bInitLogging) || $bInitLogging)
|
||||
{
|
||||
configLogging(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(configLoad);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionIdFromIndex - return name for options that can be indexed (e.g. pg1-host, pg2-host).
|
||||
####################################################################################################################################
|
||||
sub cfgOptionIdFromIndex
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
my $iIndex = shift;
|
||||
|
||||
# If the option doesn't have a prefix it can't be indexed
|
||||
$iIndex = defined($iIndex) ? $iIndex : 1;
|
||||
my $strPrefix = cfgDefOptionPrefix($iOptionId);
|
||||
|
||||
if (!defined($strPrefix))
|
||||
{
|
||||
if ($iIndex > 1)
|
||||
{
|
||||
confess &log(ASSERT, "'" . cfgOptionName($iOptionId) . "' option does not allow indexing");
|
||||
}
|
||||
|
||||
return $iOptionId;
|
||||
}
|
||||
|
||||
return cfgOptionId("${strPrefix}${iIndex}" . substr(cfgOptionName($iOptionId), index(cfgOptionName($iOptionId), '-')));
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionIdFromIndex);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionSource - how was the option set?
|
||||
####################################################################################################################################
|
||||
sub cfgOptionSource
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
|
||||
cfgOptionValid($iOptionId, true);
|
||||
|
||||
return $oOption{cfgOptionName($iOptionId)}{source};
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionSource);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionValid - is the option valid for the current command?
|
||||
####################################################################################################################################
|
||||
sub cfgOptionValid
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
my $bError = shift;
|
||||
|
||||
# If defined then this is the command help is being generated for so all valid checks should be against that command
|
||||
my $iCommandId;
|
||||
|
||||
if (defined($strCommand))
|
||||
{
|
||||
$iCommandId = cfgCommandId($strCommand);
|
||||
}
|
||||
|
||||
if (defined($iCommandId) && cfgDefOptionValid($iCommandId, $iOptionId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (defined($bError) && $bError)
|
||||
{
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
if (!defined($oOption{$strOption}))
|
||||
{
|
||||
confess &log(ASSERT, "option '${strOption}' does not exist");
|
||||
}
|
||||
|
||||
confess &log(ASSERT, "option '${strOption}' not valid for command '" . cfgCommandName(cfgCommandGet()) . "'");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionValid);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOption - get option value
|
||||
####################################################################################################################################
|
||||
sub cfgOption
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
my $bRequired = shift;
|
||||
|
||||
cfgOptionValid($iOptionId, true);
|
||||
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
if (!defined($oOption{$strOption}{value}) && (!defined($bRequired) || $bRequired))
|
||||
{
|
||||
confess &log(ASSERT, "option ${strOption} is required");
|
||||
}
|
||||
|
||||
return $oOption{$strOption}{value};
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOption);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionDefault - get option default value
|
||||
####################################################################################################################################
|
||||
sub cfgOptionDefault
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
|
||||
cfgOptionValid($iOptionId, true);
|
||||
|
||||
return cfgDefOptionDefault(cfgCommandId($strCommand), $iOptionId);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionDefault);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionSet - set option value and source
|
||||
####################################################################################################################################
|
||||
sub cfgOptionSet
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
my $oValue = shift;
|
||||
my $bForce = shift;
|
||||
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
if (!cfgOptionValid($iOptionId, !defined($bForce) || !$bForce))
|
||||
{
|
||||
$oOption{$strOption}{valid} = true;
|
||||
}
|
||||
|
||||
$oOption{$strOption}{source} = CFGDEF_SOURCE_PARAM;
|
||||
$oOption{$strOption}{value} = $oValue;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionSet);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgOptionTest - test if an option exists or has a specific value
|
||||
####################################################################################################################################
|
||||
sub cfgOptionTest
|
||||
{
|
||||
my $iOptionId = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
if (!cfgOptionValid($iOptionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (defined($strValue))
|
||||
{
|
||||
return cfgOption($iOptionId) eq $strValue ? true : false;
|
||||
}
|
||||
|
||||
return defined($oOption{cfgOptionName($iOptionId)}{value}) ? true : false;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgOptionTest);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgCommandGet - get the current command
|
||||
####################################################################################################################################
|
||||
sub cfgCommandGet
|
||||
{
|
||||
return cfgCommandId($strCommand);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgCommandGet);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgCommandTest - test that the current command is equal to the provided value
|
||||
####################################################################################################################################
|
||||
sub cfgCommandTest
|
||||
{
|
||||
my $iCommandIdTest = shift;
|
||||
|
||||
return cfgCommandName($iCommandIdTest) eq $strCommand;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgCommandTest);
|
||||
|
||||
####################################################################################################################################
|
||||
# Set current command
|
||||
####################################################################################################################################
|
||||
sub cfgCommandSet
|
||||
{
|
||||
my $iCommandId = shift;
|
||||
|
||||
$strCommand = cfgCommandName($iCommandId);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgCommandSet);
|
||||
|
||||
####################################################################################################################################
|
||||
# cfgCommandWrite - using the options for the current command, write the command string for another command
|
||||
#
|
||||
# For example, this can be used to write the archive-get command for recovery.conf during a restore.
|
||||
####################################################################################################################################
|
||||
sub cfgCommandWrite
|
||||
{
|
||||
my $iNewCommandId = shift;
|
||||
my $bIncludeConfig = shift;
|
||||
my $strExeString = shift;
|
||||
my $bIncludeCommand = shift;
|
||||
my $oOptionOverride = shift;
|
||||
my $bDisplayOnly = shift;
|
||||
|
||||
# Set defaults
|
||||
$strExeString = defined($strExeString) ? $strExeString : projectBin();
|
||||
$bIncludeConfig = defined($bIncludeConfig) ? $bIncludeConfig : false;
|
||||
$bIncludeCommand = defined($bIncludeCommand) ? $bIncludeCommand : true;
|
||||
|
||||
# Iterate the options to figure out which ones are not default and need to be written out to the new command string
|
||||
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
|
||||
{
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
my $bSecure = cfgDefOptionSecure($iOptionId);
|
||||
|
||||
# Skip option if it is secure and should not be output in logs or the command line
|
||||
next if (($bSecure || $iOptionId == CFGOPT_REPO_CIPHER_TYPE) && !$bDisplayOnly);
|
||||
|
||||
# Process any option id overrides first
|
||||
if (defined($oOptionOverride->{$iOptionId}))
|
||||
{
|
||||
if (defined($oOptionOverride->{$iOptionId}{value}))
|
||||
{
|
||||
$strExeString .= cfgCommandWriteOptionFormat(
|
||||
$strOption, false, $bSecure, {value => $oOptionOverride->{$iOptionId}{value}});
|
||||
}
|
||||
}
|
||||
# And process overrides passed by string - this is used by Perl compatibility functions
|
||||
elsif (defined($oOptionOverride->{$strOption}))
|
||||
{
|
||||
if (defined($oOptionOverride->{$strOption}{value}))
|
||||
{
|
||||
$strExeString .= cfgCommandWriteOptionFormat(
|
||||
$strOption, false, $bSecure, {value => $oOptionOverride->{$strOption}{value}});
|
||||
}
|
||||
}
|
||||
# else look for non-default options in the current configuration
|
||||
elsif (cfgDefOptionValid($iNewCommandId, $iOptionId) &&
|
||||
defined($oOption{$strOption}{value}) &&
|
||||
($bIncludeConfig ?
|
||||
$oOption{$strOption}{source} ne CFGDEF_SOURCE_DEFAULT : $oOption{$strOption}{source} eq CFGDEF_SOURCE_PARAM))
|
||||
{
|
||||
my $oValue;
|
||||
my $bMulti = false;
|
||||
|
||||
# If this is a hash then it will break up into multiple command-line options
|
||||
if (ref($oOption{$strOption}{value}) eq 'HASH')
|
||||
{
|
||||
$oValue = $oOption{$strOption}{value};
|
||||
$bMulti = true;
|
||||
}
|
||||
# Else a single value but store it in a hash anyway to make processing below simpler
|
||||
else
|
||||
{
|
||||
$oValue = {value => $oOption{$strOption}{value}};
|
||||
}
|
||||
|
||||
$strExeString .= cfgCommandWriteOptionFormat($strOption, $bMulti, $bSecure, $oValue);
|
||||
}
|
||||
# Else is reset
|
||||
elsif (cfgDefOptionValid($iNewCommandId, $iOptionId) && $oOption{$strOption}{reset})
|
||||
{
|
||||
$strExeString .= " --reset-${strOption}";
|
||||
}
|
||||
}
|
||||
|
||||
if ($bIncludeCommand)
|
||||
{
|
||||
$strExeString .= ' ' . cfgCommandName($iNewCommandId);
|
||||
}
|
||||
|
||||
return $strExeString;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(cfgCommandWrite);
|
||||
|
||||
# Helper function for cfgCommandWrite() to correctly format options for command-line usage
|
||||
sub cfgCommandWriteOptionFormat
|
||||
{
|
||||
my $strOption = shift;
|
||||
my $bMulti = shift;
|
||||
my $bSecure = shift;
|
||||
my $oValue = shift;
|
||||
|
||||
# Loops though all keys in the hash
|
||||
my $strOptionFormat = '';
|
||||
my $strParam;
|
||||
|
||||
foreach my $strKey (sort(keys(%$oValue)))
|
||||
{
|
||||
# Get the value - if the original value was a hash then the key must be prefixed
|
||||
my $strValue = $bSecure ? '<redacted>' : ($bMulti ? "${strKey}=" : '') . $$oValue{$strKey};
|
||||
|
||||
# Handle the no- prefix for boolean values
|
||||
if (cfgDefOptionType(cfgOptionId($strOption)) eq CFGDEF_TYPE_BOOLEAN)
|
||||
{
|
||||
$strParam = '--' . ($strValue ? '' : 'no-') . $strOption;
|
||||
}
|
||||
else
|
||||
{
|
||||
$strParam = "--${strOption}=${strValue}";
|
||||
}
|
||||
|
||||
# Add quotes if the value has spaces in it
|
||||
$strOptionFormat .= ' ' . (index($strValue, " ") != -1 ? "\"${strParam}\"" : $strParam);
|
||||
}
|
||||
|
||||
return $strOptionFormat;
|
||||
}
|
||||
|
||||
1;
|
@ -1,64 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# C to Perl Interface
|
||||
####################################################################################################################################
|
||||
package pgBackRest::LibC;
|
||||
use base 'Exporter';
|
||||
|
||||
use 5.010001;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
use pgBackRest::LibCAuto;
|
||||
|
||||
# Dynamically create constants
|
||||
my $rhConstant = pgBackRest::LibCAuto::libcAutoConstant();
|
||||
|
||||
foreach my $strConstant (keys(%{$rhConstant}))
|
||||
{
|
||||
eval "use constant ${strConstant} => '" . $rhConstant->{$strConstant} . "'";
|
||||
}
|
||||
|
||||
# Export functions and constants
|
||||
our %EXPORT_TAGS = %{pgBackRest::LibCAuto::libcAutoExportTag()};
|
||||
our @EXPORT_OK;
|
||||
|
||||
foreach my $strSection (keys(%EXPORT_TAGS))
|
||||
{
|
||||
# Assign values to serial constants like CFGCMD_* and CFGOPT_*. New commands and options (especially options) renumber the list
|
||||
# and cause a lot of churn in the commits. This takes care of the renumbering to cut down on that churn.
|
||||
my $strPrefixLast = 'XXXXXXXX';
|
||||
my $iConstantIdx = 0;
|
||||
|
||||
foreach my $strConstant (@{$EXPORT_TAGS{$strSection}})
|
||||
{
|
||||
my $strPrefix = ($strConstant =~ m/^[A-Z0-9]+/g)[0];
|
||||
|
||||
if (defined($strPrefix))
|
||||
{
|
||||
if ($strPrefix ne $strPrefixLast)
|
||||
{
|
||||
$iConstantIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iConstantIdx++;
|
||||
}
|
||||
|
||||
if ($strPrefix eq 'CFGCMD' || $strPrefix eq 'CFGOPT')
|
||||
{
|
||||
eval "use constant ${strConstant} => ${iConstantIdx}";
|
||||
}
|
||||
|
||||
$strPrefixLast = $strPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
# OK to export everything in the tag
|
||||
push(@EXPORT_OK, @{$EXPORT_TAGS{$strSection}});
|
||||
}
|
||||
|
||||
# Nothing is exported by default
|
||||
our @EXPORT = ();
|
||||
|
||||
1;
|
@ -1,356 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Automatically generated by Build.pm -- do not modify directly.
|
||||
####################################################################################################################################
|
||||
package pgBackRest::LibCAuto;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Configuration option value constants
|
||||
sub libcAutoConstant
|
||||
{
|
||||
return
|
||||
{
|
||||
CFGOPTVAL_COMPRESS_TYPE_NONE => 'none',
|
||||
CFGOPTVAL_COMPRESS_TYPE_GZ => 'gz',
|
||||
|
||||
CFGOPTVAL_INFO_OUTPUT_TEXT => 'text',
|
||||
CFGOPTVAL_INFO_OUTPUT_JSON => 'json',
|
||||
|
||||
CFGOPTVAL_REPO_LS_OUTPUT_TEXT => 'text',
|
||||
CFGOPTVAL_REPO_LS_OUTPUT_JSON => 'json',
|
||||
|
||||
CFGOPTVAL_REMOTE_TYPE_PG => 'pg',
|
||||
CFGOPTVAL_REMOTE_TYPE_REPO => 'repo',
|
||||
|
||||
CFGOPTVAL_REPO_CIPHER_TYPE_NONE => 'none',
|
||||
CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC => 'aes-256-cbc',
|
||||
|
||||
CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL => 'full',
|
||||
CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF => 'diff',
|
||||
CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR => 'incr',
|
||||
|
||||
CFGOPTVAL_REPO_S3_URI_STYLE_HOST => 'host',
|
||||
CFGOPTVAL_REPO_S3_URI_STYLE_PATH => 'path',
|
||||
|
||||
CFGOPTVAL_REPO_TYPE_CIFS => 'cifs',
|
||||
CFGOPTVAL_REPO_TYPE_POSIX => 'posix',
|
||||
CFGOPTVAL_REPO_TYPE_S3 => 's3',
|
||||
|
||||
CFGOPTVAL_SORT_NONE => 'none',
|
||||
CFGOPTVAL_SORT_ASC => 'asc',
|
||||
CFGOPTVAL_SORT_DESC => 'desc',
|
||||
|
||||
CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE => 'pause',
|
||||
CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE => 'promote',
|
||||
CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN => 'shutdown',
|
||||
|
||||
CFGOPTVAL_BACKUP_TYPE_FULL => 'full',
|
||||
CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff',
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR => 'incr',
|
||||
|
||||
CFGOPTVAL_RESTORE_TYPE_NAME => 'name',
|
||||
CFGOPTVAL_RESTORE_TYPE_TIME => 'time',
|
||||
CFGOPTVAL_RESTORE_TYPE_XID => 'xid',
|
||||
CFGOPTVAL_RESTORE_TYPE_PRESERVE => 'preserve',
|
||||
CFGOPTVAL_RESTORE_TYPE_NONE => 'none',
|
||||
CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate',
|
||||
CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default',
|
||||
CFGOPTVAL_RESTORE_TYPE_STANDBY => 'standby',
|
||||
|
||||
CFGDEF_TYPE_BOOLEAN => 0,
|
||||
CFGDEF_TYPE_FLOAT => 1,
|
||||
CFGDEF_TYPE_HASH => 2,
|
||||
CFGDEF_TYPE_INTEGER => 3,
|
||||
CFGDEF_TYPE_LIST => 4,
|
||||
CFGDEF_TYPE_PATH => 5,
|
||||
CFGDEF_TYPE_SIZE => 6,
|
||||
CFGDEF_TYPE_STRING => 7,
|
||||
|
||||
ENCODE_TYPE_BASE64 => 0,
|
||||
|
||||
CIPHER_MODE_ENCRYPT => 0,
|
||||
CIPHER_MODE_DECRYPT => 1,
|
||||
}
|
||||
}
|
||||
|
||||
# Export function and constants
|
||||
sub libcAutoExportTag
|
||||
{
|
||||
return
|
||||
{
|
||||
config =>
|
||||
[
|
||||
'CFGOPTVAL_COMPRESS_TYPE_NONE',
|
||||
'CFGOPTVAL_COMPRESS_TYPE_GZ',
|
||||
'CFGOPTVAL_INFO_OUTPUT_TEXT',
|
||||
'CFGOPTVAL_INFO_OUTPUT_JSON',
|
||||
'CFGOPTVAL_REPO_LS_OUTPUT_TEXT',
|
||||
'CFGOPTVAL_REPO_LS_OUTPUT_JSON',
|
||||
'CFGOPTVAL_REMOTE_TYPE_PG',
|
||||
'CFGOPTVAL_REMOTE_TYPE_REPO',
|
||||
'CFGOPTVAL_REPO_CIPHER_TYPE_NONE',
|
||||
'CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC',
|
||||
'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL',
|
||||
'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF',
|
||||
'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR',
|
||||
'CFGOPTVAL_REPO_S3_URI_STYLE_HOST',
|
||||
'CFGOPTVAL_REPO_S3_URI_STYLE_PATH',
|
||||
'CFGOPTVAL_REPO_TYPE_CIFS',
|
||||
'CFGOPTVAL_REPO_TYPE_POSIX',
|
||||
'CFGOPTVAL_REPO_TYPE_S3',
|
||||
'CFGOPTVAL_SORT_NONE',
|
||||
'CFGOPTVAL_SORT_ASC',
|
||||
'CFGOPTVAL_SORT_DESC',
|
||||
'CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE',
|
||||
'CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE',
|
||||
'CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN',
|
||||
'CFGOPTVAL_BACKUP_TYPE_FULL',
|
||||
'CFGOPTVAL_BACKUP_TYPE_DIFF',
|
||||
'CFGOPTVAL_BACKUP_TYPE_INCR',
|
||||
'CFGOPTVAL_RESTORE_TYPE_NAME',
|
||||
'CFGOPTVAL_RESTORE_TYPE_TIME',
|
||||
'CFGOPTVAL_RESTORE_TYPE_XID',
|
||||
'CFGOPTVAL_RESTORE_TYPE_PRESERVE',
|
||||
'CFGOPTVAL_RESTORE_TYPE_NONE',
|
||||
'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE',
|
||||
'CFGOPTVAL_RESTORE_TYPE_DEFAULT',
|
||||
'CFGOPTVAL_RESTORE_TYPE_STANDBY',
|
||||
'CFGCMD_ARCHIVE_GET',
|
||||
'CFGCMD_ARCHIVE_PUSH',
|
||||
'CFGCMD_BACKUP',
|
||||
'CFGCMD_CHECK',
|
||||
'CFGCMD_EXPIRE',
|
||||
'CFGCMD_HELP',
|
||||
'CFGCMD_INFO',
|
||||
'CFGCMD_REPO_CREATE',
|
||||
'CFGCMD_REPO_GET',
|
||||
'CFGCMD_REPO_LS',
|
||||
'CFGCMD_REPO_PUT',
|
||||
'CFGCMD_REPO_RM',
|
||||
'CFGCMD_RESTORE',
|
||||
'CFGCMD_STANZA_CREATE',
|
||||
'CFGCMD_STANZA_DELETE',
|
||||
'CFGCMD_STANZA_UPGRADE',
|
||||
'CFGCMD_START',
|
||||
'CFGCMD_STOP',
|
||||
'CFGCMD_VERSION',
|
||||
'CFGOPT_ARCHIVE_ASYNC',
|
||||
'CFGOPT_ARCHIVE_CHECK',
|
||||
'CFGOPT_ARCHIVE_COPY',
|
||||
'CFGOPT_ARCHIVE_GET_QUEUE_MAX',
|
||||
'CFGOPT_ARCHIVE_PUSH_QUEUE_MAX',
|
||||
'CFGOPT_ARCHIVE_TIMEOUT',
|
||||
'CFGOPT_BACKUP_STANDBY',
|
||||
'CFGOPT_BUFFER_SIZE',
|
||||
'CFGOPT_CHECKSUM_PAGE',
|
||||
'CFGOPT_CIPHER_PASS',
|
||||
'CFGOPT_CMD_SSH',
|
||||
'CFGOPT_COMPRESS',
|
||||
'CFGOPT_COMPRESS_LEVEL',
|
||||
'CFGOPT_COMPRESS_LEVEL_NETWORK',
|
||||
'CFGOPT_COMPRESS_TYPE',
|
||||
'CFGOPT_CONFIG',
|
||||
'CFGOPT_CONFIG_INCLUDE_PATH',
|
||||
'CFGOPT_CONFIG_PATH',
|
||||
'CFGOPT_DB_INCLUDE',
|
||||
'CFGOPT_DB_TIMEOUT',
|
||||
'CFGOPT_DELTA',
|
||||
'CFGOPT_EXCLUDE',
|
||||
'CFGOPT_FILTER',
|
||||
'CFGOPT_FORCE',
|
||||
'CFGOPT_HOST_ID',
|
||||
'CFGOPT_IGNORE_MISSING',
|
||||
'CFGOPT_LINK_ALL',
|
||||
'CFGOPT_LINK_MAP',
|
||||
'CFGOPT_LOCK_PATH',
|
||||
'CFGOPT_LOG_LEVEL_CONSOLE',
|
||||
'CFGOPT_LOG_LEVEL_FILE',
|
||||
'CFGOPT_LOG_LEVEL_STDERR',
|
||||
'CFGOPT_LOG_PATH',
|
||||
'CFGOPT_LOG_SUBPROCESS',
|
||||
'CFGOPT_LOG_TIMESTAMP',
|
||||
'CFGOPT_MANIFEST_SAVE_THRESHOLD',
|
||||
'CFGOPT_NEUTRAL_UMASK',
|
||||
'CFGOPT_ONLINE',
|
||||
'CFGOPT_OUTPUT',
|
||||
'CFGOPT_PG_HOST',
|
||||
'CFGOPT_PG_HOST2',
|
||||
'CFGOPT_PG_HOST3',
|
||||
'CFGOPT_PG_HOST4',
|
||||
'CFGOPT_PG_HOST5',
|
||||
'CFGOPT_PG_HOST6',
|
||||
'CFGOPT_PG_HOST7',
|
||||
'CFGOPT_PG_HOST8',
|
||||
'CFGOPT_PG_HOST_CMD',
|
||||
'CFGOPT_PG_HOST_CMD2',
|
||||
'CFGOPT_PG_HOST_CMD3',
|
||||
'CFGOPT_PG_HOST_CMD4',
|
||||
'CFGOPT_PG_HOST_CMD5',
|
||||
'CFGOPT_PG_HOST_CMD6',
|
||||
'CFGOPT_PG_HOST_CMD7',
|
||||
'CFGOPT_PG_HOST_CMD8',
|
||||
'CFGOPT_PG_HOST_CONFIG',
|
||||
'CFGOPT_PG_HOST_CONFIG2',
|
||||
'CFGOPT_PG_HOST_CONFIG3',
|
||||
'CFGOPT_PG_HOST_CONFIG4',
|
||||
'CFGOPT_PG_HOST_CONFIG5',
|
||||
'CFGOPT_PG_HOST_CONFIG6',
|
||||
'CFGOPT_PG_HOST_CONFIG7',
|
||||
'CFGOPT_PG_HOST_CONFIG8',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH2',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH3',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH4',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH5',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH6',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH7',
|
||||
'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH8',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH2',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH3',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH4',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH5',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH6',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH7',
|
||||
'CFGOPT_PG_HOST_CONFIG_PATH8',
|
||||
'CFGOPT_PG_HOST_PORT',
|
||||
'CFGOPT_PG_HOST_PORT2',
|
||||
'CFGOPT_PG_HOST_PORT3',
|
||||
'CFGOPT_PG_HOST_PORT4',
|
||||
'CFGOPT_PG_HOST_PORT5',
|
||||
'CFGOPT_PG_HOST_PORT6',
|
||||
'CFGOPT_PG_HOST_PORT7',
|
||||
'CFGOPT_PG_HOST_PORT8',
|
||||
'CFGOPT_PG_HOST_USER',
|
||||
'CFGOPT_PG_HOST_USER2',
|
||||
'CFGOPT_PG_HOST_USER3',
|
||||
'CFGOPT_PG_HOST_USER4',
|
||||
'CFGOPT_PG_HOST_USER5',
|
||||
'CFGOPT_PG_HOST_USER6',
|
||||
'CFGOPT_PG_HOST_USER7',
|
||||
'CFGOPT_PG_HOST_USER8',
|
||||
'CFGOPT_PG_PATH',
|
||||
'CFGOPT_PG_PATH2',
|
||||
'CFGOPT_PG_PATH3',
|
||||
'CFGOPT_PG_PATH4',
|
||||
'CFGOPT_PG_PATH5',
|
||||
'CFGOPT_PG_PATH6',
|
||||
'CFGOPT_PG_PATH7',
|
||||
'CFGOPT_PG_PATH8',
|
||||
'CFGOPT_PG_PORT',
|
||||
'CFGOPT_PG_PORT2',
|
||||
'CFGOPT_PG_PORT3',
|
||||
'CFGOPT_PG_PORT4',
|
||||
'CFGOPT_PG_PORT5',
|
||||
'CFGOPT_PG_PORT6',
|
||||
'CFGOPT_PG_PORT7',
|
||||
'CFGOPT_PG_PORT8',
|
||||
'CFGOPT_PG_SOCKET_PATH',
|
||||
'CFGOPT_PG_SOCKET_PATH2',
|
||||
'CFGOPT_PG_SOCKET_PATH3',
|
||||
'CFGOPT_PG_SOCKET_PATH4',
|
||||
'CFGOPT_PG_SOCKET_PATH5',
|
||||
'CFGOPT_PG_SOCKET_PATH6',
|
||||
'CFGOPT_PG_SOCKET_PATH7',
|
||||
'CFGOPT_PG_SOCKET_PATH8',
|
||||
'CFGOPT_PG_USER',
|
||||
'CFGOPT_PG_USER2',
|
||||
'CFGOPT_PG_USER3',
|
||||
'CFGOPT_PG_USER4',
|
||||
'CFGOPT_PG_USER5',
|
||||
'CFGOPT_PG_USER6',
|
||||
'CFGOPT_PG_USER7',
|
||||
'CFGOPT_PG_USER8',
|
||||
'CFGOPT_PROCESS',
|
||||
'CFGOPT_PROCESS_MAX',
|
||||
'CFGOPT_PROTOCOL_TIMEOUT',
|
||||
'CFGOPT_RAW',
|
||||
'CFGOPT_RECOVERY_OPTION',
|
||||
'CFGOPT_RECURSE',
|
||||
'CFGOPT_REMOTE_TYPE',
|
||||
'CFGOPT_REPO_CIPHER_PASS',
|
||||
'CFGOPT_REPO_CIPHER_TYPE',
|
||||
'CFGOPT_REPO_HARDLINK',
|
||||
'CFGOPT_REPO_HOST',
|
||||
'CFGOPT_REPO_HOST_CMD',
|
||||
'CFGOPT_REPO_HOST_CONFIG',
|
||||
'CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH',
|
||||
'CFGOPT_REPO_HOST_CONFIG_PATH',
|
||||
'CFGOPT_REPO_HOST_PORT',
|
||||
'CFGOPT_REPO_HOST_USER',
|
||||
'CFGOPT_REPO_PATH',
|
||||
'CFGOPT_REPO_RETENTION_ARCHIVE',
|
||||
'CFGOPT_REPO_RETENTION_ARCHIVE_TYPE',
|
||||
'CFGOPT_REPO_RETENTION_DIFF',
|
||||
'CFGOPT_REPO_RETENTION_FULL',
|
||||
'CFGOPT_REPO_S3_BUCKET',
|
||||
'CFGOPT_REPO_S3_CA_FILE',
|
||||
'CFGOPT_REPO_S3_CA_PATH',
|
||||
'CFGOPT_REPO_S3_ENDPOINT',
|
||||
'CFGOPT_REPO_S3_HOST',
|
||||
'CFGOPT_REPO_S3_KEY',
|
||||
'CFGOPT_REPO_S3_KEY_SECRET',
|
||||
'CFGOPT_REPO_S3_PORT',
|
||||
'CFGOPT_REPO_S3_REGION',
|
||||
'CFGOPT_REPO_S3_TOKEN',
|
||||
'CFGOPT_REPO_S3_URI_STYLE',
|
||||
'CFGOPT_REPO_S3_VERIFY_TLS',
|
||||
'CFGOPT_REPO_TYPE',
|
||||
'CFGOPT_RESUME',
|
||||
'CFGOPT_SET',
|
||||
'CFGOPT_SORT',
|
||||
'CFGOPT_SPOOL_PATH',
|
||||
'CFGOPT_STANZA',
|
||||
'CFGOPT_START_FAST',
|
||||
'CFGOPT_STOP_AUTO',
|
||||
'CFGOPT_TABLESPACE_MAP',
|
||||
'CFGOPT_TABLESPACE_MAP_ALL',
|
||||
'CFGOPT_TARGET',
|
||||
'CFGOPT_TARGET_ACTION',
|
||||
'CFGOPT_TARGET_EXCLUSIVE',
|
||||
'CFGOPT_TARGET_TIMELINE',
|
||||
'CFGOPT_TYPE',
|
||||
'cfgCommandName',
|
||||
'cfgOptionIndexTotal',
|
||||
'cfgOptionName',
|
||||
],
|
||||
|
||||
configDefine =>
|
||||
[
|
||||
'CFGDEF_TYPE_BOOLEAN',
|
||||
'CFGDEF_TYPE_FLOAT',
|
||||
'CFGDEF_TYPE_HASH',
|
||||
'CFGDEF_TYPE_INTEGER',
|
||||
'CFGDEF_TYPE_LIST',
|
||||
'CFGDEF_TYPE_PATH',
|
||||
'CFGDEF_TYPE_SIZE',
|
||||
'CFGDEF_TYPE_STRING',
|
||||
'cfgCommandId',
|
||||
'cfgDefOptionDefault',
|
||||
'cfgDefOptionPrefix',
|
||||
'cfgDefOptionSecure',
|
||||
'cfgDefOptionType',
|
||||
'cfgDefOptionValid',
|
||||
'cfgOptionId',
|
||||
'cfgOptionTotal',
|
||||
],
|
||||
|
||||
debug =>
|
||||
[
|
||||
'libcUvSize',
|
||||
],
|
||||
|
||||
storage =>
|
||||
[
|
||||
'storageRepoFree',
|
||||
],
|
||||
|
||||
test =>
|
||||
[
|
||||
'cfgParseTest',
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -18,8 +18,6 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
@ -94,31 +92,31 @@ use constant MANIFEST_KEY_TYPE => 'backup-t
|
||||
push @EXPORT, qw(MANIFEST_KEY_TYPE);
|
||||
|
||||
# Options that were set when the backup was made
|
||||
use constant MANIFEST_KEY_BACKUP_STANDBY => 'option-' . cfgOptionName(CFGOPT_BACKUP_STANDBY);
|
||||
use constant MANIFEST_KEY_BACKUP_STANDBY => 'option-backup-standby';
|
||||
push @EXPORT, qw(MANIFEST_KEY_BACKUP_STANDBY);
|
||||
use constant MANIFEST_KEY_HARDLINK => 'option-hardlink';
|
||||
push @EXPORT, qw(MANIFEST_KEY_HARDLINK);
|
||||
use constant MANIFEST_KEY_ARCHIVE_CHECK => 'option-' . cfgOptionName(CFGOPT_ARCHIVE_CHECK);
|
||||
use constant MANIFEST_KEY_ARCHIVE_CHECK => 'option-archive-check';
|
||||
push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_CHECK);
|
||||
use constant MANIFEST_KEY_ARCHIVE_COPY => 'option-' .cfgOptionName(CFGOPT_ARCHIVE_COPY);
|
||||
use constant MANIFEST_KEY_ARCHIVE_COPY => 'option-archive-copy';
|
||||
push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_COPY);
|
||||
use constant MANIFEST_KEY_BUFFER_SIZE => 'option-' . cfgOptionName(CFGOPT_BUFFER_SIZE);
|
||||
use constant MANIFEST_KEY_BUFFER_SIZE => 'option-buffer-size';
|
||||
push @EXPORT, qw(MANIFEST_KEY_BUFFER_SIZE);
|
||||
use constant MANIFEST_KEY_CHECKSUM_PAGE => 'option-' . cfgOptionName(CFGOPT_CHECKSUM_PAGE);
|
||||
use constant MANIFEST_KEY_CHECKSUM_PAGE => 'option-checksum-page';
|
||||
push @EXPORT, qw(MANIFEST_KEY_CHECKSUM_PAGE);
|
||||
use constant MANIFEST_KEY_COMPRESS => 'option-' . cfgOptionName(CFGOPT_COMPRESS);
|
||||
use constant MANIFEST_KEY_COMPRESS => 'option-compress';
|
||||
push @EXPORT, qw(MANIFEST_KEY_COMPRESS);
|
||||
use constant MANIFEST_KEY_COMPRESS_TYPE => 'option-' . cfgOptionName(CFGOPT_COMPRESS_TYPE);
|
||||
use constant MANIFEST_KEY_COMPRESS_TYPE => 'option-compress-type';
|
||||
push @EXPORT, qw(MANIFEST_KEY_COMPRESS_TYPE);
|
||||
use constant MANIFEST_KEY_COMPRESS_LEVEL => 'option-' . cfgOptionName(CFGOPT_COMPRESS_LEVEL);
|
||||
use constant MANIFEST_KEY_COMPRESS_LEVEL => 'option-compress-level';
|
||||
push @EXPORT, qw(MANIFEST_KEY_COMPRESS_LEVEL);
|
||||
use constant MANIFEST_KEY_COMPRESS_LEVEL_NETWORK => 'option-' . cfgOptionName(CFGOPT_COMPRESS_LEVEL_NETWORK);
|
||||
use constant MANIFEST_KEY_COMPRESS_LEVEL_NETWORK => 'option-compress-level-network';
|
||||
push @EXPORT, qw(MANIFEST_KEY_COMPRESS_LEVEL_NETWORK);
|
||||
use constant MANIFEST_KEY_ONLINE => 'option-' . cfgOptionName(CFGOPT_ONLINE);
|
||||
use constant MANIFEST_KEY_ONLINE => 'option-online';
|
||||
push @EXPORT, qw(MANIFEST_KEY_ONLINE);
|
||||
use constant MANIFEST_KEY_DELTA => 'option-' . cfgOptionName(CFGOPT_DELTA);
|
||||
use constant MANIFEST_KEY_DELTA => 'option-delta';
|
||||
push @EXPORT, qw(MANIFEST_KEY_DELTA);
|
||||
use constant MANIFEST_KEY_PROCESS_MAX => 'option-' . cfgOptionName(CFGOPT_PROCESS_MAX);
|
||||
use constant MANIFEST_KEY_PROCESS_MAX => 'option-process-max';
|
||||
push @EXPORT, qw(MANIFEST_KEY_PROCESS_MAX);
|
||||
|
||||
# Information about the database that was backed up
|
||||
@ -320,8 +318,8 @@ sub new
|
||||
);
|
||||
|
||||
# Init object and store variables
|
||||
my $self = $class->SUPER::new($strFileName, {bLoad => $bLoad, oStorage => $oStorage, strCipherPass => $strCipherPass,
|
||||
strCipherPassSub => $strCipherPassSub});
|
||||
my $self = $class->SUPER::new(
|
||||
$oStorage, $strFileName, {bLoad => $bLoad, strCipherPass => $strCipherPass, strCipherPassSub => $strCipherPassSub});
|
||||
|
||||
# If manifest not loaded from a file then the db version and catalog version must be set
|
||||
if (!$bLoad)
|
||||
@ -1111,9 +1109,6 @@ sub build
|
||||
# consistent anyway and the one-second resolution problem is the least of our worries).
|
||||
my $lTimeBegin = waitRemainder($bOnline);
|
||||
|
||||
# Check that links are valid
|
||||
$self->linkCheck();
|
||||
|
||||
if (defined($oLastManifest))
|
||||
{
|
||||
$self->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef,
|
||||
@ -1244,52 +1239,6 @@ sub build
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# linkCheck
|
||||
#
|
||||
# Check all link targets and make sure none of them are a subset of another link. In theory it would be possible to resolve the
|
||||
# dependencies and generate a valid backup/restore but it's really complicated and there don't seem to be any compelling use cases.
|
||||
####################################################################################################################################
|
||||
sub linkCheck
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->linkCheck');
|
||||
|
||||
# Working variable
|
||||
my $strBasePath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH);
|
||||
|
||||
foreach my $strTargetParent ($self->keys(MANIFEST_SECTION_BACKUP_TARGET))
|
||||
{
|
||||
if ($self->isTargetLink($strTargetParent))
|
||||
{
|
||||
my $strParentPath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_PATH);
|
||||
my $strParentFile = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_FILE, false);
|
||||
|
||||
foreach my $strTargetChild ($self->keys(MANIFEST_SECTION_BACKUP_TARGET))
|
||||
{
|
||||
if ($self->isTargetLink($strTargetChild) && $strTargetParent ne $strTargetChild)
|
||||
{
|
||||
my $strChildPath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetChild, MANIFEST_SUBKEY_PATH);
|
||||
my $strChildFile = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_FILE, false);
|
||||
|
||||
if (!(defined($strParentFile) && defined($strChildFile)) &&
|
||||
index(
|
||||
storageLocal()->pathAbsolute($strBasePath, $strChildPath) . '/',
|
||||
storageLocal()->pathAbsolute($strBasePath, $strParentPath) . '/') == 0)
|
||||
{
|
||||
confess &log(ERROR, 'link ' . $self->dbPathGet($strBasePath, $strTargetChild) .
|
||||
" (${strChildPath}) references a subdirectory of or" .
|
||||
" the same directory as link " . $self->dbPathGet($strBasePath, $strTargetParent) .
|
||||
" (${strParentPath})", ERROR_LINK_DESTINATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# fileAdd
|
||||
#
|
||||
|
@ -1,89 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Db & Repository Storage Helper
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Protocol::Storage::Helper;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(basename);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::LibC qw(:storage);
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
####################################################################################################################################
|
||||
# Storage constants
|
||||
####################################################################################################################################
|
||||
use constant STORAGE_DB => '<DB>';
|
||||
push @EXPORT, qw(STORAGE_DB);
|
||||
|
||||
use constant STORAGE_REPO => '<REPO>';
|
||||
push @EXPORT, qw(STORAGE_REPO);
|
||||
use constant STORAGE_REPO_ARCHIVE => '<REPO:ARCHIVE>';
|
||||
push @EXPORT, qw(STORAGE_REPO_ARCHIVE);
|
||||
use constant STORAGE_REPO_BACKUP => '<REPO:BACKUP>';
|
||||
push @EXPORT, qw(STORAGE_REPO_BACKUP);
|
||||
|
||||
####################################################################################################################################
|
||||
# Cache storage so it can be retrieved quickly
|
||||
####################################################################################################################################
|
||||
my $hStorage;
|
||||
|
||||
####################################################################################################################################
|
||||
# storageRepo - get repository storage
|
||||
####################################################################################################################################
|
||||
sub storageRepo
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strStanza,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::storageRepo', \@_,
|
||||
{name => 'strStanza', optional => true, trace => true},
|
||||
);
|
||||
|
||||
# Create storage if not defined
|
||||
if (!defined($hStorage->{&STORAGE_REPO}))
|
||||
{
|
||||
$hStorage->{&STORAGE_REPO} = new pgBackRest::Storage::Storage(
|
||||
STORAGE_REPO, {lBufferMax => cfgOption(CFGOPT_BUFFER_SIZE)});
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oStorageRepo', value => $hStorage->{&STORAGE_REPO}, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepo);
|
||||
|
||||
####################################################################################################################################
|
||||
# Clear the repo storage cache - FOR TESTING ONLY!
|
||||
####################################################################################################################################
|
||||
sub storageRepoCacheClear
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '::storageRepoCacheClear');
|
||||
|
||||
delete($hStorage->{&STORAGE_REPO});
|
||||
|
||||
storageRepoFree();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepoCacheClear);
|
||||
|
||||
1;
|
@ -23,8 +23,8 @@ use pgBackRest::Common::Log;
|
||||
use constant STORAGE_LOCAL => '<LOCAL>';
|
||||
push @EXPORT, qw(STORAGE_LOCAL);
|
||||
|
||||
use constant STORAGE_S3 => 's3';
|
||||
push @EXPORT, qw(STORAGE_S3);
|
||||
use constant STORAGE_OBJECT => 'object';
|
||||
push @EXPORT, qw(STORAGE_OBJECT);
|
||||
use constant STORAGE_POSIX => 'posix';
|
||||
push @EXPORT, qw(STORAGE_POSIX);
|
||||
|
||||
@ -71,145 +71,6 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
####################################################################################################################################
|
||||
# Copy a file. If special encryption settings are required, then the file objects from openRead/openWrite must be passed instead of
|
||||
# file names.
|
||||
####################################################################################################################################
|
||||
sub copy
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xSourceFile,
|
||||
$xDestinationFile,
|
||||
$bSourceOpen,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->copy', \@_,
|
||||
{name => 'xSourceFile', required => false},
|
||||
{name => 'xDestinationFile'},
|
||||
{name => 'bSourceOpen', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Is source/destination an IO object or a file expression?
|
||||
my $oSourceFileIo = defined($xSourceFile) ? (ref($xSourceFile) ? $xSourceFile : $self->openRead($xSourceFile)) : undef;
|
||||
|
||||
# Does the source file exist?
|
||||
my $bResult = false;
|
||||
|
||||
# Copy if the source file exists
|
||||
if (defined($oSourceFileIo))
|
||||
{
|
||||
my $oDestinationFileIo = ref($xDestinationFile) ? $xDestinationFile : $self->openWrite($xDestinationFile);
|
||||
|
||||
# Use C copy if source and destination are C objects
|
||||
if (defined($oSourceFileIo->{oStorageCRead}) && defined($oDestinationFileIo->{oStorageCWrite}))
|
||||
{
|
||||
$bResult = $self->{oStorageC}->copy(
|
||||
$oSourceFileIo->{oStorageCRead}, $oDestinationFileIo->{oStorageCWrite}) ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Open the source file if it is a C object
|
||||
$bResult = defined($oSourceFileIo->{oStorageCRead}) ? ($bSourceOpen || $oSourceFileIo->open()) : true;
|
||||
|
||||
if ($bResult)
|
||||
{
|
||||
# Open the destination file if it is a C object
|
||||
if (defined($oDestinationFileIo->{oStorageCWrite}))
|
||||
{
|
||||
$oDestinationFileIo->open();
|
||||
}
|
||||
|
||||
# Copy the data
|
||||
do
|
||||
{
|
||||
# Read data
|
||||
my $tBuffer = '';
|
||||
|
||||
$oSourceFileIo->read(\$tBuffer, $self->{lBufferMax});
|
||||
$oDestinationFileIo->write(\$tBuffer);
|
||||
}
|
||||
while (!$oSourceFileIo->eof());
|
||||
|
||||
# Close files
|
||||
$oSourceFileIo->close();
|
||||
$oDestinationFileIo->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => $bResult, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# get - reads a buffer from storage all at once
|
||||
####################################################################################################################################
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$strCipherPass,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->get', \@_,
|
||||
{name => 'xFile', required => false, trace => true},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or
|
||||
# if the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = defined($xFile) ? (ref($xFile) ? $xFile : $self->openRead(
|
||||
$xFile, {strCipherPass => defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser()})) : undef;
|
||||
|
||||
# Read only if there is something to read from
|
||||
my $tContent;
|
||||
my $lSize = 0;
|
||||
|
||||
if (defined($oFileIo))
|
||||
{
|
||||
my $lSizeRead;
|
||||
|
||||
do
|
||||
{
|
||||
$lSizeRead = $oFileIo->read(\$tContent, $self->{lBufferMax});
|
||||
$lSize += $lSizeRead;
|
||||
}
|
||||
while ($lSizeRead != 0);
|
||||
|
||||
# Close the file
|
||||
$oFileIo->close();
|
||||
|
||||
# If nothing was read then set to undef
|
||||
if ($lSize == 0)
|
||||
{
|
||||
$tContent = undef;
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rtContent', value => defined($oFileIo) ? \$tContent : undef, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Calculate sha1 hash and size of file. If special encryption settings are required, then the file objects from openRead/openWrite
|
||||
# must be passed instead of file names.
|
||||
@ -328,57 +189,4 @@ sub pathAbsolute
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# put - writes a buffer out to storage all at once
|
||||
####################################################################################################################################
|
||||
sub put
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$xContent,
|
||||
$strCipherPass,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->put', \@_,
|
||||
{name => 'xFile', trace => true},
|
||||
{name => 'xContent', required => false, trace => true},
|
||||
{name => 'strCipherPass', optional => true, trace => true, redact => true},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or if
|
||||
# the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = ref($xFile) ? $xFile : $self->openWrite(
|
||||
$xFile, {strCipherPass => defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser()});
|
||||
|
||||
# Determine size of content
|
||||
my $lSize = defined($xContent) ? length(ref($xContent) ? $$xContent : $xContent) : 0;
|
||||
|
||||
# Write only if there is something to write
|
||||
if ($lSize > 0)
|
||||
{
|
||||
$oFileIo->write(ref($xContent) ? $xContent : \$xContent);
|
||||
}
|
||||
# Else open the file so a zero length file is created (since file is not opened until first write)
|
||||
else
|
||||
{
|
||||
$oFileIo->open();
|
||||
}
|
||||
|
||||
# Close the file
|
||||
$oFileIo->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'lSize', value => $lSize, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -1,5 +1,5 @@
|
||||
####################################################################################################################################
|
||||
# Local Storage Helper
|
||||
# Repository Storage Helper
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Storage::Helper;
|
||||
|
||||
@ -12,17 +12,9 @@ use Exporter qw(import);
|
||||
use File::Basename qw(basename);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Storage;
|
||||
use pgBackRest::Version;
|
||||
|
||||
####################################################################################################################################
|
||||
# Compression extension
|
||||
####################################################################################################################################
|
||||
use constant COMPRESS_EXT => 'gz';
|
||||
push @EXPORT, qw(COMPRESS_EXT);
|
||||
|
||||
####################################################################################################################################
|
||||
# Temp file extension
|
||||
####################################################################################################################################
|
||||
@ -30,24 +22,88 @@ use constant STORAGE_TEMP_EXT => PROJECT_E
|
||||
push @EXPORT, qw(STORAGE_TEMP_EXT);
|
||||
|
||||
####################################################################################################################################
|
||||
# storageLocal - get local storage
|
||||
#
|
||||
# Local storage is generally read-only (except for locking) and can never reference a remote path. Used for adhoc activities like
|
||||
# reading pgbackrest.conf.
|
||||
# Cache storage so it can be retrieved quickly
|
||||
####################################################################################################################################
|
||||
sub storageLocal
|
||||
my $oRepoStorage;
|
||||
|
||||
####################################################################################################################################
|
||||
# storageRepoCommandSet
|
||||
####################################################################################################################################
|
||||
my $strStorageRepoCommand;
|
||||
my $strStorageRepoType;
|
||||
|
||||
sub storageRepoCommandSet
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '::storageLocal');
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
$strStorageType,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::storageRepoCommandSet', \@_,
|
||||
{name => 'strCommand'},
|
||||
{name => 'strStorageType'},
|
||||
);
|
||||
|
||||
$strStorageRepoCommand = $strCommand;
|
||||
$strStorageRepoType = $strStorageType;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepoCommandSet);
|
||||
|
||||
####################################################################################################################################
|
||||
# storageRepo - get repository storage
|
||||
####################################################################################################################################
|
||||
sub storageRepo
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strStanza,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::storageRepo', \@_,
|
||||
{name => 'strStanza', optional => true, trace => true},
|
||||
);
|
||||
|
||||
# Create storage if not defined
|
||||
if (!defined($oRepoStorage))
|
||||
{
|
||||
$oRepoStorage = new pgBackRest::Storage::Storage($strStorageRepoCommand, $strStorageRepoType, 64 * 1024, 60);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oStorageLocal', value => new pgBackRest::Storage::Storage(STORAGE_LOCAL), trace => true},
|
||||
{name => 'oStorageRepo', value => $oRepoStorage, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageLocal);
|
||||
push @EXPORT, qw(storageRepo);
|
||||
|
||||
####################################################################################################################################
|
||||
# Clear the repo storage cache - FOR TESTING ONLY!
|
||||
####################################################################################################################################
|
||||
sub storageRepoCacheClear
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '::storageRepoCacheClear');
|
||||
|
||||
undef($oRepoStorage);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepoCacheClear);
|
||||
|
||||
1;
|
||||
|
@ -17,10 +17,9 @@ use JSON::PP;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Handle;
|
||||
use pgBackRest::Common::Io::Process;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::StorageRead;
|
||||
use pgBackRest::Storage::StorageWrite;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
@ -36,32 +35,24 @@ sub new
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strCommand},
|
||||
$self->{strType},
|
||||
$self->{strPath},
|
||||
$self->{lBufferMax},
|
||||
$self->{iTimeoutIo},
|
||||
$self->{strDefaultPathMode},
|
||||
$self->{strDefaultFileMode},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strCommand'},
|
||||
{name => 'strType'},
|
||||
{name => 'strPath', optional => true},
|
||||
{name => 'lBufferMax', optional => true, default => 65536},
|
||||
{name => 'lBufferMax'},
|
||||
{name => 'iTimeoutIo'},
|
||||
{name => 'strDefaultPathMode', optional => true, default => '0750'},
|
||||
{name => 'strDefaultFileMode', optional => true, default => '0640'},
|
||||
);
|
||||
|
||||
# Create C storage object
|
||||
$self->{oStorageC} = pgBackRest::LibC::Storage->new($self->{strType}, $self->{strPath});
|
||||
|
||||
# Get encryption settings
|
||||
if ($self->{strType} eq '<REPO>')
|
||||
{
|
||||
$self->{strCipherType} = $self->{oStorageC}->cipherType();
|
||||
$self->{strCipherPass} = $self->{oStorageC}->cipherPass();
|
||||
}
|
||||
|
||||
# Create JSON object
|
||||
$self->{oJSON} = JSON::PP->new()->allow_nonref();
|
||||
|
||||
@ -73,6 +64,103 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Escape characteres that have special meaning on the command line
|
||||
####################################################################################################################################
|
||||
sub escape
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strValue,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->escape', \@_,
|
||||
{name => 'strValue', trace => true},
|
||||
);
|
||||
|
||||
$strValue =~ s/\\/\\\\/g;
|
||||
$strValue =~ s/\</\\\</g;
|
||||
$strValue =~ s/\>/\\\>/g;
|
||||
$strValue =~ s/\!/\\\!/g;
|
||||
$strValue =~ s/\*/\\\*/g;
|
||||
$strValue =~ s/\(/\\\(/g;
|
||||
$strValue =~ s/\)/\\\)/g;
|
||||
$strValue =~ s/\&/\\\&/g;
|
||||
$strValue =~ s/\'/\\\'/g;
|
||||
$strValue =~ s/\;/\\\;/g;
|
||||
$strValue =~ s/\?/\\\?/g;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strValue', value => $strValue},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Execute command and return the output
|
||||
####################################################################################################################################
|
||||
sub exec
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->exec', \@_,
|
||||
{name => 'strCommand'},
|
||||
);
|
||||
|
||||
$strCommand = "$self->{strCommand} ${strCommand}";
|
||||
my $oBuffer = new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle($strCommand), $self->{iTimeoutIo}, $self->{lBufferMax});
|
||||
my $oProcess = new pgBackRest::Common::Io::Process($oBuffer, $strCommand);
|
||||
|
||||
my $tResult;
|
||||
|
||||
while (!$oBuffer->eof())
|
||||
{
|
||||
$oBuffer->read(\$tResult, $self->{lBufferMax}, false);
|
||||
}
|
||||
|
||||
$oProcess->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'tResult', value => $tResult},
|
||||
{name => 'iExitStatus', value => $oProcess->exitStatus()},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Create storage
|
||||
####################################################################################################################################
|
||||
sub create
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->create');
|
||||
|
||||
$self->exec("repo-create");
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Check if file exists (not a path)
|
||||
####################################################################################################################################
|
||||
@ -96,7 +184,7 @@ sub exists
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bExists', value => defined($self->info($strFileExp, {bIgnoreMissing => true}))}
|
||||
{name => 'bExists', value => $self->info($strFileExp, {bIgnoreMissing => true})->{type} eq 'f'}
|
||||
);
|
||||
}
|
||||
|
||||
@ -113,33 +201,49 @@ sub get
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$strCipherPass,
|
||||
$bRaw,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->get', \@_,
|
||||
{name => 'xFile', required => false, trace => true},
|
||||
{name => 'strCipherPass', optional => true, default => $self->cipherPassUser(), redact => true},
|
||||
{name => 'xFile', required => false},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
{name => 'bRaw', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or
|
||||
# if the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = defined($xFile) ? (ref($xFile) ? $xFile : $self->openRead($xFile, {strCipherPass => $strCipherPass})) : undef;
|
||||
# If openRead() was called first set values from that call
|
||||
my $strFile = $xFile;
|
||||
my $bIgnoreMissing = false;
|
||||
|
||||
# Get the file contents
|
||||
my $bEmpty = false;
|
||||
my $tContent = $self->{oStorageC}->get($oFileIo->{oStorageCRead});
|
||||
|
||||
if (defined($tContent) && length($tContent) == 0)
|
||||
if (ref($xFile))
|
||||
{
|
||||
$tContent = undef;
|
||||
$bEmpty = true;
|
||||
$strFile = $xFile->{strFile};
|
||||
$bIgnoreMissing = $xFile->{bIgnoreMissing};
|
||||
$strCipherPass = $xFile->{strCipherPass};
|
||||
}
|
||||
|
||||
# Check invalid params
|
||||
if ($bRaw && defined($strCipherPass))
|
||||
{
|
||||
confess &log(ERROR, 'bRaw and strCipherPass cannot both be set');
|
||||
}
|
||||
|
||||
# Get file
|
||||
my ($tResult, $iExitStatus) = $self->exec(
|
||||
(defined($strCipherPass) ? ' --cipher-pass=' . $self->escape($strCipherPass) : '') . ($bRaw ? ' --raw' : '') .
|
||||
($bIgnoreMissing ? ' --ignore-missing' : '') . ' repo-get ' . $self->escape($strFile));
|
||||
|
||||
# Error if missing an not ignored
|
||||
if ($iExitStatus == 1 && !$bIgnoreMissing)
|
||||
{
|
||||
confess &log(ERROR, "unable to open '${strFile}'", ERROR_FILE_OPEN);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rtContent', value => defined($tContent) || $bEmpty ? \$tContent : undef, trace => true},
|
||||
{name => 'rtContent', value => $iExitStatus == 0 ? \$tResult : undef, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
@ -164,19 +268,11 @@ sub info
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
);
|
||||
|
||||
my $rhInfo;
|
||||
my $strJson = $self->{oStorageC}->info($strPathFileExp, $bIgnoreMissing);
|
||||
|
||||
if (defined($strJson))
|
||||
{
|
||||
$rhInfo = $self->{oJSON}->decode($strJson);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rhInfo', value => $rhInfo, trace => true}
|
||||
{name => 'rhInfo', value => $self->manifest($strPathFileExp, {bRecurse => false})->{'.'}, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
@ -207,11 +303,14 @@ sub list
|
||||
|
||||
# Get file list
|
||||
my $rstryFileList = [];
|
||||
my $strFileList = $self->{oStorageC}->list($strPathExp, $bIgnoreMissing, $strSortOrder eq 'forward', $strExpression);
|
||||
my $rhManifest = $self->manifest($strPathExp, {bRecurse => false});
|
||||
|
||||
if (defined($strFileList) && $strFileList ne '[]')
|
||||
foreach my $strKey ($strSortOrder eq 'reverse' ? sort {$b cmp $a} keys(%{$rhManifest}) : sort keys(%{$rhManifest}))
|
||||
{
|
||||
$rstryFileList = $self->{oJSON}->decode($strFileList);
|
||||
next if $strKey eq '.';
|
||||
next if defined($strExpression) && $strKey !~ $strExpression;
|
||||
|
||||
push(@{$rstryFileList}, $strKey);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -234,50 +333,54 @@ sub manifest
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
$strFilter,
|
||||
$bRecurse,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manifest', \@_,
|
||||
{name => 'strPathExp'},
|
||||
{name => 'strFilter', optional => true, trace => true},
|
||||
{name => 'bRecurse', optional => true, default => true},
|
||||
);
|
||||
|
||||
my $hManifest = $self->{oJSON}->decode($self->manifestJson($strPathExp, {strFilter => $strFilter}));
|
||||
my $rhManifest = $self->{oJSON}->decode(
|
||||
$self->exec("--output=json " . ($bRecurse ? ' --recurse' : '') . " repo-ls " . $self->escape($strPathExp)));
|
||||
|
||||
# Transform the manifest to the old format
|
||||
foreach my $strKey (keys(%{$rhManifest}))
|
||||
{
|
||||
if ($rhManifest->{$strKey}{type} eq 'file')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'f';
|
||||
|
||||
if (defined($rhManifest->{$strKey}{time}))
|
||||
{
|
||||
$rhManifest->{$strKey}{modified_time} = $rhManifest->{$strKey}{time};
|
||||
delete($rhManifest->{$strKey}{time});
|
||||
}
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'path')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'd';
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'link')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'l';
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'special')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 's';
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "invalid file type '$rhManifest->{type}'";
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'hManifest', value => $hManifest, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
sub manifestJson
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
$strFilter,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manifestJson', \@_,
|
||||
{name => 'strPathExp'},
|
||||
{name => 'strFilter', optional => true, trace => true},
|
||||
);
|
||||
|
||||
my $strManifestJson = $self->{oStorageC}->manifest($strPathExp, $strFilter);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strManifestJson', value => $strManifestJson, trace => true}
|
||||
{name => 'rhManifest', value => $rhManifest, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
@ -292,137 +395,24 @@ sub openRead
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFileExp,
|
||||
$strFile,
|
||||
$bIgnoreMissing,
|
||||
$rhyFilter,
|
||||
$strCipherPass,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->openRead', \@_,
|
||||
{name => 'xFileExp'},
|
||||
{name => 'strFile'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
{name => 'rhyFilter', optional => true},
|
||||
{name => 'strCipherPass', optional => true, default => $self->cipherPassUser(), redact => true},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
);
|
||||
|
||||
# Open the file
|
||||
my $oFileIo = pgBackRest::LibC::StorageRead->new($self->{oStorageC}, $xFileExp, $bIgnoreMissing);
|
||||
|
||||
# If cipher is set then decryption is the first filter applied to the read
|
||||
if (defined($self->cipherType()))
|
||||
{
|
||||
$oFileIo->filterAdd(STORAGE_FILTER_CIPHER_BLOCK, $self->{oJSON}->encode([false, $self->cipherType(), $strCipherPass]));
|
||||
}
|
||||
|
||||
# Apply any other filters
|
||||
if (defined($rhyFilter))
|
||||
{
|
||||
foreach my $rhFilter (@{$rhyFilter})
|
||||
{
|
||||
$oFileIo->filterAdd(
|
||||
$rhFilter->{strClass}, defined($rhFilter->{rxyParam}) ? $self->{oJSON}->encode($rhFilter->{rxyParam}) : undef);
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oFileIo', value => new pgBackRest::Storage::StorageRead($self, $oFileIo), trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Open file for writing
|
||||
####################################################################################################################################
|
||||
sub openWrite
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFileExp,
|
||||
$strMode,
|
||||
$strUser,
|
||||
$strGroup,
|
||||
$lTimestamp,
|
||||
$bAtomic,
|
||||
$bPathCreate,
|
||||
$rhyFilter,
|
||||
$strCipherPass,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->openWrite', \@_,
|
||||
{name => 'xFileExp'},
|
||||
{name => 'strMode', optional => true, default => $self->{strDefaultFileMode}},
|
||||
{name => 'strUser', optional => true},
|
||||
{name => 'strGroup', optional => true},
|
||||
{name => 'lTimestamp', optional => true, default => '0'},
|
||||
{name => 'bAtomic', optional => true, default => false},
|
||||
{name => 'bPathCreate', optional => true, default => true},
|
||||
{name => 'rhyFilter', optional => true},
|
||||
{name => 'strCipherPass', optional => true, default => $self->cipherPassUser(), redact => true},
|
||||
);
|
||||
|
||||
# Open the file
|
||||
my $oFileIo = pgBackRest::LibC::StorageWrite->new(
|
||||
$self->{oStorageC}, $xFileExp, oct($strMode), $strUser, $strGroup, $lTimestamp, $bAtomic, $bPathCreate);
|
||||
|
||||
# Apply any other filters
|
||||
if (defined($rhyFilter))
|
||||
{
|
||||
foreach my $rhFilter (@{$rhyFilter})
|
||||
{
|
||||
$oFileIo->filterAdd(
|
||||
$rhFilter->{strClass}, defined($rhFilter->{rxyParam}) ? $self->{oJSON}->encode($rhFilter->{rxyParam}) : undef);
|
||||
}
|
||||
}
|
||||
|
||||
# If cipher is set then encryption is the last filter applied to the write
|
||||
if (defined($self->cipherType()))
|
||||
{
|
||||
$oFileIo->filterAdd(STORAGE_FILTER_CIPHER_BLOCK, $self->{oJSON}->encode([true, $self->cipherType(), $strCipherPass]));
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oFileIo', value => new pgBackRest::Storage::StorageWrite($self, $oFileIo), trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Resolve a path expression into an absolute path
|
||||
####################################################################################################################################
|
||||
sub pathGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->pathGet', \@_,
|
||||
{name => 'strPathExp'},
|
||||
);
|
||||
|
||||
# Check exists
|
||||
my $strPath = $self->{oStorageC}->pathGet($strPathExp);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strPath', value => $strPath, trace => true}
|
||||
{name => 'rhFileIo', value => {strFile => $strFile, bIgnoreMissing => $bIgnoreMissing, strCipherPass => $strCipherPass},
|
||||
trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
@ -437,19 +427,17 @@ sub pathRemove
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
$bIgnoreMissing,
|
||||
$strPath,
|
||||
$bRecurse,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->pathRemove', \@_,
|
||||
{name => 'strPathExp'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => true},
|
||||
{name => 'strPath'},
|
||||
{name => 'bRecurse', optional => true, default => false},
|
||||
);
|
||||
|
||||
$self->{oStorageC}->pathRemove($strPathExp, $bIgnoreMissing, $bRecurse);
|
||||
$self->exec("repo-rm " . ($bRecurse ? '--recurse ' : '') . $self->escape($strPath));
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
@ -466,31 +454,54 @@ sub put
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$xContent,
|
||||
$strFile,
|
||||
$tContent,
|
||||
$strCipherPass,
|
||||
$bRaw,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->put', \@_,
|
||||
{name => 'xFile', trace => true},
|
||||
{name => 'xContent', required => false, trace => true},
|
||||
{name => 'strCipherPass', optional => true, default => $self->cipherPassUser(), trace => true, redact => true},
|
||||
{name => 'strFile'},
|
||||
{name => 'tContent', required => false},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
{name => 'bRaw', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or if
|
||||
# the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = ref($xFile) ? $xFile : $self->openWrite($xFile, {strCipherPass => $strCipherPass});
|
||||
# Check invalid params
|
||||
if ($bRaw && defined($strCipherPass))
|
||||
{
|
||||
confess &log(ERROR, 'bRaw and strCipherPass cannot both be set');
|
||||
}
|
||||
|
||||
# Write the content
|
||||
my $lSize = $self->{oStorageC}->put($oFileIo->{oStorageCWrite}, ref($xContent) ? $$xContent : $xContent);
|
||||
# Put file
|
||||
my $strCommand =
|
||||
"$self->{strCommand}" . (defined($strCipherPass) ? ' --cipher-pass=' . $self->escape($strCipherPass) : '') .
|
||||
($bRaw ? ' --raw' : '') . ' repo-put ' . $self->escape($strFile);
|
||||
|
||||
my $oBuffer = new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle($strCommand), $self->{iTimeoutIo}, $self->{lBufferMax});
|
||||
my $oProcess = new pgBackRest::Common::Io::Process($oBuffer, $strCommand);
|
||||
|
||||
if (defined($tContent))
|
||||
{
|
||||
$oBuffer->write(\$tContent);
|
||||
}
|
||||
|
||||
close($oBuffer->handleWrite());
|
||||
|
||||
my $tResult;
|
||||
|
||||
while (!$oBuffer->eof())
|
||||
{
|
||||
$oBuffer->read(\$tResult, $self->{lBufferMax}, false);
|
||||
}
|
||||
|
||||
close($oBuffer->handleRead());
|
||||
$oProcess->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'lSize', value => $lSize, trace => true},
|
||||
);
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -504,20 +515,15 @@ sub remove
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFileExp,
|
||||
$bIgnoreMissing,
|
||||
$strFile,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->remove', \@_,
|
||||
{name => 'xFileExp'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => true},
|
||||
);
|
||||
|
||||
foreach my $strFileExp (ref($xFileExp) ? @{$xFileExp} : ($xFileExp))
|
||||
{
|
||||
$self->{oStorageC}->remove($strFileExp, $bIgnoreMissing);
|
||||
}
|
||||
$self->exec("repo-rm " . $self->escape($strFile));
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
@ -527,8 +533,6 @@ sub remove
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
sub capability {shift->type() eq STORAGE_POSIX}
|
||||
sub type {shift->{oStorageC}->type()}
|
||||
sub cipherType {shift->{strCipherType}}
|
||||
sub cipherPassUser {shift->{strCipherPass}}
|
||||
sub type {shift->{strType}}
|
||||
|
||||
1;
|
||||
|
@ -1,143 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# C Storage Read Interface
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Storage::StorageRead;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Fcntl qw(:mode);
|
||||
use File::stat qw{lstat};
|
||||
use JSON::PP;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oStorage},
|
||||
$self->{oStorageCRead},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'oStorageCRead'},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Open the file
|
||||
####################################################################################################################################
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->open');
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => $self->{oStorageCRead}->open() ? true : false, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Read data
|
||||
####################################################################################################################################
|
||||
sub read
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my (
|
||||
$strOperation,
|
||||
$rtBuffer,
|
||||
$iSize,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->read', \@_,
|
||||
{name => 'rtBuffer'},
|
||||
{name => 'iSize'},
|
||||
);
|
||||
|
||||
# Read if not eof
|
||||
my $iActualSize = 0;
|
||||
|
||||
if (!$self->eof())
|
||||
{
|
||||
my $tBuffer = $self->{oStorageCRead}->read($iSize);
|
||||
$iActualSize = length($tBuffer);
|
||||
$$rtBuffer .= $tBuffer;
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iActualSize', value => $iActualSize}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Is the file at eof?
|
||||
####################################################################################################################################
|
||||
sub eof
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->eof');
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => $self->{oStorageCRead}->eof() ? true : false, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Close the file
|
||||
####################################################################################################################################
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->close');
|
||||
|
||||
$self->{oStorageCRead}->close();
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => true, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
@ -1,116 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# C Storage Write Interface
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Storage::StorageWrite;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Fcntl qw(:mode);
|
||||
use File::stat qw{lstat};
|
||||
use JSON::PP;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oStorage},
|
||||
$self->{oStorageCWrite},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'oStorageCWrite'},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Open the file
|
||||
####################################################################################################################################
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->open');
|
||||
|
||||
$self->{oStorageCWrite}->open();
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => true, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Write data
|
||||
####################################################################################################################################
|
||||
sub write
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my (
|
||||
$strOperation,
|
||||
$rtBuffer,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->write', \@_,
|
||||
{name => 'rtBuffer'},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iActualSize', value => $self->{oStorageCWrite}->write($$rtBuffer)}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Close the file
|
||||
####################################################################################################################################
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->close');
|
||||
|
||||
$self->{oStorageCWrite}->close();
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => true, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
78
libc/LibC.h
78
libc/LibC.h
@ -1,78 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Helper macros for LibC.xs
|
||||
***********************************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Package Names
|
||||
***********************************************************************************************************************************/
|
||||
#define PACKAGE_NAME "pgBackRest"
|
||||
#define PACKAGE_NAME_LIBC PACKAGE_NAME "::LibC"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Error handling macros that throw a Perl error when a C error is caught
|
||||
***********************************************************************************************************************************/
|
||||
#define ERROR_XS_BEGIN() \
|
||||
TRY_BEGIN()
|
||||
|
||||
#define ERROR_XS() \
|
||||
croak("PGBRCLIB:%d:%s:%d:%s", errorCode(), errorFileName(), errorFileLine(), errorMessage());
|
||||
|
||||
#define ERROR_XS_END() \
|
||||
CATCH_ANY() \
|
||||
{ \
|
||||
ERROR_XS(); \
|
||||
} \
|
||||
TRY_END();
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Simplifies switching to a temp memory context in functions and includes error handling
|
||||
***********************************************************************************************************************************/
|
||||
#define MEM_CONTEXT_XS_TEMP() \
|
||||
MEM_CONTEXT_XS_TEMP_memContext
|
||||
|
||||
#define MEM_CONTEXT_XS_TEMP_BEGIN() \
|
||||
{ \
|
||||
/* Create temp memory context */ \
|
||||
MemContext *MEM_CONTEXT_XS_TEMP() = memContextNew("temporary"); \
|
||||
\
|
||||
/* Switch to temp memory context */ \
|
||||
memContextSwitch(MEM_CONTEXT_XS_TEMP()); \
|
||||
\
|
||||
/* Store any errors to be croaked to Perl at the end */ \
|
||||
bool MEM_CONTEXT_XS_croak = false; \
|
||||
\
|
||||
/* Try the statement block */ \
|
||||
TRY_BEGIN()
|
||||
|
||||
#define MEM_CONTEXT_XS_TEMP_END() \
|
||||
/* Set error to be croak to Perl later */ \
|
||||
CATCH_ANY() \
|
||||
{ \
|
||||
MEM_CONTEXT_XS_croak = true; \
|
||||
} \
|
||||
/* Free the context on error */ \
|
||||
FINALLY() \
|
||||
{ \
|
||||
memContextSwitchBack(); \
|
||||
memContextDiscard(); \
|
||||
} \
|
||||
TRY_END(); \
|
||||
\
|
||||
/* Croak on error */ \
|
||||
if (MEM_CONTEXT_XS_croak) \
|
||||
{ \
|
||||
ERROR_XS() \
|
||||
} \
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Create new string from an SV
|
||||
***********************************************************************************************************************************/
|
||||
#define STR_NEW_SV(param) \
|
||||
(SvOK(param) ? strNewN(SvPV_nolen(param), SvCUR(param)) : NULL)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Create const buffer from an SV
|
||||
***********************************************************************************************************************************/
|
||||
#define BUF_CONST_SV(param) \
|
||||
(SvOK(param) ? BUF(SvPV_nolen(param), SvCUR(param)) : NULL)
|
98
libc/LibC.xs
98
libc/LibC.xs
@ -1,98 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
C to Perl Interface
|
||||
|
||||
The following C types are mapped by the current typemap:
|
||||
|
||||
'AV *', 'Boolean', 'CV *', 'FILE *', 'FileHandle', 'HV *', 'I16', 'I32', 'I8', 'IV', 'InOutStream', 'InputStream', 'NV',
|
||||
'OutputStream', 'PerlIO *', 'Result', 'STRLEN', 'SV *', 'SVREF', 'SysRet', 'SysRetLong', 'Time_t *', 'U16', 'U32', 'U8', 'UV',
|
||||
'bool', 'bool_t', 'caddr_t', 'char', 'char *', 'char **', 'const char *', 'double', 'float', 'int', 'long', 'short', 'size_t',
|
||||
'ssize_t', 'time_t', 'unsigned', 'unsigned char', 'unsigned char *', 'unsigned int', 'unsigned long', 'unsigned long *',
|
||||
'unsigned short', 'void *', 'wchar_t', 'wchar_t *'
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#define PERL_NO_GET_CONTEXT
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Perl includes
|
||||
|
||||
Order is critical here so don't change it.
|
||||
***********************************************************************************************************************************/
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 8 || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ >= 0)))
|
||||
#define WARNING_MAYBE_INITIALIZED 1
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ >= 0)))
|
||||
#define WARNING_INITIALIZED 1
|
||||
#endif
|
||||
|
||||
#if WARNING_MAYBE_INITIALIZED
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#elif WARNING_INITIALIZED
|
||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
|
||||
#include <XSUB.h>
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
|
||||
#if WARNING_MAYBE_INITIALIZED
|
||||
#pragma GCC diagnostic warning "-Wmaybe-uninitialized"
|
||||
#elif WARNING_INITIALIZED
|
||||
#pragma GCC diagnostic warning "-Wuninitialized"
|
||||
#endif
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
C includes
|
||||
|
||||
These includes are from the src directory. There is no Perl-specific code in them.
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/error.h"
|
||||
#include "common/io/io.h"
|
||||
#include "config/config.h"
|
||||
#include "config/define.h"
|
||||
#include "config/load.h"
|
||||
#include "config/parse.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Helper macros
|
||||
***********************************************************************************************************************************/
|
||||
#include "LibC.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
XSH includes
|
||||
|
||||
These includes define data structures that are required for the C to Perl interface but are not part of the regular C source.
|
||||
***********************************************************************************************************************************/
|
||||
#include "xs/config/configTest.xsh"
|
||||
#include "xs/storage/storage.xsh"
|
||||
#include "xs/storage/storageRead.xsh"
|
||||
#include "xs/storage/storageWrite.xsh"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Module definition
|
||||
***********************************************************************************************************************************/
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
PROTOTYPES: DISABLE
|
||||
|
||||
# Return UVSIZE to ensure that this Perl supports 64-bit integers
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
I32
|
||||
libcUvSize()
|
||||
CODE:
|
||||
RETVAL = UVSIZE;
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
# Exported functions and modules
|
||||
#
|
||||
# These modules should map 1-1 with C modules in src directory.
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
INCLUDE: xs/config/config.xs
|
||||
INCLUDE: xs/config/configTest.xs
|
||||
INCLUDE: xs/config/define.xs
|
||||
INCLUDE: xs/storage/storage.xs
|
||||
INCLUDE: xs/storage/storageRead.xs
|
||||
INCLUDE: xs/storage/storageWrite.xs
|
147
libc/Makefile.PL
147
libc/Makefile.PL
@ -1,147 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Build Makefile and Auto-Generate Files Required for Build
|
||||
#
|
||||
# The C library is only used for Perl unit tests. For a production build all C library exports are built directly into the
|
||||
# pgbackrest executable. See src/perl/libc.auto.c.
|
||||
####################################################################################################################################
|
||||
use 5.010001;
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
# Convert die to confess to capture the stack trace
|
||||
$SIG{__DIE__} = sub { Carp::confess @_ };
|
||||
|
||||
use Cwd qw(abs_path);
|
||||
use ExtUtils::MakeMaker;
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
####################################################################################################################################
|
||||
# Storage object to use for all file operations
|
||||
####################################################################################################################################
|
||||
use constant PROJECT_NAME => 'pgBackRest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Make sure the makefile is being created in an expected test directory. This should prevent users from building it in production.
|
||||
####################################################################################################################################
|
||||
if (dirname($0) !~ /\.vagrant\/bin\/[^\/]+\/libc$/)
|
||||
{
|
||||
confess
|
||||
"LibC is not being built in a test directory (" . dirname($0) .
|
||||
"). LibC should not be distributed for production builds. See build documentation for details.";
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Create C Makefile
|
||||
####################################################################################################################################
|
||||
my $strBuildPath = dirname(dirname(abs_path($0)));
|
||||
|
||||
# Create C files array
|
||||
my @stryCFile =
|
||||
(
|
||||
'LibC.c',
|
||||
|
||||
'command/command.c',
|
||||
'common/compress/gz/common.c',
|
||||
'common/compress/gz/compress.c',
|
||||
'common/compress/gz/decompress.c',
|
||||
'common/compress/helper.c',
|
||||
'common/crypto/cipherBlock.c',
|
||||
'common/crypto/common.c',
|
||||
'common/crypto/hash.c',
|
||||
'common/debug.c',
|
||||
'common/encode.c',
|
||||
'common/encode/base64.c',
|
||||
'common/error.c',
|
||||
'common/ini.c',
|
||||
'common/io/bufferRead.c',
|
||||
'common/io/bufferWrite.c',
|
||||
'common/io/filter/buffer.c',
|
||||
'common/io/filter/filter.c',
|
||||
'common/io/filter/group.c',
|
||||
'common/io/filter/sink.c',
|
||||
'common/io/filter/size.c',
|
||||
'common/io/handleWrite.c',
|
||||
'common/io/http/cache.c',
|
||||
'common/io/http/client.c',
|
||||
'common/io/http/common.c',
|
||||
'common/io/http/header.c',
|
||||
'common/io/http/query.c',
|
||||
'common/io/io.c',
|
||||
'common/io/read.c',
|
||||
'common/io/tls/client.c',
|
||||
'common/io/write.c',
|
||||
'common/log.c',
|
||||
'common/memContext.c',
|
||||
'common/regExp.c',
|
||||
'common/stackTrace.c',
|
||||
'common/time.c',
|
||||
'common/type/convert.c',
|
||||
'common/type/buffer.c',
|
||||
'common/type/json.c',
|
||||
'common/type/keyValue.c',
|
||||
'common/type/list.c',
|
||||
'common/type/string.c',
|
||||
'common/type/stringList.c',
|
||||
'common/type/variant.c',
|
||||
'common/type/variantList.c',
|
||||
'common/type/xml.c',
|
||||
'common/user.c',
|
||||
'common/wait.c',
|
||||
'config/config.c',
|
||||
'config/define.c',
|
||||
'config/load.c',
|
||||
'config/parse.c',
|
||||
'protocol/client.c',
|
||||
'protocol/command.c',
|
||||
'protocol/helper.c',
|
||||
'protocol/parallel.c',
|
||||
'protocol/parallelJob.c',
|
||||
'protocol/server.c',
|
||||
'storage/posix/read.c',
|
||||
'storage/posix/storage.c',
|
||||
'storage/posix/write.c',
|
||||
'storage/s3/read.c',
|
||||
'storage/s3/storage.c',
|
||||
'storage/s3/write.c',
|
||||
'storage/helper.c',
|
||||
'storage/read.c',
|
||||
'storage/storage.c',
|
||||
'storage/write.c',
|
||||
);
|
||||
|
||||
# Add ../src for files that are outside libc
|
||||
for (my $iFileIdx = 1; $iFileIdx < @stryCFile; $iFileIdx++)
|
||||
{
|
||||
$stryCFile[$iFileIdx] = '../src/' . $stryCFile[$iFileIdx];
|
||||
}
|
||||
|
||||
# Write the makefile
|
||||
WriteMakefile
|
||||
(
|
||||
NAME => PROJECT_NAME . '::LibC',
|
||||
VERSION => '999',
|
||||
AUTHOR => 'David Steele <david@pgbackrest.org>',
|
||||
|
||||
CCFLAGS => join(' ', qw)
|
||||
-Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -Wno-missing-field-initializers
|
||||
-o $@
|
||||
-std=c99
|
||||
-D_POSIX_C_SOURCE=200112L
|
||||
-D_FILE_OFFSET_BITS=64
|
||||
`pkg-config libxml-2.0 --cflags`
|
||||
-I`pg_config --includedir`
|
||||
)),
|
||||
|
||||
INC => join(' ', qw(
|
||||
-I.
|
||||
-I../src
|
||||
)),
|
||||
|
||||
C => \@stryCFile,
|
||||
|
||||
LIBS => '-lcrypto -lpq -lssl -lxml2',
|
||||
|
||||
OBJECT => '$(O_FILES)',
|
||||
);
|
@ -1,372 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Auto-Generate XS and PM Files Required for Perl
|
||||
####################################################################################################################################
|
||||
package pgBackRestLibC::Build;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Cwd qw(abs_path);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use lib dirname($0) . '/../build/lib';
|
||||
use lib dirname($0) . '/../lib';
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestBuild::Build;
|
||||
use pgBackRestBuild::Build::Common;
|
||||
use pgBackRestBuild::Config::Data;
|
||||
use pgBackRestBuild::Error::Data;
|
||||
|
||||
use pgBackRestTest::Common::Storage;
|
||||
use pgBackRestTest::Common::StoragePosix;
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl function and constant exports
|
||||
####################################################################################################################################
|
||||
use constant BLD_EXPORTTYPE_SUB => 'sub';
|
||||
use constant BLD_EXPORTTYPE_CONSTANT => 'constant';
|
||||
|
||||
use constant LIB_AUTO_NAME => 'LibCAuto';
|
||||
|
||||
####################################################################################################################################
|
||||
# Save contents to a file if the file is missing or the contents are different. This saves write IO and prevents the timestamp from
|
||||
# changing.
|
||||
####################################################################################################################################
|
||||
sub buildPutDiffers
|
||||
{
|
||||
my $oStorage = shift;
|
||||
my $strFile = shift;
|
||||
my $strContents = shift;
|
||||
|
||||
# Attempt to load the file
|
||||
my $bSave = true;
|
||||
my $oFile = $oStorage->openRead($strFile, {bIgnoreMissing => true});
|
||||
|
||||
# If file was found see if the content is the same
|
||||
if (defined($oFile) && ${$oStorage->get($oFile)} eq $strContents)
|
||||
{
|
||||
$bSave = false;
|
||||
}
|
||||
|
||||
# Save if the contents are different or missing
|
||||
if ($bSave)
|
||||
{
|
||||
$oStorage->put($strFile, $strContents);
|
||||
}
|
||||
|
||||
return $bSave;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Static exports
|
||||
####################################################################################################################################
|
||||
my $rhExport =
|
||||
{
|
||||
'config' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
cfgCommandName
|
||||
cfgOptionIndexTotal
|
||||
cfgOptionName
|
||||
)],
|
||||
},
|
||||
|
||||
'configDefine' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
cfgCommandId
|
||||
cfgDefOptionDefault
|
||||
cfgDefOptionPrefix
|
||||
cfgDefOptionSecure
|
||||
cfgDefOptionType
|
||||
cfgDefOptionValid
|
||||
cfgOptionId
|
||||
cfgOptionTotal
|
||||
)],
|
||||
},
|
||||
|
||||
'debug' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
libcUvSize
|
||||
)],
|
||||
},
|
||||
|
||||
'storage' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
storageRepoFree
|
||||
)],
|
||||
},
|
||||
|
||||
'test' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
cfgParseTest
|
||||
)],
|
||||
},
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# Execute all build functions
|
||||
####################################################################################################################################
|
||||
sub buildXsAll
|
||||
{
|
||||
my $strBuildPath = shift;
|
||||
|
||||
# List of files built
|
||||
my @stryBuilt;
|
||||
|
||||
# Storage
|
||||
my $oStorage = new pgBackRestTest::Common::Storage(
|
||||
$strBuildPath, new pgBackRestTest::Common::StoragePosix({bFileSync => false, bPathSync => false}));
|
||||
|
||||
# Build interface file
|
||||
my $strContent =
|
||||
('#' x 132) . "\n" .
|
||||
'# ' . bldAutoWarning('Build.pm') . "\n" .
|
||||
('#' x 132) . "\n" .
|
||||
"package pgBackRest::LibCAuto;\n" .
|
||||
"\n" .
|
||||
"use strict;\n" .
|
||||
"use warnings;\n";
|
||||
|
||||
# Generate constants for options that have a list of strings as allowed values
|
||||
my $rhConfigDefine = cfgDefine();
|
||||
my $strConstantBlock;
|
||||
|
||||
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
||||
{
|
||||
my $rhOption = $rhConfigDefine->{$strOption};
|
||||
|
||||
next if $rhOption->{&CFGDEF_TYPE} ne CFGDEF_TYPE_STRING;
|
||||
next if $strOption =~ /^log-level-/;
|
||||
|
||||
if (defined($rhOption->{&CFGDEF_ALLOW_LIST}))
|
||||
{
|
||||
$strConstantBlock .= defined($strConstantBlock) ? "\n" : '';
|
||||
|
||||
foreach my $strValue (@{$rhOption->{&CFGDEF_ALLOW_LIST}})
|
||||
{
|
||||
my $strConstant = 'CFGOPTVAL_' . uc("${strOption}_${strValue}");
|
||||
$strConstant =~ s/\-/\_/g;
|
||||
|
||||
$strConstantBlock .= " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> '${strValue}',\n";
|
||||
push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant);
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $strCommand (sort(keys(%{$rhOption->{&CFGDEF_COMMAND}})))
|
||||
{
|
||||
my $rhCommand = $rhOption->{&CFGDEF_COMMAND}{$strCommand};
|
||||
|
||||
if (defined($rhCommand->{&CFGDEF_ALLOW_LIST}))
|
||||
{
|
||||
$strConstantBlock .= defined($strConstantBlock) ? "\n" : '';
|
||||
|
||||
foreach my $strValue (@{$rhCommand->{&CFGDEF_ALLOW_LIST}})
|
||||
{
|
||||
my $strConstant = 'CFGOPTVAL_' . uc("${strCommand}_${strOption}_${strValue}");
|
||||
$strConstant =~ s/\-/\_/g;
|
||||
|
||||
$strConstantBlock .= " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> '${strValue}',\n";
|
||||
push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Generate command constants
|
||||
foreach my $strCommand (cfgDefineCommandList())
|
||||
{
|
||||
my $strConstant = "CFGCMD_" . uc($strCommand);
|
||||
$strConstant =~ s/\-/\_/g;
|
||||
|
||||
push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant);
|
||||
}
|
||||
|
||||
# Generate option constants
|
||||
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
||||
{
|
||||
# Build Perl constant
|
||||
my $strConstant = "CFGOPT_" . uc($strOption);
|
||||
$strConstant =~ s/\-/\_/g;
|
||||
|
||||
# Builds option data
|
||||
for (my $iOptionIndex = 1; $iOptionIndex <= $rhConfigDefine->{$strOption}{&CFGDEF_INDEX_TOTAL}; $iOptionIndex++)
|
||||
{
|
||||
push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant . ($iOptionIndex == 1 ? '' : $iOptionIndex));
|
||||
}
|
||||
}
|
||||
|
||||
# Generate option type constants
|
||||
$strConstantBlock .= defined($strConstantBlock) ? "\n" : '';
|
||||
my $iIndex = 0;
|
||||
|
||||
foreach my $strOptionType (cfgDefineOptionTypeList())
|
||||
{
|
||||
# Build Perl constant
|
||||
my $strConstant = "CFGDEF_TYPE_" . uc($strOptionType);
|
||||
$strConstant =~ s/\-/\_/g;
|
||||
|
||||
$strConstantBlock .=
|
||||
" ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> $iIndex,\n";
|
||||
push(@{$rhExport->{'configDefine'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant);
|
||||
|
||||
$iIndex++;
|
||||
};
|
||||
|
||||
# Generate encode type constants
|
||||
$strConstantBlock .= defined($strConstantBlock) ? "\n" : '';
|
||||
|
||||
my $strConstant = "ENCODE_TYPE_BASE64";
|
||||
$strConstantBlock .=
|
||||
" ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 0,\n";
|
||||
|
||||
# Generate cipher type constants
|
||||
$strConstantBlock .= defined($strConstantBlock) ? "\n" : '';
|
||||
|
||||
$strConstant = "CIPHER_MODE_ENCRYPT";
|
||||
$strConstantBlock .=
|
||||
" ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 0,\n";
|
||||
$strConstant = "CIPHER_MODE_DECRYPT";
|
||||
$strConstantBlock .=
|
||||
" ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 1,\n";
|
||||
|
||||
$strContent .=
|
||||
"\n" .
|
||||
"# Configuration option value constants\n" .
|
||||
"sub libcAutoConstant\n" .
|
||||
"{\n" .
|
||||
" return\n" .
|
||||
" {\n" .
|
||||
" " . trim($strConstantBlock) . "\n" .
|
||||
" }\n" .
|
||||
"}\n";
|
||||
|
||||
# Generate export tags
|
||||
my $strExportTags;
|
||||
|
||||
foreach my $strSection (sort(keys(%{$rhExport})))
|
||||
{
|
||||
my $rhExportSection = $rhExport->{$strSection};
|
||||
|
||||
$strExportTags .= (defined($strExportTags) ? "\n" : '') . " ${strSection} =>\n [\n";
|
||||
|
||||
if (defined($rhExportSection->{&BLD_EXPORTTYPE_CONSTANT}) && @{$rhExportSection->{&BLD_EXPORTTYPE_CONSTANT}} > 0)
|
||||
{
|
||||
foreach my $strConstant (@{$rhExportSection->{&BLD_EXPORTTYPE_CONSTANT}})
|
||||
{
|
||||
$strExportTags .= " '${strConstant}',\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($rhExportSection->{&BLD_EXPORTTYPE_SUB}) && @{$rhExportSection->{&BLD_EXPORTTYPE_SUB}} > 0)
|
||||
{
|
||||
foreach my $strSub (@{$rhExportSection->{&BLD_EXPORTTYPE_SUB}})
|
||||
{
|
||||
$strExportTags .= " '${strSub}',\n";
|
||||
}
|
||||
}
|
||||
|
||||
$strExportTags .= " ],\n";
|
||||
}
|
||||
|
||||
$strContent .=
|
||||
"\n" .
|
||||
"# Export function and constants\n" .
|
||||
"sub libcAutoExportTag\n" .
|
||||
"{\n" .
|
||||
" return\n" .
|
||||
" {\n" .
|
||||
$strExportTags .
|
||||
" }\n" .
|
||||
"}\n";
|
||||
|
||||
# Add module end marker
|
||||
$strContent .=
|
||||
"\n" .
|
||||
"1;\n";
|
||||
|
||||
# Save the file
|
||||
my $strFile = 'lib/' . PROJECT_NAME . '/' . LIB_AUTO_NAME . '.pm';
|
||||
|
||||
if (buildPutDiffers($oStorage, "../${strFile}", $strContent))
|
||||
{
|
||||
push(@stryBuilt, $strFile);
|
||||
}
|
||||
|
||||
# Build error file
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
my $rhErrorDefine = errorDefine();
|
||||
|
||||
# Order by id for the list that is id ordered
|
||||
my $rhErrorId = {};
|
||||
|
||||
foreach my $strType (sort(keys(%{$rhErrorDefine})))
|
||||
{
|
||||
my $iCode = $rhErrorDefine->{$strType};
|
||||
$rhErrorId->{$iCode} = $strType;
|
||||
}
|
||||
|
||||
# Output errors
|
||||
$strContent =
|
||||
('#' x 132) . "\n" .
|
||||
"# COMMON EXCEPTION AUTO MODULE\n" .
|
||||
"# \n" .
|
||||
'# ' . bldAutoWarning('Build.pm') . "\n" .
|
||||
('#' x 132) . "\n" .
|
||||
"package pgBackRest::Common::ExceptionAuto;\n" .
|
||||
"\n" .
|
||||
"use strict;\n" .
|
||||
"use warnings FATAL => qw(all);\n" .
|
||||
"\n" .
|
||||
"use Exporter qw(import);\n" .
|
||||
" our \@EXPORT = qw();\n" .
|
||||
"\n" .
|
||||
('#' x 132) . "\n" .
|
||||
"# Error Definitions\n" .
|
||||
('#' x 132) . "\n" .
|
||||
"use constant ERROR_MINIMUM => " . ERRDEF_MIN . ";\n" .
|
||||
"push \@EXPORT, qw(ERROR_MINIMUM);\n" .
|
||||
"use constant ERROR_MAXIMUM => " . ERRDEF_MAX . ";\n" .
|
||||
"push \@EXPORT, qw(ERROR_MAXIMUM);\n" .
|
||||
"\n";
|
||||
|
||||
foreach my $iCode (sort({sprintf("%03d", $a) cmp sprintf("%03d", $b)} keys(%{$rhErrorId})))
|
||||
{
|
||||
my $strType = "ERROR_" . uc($rhErrorId->{$iCode});
|
||||
$strType =~ s/\-/\_/g;
|
||||
|
||||
$strContent .=
|
||||
"use constant ${strType}" . (' ' x (54 - length($strType))) . " => $iCode;\n" .
|
||||
"push \@EXPORT, qw(${strType});\n"
|
||||
}
|
||||
|
||||
$strContent .=
|
||||
"\n" .
|
||||
"1;\n";
|
||||
|
||||
$strFile = 'lib/' . PROJECT_NAME . '/Common/ExceptionAuto.pm';
|
||||
|
||||
if (buildPutDiffers($oStorage, "../${strFile}", $strContent))
|
||||
{
|
||||
push(@stryBuilt, $strFile);
|
||||
}
|
||||
|
||||
# Return list of files built
|
||||
return @stryBuilt;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(buildXsAll);
|
||||
|
||||
1;
|
@ -1,3 +0,0 @@
|
||||
pgBackRest::LibC::Storage T_PTROBJ
|
||||
pgBackRest::LibC::StorageRead T_PTROBJ
|
||||
pgBackRest::LibC::StorageWrite T_PTROBJ
|
@ -1,17 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Config Perl Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
|
||||
const char *
|
||||
cfgCommandName(commandId)
|
||||
U32 commandId
|
||||
|
||||
I32
|
||||
cfgOptionIndexTotal(optionId)
|
||||
U32 optionId
|
||||
|
||||
const char *
|
||||
cfgOptionName(optionId)
|
||||
U32 optionId
|
@ -1,38 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Config Test Perl Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
|
||||
####################################################################################################################################
|
||||
# Parse command line and return a JSON object with results
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
cfgParseTest(backrestBin, parseParam)
|
||||
const char *backrestBin
|
||||
const char *parseParam
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
// This should run in a temp context but for some reason getopt_long gets upset when if gets called again after the previous
|
||||
// arg list being freed. So, this is a memory leak but it is only used for testing, not production.
|
||||
StringList *paramList = strLstNewSplitZ(strCat(strNew("pgbackrest|"), parseParam), "|");
|
||||
|
||||
// Don't use cfgLoad() because it has a lot of side effects that we don't want
|
||||
configParse(strLstSize(paramList), strLstPtr(paramList), false);
|
||||
cfgExeSet(strNew(backrestBin));
|
||||
cfgLoadUpdateOption();
|
||||
|
||||
String *result = perlOptionJson();
|
||||
|
||||
RETVAL = newSV(strSize(result));
|
||||
SvPOK_only(RETVAL);
|
||||
|
||||
strcpy(SvPV_nolen(RETVAL), strPtr(result));
|
||||
SvCUR_set(RETVAL, strSize(result));
|
||||
}
|
||||
ERROR_XS_END()
|
||||
OUTPUT:
|
||||
RETVAL
|
@ -1,122 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Config XS Header
|
||||
***********************************************************************************************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/json.h"
|
||||
#include "config/config.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Build JSON output from options
|
||||
***********************************************************************************************************************************/
|
||||
String *
|
||||
perlOptionJson(void)
|
||||
{
|
||||
String *result = NULL;
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
KeyValue *configKv = kvNew();
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
// Skip if not valid
|
||||
if (!cfgOptionValid(optionId))
|
||||
continue;
|
||||
|
||||
Variant *optionVar = varNewKv(kvNew());
|
||||
|
||||
// Add valid
|
||||
kvPut(varKv(optionVar), VARSTRDEF("valid"), BOOL_TRUE_VAR);
|
||||
|
||||
// Add source
|
||||
const Variant *source = NULL;
|
||||
|
||||
switch (cfgOptionSource(optionId))
|
||||
{
|
||||
case cfgSourceParam:
|
||||
{
|
||||
source = varNewStrZ("param");
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgSourceConfig:
|
||||
{
|
||||
source = varNewStrZ("config");
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgSourceDefault:
|
||||
{
|
||||
source = varNewStrZ("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kvPut(varKv(optionVar), VARSTRDEF("source"), source);
|
||||
|
||||
// Add negate and reset
|
||||
kvPut(varKv(optionVar), VARSTRDEF("negate"), VARBOOL(cfgOptionNegate(optionId)));
|
||||
kvPut(varKv(optionVar), VARSTRDEF("reset"), VARBOOL(cfgOptionReset(optionId)));
|
||||
|
||||
// Add value if it is set
|
||||
if (cfgOptionTest(optionId))
|
||||
{
|
||||
const Variant *valueVar = NULL;
|
||||
|
||||
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||
{
|
||||
case cfgDefOptTypeBoolean:
|
||||
case cfgDefOptTypeFloat:
|
||||
case cfgDefOptTypeInteger:
|
||||
case cfgDefOptTypePath:
|
||||
case cfgDefOptTypeSize:
|
||||
case cfgDefOptTypeString:
|
||||
{
|
||||
valueVar = cfgOption(optionId);
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeHash:
|
||||
{
|
||||
valueVar = varNewKv(kvNew());
|
||||
|
||||
const KeyValue *valueKv = cfgOptionKv(optionId);
|
||||
const VariantList *keyList = kvKeyList(valueKv);
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
|
||||
kvPut(varKv(valueVar), varLstGet(keyList, listIdx), kvGet(valueKv, varLstGet(keyList, listIdx)));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeList:
|
||||
{
|
||||
valueVar = varNewKv(kvNew());
|
||||
|
||||
const VariantList *valueList = cfgOptionLst(optionId);
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(valueList); listIdx++)
|
||||
kvPut(varKv(valueVar), varLstGet(valueList, listIdx), BOOL_TRUE_VAR);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kvPut(varKv(optionVar), VARSTRDEF("value"), valueVar);
|
||||
}
|
||||
|
||||
kvPut(configKv, VARSTRZ(cfgOptionName(optionId)), optionVar);
|
||||
}
|
||||
|
||||
MEM_CONTEXT_PRIOR_BEGIN()
|
||||
{
|
||||
result = jsonFromKv(configKv);
|
||||
}
|
||||
MEM_CONTEXT_PRIOR_END();
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
return result;
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Config Definition Perl Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
|
||||
I32
|
||||
cfgCommandId(commandName)
|
||||
const char *commandName
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgCommandId(commandName, true);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
I32
|
||||
cfgOptionId(optionName)
|
||||
const char *optionName
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgOptionId(optionName);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionDefault(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionDefault(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionPrefix(optionId)
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionPrefix(cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionSecure(optionId)
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionSecure(cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
I32
|
||||
cfgDefOptionType(optionId);
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionType(cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionValid(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionValid(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
U32
|
||||
cfgOptionTotal()
|
||||
CODE:
|
||||
RETVAL = CFG_OPTION_TOTAL;
|
||||
OUTPUT:
|
||||
RETVAL
|
@ -1,356 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Storage Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC::Storage
|
||||
|
||||
####################################################################################################################################
|
||||
pgBackRest::LibC::Storage
|
||||
new(class, type, path)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
const String *class = STR_NEW_SV($arg);
|
||||
const String *type = STR_NEW_SV($arg);
|
||||
const String *path = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
CHECK(strEqZ(class, PACKAGE_NAME_LIBC "::Storage"));
|
||||
|
||||
if (strEqZ(type, "<LOCAL>"))
|
||||
{
|
||||
MEM_CONTEXT_PRIOR_BEGIN()
|
||||
{
|
||||
RETVAL = storagePosixNew(
|
||||
path == NULL ? STRDEF("/") : path, STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, true, NULL);
|
||||
}
|
||||
MEM_CONTEXT_PRIOR_END();
|
||||
}
|
||||
else if (strEqZ(type, "<REPO>"))
|
||||
{
|
||||
CHECK(path == NULL);
|
||||
RETVAL = (Storage *)storageRepoWrite();
|
||||
}
|
||||
else if (strEqZ(type, "<DB>"))
|
||||
{
|
||||
CHECK(path == NULL);
|
||||
|
||||
MEM_CONTEXT_PRIOR_BEGIN()
|
||||
{
|
||||
RETVAL = storagePosixNew(cfgOptionStr(cfgOptPgPath), STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, true, NULL);
|
||||
}
|
||||
MEM_CONTEXT_PRIOR_END();
|
||||
}
|
||||
else
|
||||
THROW_FMT(AssertError, "unexpected storage type '%s'", strPtr(type));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
bucketCreate(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
CODE:
|
||||
if (strEq(storageType(self), STORAGE_S3_TYPE_STR))
|
||||
storageS3Request((StorageS3 *)storageDriver(self), HTTP_VERB_PUT_STR, FSLASH_STR, NULL, NULL, true, false);
|
||||
else
|
||||
THROW_FMT(AssertError, "unable to create bucket on '%s' storage", strPtr(storageType(self)));
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
bool
|
||||
copy(self, source, destination)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead source
|
||||
pgBackRest::LibC::StorageWrite destination
|
||||
CODE:
|
||||
RETVAL = storageCopyP(source, destination);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
get(self, read)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead read
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
Buffer *buffer = storageGetP(read);
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
if (bufUsed(buffer) == 0)
|
||||
RETVAL = newSVpv("", 0);
|
||||
else
|
||||
RETVAL = newSVpv((char *)bufPtr(buffer), bufUsed(buffer));
|
||||
}
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
info(self, pathExp, ignoreMissing)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *pathExp = STR_NEW_SV($arg);
|
||||
bool ignoreMissing
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
StorageInfo info = storageInfoP(self, pathExp, .ignoreMissing = ignoreMissing);
|
||||
|
||||
if (info.exists)
|
||||
{
|
||||
String *json = storageManifestXsInfo(NULL, &info);
|
||||
RETVAL = newSVpv((char *)strPtr(json), strSize(json));
|
||||
}
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
list(self, pathExp, ignoreMissing, sortAsc, expression)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *pathExp = STR_NEW_SV($arg);
|
||||
bool ignoreMissing
|
||||
bool sortAsc
|
||||
const String *expression = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
StringList *fileList = strLstSort(
|
||||
storageListP(self, pathExp, .errorOnMissing = storageFeature(self, storageFeaturePath) ? !ignoreMissing : false,
|
||||
.expression = expression), sortAsc ? sortOrderAsc : sortOrderDesc);
|
||||
|
||||
const String *fileListJson = jsonFromVar(varNewVarLst(varLstNewStrLst(fileList)));
|
||||
|
||||
RETVAL = newSVpv(strPtr(fileListJson), strSize(fileListJson));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
manifest(self, pathExp, filter=NULL)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *pathExp = STR_NEW_SV($arg);
|
||||
const String *filter = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
StorageManifestXsCallbackData data = {.storage = self, .json = strNew("{"), .pathRoot = pathExp, .filter = filter};
|
||||
|
||||
// If a path is specified
|
||||
StorageInfo info = storageInfoP(self, pathExp, .ignoreMissing = true);
|
||||
|
||||
if (!info.exists || info.type == storageTypePath)
|
||||
{
|
||||
storageInfoListP(
|
||||
self, data.pathRoot, storageManifestXsCallback, &data,
|
||||
.errorOnMissing = storageFeature(self, storageFeaturePath) ? true : false);
|
||||
}
|
||||
// Else a file is specified
|
||||
else
|
||||
{
|
||||
info.name = strBase(storagePathP(self, pathExp));
|
||||
strCat(data.json, strPtr(storageManifestXsInfo(NULL, &info)));
|
||||
}
|
||||
|
||||
strCat(data.json, "}");
|
||||
|
||||
RETVAL = newSVpv((char *)strPtr(data.json), strSize(data.json));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
pathGet(self, pathExp)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *pathExp = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
String *path = storagePathP(self, pathExp);
|
||||
RETVAL = newSVpv((char *)strPtr(path), strSize(path));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
pathRemove(self, pathExp, ignoreMissing, recurse)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *pathExp = STR_NEW_SV($arg);
|
||||
bool ignoreMissing
|
||||
bool recurse
|
||||
CODE:
|
||||
storagePathRemoveP(
|
||||
self, pathExp, .errorOnMissing = storageFeature(self, storageFeaturePath) ? !ignoreMissing : false, .recurse = recurse);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
UV
|
||||
put(self, write, buffer)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite write
|
||||
const Buffer *buffer = BUF_CONST_SV($arg);
|
||||
CODE:
|
||||
storagePutP(write, buffer);
|
||||
RETVAL = buffer ? bufUsed(buffer) : 0;
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
bool
|
||||
readDrain(self, read)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead read
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
// Read and discard all IO (this is useful for processing filters)
|
||||
if (ioReadOpen(storageReadIo(read)))
|
||||
{
|
||||
Buffer *buffer = bufNew(ioBufferSize());
|
||||
|
||||
do
|
||||
{
|
||||
ioRead(storageReadIo(read), buffer);
|
||||
bufUsedZero(buffer);
|
||||
}
|
||||
while (!ioReadEof(storageReadIo(read)));
|
||||
|
||||
ioReadClose(storageReadIo(read));
|
||||
RETVAL = true;
|
||||
}
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
remove(self, fileExp, ignoreMissing)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
const String *fileExp = STR_NEW_SV($arg);
|
||||
bool ignoreMissing
|
||||
CODE:
|
||||
storageRemoveP(self, fileExp, .errorOnMissing = storageFeature(self, storageFeaturePath) ? !ignoreMissing : false);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
const char *
|
||||
cipherType(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
CODE:
|
||||
if (cfgOptionStr(cfgOptRepoCipherType) == NULL || cipherType(cfgOptionStr(cfgOptRepoCipherType)) == cipherTypeNone)
|
||||
RETVAL = NULL;
|
||||
else
|
||||
RETVAL = strPtr(cfgOptionStr(cfgOptRepoCipherType));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
const char *
|
||||
cipherPass(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
CODE:
|
||||
RETVAL = strPtr(cfgOptionStr(cfgOptRepoCipherPass));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
const char *
|
||||
type(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::Storage self
|
||||
CODE:
|
||||
RETVAL = strPtr(storageType(self));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
storageRepoFree()
|
||||
CODE:
|
||||
storageHelperFree();
|
@ -1,129 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage XS Header
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/assert.h"
|
||||
#include "common/compress/gz/compress.h"
|
||||
#include "common/compress/gz/decompress.h"
|
||||
#include "common/crypto/cipherBlock.h"
|
||||
#include "common/io/filter/size.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/convert.h"
|
||||
#include "common/type/json.h"
|
||||
#include "postgres/interface.h"
|
||||
#include "storage/helper.h"
|
||||
#include "storage/s3/storage.intern.h"
|
||||
#include "storage/storage.intern.h"
|
||||
|
||||
typedef Storage *pgBackRest__LibC__Storage;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Manifest callback
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct StorageManifestXsCallbackData
|
||||
{
|
||||
const Storage *storage;
|
||||
const String *pathRoot;
|
||||
const String *path;
|
||||
String *json;
|
||||
const String *filter;
|
||||
} StorageManifestXsCallbackData;
|
||||
|
||||
String *
|
||||
storageManifestXsInfo(const String *path, const StorageInfo *info)
|
||||
{
|
||||
String *json = strNew("");
|
||||
|
||||
if (info->name != NULL)
|
||||
{
|
||||
strCatFmt(
|
||||
json, "%s:", strPtr(jsonFromStr(path == NULL ? info->name : strNewFmt("%s/%s", strPtr(path), strPtr(info->name)))));
|
||||
}
|
||||
|
||||
strCatFmt(json, "{\"group\":%s,\"user\":%s,\"type\":\"", strPtr(jsonFromStr(info->group)), strPtr(jsonFromStr(info->user)));
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
case storageTypeFile:
|
||||
{
|
||||
strCatFmt(
|
||||
json, "f\",\"mode\":\"%04o\",\"modification_time\":%" PRId64 ",\"size\":%" PRIu64 "}", info->mode,
|
||||
(int64_t)info->timeModified, info->size);
|
||||
break;
|
||||
}
|
||||
|
||||
case storageTypeLink:
|
||||
{
|
||||
strCatFmt(json, "l\",\"link_destination\":%s}", strPtr(jsonFromStr(info->linkDestination)));
|
||||
break;
|
||||
}
|
||||
|
||||
case storageTypePath:
|
||||
{
|
||||
strCatFmt(json, "d\",\"mode\":\"%04o\"}", info->mode);
|
||||
break;
|
||||
}
|
||||
|
||||
case storageTypeSpecial:
|
||||
{
|
||||
strCatFmt(json, "s\",\"mode\":\"%04o\"}", info->mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void
|
||||
storageManifestXsCallback(void *callbackData, const StorageInfo *info)
|
||||
{
|
||||
StorageManifestXsCallbackData *data = (StorageManifestXsCallbackData *)callbackData;
|
||||
|
||||
if (data->path == NULL || !strEqZ(info->name, "."))
|
||||
{
|
||||
if (!strEqZ(info->name, ".") && data->filter && !strEq(data->filter, info->name))
|
||||
return;
|
||||
|
||||
if (strSize(data->json) != 1)
|
||||
strCat(data->json, ",");
|
||||
|
||||
strCat(data->json, strPtr(storageManifestXsInfo(data->path, info)));
|
||||
|
||||
if (info->type == storageTypePath)
|
||||
{
|
||||
if (!strEqZ(info->name, "."))
|
||||
{
|
||||
StorageManifestXsCallbackData dataSub =
|
||||
{
|
||||
.storage = data->storage,
|
||||
.json = data->json,
|
||||
.pathRoot = data->pathRoot,
|
||||
.path = data->path == NULL ? info->name : strNewFmt("%s/%s", strPtr(data->path), strPtr(info->name)),
|
||||
};
|
||||
|
||||
storageInfoListP(
|
||||
dataSub.storage, strNewFmt("%s/%s", strPtr(dataSub.pathRoot), strPtr(dataSub.path)), storageManifestXsCallback,
|
||||
&dataSub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Add IO filter
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
storageFilterXsAdd(IoFilterGroup *filterGroup, const String *filter, const String *paramJson)
|
||||
{
|
||||
VariantList *paramList = paramJson ? jsonToVarLst(paramJson) : NULL;
|
||||
|
||||
if (strEqZ(filter, "pgBackRest::Storage::Filter::CipherBlock"))
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
filterGroup,
|
||||
cipherBlockNew(
|
||||
varUInt64Force(varLstGet(paramList, 0)) ? cipherModeEncrypt : cipherModeDecrypt,
|
||||
cipherType(varStr(varLstGet(paramList, 1))), BUFSTR(varStr(varLstGet(paramList, 2))), NULL));
|
||||
}
|
||||
else
|
||||
THROW_FMT(AssertError, "unable to add invalid filter '%s'", strPtr(filter));
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Storage Read Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC::StorageRead
|
||||
|
||||
####################################################################################################################################
|
||||
pgBackRest::LibC::StorageRead
|
||||
new(class, storage, file, ignoreMissing)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
const String *class = STR_NEW_SV($arg);
|
||||
pgBackRest::LibC::Storage storage
|
||||
const String *file = STR_NEW_SV($arg);
|
||||
bool ignoreMissing
|
||||
CODE:
|
||||
CHECK(strEqZ(class, PACKAGE_NAME_LIBC "::StorageRead"));
|
||||
|
||||
RETVAL = storageReadMove(storageNewReadP(storage, file, .ignoreMissing = ignoreMissing), memContextPrior());
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
filterAdd(self, filter, param)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
const String *filter = STR_NEW_SV($arg);
|
||||
const String *param = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
IoFilterGroup *filterGroup = ioReadFilterGroup(storageReadIo(self));
|
||||
storageFilterXsAdd(filterGroup, filter, param);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
bool
|
||||
open(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
CODE:
|
||||
RETVAL = ioReadOpen(storageReadIo(self));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
read(self, bufferSize)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
U32 bufferSize
|
||||
CODE:
|
||||
RETVAL = NEWSV(0, bufferSize);
|
||||
SvPOK_only(RETVAL);
|
||||
|
||||
Buffer *bufferRead = bufNewUseC((unsigned char *)SvPV_nolen(RETVAL), bufferSize);
|
||||
ioRead(storageReadIo(self), bufferRead);
|
||||
|
||||
SvCUR_set(RETVAL, bufUsed(bufferRead));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
bool
|
||||
eof(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
CODE:
|
||||
RETVAL = ioReadEof(storageReadIo(self));
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
close(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
CODE:
|
||||
ioReadClose(storageReadIo(self));
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
DESTROY(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageRead self
|
||||
CODE:
|
||||
storageReadFree(self);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
@ -1,4 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage Read XS Header
|
||||
***********************************************************************************************************************************/
|
||||
typedef StorageRead *pgBackRest__LibC__StorageRead;
|
@ -1,113 +0,0 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Storage Write Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC::StorageWrite
|
||||
|
||||
####################################################################################################################################
|
||||
pgBackRest::LibC::StorageWrite
|
||||
new(class, storage, file, mode, user, group, timeModified, atomic, pathCreate)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
const String *class = STR_NEW_SV($arg);
|
||||
pgBackRest::LibC::Storage storage
|
||||
const String *file = STR_NEW_SV($arg);
|
||||
U32 mode
|
||||
const String *user = STR_NEW_SV($arg);
|
||||
const String *group = STR_NEW_SV($arg);
|
||||
IV timeModified
|
||||
bool atomic
|
||||
bool pathCreate
|
||||
CODE:
|
||||
CHECK(strEqZ(class, PACKAGE_NAME_LIBC "::StorageWrite"));
|
||||
|
||||
RETVAL = storageWriteMove(
|
||||
storageNewWriteP(
|
||||
storage, file, .modeFile = mode, .user = user, .group = group, .timeModified = (time_t)timeModified,
|
||||
.noCreatePath = storageFeature(storage, storageFeaturePath) ? !pathCreate : false, .noSyncPath = !atomic,
|
||||
.noAtomic = !atomic),
|
||||
memContextPrior());
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
filterAdd(self, filter, param)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite self
|
||||
const String *filter = STR_NEW_SV($arg);
|
||||
const String *param = STR_NEW_SV($arg);
|
||||
CODE:
|
||||
IoFilterGroup *filterGroup = ioWriteFilterGroup(storageWriteIo(self));
|
||||
storageFilterXsAdd(filterGroup, filter, param);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
open(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite self
|
||||
CODE:
|
||||
ioWriteOpen(storageWriteIo(self));
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
UV
|
||||
write(self, buffer)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite self
|
||||
const Buffer *buffer = BUF_CONST_SV($arg);
|
||||
CODE:
|
||||
ioWrite(storageWriteIo(self), buffer);
|
||||
RETVAL = bufUsed(buffer);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
close(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite self
|
||||
CODE:
|
||||
ioWriteClose(storageWriteIo(self));
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
||||
|
||||
####################################################################################################################################
|
||||
void
|
||||
DESTROY(self)
|
||||
PREINIT:
|
||||
MEM_CONTEXT_XS_TEMP_BEGIN()
|
||||
{
|
||||
INPUT:
|
||||
pgBackRest::LibC::StorageWrite self
|
||||
CODE:
|
||||
storageWriteFree(self);
|
||||
CLEANUP:
|
||||
}
|
||||
MEM_CONTEXT_XS_TEMP_END();
|
@ -1,4 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage Write XS Header
|
||||
***********************************************************************************************************************************/
|
||||
typedef StorageWrite *pgBackRest__LibC__StorageWrite;
|
2
test/Vagrantfile
vendored
2
test/Vagrantfile
vendored
@ -91,7 +91,7 @@ Vagrant.configure(2) do |config|
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
echo 'Build VM Images' && date
|
||||
rm -rf /backrest/test/.vagrant/docker/*
|
||||
rm -rf /backrest/test/.vagrant/libc/*
|
||||
rm -rf /backrest/test/.vagrant/bin/*
|
||||
rm -rf /backrest/test/.vagrant/package/*
|
||||
sudo su - vagrant -c '/backrest/test/test.pl --vm-build'
|
||||
|
||||
|
@ -239,14 +239,6 @@ lib/pgBackRest/InfoCommon.pm:
|
||||
class: test/harness
|
||||
type: perl
|
||||
|
||||
lib/pgBackRest/LibC.pm:
|
||||
class: test/harness
|
||||
type: perl
|
||||
|
||||
lib/pgBackRest/LibCAuto.pm:
|
||||
class: test/harness/auto
|
||||
type: perl
|
||||
|
||||
lib/pgBackRest/Manifest.pm:
|
||||
class: test/harness
|
||||
type: perl
|
||||
@ -279,82 +271,6 @@ lib/pgBackRest/Version.pm:
|
||||
class: test/harness
|
||||
type: perl
|
||||
|
||||
libc/LibC.h:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/LibC.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/Makefile.PL:
|
||||
class: build
|
||||
type: perl
|
||||
|
||||
libc/build/lib/pgBackRestLibC/Build.pm:
|
||||
class: build
|
||||
type: perl
|
||||
|
||||
libc/xs/config/config.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/config/configTest.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/config/configTest.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/xs/config/define.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/crypto/hash.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/crypto/hash.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/xs/postgres/client.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/postgres/client.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/xs/postgres/pageChecksum.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/storage/storage.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/storage/storage.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/xs/storage/storageRead.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/storage/storageRead.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
libc/xs/storage/storageWrite.xs:
|
||||
class: test/harness
|
||||
type: xs
|
||||
|
||||
libc/xs/storage/storageWrite.xsh:
|
||||
class: test/harness
|
||||
type: c/h
|
||||
|
||||
src/Makefile.in:
|
||||
class: build
|
||||
type: make
|
||||
|
@ -113,7 +113,7 @@ sub buildDependencyTree
|
||||
# Only process non-auto files
|
||||
if ($strFile =~ /^[A-Za-z0-9\/]+\.(c|h)$/)
|
||||
{
|
||||
buildDependencyTreeSub($oStorage, $rhDependencyTree, $strFile, true, undef, ['src', 'libc']);
|
||||
buildDependencyTreeSub($oStorage, $rhDependencyTree, $strFile, true, undef, ['src']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,8 +229,7 @@ sub buildMakefileObjectCompile
|
||||
|
||||
foreach my $strInclude (@{$rhDependencyTree->{$strFile}{include}})
|
||||
{
|
||||
$strDepend .=
|
||||
' ' . ($oStorage->exists("src/${strInclude}") || $strInclude eq BUILD_AUTO_H ? '' : '../libc/') . $strInclude;
|
||||
$strDepend .= " ${strInclude}";
|
||||
}
|
||||
|
||||
$strMakefile .=
|
||||
@ -288,27 +287,5 @@ sub buildMakefile
|
||||
|
||||
push @EXPORT, qw(buildMakefile);
|
||||
|
||||
####################################################################################################################################
|
||||
# Load the C library and check pointer size
|
||||
####################################################################################################################################
|
||||
sub buildLoadLibC
|
||||
{
|
||||
# Load the module dynamically
|
||||
require pgBackRest::LibC;
|
||||
pgBackRest::LibC->import(qw(:debug));
|
||||
|
||||
# Load shared object
|
||||
require XSLoader;
|
||||
XSLoader::load('pgBackRest::LibC', '999');
|
||||
|
||||
# Do a basic test to make sure it installed correctly
|
||||
if (libcUvSize() != 8)
|
||||
{
|
||||
confess &log(ERROR, 'UVSIZE in test library does not equal 8');
|
||||
}
|
||||
}
|
||||
|
||||
push @EXPORT, qw(buildLoadLibC);
|
||||
|
||||
|
||||
1;
|
||||
|
@ -55,7 +55,6 @@ sub codeCountScan
|
||||
$strFile =~ '\.eps$' ||
|
||||
$strFile =~ '\.cache$' ||
|
||||
$strFile =~ '^doc/site/' ||
|
||||
$strFile eq 'libc/typemap' ||
|
||||
$strFile eq 'test/Vagrantfile' ||
|
||||
$strFile =~ '^test/\.vagrant/' ||
|
||||
$strFile =~ '^test/certificate/' ||
|
||||
@ -83,13 +82,12 @@ sub codeCountScan
|
||||
{
|
||||
$strClass = 'doc/core';
|
||||
}
|
||||
elsif ($strFile =~ '^build/' || $strFile =~ '^libc/build/' || $strFile eq 'libc/Makefile.PL' ||
|
||||
$strFile eq 'src/Makefile.in' || $strFile eq 'src/configure' || $strFile eq 'src/configure.ac')
|
||||
elsif ($strFile =~ '^build/' || $strFile eq 'src/Makefile.in' || $strFile eq 'src/configure' ||
|
||||
$strFile eq 'src/configure.ac')
|
||||
{
|
||||
$strClass = 'build';
|
||||
}
|
||||
elsif ($strFile =~ '^test/lib/pgBackRestTest/Module/' || $strFile =~ '^test/src/module/' ||
|
||||
$strFile =~ '^libc/t/')
|
||||
elsif ($strFile =~ '^test/lib/pgBackRestTest/Module/' || $strFile =~ '^test/src/module/')
|
||||
{
|
||||
$strClass = 'test/module';
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
@ -154,7 +153,7 @@ sub forceStorageMode
|
||||
(
|
||||
$strOperation,
|
||||
$oStorage,
|
||||
$strPathExp,
|
||||
$strPath,
|
||||
$strMode,
|
||||
$bRecurse
|
||||
) =
|
||||
@ -162,15 +161,15 @@ sub forceStorageMode
|
||||
(
|
||||
__PACKAGE__ . '::forceStorageMode', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'strPathExp'},
|
||||
{name => 'strPath'},
|
||||
{name => 'strMode'},
|
||||
{name => 'bRecurse', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Mode commands are ignored on S3
|
||||
if (!$oStorage->can('type') || $oStorage->type() ne STORAGE_S3)
|
||||
# Mode commands are ignored on object storage
|
||||
if ($oStorage->type() ne STORAGE_OBJECT)
|
||||
{
|
||||
executeTest('chmod ' . ($bRecurse ? '-R ' : '') . "${strMode} " . $oStorage->pathGet($strPathExp));
|
||||
executeTest('chmod ' . ($bRecurse ? '-R ' : '') . "${strMode} ${strPath}");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -189,55 +188,48 @@ sub forceStorageMove
|
||||
(
|
||||
$strOperation,
|
||||
$oStorage,
|
||||
$strSourcePathExp,
|
||||
$strDestinationPathExp,
|
||||
$strSourcePath,
|
||||
$strDestinationPath,
|
||||
$bRecurse,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->forceStorageMove', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'strSourcePathExp'},
|
||||
{name => 'strDestinationPathExp'},
|
||||
{name => 'strSourcePath'},
|
||||
{name => 'strDestinationPath'},
|
||||
{name => 'bRecurse', optional => true, default => true},
|
||||
);
|
||||
|
||||
# If S3 then use storage commands to remove
|
||||
if ($oStorage->type() eq STORAGE_S3)
|
||||
# If object storage then use storage commands to remove
|
||||
if ($oStorage->type() eq STORAGE_OBJECT)
|
||||
{
|
||||
if ($bRecurse)
|
||||
{
|
||||
my $rhManifest = $oStorage->manifest($strSourcePathExp);
|
||||
my $rhManifest = $oStorage->manifest($strSourcePath);
|
||||
|
||||
foreach my $strName (sort(keys(%{$rhManifest})))
|
||||
{
|
||||
if ($rhManifest->{$strName}{type} eq 'f')
|
||||
{
|
||||
$oStorage->put(
|
||||
new pgBackRest::Storage::StorageWrite(
|
||||
$oStorage,
|
||||
pgBackRest::LibC::StorageWrite->new(
|
||||
$oStorage->{oStorageC}, "${strDestinationPathExp}/${strName}", 0, undef, undef, 0, true, false)),
|
||||
${$oStorage->get(
|
||||
new pgBackRest::Storage::StorageRead(
|
||||
$oStorage,
|
||||
pgBackRest::LibC::StorageRead->new(
|
||||
$oStorage->{oStorageC}, "${strSourcePathExp}/${strName}", false)))});
|
||||
|
||||
$oStorage->remove("${strSourcePathExp}/${strName}");
|
||||
"${strDestinationPath}/${strName}", ${$oStorage->get("${strSourcePath}/${strName}", {bRaw => true})},
|
||||
{bRaw => true});
|
||||
}
|
||||
}
|
||||
|
||||
$oStorage->pathRemove($strSourcePath, {bRecurse => true});
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStorage->put($strDestinationPathExp, ${$oStorage->get($strSourcePathExp)});
|
||||
$oStorage->remove($strSourcePathExp);
|
||||
$oStorage->put($strDestinationPath, ${$oStorage->get($strSourcePath)});
|
||||
$oStorage->remove($strSourcePath);
|
||||
}
|
||||
}
|
||||
# Else remove using filesystem commands
|
||||
else
|
||||
{
|
||||
executeTest('mv ' . $oStorage->pathGet($strSourcePathExp) . ' ' . $oStorage->pathGet($strDestinationPathExp));
|
||||
executeTest("mv ${strSourcePath} ${strDestinationPath}");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -246,41 +238,6 @@ sub forceStorageMove
|
||||
|
||||
push(@EXPORT, qw(forceStorageMove));
|
||||
|
||||
####################################################################################################################################
|
||||
# forceStorageOwner - force ownership on a file or path
|
||||
####################################################################################################################################
|
||||
sub forceStorageOwner
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oStorage,
|
||||
$strPathExp,
|
||||
$strOwner,
|
||||
$bRecurse
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::forceStorageOwner', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'strPathExp'},
|
||||
{name => 'strOwner'},
|
||||
{name => 'bRecurse', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Owner commands are ignored on S3
|
||||
if ($oStorage->type() ne STORAGE_S3)
|
||||
{
|
||||
executeTest('chown ' . ($bRecurse ? '-R ' : '') . "${strOwner} " . $oStorage->pathGet($strPathExp));
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
push(@EXPORT, qw(forceStorageOwner));
|
||||
|
||||
####################################################################################################################################
|
||||
# forceStorageRemove - force remove a file or path from storage
|
||||
####################################################################################################################################
|
||||
@ -291,34 +248,25 @@ sub forceStorageRemove
|
||||
(
|
||||
$strOperation,
|
||||
$oStorage,
|
||||
$strPathExp,
|
||||
$strPath,
|
||||
$bRecurse
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->forceStorageRemove', \@_,
|
||||
{name => 'oStorage'},
|
||||
{name => 'strPathExp'},
|
||||
{name => 'strPath'},
|
||||
{name => 'bRecurse', optional => true, default => false},
|
||||
);
|
||||
|
||||
# If S3 then use storage commands to remove
|
||||
if ($oStorage->type() eq STORAGE_S3)
|
||||
# If object storage then use storage commands to remove
|
||||
if ($oStorage->type() eq STORAGE_OBJECT)
|
||||
{
|
||||
my $oInfo = $oStorage->info($strPathExp, {bIgnoreMissing => true});
|
||||
|
||||
if (defined($oInfo) && $oInfo->{type} eq 'f')
|
||||
{
|
||||
$oStorage->remove($strPathExp);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStorage->pathRemove($strPathExp, {bRecurse => true});
|
||||
}
|
||||
$oStorage->pathRemove($strPath, {bRecurse => true});
|
||||
}
|
||||
else
|
||||
{
|
||||
executeTest('rm -f' . ($bRecurse ? 'r ' : ' ') . $oStorage->pathGet($strPathExp));
|
||||
executeTest('rm -f' . ($bRecurse ? 'r ' : ' ') . $strPath);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
|
@ -221,13 +221,11 @@ sub run
|
||||
if (!$rhBuildInit->{$self->{oTest}->{&TEST_VM}}{$self->{iVmIdx}})
|
||||
{
|
||||
executeTest(
|
||||
'rsync -rt --delete --exclude=*.o --exclude=test.c --exclude=test.gcno --exclude=LibC.h --exclude=xs' .
|
||||
'rsync -rt --delete --exclude=*.o --exclude=test.c --exclude=test.gcno ' .
|
||||
' --exclude=test --exclude=buildflags --exclude=testflags --exclude=harnessflags' .
|
||||
' --exclude=build.auto.h --exclude=build.auto.h.in --exclude=Makefile --exclude=Makefile.in' .
|
||||
' --exclude=configure --exclude=configure.ac' .
|
||||
" $self->{strBackRestBase}/src/ $self->{strGCovPath} && " .
|
||||
"rsync -t $self->{strBackRestBase}/libc/LibC.h $self->{strGCovPath} && " .
|
||||
"rsync -rt --delete $self->{strBackRestBase}/libc/xs/ $self->{strGCovPath}/xs && " .
|
||||
"rsync -rt --delete --exclude=*.o $self->{strBackRestBase}/test/src/ $self->{strGCovPath}/test");
|
||||
}
|
||||
|
||||
@ -794,7 +792,6 @@ sub jobInstallC
|
||||
|
||||
my $oVm = vmGet();
|
||||
my $strBuildPath = "${strBasePath}/test/.vagrant/bin/${strVm}";
|
||||
my $strBuildLibCPath = "${strBuildPath}/libc";
|
||||
my $strBuildBinPath = "${strBuildPath}/src";
|
||||
|
||||
executeTest(
|
||||
|
@ -115,7 +115,7 @@ sub testListGet
|
||||
# Skip this test if it is integration and vm=none
|
||||
next if ($strVm eq VM_NONE && $hTest->{&TESTDEF_TYPE} eq TESTDEF_INTEGRATION);
|
||||
|
||||
# Skip this test if it is not C and vm=none. Perl tests require libc which is not supported.
|
||||
# Skip this test if it is not C and vm=none. Perl tests require Docker which is not supported.
|
||||
next if ($strVm eq VM_NONE && !$hTest->{&TESTDEF_C});
|
||||
|
||||
# Skip this test if a container is required and vm=none.
|
||||
|
@ -114,7 +114,7 @@ sub process
|
||||
$self->{iVmId},
|
||||
$self->{strBasePath},
|
||||
$self->{strTestPath},
|
||||
$self->{strBackRestExeC},
|
||||
$self->{strBackRestExe},
|
||||
$self->{strBackRestExeHelper},
|
||||
$self->{strPgBinPath},
|
||||
$self->{strPgVersion},
|
||||
@ -136,7 +136,7 @@ sub process
|
||||
{name => 'iVmId'},
|
||||
{name => 'strBasePath'},
|
||||
{name => 'strTestPath'},
|
||||
{name => 'strBackRestExeC'},
|
||||
{name => 'strBackRestExe'},
|
||||
{name => 'strBackRestExeHelper'},
|
||||
{name => 'strPgBinPath', required => false},
|
||||
{name => 'strPgVersion', required => false},
|
||||
@ -159,9 +159,6 @@ sub process
|
||||
$oStorage = new pgBackRestTest::Common::Storage(
|
||||
$self->testPath(), new pgBackRestTest::Common::StoragePosix({bFileSync => false, bPathSync => false}));
|
||||
|
||||
# Generate backrest exe
|
||||
$self->{strBackRestExe} = defined($self->{strBackRestExeC}) ? $self->{strBackRestExeC} : $self->{strBackRestExeHelper};
|
||||
|
||||
projectBinSet($self->{strBackRestExe});
|
||||
|
||||
# Init, run, and end the test(s)
|
||||
@ -545,6 +542,7 @@ push(@EXPORT, qw(storageTest));
|
||||
####################################################################################################################################
|
||||
sub archBits {return vmArchBits(shift->{strVm})}
|
||||
sub backrestExe {return shift->{strBackRestExe}}
|
||||
sub backrestExeHelper {return shift->{strBackRestExeHelper}}
|
||||
sub basePath {return shift->{strBasePath}}
|
||||
sub dataPath {return shift->basePath() . '/test/data'}
|
||||
sub doCleanup {return shift->{bCleanup}}
|
||||
|
@ -69,6 +69,85 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Copy a file. If special encryption settings are required, then the file objects from openRead/openWrite must be passed instead of
|
||||
# file names.
|
||||
####################################################################################################################################
|
||||
sub copy
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xSourceFile,
|
||||
$xDestinationFile,
|
||||
$bSourceOpen,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->copy', \@_,
|
||||
{name => 'xSourceFile', required => false},
|
||||
{name => 'xDestinationFile'},
|
||||
{name => 'bSourceOpen', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Is source/destination an IO object or a file expression?
|
||||
my $oSourceFileIo = defined($xSourceFile) ? (ref($xSourceFile) ? $xSourceFile : $self->openRead($xSourceFile)) : undef;
|
||||
|
||||
# Does the source file exist?
|
||||
my $bResult = false;
|
||||
|
||||
# Copy if the source file exists
|
||||
if (defined($oSourceFileIo))
|
||||
{
|
||||
my $oDestinationFileIo = ref($xDestinationFile) ? $xDestinationFile : $self->openWrite($xDestinationFile);
|
||||
|
||||
# Use C copy if source and destination are C objects
|
||||
if (defined($oSourceFileIo->{oStorageCRead}) && defined($oDestinationFileIo->{oStorageCWrite}))
|
||||
{
|
||||
$bResult = $self->{oStorageC}->copy(
|
||||
$oSourceFileIo->{oStorageCRead}, $oDestinationFileIo->{oStorageCWrite}) ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Open the source file if it is a C object
|
||||
$bResult = defined($oSourceFileIo->{oStorageCRead}) ? ($bSourceOpen || $oSourceFileIo->open()) : true;
|
||||
|
||||
if ($bResult)
|
||||
{
|
||||
# Open the destination file if it is a C object
|
||||
if (defined($oDestinationFileIo->{oStorageCWrite}))
|
||||
{
|
||||
$oDestinationFileIo->open();
|
||||
}
|
||||
|
||||
# Copy the data
|
||||
do
|
||||
{
|
||||
# Read data
|
||||
my $tBuffer = '';
|
||||
|
||||
$oSourceFileIo->read(\$tBuffer, $self->{lBufferMax});
|
||||
$oDestinationFileIo->write(\$tBuffer);
|
||||
}
|
||||
while (!$oSourceFileIo->eof());
|
||||
|
||||
# Close files
|
||||
$oSourceFileIo->close();
|
||||
$oDestinationFileIo->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => $bResult, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# exists - check if file exists
|
||||
####################################################################################################################################
|
||||
@ -99,6 +178,62 @@ sub exists
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# get - reads a buffer from storage all at once
|
||||
####################################################################################################################################
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->get', \@_,
|
||||
{name => 'xFile', required => false, trace => true},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or
|
||||
# if the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = defined($xFile) ? (ref($xFile) ? $xFile : $self->openRead($xFile)) : undef;
|
||||
|
||||
# Read only if there is something to read from
|
||||
my $tContent;
|
||||
my $lSize = 0;
|
||||
|
||||
if (defined($oFileIo))
|
||||
{
|
||||
my $lSizeRead;
|
||||
|
||||
do
|
||||
{
|
||||
$lSizeRead = $oFileIo->read(\$tContent, $self->{lBufferMax});
|
||||
$lSize += $lSizeRead;
|
||||
}
|
||||
while ($lSizeRead != 0);
|
||||
|
||||
# Close the file
|
||||
$oFileIo->close();
|
||||
|
||||
# If nothing was read then set to undef
|
||||
if ($lSize == 0)
|
||||
{
|
||||
$tContent = undef;
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rtContent', value => defined($oFileIo) ? \$tContent : undef, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# info - get information for path/file
|
||||
####################################################################################################################################
|
||||
@ -595,6 +730,56 @@ sub pathSync
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# put - writes a buffer out to storage all at once
|
||||
####################################################################################################################################
|
||||
sub put
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$xContent,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->put', \@_,
|
||||
{name => 'xFile', trace => true},
|
||||
{name => 'xContent', required => false, trace => true},
|
||||
);
|
||||
|
||||
# Is this an IO object or a file expression? If file expression, then open the file and pass passphrase if one is defined or if
|
||||
# the repo has a user passphrase defined - else pass undef
|
||||
my $oFileIo = ref($xFile) ? $xFile : $self->openWrite($xFile);
|
||||
|
||||
# Determine size of content
|
||||
my $lSize = defined($xContent) ? length(ref($xContent) ? $$xContent : $xContent) : 0;
|
||||
|
||||
# Write only if there is something to write
|
||||
if ($lSize > 0)
|
||||
{
|
||||
$oFileIo->write(ref($xContent) ? $xContent : \$xContent);
|
||||
}
|
||||
# Else open the file so a zero length file is created (since file is not opened until first write)
|
||||
else
|
||||
{
|
||||
$oFileIo->open();
|
||||
}
|
||||
|
||||
# Close the file
|
||||
$oFileIo->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'lSize', value => $lSize, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# remove - remove path/file
|
||||
####################################################################################################################################
|
||||
@ -647,7 +832,6 @@ sub remove
|
||||
####################################################################################################################################
|
||||
sub pathBase {shift->{strPathBase}}
|
||||
sub driver {shift->{oDriver}}
|
||||
sub cipherType {undef}
|
||||
sub cipherPassUser {undef}
|
||||
sub type {shift->{oDriver}->type()}
|
||||
|
||||
1;
|
||||
|
@ -978,5 +978,6 @@ sub remove
|
||||
sub className {STORAGE_POSIX_DRIVER}
|
||||
sub tempExtension {shift->{strTempExtension}}
|
||||
sub tempExtensionSet {my $self = shift; $self->{strTempExtension} = shift}
|
||||
sub type {STORAGE_POSIX}
|
||||
|
||||
1;
|
||||
|
@ -509,7 +509,7 @@ sub vmValid
|
||||
|
||||
if (!defined($oyVm->{$strVm}))
|
||||
{
|
||||
confess &log(ERROR, "no definition for vm '${strVm}'", ERROR_OPTION_INVALID_VALUE);
|
||||
confess &log(ERROR, "no definition for vm '${strVm}'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,191 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# ConfigCommonTest.pm - Common code for Config unit tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Env::ConfigEnvTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::LibC qw(:test);
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
use constant CONFIGENVTEST => 'ConfigEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Is the option secure?
|
||||
####################################################################################################################################
|
||||
sub optionTestSecure
|
||||
{
|
||||
my $self = shift;
|
||||
my $strOption = shift;
|
||||
|
||||
return (cfgDefOptionSecure(cfgOptionId($strOption)) ? true : false);
|
||||
}
|
||||
|
||||
sub optionTestSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $iOptionId = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
$self->{&CONFIGENVTEST}{option}{cfgOptionName($iOptionId)} = $strValue;
|
||||
}
|
||||
|
||||
sub optionTestSetBool
|
||||
{
|
||||
my $self = shift;
|
||||
my $iOptionId = shift;
|
||||
my $bValue = shift;
|
||||
|
||||
$self->{&CONFIGENVTEST}{boolean}{cfgOptionName($iOptionId)} = defined($bValue) ? $bValue : true;
|
||||
}
|
||||
|
||||
sub optionTestClear
|
||||
{
|
||||
my $self = shift;
|
||||
my $iOptionId = shift;
|
||||
|
||||
delete($self->{&CONFIGENVTEST}{option}{cfgOptionName($iOptionId)});
|
||||
delete($self->{&CONFIGENVTEST}{boolean}{cfgOptionName($iOptionId)});
|
||||
}
|
||||
|
||||
sub configTestClear
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
my $rhConfig = $self->{&CONFIGENVTEST};
|
||||
|
||||
delete($self->{&CONFIGENVTEST});
|
||||
|
||||
return $rhConfig;
|
||||
}
|
||||
|
||||
sub configTestSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $rhConfig = shift;
|
||||
|
||||
$self->{&CONFIGENVTEST} = $rhConfig;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Write all secure options to a config file
|
||||
####################################################################################################################################
|
||||
sub configFileWrite
|
||||
{
|
||||
my $self = shift;
|
||||
my $strConfigFile = shift;
|
||||
my $rhConfig = shift;
|
||||
|
||||
my $strConfig = "[global]\n";
|
||||
|
||||
if (defined($rhConfig->{boolean}))
|
||||
{
|
||||
foreach my $strOption (sort(keys(%{$rhConfig->{boolean}})))
|
||||
{
|
||||
if ($self->optionTestSecure($strOption))
|
||||
{
|
||||
$strConfig .= "${strOption}=" . ($rhConfig->{boolean}{$strOption} ? 'y' : 'n') . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($rhConfig->{option}))
|
||||
{
|
||||
foreach my $strOption (sort(keys(%{$rhConfig->{option}})))
|
||||
{
|
||||
if ($self->optionTestSecure($strOption))
|
||||
{
|
||||
$strConfig .= "${strOption}=$rhConfig->{option}{$strOption}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
storageTest()->put($strConfigFile, $strConfig);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Write all non-secure options to the command line
|
||||
####################################################################################################################################
|
||||
sub commandTestWrite
|
||||
{
|
||||
my $self = shift;
|
||||
my $strCommand = shift;
|
||||
my $strConfigFile = shift;
|
||||
my $rhConfig = shift;
|
||||
|
||||
my @szyParam = ();
|
||||
|
||||
# Add boolean options
|
||||
if (defined($rhConfig->{boolean}))
|
||||
{
|
||||
foreach my $strOption (sort(keys(%{$rhConfig->{boolean}})))
|
||||
{
|
||||
if (!$self->optionTestSecure($strOption))
|
||||
{
|
||||
if ($rhConfig->{boolean}{$strOption})
|
||||
{
|
||||
push(@szyParam, "--${strOption}");
|
||||
}
|
||||
else
|
||||
{
|
||||
push(@szyParam, "--no-${strOption}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add non-boolean options
|
||||
if (defined($rhConfig->{option}))
|
||||
{
|
||||
foreach my $strOption (sort(keys(%{$rhConfig->{option}})))
|
||||
{
|
||||
if (!$self->optionTestSecure($strOption))
|
||||
{
|
||||
push(@szyParam, "--${strOption}=$rhConfig->{option}{$strOption}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add config file
|
||||
push(@szyParam, '--' . cfgOptionName(CFGOPT_CONFIG) . "=${strConfigFile}");
|
||||
|
||||
# Add command
|
||||
push(@szyParam, $strCommand);
|
||||
|
||||
return @szyParam;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Load the configuration
|
||||
####################################################################################################################################
|
||||
sub configTestLoad
|
||||
{
|
||||
my $self = shift;
|
||||
my $iCommandId = shift;
|
||||
|
||||
# A config file is required to store secure options before they can be parsed
|
||||
my $strConfigFile = $self->testPath() . '/pgbackrest.test.conf';
|
||||
$self->configFileWrite($strConfigFile, $self->{&CONFIGENVTEST});
|
||||
|
||||
my @stryArg = $self->commandTestWrite(cfgCommandName($iCommandId), $strConfigFile, $self->{&CONFIGENVTEST});
|
||||
my $strConfigJson = cfgParseTest(projectBin(), join('|', @stryArg));
|
||||
$self->testResult(
|
||||
sub {configLoad(false, projectBin(), cfgCommandName($iCommandId), \$strConfigJson)},
|
||||
true, 'config load: ' . join(" ", @stryArg));
|
||||
}
|
||||
|
||||
1;
|
@ -20,10 +20,8 @@ use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
@ -50,6 +48,7 @@ sub new
|
||||
$self->{oHostBackup},
|
||||
$self->{strBackRestExe},
|
||||
$self->{oStorageRepo},
|
||||
$self->{strPgPath},
|
||||
$self->{oLogTest},
|
||||
$self->{oRunTest},
|
||||
) =
|
||||
@ -59,6 +58,7 @@ sub new
|
||||
{name => 'oHostBackup', required => false, trace => true},
|
||||
{name => 'strBackRestExe', trace => true},
|
||||
{name => 'oStorageRepo', trace => true},
|
||||
{name => 'strPgPath', trace => true},
|
||||
{name => 'oLogTest', required => false, trace => true},
|
||||
{name => 'oRunTest', required => false, trace => true},
|
||||
);
|
||||
@ -124,7 +124,7 @@ sub info
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->info', \@_,
|
||||
{name => 'strDbPath', default => cfgOption(CFGOPT_PG_PATH)}
|
||||
{name => 'strDbPath', default => $self->{strPgPath}}
|
||||
);
|
||||
|
||||
# Open the control file and read system id and versions
|
||||
@ -168,8 +168,7 @@ sub info
|
||||
ERROR,
|
||||
'unexpected control version = ' . $self->{info}{$strDbPath}{iDbControlVersion} .
|
||||
' and catalog version = ' . $self->{info}{$strDbPath}{iDbCatalogVersion} . "\n" .
|
||||
'HINT: is this version of PostgreSQL supported?',
|
||||
ERROR_VERSION_NOT_SUPPORTED);
|
||||
'HINT: is this version of PostgreSQL supported?');
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -210,7 +209,6 @@ sub stanzaSet
|
||||
my $oStanza = {};
|
||||
my $oArchiveInfo = {};
|
||||
my $oBackupInfo = {};
|
||||
my $bEncrypted = defined($self->{oStorageRepo}->cipherType());
|
||||
my $iArchiveDbId = 1;
|
||||
my $iBackupDbId = 1;
|
||||
|
||||
@ -218,26 +216,21 @@ sub stanzaSet
|
||||
if (!$bStanzaUpgrade)
|
||||
{
|
||||
$oArchiveInfo =
|
||||
new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath(), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
$oBackupInfo =
|
||||
new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath(), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
}
|
||||
# Else get the info data from disk
|
||||
else
|
||||
{
|
||||
$oArchiveInfo =
|
||||
new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE),
|
||||
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath(),
|
||||
{strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
$oBackupInfo =
|
||||
new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP),
|
||||
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
}
|
||||
|
||||
if (cfgOption(CFGOPT_ONLINE))
|
||||
{
|
||||
confess &log(ERROR, "this function may not be used for online tests");
|
||||
new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath(),
|
||||
{strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
}
|
||||
|
||||
# Get the database info for the stanza
|
||||
@ -258,8 +251,8 @@ sub stanzaSet
|
||||
$oBackupInfo->save();
|
||||
|
||||
# Get the archive and directory paths for the stanza
|
||||
$$oStanza{strArchiveClusterPath} = $self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE) . '/' . ($oArchiveInfo->archiveId());
|
||||
$$oStanza{strBackupClusterPath} = $self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP);
|
||||
$$oStanza{strArchiveClusterPath} = $self->{oHostBackup}->repoArchivePath($oArchiveInfo->archiveId());
|
||||
$$oStanza{strBackupClusterPath} = $self->{oHostBackup}->repoBackupPath();
|
||||
|
||||
$self->{oStanzaHash}{$strStanza} = $oStanza;
|
||||
|
||||
@ -291,14 +284,12 @@ sub stanzaCreate
|
||||
my $strDbVersionTemp = $strDbVersion;
|
||||
$strDbVersionTemp =~ s/\.//;
|
||||
|
||||
my $strDbPath = cfgOption(CFGOPT_PG_PATH);
|
||||
|
||||
# Create the test path for pg_control
|
||||
storageTest()->pathCreate(($strDbPath . '/' . DB_PATH_GLOBAL), {bIgnoreExists => true});
|
||||
storageTest()->pathCreate(($self->{strPgPath} . '/' . DB_PATH_GLOBAL), {bIgnoreExists => true});
|
||||
|
||||
# Generate pg_control for stanza-create
|
||||
$self->controlGenerate($strDbPath, $strDbVersion);
|
||||
executeTest('chmod 600 ' . $strDbPath . '/' . DB_FILE_PGCONTROL);
|
||||
$self->controlGenerate($self->{strPgPath}, $strDbVersion);
|
||||
executeTest('chmod 600 ' . $self->{strPgPath} . '/' . DB_FILE_PGCONTROL);
|
||||
|
||||
# Create the stanza and set the local stanza object
|
||||
$self->stanzaSet($strStanza, $strDbVersion, false);
|
||||
@ -332,11 +323,11 @@ sub stanzaUpgrade
|
||||
$strDbVersionTemp =~ s/\.//;
|
||||
|
||||
# Remove pg_control
|
||||
storageTest()->remove(cfgOption(CFGOPT_PG_PATH) . '/' . DB_FILE_PGCONTROL);
|
||||
storageTest()->remove($self->{strPgPath} . '/' . DB_FILE_PGCONTROL);
|
||||
|
||||
# Copy pg_control for stanza-upgrade
|
||||
$self->controlGenerate(cfgOption(CFGOPT_PG_PATH), $strDbVersion);
|
||||
executeTest('chmod 600 ' . cfgOption(CFGOPT_PG_PATH) . '/' . DB_FILE_PGCONTROL);
|
||||
$self->controlGenerate($self->{strPgPath}, $strDbVersion);
|
||||
executeTest('chmod 600 ' . $self->{strPgPath} . '/' . DB_FILE_PGCONTROL);
|
||||
|
||||
$self->stanzaSet($strStanza, $strDbVersion, true);
|
||||
|
||||
@ -393,7 +384,7 @@ sub backupCreate
|
||||
|
||||
# Get passphrase (returns undefined if repo not encrypted) to access the manifest
|
||||
my $strCipherPassManifest =
|
||||
(new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP)))->cipherPassSub();
|
||||
(new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath()))->cipherPassSub();
|
||||
my $strCipherPassBackupSet;
|
||||
|
||||
# If repo is encrypted then get passphrase for accessing the backup files from the last manifest if it exists provide one
|
||||
@ -540,7 +531,7 @@ sub archiveCreate
|
||||
|
||||
# Get passphrase (returns undefined if repo not encrypted) to access the archive files
|
||||
my $strCipherPass =
|
||||
(new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE)))->cipherPassSub();
|
||||
(new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath()))->cipherPassSub();
|
||||
|
||||
push(my @stryArchive, $strArchive);
|
||||
|
||||
@ -604,7 +595,7 @@ sub supplementalLog
|
||||
join("\n", grep(!/^backup\.info.*$/i, storageRepo()->list("backup/${strStanza}"))));
|
||||
|
||||
# Output archive manifest
|
||||
my $rhManifest = storageRepo()->manifest(STORAGE_REPO_ARCHIVE);
|
||||
my $rhManifest = storageRepo()->manifest($self->{oHostBackup}->repoArchivePath());
|
||||
my $strManifest;
|
||||
my $strPrefix = '';
|
||||
|
||||
@ -615,7 +606,7 @@ sub supplementalLog
|
||||
|
||||
if ($rhManifest->{$strEntry}->{type} eq 'd')
|
||||
{
|
||||
$strEntry = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . ($strEntry eq '.' ? '' : "/${strEntry}");
|
||||
$strEntry = $self->{oHostBackup}->repoArchivePath($strEntry eq '.' ? undef : $strEntry);
|
||||
|
||||
# &log(WARN, "DIR $strEntry");
|
||||
$strManifest .= (defined($strManifest) ? "\n" : '') . "${strEntry}:\n";
|
||||
@ -670,10 +661,9 @@ sub process
|
||||
|
||||
undef($$oStanza{strBackupDescription});
|
||||
|
||||
my $strCommand = $self->{strBackRestExe} .
|
||||
' --' . cfgOptionName(CFGOPT_CONFIG) . '="' . $self->{oHostBackup}->backrestConfig() . '"' .
|
||||
' --' . cfgOptionName(CFGOPT_STANZA) . '=' . $strStanza .
|
||||
' --' . cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE) . '=' . lc(DETAIL);
|
||||
my $strCommand =
|
||||
$self->{strBackRestExe} . ' --config="' . $self->{oHostBackup}->backrestConfig() . '"' . ' --stanza=' . $strStanza .
|
||||
' --log-level-console=' . lc(DETAIL);
|
||||
|
||||
if (defined($iExpireFull))
|
||||
{
|
||||
|
@ -24,12 +24,11 @@ use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
@ -50,6 +49,49 @@ use constant HOST_PATH_REPO => 'repo';
|
||||
use constant HOST_PROTOCOL_TIMEOUT => 10;
|
||||
push @EXPORT, qw(HOST_PROTOCOL_TIMEOUT);
|
||||
|
||||
####################################################################################################################################
|
||||
# Configuration constants
|
||||
####################################################################################################################################
|
||||
use constant CFGDEF_SECTION_GLOBAL => 'global';
|
||||
push @EXPORT, qw(CFGDEF_SECTION_GLOBAL);
|
||||
use constant CFGDEF_SECTION_STANZA => 'stanza';
|
||||
push @EXPORT, qw(CFGDEF_SECTION_STANZA);
|
||||
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_FULL => 'full';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_FULL);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_DIFF);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_INCR => 'incr';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_INCR);
|
||||
|
||||
use constant CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC => 'aes-256-cbc';
|
||||
push @EXPORT, qw(CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
|
||||
use constant STORAGE_CIFS => 'cifs';
|
||||
push @EXPORT, qw(STORAGE_CIFS);
|
||||
use constant STORAGE_S3 => 's3';
|
||||
push @EXPORT, qw(STORAGE_S3);
|
||||
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_DEFAULT);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_IMMEDIATE);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_NAME => 'name';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_NAME);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_PRESERVE => 'preserve';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_PRESERVE);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_STANDBY => 'standby';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_STANDBY);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_TIME => 'time';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_TIME);
|
||||
use constant CFGOPTVAL_RESTORE_TYPE_XID => 'xid';
|
||||
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_XID);
|
||||
|
||||
use constant NONE => 'none';
|
||||
push @EXPORT, qw(NONE);
|
||||
use constant GZ => 'gz';
|
||||
push @EXPORT, qw(GZ);
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
@ -251,8 +293,8 @@ sub backupEnd
|
||||
{
|
||||
if ($strType eq CFGOPTVAL_BACKUP_TYPE_FULL || $self->hardLink())
|
||||
{
|
||||
my $hTablespaceManifest = storageRepo()->manifest(
|
||||
STORAGE_REPO_BACKUP . "/${strBackup}/" . MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGTBLSPC);
|
||||
my $hTablespaceManifest = storageTest()->manifest(
|
||||
$self->repoBackupPath("${strBackup}/" . MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGTBLSPC));
|
||||
|
||||
# Remove . and ..
|
||||
delete($hTablespaceManifest->{'.'});
|
||||
@ -305,19 +347,17 @@ sub backupEnd
|
||||
}
|
||||
# Else there should not be a tablespace directory at all. This is only valid for storage that supports links.
|
||||
elsif (storageRepo()->capability(STORAGE_CAPABILITY_LINK) &&
|
||||
storageTest()->pathExists(
|
||||
storageRepo()->pathGet(
|
||||
STORAGE_REPO_BACKUP . "/${strBackup}/" . MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGTBLSPC)))
|
||||
storageTest()->pathExists($self->repoBackupPath("${strBackup}/" . MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGTBLSPC)))
|
||||
{
|
||||
confess &log(ERROR, 'backup must be full or hard-linked to have ' . DB_PATH_PGTBLSPC . ' directory');
|
||||
}
|
||||
}
|
||||
|
||||
# Check that latest link exists unless repo links are disabled
|
||||
my $strLatestLink = storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . LINK_LATEST);
|
||||
my $strLatestLink = $self->repoBackupPath(LINK_LATEST);
|
||||
my $bLatestLinkExists = storageRepo()->exists($strLatestLink);
|
||||
|
||||
if ((!defined($oParam->{strRepoType}) || $oParam->{strRepoType} eq CFGOPTVAL_REPO_TYPE_POSIX) && $self->hasLink())
|
||||
if ((!defined($oParam->{strRepoType}) || $oParam->{strRepoType} eq STORAGE_POSIX) && $self->hasLink())
|
||||
{
|
||||
my $strLatestLinkDestination = readlink($strLatestLink);
|
||||
|
||||
@ -367,14 +407,12 @@ sub backupEnd
|
||||
if ($self->synthetic() && $bManifestCompare)
|
||||
{
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST), undef,
|
||||
$self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), undef,
|
||||
${storageRepo()->get(
|
||||
storageRepo()->openRead(
|
||||
STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST,
|
||||
{strCipherPass => $self->cipherPassManifest()}))});
|
||||
$self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), {strCipherPass => $self->cipherPassManifest()}))});
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO), undef,
|
||||
${storageRepo->get(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO)});
|
||||
$self->repoBackupPath(FILE_BACKUP_INFO), undef, ${storageRepo->get($self->repoBackupPath(FILE_BACKUP_INFO))});
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,8 +484,7 @@ sub backupCompare
|
||||
${$oExpectedManifest}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_LABEL} = $strBackup;
|
||||
|
||||
my $oActualManifest = new pgBackRest::Manifest(
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST),
|
||||
{strCipherPass => $self->cipherPassManifest()});
|
||||
$self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), {strCipherPass => $self->cipherPassManifest()});
|
||||
|
||||
${$oExpectedManifest}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_START} =
|
||||
$oActualManifest->get(MANIFEST_SECTION_BACKUP, &MANIFEST_KEY_TIMESTAMP_START);
|
||||
@ -478,7 +515,7 @@ sub backupCompare
|
||||
# Determine repo size if compression or encryption is enabled
|
||||
my $strCompressType = $oExpectedManifest->{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS_TYPE};
|
||||
|
||||
if ($strCompressType ne CFGOPTVAL_COMPRESS_TYPE_NONE ||
|
||||
if ($strCompressType ne NONE ||
|
||||
(defined($oExpectedManifest->{&INI_SECTION_CIPHER}) &&
|
||||
defined($oExpectedManifest->{&INI_SECTION_CIPHER}{&INI_KEY_CIPHER_PASS})))
|
||||
{
|
||||
@ -486,9 +523,9 @@ sub backupCompare
|
||||
my $lRepoSize =
|
||||
$oActualManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REFERENCE) ?
|
||||
$oActualManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REPO_SIZE, false) :
|
||||
(storageRepo()->info(STORAGE_REPO_BACKUP .
|
||||
"/${strBackup}/${strFileKey}" .
|
||||
($strCompressType eq CFGOPTVAL_COMPRESS_TYPE_NONE ? '' : ".${strCompressType}")))->{size};
|
||||
(storageRepo()->info(
|
||||
$self->repoBackupPath("${strBackup}/${strFileKey}") .
|
||||
($strCompressType eq NONE ? '' : ".${strCompressType}")))->{size};
|
||||
|
||||
if (defined($lRepoSize) &&
|
||||
$lRepoSize != $oExpectedManifest->{&MANIFEST_SECTION_TARGET_FILE}{$strFileKey}{&MANIFEST_SUBKEY_SIZE})
|
||||
@ -613,7 +650,7 @@ sub backupLast
|
||||
my $self = shift;
|
||||
|
||||
my @stryBackup = storageRepo()->list(
|
||||
STORAGE_REPO_BACKUP, {strExpression => '[0-9]{8}-[0-9]{6}F(_[0-9]{8}-[0-9]{6}(D|I)){0,1}', strSortOrder => 'reverse'});
|
||||
$self->repoBackupPath(), {strExpression => '[0-9]{8}-[0-9]{6}F(_[0-9]{8}-[0-9]{6}(D|I)){0,1}', strSortOrder => 'reverse'});
|
||||
|
||||
if (!defined($stryBackup[0]))
|
||||
{
|
||||
@ -780,13 +817,11 @@ sub stanzaCreate
|
||||
if (defined($self->{oLogTest}) && $self->synthetic())
|
||||
{
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet('backup/' . $self->stanza() . qw{/} . FILE_BACKUP_INFO), undef,
|
||||
${storageRepo()->get(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO)});
|
||||
$self->repoBackupPath(FILE_BACKUP_INFO), undef, ${storageRepo()->get($self->repoBackupPath(FILE_BACKUP_INFO))});
|
||||
}
|
||||
|
||||
# Get the passphrase for accessing the manifest file
|
||||
$self->{strCipherPassManifest} =
|
||||
(new pgBackRest::Backup::Info(storageRepo()->pathGet('backup/' . $self->stanza())))->cipherPassSub();
|
||||
$self->{strCipherPassManifest} = (new pgBackRest::Backup::Info($self->repoBackupPath()))->cipherPassSub();
|
||||
}
|
||||
|
||||
if (storageRepo()->exists('archive/' . $self->stanza() . qw{/} . ARCHIVE_INFO_FILE))
|
||||
@ -795,13 +830,12 @@ sub stanzaCreate
|
||||
if (defined($self->{oLogTest}) && $self->synthetic())
|
||||
{
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet('archive/' . $self->stanza() . qw{/} . ARCHIVE_INFO_FILE), undef,
|
||||
${storageRepo()->get(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE)});
|
||||
$self->repoArchivePath(ARCHIVE_INFO_FILE), undef, ${storageRepo()->get($self->repoArchivePath(ARCHIVE_INFO_FILE))});
|
||||
}
|
||||
|
||||
# Get the passphrase for accessing the archived files
|
||||
$self->{strCipherPassArchive} =
|
||||
(new pgBackRest::Archive::Info(storageRepo()->pathGet('archive/' . $self->stanza())))->cipherPassSub();
|
||||
(new pgBackRest::Archive::Info($self->repoArchivePath()))->cipherPassSub();
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -848,16 +882,14 @@ sub stanzaUpgrade
|
||||
storageRepo()->exists('backup/' . $self->stanza() . qw{/} . FILE_BACKUP_INFO))
|
||||
{
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet('backup/' . $self->stanza() . qw{/} . FILE_BACKUP_INFO), undef,
|
||||
${storageRepo()->get(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO)});
|
||||
$self->repoBackupPath(FILE_BACKUP_INFO), undef, ${storageRepo()->get($self->repoBackupPath(FILE_BACKUP_INFO))});
|
||||
}
|
||||
|
||||
if (defined($self->{oLogTest}) && $self->synthetic() &&
|
||||
storageRepo()->exists('archive/' . $self->stanza() . qw{/} . ARCHIVE_INFO_FILE))
|
||||
{
|
||||
$self->{oLogTest}->supplementalAdd(
|
||||
storageRepo()->pathGet('archive/' . $self->stanza() . qw{/} . ARCHIVE_INFO_FILE), undef,
|
||||
${storageRepo()->get(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE)});
|
||||
$self->repoArchivePath(ARCHIVE_INFO_FILE), undef, ${storageRepo()->get($self->repoArchivePath(ARCHIVE_INFO_FILE))});
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -1009,65 +1041,64 @@ sub configCreate
|
||||
|
||||
# General options
|
||||
# ------------------------------------------------------------------------------------------------------------------------------
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)} = lc(DETAIL);
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_FILE)} = testRunGet()->logLevelTestFile();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_STDERR)} = lc(OFF);
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_SUBPROCESS)} =
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-level-console'} = lc(DETAIL);
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-level-file'} = testRunGet()->logLevelTestFile();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-level-stderr'} = lc(OFF);
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-subprocess'} =
|
||||
testRunGet()->logLevelTestFile() eq lc(OFF) ? 'n' : 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_TIMESTAMP)} = 'n';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_BUFFER_SIZE)} = '64k';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-timestamp'} = 'n';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'buffer-size'} = '64k';
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_PATH)} = $self->logPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOCK_PATH)} = $self->lockPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-path'} = $self->logPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'lock-path'} = $self->lockPath();
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_PROTOCOL_TIMEOUT)} = 60;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_DB_TIMEOUT)} = 45;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'protocol-timeout'} = 60;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'db-timeout'} = 45;
|
||||
|
||||
# Set to make sure that changing the default works and to speed compression for testing
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_COMPRESS_LEVEL)} = 3;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'compress-level'} = 3;
|
||||
|
||||
# Only set network compress level if there is more than one host
|
||||
if ($oHostBackup != $oHostDbMaster)
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_COMPRESS_LEVEL_NETWORK)} = 1;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'compress-level-network'} = 1;
|
||||
}
|
||||
|
||||
if (defined($oParam->{strCompressType}) && $oParam->{strCompressType} ne CFGOPTVAL_COMPRESS_TYPE_GZ)
|
||||
if (defined($oParam->{strCompressType}) && $oParam->{strCompressType} ne 'gz')
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_COMPRESS_TYPE)} = $oParam->{strCompressType};
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'compress-type'} = $oParam->{strCompressType};
|
||||
}
|
||||
|
||||
if ($self->isHostBackup())
|
||||
{
|
||||
if ($self->repoEncrypt())
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_CIPHER_TYPE)} =
|
||||
CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_CIPHER_PASS)} = 'x';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-cipher-type'} = CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-cipher-pass'} = 'x';
|
||||
}
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_PATH)} = $self->repoPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-path'} = $self->repoPath();
|
||||
|
||||
# S3 settings
|
||||
if ($oParam->{bS3})
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_TYPE)} = CFGOPTVAL_REPO_TYPE_S3;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_S3_KEY)} = HOST_S3_ACCESS_KEY;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_S3_KEY_SECRET)} = HOST_S3_ACCESS_SECRET_KEY;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_S3_BUCKET)} = HOST_S3_BUCKET;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_S3_ENDPOINT)} = HOST_S3_ENDPOINT;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_S3_REGION)} = HOST_S3_REGION;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-type'} = STORAGE_S3;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-key'} = HOST_S3_ACCESS_KEY;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-key-secret'} = HOST_S3_ACCESS_SECRET_KEY;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-bucket'} = HOST_S3_BUCKET;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-endpoint'} = HOST_S3_ENDPOINT;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-region'} = HOST_S3_REGION;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-s3-verify-ssl'} = 'n';
|
||||
}
|
||||
|
||||
if (defined($$oParam{bHardlink}) && $$oParam{bHardlink})
|
||||
{
|
||||
$self->{bHardLink} = true;
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_REPO_HARDLINK)} = 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':backup'}{'repo1-s3-hardlink'} = 'y';
|
||||
}
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_ARCHIVE_COPY)} = 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_START_FAST)} = 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':backup'}{'archive-copy'} = 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':backup'}{'start-fast'} = 'y';
|
||||
}
|
||||
|
||||
# Host specific options
|
||||
@ -1087,53 +1118,44 @@ sub configCreate
|
||||
|
||||
if ($self->nameTest(HOST_BACKUP))
|
||||
{
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_HOST)} = $oHostDb1->nameGet();
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_HOST_USER)} = $oHostDb1->userGet();
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_HOST_CMD)} = $oHostDb1->backrestExe();
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_HOST_CONFIG)} = $oHostDb1->backrestConfig();
|
||||
$oParamHash{$strStanza}{'pg1-host'} = $oHostDb1->nameGet();
|
||||
$oParamHash{$strStanza}{'pg1-host-user'} = $oHostDb1->userGet();
|
||||
$oParamHash{$strStanza}{'pg1-host-cmd'} = $oHostDb1->backrestExe();
|
||||
$oParamHash{$strStanza}{'pg1-host-config'} = $oHostDb1->backrestConfig();
|
||||
|
||||
# Port can't be configured for a synthetic host
|
||||
if (!$self->synthetic())
|
||||
{
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_PORT)} = $oHostDb1->pgPort();
|
||||
$oParamHash{$strStanza}{'pg1-port'} = $oHostDb1->pgPort();
|
||||
}
|
||||
}
|
||||
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_PATH)} = $oHostDb1->dbBasePath();
|
||||
$oParamHash{$strStanza}{'pg1-path'} = $oHostDb1->dbBasePath();
|
||||
|
||||
if (defined($oHostDb2))
|
||||
{
|
||||
# Add an invalid replica to simulate more than one replica. A warning should be thrown when a stanza is created and a
|
||||
# valid replica should be chosen.
|
||||
my $iInvalidReplica = 2;
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iInvalidReplica))} = BOGUS;
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_USER, $iInvalidReplica))} =
|
||||
$oHostDb2->userGet();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iInvalidReplica))} =
|
||||
$oHostDb2->backrestExe();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG, $iInvalidReplica))} =
|
||||
$oHostDb2->backrestConfig();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iInvalidReplica))} =
|
||||
$oHostDb2->dbBasePath();
|
||||
$oParamHash{$strStanza}{"pg2-host"} = BOGUS;
|
||||
$oParamHash{$strStanza}{"pg2-host-user"} = $oHostDb2->userGet();
|
||||
$oParamHash{$strStanza}{"pg2-host-cmd"} = $oHostDb2->backrestExe();
|
||||
$oParamHash{$strStanza}{"pg2-host-config"} = $oHostDb2->backrestConfig();
|
||||
$oParamHash{$strStanza}{"pg2-path"} = $oHostDb2->dbBasePath();
|
||||
|
||||
# Set a flag so we know there's a bogus host
|
||||
$self->{bBogusHost} = true;
|
||||
|
||||
# Set a valid replica to the last possible index to ensure skipping indexes does not make a difference.
|
||||
my $iValidReplica = cfgOptionIndexTotal(CFGOPT_PG_PATH);
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iValidReplica))} = $oHostDb2->nameGet();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_USER, $iValidReplica))} =
|
||||
$oHostDb2->userGet();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iValidReplica))} =
|
||||
$oHostDb2->backrestExe();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG, $iValidReplica))} =
|
||||
$oHostDb2->backrestConfig();
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iValidReplica))} = $oHostDb2->dbBasePath();
|
||||
# Set a valid replica to a higher index to ensure skipping indexes does not make a difference
|
||||
$oParamHash{$strStanza}{"pg8-host"} = $oHostDb2->nameGet();
|
||||
$oParamHash{$strStanza}{"pg8-host-user"} = $oHostDb2->userGet();
|
||||
$oParamHash{$strStanza}{"pg8-host-cmd"} = $oHostDb2->backrestExe();
|
||||
$oParamHash{$strStanza}{"pg8-host-config"} = $oHostDb2->backrestConfig();
|
||||
$oParamHash{$strStanza}{"pg8-path"} = $oHostDb2->dbBasePath();
|
||||
|
||||
# Only test explicit ports on the backup server. This is so locally configured ports are also tested.
|
||||
if (!$self->synthetic() && $self->nameTest(HOST_BACKUP))
|
||||
{
|
||||
$oParamHash{$strStanza}{cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_PORT, $iValidReplica))} = $oHostDb2->pgPort();
|
||||
$oParamHash{$strStanza}{"pg8-port"} = $oHostDb2->pgPort();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1141,32 +1163,31 @@ sub configCreate
|
||||
# If this is a database host
|
||||
if ($self->isHostDb())
|
||||
{
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_PATH)} = $self->dbBasePath();
|
||||
$oParamHash{$strStanza}{'pg1-path'} = $self->dbBasePath();
|
||||
|
||||
if (!$self->synthetic())
|
||||
{
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_SOCKET_PATH)} = $self->pgSocketPath();
|
||||
$oParamHash{$strStanza}{cfgOptionName(CFGOPT_PG_PORT)} = $self->pgPort();
|
||||
$oParamHash{$strStanza}{'pg1-socket-path'} = $self->pgSocketPath();
|
||||
$oParamHash{$strStanza}{'pg1-port'} = $self->pgPort();
|
||||
}
|
||||
|
||||
if ($bArchiveAsync)
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':' .
|
||||
cfgCommandName(CFGCMD_ARCHIVE_PUSH)}{cfgOptionName(CFGOPT_ARCHIVE_ASYNC)} = 'y';
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL . ':archive-push'}{'archive-async'} = 'y';
|
||||
}
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_SPOOL_PATH)} = $self->spoolPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'spool-path'} = $self->spoolPath();
|
||||
|
||||
# If the the backup host is remote
|
||||
if (!$self->isHostBackup())
|
||||
{
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_HOST)} = $oHostBackup->nameGet();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_HOST_USER)} = $oHostBackup->userGet();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_HOST_CMD)} = $oHostBackup->backrestExe();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_HOST_CONFIG)} = $oHostBackup->backrestConfig();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-host'} = $oHostBackup->nameGet();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-host-user'} = $oHostBackup->userGet();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-host-cmd'} = $oHostBackup->backrestExe();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'repo1-host-config'} = $oHostBackup->backrestConfig();
|
||||
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_PATH)} = $self->logPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOCK_PATH)} = $self->lockPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'log-path'} = $self->logPath();
|
||||
$oParamHash{&CFGDEF_SECTION_GLOBAL}{'lock-path'} = $self->lockPath();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1244,7 +1265,7 @@ sub manifestMunge
|
||||
{name => 'bCache', default => true},
|
||||
);
|
||||
|
||||
$self->infoMunge(storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST), $hParam, $bCache, true);
|
||||
$self->infoMunge($self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), $hParam, $bCache, true);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
@ -1271,7 +1292,7 @@ sub manifestRestore
|
||||
{name => 'bSave', default => true},
|
||||
);
|
||||
|
||||
$self->infoRestore(storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST), $bSave);
|
||||
$self->infoRestore($self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), $bSave);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
@ -1309,15 +1330,16 @@ sub infoMunge
|
||||
# If the original file content does not exist then load it
|
||||
if (!defined($self->{hInfoFile}{$strFileName}))
|
||||
{
|
||||
$self->{hInfoFile}{$strFileName} = new pgBackRest::Common::Ini($strFileName, {oStorage => storageRepo(),
|
||||
strCipherPass => !$bManifest ? storageRepo()->cipherPassUser() : $self->cipherPassManifest()});
|
||||
$self->{hInfoFile}{$strFileName} = new pgBackRest::Common::Ini(
|
||||
storageRepo(), $strFileName,
|
||||
{strCipherPass => !$bManifest ? undef : $self->cipherPassManifest()});
|
||||
}
|
||||
|
||||
# Make a copy of the original file contents
|
||||
my $oMungeIni = new pgBackRest::Common::Ini(
|
||||
$strFileName,
|
||||
{bLoad => false, strContent => iniRender($self->{hInfoFile}{$strFileName}->{oContent}), oStorage => storageRepo(),
|
||||
strCipherPass => !$bManifest ? storageRepo()->cipherPassUser() : $self->cipherPassManifest()});
|
||||
storageRepo(), $strFileName,
|
||||
{bLoad => false, strContent => iniRender($self->{hInfoFile}{$strFileName}->{oContent}),
|
||||
strCipherPass => !$bManifest ? undef : $self->cipherPassManifest()});
|
||||
|
||||
# Load params
|
||||
foreach my $strSection (keys(%{$hParam}))
|
||||
@ -1438,7 +1460,7 @@ sub configRecovery
|
||||
|
||||
if (@stryRecoveryOption)
|
||||
{
|
||||
$oConfig->{$strStanza}{cfgOptionName(CFGOPT_RECOVERY_OPTION)} = \@stryRecoveryOption;
|
||||
$oConfig->{$strStanza}{'recovery-option'} = \@stryRecoveryOption;
|
||||
}
|
||||
|
||||
# Save db config file
|
||||
@ -1472,7 +1494,7 @@ sub configRemap
|
||||
}
|
||||
|
||||
# Rewrite recovery section
|
||||
delete($oConfig->{"${strStanza}:restore"}{cfgOptionName(CFGOPT_TABLESPACE_MAP)});
|
||||
delete($oConfig->{"${strStanza}:restore"}{'tablespace-map'});
|
||||
my @stryTablespaceMap;
|
||||
|
||||
foreach my $strRemap (sort(keys(%$oRemapHashRef)))
|
||||
@ -1481,13 +1503,13 @@ sub configRemap
|
||||
|
||||
if ($strRemap eq MANIFEST_TARGET_PGDATA)
|
||||
{
|
||||
$oConfig->{$strStanza}{cfgOptionName(CFGOPT_PG_PATH)} = $strRemapPath;
|
||||
$oConfig->{$strStanza}{'pg1-path'} = $strRemapPath;
|
||||
|
||||
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{&MANIFEST_TARGET_PGDATA}{&MANIFEST_SUBKEY_PATH} = $strRemapPath;
|
||||
|
||||
if (defined($oHostBackup))
|
||||
{
|
||||
$oRemoteConfig->{$strStanza}{cfgOptionName(CFGOPT_PG_PATH)} = $strRemapPath;
|
||||
$oRemoteConfig->{$strStanza}{'pg1-path'} = $strRemapPath;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1502,7 +1524,7 @@ sub configRemap
|
||||
|
||||
if (@stryTablespaceMap)
|
||||
{
|
||||
$oConfig->{"${strStanza}:restore"}{cfgOptionName(CFGOPT_TABLESPACE_MAP)} = \@stryTablespaceMap;
|
||||
$oConfig->{"${strStanza}:restore"}{'tablespace-map'} = \@stryTablespaceMap;
|
||||
}
|
||||
|
||||
# Save db config file
|
||||
@ -1577,14 +1599,13 @@ sub restore
|
||||
$strComment = 'restore' .
|
||||
($bDelta ? ' delta' : '') .
|
||||
($bForce ? ', force' : '') .
|
||||
($strBackup ne cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET) ? ", backup '${strBackup}'" : '') .
|
||||
($strBackup ne 'latest' ? ", backup '${strBackup}'" : '') .
|
||||
# This does not output 'default' for synthetic tests to make expect logs match up (may change later)
|
||||
($strType ? ", type '${strType}'" : (defined($rhExpectedManifest) ? '' : ", type 'default'")) .
|
||||
($strTarget ? ", target '${strTarget}'" : '') .
|
||||
($strTargetTimeline ? ", timeline '${strTargetTimeline}'" : '') .
|
||||
($bTargetExclusive ? ', exclusive' : '') .
|
||||
(defined($strTargetAction) && $strTargetAction ne cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_TARGET_ACTION)
|
||||
? ', ' . cfgOptionName(CFGOPT_TARGET_ACTION) . "=${strTargetAction}" : '') .
|
||||
(defined($strTargetAction) && $strTargetAction ne 'pause' ? ", target-action=${strTargetAction}" : '') .
|
||||
(defined($rhRemapHash) ? ', remap' : '') .
|
||||
(defined($iExpectedExitStatus) ? ", expect exit ${iExpectedExitStatus}" : '') .
|
||||
(defined($strComment) ? " - ${strComment}" : '') .
|
||||
@ -1602,7 +1623,7 @@ sub restore
|
||||
# - which should be the backup passed as strBackupExpected. If it is not defined, then set it based on the strBackup passed.
|
||||
if (!defined($strBackupExpected))
|
||||
{
|
||||
$strBackupExpected = $strBackup eq cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET) ? $oHostBackup->backupLast() :
|
||||
$strBackupExpected = $strBackup eq 'latest' ? $oHostBackup->backupLast() :
|
||||
$strBackup;
|
||||
}
|
||||
|
||||
@ -1610,9 +1631,7 @@ sub restore
|
||||
{
|
||||
# Load the manifest from the backup expected to be chosen/processed by restore
|
||||
my $oExpectedManifest = new pgBackRest::Manifest(
|
||||
storageRepo()->pathGet(
|
||||
STORAGE_REPO_BACKUP . qw{/} . $strBackupExpected. qw{/} .
|
||||
FILE_MANIFEST),
|
||||
$self->repoBackupPath($strBackupExpected . qw{/} . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
|
||||
$rhExpectedManifest = $oExpectedManifest->{oContent};
|
||||
@ -1672,7 +1691,7 @@ sub restore
|
||||
' --config=' . $self->backrestConfig() .
|
||||
($bDelta ? ' --delta' : '') .
|
||||
($bForce ? ' --force' : '') .
|
||||
($strBackup ne cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET) ? " --set=${strBackup}" : '') .
|
||||
($strBackup ne 'latest' ? " --set=${strBackup}" : '') .
|
||||
(defined($strOptionalParam) ? " ${strOptionalParam} " : '') .
|
||||
(defined($strType) && $strType ne CFGOPTVAL_RESTORE_TYPE_DEFAULT ? " --type=${strType}" : '') .
|
||||
(defined($strTarget) ? " --target=\"${strTarget}\"" : '') .
|
||||
@ -1680,8 +1699,7 @@ sub restore
|
||||
($bTargetExclusive ? ' --target-exclusive' : '') .
|
||||
(defined($strLinkMap) ? $strLinkMap : '') .
|
||||
($self->synthetic() ? '' : ' --link-all') .
|
||||
(defined($strTargetAction) && $strTargetAction ne cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_TARGET_ACTION)
|
||||
? ' --' . cfgOptionName(CFGOPT_TARGET_ACTION) . "=${strTargetAction}" : '') .
|
||||
(defined($strTargetAction) && $strTargetAction ne 'pause' ? " --target-action=${strTargetAction}" : '') .
|
||||
' --stanza=' . $self->stanza() . ' restore',
|
||||
{strComment => $strComment, iExpectedExitStatus => $iExpectedExitStatus, oLogTest => $self->{oLogTest},
|
||||
bLogOutput => $self->synthetic()},
|
||||
@ -1723,9 +1741,8 @@ sub restoreCompare
|
||||
{
|
||||
my $oExpectedManifest =
|
||||
new pgBackRest::Manifest(
|
||||
storageRepo()->pathGet(
|
||||
STORAGE_REPO_BACKUP . qw{/} . ($strBackup eq 'latest' ? $oHostBackup->backupLast() : $strBackup) .
|
||||
'/'. FILE_MANIFEST),
|
||||
$self->repoBackupPath(
|
||||
($strBackup eq 'latest' ? $oHostBackup->backupLast() : $strBackup) . '/' . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
|
||||
# Get the --delta option from the backup manifest so the actual manifest can be built the same way for comparison
|
||||
@ -1734,9 +1751,8 @@ sub restoreCompare
|
||||
|
||||
$oLastManifest =
|
||||
new pgBackRest::Manifest(
|
||||
storageRepo()->pathGet(
|
||||
STORAGE_REPO_BACKUP . qw{/} .
|
||||
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} . qw{/} . FILE_MANIFEST),
|
||||
$self->repoBackupPath(
|
||||
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} . qw{/} . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
}
|
||||
|
||||
@ -2027,6 +2043,20 @@ sub restoreCompare
|
||||
storageTest()->remove("${strTestPath}/actual.manifest");
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get repo backup/archive path
|
||||
####################################################################################################################################
|
||||
sub repoSubPath
|
||||
{
|
||||
my $self = shift;
|
||||
my $strSubPath = shift;
|
||||
my $strPath = shift;
|
||||
|
||||
return
|
||||
($self->{strRepoPath} eq '/' ? '' : $self->{strRepoPath}) . "/${strSubPath}/" . $self->stanza() .
|
||||
(defined($strPath) ? "/${strPath}" : '');
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
@ -2036,13 +2066,15 @@ sub backrestExe {return testRunGet()->backrestExe()}
|
||||
sub bogusHost {return shift->{bBogusHost}}
|
||||
sub hardLink {return shift->{bHardLink}}
|
||||
sub hasLink {storageRepo()->capability(STORAGE_CAPABILITY_LINK)}
|
||||
sub isFS {storageRepo()->type() ne STORAGE_S3}
|
||||
sub isFS {storageRepo()->type() ne STORAGE_OBJECT}
|
||||
sub isHostBackup {my $self = shift; return $self->backupDestination() eq $self->nameGet()}
|
||||
sub isHostDbMaster {return shift->nameGet() eq HOST_DB_MASTER}
|
||||
sub isHostDbStandby {return shift->nameGet() eq HOST_DB_STANDBY}
|
||||
sub isHostDb {my $self = shift; return $self->isHostDbMaster() || $self->isHostDbStandby()}
|
||||
sub lockPath {return shift->{strLockPath}}
|
||||
sub logPath {return shift->{strLogPath}}
|
||||
sub repoArchivePath {return shift->repoSubPath('archive', shift)}
|
||||
sub repoBackupPath {return shift->repoSubPath('backup', shift)}
|
||||
sub repoPath {return shift->{strRepoPath}}
|
||||
sub repoEncrypt {return shift->{bRepoEncrypt}}
|
||||
sub stanza {return testRunGet()->stanza()}
|
||||
|
@ -17,7 +17,7 @@ use Exporter qw(import);
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
|
@ -21,10 +21,9 @@ use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
|
@ -23,7 +23,7 @@ use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
|
@ -22,7 +22,7 @@ use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
|
@ -22,9 +22,8 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
|
@ -2,7 +2,7 @@
|
||||
# FullCommonTest.pm - Common code for backup tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Env::HostEnvTest;
|
||||
use parent 'pgBackRestTest::Env::ConfigEnvTest';
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
@ -18,9 +18,9 @@ use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Common;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
@ -43,11 +43,6 @@ use constant ENCRYPTION_KEY_MANIFEST => 'manifest';
|
||||
use constant ENCRYPTION_KEY_BACKUPSET => 'backupset';
|
||||
push @EXPORT, qw(ENCRYPTION_KEY_BACKUPSET);
|
||||
|
||||
use constant NONE => CFGOPTVAL_COMPRESS_TYPE_NONE;
|
||||
push @EXPORT, qw(NONE);
|
||||
use constant GZ => CFGOPTVAL_COMPRESS_TYPE_GZ;
|
||||
push @EXPORT, qw(GZ);
|
||||
|
||||
####################################################################################################################################
|
||||
# setup
|
||||
####################################################################################################################################
|
||||
@ -151,6 +146,13 @@ sub setup
|
||||
$oHostBackup = $strBackupDestination eq HOST_DB_MASTER ? $oHostDbMaster : $oHostDbStandby;
|
||||
}
|
||||
|
||||
storageRepoCommandSet(
|
||||
$self->backrestExeHelper() .
|
||||
' --config=' . $oHostBackup->backrestConfig() . ' --stanza=' . $self->stanza() . ' --log-level-console=off' .
|
||||
' --log-level-stderr=error' .
|
||||
($oConfigParam->{bS3} ? ' --no-repo1-s3-verify-tls --repo1-s3-host=' . $oHostS3->ipGet() : ''),
|
||||
$oConfigParam->{bS3} ? STORAGE_OBJECT : STORAGE_POSIX);
|
||||
|
||||
# Create db-standby config
|
||||
if (defined($oHostDbStandby))
|
||||
{
|
||||
@ -161,37 +163,10 @@ sub setup
|
||||
bArchiveAsync => $$oConfigParam{bArchiveAsync}});
|
||||
}
|
||||
|
||||
# Set options needed for storage helper
|
||||
$self->optionTestSet(CFGOPT_PG_PATH, $oHostDbMaster->dbBasePath());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $oHostBackup->repoPath());
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
|
||||
# Configure the repo to be encrypted if required
|
||||
if ($bRepoEncrypt)
|
||||
{
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
}
|
||||
|
||||
# Set S3 options
|
||||
if (defined($oHostS3))
|
||||
{
|
||||
$self->optionTestSet(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY, HOST_S3_ACCESS_KEY);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY_SECRET, HOST_S3_ACCESS_SECRET_KEY);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_BUCKET, HOST_S3_BUCKET);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_ENDPOINT, HOST_S3_ENDPOINT);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_REGION, HOST_S3_REGION);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_HOST, $oHostS3->ipGet());
|
||||
$self->optionTestSetBool(CFGOPT_REPO_S3_VERIFY_TLS, false);
|
||||
}
|
||||
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Create S3 bucket
|
||||
if (defined($oHostS3))
|
||||
{
|
||||
storageRepo()->{oStorageC}->bucketCreate();
|
||||
storageRepo()->create();
|
||||
}
|
||||
|
||||
return $oHostDbMaster, $oHostDbStandby, $oHostBackup, $oHostS3;
|
||||
|
@ -21,10 +21,8 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
@ -93,12 +91,12 @@ sub run
|
||||
# without slowing down the other tests too much.
|
||||
if ($bS3)
|
||||
{
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_PROCESS_MAX) => 2}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_PROCESS_MAX) => 2}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'process-max' => 2}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {'process-max' => 2}});
|
||||
|
||||
# Reduce log level to warn because parallel tests do not create deterministic logs
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE) => lc(WARN)}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE) => lc(WARN)}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'log-level-console' => lc(WARN)}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {'log-level-console' => lc(WARN)}});
|
||||
}
|
||||
|
||||
# Get base time
|
||||
@ -115,7 +113,7 @@ sub run
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_BUFFER_SIZE} = 16384;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_CHECKSUM_PAGE} = JSON::PP::true;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS} = JSON::PP::false;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS_TYPE} = CFGOPTVAL_COMPRESS_TYPE_NONE;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS_TYPE} = NONE;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS_LEVEL} = 3;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS_LEVEL_NETWORK} = $bRemote ? 1 : 3;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_HARDLINK} = JSON::PP::false;
|
||||
@ -306,7 +304,7 @@ sub run
|
||||
my $strTestPoint;
|
||||
|
||||
# Create the archive info file
|
||||
$oHostBackup->stanzaCreate('create required data for stanza', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('create required data for stanza', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Create a link to postgresql.conf
|
||||
storageTest()->pathCreate($oHostDbMaster->dbPath() . '/pg_config', {strMode => '0700', bCreateParent => true});
|
||||
@ -343,14 +341,13 @@ sub run
|
||||
{oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => $strOptionalParam .
|
||||
# Pass ssh path to make sure it is used
|
||||
($bRemote ? ' --' . cfgOptionName(CFGOPT_CMD_SSH) . '=/usr/bin/ssh' : '') .
|
||||
($bRemote ? ' --cmd-ssh=/usr/bin/ssh' : '') .
|
||||
# Pass bogus ssh port to make sure it is passed through the protocol layer (it won't be used)
|
||||
($bRemote ? ' --' . cfgOptionName(CFGOPT_PG_PORT) . '=9999' : '') .
|
||||
($bRemote ? ' --pg1-port=9999' : '') .
|
||||
# Pass bogus socket path to make sure it is passed through the protocol layer (it won't be used)
|
||||
($bRemote ? ' --' . cfgOptionName(CFGOPT_PG_SOCKET_PATH) . '=/test_socket_path' : '') .
|
||||
' --' . cfgOptionName(CFGOPT_BUFFER_SIZE) . '=16384 --' . cfgOptionName(CFGOPT_CHECKSUM_PAGE) .
|
||||
' --' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1',
|
||||
strRepoType => $bS3 ? undef : CFGOPTVAL_REPO_TYPE_CIFS, strTest => $strTestPoint, fTestDelay => 0});
|
||||
($bRemote ? ' --pg1-socket-path=/test_socket_path' : '') .
|
||||
' --buffer-size=16384 --checksum-page --process-max=1',
|
||||
strRepoType => $bS3 ? undef : STORAGE_CIFS, strTest => $strTestPoint, fTestDelay => 0});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_BUFFER_SIZE} = 65536;
|
||||
@ -409,13 +406,13 @@ sub run
|
||||
|
||||
# Resume by copying the valid full backup over the last aborted full backup if it exists, or by creating a new path
|
||||
my $strResumeBackup = (storageRepo()->list(
|
||||
STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse'}))[0];
|
||||
$oHostBackup->repoBackupPath(), {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse'}))[0];
|
||||
my $strResumeLabel = $strResumeBackup ne $strFullBackup ?
|
||||
$strResumeBackup : backupLabel(storageRepo(), $strType, undef, time());
|
||||
my $strResumePath = storageRepo()->pathGet('backup/' . $self->stanza() . '/' . $strResumeLabel);
|
||||
$strResumeBackup : backupLabel(storageRepo(), $oHostBackup->repoBackupPath(), $strType, undef, time());
|
||||
my $strResumePath = $oHostBackup->repoBackupPath($strResumeLabel);
|
||||
|
||||
forceStorageRemove(storageRepo(), $strResumePath, {bRecurse => true});
|
||||
forceStorageMove(storageRepo(), 'backup/' . $self->stanza() . "/${strFullBackup}", $strResumePath);
|
||||
forceStorageMove(storageRepo(), $oHostBackup->repoBackupPath($strFullBackup), $strResumePath);
|
||||
|
||||
# Set ownership on base directory to bogus values
|
||||
if (!$bRemote)
|
||||
@ -464,7 +461,7 @@ sub run
|
||||
# Create files to be excluded with the --exclude option
|
||||
$oHostBackup->configUpdate(
|
||||
{(CFGDEF_SECTION_GLOBAL . ':backup') =>
|
||||
{cfgOptionName(CFGOPT_EXCLUDE) => ['postgresql.auto.conf', 'pg_log/', 'pg_log2', 'apipe']}});
|
||||
{'exclude' => ['postgresql.auto.conf', 'pg_log/', 'pg_log2', 'apipe']}});
|
||||
$oHostDbMaster->dbLinkCreate(\%oManifest, MANIFEST_TARGET_PGDATA, 'postgresql.auto.conf',
|
||||
'../pg_config/postgresql.conf', true);
|
||||
$oHostDbMaster->manifestPathCreate(\%oManifest, MANIFEST_TARGET_PGDATA, 'pg_log');
|
||||
@ -476,7 +473,7 @@ sub run
|
||||
$strFullBackup = $oHostBackup->backup(
|
||||
$strType, 'resume',
|
||||
{oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--force --' . cfgOptionName(CFGOPT_CHECKSUM_PAGE) . ($bDeltaBackup ? ' --delta' : '')});
|
||||
strOptionalParam => '--force --checksum-page' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
|
||||
# Remove postmaster.pid so restore will succeed (the rest will be cleaned up by the delta)
|
||||
storageTest->remove($oHostDbMaster->dbBasePath() . '/' . DB_FILE_POSTMASTERPID);
|
||||
@ -523,7 +520,7 @@ sub run
|
||||
strOptionalParam => ' --link-all' . ($bRemote ? ' --cmd-ssh=/usr/bin/ssh' : '')});
|
||||
|
||||
# Remove excludes now that they just create noise in the log
|
||||
$oHostBackup->configUpdate({(CFGDEF_SECTION_GLOBAL . ':backup') => {cfgOptionName(CFGOPT_EXCLUDE) => []}});
|
||||
$oHostBackup->configUpdate({(CFGDEF_SECTION_GLOBAL . ':backup') => {'exclude' => []}});
|
||||
|
||||
# Run again to fix permissions
|
||||
if (!$bRemote)
|
||||
@ -624,11 +621,11 @@ sub run
|
||||
$strType = CFGOPTVAL_BACKUP_TYPE_INCR;
|
||||
|
||||
# Create resumable backup from last backup
|
||||
$strResumeLabel = backupLabel(storageRepo(), $strType, substr($strBackup, 0, 16), time());
|
||||
$strResumePath = storageRepo()->pathGet('backup/' . $self->stanza() . '/' . $strResumeLabel);
|
||||
$strResumeLabel = backupLabel(storageRepo(), $oHostBackup->repoBackupPath(), $strType, substr($strBackup, 0, 16), time());
|
||||
$strResumePath = $oHostBackup->repoBackupPath($strResumeLabel);
|
||||
|
||||
forceStorageRemove(storageRepo(), $strResumePath);
|
||||
forceStorageMove(storageRepo(), 'backup/' . $self->stanza() . "/${strBackup}", $strResumePath);
|
||||
forceStorageMove(storageRepo(), $oHostBackup->repoBackupPath($strBackup), $strResumePath);
|
||||
|
||||
# Munge manifest so the resumed file in the repo appears to be bad
|
||||
if ($bEncrypt || $bRemote)
|
||||
@ -698,7 +695,7 @@ sub run
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'resume and add tablespace 2',
|
||||
{oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
strOptionalParam => '--process-max=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
|
||||
@ -719,9 +716,7 @@ sub run
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'drop tablespace 11',
|
||||
{oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1' .
|
||||
($bDeltaBackup ? ' --delta' : '')});
|
||||
{oExpectedManifest => \%oManifest, strOptionalParam => '--process-max=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
|
||||
@ -776,7 +771,7 @@ sub run
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'add files and remove tablespace 2',
|
||||
{oExpectedManifest => \%oManifest, strOptionalParam => '--' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1'});
|
||||
{oExpectedManifest => \%oManifest, strOptionalParam => '--process-max=1'});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
|
||||
@ -801,7 +796,7 @@ sub run
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'updates since last full', {oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
strOptionalParam => '--process-max=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
|
||||
@ -814,17 +809,17 @@ sub run
|
||||
# Enable compression to ensure a warning is raised (reset when gz to avoid log churn since it is the default)
|
||||
if ($strCompressType eq GZ)
|
||||
{
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_COMPRESS_TYPE) => undef}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'compress-type' => undef}});
|
||||
}
|
||||
else
|
||||
{
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_COMPRESS_TYPE) => $strCompressType}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'compress-type' => $strCompressType}});
|
||||
}
|
||||
|
||||
# Enable hardlinks (except for s3) to ensure a warning is raised
|
||||
if (!$bS3)
|
||||
{
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_REPO_HARDLINK) => 'y'}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'repo1-hardlink' => 'y'}});
|
||||
}
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = 1;
|
||||
@ -840,7 +835,7 @@ sub run
|
||||
$oHostBackup->backup(
|
||||
$strType, 'remove files',
|
||||
{oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--' . cfgOptionName(CFGOPT_PROCESS_MAX) . '=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
strOptionalParam => '--process-max=1' . ($bDeltaBackup ? ' --delta' : '')});
|
||||
|
||||
$oManifest{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_PROCESS_MAX} = $bS3 ? 2 : 1;
|
||||
|
||||
@ -889,8 +884,7 @@ sub run
|
||||
$strFullBackup, {&MANIFEST_SECTION_BACKUP_OPTION => {&MANIFEST_KEY_CHECKSUM_PAGE => undef}}, false);
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'add file',
|
||||
{oExpectedManifest => \%oManifest, strOptionalParam => '--' . cfgOptionName(CFGOPT_CHECKSUM_PAGE)});
|
||||
$strType, 'add file', {oExpectedManifest => \%oManifest, strOptionalParam => '--checksum-page'});
|
||||
|
||||
# Selective Restore
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
@ -906,7 +900,7 @@ sub run
|
||||
{&MANIFEST_SUBKEY_CHECKSUM});
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
'selective restore 16384', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'selective restore 16384', 'latest',
|
||||
{rhExpectedManifest => \%oManifest, rhRemapHash => \%oRemapHash, bDelta => true,
|
||||
strOptionalParam => '--db-include=16384'});
|
||||
|
||||
@ -924,7 +918,7 @@ sub run
|
||||
delete($oManifest{&MANIFEST_SECTION_TARGET_FILE}{'pg_data/base/16384/17000'}{&MANIFEST_SUBKEY_CHECKSUM});
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
'selective restore 32768', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'selective restore 32768', 'latest',
|
||||
{rhExpectedManifest => \%oManifest, rhRemapHash => \%oRemapHash, bDelta => true,
|
||||
strOptionalParam => '--db-include=32768'});
|
||||
|
||||
@ -932,12 +926,12 @@ sub run
|
||||
'7579ada0808d7f98087a0a586d0df9de009cdc33';
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
'error on invalid id', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'error on invalid id', 'latest',
|
||||
{rhExpectedManifest => \%oManifest, rhRemapHash => \%oRemapHash, bDelta => true,
|
||||
iExpectedExitStatus => ERROR_DB_MISSING, strOptionalParam => '--log-level-console=warn --db-include=7777'});
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
'error on system id', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'error on system id', 'latest',
|
||||
{rhExpectedManifest => \%oManifest, rhRemapHash => \%oRemapHash, bDelta => true,
|
||||
iExpectedExitStatus => ERROR_DB_INVALID, strOptionalParam => '--log-level-console=warn --db-include=1'});
|
||||
|
||||
@ -952,7 +946,7 @@ sub run
|
||||
delete($oRemapHash{&MANIFEST_TARGET_PGTBLSPC . '/2'});
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
'no tablespace remap', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'no tablespace remap', 'latest',
|
||||
{rhExpectedManifest => \%oManifest, rhRemapHash => \%oRemapHash, bTablespace => false,
|
||||
strOptionalParam => '--tablespace-map-all=../../tablespace'});
|
||||
|
||||
@ -965,8 +959,9 @@ sub run
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
if (!$bRemote && !$bS3)
|
||||
{
|
||||
executeTest('ls -1Rtr ' . storageRepo()->pathGet('backup/' . $self->stanza() . '/' . PATH_BACKUP_HISTORY),
|
||||
{oLogTest => $self->expect(), bRemote => $bRemote});
|
||||
executeTest(
|
||||
'ls -1Rtr ' . $oHostBackup->repoBackupPath(PATH_BACKUP_HISTORY),
|
||||
{oLogTest => $self->expect(), bRemote => $bRemote});
|
||||
}
|
||||
|
||||
# Test backup from standby warning that standby not configured so option reset
|
||||
@ -975,7 +970,7 @@ sub run
|
||||
{
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'option backup-standby reset - backup performed from master', {oExpectedManifest => \%oManifest,
|
||||
strOptionalParam => '--log-level-console=info --' . cfgOptionName(CFGOPT_BACKUP_STANDBY)});
|
||||
strOptionalParam => '--log-level-console=info --backup-standby'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,11 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
@ -86,7 +85,7 @@ sub run
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_94);
|
||||
|
||||
# Create the archive info file
|
||||
$oHostBackup->stanzaCreate('create required data for stanza', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('create required data for stanza', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Push a WAL segment
|
||||
&log(INFO, ' push first WAL');
|
||||
@ -96,7 +95,7 @@ sub run
|
||||
if ($iError == 0)
|
||||
{
|
||||
$oHostBackup->infoMunge(
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
||||
$oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE),
|
||||
{&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'},
|
||||
&INFO_ARCHIVE_SECTION_DB_HISTORY => {1 => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}});
|
||||
}
|
||||
@ -120,13 +119,12 @@ sub run
|
||||
# Fix the database version
|
||||
if ($iError == 0)
|
||||
{
|
||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE));
|
||||
$oHostBackup->infoRestore($oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE));
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageRepo()->list(
|
||||
STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_94 . '-1/0000000100000001')},
|
||||
sub {storageRepo()->list($oHostBackup->repoArchivePath(PG_VERSION_94 . '-1/0000000100000001'))},
|
||||
"000000010000000100000001-${strWalHash}${strCompressExt}",
|
||||
'segment 2-4 not pushed', {iWaitSeconds => 5});
|
||||
|
||||
@ -134,8 +132,7 @@ sub run
|
||||
$oHostDbMaster->archivePush($strWalPath, $strWalTestFile, 5);
|
||||
|
||||
$self->testResult(
|
||||
sub {storageRepo()->list(
|
||||
STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_94 . '-1/0000000100000001')},
|
||||
sub {storageRepo()->list($oHostBackup->repoArchivePath(PG_VERSION_94 . '-1/0000000100000001'))},
|
||||
"(000000010000000100000001-${strWalHash}${strCompressExt}, " .
|
||||
"000000010000000100000005-${strWalHash}${strCompressExt})",
|
||||
'segment 5 is pushed', {iWaitSeconds => 5});
|
||||
|
@ -20,11 +20,10 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
@ -38,13 +37,15 @@ use pgBackRestTest::Common::VmTest;
|
||||
sub archiveCheck
|
||||
{
|
||||
my $self = shift;
|
||||
my $oHostBackup = shift;
|
||||
my $strArchiveFile = shift;
|
||||
my $strArchiveChecksum = shift;
|
||||
my $strCompressType = shift;
|
||||
my $strSpoolPath = shift;
|
||||
|
||||
# Build the archive name to check for at the destination
|
||||
my $strArchiveCheck = PG_VERSION_94 . "-1/${strArchiveFile}-${strArchiveChecksum}";
|
||||
my $strArchiveCheck = $oHostBackup->repoArchivePath(
|
||||
PG_VERSION_94 . "-1/" . substr($strArchiveFile, 0, 16) . "/${strArchiveFile}-${strArchiveChecksum}");
|
||||
|
||||
if (defined($strCompressType))
|
||||
{
|
||||
@ -56,13 +57,13 @@ sub archiveCheck
|
||||
|
||||
do
|
||||
{
|
||||
$bFound = storageRepo()->exists(STORAGE_REPO_ARCHIVE . "/${strArchiveCheck}");
|
||||
$bFound = storageRepo()->exists($strArchiveCheck);
|
||||
}
|
||||
while (!$bFound && waitMore($oWait));
|
||||
|
||||
if (!$bFound)
|
||||
{
|
||||
confess 'unable to find ' . storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/${strArchiveCheck}");
|
||||
confess "unable to find ${strArchiveCheck}";
|
||||
}
|
||||
|
||||
if (defined($strSpoolPath))
|
||||
@ -108,7 +109,7 @@ sub run
|
||||
true, $self->expect(), {bHostBackup => $bRemote, bS3 => $bS3, bRepoEncrypt => $bEncrypt, strCompressType => NONE});
|
||||
|
||||
# Reduce console logging to detail
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE) => lc(DETAIL)}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {'log-level-console' => lc(DETAIL)}});
|
||||
|
||||
# Create the wal path
|
||||
my $strWalPath = $oHostDbMaster->dbBasePath() . '/pg_xlog';
|
||||
@ -121,11 +122,11 @@ sub run
|
||||
# Create archive-push command
|
||||
my $strCommandPush =
|
||||
$oHostDbMaster->backrestExe() . ' --config=' . $oHostDbMaster->backrestConfig() . ' --stanza=' . $self->stanza() .
|
||||
' ' . cfgCommandName(CFGCMD_ARCHIVE_PUSH);
|
||||
' archive-push';
|
||||
|
||||
my $strCommandGet =
|
||||
$oHostDbMaster->backrestExe() . ' --config=' . $oHostDbMaster->backrestConfig() . ' --stanza=' . $self->stanza() .
|
||||
' ' . cfgCommandName(CFGCMD_ARCHIVE_GET);
|
||||
' archive-get';
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' archive.info missing');
|
||||
@ -142,9 +143,7 @@ sub run
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, oLogTest => $self->expect()});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaCreate(
|
||||
'stanza create',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('stanza create', {strOptionalParam => '--no-online'});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' push first WAL');
|
||||
@ -160,7 +159,7 @@ sub run
|
||||
push(@stryExpectedWAL, "${strSourceFile}-${strArchiveChecksum}.${strCompressType}");
|
||||
|
||||
# Test that the WAL was pushed
|
||||
$self->archiveCheck($strSourceFile, $strArchiveChecksum, $strCompressType);
|
||||
$self->archiveCheck($oHostBackup, $strSourceFile, $strArchiveChecksum, $strCompressType);
|
||||
|
||||
# Remove from archive_status
|
||||
storageTest()->remove("${strWalPath}/archive_status/${strSourceFile}.ready");
|
||||
@ -245,7 +244,7 @@ sub run
|
||||
}
|
||||
|
||||
# Test that the WAL was pushed
|
||||
$self->archiveCheck($strSourceFile, $strArchiveChecksum, $strCompressType, $oHostDbMaster->spoolPath());
|
||||
$self->archiveCheck($oHostBackup, $strSourceFile, $strArchiveChecksum, $strCompressType, $oHostDbMaster->spoolPath());
|
||||
|
||||
# Remove from archive_status
|
||||
storageTest()->remove("${strWalPath}/archive_status/${strSourceFile}.ready");
|
||||
@ -263,7 +262,7 @@ sub run
|
||||
"${strCommandPush} --archive-async ${strWalPath}/00000002.history",
|
||||
{oLogTest => $self->expect()});
|
||||
|
||||
if (!storageRepo()->exists(STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_94 . '-1/00000002.history'))
|
||||
if (!storageRepo()->exists($oHostBackup->repoArchivePath(PG_VERSION_94 . '-1/00000002.history')))
|
||||
{
|
||||
confess 'unable to find history file in archive';
|
||||
}
|
||||
@ -275,7 +274,7 @@ sub run
|
||||
|
||||
# db section and corresponding history munged
|
||||
$oHostBackup->infoMunge(
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
||||
$oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE),
|
||||
{&INFO_ARCHIVE_SECTION_DB_HISTORY => {'1' => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}});
|
||||
|
||||
$oHostDbMaster->executeSimple(
|
||||
@ -283,13 +282,13 @@ sub run
|
||||
{iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH, oLogTest => $self->expect()});
|
||||
|
||||
# Restore the file to its original condition
|
||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE));
|
||||
$oHostBackup->infoRestore($oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' db system-id mismatch error');
|
||||
|
||||
$oHostBackup->infoMunge(
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
||||
$oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE),
|
||||
{&INFO_ARCHIVE_SECTION_DB => {&INFO_BACKUP_KEY_SYSTEM_ID => 5000900090001855000},
|
||||
&INFO_ARCHIVE_SECTION_DB_HISTORY => {'1' => {&INFO_ARCHIVE_KEY_DB_ID => 5000900090001855000}}});
|
||||
|
||||
@ -302,7 +301,7 @@ sub run
|
||||
{iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH, oLogTest => $self->expect()});
|
||||
|
||||
# Restore the file to its original condition
|
||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE));
|
||||
$oHostBackup->infoRestore($oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' stop');
|
||||
@ -384,7 +383,7 @@ sub run
|
||||
$oHostDbMaster->executeSimple(
|
||||
$strCommandPush . " ${strWalPath}/${strSourceFile}.partial",
|
||||
{oLogTest => $self->expect()});
|
||||
$self->archiveCheck("${strSourceFile}.partial", $strArchiveChecksum);
|
||||
$self->archiveCheck($oHostBackup, "${strSourceFile}.partial", $strArchiveChecksum);
|
||||
|
||||
push(@stryExpectedWAL, "${strSourceFile}.partial-${strArchiveChecksum}");
|
||||
|
||||
@ -393,7 +392,7 @@ sub run
|
||||
|
||||
$oHostDbMaster->executeSimple(
|
||||
$strCommandPush . " ${strWalPath}/${strSourceFile}.partial", {oLogTest => $self->expect()});
|
||||
$self->archiveCheck("${strSourceFile}.partial", $strArchiveChecksum);
|
||||
$self->archiveCheck($oHostBackup, "${strSourceFile}.partial", $strArchiveChecksum);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' .partial WAL with different checksum');
|
||||
@ -405,7 +404,7 @@ sub run
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageRepo()->list(STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_94 . '-1/0000000100000001')},
|
||||
sub {storageRepo()->list($oHostBackup->repoArchivePath(PG_VERSION_94 . '-1/0000000100000001'))},
|
||||
'(' . join(', ', @stryExpectedWAL) . ')',
|
||||
'all WAL in archive', {iWaitSeconds => 5});
|
||||
}
|
||||
|
@ -21,50 +21,17 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Env::ExpireEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initStanzaOption
|
||||
####################################################################################################################################
|
||||
sub initStanzaOption
|
||||
{
|
||||
my $self = shift;
|
||||
my $strDbBasePath = shift;
|
||||
my $strRepoPath = shift;
|
||||
my $oHostS3 = shift;
|
||||
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_PG_PATH, $strDbBasePath);
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $strRepoPath);
|
||||
$self->optionTestSet(CFGOPT_LOG_PATH, $self->testPath());
|
||||
|
||||
$self->optionTestSetBool(CFGOPT_ONLINE, false);
|
||||
|
||||
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 5);
|
||||
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 6);
|
||||
|
||||
if (defined($oHostS3))
|
||||
{
|
||||
$self->optionTestSet(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY, HOST_S3_ACCESS_KEY);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY_SECRET, HOST_S3_ACCESS_SECRET_KEY);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_BUCKET, HOST_S3_BUCKET);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_ENDPOINT, HOST_S3_ENDPOINT);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_REGION, HOST_S3_REGION);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_HOST, $oHostS3->ipGet());
|
||||
$self->optionTestSetBool(CFGOPT_REPO_S3_VERIFY_TLS, false);
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
@ -103,12 +70,9 @@ sub run
|
||||
my ($oHostDbMaster, $oHostDbStandby, $oHostBackup, $oHostS3) = $self->setup(
|
||||
true, $self->expect(), {bS3 => $bS3, bRepoEncrypt => $bEncrypt});
|
||||
|
||||
$self->initStanzaOption($oHostDbMaster->dbBasePath(), $oHostBackup->{strRepoPath}, $oHostS3);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
# Create the test object
|
||||
my $oExpireTest = new pgBackRestTest::Env::ExpireEnvTest(
|
||||
$oHostBackup, $self->backrestExe(), storageRepo(), $self->expect(), $self);
|
||||
$oHostBackup, $self->backrestExe(), storageRepo(), $oHostDbMaster->dbPath(), $self->expect(), $self);
|
||||
|
||||
$oExpireTest->stanzaCreate($self->stanza(), PG_VERSION_92);
|
||||
|
||||
@ -202,12 +166,9 @@ sub run
|
||||
my ($oHostDbMaster, $oHostDbStandby, $oHostBackup, $oHostS3) = $self->setup(
|
||||
true, $self->expect(), {bS3 => $bS3, bRepoEncrypt => $bEncrypt});
|
||||
|
||||
$self->initStanzaOption($oHostDbMaster->dbBasePath(), $oHostBackup->{strRepoPath}, $oHostS3);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
# Create the test object
|
||||
my $oExpireTest = new pgBackRestTest::Env::ExpireEnvTest(
|
||||
$oHostBackup, $self->backrestExe(), storageRepo(), $self->expect(), $self);
|
||||
$oHostBackup, $self->backrestExe(), storageRepo(), $oHostDbMaster->dbPath(), $self->expect(), $self);
|
||||
|
||||
$oExpireTest->stanzaCreate($self->stanza(), PG_VERSION_92);
|
||||
|
||||
|
@ -19,14 +19,13 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
@ -40,17 +39,6 @@ sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Archive and backup info file names
|
||||
my $strArchiveInfoFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE;
|
||||
my $strArchiveInfoCopyFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE . INI_COPY_EXT;
|
||||
my $strArchiveInfoOldFile = "${strArchiveInfoFile}.old";
|
||||
my $strArchiveInfoCopyOldFile = "${strArchiveInfoCopyFile}.old";
|
||||
|
||||
my $strBackupInfoFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO;
|
||||
my $strBackupInfoCopyFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT;
|
||||
my $strBackupInfoOldFile = "${strBackupInfoFile}.old";
|
||||
my $strBackupInfoCopyOldFile = "${strBackupInfoCopyFile}.old";
|
||||
|
||||
foreach my $rhRun
|
||||
(
|
||||
{vm => VM1, remote => false, s3 => false, encrypt => true, compress => GZ},
|
||||
@ -80,9 +68,20 @@ sub run
|
||||
true, $self->expect(), {bHostBackup => $bRemote, bS3 => $bS3, bRepoEncrypt => $bEncrypt,
|
||||
strCompressType => $strCompressType});
|
||||
|
||||
# Archive and backup info file names
|
||||
my $strArchiveInfoFile = $oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE);
|
||||
my $strArchiveInfoCopyFile = $oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE . INI_COPY_EXT);
|
||||
my $strArchiveInfoOldFile = "${strArchiveInfoFile}.old";
|
||||
my $strArchiveInfoCopyOldFile = "${strArchiveInfoCopyFile}.old";
|
||||
|
||||
my $strBackupInfoFile = $oHostBackup->repoBackupPath(FILE_BACKUP_INFO);
|
||||
my $strBackupInfoCopyFile = $oHostBackup->repoBackupPath(FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
my $strBackupInfoOldFile = "${strBackupInfoFile}.old";
|
||||
my $strBackupInfoCopyOldFile = "${strBackupInfoCopyFile}.old";
|
||||
|
||||
# Create the stanza
|
||||
$oHostBackup->stanzaCreate('fail on missing control file', {iExpectedExitStatus => ERROR_FILE_MISSING,
|
||||
strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_LOG_LEVEL_FILE) . '=info'});
|
||||
strOptionalParam => '--no-online --log-level-file=info'});
|
||||
|
||||
# Generate pg_control for stanza-create
|
||||
storageTest()->pathCreate(($oHostDbMaster->dbBasePath() . '/' . DB_PATH_GLOBAL), {bCreateParent => true});
|
||||
@ -91,17 +90,17 @@ sub run
|
||||
# Fail stanza upgrade before stanza-create has been performed
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaUpgrade('fail on stanza not initialized since archive.info is missing',
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-online'});
|
||||
|
||||
# Create the stanza successfully without force
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaCreate('successfully create the stanza', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('successfully create the stanza', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Rerun stanza-create and confirm it does not fail
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaCreate(
|
||||
'do not fail on rerun of stanza-create - info files exist and DB section ok',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
{strOptionalParam => '--no-online'});
|
||||
|
||||
# Stanza Create fails when not using force - database mismatch with pg_control file
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
@ -109,15 +108,14 @@ sub run
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_94);
|
||||
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch and warn force option deprecated',
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) .
|
||||
' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-online --force'});
|
||||
|
||||
# Restore pg_control
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_93);
|
||||
|
||||
# Perform a stanza upgrade which will indicate already up to date
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaUpgrade('already up to date', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaUpgrade('already up to date', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Create the wal path
|
||||
my $strWalPath = $oHostDbMaster->dbBasePath() . '/pg_xlog';
|
||||
@ -140,7 +138,7 @@ sub run
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
$oHostBackup->stanzaCreate('fail on archive info file missing from non-empty dir',
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-online'});
|
||||
}
|
||||
|
||||
# Restore info files from copy
|
||||
@ -170,8 +168,7 @@ sub run
|
||||
# Save a pre-upgrade copy of archive info fo testing db-id mismatch
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
|
||||
$oHostBackup->stanzaUpgrade('successful upgrade creates additional history', {strOptionalParam => '--no-' .
|
||||
cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaUpgrade('successful upgrade creates additional history', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Make sure that WAL from the old version can still be retrieved
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
@ -193,7 +190,7 @@ sub run
|
||||
# Push a WAL segment so have a valid file in the latest DB archive dir only
|
||||
$oHostDbMaster->archivePush($strWalPath, $strArchiveTestFile, 1);
|
||||
$self->testResult(
|
||||
sub {storageRepo()->list(STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_94 . '-2/0000000100000001')},
|
||||
sub {storageRepo()->list($oHostBackup->repoArchivePath(PG_VERSION_94 . '-2/0000000100000001'))},
|
||||
'000000010000000100000001-' . $self->walGenerateContentChecksum(PG_VERSION_94) . ".${strCompressType}",
|
||||
'check that WAL is in the archive at -2');
|
||||
|
||||
@ -201,8 +198,7 @@ sub run
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($oHostDbMaster->dbBasePath() . '/' . DB_PATH_PGTBLSPC);
|
||||
$oHostBackup->backup(
|
||||
'full', 'create first full backup ',
|
||||
{strOptionalParam => '--repo1-retention-full=2 --no-' . cfgOptionName(CFGOPT_ONLINE)}, false);
|
||||
'full', 'create first full backup ', {strOptionalParam => '--repo1-retention-full=2 --no-online'}, false);
|
||||
|
||||
# Upgrade the stanza
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
@ -210,8 +206,7 @@ sub run
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_95);
|
||||
forceStorageMode(storageTest(), $oHostDbMaster->dbBasePath() . '/' . DB_FILE_PGCONTROL, '600');
|
||||
|
||||
|
||||
$oHostBackup->stanzaUpgrade('successfully upgrade', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaUpgrade('successfully upgrade', {strOptionalParam => '--no-online'});
|
||||
|
||||
# Copy archive.info and restore really old version
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
@ -219,16 +214,15 @@ sub run
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
|
||||
# Confirm versions
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet('archive/' . $self->stanza()));
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet('backup/' . $self->stanza()));
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
$self->testResult(sub {$oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
||||
PG_VERSION_93)}, true, 'archive at old pg version');
|
||||
$self->testResult(sub {$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef,
|
||||
PG_VERSION_95)}, true, 'backup at new pg version');
|
||||
|
||||
$oHostBackup->stanzaUpgrade(
|
||||
'upgrade fails with mismatched db-ids',
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
'upgrade fails with mismatched db-ids', {iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-online'});
|
||||
|
||||
# Restore archive.info
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
@ -239,8 +233,8 @@ sub run
|
||||
$oHostDbMaster->archivePush($strWalPath, $strArchiveTestFile, 1);
|
||||
|
||||
# Test backup is changed from type=DIFF to FULL (WARN message displayed)
|
||||
my $oExecuteBackup = $oHostBackup->backupBegin('diff', 'diff changed to full backup',
|
||||
{strOptionalParam => '--repo1-retention-full=2 --no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
my $oExecuteBackup = $oHostBackup->backupBegin(
|
||||
'diff', 'diff changed to full backup', {strOptionalParam => '--repo1-retention-full=2 --no-online'});
|
||||
$oHostBackup->backupEnd('full', $oExecuteBackup, undef, false);
|
||||
|
||||
# Delete the stanza
|
||||
|
@ -16,7 +16,6 @@ use Storable qw(dclone);
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
@ -63,11 +62,8 @@ sub run
|
||||
for (my $iIndex = 0; $iIndex < $iRunTotal; $iIndex++)
|
||||
{
|
||||
executeTest(
|
||||
$self->backrestExe() . ' --' . cfgOptionName(CFGOPT_STANZA) . '=' . $self->stanza() .
|
||||
' --' . cfgOptionName(CFGOPT_ARCHIVE_ASYNC) .
|
||||
' --' . cfgOptionName(CFGOPT_SPOOL_PATH) . '=' . $self->{strSpoolPath} .
|
||||
' --' . cfgOptionName(CFGOPT_ARCHIVE_TIMEOUT) . '=1' .
|
||||
' archive-push /pg_xlog/000000010000000100000001');
|
||||
$self->backrestExe() . ' --stanza=' . $self->stanza() . ' --archive-async --spool-path=' . $self->{strSpoolPath} .
|
||||
' --archive-timeout=1 archive-push /pg_xlog/000000010000000100000001');
|
||||
}
|
||||
|
||||
&log(INFO, 'time per execution: ' . ((gettimeofday() - $lTimeBegin) / $iRunTotal));
|
||||
|
@ -20,10 +20,8 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
@ -111,8 +109,8 @@ sub run
|
||||
# without slowing down the other tests too much.
|
||||
if ($bS3)
|
||||
{
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_PROCESS_MAX) => 2}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_PROCESS_MAX) => 2}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'process-max' => 2}});
|
||||
$oHostDbMaster->configUpdate({&CFGDEF_SECTION_GLOBAL => {'process-max' => 2}});
|
||||
}
|
||||
|
||||
$oHostDbMaster->clusterCreate();
|
||||
@ -122,7 +120,7 @@ sub run
|
||||
|
||||
# Get passphrase to access the Manifest file from backup.info - returns undefined if repo not encrypted
|
||||
my $strCipherPass =
|
||||
(new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->cipherPassSub();
|
||||
(new pgBackRest::Backup::Info($oHostBackup->repoBackupPath()))->cipherPassSub();
|
||||
|
||||
# Create a manifest with the pg version to get version-specific paths
|
||||
my $oManifest = new pgBackRest::Manifest(BOGUS, {bLoad => false, strDbVersion => $self->pgVersion(),
|
||||
@ -157,13 +155,13 @@ sub run
|
||||
my $strComment = undef;
|
||||
|
||||
# Archive and backup info file names
|
||||
my $strArchiveInfoFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE;
|
||||
my $strArchiveInfoCopyFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE . INI_COPY_EXT;
|
||||
my $strArchiveInfoFile = $oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE);
|
||||
my $strArchiveInfoCopyFile = $oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE . INI_COPY_EXT);
|
||||
my $strArchiveInfoOldFile = "${strArchiveInfoFile}.old";
|
||||
my $strArchiveInfoCopyOldFile = "${strArchiveInfoCopyFile}.old";
|
||||
|
||||
my $strBackupInfoFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO;
|
||||
my $strBackupInfoCopyFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT;
|
||||
my $strBackupInfoFile = $oHostBackup->repoBackupPath(FILE_BACKUP_INFO);
|
||||
my $strBackupInfoCopyFile = $oHostBackup->repoBackupPath(FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
my $strBackupInfoOldFile = "${strBackupInfoFile}.old";
|
||||
my $strBackupInfoCopyOldFile = "${strBackupInfoCopyFile}.old";
|
||||
|
||||
@ -232,7 +230,7 @@ sub run
|
||||
|
||||
# load the archive info file and munge it for testing by breaking the database version
|
||||
$oHostBackup->infoMunge(
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
||||
$oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE),
|
||||
{&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'},
|
||||
&INFO_ARCHIVE_SECTION_DB_HISTORY => {1 => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}});
|
||||
|
||||
@ -245,7 +243,7 @@ sub run
|
||||
}
|
||||
|
||||
# Restore the file to its original condition
|
||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE));
|
||||
$oHostBackup->infoRestore($oHostBackup->repoArchivePath(ARCHIVE_INFO_FILE));
|
||||
|
||||
# Check archive_timeout error when WAL segment is not found
|
||||
$strComment = 'fail on archive timeout';
|
||||
@ -268,7 +266,7 @@ sub run
|
||||
|
||||
# Load the backup.info file and munge it for testing by breaking the database version and system id
|
||||
$oHostBackup->infoMunge(
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO),
|
||||
$oHostBackup->repoBackupPath(FILE_BACKUP_INFO),
|
||||
{&INFO_BACKUP_SECTION_DB =>
|
||||
{&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999},
|
||||
&INFO_BACKUP_SECTION_DB_HISTORY =>
|
||||
@ -284,7 +282,7 @@ sub run
|
||||
}
|
||||
|
||||
# Restore the file to its original condition
|
||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO));
|
||||
$oHostBackup->infoRestore($oHostBackup->repoBackupPath(FILE_BACKUP_INFO));
|
||||
|
||||
# ??? Removed temporarily until manifest build can be brought back into the check command
|
||||
# Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check
|
||||
@ -332,22 +330,20 @@ sub run
|
||||
|
||||
# Run stanza-create online to confirm proper handling of configValidation error against new pg-path
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch with directory',
|
||||
{strOptionalParam => ' --' . cfgOptionName(CFGOPT_PG_PATH) . '=' . $oHostDbMaster->dbPath() .
|
||||
'/testbase/', iExpectedExitStatus => ERROR_DB_MISMATCH});
|
||||
{strOptionalParam => ' --pg1-path=' . $oHostDbMaster->dbPath() . '/testbase/',
|
||||
iExpectedExitStatus => ERROR_DB_MISMATCH});
|
||||
|
||||
# Remove the directories to be able to create the stanza
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP, {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE, {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), $oHostBackup->repoBackupPath(), {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), $oHostBackup->repoArchivePath(), {bRecurse => true});
|
||||
|
||||
# Stanza Upgrade - tests configValidate code - all other tests in synthetic integration tests
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Run stanza-create offline to create files needing to be upgraded (using new pg-path)
|
||||
$oHostBackup->stanzaCreate('successfully create stanza files to be upgraded',
|
||||
{strOptionalParam =>
|
||||
' --' . cfgOptionName(CFGOPT_PG_PATH) . '=' . $oHostDbMaster->dbPath() .
|
||||
'/testbase/ --no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet('archive/' . $self->stanza()));
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet('backup/' . $self->stanza()));
|
||||
{strOptionalParam => ' --pg1-path=' . $oHostDbMaster->dbPath() . '/testbase/ --no-online --force'});
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
|
||||
# Read info files to confirm the files were created with a different database version
|
||||
if ($self->pgVersion() eq PG_VERSION_94)
|
||||
@ -369,8 +365,8 @@ sub run
|
||||
$oHostBackup->stanzaUpgrade('upgrade stanza files online');
|
||||
|
||||
# Reread the info files and confirm the result
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet('archive/' . $self->stanza()));
|
||||
$oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet('backup/' . $self->stanza()));
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
$oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
$self->testResult(sub {$oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
||||
$self->pgVersion())}, true, 'archive upgrade online corrects db');
|
||||
$self->testResult(sub {$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef,
|
||||
@ -409,10 +405,10 @@ sub run
|
||||
|
||||
my $strFullBackup = $oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_FULL, 'update during backup',
|
||||
{strOptionalParam => ' --' . cfgOptionName(CFGOPT_BUFFER_SIZE) . '=16384'});
|
||||
{strOptionalParam => ' --buffer-size=16384'});
|
||||
|
||||
# Enabled async archiving
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {cfgOptionName(CFGOPT_ARCHIVE_ASYNC) => 'y'}});
|
||||
$oHostBackup->configUpdate({&CFGDEF_SECTION_GLOBAL => {'archive-async' => 'y'}});
|
||||
|
||||
# Kick out a bunch of archive logs to exercise async archiving. Only do this when compressed and remote to slow it
|
||||
# down enough to make it evident that the async process is working.
|
||||
@ -444,7 +440,7 @@ sub run
|
||||
}
|
||||
|
||||
$oHostDbStandby->restore(
|
||||
'restore backup on replica', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
'restore backup on replica', 'latest',
|
||||
{rhRemapHash => \%oRemapHash, strType => CFGOPTVAL_RESTORE_TYPE_STANDBY,
|
||||
strOptionalParam =>
|
||||
' --recovery-option="primary_conninfo=host=' . HOST_DB_MASTER .
|
||||
@ -470,19 +466,13 @@ sub run
|
||||
{
|
||||
my $strStandbyBackup = $oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_FULL, 'backup from standby, failure to reach master',
|
||||
{bStandby => true,
|
||||
iExpectedExitStatus => ERROR_DB_CONNECT,
|
||||
strOptionalParam => '--' .
|
||||
cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST, cfgOptionIndexTotal(CFGOPT_PG_PATH))) . '=' . BOGUS});
|
||||
{bStandby => true, iExpectedExitStatus => ERROR_DB_CONNECT, strOptionalParam => '--pg8-host=' . BOGUS});
|
||||
}
|
||||
else
|
||||
{
|
||||
my $strStandbyBackup = $oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_FULL, 'backup from standby, failure to access at least one standby',
|
||||
{bStandby => true,
|
||||
iExpectedExitStatus => ERROR_DB_CONNECT,
|
||||
strOptionalParam => '--' .
|
||||
cfgOptionName(cfgOptionIdFromIndex(CFGOPT_PG_HOST, cfgOptionIndexTotal(CFGOPT_PG_PATH))) . '=' . BOGUS});
|
||||
{bStandby => true, iExpectedExitStatus => ERROR_DB_CONNECT, strOptionalParam => '--pg8-host=' . BOGUS});
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,7 +480,7 @@ sub run
|
||||
CFGOPTVAL_BACKUP_TYPE_FULL, 'backup from standby',
|
||||
{bStandby => true,
|
||||
iExpectedExitStatus => $oHostDbStandby->pgVersion() >= PG_VERSION_BACKUP_STANDBY ? undef : ERROR_CONFIG,
|
||||
strOptionalParam => '--' . cfgOptionName(CFGOPT_REPO_RETENTION_FULL) . '=1'});
|
||||
strOptionalParam => '--repo1-retention-full=1'});
|
||||
|
||||
if ($oHostDbStandby->pgVersion() >= PG_VERSION_BACKUP_STANDBY)
|
||||
{
|
||||
@ -632,9 +622,7 @@ sub run
|
||||
|
||||
# Exercise --delta checksum option
|
||||
my $strIncrBackup = $oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR, 'update during backup',
|
||||
{strOptionalParam =>
|
||||
'--' . cfgOptionName(CFGOPT_STOP_AUTO) . ' --' . cfgOptionName(CFGOPT_BUFFER_SIZE) . '=32768 --delta'});
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR, 'update during backup', {strOptionalParam => '--stop-auto --buffer-size=32768 --delta'});
|
||||
|
||||
# Ensure the check command runs properly with a tablespace unless there is a bogus host
|
||||
if (!$oHostBackup->bogusHost())
|
||||
@ -702,9 +690,7 @@ sub run
|
||||
if ($bTestLocal)
|
||||
{
|
||||
# Expect failure because postmaster.pid exists
|
||||
$oHostDbMaster->restore(
|
||||
'postmaster running', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
{iExpectedExitStatus => ERROR_POSTMASTER_RUNNING});
|
||||
$oHostDbMaster->restore('postmaster running', 'latest', {iExpectedExitStatus => ERROR_POSTMASTER_RUNNING});
|
||||
}
|
||||
|
||||
$oHostDbMaster->clusterStop();
|
||||
@ -712,8 +698,7 @@ sub run
|
||||
if ($bTestLocal)
|
||||
{
|
||||
# Expect failure because db path is not empty
|
||||
$oHostDbMaster->restore(
|
||||
'path not empty', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET), {iExpectedExitStatus => ERROR_PATH_NOT_EMPTY});
|
||||
$oHostDbMaster->restore('path not empty', 'latest', {iExpectedExitStatus => ERROR_PATH_NOT_EMPTY});
|
||||
}
|
||||
|
||||
# Drop and recreate db path
|
||||
@ -726,7 +711,7 @@ sub run
|
||||
|
||||
# Now the restore should work
|
||||
$oHostDbMaster->restore(
|
||||
undef, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
undef, 'latest',
|
||||
{strOptionalParam => ($bTestLocal ? ' --db-include=test2 --db-include=test3' : '') . ' --buffer-size=16384'});
|
||||
|
||||
# Test that the first database has not been restored since --db-include did not include test1
|
||||
@ -784,8 +769,8 @@ sub run
|
||||
{
|
||||
# Backup info will have the catalog number
|
||||
my $oBackupInfo = new pgBackRest::Common::Ini(
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO),
|
||||
{bLoad => false, strContent => ${storageRepo()->get(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO)}});
|
||||
storageRepo(), $oHostBackup->repoBackupPath(FILE_BACKUP_INFO),
|
||||
{bLoad => false, strContent => ${storageRepo()->get($oHostBackup->repoBackupPath(FILE_BACKUP_INFO))}});
|
||||
|
||||
# Construct the special path
|
||||
$strTablespacePath .=
|
||||
@ -899,8 +884,7 @@ sub run
|
||||
storageTest()->put($oHostDbMaster->dbBasePath() . "/" . DB_FILE_RECOVERYSIGNAL);
|
||||
}
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
undef, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET), {strType => CFGOPTVAL_RESTORE_TYPE_PRESERVE});
|
||||
$oHostDbMaster->restore(undef, 'latest', {strType => CFGOPTVAL_RESTORE_TYPE_PRESERVE});
|
||||
|
||||
$oHostDbMaster->clusterStart();
|
||||
$oHostDbMaster->sqlSelectOneTest('select message from test', $strXidMessage);
|
||||
@ -916,7 +900,7 @@ sub run
|
||||
$oHostDbMaster->clusterStop();
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
undef, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
undef, 'latest',
|
||||
{bDelta => true, strType => CFGOPTVAL_RESTORE_TYPE_TIME, strTarget => $strTimeTarget,
|
||||
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef,
|
||||
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef,
|
||||
@ -952,7 +936,7 @@ sub run
|
||||
$oHostDbMaster->clusterStop();
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
undef, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
|
||||
undef, 'latest',
|
||||
{bDelta => true, bForce => true, strType => CFGOPTVAL_RESTORE_TYPE_NAME, strTarget => $strNameTarget,
|
||||
strTargetAction => 'promote',
|
||||
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef});
|
||||
@ -997,15 +981,13 @@ sub run
|
||||
# Incr backup - make sure a --no-online backup fails
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR, 'fail on --no-' . cfgOptionName(CFGOPT_ONLINE),
|
||||
{iExpectedExitStatus => ERROR_POSTMASTER_RUNNING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR, 'fail on --no-online',
|
||||
{iExpectedExitStatus => ERROR_POSTMASTER_RUNNING, strOptionalParam => '--no-online'});
|
||||
|
||||
# Incr backup - allow --no-online backup to succeed with --force
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->backup(
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR,
|
||||
'succeed on --no-' . cfgOptionName(CFGOPT_ONLINE) . ' with --' . cfgOptionName(CFGOPT_FORCE),
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
CFGOPTVAL_BACKUP_TYPE_INCR, 'succeed on --no-online with --force', {strOptionalParam => '--no-online --force'});
|
||||
}
|
||||
|
||||
# Stanza-delete --force without access to pgbackrest on database host
|
||||
@ -1017,8 +999,8 @@ sub run
|
||||
{
|
||||
$oHostDbMaster->stop();
|
||||
$oHostBackup->stop({strStanza => $self->stanza});
|
||||
$oHostBackup->stanzaDelete("delete stanza with --force when pgbackrest on pg host not accessible",
|
||||
{strOptionalParam => ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
$oHostBackup->stanzaDelete(
|
||||
"delete stanza with --force when pgbackrest on pg host not accessible", {strOptionalParam => ' --force'});
|
||||
$oHostDbMaster->start();
|
||||
$oHostBackup->start();
|
||||
}
|
||||
|
181
test/test.pl
181
test/test.pl
@ -81,10 +81,9 @@ test.pl [options]
|
||||
--c-only only run C tests
|
||||
--container-only only run tests that must be run in a container
|
||||
--gen-only only run auto-generation
|
||||
--gen-libc generate libc code to embed in the binary
|
||||
--no-gen do not run code generation
|
||||
--code-count generate code counts
|
||||
--smart perform libc/package builds only when source timestamps have changed
|
||||
--smart perform bin/package builds only when source timestamps have changed
|
||||
--no-package do not build packages
|
||||
--dev --smart --no-package --no-optimize
|
||||
--dev-test --no-package
|
||||
@ -155,7 +154,6 @@ my $bNoCoverage = false;
|
||||
my $bCOnly = false;
|
||||
my $bContainerOnly = false;
|
||||
my $bGenOnly = false;
|
||||
my $bGenLibC = false;
|
||||
my $bNoGen = false;
|
||||
my $bCodeCount = false;
|
||||
my $bSmart = false;
|
||||
@ -206,7 +204,6 @@ GetOptions ('q|quiet' => \$bQuiet,
|
||||
'c-only' => \$bCOnly,
|
||||
'container-only' => \$bContainerOnly,
|
||||
'gen-only' => \$bGenOnly,
|
||||
'gen-libc' => \$bGenLibC,
|
||||
'no-gen' => \$bNoGen,
|
||||
'code-count' => \$bCodeCount,
|
||||
'smart' => \$bSmart,
|
||||
@ -369,6 +366,7 @@ eval
|
||||
|
||||
# Get the base backrest path
|
||||
my $strBackRestBase = dirname(dirname(abs_path($0)));
|
||||
my $strVagrantPath = "${strBackRestBase}/test/.vagrant";
|
||||
|
||||
my $oStorageBackRest = new pgBackRestTest::Common::Storage(
|
||||
$strBackRestBase, new pgBackRestTest::Common::StoragePosix({bFileSync => false, bPathSync => false}));
|
||||
@ -550,28 +548,9 @@ eval
|
||||
}
|
||||
}
|
||||
|
||||
# Auto-generate Perl code
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
use lib dirname(dirname($0)) . '/libc/build/lib';
|
||||
use pgBackRestLibC::Build;
|
||||
|
||||
if (!$bSmart || grep(/^(build|libc\/build)\//, @stryModifiedList))
|
||||
{
|
||||
errorDefineLoad(${$oStorageBackRest->get("build/error.yaml")});
|
||||
|
||||
my @stryBuilt = buildXsAll("${strBackRestBase}/libc");
|
||||
&log(INFO, " autogenerated Perl code: " . (@stryBuilt ? join(', ', @stryBuilt) : 'no changes'));
|
||||
|
||||
if (@stryBuilt)
|
||||
{
|
||||
push(@stryBuiltAll, @stryBuilt);
|
||||
push(@stryModifiedList, @stryBuilt);
|
||||
}
|
||||
}
|
||||
|
||||
# Auto-generate C Makefile
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
if (!$bSmart || grep(/^(src|libc)\//, @stryModifiedList))
|
||||
if (!$bSmart || grep(/^src\//, @stryModifiedList))
|
||||
{
|
||||
my @stryBuilt;
|
||||
my $strBuilt = 'src/Makefile.in';
|
||||
@ -713,8 +692,7 @@ eval
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oyTestRun;
|
||||
my $bBinRequired = $bBuildOnly;
|
||||
my $bLibCHostRequired = $bBuildOnly;
|
||||
my $bLibCVmRequired = $bBuildOnly;
|
||||
my $bHostBinRequired = $bBuildOnly;
|
||||
|
||||
# Only get the test list when they can run
|
||||
if (!$bBuildOnly)
|
||||
@ -732,37 +710,26 @@ eval
|
||||
$bBinRequired = true;
|
||||
}
|
||||
|
||||
# Host LibC required if a Perl test
|
||||
# Host bin required if a Perl test
|
||||
if (!$hTest->{&TEST_C})
|
||||
{
|
||||
$bLibCHostRequired = true;
|
||||
}
|
||||
|
||||
# VM LibC required if Perl and not an integration test
|
||||
if (!$hTest->{&TEST_C} && !$hTest->{&TEST_INTEGRATION})
|
||||
{
|
||||
$bLibCVmRequired = true;
|
||||
$bHostBinRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $strBuildRequired;
|
||||
|
||||
if ($bBinRequired || $bLibCHostRequired || $bLibCVmRequired)
|
||||
if ($bBinRequired || $bHostBinRequired)
|
||||
{
|
||||
if ($bBinRequired)
|
||||
{
|
||||
$strBuildRequired = "bin";
|
||||
}
|
||||
|
||||
if ($bLibCHostRequired)
|
||||
if ($bHostBinRequired)
|
||||
{
|
||||
$strBuildRequired .= ", libc host";
|
||||
}
|
||||
|
||||
if ($bLibCVmRequired)
|
||||
{
|
||||
$strBuildRequired .= ", libc vm";
|
||||
$strBuildRequired .= ", bin host";
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -777,9 +744,8 @@ eval
|
||||
if (!$bDryRun)
|
||||
{
|
||||
my $oVm = vmGet();
|
||||
my $strVagrantPath = "${strBackRestBase}/test/.vagrant";
|
||||
my $lTimestampLast;
|
||||
my @stryBinSrcPath = ('src', 'libc');
|
||||
my @stryBinSrcPath = ('src');
|
||||
my $strBinPath = "${strVagrantPath}/bin";
|
||||
my $rhBinBuild = {};
|
||||
|
||||
@ -794,6 +760,12 @@ eval
|
||||
my $bLogDetail = $strLogLevel eq 'detail';
|
||||
my @stryBuildVm = $strVm eq VM_ALL ? VM_LIST : ($strVm);
|
||||
|
||||
# Build binary for the host
|
||||
if ($bHostBinRequired)
|
||||
{
|
||||
push(@stryBuildVm, VM_NONE);
|
||||
}
|
||||
|
||||
foreach my $strBuildVM (@stryBuildVm)
|
||||
{
|
||||
my $strBuildPath = "${strBinPath}/${strBuildVM}/src";
|
||||
@ -802,7 +774,7 @@ eval
|
||||
|
||||
# Build configure/compile options and see if they have changed from the previous build
|
||||
my $strCFlags =
|
||||
"-Wfatal-errors -g -fPIC -D_FILE_OFFSET_BITS=64" .
|
||||
"-Wfatal-errors -g" .
|
||||
(vmWithBackTrace($strBuildVM) && $bBackTrace ? ' -DWITH_BACKTRACE' : '') .
|
||||
($bDebugTestTrace ? ' -DDEBUG_TEST_TRACE' : '');
|
||||
my $strLdFlags = vmWithBackTrace($strBuildVM) && $bBackTrace ? '-lbacktrace' : '';
|
||||
@ -872,114 +844,6 @@ eval
|
||||
}
|
||||
}
|
||||
|
||||
# Build the C Library
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
if ($bLibCHostRequired || $bLibCVmRequired)
|
||||
{
|
||||
my $strLibCPath = "${strVagrantPath}/bin";
|
||||
|
||||
# Loop through VMs to do the C Library builds
|
||||
my $bLogDetail = $strLogLevel eq 'detail';
|
||||
my @stryBuildVm = ();
|
||||
|
||||
if ($strVm eq VM_ALL)
|
||||
{
|
||||
@stryBuildVm = $bLibCVmRequired ? VM_LIST : ($strVmHost);
|
||||
}
|
||||
else
|
||||
{
|
||||
@stryBuildVm = $bLibCVmRequired && $strVmHost ne $strVm ? ($strVmHost, $strVm) : ($strVmHost);
|
||||
}
|
||||
|
||||
foreach my $strBuildVM (@stryBuildVm)
|
||||
{
|
||||
my $strBuildPath = "${strLibCPath}/${strBuildVM}/libc";
|
||||
my $bContainerExists = $strBuildVM ne $strVmHost && $strBuildVM ne VM_NONE;
|
||||
my $strConfigOptions = (vmDebugIntegration($strBuildVM) ? ' --enable-test' : '');
|
||||
|
||||
my $strLibCSmart = "${strBuildPath}/blib/arch/auto/pgBackRest/LibC/LibC.so";
|
||||
my $bRebuild = !$bSmart;
|
||||
|
||||
# Rebuild if the modification time of the smart file does equal the last changes in source paths
|
||||
if ($bSmart)
|
||||
{
|
||||
if (!$oStorageBackRest->exists($strLibCSmart) ||
|
||||
$oStorageBackRest->info($strLibCSmart)->mtime < $lTimestampLast)
|
||||
{
|
||||
&log(INFO, " libc dependencies have changed for ${strBuildVM}, rebuilding...");
|
||||
|
||||
$bRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bRebuild)
|
||||
{
|
||||
&log(INFO, " build test library for ${strBuildVM} (${strBuildPath})");
|
||||
|
||||
if (!$rhBinBuild->{$strBuildVM})
|
||||
{
|
||||
foreach my $strBinSrcPath (@stryBinSrcPath)
|
||||
{
|
||||
$oStorageBackRest->pathCreate(
|
||||
"${strBinPath}/${strBuildVM}/${strBinSrcPath}", {bIgnoreExists => true, bCreateParent => true});
|
||||
}
|
||||
|
||||
executeTest(
|
||||
"rsync -rt" . (!$bSmart ? " --delete-excluded" : '') .
|
||||
" --include=" . join('/*** --include=', @stryBinSrcPath) . '/*** --exclude=*' .
|
||||
" ${strBackRestBase}/ ${strBinPath}/${strBuildVM}");
|
||||
}
|
||||
|
||||
# Can't reuse any object files in the libc dir because it does not have proper dependencies
|
||||
executeTest(
|
||||
"rsync -rt --exclude=Makefile --delete ${strBackRestBase}/libc/ ${strLibCPath}/${strBuildVM}/libc");
|
||||
|
||||
# It's very expensive to rebuild the Makefile so make sure it has actually changed
|
||||
my $bMakeRebuild =
|
||||
!$oStorageBackRest->exists("${strBuildPath}/Makefile") ||
|
||||
($oStorageBackRest->info("${strBackRestBase}/libc/Makefile.PL")->mtime >
|
||||
$oStorageBackRest->info("${strBuildPath}/Makefile.PL")->mtime);
|
||||
|
||||
if ($bContainerExists)
|
||||
{
|
||||
executeTest(
|
||||
"docker run -itd -h test-build --name=test-build" .
|
||||
" -v ${strBackRestBase}:${strBackRestBase} " . containerRepo() . ":${strBuildVM}-build",
|
||||
{bSuppressStdErr => true});
|
||||
}
|
||||
|
||||
if ($bMakeRebuild)
|
||||
{
|
||||
&log(INFO, " rebuild test library Makefile for ${strBuildVM}");
|
||||
|
||||
executeTest(
|
||||
($bContainerExists ? "docker exec -i test-build bash -c '" : '') .
|
||||
"cd ${strBuildPath} && perl ${strBuildPath}/Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none" .
|
||||
($bContainerExists ? "'" : ''),
|
||||
{bSuppressStdErr => true, bShowOutputAsync => $bLogDetail});
|
||||
}
|
||||
|
||||
if (!$oStorageBackRest->exists("${strLibCPath}/${strBuildVM}/src/Makefile"))
|
||||
{
|
||||
executeTest(
|
||||
($bContainerExists ? 'docker exec -i test-build ' : '') .
|
||||
"bash -c 'cd ${strLibCPath}/${strBuildVM}/src && ./configure${strConfigOptions}'",
|
||||
{bShowOutputAsync => $bLogDetail});
|
||||
}
|
||||
|
||||
executeTest(
|
||||
($bContainerExists ? 'docker exec -i test-build ' : '') .
|
||||
"make -j ${iBuildMax} --silent --directory ${strBuildPath}",
|
||||
{bShowOutputAsync => $bLogDetail});
|
||||
|
||||
if ($bContainerExists)
|
||||
{
|
||||
executeTest("docker rm -f test-build");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Build the package
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
if (!$bNoPackage && $strVm ne VM_NONE)
|
||||
@ -1125,7 +989,7 @@ eval
|
||||
executeTest(
|
||||
"tar --transform='s_^_pgbackrest-release-${strVersionBase}/_'" .
|
||||
" -czf ${strBuildPath}/SOURCES/${strVersionBase}.tar.gz -C ${strBackRestBase}" .
|
||||
" lib libc src LICENSE");
|
||||
" src LICENSE");
|
||||
|
||||
# Copy package files
|
||||
executeTest(
|
||||
@ -1463,13 +1327,6 @@ eval
|
||||
################################################################################################################################
|
||||
# Runs tests
|
||||
################################################################################################################################
|
||||
push(
|
||||
@INC,
|
||||
"${strBackRestBase}/test/.vagrant/bin/" .
|
||||
((testDefModuleTest($stryModule[0], $stryModuleTest[0]))->{&TESTDEF_CONTAINER} ? $strVm : $strVmHost) .
|
||||
"/libc/blib/arch");
|
||||
buildLoadLibC();
|
||||
|
||||
my $iRun = 0;
|
||||
|
||||
# Create host group for containers
|
||||
@ -1487,7 +1344,7 @@ eval
|
||||
$strBackRestBase, # Base backrest directory
|
||||
$strTestPath, # Path where the tests will run
|
||||
'/usr/bin/' . PROJECT_EXE, # Path to the backrest executable
|
||||
"${strBackRestBase}/bin/" . PROJECT_EXE, # Path to the backrest Perl helper
|
||||
"${strVagrantPath}/bin/" . VM_NONE . '/src/' . PROJECT_EXE, # Path to the backrest Perl storage helper
|
||||
$strPgVersion ne 'minimal' ? $strPgSqlBin: undef, # Pg bin path
|
||||
$strPgVersion ne 'minimal' ? $strPgVersion: undef, # Pg version
|
||||
$stryModule[0], $stryModuleTest[0], \@iyModuleTestRun, # Module info
|
||||
|
Loading…
x
Reference in New Issue
Block a user