1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-03 00:26:59 +02:00

The info command is implemented entirely in C.

The C info code has already been committed but this commit wires it into main.

Also remove the info Perl code and tests since they are no longer called.
This commit is contained in:
David Steele
2019-01-21 13:51:45 +02:00
parent f79af47bd4
commit d245f8eb42
11 changed files with 16 additions and 1956 deletions

View File

@ -15,6 +15,10 @@
<release date="XXXX-XX-XX" version="2.09dev" title="UNDER DEVELOPMENT"> <release date="XXXX-XX-XX" version="2.09dev" title="UNDER DEVELOPMENT">
<release-core-list> <release-core-list>
<release-improvement-list> <release-improvement-list>
<release-item>
<p>The <cmd>info</cmd> command is implemented entirely in C.</p>
</release-item>
<release-item> <release-item>
<p>Simplify <cmd>info</cmd> command text message when no stanza are present by replacing the repository path with <quote>the repository</quote>.</p> <p>Simplify <cmd>info</cmd> command text message when no stanza are present by replacing the repository path with <quote>the repository</quote>.</p>
</release-item> </release-item>

View File

@ -1,748 +0,0 @@
####################################################################################################################################
# INFO MODULE
####################################################################################################################################
package pgBackRest::Info;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use pgBackRest::Backup::Common;
use pgBackRest::Backup::Info;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Common::Ini;
use pgBackRest::Common::String;
use pgBackRest::Backup::Common;
use pgBackRest::Backup::Info;
use pgBackRest::Config::Config;
use pgBackRest::InfoCommon;
use pgBackRest::Manifest;
use pgBackRest::Protocol::Helper;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRest::Storage::Helper;
####################################################################################################################################
# Info constants
####################################################################################################################################
use constant INFO_SECTION_BACKREST => 'backrest';
use constant INFO_SECTION_ARCHIVE => 'archive';
use constant INFO_SECTION_DB => 'database';
use constant INFO_SECTION_INFO => 'info';
use constant INFO_SECTION_REPO => 'repository';
use constant INFO_SECTION_TIMESTAMP => 'timestamp';
use constant INFO_SECTION_STATUS => 'status';
use constant INFO_SECTION_CIPHER => 'cipher';
use constant INFO_STANZA_NAME => 'name';
use constant INFO_STANZA_STATUS_OK => 'ok';
use constant INFO_STANZA_STATUS_ERROR => 'error';
use constant INFO_STANZA_STATUS_OK_CODE => 0;
use constant INFO_STANZA_STATUS_OK_MESSAGE => INFO_STANZA_STATUS_OK;
use constant INFO_STANZA_STATUS_MISSING_STANZA_CODE => 1;
use constant INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE => 'missing stanza path';
use constant INFO_STANZA_STATUS_NO_BACKUP_CODE => 2;
use constant INFO_STANZA_STATUS_NO_BACKUP_MESSAGE => 'no valid backups';
use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE => 3;
use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE => 'missing stanza data';
use constant INFO_KEY_CODE => 'code';
use constant INFO_KEY_DELTA => 'delta';
use constant INFO_KEY_FORMAT => 'format';
use constant INFO_KEY_ID => INFO_HISTORY_ID;
use constant INFO_KEY_LABEL => 'label';
use constant INFO_KEY_MAX => 'max';
use constant INFO_KEY_MIN => 'min';
use constant INFO_KEY_MESSAGE => 'message';
use constant INFO_KEY_PRIOR => 'prior';
use constant INFO_KEY_REFERENCE => 'reference';
use constant INFO_KEY_SIZE => 'size';
use constant INFO_KEY_START => 'start';
use constant INFO_KEY_STOP => 'stop';
use constant INFO_KEY_SYSTEM_ID => INFO_SYSTEM_ID;
use constant INFO_KEY_TYPE => 'type';
use constant INFO_KEY_VERSION => INFO_DB_VERSION;
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Create the class hash
my $self = {};
bless $self, $class;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# process
####################################################################################################################################
sub process
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');
# Get stanza if specified
my $strStanza = cfgOptionTest(CFGOPT_STANZA) ? cfgOption(CFGOPT_STANZA) : undef;
# Get the stanza list with all info
my $oyStanzaList = $self->stanzaList($strStanza);
if (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_TEXT))
{
my $strOutput = $self->formatText($oyStanzaList);
if (defined($strOutput))
{
syswrite(*STDOUT, $strOutput);
}
else
{
syswrite(*STDOUT, "No stanzas exist in the repository.\n");
}
}
elsif (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_JSON))
{
my $oJSON = JSON::PP->new()->canonical()->pretty()->indent_length(4);
$self->outputJSON($oJSON->encode($oyStanzaList));
}
else
{
confess &log(ASSERT, "invalid info output option '" . cfgOption(CFGOPT_OUTPUT) . "'");
}
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# outputJSON
###################################################################################################################################
sub outputJSON
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strJSON,
) =
logDebugParam
(
__PACKAGE__ . '->outputJSON', \@_,
{name => 'strJSON'},
);
syswrite(*STDOUT, $strJSON);
# On some systems a linefeed will be appended by encode() but others will not have it. In our case there should always
# be a terminating linefeed.
if ($strJSON !~ /\n$/)
{
syswrite(*STDOUT, "\n");
}
}
####################################################################################################################################
# formatText
#
# Format --output=text info.
####################################################################################################################################
sub formatText
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oyStanzaList,
) =
logDebugParam
(
__PACKAGE__ . '->formatText', \@_,
{name => 'oyStanzaList', trace => true},
);
my $strOutput;
foreach my $oStanzaInfo (@{$oyStanzaList})
{
# Output stanza name and status
$strOutput .= (defined($strOutput) ? "\n" : '') . $self->formatTextStanza($oStanzaInfo) . "\n";
# Get the current DB info (always last element in the array)
my $hDbCurrent = @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}}[-1];
# Loop through the DB history array for the stanza from oldest to newest
foreach my $hDbInfo (@{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})
{
if ($hDbInfo->{&INFO_HISTORY_ID} == $hDbCurrent->{&INFO_HISTORY_ID})
{
$strOutput .= "\n db (current)";
}
# Get the archive information for the DB
my $strOutputArchive;
foreach my $hDbArchive (@{$oStanzaInfo->{&INFO_SECTION_ARCHIVE}})
{
if ($hDbArchive->{&INFO_SECTION_DB}{&INFO_HISTORY_ID} == $hDbInfo->{&INFO_HISTORY_ID})
{
# Output archive start / stop values
$strOutputArchive .= "\n wal archive min/max (" . $hDbArchive->{&INFO_KEY_ID} . "): ";
if (defined($hDbArchive->{&INFO_KEY_MIN}))
{
$strOutputArchive .= $hDbArchive->{&INFO_KEY_MIN} . ' / ' . $hDbArchive->{&INFO_KEY_MAX};
}
else
{
$strOutputArchive .= 'none present';
}
$strOutputArchive .= "\n";
}
}
# Get information for each stanza backup for the DB, from oldest to newest
my $strOutputBackup;
foreach my $oBackupInfo (@{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}})
{
if ($oBackupInfo->{&INFO_SECTION_DB}{&INFO_KEY_ID} == $hDbInfo->{&INFO_HISTORY_ID})
{
$strOutputBackup .= "\n" . $self->formatTextBackup($oBackupInfo) . "\n";
}
}
if (defined($strOutputArchive) || defined($strOutputBackup))
{
if ($hDbInfo->{&INFO_HISTORY_ID} != $hDbCurrent->{&INFO_HISTORY_ID})
{
$strOutput .= "\n db (prior)";
}
if (defined($strOutputArchive))
{
$strOutput .= $strOutputArchive;
}
if (defined($strOutputBackup))
{
$strOutput .= $strOutputBackup;
}
}
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strOutput', value => $strOutput, trace => true}
);
}
####################################################################################################################################
# formatTextStanza
#
# Format --output=text stanza info.
####################################################################################################################################
sub formatTextStanza
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oStanzaInfo,
) =
logDebugParam
(
__PACKAGE__ . '->formatTextStanza', \@_,
{name => 'oStanzaInfo', trace => true},
);
# Output stanza name, status and cipher type
my $strOutput =
'stanza: ' . $oStanzaInfo->{&INFO_STANZA_NAME} . "\n" .
" status: " . ($oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_CODE} == 0 ? INFO_STANZA_STATUS_OK :
INFO_STANZA_STATUS_ERROR . ' (' . $oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_MESSAGE} . ')') .
(defined($oStanzaInfo->{&INFO_SECTION_CIPHER}) ? "\n cipher: " . $oStanzaInfo->{&INFO_SECTION_CIPHER} : '');
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strOutput', value => $strOutput, trace => true}
);
}
####################################################################################################################################
# formatTextBackup
#
# Format --output=text backup info.
####################################################################################################################################
sub formatTextBackup
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oBackupInfo,
) =
logDebugParam
(
__PACKAGE__ . '->formatTextBackup', \@_,
{name => 'oBackupInfo', trace => true},
);
my $strOutput =
' ' . $$oBackupInfo{&INFO_KEY_TYPE} . ' backup: ' . $$oBackupInfo{&INFO_KEY_LABEL} . "\n" .
' timestamp start/stop: ' .
timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_START}) .
' / ' .
timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_STOP}) . "\n" .
" wal start/stop: ";
if (defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START}) &&
defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP}))
{
$strOutput .=
$oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START} . ' / ' . $oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP};
}
else
{
$strOutput .= 'n/a';
}
$strOutput .=
"\n database size: " .
(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) ?
fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) : '') .
', backup size: ' .
(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) ?
fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) : '') . "\n" .
' repository size: ' .
(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) ?
fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) : '') .
', repository backup size: ' .
(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) ?
fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) : '');
# List the backup reference chain, if any, for this backup
if (defined($oBackupInfo->{&INFO_KEY_REFERENCE}) && @{$oBackupInfo->{&INFO_KEY_REFERENCE}} > 0)
{
$strOutput .= "\n backup reference list: " . (join(', ', @{$$oBackupInfo{&INFO_KEY_REFERENCE}}));
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strOutput', value => $strOutput, trace => true}
);
}
####################################################################################################################################
# stanzaList
####################################################################################################################################
sub stanzaList
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strStanza
) =
logDebugParam
(
__PACKAGE__ . '->stanzaList', \@_,
{name => 'strStanza', required => false}
);
my @oyStanzaList;
# Run remotely
if (!isRepoLocal())
{
@oyStanzaList = @{protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(OP_INFO_STANZA_LIST, [$strStanza], true)};
}
# Run locally
else
{
my @stryStanza = storageRepo()->list(cfgCommandName(CFGCMD_BACKUP), {bIgnoreMissing => true});
foreach my $strStanzaFound (@stryStanza)
{
if (defined($strStanza) && $strStanza ne $strStanzaFound)
{
next;
}
my $oStanzaInfo = {};
$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanzaFound;
($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}, $$oStanzaInfo{&INFO_BACKUP_SECTION_DB}) =
$self->backupList($strStanzaFound);
# If there are no backups then set status to no backup
if (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}) && @{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}} == 0)
{
$$oStanzaInfo{&INFO_SECTION_STATUS} =
{
&INFO_KEY_CODE => INFO_STANZA_STATUS_NO_BACKUP_CODE,
&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_NO_BACKUP_MESSAGE
};
}
# Else status is OK
elsif (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))
{
$$oStanzaInfo{&INFO_SECTION_STATUS} =
{
&INFO_KEY_CODE => INFO_STANZA_STATUS_OK_CODE,
&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_OK_MESSAGE
};
}
$$oStanzaInfo{&INFO_SECTION_CIPHER} = defined(storageRepo({strStanza => $strStanzaFound})->cipherType()) ?
storageRepo({strStanza => $strStanzaFound})->cipherType() : CFGOPTVAL_REPO_CIPHER_TYPE_NONE;
# Array to store tne min/max archive for each database for which there are archives
my @oyDbArchiveList = ();
if (!defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))
{
$$oStanzaInfo{&INFO_SECTION_STATUS} =
{
&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE,
&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE
};
$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];
$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];
}
else
{
# Get the current DB info (always last element in the array)
my $hDbCurrent = @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}}[-1];
my $strDbCurrentVersion = $hDbCurrent->{&INFO_KEY_VERSION};
my $ullDbCurrentSystemId = $hDbCurrent->{&INFO_KEY_SYSTEM_ID};
# Loop through the DB history from oldest to newest
foreach my $hDbInfo (@{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})
{
my $strArchiveStanzaPath = "archive/" . $strStanzaFound;
my $strDbVersion = $hDbInfo->{&INFO_KEY_VERSION};
my $ullDbSysId = $hDbInfo->{&INFO_KEY_SYSTEM_ID};
# With multiple DB versions, the backup.info history-id may not be the same as archive.info history-id, so the
# archive path must be built by retrieving the archive id given the db version and system id of the backup
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet($strArchiveStanzaPath));
my $strArchiveId = $oArchiveInfo->archiveId({strDbVersion => $hDbInfo->{&INFO_KEY_VERSION},
ullDbSysId => $hDbInfo->{&INFO_KEY_SYSTEM_ID}});
my $strArchivePath = "archive/${strStanzaFound}/${strArchiveId}";
# Fill in the archive info if available
my $hDbArchive = $self->dbArchiveSection($hDbInfo, $strArchiveId, $strArchivePath, $strDbCurrentVersion,
$ullDbCurrentSystemId);
if (defined($hDbArchive))
{
push(@oyDbArchiveList, $hDbArchive);
}
}
}
# Store the archive min/max for each database in the archive section
$oStanzaInfo->{&INFO_SECTION_ARCHIVE} = \@oyDbArchiveList;
push @oyStanzaList, $oStanzaInfo;
}
if (defined($strStanza) && @oyStanzaList == 0)
{
my $oStanzaInfo = {};
$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanza;
$$oStanzaInfo{&INFO_SECTION_STATUS} =
{
&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_CODE,
&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE
};
$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];
$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];
push @oyStanzaList, $oStanzaInfo;
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oyStanzaList', value => \@oyStanzaList, log => false, ref => true}
);
}
####################################################################################################################################
# backupList
###################################################################################################################################
sub backupList
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strStanza
) =
logDebugParam
(
__PACKAGE__ . '->backupList', \@_,
{name => 'strStanza'}
);
# Load the backup.info but do not attempt to validate it
my $oBackupInfo = undef;
# Turn off console logging to control when to display the error
logDisable();
eval
{
$oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(cfgCommandName(CFGCMD_BACKUP) . "/${strStanza}"), false);
logEnable();
return true;
}
or do
{
logEnable();
if (exceptionCode($EVAL_ERROR) == ERROR_FILE_MISSING)
{
return;
}
elsif (exceptionCode($EVAL_ERROR) == ERROR_CRYPTO)
{
# Confess the encryption error with additional hint
confess &log(ERROR, exceptionMessage($EVAL_ERROR) .
"\nHINT: use option --stanza if encryption settings are different for the stanza than the global settings",
ERROR_CRYPTO);
}
else
{
# Confess unhandled errors
confess $EVAL_ERROR;
}
};
# Build the db list
my @oyDbList;
foreach my $iHistoryId ($oBackupInfo->keys(INFO_BACKUP_SECTION_DB_HISTORY))
{
my $oDbHash =
{
&INFO_HISTORY_ID => $iHistoryId + 0,
&INFO_DB_VERSION =>
$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_DB_VERSION),
&INFO_SYSTEM_ID =>
$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_SYSTEM_ID)
};
push(@oyDbList, $oDbHash);
}
# Build the backup list
my @oyBackupList;
foreach my $strBackup ($oBackupInfo->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))
{
my $oBackupHash =
{
&INFO_SECTION_ARCHIVE =>
{
&INFO_KEY_START =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_START, false),
&INFO_KEY_STOP =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_STOP, false),
},
&INFO_SECTION_BACKREST =>
{
&INFO_KEY_FORMAT =>
$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_FORMAT),
&INFO_KEY_VERSION =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_VERSION)
},
&INFO_SECTION_DB =>
{
&INFO_KEY_ID =>
$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID)
},
&INFO_SECTION_INFO =>
{
&INFO_SECTION_REPO =>
{
# Size of the backup in the repository, taking compression into account
&INFO_KEY_SIZE =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE),
# Size of this backup only (does not include referenced backups like repo->size)
&INFO_KEY_DELTA =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA),
},
# Original database size
&INFO_KEY_SIZE =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE),
# Amount of database backed up (will be equal for full backups)
&INFO_KEY_DELTA =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE_DELTA),
},
&INFO_SECTION_TIMESTAMP =>
{
&INFO_KEY_START =>
$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_START),
&INFO_KEY_STOP =>
$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_STOP),
},
&INFO_KEY_LABEL => $strBackup,
&INFO_KEY_PRIOR =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_PRIOR, false),
&INFO_KEY_REFERENCE =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_REFERENCE, false),
&INFO_KEY_TYPE =>
$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TYPE)
};
push(@oyBackupList, $oBackupHash);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oyBackupList', value => \@oyBackupList, log => false, ref => true},
{name => 'oyDbList', value => \@oyDbList, log => false, ref => true}
);
}
####################################################################################################################################
# dbArchiveSection - fills the archive section for a db. Note this is a function in order to aid unit test coverage.
####################################################################################################################################
sub dbArchiveSection
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$hDbInfo,
$strArchiveId,
$strArchivePath,
$strDbCurrentVersion,
$ullDbCurrentSystemId,
) =
logDebugParam
(
__PACKAGE__ . '->dbArchiveSection', \@_,
{name => 'hDbInfo'},
{name => 'strArchiveId'},
{name => 'strArchivePath'},
{name => 'strDbCurrentVersion'},
{name => 'ullDbCurrentSystemId'},
);
my $hDbArchive = undef;
my $strArchiveStart = undef;
my $strArchiveStop = undef;
if (storageRepo()->pathExists($strArchivePath))
{
my @stryWalMajor = storageRepo()->list($strArchivePath, {strExpression => '^[0-F]{16}$'});
# Get first WAL segment
foreach my $strWalMajor (@stryWalMajor)
{
my @stryWalFile = storageRepo()->list(
"${strArchivePath}/${strWalMajor}",
{strExpression => "^[0-F]{24}-[0-f]{40}(\\." . COMPRESS_EXT . "){0,1}\$"});
if (@stryWalFile > 0)
{
$strArchiveStart = substr($stryWalFile[0], 0, 24);
last;
}
}
# Get last WAL segment
foreach my $strWalMajor (sort({$b cmp $a} @stryWalMajor))
{
my @stryWalFile = storageRepo()->list(
"${strArchivePath}/${strWalMajor}",
{strExpression => "^[0-F]{24}-[0-f]{40}(\\." . COMPRESS_EXT . "){0,1}\$", strSortOrder => 'reverse'});
if (@stryWalFile > 0)
{
$strArchiveStop = substr($stryWalFile[0], 0, 24);
last;
}
}
}
# If there is an archive or the database is the current database then store it
if (($strDbCurrentVersion eq $hDbInfo->{&INFO_KEY_VERSION} &&
$ullDbCurrentSystemId == $hDbInfo->{&INFO_KEY_SYSTEM_ID}) ||
defined($strArchiveStart) )
{
$hDbArchive =
{
&INFO_KEY_ID => $strArchiveId,
&INFO_KEY_MIN => $strArchiveStart,
&INFO_KEY_MAX => $strArchiveStop,
&INFO_SECTION_DB =>
{
&INFO_HISTORY_ID => $hDbInfo->{&INFO_HISTORY_ID} + 0,
},
};
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'hDbArchive', value => $hDbArchive, trace => true},
);
}
1;

