You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-13 01:00:23 +02:00
Add info command set option for detailed text output.
The additional details include databases that can be used for selective restore and a list of tablespaces and symlinks with their default destinations. This information is not included in the JSON output because it requires reading the manifest which is too IO intensive to do for all manifests. We plan to include this information for JSON in a future release.
This commit is contained in:
committed by
David Steele
parent
33ec5a3aac
commit
f96c54c4ba
@ -823,7 +823,15 @@ my %hConfigDefine =
|
|||||||
&CFGCMD_RESTORE =>
|
&CFGCMD_RESTORE =>
|
||||||
{
|
{
|
||||||
&CFGDEF_DEFAULT => 'latest',
|
&CFGDEF_DEFAULT => 'latest',
|
||||||
}
|
},
|
||||||
|
&CFGCMD_INFO =>
|
||||||
|
{
|
||||||
|
&CFGDEF_REQUIRED => false,
|
||||||
|
&CFGDEF_DEPEND =>
|
||||||
|
{
|
||||||
|
&CFGDEF_DEPEND_OPTION => CFGOPT_STANZA,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1135,6 +1135,13 @@
|
|||||||
|
|
||||||
<example>json</example>
|
<example>json</example>
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
|
<option id="set" name="Set">
|
||||||
|
<summary>Backup set to detail.</summary>
|
||||||
|
|
||||||
|
<text>Details include a list of databases (with OIDs) in the backup set (excluding template databases), tablespaces (with OIDs) with the destination where they will be restored by default, and symlinks with the destination where they will be restored when <setting>--link-all</setting> is specified.</text>
|
||||||
|
<example>20150131-153358F_20150131-153401I</example>
|
||||||
|
</option>
|
||||||
</option-list>
|
</option-list>
|
||||||
|
|
||||||
<command-example-list>
|
<command-example-list>
|
||||||
|
@ -15,6 +15,16 @@
|
|||||||
<release date="XXXX-XX-XX" version="2.18dev" title="UNDER DEVELOPMENT">
|
<release date="XXXX-XX-XX" version="2.18dev" title="UNDER DEVELOPMENT">
|
||||||
<release-core-list>
|
<release-core-list>
|
||||||
<release-feature-list>
|
<release-feature-list>
|
||||||
|
<release-item>
|
||||||
|
<release-item-contributor-list>
|
||||||
|
<release-item-contributor id="cynthia.shang"/>
|
||||||
|
</release-item-contributor-list>
|
||||||
|
|
||||||
|
<p>Add <cmd>info</cmd> command <br-option>set</br-option> option for detailed text output.</p>
|
||||||
|
|
||||||
|
<p>The additional details include databases that can be used for selective restore and a list of tablespaces and symlinks with their default destinations.</p>
|
||||||
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<release-item-contributor-list>
|
<release-item-contributor-list>
|
||||||
<release-item-reviewer id="cynthia.shang"/>
|
<release-item-reviewer id="cynthia.shang"/>
|
||||||
|
@ -1752,6 +1752,22 @@
|
|||||||
</execute>
|
</execute>
|
||||||
</execute-list>
|
</execute-list>
|
||||||
|
|
||||||
|
<p>If the database to restore is not known, use the <cmd>info</cmd> command <br-option>set</br-option> option to discover databases that are part of the backup set.</p>
|
||||||
|
|
||||||
|
<execute-list host="{[host-pg1]}">
|
||||||
|
<title>Show database list for backup</title>
|
||||||
|
|
||||||
|
<execute user="postgres" show="n" variable-key="backup-last-incr">
|
||||||
|
<exe-cmd>{[cmd-backup-last]}</exe-cmd>
|
||||||
|
</execute>
|
||||||
|
|
||||||
|
<execute user="postgres">
|
||||||
|
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]}
|
||||||
|
{[dash]}-set={[backup-last-incr]} info</exe-cmd>
|
||||||
|
<exe-highlight>database list</exe-highlight>
|
||||||
|
</execute>
|
||||||
|
</execute-list>
|
||||||
|
|
||||||
<p>Stop the cluster and restore only the test2 database. Built-in databases (<id>template0</id>, <id>template1</id>, and <id>postgres</id>) are always restored.</p>
|
<p>Stop the cluster and restore only the test2 database. Built-in databases (<id>template0</id>, <id>template1</id>, and <id>postgres</id>) are always restored.</p>
|
||||||
|
|
||||||
<execute-list host="{[host-pg1]}">
|
<execute-list host="{[host-pg1]}">
|
||||||
|
@ -269,7 +269,7 @@ command/expire/expire.o: command/expire/expire.c build.auto.h command/archive/co
|
|||||||
command/help/help.o: command/help/help.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h version.h
|
command/help/help.o: command/help/help.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h version.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/help/help.c -o command/help/help.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/help/help.c -o command/help/help.o
|
||||||
|
|
||||||
command/info/info.o: command/info/info.c build.auto.h command/archive/common.h command/info/info.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h perl/exec.h postgres/interface.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/info/info.o: command/info/info.c build.auto.h command/archive/common.h command/backup/common.h command/info/info.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h perl/exec.h postgres/interface.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/info/info.c -o command/info/info.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/info/info.c -o command/info/info.o
|
||||||
|
|
||||||
command/local/local.o: command/local/local.c build.auto.h command/archive/get/protocol.h command/archive/push/protocol.h command/backup/protocol.h command/restore/protocol.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleRead.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/protocol.h protocol/client.h protocol/command.h protocol/helper.h protocol/server.h
|
command/local/local.o: command/local/local.c build.auto.h command/archive/get/protocol.h command/archive/push/protocol.h command/backup/protocol.h command/restore/protocol.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleRead.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/protocol.h protocol/client.h protocol/command.h protocol/helper.h protocol/server.h
|
||||||
|
@ -21,6 +21,7 @@ Info Command
|
|||||||
#include "info/infoArchive.h"
|
#include "info/infoArchive.h"
|
||||||
#include "info/infoBackup.h"
|
#include "info/infoBackup.h"
|
||||||
#include "info/infoPg.h"
|
#include "info/infoPg.h"
|
||||||
|
#include "info/manifest.h"
|
||||||
#include "perl/exec.h"
|
#include "perl/exec.h"
|
||||||
#include "postgres/interface.h"
|
#include "postgres/interface.h"
|
||||||
#include "storage/helper.h"
|
#include "storage/helper.h"
|
||||||
@ -36,10 +37,13 @@ VARIANT_STRDEF_STATIC(ARCHIVE_KEY_MAX_VAR, "max");
|
|||||||
VARIANT_STRDEF_STATIC(BACKREST_KEY_FORMAT_VAR, "format");
|
VARIANT_STRDEF_STATIC(BACKREST_KEY_FORMAT_VAR, "format");
|
||||||
VARIANT_STRDEF_STATIC(BACKREST_KEY_VERSION_VAR, "version");
|
VARIANT_STRDEF_STATIC(BACKREST_KEY_VERSION_VAR, "version");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_BACKREST_VAR, "backrest");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_BACKREST_VAR, "backrest");
|
||||||
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_DATABASE_REF_VAR, "database-ref");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_INFO_VAR, "info");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_INFO_VAR, "info");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_LABEL_VAR, "label");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_LABEL_VAR, "label");
|
||||||
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_LINK_VAR, "link");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_PRIOR_VAR, "prior");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_PRIOR_VAR, "prior");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_REFERENCE_VAR, "reference");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_REFERENCE_VAR, "reference");
|
||||||
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_TABLESPACE_VAR, "tablespace");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_TIMESTAMP_VAR, "timestamp");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_TIMESTAMP_VAR, "timestamp");
|
||||||
VARIANT_STRDEF_STATIC(BACKUP_KEY_TYPE_VAR, "type");
|
VARIANT_STRDEF_STATIC(BACKUP_KEY_TYPE_VAR, "type");
|
||||||
VARIANT_STRDEF_STATIC(DB_KEY_ID_VAR, "id");
|
VARIANT_STRDEF_STATIC(DB_KEY_ID_VAR, "id");
|
||||||
@ -49,12 +53,14 @@ VARIANT_STRDEF_STATIC(INFO_KEY_REPOSITORY_VAR, "repository"
|
|||||||
VARIANT_STRDEF_STATIC(KEY_ARCHIVE_VAR, "archive");
|
VARIANT_STRDEF_STATIC(KEY_ARCHIVE_VAR, "archive");
|
||||||
VARIANT_STRDEF_STATIC(KEY_DATABASE_VAR, "database");
|
VARIANT_STRDEF_STATIC(KEY_DATABASE_VAR, "database");
|
||||||
VARIANT_STRDEF_STATIC(KEY_DELTA_VAR, "delta");
|
VARIANT_STRDEF_STATIC(KEY_DELTA_VAR, "delta");
|
||||||
|
VARIANT_STRDEF_STATIC(KEY_DESTINATION_VAR, "destination");
|
||||||
|
VARIANT_STRDEF_STATIC(KEY_NAME_VAR, "name");
|
||||||
|
VARIANT_STRDEF_STATIC(KEY_OID_VAR, "oid");
|
||||||
VARIANT_STRDEF_STATIC(KEY_SIZE_VAR, "size");
|
VARIANT_STRDEF_STATIC(KEY_SIZE_VAR, "size");
|
||||||
VARIANT_STRDEF_STATIC(KEY_START_VAR, "start");
|
VARIANT_STRDEF_STATIC(KEY_START_VAR, "start");
|
||||||
VARIANT_STRDEF_STATIC(KEY_STOP_VAR, "stop");
|
VARIANT_STRDEF_STATIC(KEY_STOP_VAR, "stop");
|
||||||
VARIANT_STRDEF_STATIC(STANZA_KEY_BACKUP_VAR, "backup");
|
VARIANT_STRDEF_STATIC(STANZA_KEY_BACKUP_VAR, "backup");
|
||||||
VARIANT_STRDEF_STATIC(STANZA_KEY_CIPHER_VAR, "cipher");
|
VARIANT_STRDEF_STATIC(STANZA_KEY_CIPHER_VAR, "cipher");
|
||||||
VARIANT_STRDEF_STATIC(STANZA_KEY_NAME_VAR, "name");
|
|
||||||
VARIANT_STRDEF_STATIC(STANZA_KEY_STATUS_VAR, "status");
|
VARIANT_STRDEF_STATIC(STANZA_KEY_STATUS_VAR, "status");
|
||||||
VARIANT_STRDEF_STATIC(STANZA_KEY_DB_VAR, "db");
|
VARIANT_STRDEF_STATIC(STANZA_KEY_DB_VAR, "db");
|
||||||
VARIANT_STRDEF_STATIC(STATUS_KEY_CODE_VAR, "code");
|
VARIANT_STRDEF_STATIC(STATUS_KEY_CODE_VAR, "code");
|
||||||
@ -188,11 +194,12 @@ archiveDbList(const String *stanza, const InfoPgData *pgData, VariantList *archi
|
|||||||
For each current backup in the backup.info file of the stanza, set the data for the backup section.
|
For each current backup in the backup.info file of the stanza, set the data for the backup section.
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static void
|
static void
|
||||||
backupList(VariantList *backupSection, InfoBackup *info)
|
backupList(VariantList *backupSection, InfoBackup *info, const String *backupLabel)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(VARIANT, backupSection);
|
FUNCTION_TEST_PARAM(VARIANT, backupSection);
|
||||||
FUNCTION_TEST_PARAM(INFO_BACKUP, info);
|
FUNCTION_TEST_PARAM(INFO_BACKUP, info);
|
||||||
|
FUNCTION_TEST_PARAM(STRING, backupLabel);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(backupSection != NULL);
|
ASSERT(backupSection != NULL);
|
||||||
@ -255,10 +262,79 @@ backupList(VariantList *backupSection, InfoBackup *info)
|
|||||||
kvAdd(timeInfo, KEY_START_VAR, VARUINT64(backupData.backupTimestampStart));
|
kvAdd(timeInfo, KEY_START_VAR, VARUINT64(backupData.backupTimestampStart));
|
||||||
kvAdd(timeInfo, KEY_STOP_VAR, VARUINT64(backupData.backupTimestampStop));
|
kvAdd(timeInfo, KEY_STOP_VAR, VARUINT64(backupData.backupTimestampStop));
|
||||||
|
|
||||||
|
// If a backup label was specified and this is that label, then get the manifest
|
||||||
|
if (backupLabel != NULL && strEq(backupData.backupLabel, backupLabel))
|
||||||
|
{
|
||||||
|
// Load the manifest file
|
||||||
|
const Manifest *manifest = manifestLoadFile(
|
||||||
|
storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strPtr(backupLabel)),
|
||||||
|
cipherType(cfgOptionStr(cfgOptRepoCipherType)), infoPgCipherPass(infoBackupPg(info)));
|
||||||
|
|
||||||
|
// Get the list of databases in this backup
|
||||||
|
VariantList *databaseSection = varLstNew();
|
||||||
|
|
||||||
|
for (unsigned int dbIdx = 0; dbIdx < manifestDbTotal(manifest); dbIdx++)
|
||||||
|
{
|
||||||
|
const ManifestDb *db = manifestDb(manifest, dbIdx);
|
||||||
|
|
||||||
|
// Do not display template databases
|
||||||
|
if (db->id > db->lastSystemId)
|
||||||
|
{
|
||||||
|
Variant *database = varNewKv(kvNew());
|
||||||
|
kvPut(varKv(database), KEY_NAME_VAR, VARSTR(db->name));
|
||||||
|
kvPut(varKv(database), KEY_OID_VAR, VARUINT64(db->id));
|
||||||
|
varLstAdd(databaseSection, database);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the database section even if none found
|
||||||
|
kvPut(varKv(backupInfo), BACKUP_KEY_DATABASE_REF_VAR, varNewVarLst(databaseSection));
|
||||||
|
|
||||||
|
// Get symlinks and tablespaces
|
||||||
|
VariantList *linkSection = varLstNew();
|
||||||
|
VariantList *tablespaceSection = varLstNew();
|
||||||
|
|
||||||
|
for (unsigned int targetIdx = 0; targetIdx < manifestTargetTotal(manifest); targetIdx++)
|
||||||
|
{
|
||||||
|
const ManifestTarget *target = manifestTarget(manifest, targetIdx);
|
||||||
|
Variant *link = varNewKv(kvNew());
|
||||||
|
Variant *tablespace = varNewKv(kvNew());
|
||||||
|
|
||||||
|
if (target->type == manifestTargetTypeLink)
|
||||||
|
{
|
||||||
|
if (target->tablespaceName != NULL)
|
||||||
|
{
|
||||||
|
kvPut(varKv(tablespace), KEY_NAME_VAR, VARSTR(target->tablespaceName));
|
||||||
|
kvPut(varKv(tablespace), KEY_DESTINATION_VAR, VARSTR(target->path));
|
||||||
|
kvPut(varKv(tablespace), KEY_OID_VAR, VARUINT64(target->tablespaceId));
|
||||||
|
varLstAdd(tablespaceSection, tablespace);
|
||||||
|
}
|
||||||
|
else if (target->file != NULL)
|
||||||
|
{
|
||||||
|
kvPut(varKv(link), KEY_NAME_VAR, varNewStr(target->file));
|
||||||
|
kvPut(
|
||||||
|
varKv(link), KEY_DESTINATION_VAR, varNewStr(strNewFmt("%s/%s", strPtr(target->path),
|
||||||
|
strPtr(target->file))));
|
||||||
|
varLstAdd(linkSection, link);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kvPut(varKv(link), KEY_NAME_VAR, VARSTR(manifestPgPath(target->name)));
|
||||||
|
kvPut(varKv(link), KEY_DESTINATION_VAR, VARSTR(target->path));
|
||||||
|
varLstAdd(linkSection, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kvPut(varKv(backupInfo), BACKUP_KEY_LINK_VAR, (varLstSize(linkSection) > 0 ? varNewVarLst(linkSection) : NULL));
|
||||||
|
kvPut(
|
||||||
|
varKv(backupInfo), BACKUP_KEY_TABLESPACE_VAR,
|
||||||
|
(varLstSize(tablespaceSection) > 0 ? varNewVarLst(tablespaceSection) : NULL));
|
||||||
|
}
|
||||||
|
|
||||||
varLstAdd(backupSection, backupInfo);
|
varLstAdd(backupSection, backupInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,11 +342,12 @@ backupList(VariantList *backupSection, InfoBackup *info)
|
|||||||
Set the stanza data for each stanza found in the repo.
|
Set the stanza data for each stanza found in the repo.
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static VariantList *
|
static VariantList *
|
||||||
stanzaInfoList(const String *stanza, StringList *stanzaList)
|
stanzaInfoList(const String *stanza, StringList *stanzaList, const String *backupLabel)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(STRING, stanza);
|
FUNCTION_TEST_PARAM(STRING, stanza);
|
||||||
FUNCTION_TEST_PARAM(STRING_LIST, stanzaList);
|
FUNCTION_TEST_PARAM(STRING_LIST, stanzaList);
|
||||||
|
FUNCTION_TEST_PARAM(STRING, backupLabel);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(stanzaList != NULL);
|
ASSERT(stanzaList != NULL);
|
||||||
@ -326,8 +403,8 @@ stanzaInfoList(const String *stanza, StringList *stanzaList)
|
|||||||
}
|
}
|
||||||
TRY_END();
|
TRY_END();
|
||||||
|
|
||||||
// Set the stanza name and cipher
|
// Set the stanza name and cipher. Since we may not be going through the config parsing system, default the cipher to NONE.
|
||||||
kvPut(varKv(stanzaInfo), STANZA_KEY_NAME_VAR, VARSTR(stanzaListName));
|
kvPut(varKv(stanzaInfo), KEY_NAME_VAR, VARSTR(stanzaListName));
|
||||||
kvPut(varKv(stanzaInfo), STANZA_KEY_CIPHER_VAR, VARSTR(CIPHER_TYPE_NONE_STR));
|
kvPut(varKv(stanzaInfo), STANZA_KEY_CIPHER_VAR, VARSTR(CIPHER_TYPE_NONE_STR));
|
||||||
|
|
||||||
// If the backup.info file exists, get the database history information (newest to oldest) and corresponding archive
|
// If the backup.info file exists, get the database history information (newest to oldest) and corresponding archive
|
||||||
@ -359,7 +436,7 @@ stanzaInfoList(const String *stanza, StringList *stanzaList)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get data for all existing backups for this stanza
|
// Get data for all existing backups for this stanza
|
||||||
backupList(backupSection, info);
|
backupList(backupSection, info, backupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the database history, backup and archive sections to the stanza info
|
// Add the database history, backup and archive sections to the stanza info
|
||||||
@ -386,7 +463,7 @@ stanzaInfoList(const String *stanza, StringList *stanzaList)
|
|||||||
{
|
{
|
||||||
Variant *stanzaInfo = varNewKv(kvNew());
|
Variant *stanzaInfo = varNewKv(kvNew());
|
||||||
|
|
||||||
kvPut(varKv(stanzaInfo), STANZA_KEY_NAME_VAR, VARSTR(stanza));
|
kvPut(varKv(stanzaInfo), KEY_NAME_VAR, VARSTR(stanza));
|
||||||
|
|
||||||
kvPut(varKv(stanzaInfo), STANZA_KEY_DB_VAR, varNewVarLst(varLstNew()));
|
kvPut(varKv(stanzaInfo), STANZA_KEY_DB_VAR, varNewVarLst(varLstNew()));
|
||||||
kvPut(varKv(stanzaInfo), STANZA_KEY_BACKUP_VAR, varNewVarLst(varLstNew()));
|
kvPut(varKv(stanzaInfo), STANZA_KEY_BACKUP_VAR, varNewVarLst(varLstNew()));
|
||||||
@ -402,11 +479,12 @@ stanzaInfoList(const String *stanza, StringList *stanzaList)
|
|||||||
Format the text output for each database of the stanza.
|
Format the text output for each database of the stanza.
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static void
|
static void
|
||||||
formatTextDb(const KeyValue *stanzaInfo, String *resultStr)
|
formatTextDb(const KeyValue *stanzaInfo, String *resultStr, const String *backupLabel)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(KEY_VALUE, stanzaInfo);
|
FUNCTION_TEST_PARAM(KEY_VALUE, stanzaInfo);
|
||||||
FUNCTION_TEST_PARAM(STRING, resultStr);
|
FUNCTION_TEST_PARAM(STRING, resultStr);
|
||||||
|
FUNCTION_TEST_PARAM(STRING, backupLabel);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(stanzaInfo != NULL);
|
ASSERT(stanzaInfo != NULL);
|
||||||
@ -420,6 +498,29 @@ formatTextDb(const KeyValue *stanzaInfo, String *resultStr)
|
|||||||
{
|
{
|
||||||
KeyValue *pgInfo = varKv(varLstGet(dbSection, dbIdx));
|
KeyValue *pgInfo = varKv(varLstGet(dbSection, dbIdx));
|
||||||
unsigned int dbId = varUInt(kvGet(pgInfo, DB_KEY_ID_VAR));
|
unsigned int dbId = varUInt(kvGet(pgInfo, DB_KEY_ID_VAR));
|
||||||
|
bool backupInDb = false;
|
||||||
|
|
||||||
|
// If a backup label was specified then see if it exists for this database
|
||||||
|
if (backupLabel != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int backupIdx = 0; backupIdx < varLstSize(backupSection); backupIdx++)
|
||||||
|
{
|
||||||
|
KeyValue *backupInfo = varKv(varLstGet(backupSection, backupIdx));
|
||||||
|
KeyValue *backupDbInfo = varKv(kvGet(backupInfo, KEY_DATABASE_VAR));
|
||||||
|
unsigned int backupDbId = varUInt(kvGet(backupDbInfo, DB_KEY_ID_VAR));
|
||||||
|
|
||||||
|
// If the backup requested is in this database then break from the loop
|
||||||
|
if (backupDbId == dbId)
|
||||||
|
{
|
||||||
|
backupInDb = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If backup label was requested but was not found in this database then continue to next database
|
||||||
|
if (backupLabel != NULL && !backupInDb)
|
||||||
|
continue;
|
||||||
|
|
||||||
// List is ordered so 0 is always the current DB index
|
// List is ordered so 0 is always the current DB index
|
||||||
if (dbIdx == varLstSize(dbSection) - 1)
|
if (dbIdx == varLstSize(dbSection) - 1)
|
||||||
@ -461,6 +562,10 @@ formatTextDb(const KeyValue *stanzaInfo, String *resultStr)
|
|||||||
KeyValue *backupDbInfo = varKv(kvGet(backupInfo, KEY_DATABASE_VAR));
|
KeyValue *backupDbInfo = varKv(kvGet(backupInfo, KEY_DATABASE_VAR));
|
||||||
unsigned int backupDbId = varUInt(kvGet(backupDbInfo, DB_KEY_ID_VAR));
|
unsigned int backupDbId = varUInt(kvGet(backupDbInfo, DB_KEY_ID_VAR));
|
||||||
|
|
||||||
|
// If a backup label was specified but this is not it then continue
|
||||||
|
if (backupLabel != NULL && !strEq(varStr(kvGet(backupInfo, BACKUP_KEY_LABEL_VAR)), backupLabel))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (backupDbId == dbId)
|
if (backupDbId == dbId)
|
||||||
{
|
{
|
||||||
strCatFmt(
|
strCatFmt(
|
||||||
@ -512,6 +617,70 @@ formatTextDb(const KeyValue *stanzaInfo, String *resultStr)
|
|||||||
StringList *referenceList = strLstNewVarLst(varVarLst(kvGet(backupInfo, BACKUP_KEY_REFERENCE_VAR)));
|
StringList *referenceList = strLstNewVarLst(varVarLst(kvGet(backupInfo, BACKUP_KEY_REFERENCE_VAR)));
|
||||||
strCatFmt(backupResult, " backup reference list: %s\n", strPtr(strLstJoin(referenceList, ", ")));
|
strCatFmt(backupResult, " backup reference list: %s\n", strPtr(strLstJoin(referenceList, ", ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kvGet(backupInfo, BACKUP_KEY_DATABASE_REF_VAR) != NULL)
|
||||||
|
{
|
||||||
|
VariantList *dbSection = kvGetList(backupInfo, BACKUP_KEY_DATABASE_REF_VAR);
|
||||||
|
strCat(backupResult, " database list:");
|
||||||
|
|
||||||
|
if (varLstSize(dbSection) == 0)
|
||||||
|
strCat(backupResult, " none\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (unsigned int dbIdx = 0; dbIdx < varLstSize(dbSection); dbIdx++)
|
||||||
|
{
|
||||||
|
KeyValue *db = varKv(varLstGet(dbSection, dbIdx));
|
||||||
|
strCatFmt(
|
||||||
|
backupResult, " %s (%s)", strPtr(varStr(kvGet(db, KEY_NAME_VAR))),
|
||||||
|
strPtr(varStrForce(kvGet(db, KEY_OID_VAR))));
|
||||||
|
|
||||||
|
if (dbIdx != varLstSize(dbSection) - 1)
|
||||||
|
strCat(backupResult, ",");
|
||||||
|
}
|
||||||
|
strCat(backupResult, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kvGet(backupInfo, BACKUP_KEY_LINK_VAR) != NULL)
|
||||||
|
{
|
||||||
|
VariantList *linkSection = kvGetList(backupInfo, BACKUP_KEY_LINK_VAR);
|
||||||
|
strCat(backupResult, " symlinks:\n");
|
||||||
|
|
||||||
|
for (unsigned int linkIdx = 0; linkIdx < varLstSize(linkSection); linkIdx++)
|
||||||
|
{
|
||||||
|
KeyValue *link = varKv(varLstGet(linkSection, linkIdx));
|
||||||
|
|
||||||
|
strCatFmt(
|
||||||
|
backupResult, " %s => %s", strPtr(varStr(kvGet(link, KEY_NAME_VAR))),
|
||||||
|
strPtr(varStr(kvGet(link, KEY_DESTINATION_VAR))));
|
||||||
|
|
||||||
|
if (linkIdx != varLstSize(linkSection) - 1)
|
||||||
|
strCat(backupResult, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
strCat(backupResult, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kvGet(backupInfo, BACKUP_KEY_TABLESPACE_VAR) != NULL)
|
||||||
|
{
|
||||||
|
VariantList *tablespaceSection = kvGetList(backupInfo, BACKUP_KEY_TABLESPACE_VAR);
|
||||||
|
strCat(backupResult, " tablespaces:\n");
|
||||||
|
|
||||||
|
for (unsigned int tblIdx = 0; tblIdx < varLstSize(tablespaceSection); tblIdx++)
|
||||||
|
{
|
||||||
|
KeyValue *tablespace = varKv(varLstGet(tablespaceSection, tblIdx));
|
||||||
|
|
||||||
|
strCatFmt(
|
||||||
|
backupResult, " %s (%s) => %s", strPtr(varStr(kvGet(tablespace, KEY_NAME_VAR))),
|
||||||
|
strPtr(varStrForce(kvGet(tablespace, KEY_OID_VAR))),
|
||||||
|
strPtr(varStr(kvGet(tablespace, KEY_DESTINATION_VAR))));
|
||||||
|
|
||||||
|
if (tblIdx != varLstSize(tablespaceSection) - 1)
|
||||||
|
strCat(backupResult, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
strCat(backupResult, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +715,26 @@ infoRender(void)
|
|||||||
// Get stanza if specified
|
// Get stanza if specified
|
||||||
const String *stanza = cfgOptionTest(cfgOptStanza) ? cfgOptionStr(cfgOptStanza) : NULL;
|
const String *stanza = cfgOptionTest(cfgOptStanza) ? cfgOptionStr(cfgOptStanza) : NULL;
|
||||||
|
|
||||||
|
// Get the backup label if specified
|
||||||
|
const String *backupLabel = cfgOptionTest(cfgOptSet) ? cfgOptionStr(cfgOptSet) : NULL;
|
||||||
|
|
||||||
|
// Get the repo storage in case it is remote and encryption settings need to be pulled down
|
||||||
|
storageRepo();
|
||||||
|
|
||||||
|
// If a backup set was specified, see if the manifest exists
|
||||||
|
if (backupLabel != NULL)
|
||||||
|
{
|
||||||
|
if (!strEq(cfgOptionStr(cfgOptOutput), CFGOPTVAL_INFO_OUTPUT_TEXT_STR))
|
||||||
|
THROW(ConfigError, "option 'set' is currently only valid for text output");
|
||||||
|
|
||||||
|
if (!storageExistsNP(storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strPtr(backupLabel))))
|
||||||
|
{
|
||||||
|
THROW_FMT(
|
||||||
|
FileMissingError, "manifest does not exist for backup '%s'\n"
|
||||||
|
"HINT: is the backup listed when running the info command with --stanza option only?", strPtr(backupLabel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get a list of stanzas in the backup directory.
|
// Get a list of stanzas in the backup directory.
|
||||||
StringList *stanzaList = storageListNP(storageRepo(), STORAGE_PATH_BACKUP_STR);
|
StringList *stanzaList = storageListNP(storageRepo(), STORAGE_PATH_BACKUP_STR);
|
||||||
VariantList *infoList = varLstNew();
|
VariantList *infoList = varLstNew();
|
||||||
@ -553,7 +742,7 @@ infoRender(void)
|
|||||||
|
|
||||||
// If the backup storage exists, then search for and process any stanzas
|
// If the backup storage exists, then search for and process any stanzas
|
||||||
if (strLstSize(stanzaList) > 0)
|
if (strLstSize(stanzaList) > 0)
|
||||||
infoList = stanzaInfoList(stanza, stanzaList);
|
infoList = stanzaInfoList(stanza, stanzaList, backupLabel);
|
||||||
|
|
||||||
// Format text output
|
// Format text output
|
||||||
if (strEq(cfgOptionStr(cfgOptOutput), CFGOPTVAL_INFO_OUTPUT_TEXT_STR))
|
if (strEq(cfgOptionStr(cfgOptOutput), CFGOPTVAL_INFO_OUTPUT_TEXT_STR))
|
||||||
@ -571,7 +760,7 @@ infoRender(void)
|
|||||||
|
|
||||||
// Stanza name and status
|
// Stanza name and status
|
||||||
strCatFmt(
|
strCatFmt(
|
||||||
resultStr, "stanza: %s\n status: ", strPtr(varStr(kvGet(stanzaInfo, STANZA_KEY_NAME_VAR))));
|
resultStr, "stanza: %s\n status: ", strPtr(varStr(kvGet(stanzaInfo, KEY_NAME_VAR))));
|
||||||
|
|
||||||
// If an error has occurred, provide the information that is available and move onto next stanza
|
// If an error has occurred, provide the information that is available and move onto next stanza
|
||||||
KeyValue *stanzaStatus = varKv(kvGet(stanzaInfo, STANZA_KEY_STATUS_VAR));
|
KeyValue *stanzaStatus = varKv(kvGet(stanzaInfo, STANZA_KEY_STATUS_VAR));
|
||||||
@ -591,7 +780,7 @@ infoRender(void)
|
|||||||
|
|
||||||
// If there is a backup.info file but no backups, then process the archive info
|
// If there is a backup.info file but no backups, then process the archive info
|
||||||
if (statusCode == INFO_STANZA_STATUS_CODE_NO_BACKUP)
|
if (statusCode == INFO_STANZA_STATUS_CODE_NO_BACKUP)
|
||||||
formatTextDb(stanzaInfo, resultStr);
|
formatTextDb(stanzaInfo, resultStr, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -603,7 +792,7 @@ infoRender(void)
|
|||||||
strCatFmt(resultStr, " cipher: %s\n",
|
strCatFmt(resultStr, " cipher: %s\n",
|
||||||
strPtr(varStr(kvGet(stanzaInfo, STANZA_KEY_CIPHER_VAR))));
|
strPtr(varStr(kvGet(stanzaInfo, STANZA_KEY_CIPHER_VAR))));
|
||||||
|
|
||||||
formatTextDb(stanzaInfo, resultStr);
|
formatTextDb(stanzaInfo, resultStr, backupLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4096,11 +4096,28 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
|
|||||||
|
|
||||||
CFGDEFDATA_OPTION_COMMAND_LIST
|
CFGDEFDATA_OPTION_COMMAND_LIST
|
||||||
(
|
(
|
||||||
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdInfo)
|
||||||
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdRestore)
|
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdRestore)
|
||||||
)
|
)
|
||||||
|
|
||||||
CFGDEFDATA_OPTION_OPTIONAL_LIST
|
CFGDEFDATA_OPTION_OPTIONAL_LIST
|
||||||
(
|
(
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_COMMAND_OVERRIDE
|
||||||
|
(
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_COMMAND(cfgDefCmdInfo)
|
||||||
|
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_DEPEND(cfgDefOptStanza)
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_REQUIRED(false)
|
||||||
|
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_HELP_SUMMARY("Backup set to detail.")
|
||||||
|
CFGDEFDATA_OPTION_OPTIONAL_HELP_DESCRIPTION
|
||||||
|
(
|
||||||
|
"Details include a list of databases (with OIDs) in the backup set (excluding template databases), tablespaces "
|
||||||
|
"(with OIDs) with the destination where they will be restored by default, and symlinks with the "
|
||||||
|
"destination where they will be restored when --link-all is specified."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
CFGDEFDATA_OPTION_OPTIONAL_COMMAND_OVERRIDE
|
CFGDEFDATA_OPTION_OPTIONAL_COMMAND_OVERRIDE
|
||||||
(
|
(
|
||||||
CFGDEFDATA_OPTION_OPTIONAL_COMMAND(cfgDefCmdRestore)
|
CFGDEFDATA_OPTION_OPTIONAL_COMMAND(cfgDefCmdRestore)
|
||||||
|
@ -410,6 +410,130 @@ testRun(void)
|
|||||||
storagePutNP(storageNewWriteNP(storageLocalWrite(), strNewFmt("%s/backup.info", strPtr(backupStanza1Path))),
|
storagePutNP(storageNewWriteNP(storageLocalWrite(), strNewFmt("%s/backup.info", strPtr(backupStanza1Path))),
|
||||||
harnessInfoChecksum(content)), "put backup info to file - stanza1");
|
harnessInfoChecksum(content)), "put backup info to file - stanza1");
|
||||||
|
|
||||||
|
// Manifest with all features
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#define TEST_MANIFEST_HEADER \
|
||||||
|
"[backup]\n" \
|
||||||
|
"backup-archive-start=\"000000030000028500000089\"\n" \
|
||||||
|
"backup-archive-stop=\"000000030000028500000089\"\n" \
|
||||||
|
"backup-label=\"20190818-084502F_20190820-084502D\"\n" \
|
||||||
|
"backup-lsn-start=\"285/89000028\"\n" \
|
||||||
|
"backup-lsn-stop=\"285/89001F88\"\n" \
|
||||||
|
"backup-prior=\"20190818-084502F\"\n" \
|
||||||
|
"backup-timestamp-copy-start=1565282141\n" \
|
||||||
|
"backup-timestamp-start=1565282140\n" \
|
||||||
|
"backup-timestamp-stop=1565282142\n" \
|
||||||
|
"backup-type=\"full\"\n" \
|
||||||
|
"\n" \
|
||||||
|
"[backup:db]\n" \
|
||||||
|
"db-catalog-version=201409291\n" \
|
||||||
|
"db-control-version=942\n" \
|
||||||
|
"db-id=1\n" \
|
||||||
|
"db-system-id=1000000000000000094\n" \
|
||||||
|
"db-version=\"9.4\"\n" \
|
||||||
|
"\n" \
|
||||||
|
"[backup:option]\n" \
|
||||||
|
"option-archive-check=true\n" \
|
||||||
|
"option-archive-copy=true\n" \
|
||||||
|
"option-backup-standby=false\n" \
|
||||||
|
"option-buffer-size=16384\n" \
|
||||||
|
"option-checksum-page=true\n" \
|
||||||
|
"option-compress=false\n" \
|
||||||
|
"option-compress-level=3\n" \
|
||||||
|
"option-compress-level-network=3\n" \
|
||||||
|
"option-delta=false\n" \
|
||||||
|
"option-hardlink=false\n" \
|
||||||
|
"option-online=false\n" \
|
||||||
|
"option-process-max=32\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_TARGET \
|
||||||
|
"\n" \
|
||||||
|
"[backup:target]\n" \
|
||||||
|
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n" \
|
||||||
|
"pg_data/pg_hba.conf={\"file\":\"pg_hba.conf\",\"path\":\"../pg_config\",\"type\":\"link\"}\n" \
|
||||||
|
"pg_data/pg_stat={\"path\":\"../pg_stat\",\"type\":\"link\"}\n" \
|
||||||
|
"pg_tblspc/1={\"path\":\"/tblspc/ts1\",\"tablespace-id\":\"1\",\"tablespace-name\":\"ts1\",\"type\":\"link\"}\n" \
|
||||||
|
"pg_tblspc/12={\"path\":\"/tblspc/ts12\",\"tablespace-id\":\"12\",\"tablespace-name\":\"ts12\",\"type\":\"link\"}\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_DB \
|
||||||
|
"\n" \
|
||||||
|
"[db]\n" \
|
||||||
|
"mail={\"db-id\":16456,\"db-last-system-id\":12168}\n" \
|
||||||
|
"postgres={\"db-id\":12173,\"db-last-system-id\":12168}\n" \
|
||||||
|
"template0={\"db-id\":12168,\"db-last-system-id\":12168}\n" \
|
||||||
|
"template1={\"db-id\":1,\"db-last-system-id\":12168}\n" \
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_FILE \
|
||||||
|
"\n" \
|
||||||
|
"[target:file]\n" \
|
||||||
|
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"master\":true" \
|
||||||
|
",\"reference\":\"20190818-084502F_20190819-084506D\",\"size\":4,\"timestamp\":1565282114}\n" \
|
||||||
|
"pg_data/base/16384/17000={\"checksum\":\"e0101dd8ffb910c9c202ca35b5f828bcb9697bed\",\"checksum-page\":false" \
|
||||||
|
",\"checksum-page-error\":[1],\"repo-size\":4096,\"size\":8192,\"timestamp\":1565282114}\n" \
|
||||||
|
"pg_data/base/16384/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"group\":false,\"size\":4" \
|
||||||
|
",\"timestamp\":1565282115}\n" \
|
||||||
|
"pg_data/base/32768/33000={\"checksum\":\"7a16d165e4775f7c92e8cdf60c0af57313f0bf90\",\"checksum-page\":true" \
|
||||||
|
",\"reference\":\"20190818-084502F\",\"size\":1073741824,\"timestamp\":1565282116}\n" \
|
||||||
|
"pg_data/base/32768/33000.32767={\"checksum\":\"6e99b589e550e68e934fd235ccba59fe5b592a9e\",\"checksum-page\":true" \
|
||||||
|
",\"reference\":\"20190818-084502F\",\"size\":32768,\"timestamp\":1565282114}\n" \
|
||||||
|
"pg_data/postgresql.conf={\"checksum\":\"6721d92c9fcdf4248acff1f9a1377127d9064807\",\"master\":true,\"size\":4457" \
|
||||||
|
",\"timestamp\":1565282114}\n" \
|
||||||
|
"pg_data/special={\"master\":true,\"mode\":\"0640\",\"size\":0,\"timestamp\":1565282120,\"user\":false}\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_FILE_DEFAULT \
|
||||||
|
"\n" \
|
||||||
|
"[target:file:default]\n" \
|
||||||
|
"group=\"group1\"\n" \
|
||||||
|
"master=false\n" \
|
||||||
|
"mode=\"0600\"\n" \
|
||||||
|
"user=\"user1\"\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_LINK \
|
||||||
|
"\n" \
|
||||||
|
"[target:link]\n" \
|
||||||
|
"pg_data/pg_stat={\"destination\":\"../pg_stat\"}\n" \
|
||||||
|
"pg_data/postgresql.conf={\"destination\":\"../pg_config/postgresql.conf\",\"group\":false,\"user\":\"user1\"}\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_LINK_DEFAULT \
|
||||||
|
"\n" \
|
||||||
|
"[target:link:default]\n" \
|
||||||
|
"group=\"group1\"\n" \
|
||||||
|
"user=false\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_PATH \
|
||||||
|
"\n" \
|
||||||
|
"[target:path]\n" \
|
||||||
|
"pg_data={\"user\":\"user2\"}\n" \
|
||||||
|
"pg_data/base={\"group\":\"group2\"}\n" \
|
||||||
|
"pg_data/base/16384={\"mode\":\"0750\"}\n" \
|
||||||
|
"pg_data/base/32768={}\n" \
|
||||||
|
"pg_data/base/65536={\"user\":false}\n"
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_PATH_DEFAULT \
|
||||||
|
"\n" \
|
||||||
|
"[target:path:default]\n" \
|
||||||
|
"group=false\n" \
|
||||||
|
"mode=\"0700\"\n" \
|
||||||
|
"user=\"user1\"\n"
|
||||||
|
|
||||||
|
const Buffer *contentLoad = harnessInfoChecksumZ
|
||||||
|
(
|
||||||
|
TEST_MANIFEST_HEADER
|
||||||
|
TEST_MANIFEST_TARGET
|
||||||
|
TEST_MANIFEST_DB
|
||||||
|
TEST_MANIFEST_FILE
|
||||||
|
TEST_MANIFEST_FILE_DEFAULT
|
||||||
|
TEST_MANIFEST_LINK
|
||||||
|
TEST_MANIFEST_LINK_DEFAULT
|
||||||
|
TEST_MANIFEST_PATH
|
||||||
|
TEST_MANIFEST_PATH_DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(
|
||||||
|
storagePutNP(storageNewWriteNP(storageLocalWrite(),
|
||||||
|
strNewFmt("%s/20181119-152138F_20181119-152152I/" BACKUP_MANIFEST_FILE, strPtr(backupStanza1Path))), contentLoad),
|
||||||
|
"write manifest - stanza1");
|
||||||
|
|
||||||
String *archiveStanza2Path = strNewFmt("%s/stanza2", strPtr(archivePath));
|
String *archiveStanza2Path = strNewFmt("%s/stanza2", strPtr(archivePath));
|
||||||
String *backupStanza2Path = strNewFmt("%s/stanza2", strPtr(backupPath));
|
String *backupStanza2Path = strNewFmt("%s/stanza2", strPtr(backupPath));
|
||||||
TEST_RESULT_VOID(storagePathCreateNP(storageLocalWrite(), backupStanza1Path), "backup stanza2 directory");
|
TEST_RESULT_VOID(storagePathCreateNP(storageLocalWrite(), backupStanza1Path), "backup stanza2 directory");
|
||||||
@ -651,6 +775,142 @@ testRun(void)
|
|||||||
" wal archive min/max (9.4-1): none present\n"
|
" wal archive min/max (9.4-1): none present\n"
|
||||||
, "text - multiple stanzas, one with valid backups, archives in latest DB");
|
, "text - multiple stanzas, one with valid backups, archives in latest DB");
|
||||||
|
|
||||||
|
// Backup set requested
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList2 = strLstDup(argListText);
|
||||||
|
strLstAddZ(argList2, "--stanza=stanza1");
|
||||||
|
strLstAddZ(argList2, "--set=20181119-152138F_20181119-152152I");
|
||||||
|
harnessCfgLoad(strLstSize(argList2), strLstPtr(argList2));
|
||||||
|
|
||||||
|
TEST_RESULT_STR(strPtr(infoRender()),
|
||||||
|
|
||||||
|
"stanza: stanza1\n"
|
||||||
|
" status: ok\n"
|
||||||
|
" cipher: none\n"
|
||||||
|
"\n"
|
||||||
|
" db (prior)\n"
|
||||||
|
" wal archive min/max (9.4-1): 000000010000000000000002/000000020000000000000003\n"
|
||||||
|
"\n"
|
||||||
|
" incr backup: 20181119-152138F_20181119-152152I\n"
|
||||||
|
" timestamp start/stop: 2018-11-19 15:21:52 / 2018-11-19 15:21:55\n"
|
||||||
|
" wal start/stop: n/a\n"
|
||||||
|
" database size: 19.2MB, backup size: 8.2KB\n"
|
||||||
|
" repository size: 2.3MB, repository backup size: 346B\n"
|
||||||
|
" backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n"
|
||||||
|
" database list: mail (16456), postgres (12173)\n"
|
||||||
|
" symlinks:\n"
|
||||||
|
" pg_hba.conf => ../pg_config/pg_hba.conf\n"
|
||||||
|
" pg_stat => ../pg_stat\n"
|
||||||
|
" tablespaces:\n"
|
||||||
|
" ts1 (1) => /tblspc/ts1\n"
|
||||||
|
" ts12 (12) => /tblspc/ts12\n"
|
||||||
|
, "text - backup set requested");
|
||||||
|
|
||||||
|
strLstAddZ(argList2, "--output=json");
|
||||||
|
harnessCfgLoad(strLstSize(argList2), strLstPtr(argList2));
|
||||||
|
|
||||||
|
TEST_ERROR(strPtr(infoRender()), ConfigError, "option 'set' is currently only valid for text output");
|
||||||
|
|
||||||
|
// Backup set requested but no links
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList2 = strLstDup(argListText);
|
||||||
|
strLstAddZ(argList2, "--stanza=stanza1");
|
||||||
|
strLstAddZ(argList2, "--set=20181119-152138F_20181119-152152I");
|
||||||
|
harnessCfgLoad(strLstSize(argList2), strLstPtr(argList2));
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_TARGET_NO_LINK \
|
||||||
|
"\n" \
|
||||||
|
"[backup:target]\n" \
|
||||||
|
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n" \
|
||||||
|
|
||||||
|
contentLoad = harnessInfoChecksumZ
|
||||||
|
(
|
||||||
|
TEST_MANIFEST_HEADER
|
||||||
|
TEST_MANIFEST_TARGET_NO_LINK
|
||||||
|
TEST_MANIFEST_DB
|
||||||
|
TEST_MANIFEST_FILE
|
||||||
|
TEST_MANIFEST_FILE_DEFAULT
|
||||||
|
TEST_MANIFEST_LINK
|
||||||
|
TEST_MANIFEST_LINK_DEFAULT
|
||||||
|
TEST_MANIFEST_PATH
|
||||||
|
TEST_MANIFEST_PATH_DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(
|
||||||
|
storageRepoWrite(), strNew(STORAGE_REPO_BACKUP "/20181119-152138F_20181119-152152I/" BACKUP_MANIFEST_FILE)),
|
||||||
|
contentLoad),
|
||||||
|
"write manifest");
|
||||||
|
|
||||||
|
TEST_RESULT_STR(strPtr(infoRender()),
|
||||||
|
"stanza: stanza1\n"
|
||||||
|
" status: ok\n"
|
||||||
|
" cipher: none\n"
|
||||||
|
"\n"
|
||||||
|
" db (prior)\n"
|
||||||
|
" wal archive min/max (9.4-1): 000000010000000000000002/000000020000000000000003\n"
|
||||||
|
"\n"
|
||||||
|
" incr backup: 20181119-152138F_20181119-152152I\n"
|
||||||
|
" timestamp start/stop: 2018-11-19 15:21:52 / 2018-11-19 15:21:55\n"
|
||||||
|
" wal start/stop: n/a\n"
|
||||||
|
" database size: 19.2MB, backup size: 8.2KB\n"
|
||||||
|
" repository size: 2.3MB, repository backup size: 346B\n"
|
||||||
|
" backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n"
|
||||||
|
" database list: mail (16456), postgres (12173)\n"
|
||||||
|
, "text - backup set requested, no links");
|
||||||
|
|
||||||
|
|
||||||
|
// Backup set requested but no databases
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList2 = strLstDup(argListText);
|
||||||
|
strLstAddZ(argList2, "--stanza=stanza1");
|
||||||
|
strLstAddZ(argList2, "--set=20181119-152138F_20181119-152152I");
|
||||||
|
harnessCfgLoad(strLstSize(argList2), strLstPtr(argList2));
|
||||||
|
|
||||||
|
#define TEST_MANIFEST_NO_DB \
|
||||||
|
"\n" \
|
||||||
|
"[db]\n" \
|
||||||
|
"template0={\"db-id\":12168,\"db-last-system-id\":12168}\n" \
|
||||||
|
"template1={\"db-id\":1,\"db-last-system-id\":12168}\n" \
|
||||||
|
|
||||||
|
contentLoad = harnessInfoChecksumZ
|
||||||
|
(
|
||||||
|
TEST_MANIFEST_HEADER
|
||||||
|
TEST_MANIFEST_TARGET_NO_LINK
|
||||||
|
TEST_MANIFEST_NO_DB
|
||||||
|
TEST_MANIFEST_FILE
|
||||||
|
TEST_MANIFEST_FILE_DEFAULT
|
||||||
|
TEST_MANIFEST_LINK
|
||||||
|
TEST_MANIFEST_LINK_DEFAULT
|
||||||
|
TEST_MANIFEST_PATH
|
||||||
|
TEST_MANIFEST_PATH_DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(
|
||||||
|
storageRepoWrite(), strNew(STORAGE_REPO_BACKUP "/20181119-152138F_20181119-152152I/" BACKUP_MANIFEST_FILE)),
|
||||||
|
contentLoad),
|
||||||
|
"write manifest");
|
||||||
|
|
||||||
|
TEST_RESULT_STR(strPtr(infoRender()),
|
||||||
|
"stanza: stanza1\n"
|
||||||
|
" status: ok\n"
|
||||||
|
" cipher: none\n"
|
||||||
|
"\n"
|
||||||
|
" db (prior)\n"
|
||||||
|
" wal archive min/max (9.4-1): 000000010000000000000002/000000020000000000000003\n"
|
||||||
|
"\n"
|
||||||
|
" incr backup: 20181119-152138F_20181119-152152I\n"
|
||||||
|
" timestamp start/stop: 2018-11-19 15:21:52 / 2018-11-19 15:21:55\n"
|
||||||
|
" wal start/stop: n/a\n"
|
||||||
|
" database size: 19.2MB, backup size: 8.2KB\n"
|
||||||
|
" repository size: 2.3MB, repository backup size: 346B\n"
|
||||||
|
" backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n"
|
||||||
|
" database list: none\n"
|
||||||
|
, "text - backup set requested, no db");
|
||||||
|
|
||||||
// Stanza not found
|
// Stanza not found
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
argList2 = strLstDup(argList);
|
argList2 = strLstDup(argList);
|
||||||
@ -790,7 +1050,7 @@ testRun(void)
|
|||||||
kvPut(stanzaInfo, KEY_ARCHIVE_VAR, varNewVarLst(varLstNew()));
|
kvPut(stanzaInfo, KEY_ARCHIVE_VAR, varNewVarLst(varLstNew()));
|
||||||
|
|
||||||
String *result = strNew("");
|
String *result = strNew("");
|
||||||
formatTextDb(stanzaInfo, result);
|
formatTextDb(stanzaInfo, result, NULL);
|
||||||
|
|
||||||
TEST_RESULT_STR(strPtr(result),
|
TEST_RESULT_STR(strPtr(result),
|
||||||
"\n"
|
"\n"
|
||||||
@ -832,6 +1092,21 @@ testRun(void)
|
|||||||
TEST_RESULT_STR(
|
TEST_RESULT_STR(
|
||||||
strPtr(strNewBuf(storageGetNP(storageNewReadNP(storage, stdoutFile)))), "No stanzas exist in the repository.\n",
|
strPtr(strNewBuf(storageGetNP(storageNewReadNP(storage, stdoutFile)))), "No stanzas exist in the repository.\n",
|
||||||
" check text");
|
" check text");
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
strLstAddZ(argList, "--set=bogus");
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
harnessCfgLoad(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
|
||||||
|
"option 'set' not valid without option 'stanza'");
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
strLstAddZ(argList, "--stanza=stanza1");
|
||||||
|
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
cmdInfo(), FileMissingError, "manifest does not exist for backup 'bogus'\n"
|
||||||
|
"HINT: is the backup listed when running the info command with --stanza option only?");
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_HARNESS_RESULT_VOID();
|
FUNCTION_HARNESS_RESULT_VOID();
|
||||||
|
Reference in New Issue
Block a user