1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-30 05:39:12 +02:00

Add --dry-run option to the expire command.

Use dry-run to see which backups/archive would be removed by the expire command without actually removing anything.
This commit is contained in:
Cynthia Shang 2020-03-16 13:56:52 -04:00 committed by David Steele
parent 4608ca473e
commit 2fa69af8da
12 changed files with 581 additions and 20 deletions

View File

@ -128,6 +128,8 @@ use constant CFGOPT_CONFIG_INCLUDE_PATH => 'config-i
push @EXPORT, qw(CFGOPT_CONFIG_INCLUDE_PATH);
use constant CFGOPT_DELTA => 'delta';
push @EXPORT, qw(CFGOPT_DELTA);
use constant CFGOPT_DRYRUN => 'dry-run';
push @EXPORT, qw(CFGOPT_DRYRUN);
use constant CFGOPT_FORCE => 'force';
push @EXPORT, qw(CFGOPT_FORCE);
use constant CFGOPT_ONLINE => 'online';
@ -760,6 +762,16 @@ my %hConfigDefine =
&CFGDEF_NEGATE => false,
},
&CFGOPT_DRYRUN =>
{
&CFGDEF_TYPE => CFGDEF_TYPE_BOOLEAN,
&CFGDEF_DEFAULT => false,
&CFGDEF_COMMAND =>
{
&CFGCMD_EXPIRE => {},
},
},
&CFGOPT_FORCE =>
{
&CFGDEF_TYPE => CFGDEF_TYPE_BOOLEAN,

View File

@ -935,6 +935,15 @@
<example>/conf/pgbackrest</example>
</option>
<!-- OPERATION - GENERAL - DRY-RUN OPTION -->
<option id="dry-run" name="Dry Run">
<summary>Execute a dry-run for the command.</summary>
<text>The <br-option>{[dash]}-dry-run</br-option> option is a command-line only option and can be passed when it is desireable to determine what modifications will be made by the command without the command actually making any modifications.</text>
<example>y</example>
</option>
<!-- OPERATION - GENERAL - RAW -->
<option id="raw" name="Raw Data">
<summary>Do not transform data.</summary>

View File

@ -24,6 +24,17 @@
<p>Note that setting <br-option>compress-type=lz4</br-option> will make new backups and archive incompatible (unrestorable) with prior versions of <backrest/>.</p>
</release-item>
<release-item>
<release-item-contributor-list>
<release-item-contributor id="cynthia.shang"/>
<release-item-contributor id="luca.ferrari"/>
</release-item-contributor-list>
<p>Add <br-option>--dry-run</br-option> option to the <cmd>expire</cmd> command.</p>
<p>Use dry-run to see which backups/archive would be removed by the <cmd>expire</cmd> command without actually removing anything.</p>
</release-item>
</release-feature-list>
<release-improvement-list>

View File

@ -1539,7 +1539,7 @@
<p>Although <backrest/> automatically removes archived WAL segments when expiring backups (the default expires WAL for full backups based on the <br-option>repo1-retention-full</br-option> option), it may be useful to expire archive more aggressively to save disk space. Note that full backups are treated as differential backups for the purpose of differential archive retention.</p>
<p>Expiring archive will never remove WAL segments that are required to make a backup consistent. However, since Point-in-Time-Recovery (PITR) only works on a continuous WAL stream, care should be taken when aggressively expiring archive outside of the normal backup expiration process.</p>
<p>Expiring archive will never remove WAL segments that are required to make a backup consistent. However, since Point-in-Time-Recovery (PITR) only works on a continuous WAL stream, care should be taken when aggressively expiring archive outside of the normal backup expiration process. To determine what will be expired without actually expiring anything, the <br-option>dry-run</br-option> option can be provided on the command line with the <cmd>expire</cmd> command.</p>
<backrest-config host="{[host-pg1]}" file="{[backrest-config-demo]}">
<title>Configure <br-option>repo1-retention-diff</br-option></title>

View File

@ -59,9 +59,14 @@ expireBackup(InfoBackup *infoBackup, String *removeBackupLabel, String *backupEx
ASSERT(removeBackupLabel != NULL);
ASSERT(backupExpired != NULL);
storageRemoveP(storageRepoWrite(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strPtr(removeBackupLabel)));
storageRemoveP(
storageRepoWrite(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strPtr(removeBackupLabel)));
// Execute the real expiration and deletion only if the dry-run option is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
{
storageRemoveP(storageRepoWrite(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strPtr(removeBackupLabel)));
storageRemoveP(
storageRepoWrite(),
strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strPtr(removeBackupLabel)));
}
// Remove the backup from the info object
infoBackupDataDelete(infoBackup, removeBackupLabel);
@ -359,8 +364,12 @@ removeExpiredArchive(InfoBackup *infoBackup)
{
String *fullPath = storagePathP(
storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s", strPtr(archiveId)));
storagePathRemoveP(storageRepoWrite(), fullPath, .recurse = true);
LOG_INFO_FMT("remove archive path: %s", strPtr(fullPath));
// Execute the real expiration and deletion only if the dry-run option is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
storagePathRemoveP(storageRepoWrite(), fullPath, .recurse = true);
}
// Continue to next directory
@ -503,9 +512,14 @@ removeExpiredArchive(InfoBackup *infoBackup)
// Remove the entire directory if all archive is expired
if (removeArchive)
{
storagePathRemoveP(
storageRepoWrite(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId),
strPtr(walPath)), .recurse = true);
// Execute the real expiration and deletion only if the dry-run mode is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
{
storagePathRemoveP(
storageRepoWrite(),
strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), strPtr(walPath)),
.recurse = true);
}
archiveExpire.total++;
archiveExpire.start = strDup(walPath);
@ -547,10 +561,15 @@ removeExpiredArchive(InfoBackup *infoBackup)
// Remove archive log if it is not used in a backup
if (removeArchive)
{
storageRemoveP(
storageRepoWrite(),
strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s/%s",
strPtr(archiveId), strPtr(walPath), strPtr(walSubPath)));
// Execute the real expiration and deletion only if the dry-run mode is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
{
storageRemoveP(
storageRepoWrite(),
strNewFmt(
STORAGE_REPO_ARCHIVE "/%s/%s/%s", strPtr(archiveId), strPtr(walPath),
strPtr(walSubPath)));
}
// Track that this archive was removed
archiveExpire.total++;
@ -610,9 +629,13 @@ removeExpiredBackup(InfoBackup *infoBackup)
{
LOG_INFO_FMT("remove expired backup %s", strPtr(strLstGet(backupList, backupIdx)));
storagePathRemoveP(
storageRepoWrite(), strNewFmt(STORAGE_REPO_BACKUP "/%s", strPtr(strLstGet(backupList, backupIdx))),
.recurse = true);
// Execute the real expiration and deletion only if the dry-run mode is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
{
storagePathRemoveP(
storageRepoWrite(), strNewFmt(STORAGE_REPO_BACKUP "/%s", strPtr(strLstGet(backupList, backupIdx))),
.recurse = true);
}
}
}
@ -640,9 +663,13 @@ cmdExpire(void)
expireFullBackup(infoBackup);
expireDiffBackup(infoBackup);
infoBackupSaveFile(
infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
// Store the new backup info only if the dry-run mode is disabled
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
{
infoBackupSaveFile(
infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
}
removeExpiredBackup(infoBackup);
removeExpiredArchive(infoBackup);

View File

@ -304,6 +304,7 @@ STRING_EXTERN(CFGOPT_CONFIG_PATH_STR, CFGOPT_CONFI
STRING_EXTERN(CFGOPT_DB_INCLUDE_STR, CFGOPT_DB_INCLUDE);
STRING_EXTERN(CFGOPT_DB_TIMEOUT_STR, CFGOPT_DB_TIMEOUT);
STRING_EXTERN(CFGOPT_DELTA_STR, CFGOPT_DELTA);
STRING_EXTERN(CFGOPT_DRY_RUN_STR, CFGOPT_DRY_RUN);
STRING_EXTERN(CFGOPT_EXCLUDE_STR, CFGOPT_EXCLUDE);
STRING_EXTERN(CFGOPT_FILTER_STR, CFGOPT_FILTER);
STRING_EXTERN(CFGOPT_FORCE_STR, CFGOPT_FORCE);
@ -633,6 +634,14 @@ static ConfigOptionData configOptionData[CFG_OPTION_TOTAL] = CONFIG_OPTION_LIST
CONFIG_OPTION_DEFINE_ID(cfgDefOptDelta)
)
//------------------------------------------------------------------------------------------------------------------------------
CONFIG_OPTION
(
CONFIG_OPTION_NAME(CFGOPT_DRY_RUN)
CONFIG_OPTION_INDEX(0)
CONFIG_OPTION_DEFINE_ID(cfgDefOptDryRun)
)
//------------------------------------------------------------------------------------------------------------------------------
CONFIG_OPTION
(

View File

@ -95,6 +95,8 @@ Option constants
STRING_DECLARE(CFGOPT_DB_TIMEOUT_STR);
#define CFGOPT_DELTA "delta"
STRING_DECLARE(CFGOPT_DELTA_STR);
#define CFGOPT_DRY_RUN "dry-run"
STRING_DECLARE(CFGOPT_DRY_RUN_STR);
#define CFGOPT_EXCLUDE "exclude"
STRING_DECLARE(CFGOPT_EXCLUDE_STR);
#define CFGOPT_FILTER "filter"
@ -406,7 +408,7 @@ Option constants
#define CFGOPT_TYPE "type"
STRING_DECLARE(CFGOPT_TYPE_STR);
#define CFG_OPTION_TOTAL 176
#define CFG_OPTION_TOTAL 177
/***********************************************************************************************************************************
Command enum
@ -461,6 +463,7 @@ typedef enum
cfgOptDbInclude,
cfgOptDbTimeout,
cfgOptDelta,
cfgOptDryRun,
cfgOptExclude,
cfgOptFilter,
cfgOptForce,

View File

@ -1108,6 +1108,37 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
)
)
// -----------------------------------------------------------------------------------------------------------------------------
CFGDEFDATA_OPTION
(
CFGDEFDATA_OPTION_NAME("dry-run")
CFGDEFDATA_OPTION_REQUIRED(true)
CFGDEFDATA_OPTION_SECTION(cfgDefSectionCommandLine)
CFGDEFDATA_OPTION_TYPE(cfgDefOptTypeBoolean)
CFGDEFDATA_OPTION_INTERNAL(false)
CFGDEFDATA_OPTION_INDEX_TOTAL(1)
CFGDEFDATA_OPTION_SECURE(false)
CFGDEFDATA_OPTION_HELP_SECTION("general")
CFGDEFDATA_OPTION_HELP_SUMMARY("Execute a dry-run for the command.")
CFGDEFDATA_OPTION_HELP_DESCRIPTION
(
"The --dry-run option is a command-line only option and can be passed when it is desireable to determine what "
"modifications will be made by the command without the command actually making any modifications."
)
CFGDEFDATA_OPTION_COMMAND_LIST
(
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdExpire)
)
CFGDEFDATA_OPTION_OPTIONAL_LIST
(
CFGDEFDATA_OPTION_OPTIONAL_DEFAULT("0")
)
)
// -----------------------------------------------------------------------------------------------------------------------------
CFGDEFDATA_OPTION
(

View File

@ -73,6 +73,7 @@ typedef enum
cfgDefOptDbInclude,
cfgDefOptDbTimeout,
cfgDefOptDelta,
cfgDefOptDryRun,
cfgDefOptExclude,
cfgDefOptFilter,
cfgDefOptForce,

View File

@ -279,6 +279,13 @@ static const struct option optionList[] =
.val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptDelta,
},
// dry-run option
// -----------------------------------------------------------------------------------------------------------------------------
{
.name = CFGOPT_DRY_RUN,
.val = PARSE_OPTION_FLAG | cfgOptDryRun,
},
// exclude option
// -----------------------------------------------------------------------------------------------------------------------------
{
@ -2380,6 +2387,7 @@ static const ConfigOption optionResolveOrder[] =
cfgOptDbInclude,
cfgOptDbTimeout,
cfgOptDelta,
cfgOptDryRun,
cfgOptExclude,
cfgOptFilter,
cfgOptHostId,

View File

@ -0,0 +1,354 @@
####################################################################################################################################
# Automatically generated by Build.pm -- do not modify directly.
####################################################################################################################################
package pgBackRest::LibCAuto;
use strict;
use warnings;
# Configuration option value constants
sub libcAutoConstant
{
return
{
CFGOPTVAL_INFO_OUTPUT_TEXT => 'text',
CFGOPTVAL_INFO_OUTPUT_JSON => 'json',
CFGOPTVAL_LS_OUTPUT_TEXT => 'text',
CFGOPTVAL_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
{
checksum =>
[
'pageChecksum',
],
config =>
[
'CFGOPTVAL_INFO_OUTPUT_TEXT',
'CFGOPTVAL_INFO_OUTPUT_JSON',
'CFGOPTVAL_LS_OUTPUT_TEXT',
'CFGOPTVAL_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_LS',
'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_CMD_SSH',
'CFGOPT_COMPRESS',
'CFGOPT_COMPRESS_LEVEL',
'CFGOPT_COMPRESS_LEVEL_NETWORK',
'CFGOPT_CONFIG',
'CFGOPT_CONFIG_INCLUDE_PATH',
'CFGOPT_CONFIG_PATH',
'CFGOPT_DB_INCLUDE',
'CFGOPT_DB_TIMEOUT',
'CFGOPT_DELTA',
'CFGOPT_DRY_RUN',
'CFGOPT_EXCLUDE',
'CFGOPT_FILTER',
'CFGOPT_FORCE',
'CFGOPT_HOST_ID',
'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_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',
],
crypto =>
[
'cryptoHashOne',
],
debug =>
[
'libcUvSize',
],
storage =>
[
'storageRepoFree',
],
test =>
[
'cfgParseTest',
],
}
}
1;

View File

@ -716,6 +716,7 @@ testRun(void)
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
// Write backup.manifest so infoBackup reconstruct produces same results as backup.info on disk
@ -741,6 +742,64 @@ testRun(void)
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F_20181119-152500I/" BACKUP_MANIFEST_FILE,
strPtr(backupStanzaPath))), BUFSTRDEF("tmp"));
TEST_RESULT_VOID(cmdExpire(), "expire (dry-run) do not remove last backup in archive sub path or sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strPtr(archiveStanzaPath), "9.4-1/0000000100000000")),
true, " archive sub path not removed");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath))),
true, " backup not removed");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F");
// Save a copy of the info files for a later test
storageCopy(
storageNewReadP(storageTest, backupInfoFileName),
storageNewWriteP(storageTest, strNewFmt("%s%s", strPtr(backupInfoFileName), ".save")));
storageCopy(
storageNewReadP(storageTest, archiveInfoFileName),
storageNewWriteP(storageTest, strNewFmt("%s%s", strPtr(archiveInfoFileName), ".save")));
//--------------------------------------------------------------------------------------------------------------------------
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
harnessCfgLoad(cfgCmdBackup, argList);
TEST_RESULT_VOID(cmdExpire(), "via backup command: expire last backup in archive sub path and remove sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strPtr(archiveStanzaPath), "9.4-1/0000000100000000")),
false, " archive sub path removed");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F");
//--------------------------------------------------------------------------------------------------------------------------
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
harnessCfgLoad(cfgCmdExpire, argList);
// Restore info files from a previous test
storageCopy(
storageNewReadP(storageTest, strNewFmt("%s%s", strPtr(backupInfoFileName), ".save")),
storageNewWriteP(storageTest, backupInfoFileName));
storageCopy(
storageNewReadP(storageTest, strNewFmt("%s%s", strPtr(archiveInfoFileName), ".save")),
storageNewWriteP(storageTest, archiveInfoFileName));
// Write out manifest and archive that will be removed
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath))),
BUFSTRDEF("tmp"));
archiveGenerate(storageTest, archiveStanzaPath, 2, 2, "9.4-1", "0000000100000000");
TEST_RESULT_VOID(cmdExpire(), "expire last backup in archive sub path and remove sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strPtr(archiveStanzaPath), "9.4-1/0000000100000000")),
@ -752,9 +811,37 @@ testRun(void)
//--------------------------------------------------------------------------------------------------------------------------
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire last backup in archive path and remove path");
TEST_RESULT_VOID(cmdExpire(), "expire (dry-run) - log expired backups and archive path to remove");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strPtr(archiveStanzaPath), "9.4-1")),
true, " archive path not removed");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strPtr(backupStanzaPath)))),
true, " backup not removed");
harnessLogResult(strPtr(strNewFmt(
"P00 INFO: expire full backup set: 20181119-152800F, 20181119-152800F_20181119-152152D, "
"20181119-152800F_20181119-152155I, 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152152D\n"
"P00 INFO: remove expired backup 20181119-152800F\n"
"P00 INFO: remove archive path: %s/%s/9.4-1", testPath(), strPtr(archiveStanzaPath))));
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
harnessCfgLoad(cfgCmdBackup, argList);
TEST_RESULT_VOID(cmdExpire(), "via backup command: expire backups and remove archive path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strPtr(archiveStanzaPath), "9.4-1")),
false, " archive path removed");
@ -774,6 +861,15 @@ testRun(void)
strLstJoin(strLstSort(infoBackupDataLabelList(infoBackup, NULL), sortOrderAsc), ", "),
"20181119-152900F, 20181119-152900F_20181119-152500I", " remaining current backups correct");
archiveGenerate(storageTest, archiveStanzaPath, 1, 1, "9.4-1", "0000000100000000");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire remove archive path");
harnessLogResult(
strPtr(strNewFmt("P00 INFO: remove archive path: %s/%s/9.4-1", testPath(), strPtr(archiveStanzaPath))));
//--------------------------------------------------------------------------------------------------------------------------
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(