View File

@ -66,10 +66,6 @@ use constant OP_STORAGE_MOVE => 'storageM
use constant OP_STORAGE_PATH_GET => 'storagePathGet'; use constant OP_STORAGE_PATH_GET => 'storagePathGet';
push @EXPORT, qw(OP_STORAGE_PATH_GET); push @EXPORT, qw(OP_STORAGE_PATH_GET);
# Info module
use constant OP_INFO_STANZA_LIST => 'infoStanzList';
push @EXPORT, qw(OP_INFO_STANZA_LIST);
# Restore module # Restore module
use constant OP_RESTORE_FILE => 'restoreFile'; use constant OP_RESTORE_FILE => 'restoreFile';
push @EXPORT, qw(OP_RESTORE_FILE); push @EXPORT, qw(OP_RESTORE_FILE);

View File

@ -19,7 +19,6 @@ use pgBackRest::Archive::Push::File;
use pgBackRest::Check::Check; use pgBackRest::Check::Check;
use pgBackRest::Config::Config; use pgBackRest::Config::Config;
use pgBackRest::Db; use pgBackRest::Db;
use pgBackRest::Info;
use pgBackRest::Protocol::Command::Minion; use pgBackRest::Protocol::Command::Minion;
use pgBackRest::Protocol::Helper; use pgBackRest::Protocol::Helper;
use pgBackRest::Protocol::Storage::Helper; use pgBackRest::Protocol::Storage::Helper;
@ -71,7 +70,6 @@ sub init
my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo(); my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();
my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef; my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;
my $oInfo = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Info() : undef;
my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef; my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;
# Create anonymous subs for each command # Create anonymous subs for each command
@ -122,9 +120,6 @@ sub init
&OP_STORAGE_PATH_GET => sub {$oStorage->pathGet(@{shift()})}, &OP_STORAGE_PATH_GET => sub {$oStorage->pathGet(@{shift()})},
&OP_STORAGE_HASH_SIZE => sub {$oStorage->hashSize(@{shift()})}, &OP_STORAGE_HASH_SIZE => sub {$oStorage->hashSize(@{shift()})},
# Info commands
&OP_INFO_STANZA_LIST => sub {$oInfo->stanzaList(@{shift()})},
# Wait command # Wait command
&OP_WAIT => sub {waitRemainder(@{shift()})}, &OP_WAIT => sub {waitRemainder(@{shift()})},
}; };

