mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Added documentation in the user guide for delta restores, expiration, dedicated backup hosts, starting and stopping pgBackRest, and replication.
This commit is contained in:
parent
8ddfdcdd3b
commit
fa05715dec
@ -3,6 +3,8 @@
|
||||
## v0.90: UNDER DEVELOPMENT
|
||||
__No Release Date Set__
|
||||
|
||||
* Added documentation in the user guide for delta restores, expiration, dedicated backup hosts, starting and stopping pgBackRest, and replication.
|
||||
|
||||
* Fixed an issue where the `start`/`stop` commands required the `--config` option.
|
||||
|
||||
* Fixed an issue where log files were being overwritten instead of appended.
|
||||
|
160
doc/doc.pl
160
doc/doc.pl
@ -16,18 +16,22 @@ use Cwd qw(abs_path);
|
||||
use File::Basename qw(dirname);
|
||||
use Getopt::Long qw(GetOptions);
|
||||
use Pod::Usage qw(pod2usage);
|
||||
use Storable;
|
||||
use XML::Checker::Parser;
|
||||
|
||||
use lib dirname($0) . '/lib';
|
||||
use BackRestDoc::Common::Doc;
|
||||
use BackRestDoc::Common::DocConfig;
|
||||
use BackRestDoc::Html::DocHtmlSite;
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
use BackRestDoc::Common::DocRender;
|
||||
use BackRestDoc::Html::DocHtmlSite;
|
||||
use BackRestDoc::Latex::DocLatex;
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::Config::Config;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
####################################################################################################################################
|
||||
# Usage
|
||||
@ -60,19 +64,25 @@ my $bHelp = false; # Display usage
|
||||
my $bVersion = false; # Display version
|
||||
my $bQuiet = false; # Sets log level to ERROR
|
||||
my $strLogLevel = 'info'; # Log level for tests
|
||||
my $strProjectName = 'pgBackRest'; # Project name to use in docs
|
||||
my $strExeName = 'pg_backrest'; # Exe name to use in docs
|
||||
my $bHtml = false; # Generate full html documentation
|
||||
my $strHtmlRoot = '/'; # Root html page
|
||||
my $bNoExe = false; # Should commands be executed when buildng help? (for testing only)
|
||||
my $bUseCache = false; # Use cached data to generate the docs (for testing code changes only)
|
||||
my $oVariableOverride = {}; # Override variables
|
||||
my $strDocPath; # Document path to render
|
||||
my @stryOutput; # Output types
|
||||
my @stryKeyword; # Keyword used to filter output
|
||||
my @stryRequire; # Required sections of the document (to speed testing)
|
||||
|
||||
GetOptions ('help' => \$bHelp,
|
||||
'version' => \$bVersion,
|
||||
'quiet' => \$bQuiet,
|
||||
'log-level=s' => \$strLogLevel,
|
||||
'html' => \$bHtml,
|
||||
'html-root=s' => \$strHtmlRoot,
|
||||
'no-exe', \$bNoExe)
|
||||
'out=s@' => \@stryOutput,
|
||||
'keyword=s@' => \@stryKeyword,
|
||||
'require=s@' => \@stryRequire,
|
||||
'no-exe', \$bNoExe,
|
||||
'use-cache', \$bUseCache,
|
||||
'var=s%', $oVariableOverride,
|
||||
'doc-path=s', \$strDocPath)
|
||||
or pod2usage(2);
|
||||
|
||||
# Display version and exit if requested
|
||||
@ -89,16 +99,29 @@ if ($bHelp || $bVersion)
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Set no-exe if use-cache is set
|
||||
if ($bUseCache)
|
||||
{
|
||||
$bNoExe = true;
|
||||
}
|
||||
|
||||
# Set console log level
|
||||
if ($bQuiet)
|
||||
{
|
||||
$strLogLevel = 'off';
|
||||
$strLogLevel = 'error';
|
||||
}
|
||||
|
||||
# If no keyword we passed then use default
|
||||
if (@stryKeyword == 0)
|
||||
{
|
||||
@stryKeyword = ('default')
|
||||
}
|
||||
|
||||
logLevelSet(undef, uc($strLogLevel));
|
||||
|
||||
# Get the base path
|
||||
my $strBasePath = abs_path(dirname($0));
|
||||
my $strOutputPath = "${strBasePath}/output";
|
||||
|
||||
sub docProcess
|
||||
{
|
||||
@ -108,7 +131,7 @@ sub docProcess
|
||||
$strOperation,
|
||||
$strXmlIn,
|
||||
$strMdOut,
|
||||
$oHtmlSite
|
||||
$oManifest
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
@ -122,33 +145,98 @@ sub docProcess
|
||||
my $oDoc = new BackRestDoc::Common::Doc($strXmlIn);
|
||||
|
||||
# Write markdown
|
||||
my $oRender = new BackRestDoc::Common::DocRender('markdown', $strProjectName, $strExeName);
|
||||
$oRender->save($strMdOut, $oHtmlSite->variableReplace($oRender->process($oDoc)));
|
||||
my $oRender = new BackRestDoc::Common::DocRender('markdown', $oManifest);
|
||||
$oRender->save($strMdOut, $oManifest->variableReplace($oRender->process($oDoc)));
|
||||
}
|
||||
|
||||
my $oRender = new BackRestDoc::Common::DocRender('text', $strProjectName, $strExeName);
|
||||
my $oDocConfig = new BackRestDoc::Common::DocConfig(new BackRestDoc::Common::Doc("${strBasePath}/xml/reference.xml"), $oRender);
|
||||
$oDocConfig->helpDataWrite();
|
||||
|
||||
# !!! Create Html Site Object to perform variable replacements on markdown and test
|
||||
# !!! This should be replaced with a more generic site object in the future
|
||||
my $oHtmlSite =
|
||||
new BackRestDoc::Html::DocHtmlSite
|
||||
(
|
||||
new BackRestDoc::Common::DocRender('html', $strProjectName, $strExeName),
|
||||
$oDocConfig,
|
||||
"${strBasePath}/xml",
|
||||
"${strBasePath}/html",
|
||||
"${strBasePath}/css/default.css",
|
||||
$strHtmlRoot,
|
||||
!$bNoExe
|
||||
);
|
||||
|
||||
docProcess("${strBasePath}/xml/index.xml", "${strBasePath}/../README.md", $oHtmlSite);
|
||||
docProcess("${strBasePath}/xml/change-log.xml", "${strBasePath}/../CHANGELOG.md", $oHtmlSite);
|
||||
|
||||
# Only generate the HTML site when requested
|
||||
if ($bHtml)
|
||||
# Create the out path if it does not exist
|
||||
if (!-e $strOutputPath)
|
||||
{
|
||||
$oHtmlSite->process();
|
||||
mkdir($strOutputPath)
|
||||
or confess &log(ERROR, "unable to create path ${strOutputPath}");
|
||||
}
|
||||
|
||||
# Load the manifest
|
||||
my $oManifest;
|
||||
my $strManifestCache = "${strOutputPath}/manifest.cache";
|
||||
|
||||
if ($bUseCache && -e $strManifestCache)
|
||||
{
|
||||
$oManifest = retrieve($strManifestCache);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oManifest = new BackRestDoc::Common::DocManifest(\@stryKeyword, \@stryRequire, $oVariableOverride, $strDocPath);
|
||||
}
|
||||
|
||||
# If no outputs were given
|
||||
if (@stryOutput == 0)
|
||||
{
|
||||
@stryOutput = $oManifest->renderList();
|
||||
|
||||
if ($oManifest->isBackRest())
|
||||
{
|
||||
push(@stryOutput, 'help');
|
||||
push(@stryOutput, 'markdown');
|
||||
}
|
||||
}
|
||||
|
||||
for my $strOutput (@stryOutput)
|
||||
{
|
||||
if (!(($strOutput eq 'help' || $strOutput eq 'markdown') && $oManifest->isBackRest()))
|
||||
{
|
||||
$oManifest->renderGet($strOutput);
|
||||
}
|
||||
|
||||
&log(INFO, "render ${strOutput} output");
|
||||
|
||||
if ($strOutput eq 'markdown' && $oManifest->isBackRest())
|
||||
{
|
||||
# Generate the markdown
|
||||
docProcess("${strBasePath}/xml/index.xml", "${strBasePath}/../README.md", $oManifest);
|
||||
docProcess("${strBasePath}/xml/change-log.xml", "${strBasePath}/../CHANGELOG.md", $oManifest);
|
||||
}
|
||||
elsif ($strOutput eq 'help' && $oManifest->isBackRest())
|
||||
{
|
||||
# Generate the command-line help
|
||||
my $oRender = new BackRestDoc::Common::DocRender('text', $oManifest);
|
||||
my $oDocConfig =
|
||||
new BackRestDoc::Common::DocConfig(
|
||||
new BackRestDoc::Common::Doc("${strBasePath}/xml/reference.xml"), $oRender);
|
||||
$oDocConfig->helpDataWrite($oManifest);
|
||||
}
|
||||
elsif ($strOutput eq 'html')
|
||||
{
|
||||
my $oHtmlSite =
|
||||
new BackRestDoc::Html::DocHtmlSite
|
||||
(
|
||||
$oManifest,
|
||||
"${strBasePath}/xml",
|
||||
"${strOutputPath}/html",
|
||||
"${strBasePath}/resource/html/default.css",
|
||||
!$bNoExe
|
||||
);
|
||||
|
||||
$oHtmlSite->process();
|
||||
}
|
||||
elsif ($strOutput eq 'pdf')
|
||||
{
|
||||
my $oLatex =
|
||||
new BackRestDoc::Latex::DocLatex
|
||||
(
|
||||
$oManifest,
|
||||
"${strBasePath}/xml",
|
||||
"${strOutputPath}/latex",
|
||||
"${strBasePath}/resource/latex/preamble.tex",
|
||||
!$bNoExe
|
||||
);
|
||||
|
||||
$oLatex->process();
|
||||
}
|
||||
}
|
||||
|
||||
# Cache the manifest (mostly useful for testing rendering changes in the code)
|
||||
if (!$bUseCache)
|
||||
{
|
||||
store($oManifest, $strManifestCache);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Scalar::Util qw(blessed);
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
@ -27,8 +28,10 @@ use constant OP_DOC_NEW => OP_DOC .
|
||||
use constant OP_DOC_NODE_BLESS => OP_DOC . '->nodeBless';
|
||||
use constant OP_DOC_NODE_GET => OP_DOC . '->nodeGet';
|
||||
use constant OP_DOC_NODE_LIST => OP_DOC . '->nodeList';
|
||||
use constant OP_DOC_NODE_REMOVE => OP_DOC . '->nodeRemove';
|
||||
use constant OP_DOC_PARAM_GET => OP_DOC . '->paramGet';
|
||||
use constant OP_DOC_PARAM_SET => OP_DOC . '->paramSet';
|
||||
use constant OP_DOC_PARAM_TEST => OP_DOC . '->paramSet';
|
||||
use constant OP_DOC_PARSE => OP_DOC . '->parse';
|
||||
use constant OP_DOC_VALUE_GET => OP_DOC . '->valueGet';
|
||||
use constant OP_DOC_VALUE_SET => OP_DOC . '->valueSet';
|
||||
@ -49,44 +52,60 @@ sub new
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strFileName}
|
||||
$self->{strFileName},
|
||||
my $bCached
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_NEW, \@_,
|
||||
{name => 'strFileName', required => false}
|
||||
{name => 'strFileName', required => false},
|
||||
{name => 'bCached', default => false}
|
||||
);
|
||||
|
||||
# Load the doc from a file if one has been defined
|
||||
if (defined($self->{strFileName}))
|
||||
{
|
||||
my $oParser = XML::Checker::Parser->new(ErrorContext => 2, Style => 'Tree');
|
||||
$oParser->set_sgml_search_path(dirname($self->{strFileName}) . '/dtd');
|
||||
|
||||
my $oTree;
|
||||
|
||||
eval
|
||||
if ($bCached)
|
||||
{
|
||||
local $XML::Checker::FAIL = sub
|
||||
{
|
||||
my $iCode = shift;
|
||||
$self->oDoc = XMLin(fileStringRead($self->{strFileName}));
|
||||
}
|
||||
else
|
||||
{
|
||||
my $oParser = XML::Checker::Parser->new(ErrorContext => 2, Style => 'Tree');
|
||||
|
||||
die XML::Checker::error_string($iCode, @_);
|
||||
if (-e dirname($0) . '/dtd')
|
||||
{
|
||||
$oParser->set_sgml_search_path(dirname($0) . '/dtd')
|
||||
}
|
||||
else
|
||||
{
|
||||
$oParser->set_sgml_search_path(dirname($0) . '/xml/dtd');
|
||||
}
|
||||
|
||||
my $oTree;
|
||||
|
||||
eval
|
||||
{
|
||||
local $XML::Checker::FAIL = sub
|
||||
{
|
||||
my $iCode = shift;
|
||||
|
||||
die XML::Checker::error_string($iCode, @_);
|
||||
};
|
||||
|
||||
$oTree = $oParser->parsefile($self->{strFileName});
|
||||
};
|
||||
|
||||
$oTree = $oParser->parsefile($self->{strFileName});
|
||||
};
|
||||
# Report any error that stopped parsing
|
||||
if ($@)
|
||||
{
|
||||
$@ =~ s/at \/.*?$//s; # remove module line number
|
||||
die "malformed xml in '$self->{strFileName}':\n" . trim($@);
|
||||
}
|
||||
|
||||
# Report any error that stopped parsing
|
||||
if ($@)
|
||||
{
|
||||
$@ =~ s/at \/.*?$//s; # remove module line number
|
||||
die "malformed xml in '$self->{strFileName}':\n" . trim($@);
|
||||
# Parse and build the doc
|
||||
$self->{oDoc} = $self->build($self->parse(${$oTree}[0], ${$oTree}[1]));
|
||||
}
|
||||
|
||||
# Parse and build the doc
|
||||
$self->{oDoc} = $self->build($self->parse(${$oTree}[0], ${$oTree}[1]));
|
||||
|
||||
}
|
||||
# Else create a blank doc
|
||||
else
|
||||
@ -129,8 +148,8 @@ sub parse
|
||||
|
||||
my %oOut;
|
||||
my $iIndex = 0;
|
||||
my $bText = $strName eq 'text' || $strName eq 'li' || $strName eq 'code-block' || $strName eq 'p' || $strName eq 'title' ||
|
||||
$strName eq 'summary';
|
||||
my $bText = $strName eq 'text' || $strName eq 'li' || $strName eq 'p' || $strName eq 'title' ||
|
||||
$strName eq 'summary' || $strName eq 'table-cell' || $strName eq 'table-column';
|
||||
|
||||
# Store the node name
|
||||
$oOut{name} = $strName;
|
||||
@ -244,7 +263,8 @@ sub build
|
||||
}
|
||||
}
|
||||
|
||||
if ($$oDoc{name} eq 'p' || $$oDoc{name} eq 'title' || $$oDoc{name} eq 'summary')
|
||||
if ($$oDoc{name} eq 'p' || $$oDoc{name} eq 'title' || $$oDoc{name} eq 'summary' ||
|
||||
$$oDoc{name} eq 'table-cell' || $$oDoc{name} eq 'table-column')
|
||||
{
|
||||
$$oOut{field}{text} = $oDoc;
|
||||
}
|
||||
@ -255,7 +275,7 @@ sub build
|
||||
my $oSub = $$oDoc{children}[$iIndex];
|
||||
my $strName = $$oSub{name};
|
||||
|
||||
if ($strName eq 'text' || $strName eq 'code-block')
|
||||
if ($strName eq 'text')
|
||||
{
|
||||
$$oOut{field}{text} = $oSub;
|
||||
}
|
||||
@ -351,6 +371,18 @@ sub nodeGet
|
||||
return $self->nodeGetById(shift, undef, shift);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# nodeTest
|
||||
#
|
||||
# Test that a node exists
|
||||
####################################################################################################################################
|
||||
sub nodeTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return defined($self->nodeGetById(shift, undef, false));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# nodeAdd
|
||||
#
|
||||
@ -470,6 +502,55 @@ sub nodeList
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# nodeRemove
|
||||
#
|
||||
# Remove a child node.
|
||||
####################################################################################################################################
|
||||
sub nodeRemove
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oChildRemove
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_NODE_REMOVE, \@_,
|
||||
{name => 'oChildRemove', required => false, trace => true}
|
||||
);
|
||||
|
||||
my $bRemove = false;
|
||||
my $oDoc = $self->{oDoc};
|
||||
|
||||
# Error if there are no children
|
||||
if (!defined($$oDoc{children}))
|
||||
{
|
||||
confess &log(ERROR, "node has no children");
|
||||
}
|
||||
|
||||
for (my $iIndex = 0; $iIndex < @{$$oDoc{children}}; $iIndex++)
|
||||
{
|
||||
if ($$oDoc{children}[$iIndex] == $oChildRemove->{oDoc})
|
||||
{
|
||||
splice(@{$$oDoc{children}}, $iIndex, 1);
|
||||
$bRemove = true;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bRemove)
|
||||
{
|
||||
confess &log(ERROR, "child was not found in node");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# nameGet
|
||||
####################################################################################################################################
|
||||
@ -539,6 +620,7 @@ sub paramGet
|
||||
$strOperation,
|
||||
$strName,
|
||||
$bRequired,
|
||||
$strDefault,
|
||||
$strType
|
||||
) =
|
||||
logDebugParam
|
||||
@ -546,14 +628,20 @@ sub paramGet
|
||||
OP_DOC_PARAM_GET, \@_,
|
||||
{name => 'strName', trace => true},
|
||||
{name => 'bRequired', default => true, trace => true},
|
||||
{name => 'strDefault', required => false, trace => true},
|
||||
{name => 'strType', default => 'param', trace => true}
|
||||
);
|
||||
|
||||
my $strValue = ${$self->{oDoc}}{$strType}{$strName};
|
||||
|
||||
if (!defined($strValue) && $bRequired)
|
||||
if (!defined($strValue))
|
||||
{
|
||||
confess "${strType} '${strName}' in required in node '$self->{strName}'";
|
||||
if ($bRequired)
|
||||
{
|
||||
confess "${strType} '${strName}' in required in node '$self->{strName}'";
|
||||
}
|
||||
|
||||
$strValue = $strDefault;
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@ -564,6 +652,51 @@ sub paramGet
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# paramTest
|
||||
#
|
||||
# Test that a parameter exists or has a certain value.
|
||||
####################################################################################################################################
|
||||
sub paramTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strName,
|
||||
$strExpectedValue,
|
||||
$strType
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_PARAM_TEST, \@_,
|
||||
{name => 'strName', trace => true},
|
||||
{name => 'strExpectedValue', required => false, trace => true},
|
||||
{name => 'strType', default => 'param', trace => true}
|
||||
);
|
||||
|
||||
my $bResult = true;
|
||||
my $strValue = $self->paramGet($strName, false, undef, $strType);
|
||||
|
||||
if (!defined($strValue))
|
||||
{
|
||||
$bResult = false;
|
||||
}
|
||||
elsif (defined($strExpectedValue) && $strValue ne $strExpectedValue)
|
||||
{
|
||||
$bResult = false;
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bResult', value => $bResult, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# paramSet
|
||||
#
|
||||
@ -585,7 +718,7 @@ sub paramSet
|
||||
(
|
||||
OP_DOC_PARAM_SET, \@_,
|
||||
{name => 'strName', trace => true},
|
||||
{name => 'strValue', trace => true},
|
||||
{name => 'strValue', required => false, trace => true},
|
||||
{name => 'strType', default => 'param', trace => true}
|
||||
);
|
||||
|
||||
@ -604,7 +737,19 @@ sub fieldGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->paramGet(shift, shift, 'field');
|
||||
return $self->paramGet(shift, shift, shift, 'field');
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# fieldTest
|
||||
#
|
||||
# Test if a field exists.
|
||||
####################################################################################################################################
|
||||
sub fieldTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->paramTest(shift, shift, 'field');
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -616,7 +761,7 @@ sub textGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->nodeBless($self->paramGet('text', shift, 'field'));
|
||||
return $self->nodeBless($self->paramGet('text', shift, shift, 'field'));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
|
@ -235,18 +235,28 @@ sub helpDataWrite
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my $strOperation = logDebugParam(OP_DOC_CONFIG_HELP_DATA_WRITE);
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oManifest
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_CONFIG_HELP_DATA_WRITE, \@_,
|
||||
{name => 'oManifest'}
|
||||
);
|
||||
|
||||
# Internal function used to format text by quoting it and splitting lines so it looks good in the module.
|
||||
sub formatText
|
||||
{
|
||||
my $oManifest = shift;
|
||||
my $oDocRender = shift;
|
||||
my $oText = shift;
|
||||
my $iIndent = shift;
|
||||
my $iLength = shift;
|
||||
|
||||
# Split the string into lines for processing
|
||||
my @stryText = split("\n", trim($oDocRender->processText($oText)));
|
||||
my @stryText = split("\n", trim($oManifest->variableReplace($oDocRender->processText($oText))));
|
||||
my $strText;
|
||||
my $iIndex = 0;
|
||||
|
||||
@ -321,9 +331,9 @@ sub helpDataWrite
|
||||
(defined($$oOptionHash{&CONFIG_HELP_SECTION}) ? ' ' . &CONFIG_HELP_SECTION .
|
||||
' => \'' . $$oOptionHash{&CONFIG_HELP_SECTION} . "',\n" : '') .
|
||||
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
|
||||
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . "\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . "\n" .
|
||||
" }";
|
||||
}
|
||||
|
||||
@ -346,9 +356,9 @@ sub helpDataWrite
|
||||
" '${strCommand}' =>\n" .
|
||||
" {\n" .
|
||||
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_SUMMARY}, 16, 112) . ",\n" .
|
||||
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . ",\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oCommandHash{&CONFIG_HELP_DESCRIPTION}, 16, 112) . ",\n" .
|
||||
"\n";
|
||||
|
||||
# Iterate options
|
||||
@ -385,9 +395,9 @@ sub helpDataWrite
|
||||
" '${strOption}' =>\n" .
|
||||
" {\n" .
|
||||
' ' . &CONFIG_HELP_SUMMARY . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 24, 104) . ",\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_SUMMARY}, 24, 104) . ",\n" .
|
||||
' ' . &CONFIG_HELP_DESCRIPTION . " =>\n" .
|
||||
formatText($self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 24, 104) . "\n" .
|
||||
formatText($oManifest, $self->{oDocRender}, $$oOptionHash{&CONFIG_HELP_DESCRIPTION}, 24, 104) . "\n" .
|
||||
" }";
|
||||
|
||||
$bExtraLinefeed = true;
|
||||
@ -612,7 +622,6 @@ sub helpCommandDocGet
|
||||
return $oOption, $strSection;
|
||||
}
|
||||
|
||||
|
||||
# Working variables
|
||||
my $oConfigHash = $self->{oConfigHash};
|
||||
my $oOperationDoc = $self->{oDoc}->nodeGet('operation');
|
||||
|
621
doc/lib/BackRestDoc/Common/DocExecute.pm
Normal file
621
doc/lib/BackRestDoc/Common/DocExecute.pm
Normal file
@ -0,0 +1,621 @@
|
||||
####################################################################################################################################
|
||||
# DOC EXECUTE MODULE
|
||||
####################################################################################################################################
|
||||
package BackRestDoc::Common::DocExecute;
|
||||
use parent 'BackRestDoc::Common::DocRender';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Ini;
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
use lib dirname($0) . '/../test/lib';
|
||||
use BackRestTest::Common::ExecuteTest;
|
||||
use BackRestTest::Common::HostTest;
|
||||
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
use constant OP_DOC_EXECUTE => 'DocExecute';
|
||||
|
||||
use constant OP_DOC_EXECUTE_BACKREST_CONFIG => OP_DOC_EXECUTE . '->backrestConfig';
|
||||
use constant OP_DOC_EXECUTE_EXECUTE => OP_DOC_EXECUTE . '->execute';
|
||||
use constant OP_DOC_EXECUTE_NEW => OP_DOC_EXECUTE . '->new';
|
||||
use constant OP_DOC_EXECUTE_POSTGRES_CONFIG => OP_DOC_EXECUTE . '->postresConfig';
|
||||
use constant OP_DOC_EXECUTE_SECTION_CHILD_PROCESS => OP_DOC_EXECUTE . '->sectionChildProcess';
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strType,
|
||||
$oManifest,
|
||||
$strRenderOutKey,
|
||||
$bExe
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_EXECUTE_NEW, \@_,
|
||||
{name => 'strType'},
|
||||
{name => 'oManifest'},
|
||||
{name => 'strRenderOutKey'},
|
||||
{name => 'bExe'}
|
||||
);
|
||||
|
||||
# Create the class hash
|
||||
my $self = $class->SUPER::new($strType, $oManifest, $strRenderOutKey);
|
||||
bless $self, $class;
|
||||
|
||||
$self->{bExe} = $bExe;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# execute
|
||||
####################################################################################################################################
|
||||
sub execute
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$strHostName,
|
||||
$oCommand,
|
||||
$iIndent
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_EXECUTE_EXECUTE, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'strHostName'},
|
||||
{name => 'oCommand'},
|
||||
{name => 'iIndent', default => 1}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strCommand;
|
||||
my $strOutput;
|
||||
|
||||
if ($oCommand->fieldTest('actual-command'))
|
||||
{
|
||||
$strCommand = $oCommand->fieldGet('actual-command');
|
||||
$strOutput = $oCommand->fieldGet('actual-output', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
# Command variables
|
||||
$strCommand = trim($oCommand->fieldGet('exe-cmd'));
|
||||
my $strUser = $oCommand->paramGet('user', false, 'postgres');
|
||||
my $bExeOutput = $oCommand->paramTest('output', 'y');
|
||||
my $strVariableKey = $oCommand->paramGet('variable-key', false);
|
||||
my $iExeExpectedError = $oCommand->paramGet('err-expect', false);
|
||||
|
||||
$strCommand = $self->{oManifest}->variableReplace(
|
||||
(defined($strUser) && $strUser eq 'vagrant' ? '' :
|
||||
('sudo ' . ($strUser eq 'root' ? '' : "-u ${strUser} "))) . $strCommand);
|
||||
|
||||
# Add continuation chars and proper spacing
|
||||
$strCommand =~ s/[ ]*\n[ ]*/ \\\n /smg;
|
||||
|
||||
if (!$oCommand->paramTest('show', 'n') && $self->{bExe} && $self->isRequired($oSection))
|
||||
{
|
||||
# Make sure that no lines are greater than 80 chars
|
||||
foreach my $strLine (split("\n", $strCommand))
|
||||
{
|
||||
if (length(trim($strLine)) > 80)
|
||||
{
|
||||
confess &log(ERROR, "command has a line > 80 characters:\n${strCommand}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&log(DEBUG, (' ' x $iIndent) . "execute: $strCommand");
|
||||
|
||||
if (!$oCommand->paramTest('skip', 'y'))
|
||||
{
|
||||
if ($self->{bExe} && $self->isRequired($oSection))
|
||||
{
|
||||
# Check that the host is valid
|
||||
my $oHost = $self->{host}{$strHostName};
|
||||
|
||||
if (!defined($oHost))
|
||||
{
|
||||
confess &log(ERROR, "cannot execute on host ${strHostName} because the host does not exist");
|
||||
}
|
||||
|
||||
my $oExec = $oHost->execute($strCommand,
|
||||
{iExpectedExitStatus => $iExeExpectedError,
|
||||
bSuppressError => $oCommand->paramTest('err-suppress', 'y'),
|
||||
iRetrySeconds => $oCommand->paramGet('retry', false)});
|
||||
$oExec->begin();
|
||||
$oExec->end();
|
||||
|
||||
if ($bExeOutput && defined($oExec->{strOutLog}) && $oExec->{strOutLog} ne '')
|
||||
{
|
||||
$strOutput = $oExec->{strOutLog};
|
||||
|
||||
# Trim off extra linefeeds before and after
|
||||
$strOutput =~ s/^\n+|\n$//g;
|
||||
|
||||
if ($strCommand =~ / pg\_backrest /)
|
||||
{
|
||||
$strOutput =~ s/^ //smg;
|
||||
$strOutput =~ s/^[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]\.[0-9]{3} T[0-9]{2} //smg;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($iExeExpectedError))
|
||||
{
|
||||
$strOutput .= trim($oExec->{strErrorLog});
|
||||
}
|
||||
|
||||
# Output is assigned to a var
|
||||
if (defined($strVariableKey))
|
||||
{
|
||||
$self->{oManifest}->variableSet($strVariableKey, trim($oExec->{strOutLog}));
|
||||
}
|
||||
elsif (!$oCommand->paramTest('filter', 'n') && $bExeOutput && defined($strOutput))
|
||||
{
|
||||
my $strHighLight = $self->{oManifest}->variableReplace($oCommand->fieldGet('exe-highlight', false));
|
||||
|
||||
if (!defined($strHighLight))
|
||||
{
|
||||
confess &log(ERROR, 'filter requires highlight definition: ' . $strCommand);
|
||||
}
|
||||
|
||||
my $iFilterContext = $oCommand->paramGet('filter-context', false, 2);
|
||||
|
||||
my @stryOutput = split("\n", $strOutput);
|
||||
undef($strOutput);
|
||||
# my $iFiltered = 0;
|
||||
my $iLastOutput = -1;
|
||||
|
||||
for (my $iIndex = 0; $iIndex < @stryOutput; $iIndex++)
|
||||
{
|
||||
if ($stryOutput[$iIndex] =~ /$strHighLight/)
|
||||
{
|
||||
# Determine the first line to output
|
||||
my $iFilterFirst = $iIndex - $iFilterContext;
|
||||
|
||||
# Don't go past the beginning
|
||||
$iFilterFirst = $iFilterFirst < 0 ? 0 : $iFilterFirst;
|
||||
|
||||
# Don't repeat lines that have already been output
|
||||
$iFilterFirst = $iFilterFirst <= $iLastOutput ? $iLastOutput + 1 : $iFilterFirst;
|
||||
|
||||
# Determine the last line to output
|
||||
my $iFilterLast = $iIndex + $iFilterContext;
|
||||
|
||||
# Don't got past the end
|
||||
$iFilterLast = $iFilterLast >= @stryOutput ? @stryOutput -1 : $iFilterLast;
|
||||
|
||||
# Mark filtered lines if any
|
||||
if ($iFilterFirst > $iLastOutput + 1)
|
||||
{
|
||||
my $iFiltered = $iFilterFirst - ($iLastOutput + 1);
|
||||
|
||||
if ($iFiltered > 1)
|
||||
{
|
||||
$strOutput .= (defined($strOutput) ? "\n" : '') .
|
||||
" [filtered ${iFiltered} lines of output]";
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFilterFirst -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Output the lines
|
||||
for (my $iOutputIndex = $iFilterFirst; $iOutputIndex <= $iFilterLast; $iOutputIndex++)
|
||||
{
|
||||
$strOutput .= (defined($strOutput) ? "\n" : '') . $stryOutput[$iOutputIndex];
|
||||
}
|
||||
|
||||
$iLastOutput = $iFilterLast;
|
||||
}
|
||||
}
|
||||
|
||||
if (@stryOutput - 1 > $iLastOutput + 1)
|
||||
{
|
||||
my $iFiltered = (@stryOutput - 1) - ($iLastOutput + 1);
|
||||
|
||||
if ($iFiltered > 1)
|
||||
{
|
||||
$strOutput .= (defined($strOutput) ? "\n" : '') .
|
||||
" [filtered ${iFiltered} lines of output]";
|
||||
}
|
||||
else
|
||||
{
|
||||
$strOutput .= (defined($strOutput) ? "\n" : '') . $stryOutput[@stryOutput - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($bExeOutput)
|
||||
{
|
||||
$strOutput = 'Output suppressed for testing';
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($strVariableKey) && !defined($self->{oManifest}->variableGet($strVariableKey)))
|
||||
{
|
||||
$self->{oManifest}->variableSet($strVariableKey, '[Test Variable]');
|
||||
}
|
||||
|
||||
$oCommand->fieldSet('actual-command', $strCommand);
|
||||
$oCommand->fieldSet('actual-output', $strOutput);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strCommand', value => $strCommand, trace => true},
|
||||
{name => 'strOutput', value => $strOutput, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# backrestConfig
|
||||
####################################################################################################################################
|
||||
sub backrestConfig
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oConfig,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_EXECUTE_BACKREST_CONFIG, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oConfig'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strFile;
|
||||
my $strConfig;
|
||||
|
||||
if ($oConfig->fieldTest('actual-file'))
|
||||
{
|
||||
$strFile = $oConfig->fieldGet('actual-file');
|
||||
$strConfig = $oConfig->fieldGet('actual-config');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Get filename
|
||||
$strFile = $self->{oManifest}->variableReplace($oConfig->paramGet('file'));
|
||||
|
||||
&log(DEBUG, (' ' x $iDepth) . 'process backrest config: ' . $strFile);
|
||||
|
||||
if ($self->{bExe} && $self->isRequired($oSection))
|
||||
{
|
||||
# Check that the host is valid
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
||||
my $oHost = $self->{host}{$strHostName};
|
||||
|
||||
if (!defined($oHost))
|
||||
{
|
||||
confess &log(ERROR, "cannot configure backrest on host ${strHostName} because the host does not exist");
|
||||
}
|
||||
|
||||
# Reset all options
|
||||
if ($oConfig->paramTest('reset', 'y'))
|
||||
{
|
||||
delete(${$self->{config}}{$strHostName}{$strFile})
|
||||
}
|
||||
|
||||
foreach my $oOption ($oConfig->nodeList('backrest-config-option'))
|
||||
{
|
||||
my $strSection = $oOption->paramGet('section');
|
||||
my $strKey = $oOption->paramGet('key');
|
||||
my $strValue;
|
||||
|
||||
if (!$oOption->paramTest('remove', 'y'))
|
||||
{
|
||||
$strValue = $self->{oManifest}->variableReplace(trim($oOption->valueGet(false)));
|
||||
}
|
||||
|
||||
if (!defined($strValue))
|
||||
{
|
||||
delete(${$self->{config}}{$strHostName}{$strFile}{$strSection}{$strKey});
|
||||
|
||||
if (keys(${$self->{config}}{$strHostName}{$strFile}{$strSection}) == 0)
|
||||
{
|
||||
delete(${$self->{config}}{$strHostName}{$strFile}{$strSection});
|
||||
}
|
||||
|
||||
&log(DEBUG, (' ' x ($iDepth + 1)) . "reset ${strSection}->${strKey}");
|
||||
}
|
||||
else
|
||||
{
|
||||
${$self->{config}}{$strHostName}{$strFile}{$strSection}{$strKey} = $strValue;
|
||||
&log(DEBUG, (' ' x ($iDepth + 1)) . "set ${strSection}->${strKey} = ${strValue}");
|
||||
}
|
||||
}
|
||||
|
||||
my $strLocalFile = "/home/vagrant/data/db-master/etc/pg_backrest.conf";
|
||||
|
||||
# Save the ini file
|
||||
iniSave($strLocalFile, $self->{config}{$strHostName}{$strFile}, true);
|
||||
|
||||
$strConfig = fileStringRead($strLocalFile);
|
||||
|
||||
$oHost->copyTo($strLocalFile, $strFile, $oConfig->paramGet('owner', false, 'postgres:postgres'), '640');
|
||||
}
|
||||
else
|
||||
{
|
||||
$strConfig = 'Config suppressed for testing';
|
||||
}
|
||||
|
||||
$oConfig->fieldSet('actual-file', $strFile);
|
||||
$oConfig->fieldSet('actual-config', $strConfig);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strFile', value => $strFile, trace => true},
|
||||
{name => 'strConfig', value => $strConfig, trace => true},
|
||||
{name => 'bShow', value => $oConfig->paramTest('show', 'n') ? false : true, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# postgresConfig
|
||||
####################################################################################################################################
|
||||
sub postgresConfig
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oConfig,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_EXECUTE_POSTGRES_CONFIG, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oConfig'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strFile;
|
||||
my $strConfig;
|
||||
|
||||
if ($oConfig->fieldTest('actual-file'))
|
||||
{
|
||||
$strFile = $oConfig->fieldGet('actual-file');
|
||||
$strConfig = $oConfig->fieldGet('actual-config');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Get filename
|
||||
$strFile = $self->{oManifest}->variableReplace($oConfig->paramGet('file'));
|
||||
|
||||
if ($self->{bExe} && $self->isRequired($oSection))
|
||||
{
|
||||
# Check that the host is valid
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
||||
my $oHost = $self->{host}{$strHostName};
|
||||
|
||||
if (!defined($oHost))
|
||||
{
|
||||
confess &log(ERROR, "cannot configure postgres on host ${strHostName} because the host does not exist");
|
||||
}
|
||||
|
||||
my $strLocalFile = '/home/vagrant/data/db-master/etc/postgresql.conf';
|
||||
$oHost->copyFrom($strFile, $strLocalFile);
|
||||
|
||||
if (!defined(${$self->{'pg-config'}}{$strHostName}{$strFile}{base}) && $self->{bExe})
|
||||
{
|
||||
${$self->{'pg-config'}}{$strHostName}{$strFile}{base} = fileStringRead($strLocalFile);
|
||||
}
|
||||
|
||||
my $oConfigHash = $self->{'pg-config'}{$strHostName}{$strFile};
|
||||
my $oConfigHashNew;
|
||||
|
||||
if (!defined($$oConfigHash{old}))
|
||||
{
|
||||
$oConfigHashNew = {};
|
||||
$$oConfigHash{old} = {}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oConfigHashNew = dclone($$oConfigHash{old});
|
||||
}
|
||||
|
||||
&log(DEBUG, (' ' x $iDepth) . 'process postgres config: ' . $strFile);
|
||||
|
||||
foreach my $oOption ($oConfig->nodeList('postgres-config-option'))
|
||||
{
|
||||
my $strKey = $oOption->paramGet('key');
|
||||
my $strValue = $self->{oManifest}->variableReplace(trim($oOption->valueGet()));
|
||||
|
||||
if ($strValue eq '')
|
||||
{
|
||||
delete($$oConfigHashNew{$strKey});
|
||||
|
||||
&log(DEBUG, (' ' x ($iDepth + 1)) . "reset ${strKey}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$$oConfigHashNew{$strKey} = $strValue;
|
||||
&log(DEBUG, (' ' x ($iDepth + 1)) . "set ${strKey} = ${strValue}");
|
||||
}
|
||||
}
|
||||
|
||||
# Generate config text
|
||||
foreach my $strKey (sort(keys(%$oConfigHashNew)))
|
||||
{
|
||||
if (defined($strConfig))
|
||||
{
|
||||
$strConfig .= "\n";
|
||||
}
|
||||
|
||||
$strConfig .= "${strKey} = $$oConfigHashNew{$strKey}";
|
||||
}
|
||||
|
||||
# Save the conf file
|
||||
if ($self->{bExe})
|
||||
{
|
||||
fileStringWrite($strLocalFile, $$oConfigHash{base} .
|
||||
(defined($strConfig) ? "\n# pgBackRest Configuration\n${strConfig}\n" : ''));
|
||||
|
||||
$oHost->copyTo($strLocalFile, $strFile, 'postgres:postgres', '640');
|
||||
}
|
||||
|
||||
$$oConfigHash{old} = $oConfigHashNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
$strConfig = 'Config suppressed for testing';
|
||||
}
|
||||
|
||||
$oConfig->fieldSet('actual-file', $strFile);
|
||||
$oConfig->fieldSet('actual-config', $strConfig);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strFile', value => $strFile, trace => true},
|
||||
{name => 'strConfig', value => $strConfig, trace => true},
|
||||
{name => 'bShow', value => $oConfig->paramTest('show', 'n') ? false : true, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# sectionChildProcesss
|
||||
####################################################################################################################################
|
||||
sub sectionChildProcess
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oChild,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_EXECUTE_SECTION_CHILD_PROCESS, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oChild'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
&log(DEBUG, (' ' x ($iDepth + 1)) . 'process child: ' . $oChild->nameGet());
|
||||
|
||||
# Execute a command
|
||||
if ($oChild->nameGet() eq 'host-add')
|
||||
{
|
||||
if ($self->{bExe} && $self->isRequired($oSection) && !$oChild->paramTest('created', true))
|
||||
{
|
||||
my $strName = $self->{oManifest}->variableReplace($oChild->paramGet('name'));
|
||||
my $strUser = $self->{oManifest}->variableReplace($oChild->paramGet('user'));
|
||||
my $strImage = $self->{oManifest}->variableReplace($oChild->paramGet('image'));
|
||||
my $strOS = $self->{oManifest}->variableReplace($oChild->paramGet('os', false));
|
||||
my $strMount = $self->{oManifest}->variableReplace($oChild->paramGet('mount', false));
|
||||
|
||||
if (defined($self->{host}{$strName}))
|
||||
{
|
||||
confess &log(ERROR, 'cannot add host ${strName} because the host already exists');
|
||||
}
|
||||
|
||||
my $oHost = new BackRestTest::Common::HostTest($strName, $strImage, $strUser, $strOS, $strMount);
|
||||
$self->{host}{$strName} = $oHost;
|
||||
$self->{oManifest}->variableSet("host-${strName}-ip", $oHost->{strIP});
|
||||
|
||||
# Execute cleanup commands
|
||||
foreach my $oExecute ($oChild->nodeList('execute'))
|
||||
{
|
||||
$self->execute($oSection, $strName, $oExecute, $iDepth + 1);
|
||||
}
|
||||
|
||||
$oHost->executeSimple("sh -c 'echo \"\" >> /etc/hosts\'");
|
||||
$oHost->executeSimple("sh -c 'echo \"# Test Hosts\" >> /etc/hosts'");
|
||||
|
||||
# Add all other host IPs to this host
|
||||
foreach my $strOtherHostName (sort(keys($self->{host})))
|
||||
{
|
||||
if ($strOtherHostName ne $strName)
|
||||
{
|
||||
my $oOtherHost = $self->{host}{$strOtherHostName};
|
||||
|
||||
$oHost->executeSimple("sh -c 'echo \"$oOtherHost->{strIP} ${strOtherHostName}\" >> /etc/hosts'");
|
||||
}
|
||||
}
|
||||
|
||||
# Add this host IP to all other hosts
|
||||
foreach my $strOtherHostName (sort(keys($self->{host})))
|
||||
{
|
||||
if ($strOtherHostName ne $strName)
|
||||
{
|
||||
my $oOtherHost = $self->{host}{$strOtherHostName};
|
||||
|
||||
$oOtherHost->executeSimple("sh -c 'echo \"$oHost->{strIP} ${strName}\" >> /etc/hosts'");
|
||||
}
|
||||
}
|
||||
|
||||
$oChild->paramSet('created', true);
|
||||
}
|
||||
}
|
||||
# Skip children that have already been processed and error on others
|
||||
elsif ($oChild->nameGet() ne 'title')
|
||||
{
|
||||
confess &log(ASSERT, 'unable to process child type ' . $oChild->nameGet());
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
536
doc/lib/BackRestDoc/Common/DocManifest.pm
Normal file
536
doc/lib/BackRestDoc/Common/DocManifest.pm
Normal file
@ -0,0 +1,536 @@
|
||||
####################################################################################################################################
|
||||
# DOC MANIFEST MODULE
|
||||
####################################################################################################################################
|
||||
package BackRestDoc::Common::DocManifest;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Cwd qw(abs_path);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use Scalar::Util qw(blessed);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
use constant OP_DOC_MANIFEST => 'DocManifest';
|
||||
|
||||
use constant OP_DOC_MANIFEST_NEW => OP_DOC_MANIFEST . '->new';
|
||||
use constant OP_DOC_MANIFEST_RENDER_GET => OP_DOC_MANIFEST . '->renderGet';
|
||||
use constant OP_DOC_MANIFEST_RENDER_LIST => OP_DOC_MANIFEST . '->renderList';
|
||||
use constant OP_DOC_MANIFEST_RENDER_OUT_GET => OP_DOC_MANIFEST . '->renderOutGet';
|
||||
use constant OP_DOC_MANIFEST_RENDER_OUT_LIST => OP_DOC_MANIFEST . '->renderOutList';
|
||||
use constant OP_DOC_MANIFEST_SOURCE_GET => OP_DOC_MANIFEST . '->sourceGet';
|
||||
use constant OP_DOC_MANIFEST_VARIABLE_LIST_PARSE => OP_DOC_MANIFEST . '->variableListParse';
|
||||
|
||||
####################################################################################################################################
|
||||
# File constants
|
||||
####################################################################################################################################
|
||||
use constant FILE_MANIFEST => 'manifest.xml';
|
||||
|
||||
####################################################################################################################################
|
||||
# Render constants
|
||||
####################################################################################################################################
|
||||
use constant RENDER => 'render';
|
||||
use constant RENDER_FILE => 'file';
|
||||
|
||||
use constant RENDER_TYPE => 'type';
|
||||
use constant RENDER_TYPE_HTML => 'html';
|
||||
push @EXPORT, qw(RENDER_TYPE_HTML);
|
||||
use constant RENDER_TYPE_PDF => 'pdf';
|
||||
push @EXPORT, qw(RENDER_TYPE_PDF);
|
||||
|
||||
####################################################################################################################################
|
||||
# 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,
|
||||
$self->{stryKeyword},
|
||||
$self->{stryRequire},
|
||||
my $oVariableOverride,
|
||||
$self->{strDocPath}
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_NEW, \@_,
|
||||
{name => 'stryKeyword'},
|
||||
{name => 'stryRequire'},
|
||||
{name => 'oVariableOverride', required => false},
|
||||
{name => 'strDocPath', required => false},
|
||||
);
|
||||
|
||||
# Set the base path if it was not passed in
|
||||
if (!defined($self->{strDocPath}))
|
||||
{
|
||||
$self->{strDocPath} = abs_path(dirname($0));
|
||||
}
|
||||
|
||||
# Load the manifest
|
||||
$self->{oManifestXml} = new BackRestDoc::Common::Doc("$self->{strDocPath}/manifest.xml");
|
||||
|
||||
# Iterate the sources
|
||||
$self->{oManifest} = {};
|
||||
|
||||
foreach my $oSource ($self->{oManifestXml}->nodeGet('source-list')->nodeList('source'))
|
||||
{
|
||||
my $oSourceHash = {};
|
||||
my $strKey = $oSource->paramGet('key');
|
||||
|
||||
logDebugMisc
|
||||
(
|
||||
$strOperation, 'load source',
|
||||
{name => 'strKey', value => $strKey}
|
||||
);
|
||||
|
||||
$$oSourceHash{doc} = new BackRestDoc::Common::Doc("$self->{strDocPath}/xml/${strKey}.xml");
|
||||
|
||||
# Read variables from source
|
||||
$self->variableListParse($$oSourceHash{doc}->nodeGet('variable-list', false), $oVariableOverride);
|
||||
|
||||
${$self->{oManifest}}{source}{$strKey} = $oSourceHash;
|
||||
}
|
||||
|
||||
# Iterate the renderers
|
||||
foreach my $oRender ($self->{oManifestXml}->nodeGet('render-list')->nodeList('render'))
|
||||
{
|
||||
my $oRenderHash = {};
|
||||
my $strType = $oRender->paramGet(RENDER_TYPE);
|
||||
|
||||
# Only one instance of each render type can be defined
|
||||
if (defined(${$self->{oManifest}}{&RENDER}{$strType}))
|
||||
{
|
||||
confess &log(ERROR, "render ${strType} has already been defined");
|
||||
}
|
||||
|
||||
# Get the file param
|
||||
$${oRenderHash}{file} = $oRender->paramGet(RENDER_FILE, false);
|
||||
|
||||
logDebugMisc
|
||||
(
|
||||
$strOperation, ' load render',
|
||||
{name => 'strType', value => $strType},
|
||||
{name => 'strFile', value => $${oRenderHash}{file}}
|
||||
);
|
||||
|
||||
# Error if file is set and render type is not pdf
|
||||
if (defined($${oRenderHash}{file}) && $strType ne RENDER_TYPE_PDF)
|
||||
{
|
||||
confess &log(ERROR, 'only the pdf render type can have file set')
|
||||
}
|
||||
|
||||
# Iterate the render sources
|
||||
foreach my $oRenderOut ($oRender->nodeList('render-source'))
|
||||
{
|
||||
my $oRenderOutHash = {};
|
||||
my $strKey = $oRenderOut->paramGet('key');
|
||||
my $strSource = $oRenderOut->paramGet('source', false, $strKey);
|
||||
|
||||
$$oRenderOutHash{source} = $strSource;
|
||||
|
||||
# Get the filename if this is a pdf
|
||||
$$oRenderOutHash{menu} = $oRenderOut->paramGet('menu', false);
|
||||
|
||||
if (defined($$oRenderOutHash{menu}) && $strType ne RENDER_TYPE_HTML)
|
||||
{
|
||||
confess &log(ERROR, 'only the html render type can have menu set')
|
||||
}
|
||||
|
||||
logDebugMisc
|
||||
(
|
||||
$strOperation, ' load render source',
|
||||
{name => 'strKey', value => $strKey},
|
||||
{name => 'strSource', value => $strSource},
|
||||
{name => 'strMenu', value => $${oRenderOutHash}{menu}}
|
||||
);
|
||||
|
||||
$${oRenderHash}{out}{$strKey} = $oRenderOutHash;
|
||||
}
|
||||
|
||||
${$self->{oManifest}}{render}{$strType} = $oRenderHash;
|
||||
}
|
||||
|
||||
# Read variables from manifest
|
||||
$self->variableListParse($self->{oManifestXml}->nodeGet('variable-list', false), $oVariableOverride);
|
||||
|
||||
# use Data::Dumper; confess Dumper($self->{oVariable});
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# isBackRest
|
||||
#
|
||||
# Until all the backrest specific code can be abstracted, this function will identify when BackRest docs are being built.
|
||||
####################################################################################################################################
|
||||
sub isBackRest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return($self->variableTest('project-exe', 'pg_backrest'));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# keywordMatch
|
||||
#
|
||||
# See if all the keywords were on the command line.
|
||||
####################################################################################################################################
|
||||
sub keywordMatch
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKeywordRequired = shift;
|
||||
|
||||
if (defined($strKeywordRequired))
|
||||
{
|
||||
for my $strKeyword (split(',', $strKeywordRequired))
|
||||
{
|
||||
$strKeyword = trim($strKeyword);
|
||||
|
||||
if (!grep(/^$strKeyword$/, @{$self->{stryKeyword}}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableListParse
|
||||
#
|
||||
# Parse a variable list and store variables.
|
||||
####################################################################################################################################
|
||||
sub variableListParse
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oVariableList,
|
||||
$oVariableOverride
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_VARIABLE_LIST_PARSE, \@_,
|
||||
{name => '$oVariableList', required => false},
|
||||
{name => '$oVariableOverride', required => false}
|
||||
);
|
||||
|
||||
if (defined($oVariableList))
|
||||
{
|
||||
foreach my $oVariable ($oVariableList->nodeList('variable'))
|
||||
{
|
||||
if ($self->keywordMatch($oVariable->paramGet('keyword', false)))
|
||||
{
|
||||
my $strKey = $oVariable->paramGet('key');
|
||||
my $strValue = $oVariable->valueGet();
|
||||
|
||||
if ($oVariable->paramTest('eval', 'y'))
|
||||
{
|
||||
$strValue = eval $strValue;
|
||||
|
||||
if ($@)
|
||||
{
|
||||
confess &log(ERROR, "unable to evaluate ${strKey}: $@\n" . $oVariable->valueGet());
|
||||
}
|
||||
}
|
||||
|
||||
$self->variableSet($strKey, defined($$oVariableOverride{$strKey}) ? $$oVariableOverride{$strKey} : $strValue);
|
||||
|
||||
logDebugMisc
|
||||
(
|
||||
$strOperation, ' load variable',
|
||||
{name => 'strKey', value => $strKey},
|
||||
{name => 'strValue', value => $strValue}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableReplace
|
||||
#
|
||||
# Replace variables in the string.
|
||||
####################################################################################################################################
|
||||
sub variableReplace
|
||||
{
|
||||
my $self = shift;
|
||||
my $strBuffer = shift;
|
||||
my $strType = shift;
|
||||
|
||||
if (!defined($strBuffer))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
foreach my $strName (sort(keys(%{$self->{oVariable}})))
|
||||
{
|
||||
my $strValue = $self->{oVariable}{$strName};
|
||||
|
||||
$strBuffer =~ s/\{\[$strName\]\}/$strValue/g;
|
||||
}
|
||||
|
||||
if (defined($strType) && $strType eq 'latex')
|
||||
{
|
||||
$strBuffer =~ s/\\\_/\_/g;
|
||||
$strBuffer =~ s/\_/\\\_/g;
|
||||
$strBuffer =~ s/\\\#/\#/g;
|
||||
$strBuffer =~ s/\#/\\\#/g;
|
||||
}
|
||||
|
||||
return $strBuffer;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableSet
|
||||
#
|
||||
# Set a variable to be replaced later.
|
||||
####################################################################################################################################
|
||||
sub variableSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKey = shift;
|
||||
my $strValue = shift;
|
||||
my $bForce = shift;
|
||||
|
||||
if (defined(${$self->{oVariable}}{$strKey}) && (!defined($bForce) || !$bForce))
|
||||
{
|
||||
confess &log(ERROR, "${strKey} variable is already defined");
|
||||
}
|
||||
|
||||
${$self->{oVariable}}{$strKey} = $self->variableReplace($strValue);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableGet
|
||||
#
|
||||
# Get the current value of a variable.
|
||||
####################################################################################################################################
|
||||
sub variableGet
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKey = shift;
|
||||
|
||||
return ${$self->{oVariable}}{$strKey};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableTest
|
||||
#
|
||||
# Test that a variable is defined or has an expected value.
|
||||
####################################################################################################################################
|
||||
sub variableTest
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKey = shift;
|
||||
my $strExpectedValue = shift;
|
||||
|
||||
# Get the variable
|
||||
my $strValue = ${$self->{oVariable}}{$strKey};
|
||||
|
||||
# Return false if it is not defined
|
||||
if (!defined($strValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# Return false if it does not equal the expected value
|
||||
if (defined($strExpectedValue) && $strValue ne $strExpectedValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# sourceGet
|
||||
####################################################################################################################################
|
||||
sub sourceGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strSource
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_SOURCE_GET, \@_,
|
||||
{name => 'strSource', trace => true}
|
||||
);
|
||||
|
||||
if (!defined(${$self->{oManifest}}{source}{$strSource}))
|
||||
{
|
||||
confess &log(ERROR, "source ${strSource} does not exist");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oSource', value => ${$self->{oManifest}}{source}{$strSource}}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# renderList
|
||||
####################################################################################################################################
|
||||
sub renderList
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(OP_DOC_MANIFEST_RENDER_LIST);
|
||||
|
||||
# Check that the render output exists
|
||||
my @stryRender;
|
||||
|
||||
if (defined(${$self->{oManifest}}{render}))
|
||||
{
|
||||
@stryRender = sort(keys(${$self->{oManifest}}{render}));
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'stryRender', value => \@stryRender}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# renderGet
|
||||
####################################################################################################################################
|
||||
sub renderGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strType
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_RENDER_GET, \@_,
|
||||
{name => 'strType', trace => true}
|
||||
);
|
||||
|
||||
# Check that the render exists
|
||||
if (!defined(${$self->{oManifest}}{render}{$strType}))
|
||||
{
|
||||
confess &log(ERROR, "render type ${strType} does not exist");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oRenderOut', value => ${$self->{oManifest}}{render}{$strType}}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# renderOutList
|
||||
####################################################################################################################################
|
||||
sub renderOutList
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strType
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_RENDER_OUT_LIST, \@_,
|
||||
{name => 'strType'}
|
||||
);
|
||||
|
||||
# Check that the render output exists
|
||||
my @stryRenderOut;
|
||||
|
||||
if (defined(${$self->{oManifest}}{render}{$strType}))
|
||||
{
|
||||
@stryRenderOut = sort(keys(${$self->{oManifest}}{render}{$strType}{out}));
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'stryRenderOut', value => \@stryRenderOut}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# renderOutGet
|
||||
####################################################################################################################################
|
||||
sub renderOutGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strType,
|
||||
$strKey
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_MANIFEST_RENDER_OUT_GET, \@_,
|
||||
{name => 'strType', trace => true},
|
||||
{name => 'strKey', trace => true}
|
||||
);
|
||||
|
||||
# use Data::Dumper; print Dumper(${$self->{oManifest}}{render});
|
||||
|
||||
if (!defined(${$self->{oManifest}}{render}{$strType}{out}{$strKey}))
|
||||
{
|
||||
confess &log(ERROR, "render out ${strKey} does not exist");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oRenderOut', value => ${$self->{oManifest}}{render}{$strType}{out}{$strKey}}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
@ -15,6 +15,8 @@ use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
@ -26,8 +28,6 @@ use constant OP_DOC_RENDER_PROCESS_TEXT => OP_DOC_RE
|
||||
use constant OP_DOC_RENDER_NEW => OP_DOC_RENDER . '->new';
|
||||
use constant OP_DOC_RENDER_SAVE => OP_DOC_RENDER . '->save';
|
||||
|
||||
# use HTML::HTML5::Builder qw[:standard JQUERY];
|
||||
|
||||
####################################################################################################################################
|
||||
# Render tags for various output types
|
||||
####################################################################################################################################
|
||||
@ -35,9 +35,10 @@ my $oRenderTag =
|
||||
{
|
||||
'markdown' =>
|
||||
{
|
||||
'quote' => ['"', '"'],
|
||||
'b' => ['**', '**'],
|
||||
'i' => ['_', '_'],
|
||||
'bi' => ['_**', '**_'],
|
||||
# 'bi' => ['_**', '**_'],
|
||||
'ul' => ["\n", "\n"],
|
||||
'ol' => ["\n", "\n"],
|
||||
'li' => ['- ', "\n"],
|
||||
@ -48,17 +49,18 @@ my $oRenderTag =
|
||||
'param' => ['`', '`'],
|
||||
'setting' => ['`', '`'],
|
||||
'code' => ['`', '`'],
|
||||
'code-block' => ['```', '```'],
|
||||
'exe' => [undef, ''],
|
||||
# 'code-block' => ['```', '```'],
|
||||
# 'exe' => [undef, ''],
|
||||
'backrest' => [undef, ''],
|
||||
'postgres' => ['PostgreSQL', '']
|
||||
},
|
||||
|
||||
'text' =>
|
||||
{
|
||||
'quote' => ['"', '"'],
|
||||
'b' => ['', ''],
|
||||
'i' => ['', ''],
|
||||
'bi' => ['', ''],
|
||||
# 'bi' => ['', ''],
|
||||
'ul' => ["\n", "\n"],
|
||||
'ol' => ["\n", "\n"],
|
||||
'li' => ['* ', "\n"],
|
||||
@ -76,15 +78,47 @@ my $oRenderTag =
|
||||
'postgres' => ['PostgreSQL', '']
|
||||
},
|
||||
|
||||
'latex' =>
|
||||
{
|
||||
'quote' => ['``', '"'],
|
||||
'b' => ['\textbf{', '}'],
|
||||
'i' => ['\textit{', '}'],
|
||||
# 'bi' => ['', ''],
|
||||
# 'ul' => ["\n", "\n"],
|
||||
# 'ol' => ["\n", "\n"],
|
||||
# 'li' => ['* ', "\n"],
|
||||
'id' => ['\textnormal{\texttt{', '}}'],
|
||||
'host' => ['\textnormal{\textbf{', '}}'],
|
||||
'file' => ['\textnormal{\texttt{', '}}'],
|
||||
'path' => ['\textnormal{\texttt{', '}}'],
|
||||
'cmd' => ['\textnormal{\texttt{', "}}"],
|
||||
'user' => ['\textnormal{\texttt{', '}}'],
|
||||
'br-option' => ['', ''],
|
||||
# 'param' => ['\texttt{', '}'],
|
||||
# 'setting' => ['\texttt{', '}'],
|
||||
'br-option' => ['\textnormal{\texttt{', '}}'],
|
||||
'br-setting' => ['\textnormal{\texttt{', '}}'],
|
||||
'pg-option' => ['\textnormal{\texttt{', '}}'],
|
||||
'pg-setting' => ['\textnormal{\texttt{', '}}'],
|
||||
'code' => ['\textnormal{\texttt{', '}}'],
|
||||
# 'code' => ['\texttt{', '}'],
|
||||
# 'code-block' => ['', ''],
|
||||
# 'exe' => [undef, ''],
|
||||
'backrest' => [undef, ''],
|
||||
'postgres' => ['PostgreSQL', '']
|
||||
},
|
||||
|
||||
'html' =>
|
||||
{
|
||||
'quote' => ['<q>', '</q>'],
|
||||
'b' => ['<b>', '</b>'],
|
||||
'i' => ['<i>', '</i>'],
|
||||
'bi' => ['<i><b>', '</b></i>'],
|
||||
# 'bi' => ['<i><b>', '</b></i>'],
|
||||
'ul' => ['<ul>', '</ul>'],
|
||||
'ol' => ['<ol>', '</ol>'],
|
||||
'li' => ['<li>', '</li>'],
|
||||
'id' => ['<span class="id">', '</span>'],
|
||||
'host' => ['<span class="host">', '</span>'],
|
||||
'file' => ['<span class="file">', '</span>'],
|
||||
'path' => ['<span class="path">', '</span>'],
|
||||
'cmd' => ['<span class="cmd">', '</span>'],
|
||||
@ -93,9 +127,9 @@ my $oRenderTag =
|
||||
'br-setting' => ['<span class="br-setting">', '</span>'],
|
||||
'pg-option' => ['<span class="pg-option">', '</span>'],
|
||||
'pg-setting' => ['<span class="pg-setting">', '</span>'],
|
||||
'code' => ['<id>', '</id>'],
|
||||
'code' => ['<span class="id">', '</span>'],
|
||||
'code-block' => ['<code-block>', '</code-block>'],
|
||||
'exe' => ['<id>', '</id>'],
|
||||
'exe' => [undef, ''],
|
||||
'setting' => ['<span class="br-setting">', '</span>'], # !!! This will need to be fixed
|
||||
'backrest' => [undef, ''],
|
||||
'postgres' => ['<span class="postgres">PostgreSQL</span>', '']
|
||||
@ -117,22 +151,76 @@ sub new
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strType},
|
||||
$self->{strProjectName},
|
||||
$self->{strExeName}
|
||||
$self->{oManifest},
|
||||
$self->{strRenderOutKey},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_RENDER_NEW, \@_,
|
||||
{name => 'strType'},
|
||||
{name => 'strProjectName'},
|
||||
{name => 'strExeName'}
|
||||
{name => 'oManifest'},
|
||||
{name => 'strRenderOutKey', required => false}
|
||||
);
|
||||
|
||||
$$oRenderTag{markdown}{backrest}[0] = $self->{strProjectName};
|
||||
$$oRenderTag{markdown}{exe}[0] = $self->{strExeName};
|
||||
$$oRenderTag{text}{backrest}[0] = $self->{strProjectName};
|
||||
$$oRenderTag{text}{exe}[0] = $self->{strExeName};
|
||||
$$oRenderTag{html}{backrest}[0] = "<span class=\"backrest\">$self->{strProjectName}</span>";
|
||||
# Initialize project tags
|
||||
$$oRenderTag{markdown}{backrest}[0] = "{[project]}";
|
||||
$$oRenderTag{markdown}{exe}[0] = "{[project-exe]}";
|
||||
|
||||
$$oRenderTag{text}{backrest}[0] = "{[project]}";
|
||||
$$oRenderTag{text}{exe}[0] = "{[project-exe]}";
|
||||
|
||||
$$oRenderTag{latex}{backrest}[0] = "{[project]}";
|
||||
$$oRenderTag{latex}{exe}[0] = "\\textnormal\{\\texttt\{[project-exe]}}\}\}";
|
||||
|
||||
$$oRenderTag{html}{backrest}[0] = "<span class=\"backrest\">{[project]}</span>";
|
||||
$$oRenderTag{html}{exe}[0] = "<span class=\"file\">{[project-exe]}</span>";
|
||||
|
||||
if (defined($self->{strRenderOutKey}))
|
||||
{
|
||||
# Copy page data to self
|
||||
my $oRenderOut = $self->{oManifest}->renderOutGet($self->{strType} eq 'latex' ? 'pdf' : $self->{strType}, $self->{strRenderOutKey});
|
||||
|
||||
# Get the reference if this is the backrest project
|
||||
if ($self->{oManifest}->isBackRest())
|
||||
{
|
||||
$self->{oReference} = new BackRestDoc::Common::DocConfig(${$self->{oManifest}->sourceGet('reference')}{doc}, $self);
|
||||
}
|
||||
|
||||
if (defined($$oRenderOut{source}) && $$oRenderOut{source} eq 'reference')
|
||||
{
|
||||
if ($self->{strRenderOutKey} eq 'configuration')
|
||||
{
|
||||
$self->{oDoc} = $self->{oReference}->helpConfigDocGet();
|
||||
}
|
||||
elsif ($self->{strRenderOutKey} eq 'command')
|
||||
{
|
||||
$self->{oDoc} = $self->{oReference}->helpCommandDocGet();
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ERROR, "cannot render $self->{strRenderOutKey} from source $$oRenderOut{source}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$self->{oDoc} = ${$self->{oManifest}->sourceGet($self->{strRenderOutKey})}{doc};
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($self->{strRenderOutKey}))
|
||||
{
|
||||
# Build the doc
|
||||
$self->build($self->{oDoc});
|
||||
|
||||
# Get required sections
|
||||
foreach my $strPath (@{$self->{oManifest}->{stryRequire}})
|
||||
{
|
||||
if (defined(${$self->{oSection}}{$strPath}))
|
||||
{
|
||||
$self->required($strPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
@ -142,6 +230,183 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableReplace
|
||||
#
|
||||
# Replace variables in the string.
|
||||
####################################################################################################################################
|
||||
sub variableReplace
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{oManifest}->variableReplace(shift, $self->{strType});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableSet
|
||||
#
|
||||
# Set a variable to be replaced later.
|
||||
####################################################################################################################################
|
||||
sub variableSet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{oManifest}->variableSet(shift, shift);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableGet
|
||||
#
|
||||
# Get the current value of a variable.
|
||||
####################################################################################################################################
|
||||
sub variableGet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{oManifest}->variableGet(shift);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# build
|
||||
#
|
||||
# Build the section map and perform keyword matching.
|
||||
####################################################################################################################################
|
||||
sub build
|
||||
{
|
||||
my $self = shift;
|
||||
my $oNode = shift;
|
||||
my $oParent = shift;
|
||||
my $strPath = shift;
|
||||
|
||||
# &log(INFO, " node " . $oNode->nameGet());
|
||||
|
||||
my $strName = $oNode->nameGet();
|
||||
|
||||
if (defined($oParent))
|
||||
{
|
||||
if (!$self->{oManifest}->keywordMatch($oNode->paramGet('keyword', false)))
|
||||
{
|
||||
my $strDescription;
|
||||
|
||||
if (defined($oNode->nodeGet('title', false)))
|
||||
{
|
||||
$strDescription = $self->processText($oNode->nodeGet('title')->textGet());
|
||||
}
|
||||
|
||||
&log(DEBUG, " filtered ${strName}" . (defined($strDescription) ? ": ${strDescription}" : ''));
|
||||
|
||||
$oParent->nodeRemove($oNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
&log(DEBUG, ' build document');
|
||||
$self->{oSection} = {};
|
||||
}
|
||||
|
||||
if ($strName eq 'section')
|
||||
{
|
||||
if (defined($strPath))
|
||||
{
|
||||
$oNode->paramSet('path-parent', $strPath);
|
||||
}
|
||||
|
||||
$strPath .= '/' . $oNode->paramGet('id');
|
||||
|
||||
&log(DEBUG, " path ${strPath}");
|
||||
${$self->{oSection}}{$strPath} = $oNode;
|
||||
$oNode->paramSet('path', $strPath);
|
||||
}
|
||||
|
||||
# Iterate all nodes
|
||||
foreach my $oChild ($oNode->nodeList(undef, false))
|
||||
{
|
||||
$self->build($oChild, $oNode, $strPath);
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# required
|
||||
#
|
||||
# Build a list of required sections
|
||||
####################################################################################################################################
|
||||
sub required
|
||||
{
|
||||
my $self = shift;
|
||||
my $strPath = shift;
|
||||
my $bDepend = shift;
|
||||
|
||||
# If node is not found that means the path is invalid
|
||||
my $oNode = ${$self->{oSection}}{$strPath};
|
||||
|
||||
if (!defined($oNode))
|
||||
{
|
||||
confess &log(ERROR, "invalid path ${strPath}");
|
||||
}
|
||||
|
||||
# Only add sections that are listed dependencies
|
||||
if (!defined($bDepend) || $bDepend)
|
||||
{
|
||||
# Match section and all child sections
|
||||
foreach my $strChildPath (sort(keys($self->{oSection})))
|
||||
{
|
||||
if ($strChildPath =~ /^$strPath$/ || $strChildPath =~ /^$strPath\/.*$/)
|
||||
{
|
||||
&log(INFO, " require section: ${strChildPath}");
|
||||
|
||||
${$self->{oSectionRequired}}{$strChildPath} = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Get the path of the current section's parent
|
||||
my $strParentPath = $oNode->paramGet('path-parent', false);
|
||||
|
||||
if ($oNode->paramTest('depend'))
|
||||
{
|
||||
foreach my $strDepend (split(',', $oNode->paramGet('depend')))
|
||||
{
|
||||
if ($strDepend !~ /^\//)
|
||||
{
|
||||
if (!defined($strParentPath))
|
||||
{
|
||||
$strDepend = "/${strDepend}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$strDepend = "${strParentPath}/${strDepend}";
|
||||
}
|
||||
}
|
||||
|
||||
$self->required($strDepend, true);
|
||||
}
|
||||
}
|
||||
elsif (defined($strParentPath))
|
||||
{
|
||||
$self->required($strParentPath, false);
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# isRequired
|
||||
#
|
||||
# Is it required to execute the section statements?
|
||||
####################################################################################################################################
|
||||
sub isRequired
|
||||
{
|
||||
my $self = shift;
|
||||
my $oSection = shift;
|
||||
|
||||
if (!defined($self->{oSectionRequired}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
my $strPath = $oSection->paramGet('path');
|
||||
|
||||
defined(${$self->{oSectionRequired}}{$strPath}) ? true : false;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# process
|
||||
#
|
||||
@ -168,7 +433,6 @@ sub process
|
||||
);
|
||||
|
||||
my $strType = $self->{strType};
|
||||
my $strProjectName = $self->{strProjectName};
|
||||
|
||||
my $strBuffer = "";
|
||||
my $bList = $oDoc->nameGet() =~ /.*-bullet-list$/;
|
||||
@ -211,7 +475,7 @@ sub process
|
||||
$strBuffer .= 'v' . $oDoc->paramGet('version') . ': ';
|
||||
}
|
||||
|
||||
$strBuffer .= ($iDepth == 1 ? "${strProjectName}<br/>" : '') . $strTitle;
|
||||
$strBuffer .= ($iDepth == 1 ? "{[project]}<br/>" : '') . $strTitle;
|
||||
|
||||
if (defined($oDoc->paramGet('date', false)))
|
||||
{
|
||||
@ -369,6 +633,10 @@ sub processTag
|
||||
|
||||
$strBuffer = '<a href="' . $strUrl . '">' . $oTag->valueGet() . '</a>';
|
||||
}
|
||||
elsif ($strType eq 'latex')
|
||||
{
|
||||
$strBuffer = $oTag->valueGet();
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "tag link not valid for type ${strType}";
|
||||
@ -439,6 +707,11 @@ sub processText
|
||||
{
|
||||
if (ref(\$oNode) eq "SCALAR")
|
||||
{
|
||||
if ($oNode =~ /\"/)
|
||||
{
|
||||
confess &log(ERROR, "unable to process quotes in string (use <quote> instead):\n${oNode}");
|
||||
}
|
||||
|
||||
$strBuffer .= $oNode;
|
||||
}
|
||||
else
|
||||
@ -462,6 +735,17 @@ sub processText
|
||||
$strBuffer =~ s/^ //smg;
|
||||
# }
|
||||
|
||||
if ($strType eq 'latex')
|
||||
{
|
||||
$strBuffer =~ s/\&mdash\;/---/g;
|
||||
$strBuffer =~ s/\<\;/\</g;
|
||||
$strBuffer =~ s/\<\=/\$\\leq\$/g;
|
||||
$strBuffer =~ s/\>\=/\$\\geq\$/g;
|
||||
# $strBuffer =~ s/\_/\\_/g;
|
||||
}
|
||||
|
||||
$strBuffer = $self->variableReplace($strBuffer);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
|
@ -44,13 +44,15 @@ sub new
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strName},
|
||||
$self->{strTitle}
|
||||
$self->{strTitle},
|
||||
$self->{bPretty}
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_BUILDER_NEW, \@_,
|
||||
{name => 'strName'},
|
||||
{name => 'strTitle'}
|
||||
{name => 'strTitle'},
|
||||
{name => 'bPretty', default => false}
|
||||
);
|
||||
|
||||
$self->{oBody} = new BackRestDoc::Html::DocHtmlElement(HTML_BODY);
|
||||
@ -73,7 +75,7 @@ sub indent
|
||||
my $self = shift;
|
||||
my $iDepth = shift;
|
||||
|
||||
return (' ' x $iDepth);
|
||||
return $self->{bPretty} ? (' ' x $iDepth) : '';
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -85,7 +87,7 @@ sub lf
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return "\n";
|
||||
return $self->{bPretty} ? "\n" : '';
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -118,8 +120,8 @@ sub htmlRender
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_BUILDER_HTML_RENDER, \@_,
|
||||
{name => 'oElement'},
|
||||
{name => 'iDepth'}
|
||||
{name => 'oElement', trace => true},
|
||||
{name => 'iDepth', trace => true}
|
||||
);
|
||||
|
||||
# Build the header
|
||||
@ -131,8 +133,19 @@ sub htmlRender
|
||||
|
||||
if (defined($oElement->{strContent}))
|
||||
{
|
||||
$oElement->{strContent} =~ s/\n/\<br\/>\n/g;
|
||||
$strHtml .= $self->lf() . trim($oElement->{strContent}) . $self->lf() . $self->indent($iDepth);
|
||||
if (!defined($oElement->{bPre}) || !$oElement->{bPre})
|
||||
{
|
||||
$oElement->{strContent} =~ s/\n/\<br\/>\n/g;
|
||||
$oElement->{strContent} = trim($oElement->{strContent});
|
||||
$strHtml .= $self->lf();
|
||||
}
|
||||
|
||||
$strHtml .= $oElement->{strContent};
|
||||
|
||||
if (!defined($oElement->{bPre}) || !$oElement->{bPre})
|
||||
{
|
||||
$strHtml .= $self->lf() . $self->indent($iDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -32,6 +32,8 @@ use constant HTML_A => 'a';
|
||||
push @EXPORT, qw(HTML_A);
|
||||
use constant HTML_BODY => 'body';
|
||||
push @EXPORT, qw(HTML_BODY);
|
||||
use constant HTML_PRE => 'pre';
|
||||
push @EXPORT, qw(HTML_PRE);
|
||||
use constant HTML_DIV => 'div';
|
||||
push @EXPORT, qw(HTML_DIV);
|
||||
use constant HTML_SPAN => 'span';
|
||||
@ -69,6 +71,7 @@ sub new
|
||||
$self->{strContent} = $$oParam{strContent};
|
||||
$self->{strId} = $$oParam{strId};
|
||||
$self->{strRef} = $$oParam{strRef};
|
||||
$self->{bPre} = $$oParam{bPre};
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
|
@ -2,6 +2,7 @@
|
||||
# DOC HTML PAGE MODULE
|
||||
####################################################################################################################################
|
||||
package BackRestDoc::Html::DocHtmlPage;
|
||||
use parent 'BackRestDoc::Common::DocExecute';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
@ -15,15 +16,11 @@ use File::Copy;
|
||||
use Storable qw(dclone);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Ini;
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::Config::ConfigHelp;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
use lib dirname($0) . '/../test/lib';
|
||||
use BackRestTest::Common::ExecuteTest;
|
||||
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
use BackRestDoc::Html::DocHtmlBuilder;
|
||||
use BackRestDoc::Html::DocHtmlElement;
|
||||
|
||||
@ -33,7 +30,6 @@ use BackRestDoc::Html::DocHtmlElement;
|
||||
use constant OP_DOC_HTML_PAGE => 'DocHtmlPage';
|
||||
|
||||
use constant OP_DOC_HTML_PAGE_BACKREST_CONFIG_PROCESS => OP_DOC_HTML_PAGE . '->backrestConfigProcess';
|
||||
use constant OP_DOC_HTML_PAGE_EXECUTE => OP_DOC_HTML_PAGE . '->execute';
|
||||
use constant OP_DOC_HTML_PAGE_NEW => OP_DOC_HTML_PAGE . '->new';
|
||||
use constant OP_DOC_HTML_PAGE_POSTGRES_CONFIG_PROCESS => OP_DOC_HTML_PAGE . '->postgresConfigProcess';
|
||||
use constant OP_DOC_HTML_PAGE_PROCESS => OP_DOC_HTML_PAGE . '->process';
|
||||
@ -46,35 +42,25 @@ sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
$self->{strClass} = $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oSite},
|
||||
$self->{strPageId},
|
||||
$self->{bExe}
|
||||
$strOperation,
|
||||
$oManifest,
|
||||
$strRenderOutKey,
|
||||
$bExe
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_PAGE_NEW, \@_,
|
||||
{name => 'oSite'},
|
||||
{name => 'strPageId'},
|
||||
{name => 'bExe', default => true}
|
||||
{name => 'oManifest'},
|
||||
{name => 'strRenderOutKey'},
|
||||
{name => 'bExe'}
|
||||
);
|
||||
#
|
||||
# use Data::Dumper;
|
||||
# confess Dumper(${$self->{oSite}->{oSite}}{common}{oRender});
|
||||
|
||||
# Copy page data to self
|
||||
$self->{oPage} = ${$self->{oSite}->{oSite}}{page}{$self->{strPageId}};
|
||||
$self->{oDoc} = ${$self->{oPage}}{'oDoc'};
|
||||
$self->{oRender} = ${$self->{oSite}->{oSite}}{common}{oRender};
|
||||
$self->{oReference} = ${$self->{oSite}->{oSite}}{common}{oReference};
|
||||
# Create the class hash
|
||||
my $self = $class->SUPER::new(RENDER_TYPE_HTML, $oManifest, $strRenderOutKey, $bExe);
|
||||
bless $self, $class;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
@ -84,100 +70,6 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# execute
|
||||
####################################################################################################################################
|
||||
sub execute
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oCommand,
|
||||
$iIndent
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_PAGE_EXECUTE, \@_,
|
||||
{name => 'oCommand'},
|
||||
{name => 'iIndent', default => 1}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strOutput;
|
||||
|
||||
# Command variables
|
||||
my $strCommand = trim($oCommand->fieldGet('exe-cmd'));
|
||||
my $strUser = $oCommand->fieldGet('exe-user', false);
|
||||
my $bSuppressError = defined($oCommand->fieldGet('exe-err-suppress', false)) ? $oCommand->fieldGet('exe-err-suppress') : false;
|
||||
my $bSuppressStdErr = defined($oCommand->fieldGet('exe-err-suppress-stderr', false)) ?
|
||||
$oCommand->fieldGet('exe-err-suppress-stderr') : false;
|
||||
my $bExeSkip = defined($oCommand->fieldGet('exe-skip', false)) ? $oCommand->fieldGet('exe-skip') : false;
|
||||
my $bExeOutput = defined($oCommand->fieldGet('exe-output', false)) ? $oCommand->fieldGet('exe-output') : false;
|
||||
my $bExeRetry = defined($oCommand->fieldGet('exe-retry', false)) ? $oCommand->fieldGet('exe-retry') : false;
|
||||
my $strExeVar = defined($oCommand->fieldGet('exe-var', false)) ? $oCommand->fieldGet('exe-var') : undef;
|
||||
my $iExeExpectedError = defined($oCommand->fieldGet('exe-err-expect', false)) ? $oCommand->fieldGet('exe-err-expect') : undef;
|
||||
|
||||
if ($bExeRetry)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$strUser = defined($strUser) ? $strUser : 'postgres';
|
||||
$strCommand = $self->{oSite}->variableReplace(
|
||||
($strUser eq 'vagrant' ? '' : 'sudo ' . ($strUser eq 'root' ? '' : "-u ${strUser} ")) . $strCommand);
|
||||
|
||||
&log(INFO, (' ' x $iIndent) . "execute: $strCommand");
|
||||
|
||||
if (!$bExeSkip)
|
||||
{
|
||||
if ($self->{bExe})
|
||||
{
|
||||
my $oExec = new BackRestTest::Common::ExecuteTest($strCommand,
|
||||
{bSuppressError => $bSuppressError,
|
||||
bSuppressStdErr => $bSuppressStdErr,
|
||||
iExpectedExitStatus => $iExeExpectedError});
|
||||
$oExec->begin();
|
||||
$oExec->end();
|
||||
|
||||
if ($bExeOutput && defined($oExec->{strOutLog}) && $oExec->{strOutLog} ne '')
|
||||
{
|
||||
$strOutput = trim($oExec->{strOutLog});
|
||||
$strOutput =~ s/^[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]\.[0-9]{3} T[0-9]{2} //smg;
|
||||
}
|
||||
|
||||
if (defined($strExeVar))
|
||||
{
|
||||
$self->{oSite}->variableSet($strExeVar, trim($oExec->{strOutLog}));
|
||||
}
|
||||
|
||||
if (defined($iExeExpectedError))
|
||||
{
|
||||
$strOutput .= trim($oExec->{strErrorLog});
|
||||
}
|
||||
}
|
||||
elsif ($bExeOutput)
|
||||
{
|
||||
$strOutput = 'Output suppressed for testing';
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($strExeVar) && !defined($self->{oSite}->variableGet($strExeVar)))
|
||||
{
|
||||
$self->{oSite}->variableSet($strExeVar, '[Unset Variable]');
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => '$strCommand', value => $strCommand, trace => true},
|
||||
{name => '$strOutput', value => $strOutput, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# process
|
||||
#
|
||||
@ -194,23 +86,13 @@ sub process
|
||||
my $oPage = $self->{oDoc};
|
||||
|
||||
# Initialize page
|
||||
my $strTitle = ${$self->{oRender}}{strProjectName} .
|
||||
my $strTitle = "{[project]}" .
|
||||
(defined($oPage->paramGet('title', false)) ? ' ' . $oPage->paramGet('title') : '');
|
||||
my $strSubTitle = $oPage->paramGet('subtitle', false);
|
||||
|
||||
my $oHtmlBuilder = new BackRestDoc::Html::DocHtmlBuilder("${$self->{oRender}}{strProjectName} - Reliable PostgreSQL Backup",
|
||||
$strTitle . (defined($strSubTitle) ? " - ${strSubTitle}" : ''));
|
||||
|
||||
# Execute cleanup commands
|
||||
if (defined($self->{oDoc}->nodeGet('cleanup', false)))
|
||||
{
|
||||
&log(INFO, "do cleanup");
|
||||
|
||||
foreach my $oExecute ($oPage->nodeGet('cleanup')->nodeList('execute'))
|
||||
{
|
||||
$self->execute($oExecute);
|
||||
}
|
||||
}
|
||||
my $oHtmlBuilder = new BackRestDoc::Html::DocHtmlBuilder("{[project]} - Reliable PostgreSQL Backup",
|
||||
$strTitle . (defined($strSubTitle) ? " - ${strSubTitle}" : ''),
|
||||
$self->{bPretty});
|
||||
|
||||
# Generate header
|
||||
my $oPageHeader = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-header');
|
||||
@ -229,24 +111,24 @@ sub process
|
||||
# Generate menu
|
||||
my $oMenuBody = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-menu')->addNew(HTML_DIV, 'menu-body');
|
||||
|
||||
if ($self->{strPageId} ne 'index')
|
||||
if ($self->{strRenderOutKey} ne 'index')
|
||||
{
|
||||
my $oPage = ${$self->{oSite}->{oSite}}{page}{'index'};
|
||||
my $oRenderOut = $self->{oManifest}->renderOutGet(RENDER_TYPE_HTML, 'index');
|
||||
|
||||
$oMenuBody->
|
||||
addNew(HTML_DIV, 'menu')->
|
||||
addNew(HTML_A, 'menu-link', {strContent => $$oPage{strMenuTitle}, strRef => '{[backrest-url-root]}'});
|
||||
addNew(HTML_A, 'menu-link', {strContent => $$oRenderOut{menu}, strRef => '{[project-url-root]}'});
|
||||
}
|
||||
|
||||
foreach my $strPageId(sort(keys(${$self->{oSite}->{oSite}}{page})))
|
||||
foreach my $strRenderOutKey ($self->{oManifest}->renderOutList(RENDER_TYPE_HTML))
|
||||
{
|
||||
if ($strPageId ne $self->{strPageId} && $strPageId ne 'index')
|
||||
if ($strRenderOutKey ne $self->{strRenderOutKey} && $strRenderOutKey ne 'index')
|
||||
{
|
||||
my $oPage = ${$self->{oSite}->{oSite}}{page}{$strPageId};
|
||||
my $oRenderOut = $self->{oManifest}->renderOutGet(RENDER_TYPE_HTML, $strRenderOutKey);
|
||||
|
||||
$oMenuBody->
|
||||
addNew(HTML_DIV, 'menu')->
|
||||
addNew(HTML_A, 'menu-link', {strContent => $$oPage{strMenuTitle}, strRef => "${strPageId}.html"});
|
||||
addNew(HTML_A, 'menu-link', {strContent => $$oRenderOut{menu}, strRef => "${strRenderOutKey}.html"});
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,7 +166,7 @@ sub process
|
||||
|
||||
my $oPageFooter = $oHtmlBuilder->bodyGet()->
|
||||
addNew(HTML_DIV, 'page-footer',
|
||||
{strContent => ${$self->{oSite}->{oSite}}{common}{strFooter}});
|
||||
{strContent => '{[html-footer]}'});
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
@ -317,7 +199,7 @@ sub sectionProcess
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
&log(INFO, (' ' x ($iDepth - 1)) . 'process section: ' . $oSection->paramGet('id'));
|
||||
&log($iDepth == 1 ? INFO : DEBUG, (' ' x ($iDepth + 1)) . 'process section: ' . $oSection->paramGet('id'));
|
||||
|
||||
if ($iDepth > 3)
|
||||
{
|
||||
@ -326,7 +208,6 @@ sub sectionProcess
|
||||
|
||||
# Working variables
|
||||
$strAnchor = (defined($strAnchor) ? "${strAnchor}-" : '') . $oSection->paramGet('id');
|
||||
my $oRender = $self->{oRender};
|
||||
|
||||
# Create the section toc element
|
||||
my $oSectionTocElement = new BackRestDoc::Html::DocHtmlElement(HTML_DIV, "section${iDepth}-toc");
|
||||
@ -338,7 +219,7 @@ sub sectionProcess
|
||||
$oSectionElement->addNew(HTML_A, undef, {strId => $strAnchor});
|
||||
|
||||
# Add the section title to section and toc
|
||||
my $strSectionTitle = $oRender->processText($oSection->nodeGet('title')->textGet());
|
||||
my $strSectionTitle = $self->processText($oSection->nodeGet('title')->textGet());
|
||||
|
||||
$oSectionElement->
|
||||
addNew(HTML_DIV, "section${iDepth}-title",
|
||||
@ -356,7 +237,7 @@ sub sectionProcess
|
||||
{
|
||||
$oSectionElement->
|
||||
addNew(HTML_DIV, "section-intro",
|
||||
{strContent => $oRender->processText($oSection->textGet())});
|
||||
{strContent => $self->processText($oSection->textGet())});
|
||||
}
|
||||
|
||||
# Add the section body
|
||||
@ -367,39 +248,51 @@ sub sectionProcess
|
||||
|
||||
foreach my $oChild ($oSection->nodeList())
|
||||
{
|
||||
&log(INFO, (' ' x $iDepth) . 'process child ' . $oChild->nameGet());
|
||||
&log(DEBUG, (' ' x ($iDepth + 2)) . 'process child ' . $oChild->nameGet());
|
||||
|
||||
# Execute a command
|
||||
if ($oChild->nameGet() eq 'execute-list')
|
||||
{
|
||||
my $oSectionBodyExecute = $oSectionBodyElement->addNew(HTML_DIV, "execute");
|
||||
my $bFirst = true;
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oChild->paramGet('host'));
|
||||
|
||||
$oSectionBodyExecute->
|
||||
addNew(HTML_DIV, "execute-title",
|
||||
{strContent => $oRender->processText($oChild->nodeGet('title')->textGet()) . ':'});
|
||||
{strContent => "<span class=\"host\">${strHostName}</span> <b>⇒</b> " .
|
||||
$self->processText($oChild->nodeGet('title')->textGet())});
|
||||
|
||||
my $oExecuteBodyElement = $oSectionBodyExecute->addNew(HTML_DIV, "execute-body");
|
||||
|
||||
foreach my $oExecute ($oChild->nodeList('execute'))
|
||||
{
|
||||
my $bExeShow = defined($oExecute->fieldGet('exe-no-show', false)) ? false : true;
|
||||
my $bExeExpectedError = defined($oExecute->fieldGet('exe-err-expect', false)) ? true : false;
|
||||
my ($strCommand, $strOutput) = $self->execute($oExecute, $iDepth + 1);
|
||||
my $bExeShow = !$oExecute->paramTest('show', 'n');
|
||||
my $bExeExpectedError = defined($oExecute->paramGet('err-expect', false));
|
||||
|
||||
my ($strCommand, $strOutput) = $self->execute($oSection, $strHostName, $oExecute, $iDepth + 3);
|
||||
|
||||
if ($bExeShow)
|
||||
{
|
||||
# Add continuation chars and proper spacing
|
||||
$strCommand =~ s/\n/\n /smg;
|
||||
|
||||
$oExecuteBodyElement->
|
||||
addNew(HTML_DIV, "execute-body-cmd" . ($bFirst ? '-first' : ''),
|
||||
{strContent => $strCommand});
|
||||
addNew(HTML_PRE, "execute-body-cmd",
|
||||
{strContent => $strCommand, bPre => true});
|
||||
|
||||
my $strHighLight = $self->{oManifest}->variableReplace($oExecute->fieldGet('exe-highlight', false));
|
||||
my $bHighLightFound = false;
|
||||
|
||||
if (defined($strOutput))
|
||||
{
|
||||
my $strHighLight = $self->{oSite}->variableReplace($oExecute->fieldGet('exe-highlight', false));
|
||||
my $bHighLightOld;
|
||||
my $bHighLightFound = false;
|
||||
my $strHighLightOutput;
|
||||
|
||||
if ($oExecute->fieldTest('exe-highlight-type', 'error'))
|
||||
{
|
||||
$bExeExpectedError = true;
|
||||
}
|
||||
|
||||
foreach my $strLine (split("\n", $strOutput))
|
||||
{
|
||||
my $bHighLight = defined($strHighLight) && $strLine =~ /$strHighLight/;
|
||||
@ -407,13 +300,14 @@ sub sectionProcess
|
||||
if (defined($bHighLightOld) && $bHighLight != $bHighLightOld)
|
||||
{
|
||||
$oExecuteBodyElement->
|
||||
addNew(HTML_DIV, 'execute-body-output' . ($bHighLightOld ? '-highlight' : '') .
|
||||
($bExeExpectedError ? '-error' : ''), {strContent => $strHighLightOutput});
|
||||
addNew(HTML_PRE, 'execute-body-output' .
|
||||
($bHighLightOld ? '-highlight' . ($bExeExpectedError ? '-error' : '') : ''),
|
||||
{strContent => $strHighLightOutput, bPre => true});
|
||||
|
||||
undef($strHighLightOutput);
|
||||
}
|
||||
|
||||
$strHighLightOutput .= "${strLine}\n";
|
||||
$strHighLightOutput .= (defined($strHighLightOutput) ? "\n" : '') . $strLine;
|
||||
$bHighLightOld = $bHighLight;
|
||||
|
||||
$bHighLightFound = $bHighLightFound ? true : $bHighLight ? true : false;
|
||||
@ -422,19 +316,18 @@ sub sectionProcess
|
||||
if (defined($bHighLightOld))
|
||||
{
|
||||
$oExecuteBodyElement->
|
||||
addNew(HTML_DIV, 'execute-body-output' . ($bHighLightOld ? '-highlight' : ''),
|
||||
{strContent => $strHighLightOutput});
|
||||
|
||||
undef($strHighLightOutput);
|
||||
}
|
||||
|
||||
if ($self->{bExe} && defined($strHighLight) && !$bHighLightFound)
|
||||
{
|
||||
confess &log(ERROR, "unable to find a match for highlight: ${strHighLight}");
|
||||
addNew(HTML_PRE, 'execute-body-output' .
|
||||
($bHighLightOld ? '-highlight' . ($bExeExpectedError ? '-error' : '') : ''),
|
||||
{strContent => $strHighLightOutput, bPre => true});
|
||||
}
|
||||
|
||||
$bFirst = true;
|
||||
}
|
||||
|
||||
if ($self->{bExe} && $self->isRequired($oSection) && defined($strHighLight) && !$bHighLightFound)
|
||||
{
|
||||
confess &log(ERROR, "unable to find a match for highlight: ${strHighLight}");
|
||||
}
|
||||
}
|
||||
|
||||
$bFirst = false;
|
||||
@ -452,7 +345,7 @@ sub sectionProcess
|
||||
{
|
||||
$oSectionBodyElement->
|
||||
addNew(HTML_DIV, 'section-body-text',
|
||||
{strContent => $oRender->processText($oChild->textGet())});
|
||||
{strContent => $self->processText($oChild->textGet())});
|
||||
}
|
||||
# Add option descriptive text
|
||||
elsif ($oChild->nameGet() eq 'option-description')
|
||||
@ -467,17 +360,27 @@ sub sectionProcess
|
||||
|
||||
$oSectionBodyElement->
|
||||
addNew(HTML_DIV, 'section-body-text',
|
||||
{strContent => $oRender->processText($oDescription)});
|
||||
{strContent => $self->processText($oDescription)});
|
||||
}
|
||||
# Add/remove backrest config options
|
||||
elsif ($oChild->nameGet() eq 'backrest-config')
|
||||
{
|
||||
$oSectionBodyElement->add($self->backrestConfigProcess($oChild, $iDepth));
|
||||
my $oConfigElement = $self->backrestConfigProcess($oSection, $oChild, $iDepth + 3);
|
||||
|
||||
if (defined($oConfigElement))
|
||||
{
|
||||
$oSectionBodyElement->add($oConfigElement);
|
||||
}
|
||||
}
|
||||
# Add/remove postgres config options
|
||||
elsif ($oChild->nameGet() eq 'postgres-config')
|
||||
{
|
||||
$oSectionBodyElement->add($self->postgresConfigProcess($oChild, $iDepth));
|
||||
my $oConfigElement = $self->postgresConfigProcess($oSection, $oChild, $iDepth + 3);
|
||||
|
||||
if (defined($oConfigElement))
|
||||
{
|
||||
$oSectionBodyElement->add($oConfigElement);
|
||||
}
|
||||
}
|
||||
# Add a subsection
|
||||
elsif ($oChild->nameGet() eq 'section')
|
||||
@ -488,10 +391,10 @@ sub sectionProcess
|
||||
$oSectionBodyElement->add($oChildSectionElement);
|
||||
$oSectionTocElement->add($oChildSectionTocElement);
|
||||
}
|
||||
# Skip children that have already been processed and error on others
|
||||
elsif ($oChild->nameGet() ne 'title')
|
||||
# Check if the child can be processed by a parent
|
||||
else
|
||||
{
|
||||
confess &log(ASSERT, 'unable to find child type ' . $oChild->nameGet());
|
||||
$self->sectionChildProcess($oSection, $oChild, $iDepth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -515,69 +418,45 @@ sub backrestConfigProcess
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oConfig,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_PAGE_BACKREST_CONFIG_PROCESS, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oConfig'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
# Get filename
|
||||
my $strFile = $self->{oSite}->variableReplace($oConfig->paramGet('file'));
|
||||
# Generate the config
|
||||
my $oConfigElement;
|
||||
my ($strFile, $strConfig, $bShow) = $self->backrestConfig($oSection, $oConfig, $iDepth);
|
||||
|
||||
&log(INFO, (' ' x $iDepth) . 'process backrest config: ' . $strFile);
|
||||
|
||||
foreach my $oOption ($oConfig->nodeList('backrest-config-option'))
|
||||
if ($bShow)
|
||||
{
|
||||
my $strSection = $oOption->fieldGet('backrest-config-option-section');
|
||||
my $strKey = $oOption->fieldGet('backrest-config-option-key');
|
||||
my $strValue = $self->{oSite}->variableReplace(trim($oOption->fieldGet('backrest-config-option-value'), false));
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
||||
|
||||
if (!defined($strValue))
|
||||
{
|
||||
delete(${$self->{config}}{$strFile}{$strSection}{$strKey});
|
||||
# Render the config
|
||||
$oConfigElement = new BackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
||||
|
||||
if (keys(${$self->{config}}{$strFile}{$strSection}) == 0)
|
||||
{
|
||||
delete(${$self->{config}}{$strFile}{$strSection});
|
||||
}
|
||||
$oConfigElement->
|
||||
addNew(HTML_DIV, "config-title",
|
||||
{strContent => "<span class=\"host\">${strHostName}</span>:<span class=\"file\">${strFile}</span>" .
|
||||
" <b>⇒</b> " . $self->processText($oConfig->nodeGet('title')->textGet())});
|
||||
|
||||
&log(INFO, (' ' x ($iDepth + 1)) . "reset ${strSection}->${strKey}");
|
||||
}
|
||||
else
|
||||
{
|
||||
${$self->{config}}{$strFile}{$strSection}{$strKey} = $strValue;
|
||||
&log(INFO, (' ' x ($iDepth + 1)) . "set ${strSection}->${strKey} = ${strValue}");
|
||||
}
|
||||
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
||||
#
|
||||
# $oConfigBodyElement->
|
||||
# addNew(HTML_DIV, "config-body-title",
|
||||
# {strContent => "${strFile}:"});
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-output",
|
||||
{strContent => $strConfig});
|
||||
}
|
||||
|
||||
# Save the ini file
|
||||
executeTest("sudo chmod 777 $strFile", {bSuppressError => true});
|
||||
iniSave($strFile, $self->{config}{$strFile}, true);
|
||||
|
||||
# Generate config element
|
||||
my $oConfigElement = new BackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
||||
|
||||
$oConfigElement->
|
||||
addNew(HTML_DIV, "config-title",
|
||||
{strContent => $self->{oRender}->processText($oConfig->nodeGet('title')->textGet()) . ':'});
|
||||
|
||||
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-title",
|
||||
{strContent => "${strFile}:"});
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-output",
|
||||
{strContent => fileStringRead($strFile)});
|
||||
|
||||
executeTest("sudo chown postgres:postgres $strFile");
|
||||
executeTest("sudo chmod 640 $strFile");
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
@ -597,97 +476,46 @@ sub postgresConfigProcess
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oConfig,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_PAGE_POSTGRES_CONFIG_PROCESS, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oConfig'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
# Get filename
|
||||
my $strFile = $self->{oSite}->variableReplace($oConfig->paramGet('file'));
|
||||
# Generate the config
|
||||
my $oConfigElement;
|
||||
my ($strFile, $strConfig, $bShow) = $self->postgresConfig($oSection, $oConfig, $iDepth);
|
||||
|
||||
if (!defined(${$self->{'pg-config'}}{$strFile}{base}))
|
||||
if ($bShow)
|
||||
{
|
||||
${$self->{'pg-config'}}{$strFile}{base} = fileStringRead($strFile);
|
||||
# Render the config
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
||||
$oConfigElement = new BackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
||||
|
||||
$oConfigElement->
|
||||
addNew(HTML_DIV, "config-title",
|
||||
{strContent => "<span class=\"host\">${strHostName}</span>:<span class=\"file\">${strFile}</span>" .
|
||||
" <b>⇒</b> " . $self->processText($oConfig->nodeGet('title')->textGet())});
|
||||
|
||||
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
||||
|
||||
# $oConfigBodyElement->
|
||||
# addNew(HTML_DIV, "config-body-title",
|
||||
# {strContent => "append to ${strFile}:"});
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-output",
|
||||
{strContent => defined($strConfig) ? $strConfig : '<No PgBackRest Settings>'});
|
||||
|
||||
$oConfig->fieldSet('actual-config', $strConfig);
|
||||
}
|
||||
|
||||
my $oConfigHash = $self->{'pg-config'}{$strFile};
|
||||
my $oConfigHashNew;
|
||||
|
||||
if (!defined($$oConfigHash{old}))
|
||||
{
|
||||
$oConfigHashNew = {};
|
||||
$$oConfigHash{old} = {}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oConfigHashNew = dclone($$oConfigHash{old});
|
||||
}
|
||||
|
||||
&log(INFO, (' ' x $iDepth) . 'process postgres config: ' . $strFile);
|
||||
|
||||
foreach my $oOption ($oConfig->nodeList('postgres-config-option'))
|
||||
{
|
||||
my $strKey = $oOption->paramGet('key');
|
||||
my $strValue = $self->{oSite}->variableReplace(trim($oOption->valueGet()));
|
||||
|
||||
if ($strValue eq '')
|
||||
{
|
||||
delete($$oConfigHashNew{$strKey});
|
||||
|
||||
&log(INFO, (' ' x ($iDepth + 1)) . "reset ${strKey}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$$oConfigHashNew{$strKey} = $strValue;
|
||||
&log(INFO, (' ' x ($iDepth + 1)) . "set ${strKey} = ${strValue}");
|
||||
}
|
||||
}
|
||||
|
||||
# Generate config text
|
||||
my $strConfig;
|
||||
|
||||
foreach my $strKey (sort(keys(%$oConfigHashNew)))
|
||||
{
|
||||
if (defined($strConfig))
|
||||
{
|
||||
$strConfig .= "\n";
|
||||
}
|
||||
|
||||
$strConfig .= "${strKey} = $$oConfigHashNew{$strKey}";
|
||||
}
|
||||
|
||||
# Save the conf file
|
||||
executeTest("sudo chown vagrant $strFile");
|
||||
|
||||
fileStringWrite($strFile, $$oConfigHash{base} .
|
||||
(defined($strConfig) ? "\n# pgBackRest Configuration\n${strConfig}" : ''));
|
||||
|
||||
executeTest("sudo chown postgres $strFile");
|
||||
|
||||
# Generate config element
|
||||
my $oConfigElement = new BackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
||||
|
||||
$oConfigElement->
|
||||
addNew(HTML_DIV, "config-title",
|
||||
{strContent => $self->{oRender}->processText($oConfig->nodeGet('title')->textGet()) . ':'});
|
||||
|
||||
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-title",
|
||||
{strContent => "append to ${strFile}:"});
|
||||
|
||||
$oConfigBodyElement->
|
||||
addNew(HTML_DIV, "config-body-output",
|
||||
{strContent => defined($strConfig) ? $strConfig : '<No PgBackRest Settings>'});
|
||||
|
||||
$$oConfigHash{old} = $oConfigHashNew;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
|
@ -25,6 +25,7 @@ use lib dirname($0) . '/../test/lib';
|
||||
use BackRestTest::Common::ExecuteTest;
|
||||
|
||||
use BackRestDoc::Common::DocConfig;
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
use BackRestDoc::Html::DocHtmlPage;
|
||||
|
||||
####################################################################################################################################
|
||||
@ -51,23 +52,19 @@ sub new
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oRender},
|
||||
$self->{oReference},
|
||||
$self->{oManifest},
|
||||
$self->{strXmlPath},
|
||||
$self->{strHtmlPath},
|
||||
$self->{strCssFile},
|
||||
$self->{strHtmlRoot},
|
||||
$self->{bExe}
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_HTML_SITE_NEW, \@_,
|
||||
{name => 'oRender'},
|
||||
{name => 'oReference'},
|
||||
{name => 'oManifest'},
|
||||
{name => 'strXmlPath'},
|
||||
{name => 'strHtmlPath'},
|
||||
{name => 'strCssFile'},
|
||||
{name => 'strHtmlRoot'},
|
||||
{name => 'bExe'}
|
||||
);
|
||||
|
||||
@ -83,74 +80,6 @@ sub new
|
||||
or confess &log(ERROR, "unable to create path $self->{strHtmlPath}");
|
||||
}
|
||||
|
||||
# Create the footer
|
||||
$self->{strFooter} = 'Copyright © 2015' . (strftime('%Y', localtime) ne '2015' ? '-' . strftime('%Y', localtime) : '') .
|
||||
', The PostgreSQL Global Development Group, <a href="{[github-url-license]}">MIT License</a>. Updated ' .
|
||||
strftime('%B ', localtime) . trim(strftime('%e,', localtime)) . strftime(' %Y.', localtime);
|
||||
|
||||
# Insert pages into the site hash
|
||||
$self->{oSite} =
|
||||
{
|
||||
'common' =>
|
||||
{
|
||||
'oRender' => $self->{oRender},
|
||||
'oReference' => $self->{oReference},
|
||||
'strFooter' => $self->{strFooter}
|
||||
},
|
||||
|
||||
'page' =>
|
||||
{
|
||||
'index' =>
|
||||
{
|
||||
strMenuTitle => 'Home',
|
||||
oDoc => new BackRestDoc::Common::Doc("$self->{strXmlPath}/index.xml")
|
||||
},
|
||||
|
||||
'command' =>
|
||||
{
|
||||
strMenuTitle => 'Commands',
|
||||
oDoc => $self->{oReference}->helpCommandDocGet()
|
||||
},
|
||||
|
||||
'configuration' =>
|
||||
{
|
||||
strMenuTitle => 'Configuration',
|
||||
oDoc => $self->{oReference}->helpConfigDocGet()
|
||||
# }
|
||||
},
|
||||
|
||||
'user-guide' =>
|
||||
{
|
||||
strMenuTitle => 'User Guide',
|
||||
oDoc => new BackRestDoc::Common::Doc("$self->{strXmlPath}/user-guide.xml")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
# Create common variables
|
||||
${$self->{var}}{version} = $VERSION;
|
||||
${$self->{var}}{'backrest-exe'} = $self->{oRender}->{strExeName};
|
||||
${$self->{var}}{'postgres'} = 'PostgreSQL';
|
||||
${$self->{var}}{'backrest-url-root'} = $self->{strHtmlRoot};
|
||||
${$self->{var}}{'dash'} = '-';
|
||||
|
||||
# Read variables from pages
|
||||
foreach my $strPageId (sort(keys(${$self->{oSite}}{page})))
|
||||
{
|
||||
my $oPage = ${$self->{oSite}}{page}{$strPageId};
|
||||
|
||||
if (defined($$oPage{oDoc}->nodeGet('variable-list', false)))
|
||||
{
|
||||
foreach my $oVariable ($$oPage{oDoc}->nodeGet('variable-list')->nodeList('variable'))
|
||||
{
|
||||
my $strName = $oVariable->fieldGet('variable-name');
|
||||
my $strValue = $oVariable->fieldGet('variable-value');
|
||||
|
||||
${$self->{var}}{$strName} = $self->variableReplace($strValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
@ -159,58 +88,6 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableReplace
|
||||
#
|
||||
# Replace variables in the string.
|
||||
####################################################################################################################################
|
||||
sub variableReplace
|
||||
{
|
||||
my $self = shift;
|
||||
my $strBuffer = shift;
|
||||
|
||||
if (!defined($strBuffer))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
foreach my $strName (sort(keys(%{$self->{var}})))
|
||||
{
|
||||
my $strValue = $self->{var}{$strName};
|
||||
|
||||
$strBuffer =~ s/\{\[$strName\]\}/$strValue/g;
|
||||
}
|
||||
|
||||
return $strBuffer;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableSet
|
||||
#
|
||||
# Set a variable to be replaced later.
|
||||
####################################################################################################################################
|
||||
sub variableSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKey = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
${$self->{var}}{$strKey} = $strValue;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# variableGet
|
||||
#
|
||||
# Get the current value of a variable.
|
||||
####################################################################################################################################
|
||||
sub variableGet
|
||||
{
|
||||
my $self = shift;
|
||||
my $strKey = shift;
|
||||
|
||||
return ${$self->{var}}{$strKey};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# process
|
||||
#
|
||||
@ -228,14 +105,14 @@ sub process
|
||||
copy($self->{strCssFile}, $strCssFileDestination)
|
||||
or confess &log(ERROR, "unable to copy $self->{strCssFile} to ${strCssFileDestination}");
|
||||
|
||||
# Render pages
|
||||
my $oSite = $self->{oSite};
|
||||
|
||||
foreach my $strPageId (sort(keys($$oSite{'page'})))
|
||||
foreach my $strPageId ($self->{oManifest}->renderOutList(RENDER_TYPE_HTML))
|
||||
{
|
||||
&log(INFO, " render out: ${strPageId}");
|
||||
|
||||
# Save the html page
|
||||
fileStringWrite("$self->{strHtmlPath}/${strPageId}.html",
|
||||
$self->variableReplace((new BackRestDoc::Html::DocHtmlPage($self, $strPageId, $self->{bExe}))->process()),
|
||||
$self->{oManifest}->variableReplace((new BackRestDoc::Html::DocHtmlPage($self->{oManifest},
|
||||
$strPageId, $self->{bExe}))->process()),
|
||||
false);
|
||||
}
|
||||
|
||||
|
137
doc/lib/BackRestDoc/Latex/DocLatex.pm
Normal file
137
doc/lib/BackRestDoc/Latex/DocLatex.pm
Normal file
@ -0,0 +1,137 @@
|
||||
####################################################################################################################################
|
||||
# DOC LATEX MODULE
|
||||
####################################################################################################################################
|
||||
package BackRestDoc::Latex::DocLatex;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Data::Dumper;
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use File::Copy;
|
||||
use POSIX qw(strftime);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::FileCommon;
|
||||
use BackRest::Version;
|
||||
|
||||
use lib dirname($0) . '/../test/lib';
|
||||
use BackRestTest::Common::ExecuteTest;
|
||||
|
||||
use BackRestDoc::Common::DocConfig;
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
use BackRestDoc::Latex::DocLatexSection;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
use constant OP_DOC_LATEX => 'DocLatex';
|
||||
|
||||
use constant OP_DOC_LATEX_NEW => OP_DOC_LATEX . '->new';
|
||||
use constant OP_DOC_LATEX_PROCESS => OP_DOC_LATEX . '->process';
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
$self->{strClass} = $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oManifest},
|
||||
$self->{strXmlPath},
|
||||
$self->{strLatexPath},
|
||||
$self->{strPreambleFile},
|
||||
$self->{bExe}
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_LATEX_NEW, \@_,
|
||||
{name => 'oManifest'},
|
||||
{name => 'strXmlPath'},
|
||||
{name => 'strLatexPath'},
|
||||
{name => 'strPreambleFile'},
|
||||
{name => 'bExe'}
|
||||
);
|
||||
|
||||
# Remove the current html path if it exists
|
||||
if (-e $self->{strLatexPath})
|
||||
{
|
||||
executeTest("rm -rf $self->{strLatexPath}/*");
|
||||
}
|
||||
# Else create the html path
|
||||
else
|
||||
{
|
||||
mkdir($self->{strLatexPath})
|
||||
or confess &log(ERROR, "unable to create path $self->{strLatexPath}");
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# process
|
||||
#
|
||||
# Generate the site html
|
||||
####################################################################################################################################
|
||||
sub process
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my $strOperation = logDebugParam(OP_DOC_LATEX_PROCESS);
|
||||
|
||||
my $oRender = $self->{oManifest}->renderGet(RENDER_TYPE_PDF);
|
||||
|
||||
# Copy the logo
|
||||
copy('/backrest/doc/resource/latex/cds-logo.eps', "$self->{strLatexPath}/logo.eps")
|
||||
or confess &log(ERROR, "unable to copy logo");
|
||||
|
||||
my $strLatex = $self->{oManifest}->variableReplace(fileStringRead($self->{strPreambleFile}), 'latex') . "\n";
|
||||
|
||||
foreach my $strPageId ($self->{oManifest}->renderOutList(RENDER_TYPE_PDF))
|
||||
{
|
||||
&log(INFO, " render out: ${strPageId}");
|
||||
|
||||
my $oDocLatexSection =
|
||||
new BackRestDoc::Latex::DocLatexSection($self->{oManifest}, $strPageId, $self->{bExe});
|
||||
|
||||
# Save the html page
|
||||
$strLatex .= $oDocLatexSection->process();
|
||||
}
|
||||
|
||||
$strLatex .= "\n% " . ('-' x 130) . "\n% End document\n% " . ('-' x 130) . "\n\\end{document}\n";
|
||||
|
||||
my $strLatexFileName = $self->{oManifest}->variableReplace("$self->{strLatexPath}/" . $$oRender{file} . '.tex');
|
||||
|
||||
fileStringWrite($strLatexFileName, $strLatex, false);
|
||||
|
||||
executeTest("pdflatex -output-directory=$self->{strLatexPath} -shell-escape $strLatexFileName",
|
||||
{bSuppressStdErr => true});
|
||||
executeTest("pdflatex -output-directory=$self->{strLatexPath} -shell-escape $strLatexFileName",
|
||||
{bSuppressStdErr => true});
|
||||
|
||||
# Return from function and log return values if any
|
||||
logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
1;
|
417
doc/lib/BackRestDoc/Latex/DocLatexSection.pm
Normal file
417
doc/lib/BackRestDoc/Latex/DocLatexSection.pm
Normal file
@ -0,0 +1,417 @@
|
||||
####################################################################################################################################
|
||||
# DOC LATEX SECTION MODULE
|
||||
####################################################################################################################################
|
||||
package BackRestDoc::Latex::DocLatexSection;
|
||||
use parent 'BackRestDoc::Common::DocExecute';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Data::Dumper;
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use File::Copy;
|
||||
use Storable qw(dclone);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Ini;
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
use BackRest::Config::ConfigHelp;
|
||||
use BackRest::FileCommon;
|
||||
|
||||
use BackRestDoc::Common::DocManifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
use constant OP_DOC_LATEX_SECTION => 'DocLatexSection';
|
||||
|
||||
use constant OP_DOC_LATEX_SECTION_CONFIG_PROCESS => OP_DOC_LATEX_SECTION . '->configProcess';
|
||||
use constant OP_DOC_LATEX_SECTION_NEW => OP_DOC_LATEX_SECTION . '->new';
|
||||
use constant OP_DOC_LATEX_SECTION_PROCESS => OP_DOC_LATEX_SECTION . '->process';
|
||||
use constant OP_DOC_LATEX_SECTION_SECTION_PROCESS => OP_DOC_LATEX_SECTION . '->sectionProcess';
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oManifest,
|
||||
$strRenderOutKey,
|
||||
$bExe
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_LATEX_SECTION_NEW, \@_,
|
||||
{name => 'oManifest'},
|
||||
{name => 'strRenderOutKey'},
|
||||
{name => 'bExe'}
|
||||
);
|
||||
|
||||
# Create the class hash
|
||||
my $self = $class->SUPER::new('latex', $oManifest, $strRenderOutKey, $bExe);
|
||||
bless $self, $class;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# process
|
||||
#
|
||||
# Generate the site html
|
||||
####################################################################################################################################
|
||||
sub process
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my $strOperation = logDebugParam(OP_DOC_LATEX_SECTION_PROCESS);
|
||||
|
||||
# Working variables
|
||||
my $oPage = $self->{oDoc};
|
||||
my $strLatex;
|
||||
|
||||
# Initialize page
|
||||
my $strTitle = "{[project]}" .
|
||||
(defined($oPage->paramGet('title', false)) ? ' ' . $oPage->paramGet('title') : '');
|
||||
my $strSubTitle = $oPage->paramGet('subtitle', false);
|
||||
|
||||
# Render sections
|
||||
foreach my $oSection ($oPage->nodeList('section'))
|
||||
{
|
||||
$strLatex .= (defined($strLatex) ? "\n" : '') . $self->sectionProcess($oSection, undef, 1);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strHtml', value => $strLatex, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# sectionProcess
|
||||
####################################################################################################################################
|
||||
sub sectionProcess
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$strSection,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_LATEX_SECTION_SECTION_PROCESS, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'strSection', required => false},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
&log($iDepth == 1 ? INFO : DEBUG, (' ' x ($iDepth + 1)) . 'process section: ' . $oSection->paramGet('id'));
|
||||
|
||||
# Create the section
|
||||
my $strSectionTitle = $self->processText($oSection->nodeGet('title')->textGet());
|
||||
$strSection .= (defined($strSection) ? ', ' : '') . "'${strSectionTitle}' " . ('Sub' x ($iDepth - 1)) . "Section";
|
||||
|
||||
my $strLatex =
|
||||
"% ${strSection}\n% " . ('-' x 130) . "\n\\";
|
||||
|
||||
if ($iDepth <= 3)
|
||||
{
|
||||
$strLatex .= ($iDepth > 1 ? ('sub' x ($iDepth - 1)) : '') . "section";
|
||||
}
|
||||
elsif ($iDepth == 4)
|
||||
{
|
||||
$strLatex .= 'paragraph';
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ASSERT, "section depth of ${iDepth} exceeds maximum");
|
||||
}
|
||||
|
||||
$strLatex .= "\{${strSectionTitle}\}\n";
|
||||
|
||||
foreach my $oChild ($oSection->nodeList())
|
||||
{
|
||||
&log(DEBUG, (' ' x ($iDepth + 2)) . 'process child ' . $oChild->nameGet());
|
||||
|
||||
# Execute a command
|
||||
if ($oChild->nameGet() eq 'execute-list')
|
||||
{
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oChild->paramGet('host'));
|
||||
|
||||
$strLatex .=
|
||||
"\n\\begin\{lstlisting\}[title=\{\\textnormal{\\textbf\{${strHostName}}} --- " .
|
||||
$self->processText($oChild->nodeGet('title')->textGet()) . "}]\n";
|
||||
|
||||
foreach my $oExecute ($oChild->nodeList('execute'))
|
||||
{
|
||||
my $bExeShow = !$oExecute->paramTest('show', 'n');
|
||||
my ($strCommand, $strOutput) = $self->execute($oSection,
|
||||
$self->{oManifest}->variableReplace($oChild->paramGet('host')),
|
||||
$oExecute, $iDepth + 3);
|
||||
|
||||
if ($bExeShow)
|
||||
{
|
||||
$strLatex .= "${strCommand}\n";
|
||||
|
||||
if (defined($strOutput))
|
||||
{
|
||||
$strLatex .= "\nOutput:\n\n${strOutput}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$strLatex .=
|
||||
"\\end{lstlisting}\n";
|
||||
}
|
||||
# Add code block
|
||||
elsif ($oChild->nameGet() eq 'code-block')
|
||||
{
|
||||
my $strTitle = $oChild->paramGet("title", false);
|
||||
|
||||
if (defined($strTitle) && $strTitle eq '')
|
||||
{
|
||||
undef($strTitle)
|
||||
}
|
||||
|
||||
# Begin the code listing
|
||||
if (!defined($strTitle))
|
||||
{
|
||||
$strLatex .=
|
||||
"\\vspace{.75em}\n";
|
||||
}
|
||||
|
||||
$strLatex .=
|
||||
"\\begin\{lstlisting\}";
|
||||
|
||||
# Add the title if one is provided
|
||||
if (defined($strTitle))
|
||||
{
|
||||
$strLatex .= "[title=\{${strTitle}:\}]";
|
||||
}
|
||||
|
||||
# End the code listing
|
||||
$strLatex .=
|
||||
"\n" .
|
||||
trim($oChild->valueGet()) . "\n" .
|
||||
"\\end{lstlisting}\n";
|
||||
}
|
||||
# Add table
|
||||
elsif ($oChild->nameGet() eq 'table')
|
||||
{
|
||||
my $oHeader = $oChild->nodeGet('table-header');
|
||||
my @oyColumn = $oHeader->nodeList('table-column');
|
||||
|
||||
my $strWidth = '{' . ($oHeader->paramTest('width') ? $oHeader->paramGet('width') : '\textwidth') . '}';
|
||||
|
||||
# Build the table header
|
||||
$strLatex .= "\\vspace{1em}\\newline\n";
|
||||
|
||||
$strLatex .= "\\begin{tabularx}${strWidth}{ | ";
|
||||
|
||||
foreach my $oColumn (@oyColumn)
|
||||
{
|
||||
my $strAlignCode;
|
||||
my $strAlign = $oColumn->paramGet("align", false);
|
||||
|
||||
if ($oColumn->paramTest('fill', 'y'))
|
||||
{
|
||||
if (!defined($strAlign) || $strAlign eq 'left')
|
||||
{
|
||||
$strAlignCode = 'X';
|
||||
}
|
||||
elsif ($strAlign eq 'right')
|
||||
{
|
||||
$strAlignCode = 'R';
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ERROR, "align '${strAlign}' not valid when fill=y");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!defined($strAlign) || $strAlign eq 'left')
|
||||
{
|
||||
$strAlignCode = 'l';
|
||||
}
|
||||
elsif ($strAlign eq 'center')
|
||||
{
|
||||
$strAlignCode = 'c';
|
||||
}
|
||||
elsif ($strAlign eq 'right')
|
||||
{
|
||||
$strAlignCode = 'r';
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ERROR, "align '${strAlign}' not valid");
|
||||
}
|
||||
}
|
||||
|
||||
# $strLatex .= 'p{' . $oColumn->paramGet("width") . '} | ';
|
||||
$strLatex .= $strAlignCode . ' | ';
|
||||
}
|
||||
|
||||
$strLatex .= "}\n";
|
||||
|
||||
if ($oChild->nodeGet("title", false))
|
||||
{
|
||||
$strLatex .= "\\caption{" . $self->processText($oChild->nodeGet("title")->textGet()) . ":}\\\\\n";
|
||||
}
|
||||
|
||||
$strLatex .= "\\hline";
|
||||
$strLatex .= "\\rowcolor{ltgray}\n";
|
||||
|
||||
my $strLine;
|
||||
|
||||
foreach my $oColumn (@oyColumn)
|
||||
{
|
||||
$strLine .= (defined($strLine) ? ' & ' : '') . '\textbf{' . $self->processText($oColumn->textGet()) . '}';
|
||||
}
|
||||
|
||||
$strLatex .= "${strLine}\\\\";
|
||||
|
||||
# Build the rows
|
||||
foreach my $oRow ($oChild->nodeGet('table-data')->nodeList('table-row'))
|
||||
{
|
||||
$strLatex .= "\\hline\n";
|
||||
undef($strLine);
|
||||
|
||||
foreach my $oRowCell ($oRow->nodeList('table-cell'))
|
||||
{
|
||||
$strLine .= (defined($strLine) ? ' & ' : '') . $self->processText($oRowCell->textGet());
|
||||
}
|
||||
|
||||
$strLatex .= "${strLine}\\\\";
|
||||
}
|
||||
|
||||
$strLatex .= "\\hline\n\\end{tabularx}\n";
|
||||
}
|
||||
# Add descriptive text
|
||||
elsif ($oChild->nameGet() eq 'p')
|
||||
{
|
||||
$strLatex .= "\n" . $self->processText($oChild->textGet()) . "\n";
|
||||
}
|
||||
# Add option descriptive text
|
||||
elsif ($oChild->nameGet() eq 'option-description')
|
||||
{
|
||||
my $strOption = $oChild->paramGet("key");
|
||||
my $oDescription = ${$self->{oReference}->{oConfigHash}}{&CONFIG_HELP_OPTION}{$strOption}{&CONFIG_HELP_DESCRIPTION};
|
||||
|
||||
if (!defined($oDescription))
|
||||
{
|
||||
confess &log(ERROR, "unable to find ${strOption} option in sections - try adding command?");
|
||||
}
|
||||
|
||||
$strLatex .= "\n" . $self->processText($oDescription) . "\n";
|
||||
}
|
||||
# Add/remove config options
|
||||
elsif ($oChild->nameGet() eq 'backrest-config' || $oChild->nameGet() eq 'postgres-config')
|
||||
{
|
||||
$strLatex .= $self->configProcess($oSection, $oChild, $iDepth + 3);
|
||||
}
|
||||
# Add a subsection
|
||||
elsif ($oChild->nameGet() eq 'section')
|
||||
{
|
||||
$strLatex .= "\n" . $self->sectionProcess($oChild, $strSection, $iDepth + 1);
|
||||
}
|
||||
# Check if the child can be processed by a parent
|
||||
else
|
||||
{
|
||||
$self->sectionChildProcess($oSection, $oChild, $iDepth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strSection', value => $strLatex, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# configProcess
|
||||
####################################################################################################################################
|
||||
sub configProcess
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oSection,
|
||||
$oConfig,
|
||||
$iDepth
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_DOC_LATEX_SECTION_CONFIG_PROCESS, \@_,
|
||||
{name => 'oSection'},
|
||||
{name => 'oConfig'},
|
||||
{name => 'iDepth'}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strLatex = '';
|
||||
my $strFile;
|
||||
my $strConfig;
|
||||
my $bShow = true;
|
||||
|
||||
# Generate the config
|
||||
if ($oConfig->nameGet() eq 'backrest-config')
|
||||
{
|
||||
($strFile, $strConfig, $bShow) = $self->backrestConfig($oSection, $oConfig, $iDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
($strFile, $strConfig, $bShow) = $self->postgresConfig($oSection, $oConfig, $iDepth);
|
||||
}
|
||||
|
||||
if ($bShow)
|
||||
{
|
||||
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
||||
|
||||
# Replace _ in filename
|
||||
$strFile = $self->variableReplace($strFile);
|
||||
|
||||
# Render the config
|
||||
$strLatex =
|
||||
"\n\\begin\{lstlisting\}[title=\{\\textnormal{\\textbf\{${strHostName}}}:\\textnormal{\\texttt\{${strFile}}} --- " .
|
||||
$self->processText($oConfig->nodeGet('title')->textGet()) . "}]\n" .
|
||||
${strConfig} .
|
||||
"\\end{lstlisting}\n";
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strConfig', value => $strLatex, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
46
doc/manifest.xml
Normal file
46
doc/manifest.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE doc SYSTEM "manifest.dtd">
|
||||
<doc>
|
||||
<!-- System-wide variables -->
|
||||
<variable-list>
|
||||
<variable key="project">pgBackRest</variable>
|
||||
<variable key="version" eval="y">use BackRest::Version; $VERSION</variable>
|
||||
<variable key="project-exe">pg_backrest</variable>
|
||||
<variable key="project-url-root">/</variable>
|
||||
<variable key="postgres">PostgreSQL</variable>
|
||||
<variable key="dash">-</variable>
|
||||
|
||||
<!-- Logo locations -->
|
||||
<variable key="logo">/backrest/doc/output/latex/logo</variable>
|
||||
|
||||
<!-- HTML variables -->
|
||||
<variable key="html-footer" eval='y'>
|
||||
use POSIX qw(strftime); 'Copyright &copy; 2015' . (strftime('%Y', localtime) ne '2015' ? '-' . strftime('%Y', localtime) : '') .
|
||||
', The PostgreSQL Global Development Group, <a href="{[github-url-license]}">MIT License</a>. Updated ' .
|
||||
strftime('%B ', localtime) . trim(strftime('%e,', localtime)) . strftime(' %Y.', localtime)</variable>
|
||||
|
||||
<!-- PDF variables -->
|
||||
<variable key="pdf-title">{[project]} User Guide</variable>
|
||||
<variable key="pdf-subtitle">Open Source PostgreSQL Backup and Restore Utility</variable>
|
||||
<variable key="pdf-file">CrunchyBackRest-UserGuide-{[version]}</variable>
|
||||
</variable-list>
|
||||
|
||||
<source-list>
|
||||
<source key="index"/>
|
||||
<source key="user-guide"/>
|
||||
<source key="reference" type="custom"/>
|
||||
</source-list>
|
||||
|
||||
<render-list>
|
||||
<render type="html">
|
||||
<render-source key="index" menu="Home"/>
|
||||
<render-source key="user-guide" menu="User Guide"/>
|
||||
<render-source key="configuration" source="reference" menu="Configuration"/>
|
||||
<render-source key="command" source="reference" menu="Commands"/>
|
||||
</render>
|
||||
|
||||
<render type="pdf" file="{[pdf-file]}">
|
||||
<render-source key="user-guide"/>
|
||||
</render>
|
||||
</render-list>
|
||||
</doc>
|
@ -17,6 +17,7 @@ body
|
||||
margin: 0px auto;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
@media (min-width: 1000px)
|
||||
@ -43,7 +44,6 @@ Header
|
||||
{
|
||||
width:100%;
|
||||
text-align:center;
|
||||
/*float:left;*/
|
||||
}
|
||||
|
||||
.page-header-title
|
||||
@ -63,24 +63,19 @@ Header
|
||||
/*******************************************************************************
|
||||
Menu
|
||||
*******************************************************************************/
|
||||
.page-menu
|
||||
{
|
||||
/*margin-top: .25em;*/
|
||||
/*font-size: 14pt;*/
|
||||
}
|
||||
/*.page-menu*/
|
||||
|
||||
.menu-body
|
||||
{
|
||||
text-align: center;
|
||||
/*font-weight: 600;*/
|
||||
/*border-bottom: 2px #dddddd solid;*/
|
||||
}
|
||||
|
||||
.menu
|
||||
{
|
||||
white-space: nowrap;
|
||||
display: inline;
|
||||
margin-left: 6px;
|
||||
margin-left: .5em;
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
.menu:first-of-type
|
||||
@ -91,20 +86,14 @@ Menu
|
||||
.menu:before
|
||||
{
|
||||
content: "[";
|
||||
/*margin-right: .5em;*/
|
||||
}
|
||||
|
||||
.menu:after
|
||||
{
|
||||
content: "]";
|
||||
/*margin-left: .5em;*/
|
||||
}
|
||||
|
||||
.menu-link
|
||||
{
|
||||
/*margin-left: 2px;
|
||||
margin-right: 2px;*/
|
||||
}
|
||||
/*.menu-link*/
|
||||
|
||||
a.menu-link:link, a.menu-link:visited, a.menu-link:active
|
||||
{
|
||||
@ -157,7 +146,7 @@ Section
|
||||
*******************************************************************************/
|
||||
.section1
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-top: 2.5em;
|
||||
}
|
||||
|
||||
.section1:first-of-type
|
||||
@ -178,7 +167,9 @@ Section
|
||||
|
||||
.section1-title, .page-toc-title
|
||||
{
|
||||
background-color: #dddddd;
|
||||
border-radius: 3px;
|
||||
background-color: #396a93;
|
||||
color: #f8f8f8;
|
||||
font-size: 22pt;
|
||||
padding-left: .5em;
|
||||
margin-bottom: .5em;
|
||||
@ -191,7 +182,8 @@ Section
|
||||
|
||||
.section2-title
|
||||
{
|
||||
border-bottom: 2px #cccccc solid;
|
||||
border-bottom: 2px #396a93 solid;
|
||||
color: #396a93;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
@ -199,7 +191,6 @@ Section
|
||||
{
|
||||
margin-left: 1em;
|
||||
margin-top: 1em;
|
||||
/*border-top: 1px #cccccc solid;*/
|
||||
}
|
||||
|
||||
.section3:first-of-type
|
||||
@ -211,8 +202,8 @@ Section
|
||||
{
|
||||
display: inline;
|
||||
font-size: 14pt;
|
||||
/*text-decoration: underline;*/
|
||||
border-bottom: 1px #bbbbbb solid;
|
||||
color: #396a93;
|
||||
border-bottom: 1px #396a93 solid;
|
||||
}
|
||||
|
||||
.section-intro
|
||||
@ -220,9 +211,7 @@ Section
|
||||
margin-top: .75em;
|
||||
}
|
||||
|
||||
.section-body
|
||||
{
|
||||
}
|
||||
/*.section-body*/
|
||||
|
||||
/*******************************************************************************
|
||||
Config, Execute, and Code Block Elements
|
||||
@ -244,7 +233,7 @@ Config, Execute, and Code Block Elements
|
||||
/*white-space: nowrap;*/
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-top: 1em;
|
||||
margin-top: .8em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
@ -259,15 +248,16 @@ Config, Execute, and Code Block Elements
|
||||
.config-body,
|
||||
.code-block
|
||||
{
|
||||
border-radius: 3px;
|
||||
background-color: #444444;
|
||||
/*overflow-x:auto;*/
|
||||
font-family: monospace;
|
||||
unicode-bidi: embed;
|
||||
color: white;
|
||||
color: #f8f8f8;
|
||||
/*color: white;*/
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.execute-body-cmd-first, .execute-body-cmd,
|
||||
.execute-body-cmd,
|
||||
.execute-body-output, .execute-body-output-highlight,
|
||||
.config-body-title,
|
||||
.code-block
|
||||
@ -276,16 +266,31 @@ Config, Execute, and Code Block Elements
|
||||
padding-right: .5em;
|
||||
}
|
||||
|
||||
.execute-body-cmd-first, .execute-body-output,
|
||||
/* Would rather not use pre at all, but Firefox won't copy code samples correctly without it */
|
||||
pre
|
||||
{
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.execute-body-cmd:before
|
||||
{
|
||||
content: "$ ";
|
||||
}
|
||||
|
||||
.execute-body-cmd:first-of-type, .execute-body-output,
|
||||
.config-body-title, .config-body-output,
|
||||
.code-block
|
||||
.code-block,
|
||||
.execute-body-output-highlight, .execute-body-output-highlight-error
|
||||
{
|
||||
padding-top: .25em;
|
||||
}
|
||||
|
||||
.execute-body-cmd-first, .execute-body-cmd, .execute-body-output,
|
||||
.execute-body-cmd, .execute-body-output,
|
||||
.config-body-title, .config-body-output,
|
||||
.code-block
|
||||
.code-block,
|
||||
.execute-body-output-highlight, .execute-body-output-highlight-error
|
||||
{
|
||||
padding-bottom: .25em;
|
||||
}
|
||||
@ -294,32 +299,31 @@ Config, Execute, and Code Block Elements
|
||||
.config-body-output,
|
||||
.code-block
|
||||
{
|
||||
border-radius: 3px;
|
||||
background-color: #606060;
|
||||
}
|
||||
|
||||
.execute-body-output-highlight
|
||||
{
|
||||
background-color: green;
|
||||
border-radius: 3px;
|
||||
background-color: #1e7b1e;
|
||||
}
|
||||
|
||||
.execute-body-output-highlight-error
|
||||
{
|
||||
background-color: firebrick;
|
||||
border-radius: 3px;
|
||||
background-color: #a32929;
|
||||
}
|
||||
|
||||
.execute-body-output, .execute-body-output-highlight, .execute-body-output-highlight-error,
|
||||
.config-body-output
|
||||
{
|
||||
padding-left: 2em;
|
||||
padding-left: 1.75em;
|
||||
}
|
||||
|
||||
.code-block
|
||||
{
|
||||
}
|
||||
/*.code-block*/
|
||||
|
||||
.section-body-execute-output
|
||||
{
|
||||
}
|
||||
/*.section-body-execute-output*/
|
||||
|
||||
/*******************************************************************************
|
||||
Keywords
|
||||
@ -329,14 +333,16 @@ Keywords
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.host
|
||||
{
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.path, .br-option, .br-setting, .pg-option, .pg-setting, .id, .user, .file, .path
|
||||
{
|
||||
/*font-weight: 600;*/
|
||||
/*background-color: #e8e8e8;*/
|
||||
unicode-bidi: embed;
|
||||
font-family: monospace;
|
||||
white-space: nowrap;
|
||||
/*font-size: 11pt;*/
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
6131
doc/resource/latex/cds-logo.eps
Normal file
6131
doc/resource/latex/cds-logo.eps
Normal file
File diff suppressed because one or more lines are too long
135
doc/resource/latex/preamble.tex
Normal file
135
doc/resource/latex/preamble.tex
Normal file
@ -0,0 +1,135 @@
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
% pgBackRest User Guide
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\documentclass[letterpaper,12pt]{article}
|
||||
|
||||
% Add hyperlinks to TOC
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{hyperref}
|
||||
|
||||
% Allow EPS files
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{graphicx}
|
||||
\usepackage{epstopdf}
|
||||
|
||||
% Use the caption package to enable captions that are not numbered (caption*)
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage[font=small,textfont=it,justification=justified,singlelinecheck=false]{caption}
|
||||
|
||||
% Create a light gray color to use for source code listings
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage[table]{xcolor}
|
||||
\definecolor{ltgray}{HTML}{E8E8E8}
|
||||
|
||||
% Use listings package instead of verbatim for displaying code
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{courier}
|
||||
|
||||
\usepackage{textcomp}
|
||||
\usepackage{listings}
|
||||
\lstset
|
||||
{
|
||||
basicstyle=\small\ttfamily,
|
||||
columns=flexible,
|
||||
breaklines=true,
|
||||
frame=tb,
|
||||
backgroundcolor=\color{ltgray},
|
||||
upquote=true
|
||||
}
|
||||
|
||||
% Use tabularx for tables
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{tabularx}
|
||||
\newcolumntype{R}{>{\raggedleft\arraybackslash}X}%
|
||||
\renewcommand{\arraystretch}{1.3}
|
||||
|
||||
% \usepackage{ltablex}
|
||||
|
||||
% Allow four section levels (The fourth is implemented with paragraph)
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{titlesec}
|
||||
\setcounter{secnumdepth}{4}
|
||||
|
||||
\titleformat{\paragraph}
|
||||
{\normalfont\normalsize\bfseries}{\theparagraph}{1em}{}
|
||||
\titlespacing*{\paragraph}{0pt}{3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex}
|
||||
|
||||
% Define source code highlighting
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\newcommand{\Hilight}{\makebox[0pt][l]{\color{cyan}\rule[-4pt]{0.65\linewidth}{14pt}}}
|
||||
|
||||
% Set the font to Helvetica
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{helvet}
|
||||
\renewcommand{\familydefault}{\sfdefault}
|
||||
|
||||
% Set margins
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage[top=.9in, bottom=1in, left=.5in, right=.5in]{geometry}
|
||||
|
||||
% Sections start a new page
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\let\stdsection\section
|
||||
\renewcommand\section{\newpage\stdsection}
|
||||
|
||||
% Format paragraphs with no indent and a blank line between paragraphs
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\setlength\parindent{0pt}
|
||||
\usepackage{parskip}
|
||||
|
||||
% Add page headers and footers
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\usepackage{fancyhdr}
|
||||
|
||||
\fancyhead[LE,RO]{\slshape \rightmark}
|
||||
\fancyhead[LO,RE]{\slshape \leftmark}
|
||||
|
||||
\fancypagestyle{plain}
|
||||
{
|
||||
\fancyhead{}
|
||||
\lhead[]{TABLE OF CONTENTS}
|
||||
}
|
||||
|
||||
\lfoot[]{{[pdf-title]}\\
|
||||
Version {[version]}}
|
||||
\cfoot[]{\ \\-\ \thepage\ -}
|
||||
\rfoot[]{Crunchy Data Solutions, Inc.\\\today}
|
||||
\pagestyle{fancy}
|
||||
|
||||
\renewcommand{\headrulewidth}{0.4pt}
|
||||
\renewcommand{\footrulewidth}{0.4pt}
|
||||
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
% Begin document
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\begin{document}
|
||||
|
||||
% Create the title page
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\makeatletter
|
||||
\begin{titlepage}
|
||||
\begin{center}
|
||||
{\large \ }\\[18ex]
|
||||
{\huge \bfseries {[pdf-title]}}\\[1ex]
|
||||
{\large \bfseries Version {[version]}}\\[4ex]
|
||||
{\large {[pdf-subtitle]}}\\[12ex]
|
||||
\includegraphics[width=6in]{{[logo]}}\\[12ex]
|
||||
{\large Crunchy Data Solutions, Inc.}\\[1ex]
|
||||
{\large \today}
|
||||
\end{center}
|
||||
\end{titlepage}
|
||||
\makeatother
|
||||
\thispagestyle{empty}
|
||||
\newpage
|
||||
|
||||
% Generate TOC
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
\setcounter{tocdepth}{3}
|
||||
\topskip0in
|
||||
\thispagestyle{plain}
|
||||
\renewcommand\contentsname{Table of Contents}
|
||||
\tableofcontents
|
||||
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
||||
% Content
|
||||
% ----------------------------------------------------------------------------------------------------------------------------------
|
@ -8,6 +8,9 @@
|
||||
<changelog>
|
||||
<changelog-release date="XXXX-XX-XX" version="0.90" title="UNDER DEVELOPMENT">
|
||||
<release-feature-bullet-list>
|
||||
<release-feature>
|
||||
<text>Added documentation in the user guide for delta restores, expiration, dedicated backup hosts, starting and stopping <backrest/>, and replication.</text>
|
||||
</release-feature>
|
||||
<release-feature>
|
||||
<text>Fixed an issue where the <cmd>start</cmd>/<cmd>stop</cmd> commands required the <setting>--config</setting> option.</text>
|
||||
</release-feature>
|
||||
@ -143,7 +146,7 @@
|
||||
<text>Added vagrant test configurations for Ubuntu 14.04 and CentOS 7.</text>
|
||||
</release-feature>
|
||||
<release-feature>
|
||||
<text>Split most of <file>README.md</file> out into <file>USERGUIDE.md</file> and <file>CHANGELOG.md</file> because it was becoming unwieldy. Changed most references to "database" in the user guide to "database cluster" for clarity.</text>
|
||||
<text>Split most of <file>README.md</file> out into <file>USERGUIDE.md</file> and <file>CHANGELOG.md</file> because it was becoming unwieldy. Changed most references to <quote>database</quote> in the user guide to <quote>database cluster</quote> for clarity.</text>
|
||||
</release-feature>
|
||||
</release-feature-bullet-list>
|
||||
</changelog-release>
|
||||
|
@ -50,45 +50,65 @@
|
||||
<!ATTLIST config-key name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT execute-list (title, execute+)>
|
||||
<!ELEMENT execute (exe-cmd, exe-user?, exe-var?, exe-retry?, exe-output?, exe-no-show?, exe-highlight?, exe-skip?,
|
||||
<!ATTLIST execute-list host CDATA #REQUIRED>
|
||||
<!ATTLIST execute-list keyword CDATA "">
|
||||
<!ELEMENT execute (exe-cmd, exe-user?, exe-var?, exe-retry?, exe-output?, (exe-highlight-type?, exe-highlight)?,
|
||||
exe-err-expect?, exe-err-suppress?, exe-err-suppress-stderr?)>
|
||||
<!ATTLIST execute keyword CDATA "">
|
||||
<!ATTLIST execute user CDATA "">
|
||||
<!ATTLIST execute filter CDATA "">
|
||||
<!ATTLIST execute filter-context CDATA "">
|
||||
<!ATTLIST execute skip CDATA "">
|
||||
<!ATTLIST execute show CDATA "">
|
||||
<!ATTLIST execute output CDATA "">
|
||||
<!ATTLIST execute err-suppress CDATA "">
|
||||
<!ATTLIST execute err-expect CDATA "">
|
||||
<!ATTLIST execute retry CDATA "">
|
||||
<!ATTLIST execute variable-key CDATA "">
|
||||
<!ELEMENT exe-cmd (#PCDATA)>
|
||||
<!ELEMENT exe-user (#PCDATA)>
|
||||
<!ELEMENT exe-highlight (#PCDATA)>
|
||||
<!ELEMENT exe-var (#PCDATA)>
|
||||
<!ELEMENT exe-output EMPTY>
|
||||
<!ELEMENT exe-skip EMPTY>
|
||||
<!ELEMENT exe-no-show EMPTY>
|
||||
<!ELEMENT exe-retry EMPTY>
|
||||
<!ELEMENT exe-err-expect (#PCDATA)>
|
||||
<!ELEMENT exe-err-suppress EMPTY>
|
||||
<!ELEMENT exe-err-suppress-stderr EMPTY>
|
||||
<!ELEMENT exe-highlight-type (#PCDATA)>
|
||||
|
||||
<!ELEMENT cleanup (execute+)>
|
||||
|
||||
<!ELEMENT variable-list (variable+)>
|
||||
<!ELEMENT variable (variable-name, variable-value)>
|
||||
<!ELEMENT variable-name (#PCDATA)>
|
||||
<!ELEMENT variable-value (#PCDATA)>
|
||||
<!ELEMENT variable (#PCDATA)>
|
||||
<!ATTLIST variable key CDATA #REQUIRED>
|
||||
<!ATTLIST variable keyword CDATA "default">
|
||||
<!ATTLIST variable eval CDATA "n">
|
||||
|
||||
<!ELEMENT backrest-config (title, backrest-config-option+)>
|
||||
<!ATTLIST backrest-config host CDATA #REQUIRED>
|
||||
<!ATTLIST backrest-config owner CDATA "">
|
||||
<!ATTLIST backrest-config show CDATA "">
|
||||
<!ATTLIST backrest-config keyword CDATA "">
|
||||
<!ATTLIST backrest-config reset CDATA "">
|
||||
<!ATTLIST backrest-config file CDATA #REQUIRED>
|
||||
<!ELEMENT backrest-config-option (backrest-config-option-section?, backrest-config-option-key, backrest-config-option-value?)>
|
||||
<!ELEMENT backrest-config-option-section (#PCDATA)>
|
||||
<!ELEMENT backrest-config-option-key (#PCDATA)>
|
||||
<!ELEMENT backrest-config-option-value (#PCDATA)>
|
||||
<!ELEMENT backrest-config-option (#PCDATA)>
|
||||
<!ATTLIST backrest-config-option keyword CDATA "">
|
||||
<!ATTLIST backrest-config-option section CDATA #REQUIRED>
|
||||
<!ATTLIST backrest-config-option key CDATA #REQUIRED>
|
||||
<!ATTLIST backrest-config-option remove CDATA "n">
|
||||
|
||||
<!ELEMENT postgres-config (title, postgres-config-option+)>
|
||||
<!ATTLIST postgres-config host CDATA #REQUIRED>
|
||||
<!ATTLIST postgres-config file CDATA #REQUIRED>
|
||||
<!ATTLIST postgres-config keyword CDATA "">
|
||||
<!ATTLIST postgres-config show CDATA "">
|
||||
<!ELEMENT postgres-config-option (#PCDATA)>
|
||||
<!ATTLIST postgres-config-option keyword CDATA "">
|
||||
<!ATTLIST postgres-config-option key CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT option-description EMPTY>
|
||||
<!ATTLIST option-description key CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT section (title,((p|execute-list|backrest-config|postgres-config|option-description)+|(p*, section+)|p*))>
|
||||
<!ELEMENT section (title,
|
||||
((p|table|host-add|execute-list|backrest-config|postgres-config|option-description|code-block)+|
|
||||
(p*, section+)|p*))>
|
||||
<!ATTLIST section id CDATA #REQUIRED>
|
||||
<!ELEMENT title (#PCDATA|b|i|bi|ul|ol|id|code|code-block|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
<!ATTLIST section keyword CDATA "">
|
||||
<!ATTLIST section depend CDATA "">
|
||||
<!ELEMENT title (#PCDATA|b|i|bi|ul|ol|id|code|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
pg-option|pg-setting|link|user)*>
|
||||
|
||||
<!ELEMENT default (#PCDATA)>
|
||||
@ -115,26 +135,54 @@
|
||||
<!ELEMENT support (text)>
|
||||
<!ATTLIST support title CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT summary (#PCDATA|b|i|bi|ul|ol|id|code|code-block|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT p (#PCDATA|b|i|bi|ul|ol|id|code|code-block|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
<!-- Host elements -->
|
||||
<!ELEMENT host-add (execute*)>
|
||||
<!ATTLIST host-add name CDATA #REQUIRED>
|
||||
<!ATTLIST host-add user CDATA #REQUIRED>
|
||||
<!ATTLIST host-add image CDATA #REQUIRED>
|
||||
<!ATTLIST host-add os CDATA "">
|
||||
<!ATTLIST host-add mount CDATA "">
|
||||
|
||||
<!-- Table elements -->
|
||||
<!ELEMENT table (title?, table-header, table-data)>
|
||||
|
||||
<!ELEMENT table-header (table-column+)>
|
||||
<!ATTLIST table-header width CDATA "">
|
||||
<!ELEMENT table-column (#PCDATA|quote|b|i|id|code|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|
|
||||
br-setting|pg-option|pg-setting|link|user)*>
|
||||
<!ATTLIST table-column align CDATA "">
|
||||
<!ATTLIST table-column fill CDATA "">
|
||||
|
||||
<!ELEMENT table-data (table-row+)>
|
||||
<!ELEMENT table-row (table-cell+)>
|
||||
<!ELEMENT table-cell (#PCDATA|quote|b|i|ul|ol|id|code|code-block|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|
|
||||
br-setting|pg-option|pg-setting|link|user)*>
|
||||
|
||||
<!-- Formatted elements -->
|
||||
<!ELEMENT summary (#PCDATA|quote|b|i|ul|ol|id|code|code-block|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|
|
||||
br-setting|pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT p (#PCDATA|quote|b|i|ul|ol|id|code|code-block|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT text (#PCDATA|b|i|bi|ul|ol|id|code|code-block|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
pg-option|pg-setting|link|user)*>
|
||||
<!ATTLIST p keyword CDATA "">
|
||||
<!ELEMENT text (#PCDATA|quote|b|i|ul|ol|id|code|code-block|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|
|
||||
br-setting|pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT b (#PCDATA)>
|
||||
<!ELEMENT bi (#PCDATA)>
|
||||
<!ELEMENT ul (li+)>
|
||||
<!ELEMENT ol (li+)>
|
||||
<!ELEMENT li (#PCDATA|b|i|bi|ul|ol|id|code|code-block|file|path|cmd|param|setting|exe|backrest|postgres|br-option|br-setting|
|
||||
pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT li (#PCDATA|quote|b|i|ul|ol|id|code|code-block|host|file|path|cmd|param|setting|exe|backrest|postgres|br-option|
|
||||
br-setting|pg-option|pg-setting|link|user)*>
|
||||
<!ELEMENT id (#PCDATA)>
|
||||
<!ELEMENT code (#PCDATA)>
|
||||
<!ELEMENT code-block (#PCDATA|exe)*>
|
||||
<!ATTLIST code-block title CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT host (#PCDATA)>
|
||||
<!ELEMENT file (#PCDATA)>
|
||||
<!ELEMENT path (#PCDATA)>
|
||||
<!ELEMENT cmd (#PCDATA)>
|
||||
<!ELEMENT user (#PCDATA)>
|
||||
<!ELEMENT quote (#PCDATA)>
|
||||
<!ELEMENT param (#PCDATA)>
|
||||
<!ELEMENT setting (#PCDATA)>
|
||||
<!ELEMENT br-option (#PCDATA)>
|
||||
|
21
doc/xml/dtd/manifest.dtd
Normal file
21
doc/xml/dtd/manifest.dtd
Normal file
@ -0,0 +1,21 @@
|
||||
<!ELEMENT doc (variable-list, source-list, render-list)>
|
||||
|
||||
<!ELEMENT variable-list (variable+)>
|
||||
<!ELEMENT variable (#PCDATA)>
|
||||
<!ATTLIST variable key CDATA #REQUIRED>
|
||||
<!ATTLIST variable eval CDATA "n">
|
||||
<!ATTLIST variable keyword CDATA "default">
|
||||
|
||||
<!ELEMENT source-list (source+)>
|
||||
<!ELEMENT source EMPTY>
|
||||
<!ATTLIST source key CDATA #REQUIRED>
|
||||
<!ATTLIST source type CDATA "">
|
||||
|
||||
<!ELEMENT render-list (render+)>
|
||||
<!ELEMENT render (render-source+)>
|
||||
<!ATTLIST render type CDATA #REQUIRED>
|
||||
<!ATTLIST render file CDATA "">
|
||||
<!ELEMENT render-source EMPTY>
|
||||
<!ATTLIST render-source key CDATA #REQUIRED>
|
||||
<!ATTLIST render-source source CDATA "">
|
||||
<!ATTLIST render-source menu CDATA "">
|
@ -3,54 +3,21 @@
|
||||
<doc subtitle="Reliable {[postgres]} Backup & Restore" toc="n">
|
||||
<variable-list>
|
||||
<!-- Variables used by the rest of the script -->
|
||||
<variable>
|
||||
<variable-name>github-url-base</variable-name>
|
||||
<variable-value>https://github.com/pgmasters/backrest</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>github-url-master</variable-name>
|
||||
<variable-value>{[github-url-base]}/blob/master</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>github-url-issues</variable-name>
|
||||
<variable-value>{[github-url-base]}/issues</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>github-url-change-log</variable-name>
|
||||
<variable-value>{[github-url-master]}/CHANGELOG.md</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>github-url-license</variable-name>
|
||||
<variable-value>{[github-url-master]}/LICENSE</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>backrest-url-base</variable-name>
|
||||
<variable-value>http://www.pgbackrest.org</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>backrest-page-user-guide</variable-name>
|
||||
<variable-value>user-guide.html</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>backrest-page-configuration</variable-name>
|
||||
<variable-value>configuration.html</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>backrest-page-command</variable-name>
|
||||
<variable-value>command.html</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>crunchy-url-base</variable-name>
|
||||
<variable-value>http://www.crunchydatasolutions.com</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>crunchy-url-cbm</variable-name>
|
||||
<variable-value>{[crunchy-url-base]}/crunchy-backup-manager</variable-value>
|
||||
</variable>
|
||||
<variable>
|
||||
<variable-name>resonate-url-base</variable-name>
|
||||
<variable-value>http://www.resonate.com</variable-value>
|
||||
</variable>
|
||||
<variable key="github-url-base">https://github.com/pgmasters/backrest</variable>
|
||||
<variable key="github-url-master">{[github-url-base]}/blob/master</variable>
|
||||
<variable key="github-url-issues">{[github-url-base]}/issues</variable>
|
||||
<variable key="github-url-change-log">{[github-url-master]}/CHANGELOG.md</variable>
|
||||
<variable key="github-url-license">{[github-url-master]}/LICENSE</variable>
|
||||
|
||||
<variable key="backrest-url-base">http://www.pgbackrest.org</variable>
|
||||
<variable key="backrest-page-user-guide">user-guide.html</variable>
|
||||
<variable key="backrest-page-configuration">configuration.html</variable>
|
||||
<variable key="backrest-page-command">command.html</variable>
|
||||
|
||||
<variable key="crunchy-url-base">http://www.crunchydatasolutions.com</variable>
|
||||
<variable key="crunchy-url-cbm">{[crunchy-url-base]}/crunchy-backup-manager</variable>
|
||||
|
||||
<variable key="resonate-url-base">http://www.resonate.com</variable>
|
||||
</variable-list>
|
||||
|
||||
<section id="introduction">
|
||||
|
@ -1,162 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE doc SYSTEM "doc.dtd">
|
||||
<doc title="User Guide">
|
||||
<!-- <intro>
|
||||
<text></text>
|
||||
</intro> -->
|
||||
|
||||
<!-- <install title="Installation">
|
||||
<text><backrest/> is written entirely in Perl. Some additional modules will need to be installed depending on the OS.</text>
|
||||
|
||||
<install-system-list>
|
||||
<install-system title="Ubuntu 12.04/14.04 Setup">
|
||||
<text>* Install required Perl modules:
|
||||
<code-block>
|
||||
apt-get install libdbd-pg-perl
|
||||
</code-block></text>
|
||||
</install-system>
|
||||
|
||||
<install-system title="CentOS 6 Setup">
|
||||
<text>* Install Perl and required modules:
|
||||
<code-block>
|
||||
yum install perl perl-Time-HiRes perl-parent perl-JSON perl-Digest-SHA perl-DBD-Pg
|
||||
</code-block></text>
|
||||
</install-system>
|
||||
|
||||
<install-system title="CentOS 7 Setup">
|
||||
<text>* Install Perl and required modules:
|
||||
<code-block>
|
||||
yum install perl perl-Thread-Queue perl-JSON-PP perl-Digest-SHA perl-DBD-Pg
|
||||
</code-block></text>
|
||||
</install-system>
|
||||
|
||||
<install-system title="Software Installation">
|
||||
<text><backrest/> can be installed by downloading the most recent release:
|
||||
|
||||
https://github.com/pgmasters/backrest/releases
|
||||
|
||||
<backrest/> can be installed anywhere but it's best (though not required) to install it in the same location on all systems.</text>
|
||||
</install-system>
|
||||
|
||||
<install-system title="Regression Test Setup">
|
||||
<text>* Create the backrest user
|
||||
|
||||
The backrest user must be created on the same system and in the same group as the user you will use for testing (which can be any user you prefer). For example:
|
||||
<code-block>
|
||||
adduser -g <test-user-group> backrest
|
||||
</code-block>
|
||||
* Setup password-less SSH login between the test user and the backrest user
|
||||
|
||||
The test user should be able to `ssh backrest@127.0.0.1` and the backrest user should be able to `ssh <testuser>@127.0.0.1` without requiring any passwords. This article (http://archive.oreilly.com/pub/h/66) has details on how to accomplish this. Do the logons both ways at the command line before running regression tests.
|
||||
|
||||
* Give group read and execute permissions to <path>~/backrest/test</path>:
|
||||
|
||||
Usually this can be accomplished by running the following as the test user:
|
||||
<code-block>
|
||||
chmod 750 ~
|
||||
</code-block>
|
||||
* Running regression:
|
||||
|
||||
Running the full regression suite is generally not necessary. Run the following first:
|
||||
<code-block>
|
||||
./test.pl {[dash]}-module=backup {[dash]}-test=full {[dash]}-db-version=all {[dash]}-thread-max=<# threads>
|
||||
</code-block>
|
||||
This will run full backup/restore regression with a variety of options on all installed versions of <postgres/>. If you are only interested in one version then modify the <setting>db-version</setting> setting to X.X (e.g. 9.4). <setting>{[dash]}-thread-max</setting> can be omitted if you are running single-threaded.
|
||||
|
||||
If there are errors in this test then run full regression to help isolate problems:
|
||||
<code-block>
|
||||
./test.pl {[dash]}-db-version=all {[dash]}-thread-max=<# threads>
|
||||
</code-block>
|
||||
Report regression test failures at https://github.com/pgmasters/backrest/issues.</text>
|
||||
</install-system>
|
||||
</install-system-list>
|
||||
</install> -->
|
||||
|
||||
<!-- CONFIG -->
|
||||
<config title="Configuration Reference">
|
||||
<text><backrest/> can be used entirely with command-line parameters but a configuration file is more practical for installations that are complex or set a lot of options. The default location for the configuration file is <file>/etc/pg_backrest.conf</file>.</text>
|
||||
<!--
|
||||
<config-example-list title="Examples">
|
||||
<config-example title="Confguring Postgres for Archiving">
|
||||
<text>Modify the following settings in <file>postgresql.conf</file>:
|
||||
<code-block>
|
||||
wal_level = archive
|
||||
archive_mode = on
|
||||
archive_command = '/path/to/backrest/bin/<exe/> -stanza=db archive-push %p'
|
||||
</code-block>
|
||||
Replace the path with the actual location where <backrest/> was installed. The stanza parameter should be changed to the actual stanza name for your database cluster.</text>
|
||||
</config-example>
|
||||
|
||||
<config-example title="Minimal Configuration">
|
||||
<text>The absolute minimum required to run <backrest/> (if all defaults are accepted) is the database cluster path.
|
||||
|
||||
<file>/etc/pg_backrest.conf</file>:
|
||||
<code-block>
|
||||
[main]
|
||||
db-path=/data/db
|
||||
</code-block>
|
||||
The <setting>db-path</setting> option could also be provided on the command line, but it's best to use a configuration file as options tend to pile up quickly.</text>
|
||||
</config-example>
|
||||
|
||||
<config-example title="Simple Single Host Configuration">
|
||||
<text>This configuration is appropriate for a small installation where backups are being made locally or to a remote file system that is mounted locally. A number of additional options are set:
|
||||
<ul>
|
||||
<li><setting>db-port</setting> - Custom port for <postgres/>.</li>
|
||||
<li><setting>compress</setting> - Disable compression (handy if the file system is already compressed).</li>
|
||||
<li><setting>repo-path</setting> - Path to the <backrest/> repository where backups and WAL archive are stored.</li>
|
||||
<li><setting>log-level-file</setting> - Set the file log level to debug (Lots of extra info if something is not working as expected).</li>
|
||||
<li><setting>hardlink</setting> - Create hardlinks between backups (but never between full backups).</li>
|
||||
<li><setting>thread-max</setting> - Use 2 threads for backup/restore operations.</li>
|
||||
</ul>
|
||||
<file>/etc/pg_backrest.conf</file>:
|
||||
<code-block>
|
||||
[global:general]
|
||||
compress=n
|
||||
repo-path=/path/to/db/repo
|
||||
|
||||
[global:log]
|
||||
log-level-file=debug
|
||||
|
||||
[global:backup]
|
||||
hardlink=y
|
||||
thread-max=2
|
||||
|
||||
[main]
|
||||
db-path=/data/db
|
||||
db-port=5555
|
||||
</code-block></text>
|
||||
</config-example>
|
||||
|
||||
<config-example title="Simple Multiple Host Configuration">
|
||||
<text>This configuration is appropriate for a small installation where backups are being made remotely. Make sure that postgres@db-host has trusted ssh to backrest@backup-host and vice versa. This configuration assumes that you have <exe/> in the same path on both servers.
|
||||
|
||||
<file>/etc/pg_backrest.conf</file> on the db host:
|
||||
<code-block>
|
||||
[global:general]
|
||||
repo-path=/path/to/db/repo
|
||||
repo-remote-path=/path/to/backup/repo
|
||||
|
||||
[global:backup]
|
||||
backup-host=backup.mydomain.com
|
||||
backup-user=backrest
|
||||
|
||||
[global:archive]
|
||||
archive-async=y
|
||||
|
||||
[main]
|
||||
db-path=/data/db
|
||||
</code-block>
|
||||
<file>/etc/pg_backrest.conf</file> on the backup host:
|
||||
<code-block>
|
||||
[global:general]
|
||||
repo-path=/path/to/backup/repo
|
||||
|
||||
[main]
|
||||
db-host=db.mydomain.com
|
||||
db-path=/data/db
|
||||
db-user=postgres
|
||||
</code-block></text>
|
||||
</config-example>
|
||||
</config-example-list> -->
|
||||
|
||||
<config-section-list title="Settings">
|
||||
<!-- CONFIG - COMMAND SECTION -->
|
||||
@ -171,7 +18,7 @@
|
||||
<text>Required only if the path to <exe/> is different on the local and remote systems. If not defined, the remote exe path will be set the same as the local exe path.</text>
|
||||
|
||||
<default>same as local</default>
|
||||
<example>/usr/lib/backrest/bin/pg_backrest_remote.pl</example>
|
||||
<example>/usr/lib/backrest/bin/pg_backrest</example>
|
||||
</config-key>
|
||||
</config-key-list>
|
||||
</config-section>
|
||||
@ -583,6 +430,7 @@
|
||||
</config-section-list>
|
||||
</config>
|
||||
|
||||
<!-- COMMAND -->
|
||||
<operation title="Command Reference">
|
||||
<text>Commands are used to execute the various <backrest/> functions. Here the command options are listed exhaustively, that is, each option applicable to a command is listed with that command even if it applies to one or more other commands. This includes all the options that may also configured in <file>pg_backrest.conf</file>.</text>
|
||||
|
||||
@ -657,8 +505,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Full Backup">
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db --type=full backup
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db --type=full backup
|
||||
</code-block>
|
||||
Run a <id>full</id> backup on the <id>db</id> stanza. <br-option>--type</br-option> can also be set to <id>incr</id> or <id>diff</id> for incremental or differential backups. However, if no <id>full</id> backup exists then a <id>full</id> backup will be forced even if <id>incr</id> or <id>diff</id> is requested.</text>
|
||||
</command-example>
|
||||
@ -673,8 +521,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example>
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db archive-push %p
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db archive-push %p
|
||||
</code-block>
|
||||
Accepts a WAL segment from <postgres/> and archives it in the repository defined by <setting>repo-path</setting>. <id>%p</id> is how <postgres/> specifies the location of the WAL segment to be archived.</text>
|
||||
</command-example>
|
||||
@ -689,8 +537,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example>
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db archive-get %f %p
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db archive-get %f %p
|
||||
</code-block>
|
||||
Retrieves a WAL segment from the repository. This command is used in <file>recovery.conf</file> to restore a backup, perform PITR, or as an alternative to streaming for keeping a replica up to date. <id>%f</id> is how <postgres/> specifies the WAL segment it needs and <id>%p</id> is the location where it should be copied.</text>
|
||||
</command-example>
|
||||
@ -705,8 +553,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example>
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db expire
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db expire
|
||||
</code-block>
|
||||
Expire (rotate) any backups that exceed the defined retention. Expiration is run automatically after every successful backup, so there is no need to run this command separately unless you have reduced retention, usually to free up some space.</text>
|
||||
</command-example>
|
||||
@ -793,6 +641,7 @@
|
||||
<summary>Recover along a timeline.</summary>
|
||||
|
||||
<text>See <setting>recovery_target_timeline</setting> in the <postgres/> docs for more information.</text>
|
||||
|
||||
<example>3</example>
|
||||
</option>
|
||||
|
||||
@ -804,13 +653,16 @@
|
||||
|
||||
Note: The <setting>restore_command</setting> option will be automatically generated but can be overridden with this option. Be careful about specifying your own <setting>restore_command</setting> as <backrest/> is designed to handle this for you. Target Recovery options (recovery_target_name, recovery_target_time, etc.) are generated automatically by <backrest/> and should not be set with this option.
|
||||
|
||||
Recovery settings can also be set in the <setting>restore:recovery-option</setting> section of pg_backrest.conf. For example:
|
||||
<code-block>
|
||||
Recovery settings can also be set in the <setting>restore:recovery-option</setting> section of pg_backrest.conf.
|
||||
<!-- For example:
|
||||
|
||||
<code-block title="">
|
||||
[restore:recovery-option]
|
||||
primary_conn_info=db.mydomain.com
|
||||
standby_mode=on
|
||||
</code-block>
|
||||
</code-block> -->
|
||||
Since <backrest/> does not start <postgres/> after writing the <file>recovery.conf</file> file, it is always possible to edit/check <file>recovery.conf</file> before manually restarting.</text>
|
||||
|
||||
<example>primary_conninfo=db.mydomain.com</example>
|
||||
</option>
|
||||
|
||||
@ -821,14 +673,15 @@
|
||||
<text>Moves a tablespace to a new location during the restore. This is useful when tablespace locations are not the same on a replica, or an upgraded system has different mount points.
|
||||
|
||||
Since <postgres/> 9.2 tablespace locations are not stored in pg_tablespace so moving tablespaces can be done with impunity. However, moving a tablespace to the <setting>data_directory</setting> is not recommended and may cause problems. For more information on moving tablespaces http://www.databasesoup.com/2013/11/moving-tablespaces.html is a good resource.</text>
|
||||
|
||||
<example>ts_01=/db/ts_01</example>
|
||||
</option>
|
||||
</option-list>
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Restore Latest">
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db --type=name --target=release restore
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db --type=name --target=release restore
|
||||
</code-block>
|
||||
Restores the latest database cluster backup and then recovers to the <id>release</id> restore point.</text>
|
||||
</command-example>
|
||||
@ -860,16 +713,16 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Information for a single stanza">
|
||||
<text><code-block>
|
||||
<exe/> --stanza=db --output=json info
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=db --output=json info
|
||||
</code-block>
|
||||
|
||||
Get information about backups in the <id>db</id> stanza.</text>
|
||||
</command-example>
|
||||
|
||||
<command-example title="Information for all stanzas">
|
||||
<text><code-block>
|
||||
<exe/> --output=json info
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --output=json info
|
||||
</code-block>
|
||||
|
||||
Get information about backups for all stanzas in the repository.</text>
|
||||
@ -885,16 +738,16 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Help for the backup command">
|
||||
<text><code-block>
|
||||
<exe/> help backup
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} help backup
|
||||
</code-block>
|
||||
|
||||
Get help for the backup command.</text>
|
||||
</command-example>
|
||||
|
||||
<command-example title="Help for backup command, --force option">
|
||||
<text><code-block>
|
||||
<exe/> help backup force
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} help backup force
|
||||
</code-block>
|
||||
|
||||
Get help for the force option of the backup command.</text>
|
||||
@ -910,8 +763,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Start processes for stanza main">
|
||||
<text><code-block>
|
||||
<exe/> --stanza=main start
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} --stanza=main start
|
||||
</code-block>
|
||||
|
||||
Allows <backrest/> processes to run for the <id>main</id> stanza.</text>
|
||||
@ -940,8 +793,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Stop processes for all stanzas">
|
||||
<text><code-block>
|
||||
<exe/> stop
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} stop
|
||||
</code-block>
|
||||
|
||||
Stop new <backrest/> processes for all stanzas but allow any current process to complete.</text>
|
||||
@ -957,8 +810,8 @@
|
||||
|
||||
<command-example-list>
|
||||
<command-example title="Get version">
|
||||
<text><code-block>
|
||||
<exe/> version
|
||||
<text><code-block title="">
|
||||
{[backrest-exe]} version
|
||||
</code-block>
|
||||
|
||||
Get <backrest/> version.</text>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -872,12 +872,7 @@ my $oConfigHelpData =
|
||||
"this for you. Target Recovery options (recovery_target_name, recovery_target_time, etc.) are " .
|
||||
"generated automatically by pgBackRest and should not be set with this option.\n" .
|
||||
"\n" .
|
||||
"Recovery settings can also be set in the restore:recovery-option section of pg_backrest.conf. For " .
|
||||
"example:\n" .
|
||||
"\n" .
|
||||
"[restore:recovery-option]\n" .
|
||||
"primary_conn_info=db.mydomain.com\n" .
|
||||
"standby_mode=on\n" .
|
||||
"Recovery settings can also be set in the restore:recovery-option section of pg_backrest.conf.\n" .
|
||||
"\n" .
|
||||
"Since pgBackRest does not start PostgreSQL after writing the recovery.conf file, it is always possible " .
|
||||
"to edit/check recovery.conf before manually restarting."
|
||||
|
224
test/lib/BackRestTest/Common/HostTest.pm
Normal file
224
test/lib/BackRestTest/Common/HostTest.pm
Normal file
@ -0,0 +1,224 @@
|
||||
####################################################################################################################################
|
||||
# HostTest.pm - Encapsulate a docker host for testing
|
||||
####################################################################################################################################
|
||||
package BackRestTest::Common::HostTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Cwd qw(abs_path);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Common::Log;
|
||||
use BackRest::Common::String;
|
||||
|
||||
use BackRestTest::Common::ExecuteTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Operation constants
|
||||
####################################################################################################################################
|
||||
use constant OP_HOST_TEST => 'LogTest';
|
||||
|
||||
use constant OP_HOST_TEST_COPY_FROM => OP_HOST_TEST . "->copyFrom";
|
||||
use constant OP_HOST_TEST_COPY_TO => OP_HOST_TEST . "->copyTo";
|
||||
use constant OP_HOST_TEST_EXECUTE => OP_HOST_TEST . "->execute";
|
||||
use constant OP_HOST_TEST_EXECUTE_SIMPLE => OP_HOST_TEST . "->executeSimple";
|
||||
use constant OP_HOST_TEST_NEW => OP_HOST_TEST . "->new";
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
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,
|
||||
$self->{strName},
|
||||
$self->{strImage},
|
||||
$self->{strUser},
|
||||
$self->{strOS},
|
||||
$self->{strMount}
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_HOST_TEST_NEW, \@_,
|
||||
{name => 'strName', trace => true},
|
||||
{name => 'strImage', trace => true},
|
||||
{name => 'strUser', trace => true},
|
||||
{name => 'strOS', trace => true},
|
||||
{name => 'strMount', trace => true}
|
||||
);
|
||||
|
||||
executeTest("docker kill $self->{strName}", {bSuppressError => true});
|
||||
executeTest("docker rm $self->{strName}", {bSuppressError => true});
|
||||
|
||||
executeTest("rm -rf ~/data/$self->{strName}");
|
||||
executeTest("mkdir -p ~/data/$self->{strName}/etc");
|
||||
|
||||
executeTest("docker run -itd -h $self->{strName} --name=$self->{strName} " .
|
||||
(defined($self->{strMount}) ? "-v $self->{strMount} " : '') .
|
||||
"$self->{strImage}");
|
||||
|
||||
$self->{strIP} = trim(executeTest("docker inspect --format '\{\{ .NetworkSettings.IPAddress \}\}' $self->{strName}"));
|
||||
$self->{bActive} = true;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# execute
|
||||
####################################################################################################################################
|
||||
sub execute
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
$oParam,
|
||||
$strUser
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_HOST_TEST_EXECUTE, \@_,
|
||||
{name => 'strCommand'},
|
||||
{name => 'oParam', required=> false},
|
||||
{name => 'strUser', required => false}
|
||||
);
|
||||
|
||||
# Set the user
|
||||
if (!defined($strUser))
|
||||
{
|
||||
$strUser = $self->{strUser};
|
||||
}
|
||||
|
||||
my $oExec = new BackRestTest::Common::ExecuteTest(
|
||||
'docker exec ' . ($strUser eq 'root' ? "-u ${strUser} " : '') . "$self->{strName} ${strCommand}" , $oParam);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oExec', value => $oExec, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# executeSimple
|
||||
####################################################################################################################################
|
||||
sub executeSimple
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
$oParam,
|
||||
$strUser
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_HOST_TEST_EXECUTE_SIMPLE, \@_,
|
||||
{name => 'strCommand', trace => true},
|
||||
{name => 'oParam', required=> false, trace => true},
|
||||
{name => 'strUser', required => false, trace => true}
|
||||
);
|
||||
|
||||
my $oExec = $self->execute($strCommand, $oParam, $strUser);
|
||||
$oExec->begin();
|
||||
$oExec->end();
|
||||
|
||||
return $oExec->{strOutLog};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# copyTo
|
||||
####################################################################################################################################
|
||||
sub copyTo
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strSource,
|
||||
$strDestination,
|
||||
$strOwner,
|
||||
$strMode
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_HOST_TEST_COPY_TO, \@_,
|
||||
{name => 'strSource'},
|
||||
{name => 'strDestination'},
|
||||
{name => 'strOwner', required => false},
|
||||
{name => 'strMode', required => false}
|
||||
);
|
||||
|
||||
executeTest("docker cp ${strSource} $self->{strName}:${strDestination}");
|
||||
|
||||
if (defined($strOwner))
|
||||
{
|
||||
$self->executeSimple("chown ${strOwner} ${strDestination}", undef, 'root');
|
||||
}
|
||||
|
||||
if (defined($strMode))
|
||||
{
|
||||
$self->executeSimple("chmod ${strMode} ${strDestination}", undef, 'root');
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# copyFrom
|
||||
####################################################################################################################################
|
||||
sub copyFrom
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strSource,
|
||||
$strDestination
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
OP_HOST_TEST_COPY_FROM, \@_,
|
||||
{name => 'strSource'},
|
||||
{name => 'strDestination'}
|
||||
);
|
||||
|
||||
executeTest("docker cp $self->{strName}:${strSource} ${strDestination}");
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
1;
|
55
test/vm/Vagrantfile
vendored
55
test/vm/Vagrantfile
vendored
@ -36,7 +36,7 @@ Vagrant.configure(2) do |config|
|
||||
/backrest/test/vm/ssh/setup-cm.sh
|
||||
|
||||
# Install required Perl modules
|
||||
apt-get install libdbi-perl libdbd-pg-perl
|
||||
apt-get install -y libdbi-perl libdbd-pg-perl
|
||||
|
||||
# Install Perl modules required for building the docs
|
||||
apt-get install -y libxml-checker-perl libxml-writer-perl
|
||||
@ -82,6 +82,59 @@ Vagrant.configure(2) do |config|
|
||||
SHELL
|
||||
end
|
||||
|
||||
config.vm.define "u14doc" do |u14doc|
|
||||
u14doc.vm.box = "boxcutter/ubuntu1404"
|
||||
|
||||
u14doc.vm.provider :virtualbox do |vb|
|
||||
vb.name = "backrest-doc-test-ubuntu-14.04"
|
||||
end
|
||||
|
||||
# Provision the VM
|
||||
u14doc.vm.provision "shell", inline: <<-SHELL
|
||||
# Install docker
|
||||
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
|
||||
echo 'deb https://apt.dockerproject.org/repo ubuntu-trusty main' > /etc/apt/sources.list.d/docker.list
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install linux-image-extra-$(uname -r)
|
||||
sudo apt-get -y install docker-engine
|
||||
sudo usermod -aG docker vagrant
|
||||
|
||||
# This requires a reboot - maybe don't do it - see how it goes first
|
||||
# sed -i 's/^GRUB_CMDLINE_LINUX\=.*$/GRUB_CMDLINE_LINUX\=\"cgroup_enable=memory swapaccount=1\"/' /etc/default/grub
|
||||
|
||||
# Install Perl modules
|
||||
apt-get install -y libxml-checker-perl ghostscript
|
||||
|
||||
# Install texlive
|
||||
mkdir /root/texlive
|
||||
wget -q -O - http://mirror.hmc.edu/ctan/systems/texlive/tlnet/install-tl-unx.tar.gz | tar zxv -C /root//texlive --strip-components=1
|
||||
echo "collection-basic 1" >> /root/texlive/texlive.profile
|
||||
echo "collection-latex 1" >> /root/texlive/texlive.profile
|
||||
/root/texlive/install-tl -profile=/root/texlive/texlive.profile
|
||||
|
||||
echo 'PATH=/usr/local/texlive/2015/bin/x86_64-linux:$PATH' >> /etc/profile
|
||||
echo 'export PATH' >> /etc/profile
|
||||
|
||||
/usr/local/texlive/2015/bin/x86_64-linux/tlmgr install caption xcolor listings parskip helvetic ltablex titlesec \
|
||||
epstopdf courier
|
||||
|
||||
# Build images
|
||||
docker build -f /backrest/test/vm/docker/u14-base -t vagrant/u14-base /backrest/test/vm
|
||||
docker build -f /backrest/test/vm/docker/u14-db -t vagrant/u14-db /backrest/test/vm
|
||||
docker build -f /backrest/test/vm/docker/u14-backup -t vagrant/u14-backup /backrest/test/vm
|
||||
|
||||
docker build -f /backrest/test/vm/docker/co6-base -t vagrant/co6-base /backrest/test/vm
|
||||
docker build -f /backrest/test/vm/docker/co6-db -t vagrant/co6-db /backrest/test/vm
|
||||
docker build -f /backrest/test/vm/docker/co6-backup -t vagrant/co6-backup /backrest/test/vm
|
||||
|
||||
# Sample docker commands
|
||||
# docker inspect --format '{{ .NetworkSettings.IPAddress }}' db-master
|
||||
# docker run -itd --name=db-master -v /backrest:/backrest vagrant/u14-db
|
||||
# docker run -itd --name=backup -v /backrest:/backrest vagrant/u14-backup
|
||||
# docker exec -it db-master bash
|
||||
SHELL
|
||||
end
|
||||
|
||||
config.vm.define "co6" do |co6|
|
||||
co6.vm.box = "boxcutter/centos67"
|
||||
|
||||
|
19
test/vm/docker/co6-backup
Normal file
19
test/vm/docker/co6-backup
Normal file
@ -0,0 +1,19 @@
|
||||
# CentOS 6 Backup Container
|
||||
FROM vagrant/co6-base
|
||||
|
||||
# Create backrest user
|
||||
RUN adduser -gpostgres -u5002 -n backrest
|
||||
|
||||
# Setup SSH
|
||||
RUN mkdir /home/backrest/.ssh
|
||||
RUN cp -p /root/resource/.ssh/* /home/backrest/.ssh
|
||||
RUN chown -R backrest:postgres /home/backrest
|
||||
RUN chmod 700 /home/backrest/.ssh
|
||||
|
||||
# Setup repository
|
||||
RUN mkdir /var/lib/backrest
|
||||
RUN chown -R backrest:postgres /var/lib/backrest
|
||||
RUN chmod 750 /var/lib/backrest
|
||||
|
||||
# Install Perl packages
|
||||
RUN yum -y install perl perl-Time-HiRes perl-parent perl-JSON perl-Digest-SHA perl-DBD-Pg
|
31
test/vm/docker/co6-base
Normal file
31
test/vm/docker/co6-base
Normal file
@ -0,0 +1,31 @@
|
||||
# CentOS 6 Base Container
|
||||
FROM centos:6.7
|
||||
|
||||
# Install SSH
|
||||
RUN yum -y install openssh-server openssh-clients
|
||||
|
||||
# Create postgres user and group
|
||||
RUN groupadd -g5000 postgres
|
||||
RUN adduser -gpostgres -u5000 -n postgres
|
||||
|
||||
# Add Postgres packages
|
||||
RUN rpm -ivh http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-centos94-9.4-1.noarch.rpm
|
||||
|
||||
# Create vagrant user
|
||||
RUN groupadd -g5001 admin
|
||||
RUN adduser -gadmin -u5001 -n vagrant
|
||||
|
||||
# Install sudo and add admin to sudoers
|
||||
RUN yum -y install sudo
|
||||
RUN echo '%admin ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/vagrant
|
||||
RUN sed -i 's/^Defaults requiretty$/\# Defaults requiretty/' /etc/sudoers
|
||||
|
||||
# Copy trusted SSH setup
|
||||
COPY ssh/config /root/resource/.ssh/config
|
||||
COPY ssh/id_rsa /root/resource/.ssh/id_rsa
|
||||
COPY ssh/id_rsa.pub /root/resource/.ssh/authorized_keys
|
||||
RUN chmod 700 /root/resource/.ssh
|
||||
RUN chmod 600 /root/resource/.ssh/*
|
||||
|
||||
# Start SSH when container starts
|
||||
ENTRYPOINT service sshd restart && bash
|
16
test/vm/docker/co6-db
Normal file
16
test/vm/docker/co6-db
Normal file
@ -0,0 +1,16 @@
|
||||
# CentOS 6 Database Container
|
||||
FROM vagrant/co6-base
|
||||
|
||||
# Install Postgres
|
||||
RUN yum -y install postgresql94-server
|
||||
|
||||
# Create pg_backrest.conf
|
||||
RUN touch /etc/pg_backrest.conf
|
||||
RUN chmod 640 /etc/pg_backrest.conf
|
||||
RUN chown postgres:postgres /etc/pg_backrest.conf
|
||||
|
||||
# Setup SSH
|
||||
RUN mkdir /home/postgres/.ssh
|
||||
RUN cp /root/resource/.ssh/* /home/postgres/.ssh
|
||||
RUN chown -R postgres:postgres /home/postgres/.ssh
|
||||
RUN chmod 700 /home/postgres/.ssh
|
19
test/vm/docker/u14-backup
Normal file
19
test/vm/docker/u14-backup
Normal file
@ -0,0 +1,19 @@
|
||||
# Ubuntu 14.04 Backup Container
|
||||
FROM vagrant/u14-base
|
||||
|
||||
# Create backrest user
|
||||
RUN adduser --ingroup=postgres --disabled-password --gecos "" backrest
|
||||
|
||||
# Setup SSH
|
||||
RUN mkdir -p /home/backrest/.ssh
|
||||
RUN cp /root/resource/.ssh/* /home/backrest/.ssh
|
||||
RUN chown -R backrest:postgres /home/backrest/.ssh
|
||||
RUN chmod 700 /home/backrest/.ssh
|
||||
|
||||
# Setup repository
|
||||
RUN mkdir /var/lib/backrest
|
||||
RUN chown backrest:postgres /var/lib/backrest
|
||||
RUN chmod 750 /var/lib/backrest
|
||||
|
||||
# Install Perl packages
|
||||
RUN apt-get -y install libdbd-pg-perl libdbi-perl libnet-daemon-perl libplrpc-perl
|
41
test/vm/docker/u14-base
Normal file
41
test/vm/docker/u14-base
Normal file
@ -0,0 +1,41 @@
|
||||
# Ubuntu 14.04 Base Container
|
||||
FROM ubuntu:14.04
|
||||
|
||||
# Get packages that make up apt-get download
|
||||
# apt-get -dy install ??? --print-uris -qq | sed -n "s/'\([^ ]\+\)' \([^ ]\+\) \([^ ]\+\) MD5Sum:\([^ ]\+\)/wget -c \1/p"
|
||||
|
||||
# Install SSH
|
||||
RUN apt-get -y install openssh-server
|
||||
|
||||
# Create postgres user and group
|
||||
RUN groupadd -g5000 postgres
|
||||
RUN adduser --ingroup=postgres --disabled-password --gecos "" postgres
|
||||
|
||||
# Add Postgres packages
|
||||
RUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main 9.5' >> /etc/apt/sources.list.d/pgdg.list
|
||||
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
RUN sudo apt-get update
|
||||
|
||||
# Create vagrant user
|
||||
RUN addgroup admin
|
||||
RUN adduser --ingroup=admin --disabled-password --gecos "" vagrant
|
||||
RUN sed -i 's/^\%admin.*$/\%admin ALL\=\(ALL\) NOPASSWD\: ALL/' /etc/sudoers
|
||||
|
||||
# Suppress dpkg interactive output
|
||||
RUN rm /etc/apt/apt.conf.d/70debconf
|
||||
|
||||
# Download Perl packages to be installed later
|
||||
RUN apt-get -dy install libdbd-pg-perl libdbi-perl libnet-daemon-perl libplrpc-perl libpq5
|
||||
|
||||
# Download Postgres packages to be installed later
|
||||
RUN apt-get -dy install postgresql-9.4
|
||||
|
||||
# Copy trusted SSH setup
|
||||
COPY ssh/config /root/resource/.ssh/config
|
||||
COPY ssh/id_rsa /root/resource/.ssh/id_rsa
|
||||
COPY ssh/id_rsa.pub /root/resource/.ssh/authorized_keys
|
||||
RUN chmod 700 /root/resource/.ssh
|
||||
RUN chmod 600 /root/resource/.ssh/*
|
||||
|
||||
# Start SSH when container starts
|
||||
ENTRYPOINT service ssh restart && bash
|
17
test/vm/docker/u14-db
Normal file
17
test/vm/docker/u14-db
Normal file
@ -0,0 +1,17 @@
|
||||
# Ubuntu 14.04 Database Container
|
||||
FROM vagrant/u14-base
|
||||
|
||||
# Install Postgres
|
||||
RUN apt-get install -y postgresql-9.4
|
||||
RUN pg_dropcluster --stop 9.4 main
|
||||
|
||||
# Create pg_backrest.conf
|
||||
RUN touch /etc/pg_backrest.conf
|
||||
RUN chmod 640 /etc/pg_backrest.conf
|
||||
RUN chown postgres:postgres /etc/pg_backrest.conf
|
||||
|
||||
# Setup SSH
|
||||
RUN mkdir /home/postgres/.ssh
|
||||
RUN cp /root/resource/.ssh/* /home/postgres/.ssh
|
||||
RUN chown -R postgres:postgres /home/postgres/.ssh
|
||||
RUN chmod 700 /home/postgres/.ssh
|
@ -1,2 +1,3 @@
|
||||
Host *
|
||||
StrictHostKeyChecking no
|
||||
LogLevel quiet
|
||||
|
Loading…
Reference in New Issue
Block a user