View File

@ -635,15 +635,9 @@ cmdInfo(void)
FUNCTION_DEBUG_VOID(logLevelDebug); FUNCTION_DEBUG_VOID(logLevelDebug);
MEM_CONTEXT_TEMP_BEGIN() MEM_CONTEXT_TEMP_BEGIN()
{
if (!cfgOptionTest(cfgOptRepoHost)) // {uncovered - Perl code is covered in integration tests}
{ {
ioHandleWriteOneStr(STDOUT_FILENO, infoRender()); ioHandleWriteOneStr(STDOUT_FILENO, infoRender());
} }
// Else do it in Perl
else
perlExec(); // {+uncovered}
}
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID(); FUNCTION_DEBUG_RESULT_VOID();

View File

@ -97,6 +97,13 @@ main(int argListSize, const char *argList[])
perlExec(); perlExec();
} }
// Info command
// -------------------------------------------------------------------------------------------------------------------------
else if (cfgCommand() == cfgCmdInfo)
{
cmdInfo();
}
// Execute Perl for commands not implemented in C // Execute Perl for commands not implemented in C
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
else else

View File

@ -10320,678 +10320,6 @@ static const EmbeddedModule embeddedModule[] =
"\n" "\n"
"1;\n" "1;\n"
}, },
{
.name = "pgBackRest/Info.pm",
.data =
"\n\n\n"
"package pgBackRest::Info;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use English '-no_match_vars';\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant INFO_SECTION_BACKREST => 'backrest';\n"
"use constant INFO_SECTION_ARCHIVE => 'archive';\n"
"use constant INFO_SECTION_DB => 'database';\n"
"use constant INFO_SECTION_INFO => 'info';\n"
"use constant INFO_SECTION_REPO => 'repository';\n"
"use constant INFO_SECTION_TIMESTAMP => 'timestamp';\n"
"use constant INFO_SECTION_STATUS => 'status';\n"
"use constant INFO_SECTION_CIPHER => 'cipher';\n"
"\n"
"use constant INFO_STANZA_NAME => 'name';\n"
"\n"
"use constant INFO_STANZA_STATUS_OK => 'ok';\n"
"use constant INFO_STANZA_STATUS_ERROR => 'error';\n"
"\n"
"use constant INFO_STANZA_STATUS_OK_CODE => 0;\n"
"use constant INFO_STANZA_STATUS_OK_MESSAGE => INFO_STANZA_STATUS_OK;\n"
"use constant INFO_STANZA_STATUS_MISSING_STANZA_CODE => 1;\n"
"use constant INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE => 'missing stanza path';\n"
"use constant INFO_STANZA_STATUS_NO_BACKUP_CODE => 2;\n"
"use constant INFO_STANZA_STATUS_NO_BACKUP_MESSAGE => 'no valid backups';\n"
"use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE => 3;\n"
"use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE => 'missing stanza data';\n"
"\n"
"use constant INFO_KEY_CODE => 'code';\n"
"use constant INFO_KEY_DELTA => 'delta';\n"
"use constant INFO_KEY_FORMAT => 'format';\n"
"use constant INFO_KEY_ID => INFO_HISTORY_ID;\n"
"use constant INFO_KEY_LABEL => 'label';\n"
"use constant INFO_KEY_MAX => 'max';\n"
"use constant INFO_KEY_MIN => 'min';\n"
"use constant INFO_KEY_MESSAGE => 'message';\n"
"use constant INFO_KEY_PRIOR => 'prior';\n"
"use constant INFO_KEY_REFERENCE => 'reference';\n"
"use constant INFO_KEY_SIZE => 'size';\n"
"use constant INFO_KEY_START => 'start';\n"
"use constant INFO_KEY_STOP => 'stop';\n"
"use constant INFO_KEY_SYSTEM_ID => INFO_SYSTEM_ID;\n"
"use constant INFO_KEY_TYPE => 'type';\n"
"use constant INFO_KEY_VERSION => INFO_DB_VERSION;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n\n"
"my $strStanza = cfgOptionTest(CFGOPT_STANZA) ? cfgOption(CFGOPT_STANZA) : undef;\n"
"\n\n"
"my $oyStanzaList = $self->stanzaList($strStanza);\n"
"\n"
"if (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_TEXT))\n"
"{\n"
"my $strOutput = $self->formatText($oyStanzaList);\n"
"\n"
"if (defined($strOutput))\n"
"{\n"
"syswrite(*STDOUT, $strOutput);\n"
"}\n"
"else\n"
"{\n"
"syswrite(*STDOUT, \"No stanzas exist in the repository.\\n\");\n"
"}\n"
"}\n"
"elsif (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_JSON))\n"
"{\n"
"my $oJSON = JSON::PP->new()->canonical()->pretty()->indent_length(4);\n"
"$self->outputJSON($oJSON->encode($oyStanzaList));\n"
"}\n"
"else\n"
"{\n"
"confess &log(ASSERT, \"invalid info output option '\" . cfgOption(CFGOPT_OUTPUT) . \"'\");\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub outputJSON\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strJSON,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->outputJSON', \\@_,\n"
"{name => 'strJSON'},\n"
");\n"
"\n"
"syswrite(*STDOUT, $strJSON);\n"
"\n\n\n"
"if ($strJSON !~ /\\n$/)\n"
"{\n"
"syswrite(*STDOUT, \"\\n\");\n"
"}\n"
"}\n"
"\n\n\n\n\n\n"
"sub formatText\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oyStanzaList,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->formatText', \\@_,\n"
"{name => 'oyStanzaList', trace => true},\n"
");\n"
"\n"
"my $strOutput;\n"
"\n"
"foreach my $oStanzaInfo (@{$oyStanzaList})\n"
"{\n"
"\n"
"$strOutput .= (defined($strOutput) ? \"\\n\" : '') . $self->formatTextStanza($oStanzaInfo) . \"\\n\";\n"
"\n\n"
"my $hDbCurrent = @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}}[-1];\n"
"\n\n"
"foreach my $hDbInfo (@{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})\n"
"{\n"
"\n"
"if ($hDbInfo->{&INFO_HISTORY_ID} == $hDbCurrent->{&INFO_HISTORY_ID})\n"
"{\n"
"$strOutput .= \"\\n db (current)\";\n"
"}\n"
"\n\n"
"my $strOutputArchive;\n"
"foreach my $hDbArchive (@{$oStanzaInfo->{&INFO_SECTION_ARCHIVE}})\n"
"{\n"
"if ($hDbArchive->{&INFO_SECTION_DB}{&INFO_HISTORY_ID} == $hDbInfo->{&INFO_HISTORY_ID})\n"
"{\n"
"\n"
"$strOutputArchive .= \"\\n wal archive min/max (\" . $hDbArchive->{&INFO_KEY_ID} . \"): \";\n"
"\n"
"if (defined($hDbArchive->{&INFO_KEY_MIN}))\n"
"{\n"
"$strOutputArchive .= $hDbArchive->{&INFO_KEY_MIN} . ' / ' . $hDbArchive->{&INFO_KEY_MAX};\n"
"}\n"
"else\n"
"{\n"
"$strOutputArchive .= 'none present';\n"
"}\n"
"\n"
"$strOutputArchive .= \"\\n\";\n"
"}\n"
"}\n"
"\n\n"
"my $strOutputBackup;\n"
"foreach my $oBackupInfo (@{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}})\n"
"{\n"
"if ($oBackupInfo->{&INFO_SECTION_DB}{&INFO_KEY_ID} == $hDbInfo->{&INFO_HISTORY_ID})\n"
"{\n"
"$strOutputBackup .= \"\\n\" . $self->formatTextBackup($oBackupInfo) . \"\\n\";\n"
"}\n"
"}\n"
"\n"
"if (defined($strOutputArchive) || defined($strOutputBackup))\n"
"{\n"
"if ($hDbInfo->{&INFO_HISTORY_ID} != $hDbCurrent->{&INFO_HISTORY_ID})\n"
"{\n"
"$strOutput .= \"\\n db (prior)\";\n"
"}\n"
"\n"
"if (defined($strOutputArchive))\n"
"{\n"
"$strOutput .= $strOutputArchive;\n"
"}\n"
"\n"
"if (defined($strOutputBackup))\n"
"{\n"
"$strOutput .= $strOutputBackup;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strOutput', value => $strOutput, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub formatTextStanza\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oStanzaInfo,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->formatTextStanza', \\@_,\n"
"{name => 'oStanzaInfo', trace => true},\n"
");\n"
"\n\n"
"my $strOutput =\n"
"'stanza: ' . $oStanzaInfo->{&INFO_STANZA_NAME} . \"\\n\" .\n"
"\" status: \" . ($oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_CODE} == 0 ? INFO_STANZA_STATUS_OK :\n"
"INFO_STANZA_STATUS_ERROR . ' (' . $oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_MESSAGE} . ')') .\n"
"(defined($oStanzaInfo->{&INFO_SECTION_CIPHER}) ? \"\\n cipher: \" . $oStanzaInfo->{&INFO_SECTION_CIPHER} : '');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strOutput', value => $strOutput, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub formatTextBackup\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oBackupInfo,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->formatTextBackup', \\@_,\n"
"{name => 'oBackupInfo', trace => true},\n"
");\n"
"\n"
"my $strOutput =\n"
"' ' . $$oBackupInfo{&INFO_KEY_TYPE} . ' backup: ' . $$oBackupInfo{&INFO_KEY_LABEL} . \"\\n\" .\n"
"\n"
"' timestamp start/stop: ' .\n"
"timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_START}) .\n"
"' / ' .\n"
"timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_STOP}) . \"\\n\" .\n"
"\n"
"\" wal start/stop: \";\n"
"\n"
"if (defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START}) &&\n"
"defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP}))\n"
"{\n"
"$strOutput .=\n"
"$oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START} . ' / ' . $oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP};\n"
"}\n"
"else\n"
"{\n"
"$strOutput .= 'n/a';\n"
"}\n"
"\n"
"$strOutput .=\n"
"\"\\n database size: \" .\n"
"(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) ?\n"
"fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) : '') .\n"
"', backup size: ' .\n"
"(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) ?\n"
"fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) : '') . \"\\n\" .\n"
"\n"
"' repository size: ' .\n"
"(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) ?\n"
"fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) : '') .\n"
"', repository backup size: ' .\n"
"(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) ?\n"
"fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) : '');\n"
"\n\n"
"if (defined($oBackupInfo->{&INFO_KEY_REFERENCE}) && @{$oBackupInfo->{&INFO_KEY_REFERENCE}} > 0)\n"
"{\n"
"$strOutput .= \"\\n backup reference list: \" . (join(', ', @{$$oBackupInfo{&INFO_KEY_REFERENCE}}));\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strOutput', value => $strOutput, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub stanzaList\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strStanza\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->stanzaList', \\@_,\n"
"{name => 'strStanza', required => false}\n"
");\n"
"\n"
"my @oyStanzaList;\n"
"\n\n"
"if (!isRepoLocal())\n"
"{\n"
"@oyStanzaList = @{protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(OP_INFO_STANZA_LIST, [$strStanza], true)};\n"
"}\n"
"\n"
"else\n"
"{\n"
"my @stryStanza = storageRepo()->list(cfgCommandName(CFGCMD_BACKUP), {bIgnoreMissing => true});\n"
"\n"
"foreach my $strStanzaFound (@stryStanza)\n"
"{\n"
"if (defined($strStanza) && $strStanza ne $strStanzaFound)\n"
"{\n"
"next;\n"
"}\n"
"\n"
"my $oStanzaInfo = {};\n"
"$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanzaFound;\n"
"($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}, $$oStanzaInfo{&INFO_BACKUP_SECTION_DB}) =\n"
"$self->backupList($strStanzaFound);\n"
"\n\n"
"if (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}) && @{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}} == 0)\n"
"{\n"
"$$oStanzaInfo{&INFO_SECTION_STATUS} =\n"
"{\n"
"&INFO_KEY_CODE => INFO_STANZA_STATUS_NO_BACKUP_CODE,\n"
"&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_NO_BACKUP_MESSAGE\n"
"};\n"
"}\n"
"\n"
"elsif (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))\n"
"{\n"
"$$oStanzaInfo{&INFO_SECTION_STATUS} =\n"
"{\n"
"&INFO_KEY_CODE => INFO_STANZA_STATUS_OK_CODE,\n"
"&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_OK_MESSAGE\n"
"};\n"
"}\n"
"\n"
"$$oStanzaInfo{&INFO_SECTION_CIPHER} = defined(storageRepo({strStanza => $strStanzaFound})->cipherType()) ?\n"
"storageRepo({strStanza => $strStanzaFound})->cipherType() : CFGOPTVAL_REPO_CIPHER_TYPE_NONE;\n"
"\n\n"
"my @oyDbArchiveList = ();\n"
"\n"
"if (!defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))\n"
"{\n"
"$$oStanzaInfo{&INFO_SECTION_STATUS} =\n"
"{\n"
"&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE,\n"
"&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE\n"
"};\n"
"\n"
"$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];\n"
"$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];\n"
"}\n"
"else\n"
"{\n"
"\n"
"my $hDbCurrent = @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}}[-1];\n"
"my $strDbCurrentVersion = $hDbCurrent->{&INFO_KEY_VERSION};\n"
"my $ullDbCurrentSystemId = $hDbCurrent->{&INFO_KEY_SYSTEM_ID};\n"
"\n\n"
"foreach my $hDbInfo (@{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})\n"
"{\n"
"my $strArchiveStanzaPath = \"archive/\" . $strStanzaFound;\n"
"my $strDbVersion = $hDbInfo->{&INFO_KEY_VERSION};\n"
"my $ullDbSysId = $hDbInfo->{&INFO_KEY_SYSTEM_ID};\n"
"\n\n\n"
"my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet($strArchiveStanzaPath));\n"
"my $strArchiveId = $oArchiveInfo->archiveId({strDbVersion => $hDbInfo->{&INFO_KEY_VERSION},\n"
"ullDbSysId => $hDbInfo->{&INFO_KEY_SYSTEM_ID}});\n"
"my $strArchivePath = \"archive/${strStanzaFound}/${strArchiveId}\";\n"
"\n\n"
"my $hDbArchive = $self->dbArchiveSection($hDbInfo, $strArchiveId, $strArchivePath, $strDbCurrentVersion,\n"
"$ullDbCurrentSystemId);\n"
"\n"
"if (defined($hDbArchive))\n"
"{\n"
"push(@oyDbArchiveList, $hDbArchive);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$oStanzaInfo->{&INFO_SECTION_ARCHIVE} = \\@oyDbArchiveList;\n"
"\n"
"push @oyStanzaList, $oStanzaInfo;\n"
"}\n"
"\n"
"if (defined($strStanza) && @oyStanzaList == 0)\n"
"{\n"
"my $oStanzaInfo = {};\n"
"\n"
"$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanza;\n"
"\n"
"$$oStanzaInfo{&INFO_SECTION_STATUS} =\n"
"{\n"
"&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_CODE,\n"
"&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE\n"
"};\n"
"\n"
"$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];\n"
"$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];\n"
"\n"
"push @oyStanzaList, $oStanzaInfo;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oyStanzaList', value => \\@oyStanzaList, log => false, ref => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub backupList\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strStanza\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->backupList', \\@_,\n"
"{name => 'strStanza'}\n"
");\n"
"\n\n"
"my $oBackupInfo = undef;\n"
"\n\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"$oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(cfgCommandName(CFGCMD_BACKUP) . \"/${strStanza}\"), false);\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"logEnable();\n"
"\n"
"if (exceptionCode($EVAL_ERROR) == ERROR_FILE_MISSING)\n"
"{\n"
"return;\n"
"}\n"
"elsif (exceptionCode($EVAL_ERROR) == ERROR_CRYPTO)\n"
"{\n"
"\n"
"confess &log(ERROR, exceptionMessage($EVAL_ERROR) .\n"
"\"\\nHINT: use option --stanza if encryption settings are different for the stanza than the global settings\",\n"
"ERROR_CRYPTO);\n"
"}\n"
"else\n"
"{\n"
"\n"
"confess $EVAL_ERROR;\n"
"}\n"
"};\n"
"\n\n"
"my @oyDbList;\n"
"\n"
"foreach my $iHistoryId ($oBackupInfo->keys(INFO_BACKUP_SECTION_DB_HISTORY))\n"
"{\n"
"my $oDbHash =\n"
"{\n"
"&INFO_HISTORY_ID => $iHistoryId + 0,\n"
"&INFO_DB_VERSION =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_DB_VERSION),\n"
"&INFO_SYSTEM_ID =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_SYSTEM_ID)\n"
"};\n"
"\n"
"push(@oyDbList, $oDbHash);\n"
"}\n"
"\n\n"
"my @oyBackupList;\n"
"\n"
"foreach my $strBackup ($oBackupInfo->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))\n"
"{\n"
"my $oBackupHash =\n"
"{\n"
"&INFO_SECTION_ARCHIVE =>\n"
"{\n"
"&INFO_KEY_START =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_START, false),\n"
"&INFO_KEY_STOP =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_STOP, false),\n"
"},\n"
"&INFO_SECTION_BACKREST =>\n"
"{\n"
"&INFO_KEY_FORMAT =>\n"
"$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_FORMAT),\n"
"&INFO_KEY_VERSION =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_VERSION)\n"
"},\n"
"&INFO_SECTION_DB =>\n"
"{\n"
"&INFO_KEY_ID =>\n"
"$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID)\n"
"},\n"
"&INFO_SECTION_INFO =>\n"
"{\n"
"&INFO_SECTION_REPO =>\n"
"{\n"
"\n"
"&INFO_KEY_SIZE =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE),\n"
"\n"
"&INFO_KEY_DELTA =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA),\n"
"},\n"
"\n"
"&INFO_KEY_SIZE =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE),\n"
"\n"
"&INFO_KEY_DELTA =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE_DELTA),\n"
"},\n"
"&INFO_SECTION_TIMESTAMP =>\n"
"{\n"
"&INFO_KEY_START =>\n"
"$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_START),\n"
"&INFO_KEY_STOP =>\n"
"$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_STOP),\n"
"},\n"
"&INFO_KEY_LABEL => $strBackup,\n"
"&INFO_KEY_PRIOR =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_PRIOR, false),\n"
"&INFO_KEY_REFERENCE =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_REFERENCE, false),\n"
"&INFO_KEY_TYPE =>\n"
"$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TYPE)\n"
"};\n"
"\n"
"push(@oyBackupList, $oBackupHash);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oyBackupList', value => \\@oyBackupList, log => false, ref => true},\n"
"{name => 'oyDbList', value => \\@oyDbList, log => false, ref => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub dbArchiveSection\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$hDbInfo,\n"
"$strArchiveId,\n"
"$strArchivePath,\n"
"$strDbCurrentVersion,\n"
"$ullDbCurrentSystemId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbArchiveSection', \\@_,\n"
"{name => 'hDbInfo'},\n"
"{name => 'strArchiveId'},\n"
"{name => 'strArchivePath'},\n"
"{name => 'strDbCurrentVersion'},\n"
"{name => 'ullDbCurrentSystemId'},\n"
");\n"
"\n"
"my $hDbArchive = undef;\n"
"my $strArchiveStart = undef;\n"
"my $strArchiveStop = undef;\n"
"\n"
"if (storageRepo()->pathExists($strArchivePath))\n"
"{\n"
"my @stryWalMajor = storageRepo()->list($strArchivePath, {strExpression => '^[0-F]{16}$'});\n"
"\n\n"
"foreach my $strWalMajor (@stryWalMajor)\n"
"{\n"
"my @stryWalFile = storageRepo()->list(\n"
"\"${strArchivePath}/${strWalMajor}\",\n"
"{strExpression => \"^[0-F]{24}-[0-f]{40}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\"});\n"
"\n"
"if (@stryWalFile > 0)\n"
"{\n"
"$strArchiveStart = substr($stryWalFile[0], 0, 24);\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"foreach my $strWalMajor (sort({$b cmp $a} @stryWalMajor))\n"
"{\n"
"my @stryWalFile = storageRepo()->list(\n"
"\"${strArchivePath}/${strWalMajor}\",\n"
"{strExpression => \"^[0-F]{24}-[0-f]{40}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\", strSortOrder => 'reverse'});\n"
"\n"
"if (@stryWalFile > 0)\n"
"{\n"
"$strArchiveStop = substr($stryWalFile[0], 0, 24);\n"
"last;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (($strDbCurrentVersion eq $hDbInfo->{&INFO_KEY_VERSION} &&\n"
"$ullDbCurrentSystemId == $hDbInfo->{&INFO_KEY_SYSTEM_ID}) ||\n"
"defined($strArchiveStart) )\n"
"{\n"
"$hDbArchive =\n"
"{\n"
"&INFO_KEY_ID => $strArchiveId,\n"
"&INFO_KEY_MIN => $strArchiveStart,\n"
"&INFO_KEY_MAX => $strArchiveStop,\n"
"&INFO_SECTION_DB =>\n"
"{\n"
"&INFO_HISTORY_ID => $hDbInfo->{&INFO_HISTORY_ID} + 0,\n"
"},\n"
"};\n"
"}\n"
"\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hDbArchive', value => $hDbArchive, trace => true},\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{ {
.name = "pgBackRest/InfoCommon.pm", .name = "pgBackRest/InfoCommon.pm",
.data = .data =
@ -13701,9 +13029,6 @@ static const EmbeddedModule embeddedModule[] =
"use constant OP_STORAGE_PATH_GET => 'storagePathGet';\n" "use constant OP_STORAGE_PATH_GET => 'storagePathGet';\n"
"push @EXPORT, qw(OP_STORAGE_PATH_GET);\n" "push @EXPORT, qw(OP_STORAGE_PATH_GET);\n"
"\n\n" "\n\n"
"use constant OP_INFO_STANZA_LIST => 'infoStanzList';\n"
"push @EXPORT, qw(OP_INFO_STANZA_LIST);\n"
"\n\n"
"use constant OP_RESTORE_FILE => 'restoreFile';\n" "use constant OP_RESTORE_FILE => 'restoreFile';\n"
"push @EXPORT, qw(OP_RESTORE_FILE);\n" "push @EXPORT, qw(OP_RESTORE_FILE);\n"
"\n\n" "\n\n"
@ -14833,7 +14158,6 @@ static const EmbeddedModule embeddedModule[] =
"use pgBackRest::Check::Check;\n" "use pgBackRest::Check::Check;\n"
"use pgBackRest::Config::Config;\n" "use pgBackRest::Config::Config;\n"
"use pgBackRest::Db;\n" "use pgBackRest::Db;\n"
"use pgBackRest::Info;\n"
"use pgBackRest::Protocol::Command::Minion;\n" "use pgBackRest::Protocol::Command::Minion;\n"
"use pgBackRest::Protocol::Helper;\n" "use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n" "use pgBackRest::Protocol::Storage::Helper;\n"
@ -14874,7 +14198,6 @@ static const EmbeddedModule embeddedModule[] =
"my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n" "my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n"
"\n" "\n"
"my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;\n" "my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;\n"
"my $oInfo = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Info() : undef;\n"
"my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n" "my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n"
"\n\n" "\n\n"
"my $hCommandMap =\n" "my $hCommandMap =\n"
@ -14919,8 +14242,6 @@ static const EmbeddedModule embeddedModule[] =
"&OP_STORAGE_PATH_GET => sub {$oStorage->pathGet(@{shift()})},\n" "&OP_STORAGE_PATH_GET => sub {$oStorage->pathGet(@{shift()})},\n"
"&OP_STORAGE_HASH_SIZE => sub {$oStorage->hashSize(@{shift()})},\n" "&OP_STORAGE_HASH_SIZE => sub {$oStorage->hashSize(@{shift()})},\n"
"\n\n" "\n\n"
"&OP_INFO_STANZA_LIST => sub {$oInfo->stanzaList(@{shift()})},\n"
"\n\n"
"&OP_WAIT => sub {waitRemainder(@{shift()})},\n" "&OP_WAIT => sub {waitRemainder(@{shift()})},\n"
"};\n" "};\n"
"\n\n" "\n\n"

View File

@ -582,13 +582,6 @@ unit:
- name: info - name: info
test: test:
# ----------------------------------------------------------------------------------------------------------------------------
- name: unit-perl
total: 2
coverage:
Info: full
# ---------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------
- name: info - name: info
total: 1 total: 1

View File

@ -4951,7 +4951,7 @@ stanza: db
timestamp start/stop: [TIMESTAMP-STR] timestamp start/stop: [TIMESTAMP-STR]
wal start/stop: n/a wal start/stop: n/a
database size: 176KB, backup size: 176KB database size: 176KB, backup size: 176KB
repository size: 2.3KB, repository backup size: 2.3KB repository size: 2.4KB, repository backup size: 2.4KB
info db stanza - normal output (db-master host) info db stanza - normal output (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --stanza=db --output=json info > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --stanza=db --output=json info
@ -5599,7 +5599,7 @@ stanza: db
timestamp start/stop: [TIMESTAMP-STR] timestamp start/stop: [TIMESTAMP-STR]
wal start/stop: n/a wal start/stop: n/a
database size: 176KB, backup size: 176KB database size: 176KB, backup size: 176KB
repository size: 2.3KB, repository backup size: 2.3KB repository size: 2.4KB, repository backup size: 2.4KB
diff backup: [BACKUP-DIFF-5] diff backup: [BACKUP-DIFF-5]
timestamp start/stop: [TIMESTAMP-STR] timestamp start/stop: [TIMESTAMP-STR]

View File

@ -2589,7 +2589,7 @@ stanza: db
timestamp start/stop: [TIMESTAMP-STR] timestamp start/stop: [TIMESTAMP-STR]
wal start/stop: n/a wal start/stop: n/a
database size: 160KB, backup size: 41B database size: 160KB, backup size: 41B
repository size: 160.6KB, repository backup size: 192B repository size: 160.7KB, repository backup size: 192B
backup reference list: [BACKUP-FULL-2] backup reference list: [BACKUP-FULL-2]
incr backup: [BACKUP-INCR-3] incr backup: [BACKUP-INCR-3]
@ -3179,7 +3179,7 @@ stanza: db
timestamp start/stop: [TIMESTAMP-STR] timestamp start/stop: [TIMESTAMP-STR]
wal start/stop: n/a wal start/stop: n/a
database size: 144.1KB, backup size: 9B database size: 144.1KB, backup size: 9B
repository size: 2.5KB, repository backup size: 48B repository size: 2.6KB, repository backup size: 48B
backup reference list: [BACKUP-FULL-3] backup reference list: [BACKUP-FULL-3]
info all stanzas - normal output (db-master host) info all stanzas - normal output (db-master host)

View File

@ -1,502 +0,0 @@
####################################################################################################################################
# Unit tests for Info module
####################################################################################################################################
package pgBackRestTest::Module::Info::InfoUnitPerlTest;
use parent 'pgBackRestTest::Env::HostEnvTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use File::Basename qw(dirname);
use Storable qw(dclone);
use pgBackRest::Backup::Common;
use pgBackRest::Backup::Info;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Lock;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::DbVersion;
use pgBackRest::Info;
use pgBackRest::InfoCommon;
use pgBackRest::Manifest;
use pgBackRest::Protocol::Helper;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRest::Storage::Local;
use pgBackRestTest::Common::ExecuteTest;
use pgBackRestTest::Common::RunTest;
use pgBackRestTest::Env::ExpireEnvTest;
use pgBackRestTest::Common::FileTest;
use pgBackRestTest::Env::Host::HostBackupTest;
use pgBackRestTest::Env::HostEnvTest;
####################################################################################################################################
# initModule
####################################################################################################################################
use constant STANZA_ENCRYPT => 'encrypt';
####################################################################################################################################
# initModule
####################################################################################################################################
sub initModule
{
my $self = shift;
$self->{strRepoPath} = $self->testPath() . '/repo';
$self->{strArchivePath} = "$self->{strRepoPath}/archive/" . $self->stanza();
$self->{strBackupPath} = "$self->{strRepoPath}/backup/" . $self->stanza();
$self->{strDbPath} = $self->testPath() . '/db';
$self->{strArchivePathEncrypt} = "$self->{strRepoPath}/archive/" . STANZA_ENCRYPT;
$self->{strBackupPathEncrypt} = "$self->{strRepoPath}/backup/" . STANZA_ENCRYPT;
}
####################################################################################################################################
# initTest
####################################################################################################################################
sub initTest
{
my $self = shift;
# Create parent path for pg_control
storageTest()->pathCreate(($self->{strDbPath} . '/' . DB_PATH_GLOBAL), {bCreateParent => true});
# Create archive info path
storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true});
# Create backup info path
storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true});
}
####################################################################################################################################
# initStanzaCreate - initialize options and create the stanza object
####################################################################################################################################
sub initStanzaCreate
{
my $self = shift;
my $strStanza = shift;
my $bEncrypted = shift;
my $strDbVersion = shift;
# Set options for stanzaCreate
my $rhConfig = $self->configTestClear();
if (!defined($strStanza))
{
$strStanza = $self->stanza();
}
if (defined($bEncrypted) && $bEncrypted == true)
{
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
}
if (!defined($strDbVersion))
{
$strDbVersion = PG_VERSION_94;
}
$self->optionTestSet(CFGOPT_STANZA, $strStanza);
$self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath});
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{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);
$self->configTestLoad(CFGCMD_STANZA_CREATE);
$self->configTestSet($rhConfig);
my $oTestObject = "oExpireTest";
# Create the test object
if (defined($bEncrypted) && $bEncrypted == true)
{
$oTestObject = "oExpireTestEncrypt";
}
$self->{$oTestObject} = new pgBackRestTest::Env::ExpireEnvTest(undef, $self->backrestExe(), storageRepo(), undef, $self);
$self->{$oTestObject}->stanzaCreate($strStanza, $strDbVersion);
}
####################################################################################################################################
# initStanzaUpgrade - initialize options and create the stanza object
####################################################################################################################################
sub initStanzaUpgrade
{
my $self = shift;
# Set options for stanzaCreate
my $rhConfig = $self->configTestClear();
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath});
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{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);
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
$self->configTestSet($rhConfig);
# Create the test object
$self->{oExpireTest} = new pgBackRestTest::Env::ExpireEnvTest(undef, $self->backrestExe(), storageRepo(), undef, $self);
$self->{oExpireTest}->stanzaUpgrade($self->stanza(), PG_VERSION_95);
}
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
# Used to create backups and WAL to test
use constant SECONDS_PER_DAY => 86400;
my $lBaseTime = 1486137448 - (60 * SECONDS_PER_DAY);
# Create the initial backup "day" number - backup day is incremented for each backup
my $iLastBackup = 5;
################################################################################################################################
if ($self->begin("Info"))
{
$self->configTestLoad(CFGCMD_INFO);
my $oInfo = new pgBackRest::Info();
# Output No stanzas exist in default text option
#---------------------------------------------------------------------------------------------------------------------------
$self->testResult(sub {$oInfo->process()}, undef, 'No stanzas exist and default text option');
# Invalid option
#---------------------------------------------------------------------------------------------------------------------------
cfgOptionSet(CFGOPT_OUTPUT, BOGUS);
$self->testException(sub {$oInfo->process()}, ERROR_ASSERT, "invalid info output option '" . BOGUS . "'");
# Output json option with no stanza defined
#---------------------------------------------------------------------------------------------------------------------------
$self->optionTestSet(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_JSON);
$self->configTestLoad(CFGCMD_INFO);
$self->testResult(sub {$oInfo->process()}, undef, 'json option');
# Add linefeed to JSON
#---------------------------------------------------------------------------------------------------------------------------
my $strJson = '[{"archive" : 1}]';
$self->testResult(sub {$oInfo->outputJSON($strJson)}, 1, 'add linefeed to json');
# Missing stanza path
#---------------------------------------------------------------------------------------------------------------------------
my $hyStanza = $oInfo->stanzaList(BOGUS);
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: bogus\n status: error (missing stanza path)\n",
'missing stanza path');
# formatBackupText - coverage for certain conditions
#---------------------------------------------------------------------------------------------------------------------------
my $oBackupHash =
{
'archive' =>
{
'start' => 1,
'stop' => undef
},
'timestamp' =>
{
'start' => 1481039848,
'stop' => 1481039848,
},
'label' => 'BACKUPLABEL',
'reference' => ['BACKUPREFERENCE'],
'type' => 'BACKUPTYPE',
};
$self->testResult(sub {$oInfo->formatTextBackup($oBackupHash)},
" BACKUPTYPE backup: BACKUPLABEL\n" .
" timestamp start/stop: 2016-12-06 15:57:28 / 2016-12-06 15:57:28\n" .
" wal start/stop: n/a\n" .
" database size: , backup size: \n" .
" repository size: , repository backup size: \n" .
" backup reference list: BACKUPREFERENCE",
'formatTextBackup');
# Test !isRepoLocal branch
#---------------------------------------------------------------------------------------------------------------------------
cfgOptionSet(CFGOPT_REPO_HOST, false);
cfgOptionSet(CFGOPT_REPO_HOST_CONFIG, BOGUS);
$self->testException(sub {$oInfo->stanzaList(BOGUS)}, ERROR_ASSERT, "option repo1-host-cmd is required");
# dbArchiveSection() -- no archive
#---------------------------------------------------------------------------------------------------------------------------
my $hDbInfo =
{
&INFO_HISTORY_ID => 1,
&INFO_DB_VERSION => PG_VERSION_94,
&INFO_SYSTEM_ID => $self->dbSysId(PG_VERSION_94),
};
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, PG_VERSION_94 . '-1', $self->{strArchivePath}, PG_VERSION_94,
$self->dbSysId(PG_VERSION_94))}, "{database => {id => 1}, id => 9.4-1, max => [undef], min => [undef]}",
'no archive, db-ver match, db-sys match');
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, PG_VERSION_94 . '-1', $self->{strArchivePath}, PG_VERSION_94,
$self->dbSysId(PG_VERSION_95))}, undef, 'no archive, db-ver match, db-sys mismatch');
$hDbInfo->{&INFO_DB_VERSION} = PG_VERSION_95;
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, PG_VERSION_94 . '-1', $self->{strArchivePath}, PG_VERSION_94,
$self->dbSysId(PG_VERSION_94))}, undef, 'no archive, db-ver mismatch, db-sys match');
$hDbInfo->{&INFO_SYSTEM_ID} = $self->dbSysId(PG_VERSION_95);
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, PG_VERSION_94 . '-1', $self->{strArchivePath}, PG_VERSION_94,
$self->dbSysId(PG_VERSION_94))}, undef, 'no archive, db-ver mismatch, db-sys mismatch');
# Create more than one stanza but no data
#---------------------------------------------------------------------------------------------------------------------------
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath});
$self->configTestLoad(CFGCMD_INFO);
# Create archive and backup paths but no info files
storageTest()->pathCreate("$self->{strRepoPath}/archive/" . BOGUS, {bIgnoreExists => true, bCreateParent => true});
storageTest()->pathCreate("$self->{strRepoPath}/backup/" . BOGUS, {bIgnoreExists => true, bCreateParent => true});
# Get a list of all stanzas in the repo
$hyStanza = $oInfo->stanzaList();
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: bogus\n status: error (missing stanza data)\n cipher: none\n\n" .
"stanza: db\n status: error (missing stanza data)\n cipher: none\n",
'fomatText() multiple stanzas missing data');
# Define the stanza option
#---------------------------------------------------------------------------------------------------------------------------
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestClear(CFGOPT_OUTPUT);
$self->configTestLoad(CFGCMD_INFO);
$self->testResult(sub {$oInfo->process()}, undef, 'stanza set');
# Create the stanza - no WAL or backups
#---------------------------------------------------------------------------------------------------------------------------
$self->initStanzaCreate();
$self->configTestLoad(CFGCMD_INFO);
$self->testResult(sub {$oInfo->formatText($oInfo->stanzaList())},
"stanza: bogus\n status: error (missing stanza data)\n cipher: none\n\n" .
"stanza: db\n status: error (no valid backups)\n cipher: none\n\n" .
" db (current)\n wal archive min/max (9.4-1): none present\n",
"formatText() multiple stanzas, one missing data");
$hyStanza = $oInfo->stanzaList($self->stanza());
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: db\n status: error (no valid backups)\n cipher: none\n\n" .
" db (current)\n wal archive min/max (9.4-1): none present\n",
"formatText() one stanza");
# Create a backup and list backup for just one stanza
#---------------------------------------------------------------------------------------------------------------------------
$self->{oExpireTest}->backupCreate($self->stanza(), CFGOPTVAL_BACKUP_TYPE_FULL, $lBaseTime += SECONDS_PER_DAY, -1, -1);
$hyStanza = $oInfo->stanzaList($self->stanza());
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: db\n status: ok\n cipher: none\n\n db (current)\n wal archive min/max (9.4-1): none present\n\n" .
" full backup: 20161206-155728F\n" .
" timestamp start/stop: 2016-12-06 15:57:28 / 2016-12-06 15:57:28\n" .
" wal start/stop: n/a\n database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"formatText() one stanza");
# Coverage for major WAL paths with no WAL
#---------------------------------------------------------------------------------------------------------------------------
storageTest()->pathCreate($self->{strArchivePath} . "/9.4-1/0000000100000000", {bIgnoreExists => true});
storageTest()->pathCreate($self->{strArchivePath} . "/9.4-1/0000000200000000", {bIgnoreExists => true});
$hyStanza = $oInfo->stanzaList($self->stanza());
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: db\n status: ok\n cipher: none\n\n db (current)\n wal archive min/max (9.4-1): none present\n\n" .
" full backup: 20161206-155728F\n" .
" timestamp start/stop: 2016-12-06 15:57:28 / 2016-12-06 15:57:28\n" .
" wal start/stop: n/a\n database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"formatText() major WAL paths with no WAL");
# Upgrade postgres version and backup with WAL
#---------------------------------------------------------------------------------------------------------------------------
undef($self->{oExpireTest});
$self->initStanzaUpgrade();
$self->configTestLoad(CFGCMD_INFO);
$self->{oExpireTest}->backupCreate($self->stanza(), CFGOPTVAL_BACKUP_TYPE_FULL, $lBaseTime += SECONDS_PER_DAY, 1, 1);
$self->{oExpireTest}->backupCreate($self->stanza(), CFGOPTVAL_BACKUP_TYPE_DIFF, $lBaseTime += SECONDS_PER_DAY, 1, 1);
# Remove the 9.4-1 path for condition test coverage
storageTest()->remove($self->{strArchivePath} . "/9.4-1/", {bRecurse => true});
$hyStanza = $oInfo->stanzaList($self->stanza());
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: db\n status: ok\n cipher: none\n" .
"\n db (prior)\n" .
" full backup: 20161206-155728F\n" .
" timestamp start/stop: 2016-12-06 15:57:28 / 2016-12-06 15:57:28\n" .
" wal start/stop: n/a\n" .
" database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n" .
"\n db (current)\n" .
" wal archive min/max (9.5-2): 000000010000000000000000 / 000000010000000000000003\n\n" .
" full backup: 20161207-155728F\n" .
" timestamp start/stop: 2016-12-07 15:57:28 / 2016-12-07 15:57:28\n" .
" wal start/stop: 000000010000000000000000 / 000000010000000000000000\n" .
" database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n\n" .
" diff backup: 20161207-155728F_20161208-155728D\n" .
" timestamp start/stop: 2016-12-08 15:57:28 / 2016-12-08 15:57:28\n" .
" wal start/stop: 000000010000000000000002 / 000000010000000000000002\n" .
" database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"formatText() multiple DB versions");
# Remove backup from db (prior)
#---------------------------------------------------------------------------------------------------------------------------
# Load the backup.info file
my $oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath});
my @stryPath = $oBackupInfo->list(backupRegExpGet(true));
# Remove the db prior full backup from the info file and save it
$oBackupInfo->delete($stryPath[0]);
$oBackupInfo->save();
# Remove the backup directory
storageTest()->remove($self->{strBackupPath} . "/" . $stryPath[0], {bRecurse => true});
$hyStanza = $oInfo->stanzaList($self->stanza());
$self->testResult(sub {$oInfo->formatText($hyStanza)},
"stanza: db\n status: ok\n cipher: none\n" .
"\n db (current)\n" .
" wal archive min/max (9.5-2): 000000010000000000000000 / 000000010000000000000003\n\n" .
" full backup: 20161207-155728F\n" .
" timestamp start/stop: 2016-12-07 15:57:28 / 2016-12-07 15:57:28\n" .
" wal start/stop: 000000010000000000000000 / 000000010000000000000000\n" .
" database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n\n" .
" diff backup: 20161207-155728F_20161208-155728D\n" .
" timestamp start/stop: 2016-12-08 15:57:28 / 2016-12-08 15:57:28\n" .
" wal start/stop: 000000010000000000000002 / 000000010000000000000002\n" .
" database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"db (prior) removed");
# dbArchiveSection() -- with archive
#---------------------------------------------------------------------------------------------------------------------------
$hDbInfo->{&INFO_HISTORY_ID} = 2;
$hDbInfo->{&INFO_DB_VERSION} = PG_VERSION_95;
$hDbInfo->{&INFO_SYSTEM_ID} = $self->dbSysId(PG_VERSION_95);
my $strArchiveId = PG_VERSION_95 . '-2';
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, $strArchiveId, "$self->{strArchivePath}/$strArchiveId",
PG_VERSION_95, $self->dbSysId(PG_VERSION_95))},
"{database => {id => 2}, id => 9.5-2, max => 000000010000000000000003, min => 000000010000000000000000}",
'archive, db-ver match, db-sys-id match');
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, $strArchiveId, "$self->{strArchivePath}/$strArchiveId",
PG_VERSION_95, $self->dbSysId(PG_VERSION_94))},
"{database => {id => 2}, id => 9.5-2, max => 000000010000000000000003, min => 000000010000000000000000}",
'archive, db-ver match, db-sys-id mismatch');
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, $strArchiveId, "$self->{strArchivePath}/$strArchiveId",
PG_VERSION_94, $self->dbSysId(PG_VERSION_95))},
"{database => {id => 2}, id => 9.5-2, max => 000000010000000000000003, min => 000000010000000000000000}",
'archive, db-ver mismatch, db-sys-id match');
$self->testResult(sub {$oInfo->dbArchiveSection($hDbInfo, $strArchiveId, "$self->{strArchivePath}/$strArchiveId",
PG_VERSION_94, $self->dbSysId(PG_VERSION_94))},
"{database => {id => 2}, id => 9.5-2, max => 000000010000000000000003, min => 000000010000000000000000}",
'archive, db-ver mismatch, db-sys-id mismatch');
# Set last backup run in this test set
$iLastBackup = 8;
}
################################################################################################################################
if ($self->begin("Info - encryption"))
{
# create an unencrypted and an encrypted repo and run a backup in each
#--------------------------------------------------------------------------------------------------------------------------
$self->initStanzaCreate();
$self->{oExpireTest}->backupCreate($self->stanza(), CFGOPTVAL_BACKUP_TYPE_FULL, $lBaseTime += SECONDS_PER_DAY, -1, -1);
$iLastBackup++;
my $strUnencryptBackup = ($iLastBackup < 10) ? "0$iLastBackup" : $iLastBackup;
$self->initStanzaCreate(STANZA_ENCRYPT, true);
$self->{oExpireTestEncrypt}->backupCreate(
STANZA_ENCRYPT, CFGOPTVAL_BACKUP_TYPE_FULL, $lBaseTime += SECONDS_PER_DAY, -1, -1);
$iLastBackup++;
my $strEncryptBackup = ($iLastBackup < 10) ? "0$iLastBackup" : $iLastBackup;;
# Clear the main storage repo settings
storageRepoCacheClear(STORAGE_REPO);
# Clear the stanza setting and set the main storage repo basePath to the testing repo path
$self->optionTestClear(CFGOPT_STANZA);
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath});
# Recreate the main storage repo with default unencrypted repo setting and test basePath
storageRepo();
# Test the info command without option --stanza being configured
#--------------------------------------------------------------------------------------------------------------------------
$self->configTestLoad(CFGCMD_INFO);
my $oInfo = new pgBackRest::Info();
$self->testException(sub {$oInfo->stanzaList()}, ERROR_CRYPTO,
"unable to parse '" . $self->{strBackupPathEncrypt} . "/backup.info'" .
"\nHINT: Is or was the repo encrypted?" .
"\nHINT: use option --stanza if encryption settings are different for the stanza than the global settings");
# Test the info command with option --stanza configured
#--------------------------------------------------------------------------------------------------------------------------
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->configTestLoad(CFGCMD_INFO);
$self->testResult(sub {$oInfo->formatText($oInfo->stanzaList($self->stanza()))},
"stanza: db\n status: ok\n cipher: none\n\n db (current)\n wal archive min/max (9.4-1): none present\n\n" .
" full backup: 201612" . $strUnencryptBackup . "-155728F\n" .
" timestamp start/stop: 2016-12-" . $strUnencryptBackup . " 15:57:28 / 2016-12-" . $strUnencryptBackup .
" 15:57:28\n" .
" wal start/stop: n/a\n database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"formatText() unencrypted stanza");
$self->optionTestSet(CFGOPT_STANZA, STANZA_ENCRYPT);
$self->configTestLoad(CFGCMD_INFO);
$self->testResult(sub {$oInfo->formatText($oInfo->stanzaList(STANZA_ENCRYPT))},
"stanza: " . STANZA_ENCRYPT ."\n status: ok\n cipher: aes-256-cbc\n\n db (current)" .
"\n wal archive min/max (9.4-1): none present\n\n" .
" full backup: 201612" . $strEncryptBackup . "-155728F\n" .
" timestamp start/stop: 2016-12-" . $strEncryptBackup . " 15:57:28 / 2016-12-" . $strEncryptBackup .
" 15:57:28\n" .
" wal start/stop: n/a\n database size: 0B, backup size: 0B\n" .
" repository size: 0B, repository backup size: 0B\n",
"formatText() encrypted stanza");
# Change the permissions of the backup file so it cannot be read and confirm correct error reported
#---------------------------------------------------------------------------------------------------------------------------
forceStorageMode(
storageRepo({strStanza => STANZA_ENCRYPT}), $self->{strBackupPathEncrypt} . "/backup.inf*", '220');
$self->testException(sub {$oInfo->backupList(STANZA_ENCRYPT)}, ERROR_FILE_OPEN,
"unable to open '" . $self->{strBackupPathEncrypt} . "/backup.info': Permission denied");
}
}
1;