diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml deleted file mode 100644 index 2102f2c53..000000000 --- a/.github/workflows/documentation.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: documentation generation - -on: - workflow_dispatch: - -jobs: - generate-doc: - name: build barman documentation - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - run: | - echo "${{ github.workspace }}" - - name: build documentation - id: build-documentation - uses: ./actions/build-documentation - with: - barman-path: ${{ github.workspace }} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index a4a1675c6..34ad45d42 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -58,10 +58,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Linters configuration. LINTER_RULES_PATH: '.' - # We are not interested in linting these files: - # * Markdown files under `doc` or `sphinx` directories, which belong to the - # old docs, and are going to be replaced soon. - FILTER_REGEX_EXCLUDE: '(doc|sphinx)/.*\.md' + # We are not interested in linting files from the old docs, which are going + # to be removed soon: + FILTER_REGEX_EXCLUDE: 'old_docs/.*\.md' DOCKERFILE_HADOLINT_FILE_NAME: .hadolint.yaml GITLEAKS_CONFIG_FILE: .gitleaks.toml MARKDOWN_CONFIG_FILE: .markdownlint.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bad219c90..3eaf1662a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Step 1 - Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Step 2 - Install python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.7 - name: Step 3 - Install dependencies @@ -35,13 +35,13 @@ jobs: steps: - name: Step 1 - Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Step 2 - Install python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "${{ matrix.python-version }}" - name: Step 3 - Do some caching for python packages - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-python-packages with: path: ${{ env.pythonLocation }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 2001a77b4..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,21 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Barman Release - -# Controls when the workflow will run -on: - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Runs a single command using the runners shell - - name: Run a one-line script - run: echo Hello, world! diff --git a/.gitignore b/.gitignore index a3879d20f..05cab0d36 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *~ \#*\# .*.swp +*.bak # eclipse project files /.project @@ -35,3 +36,10 @@ venv/* # pyenv .python-version + +# Sphinx docs +docs/_build/* +docs/contributor_guide/modules + +# Allow the man directory +!docs/_build/man/ \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md index ebd5610e6..815397038 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,3 +1,3 @@ -## Barman INSTALL instructions +# Barman INSTALL instructions -For further information, see the "Installation" section in the official manual of Barman or the Markdown source file: [doc/manual/16-installation.en.md](https://github.com/EnterpriseDB/barman/blob/master/doc/manual/16-installation.en.md). +For further information, see the "Installation" section in the official manual of Barman. diff --git a/MANIFEST.in b/MANIFEST.in index 60f6eeef2..86863a54f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ recursive-include barman *.py recursive-include rpm * -recursive-include doc * +recursive-include docs/barman.d * +include docs/barman.conf include scripts/barman.bash_completion -include AUTHORS NEWS ChangeLog LICENSE MANIFEST.in setup.py INSTALL README.rst +include AUTHORS RELNOTES.md ChangeLog LICENSE MANIFEST.in setup.py INSTALL README.rst diff --git a/NEWS b/NEWS deleted file mode 100644 index 777bfb4e0..000000000 --- a/NEWS +++ /dev/null @@ -1,1729 +0,0 @@ -Barman News - History of user-visible changes - -Version 3.11.1 - 22 August 2024 - -- Bug fixes: - - - Fix failures in `barman-cloud-backup-delete`. This command was failing when - applying retention policies due to a bug introduced by the previous release. - -Version 3.11.0 - 22 August 2024 - -- Add support for Postgres 17+ incremental backups. This major feature is - composed of several small changes: - - - Add `--incremental` command-line option to `barman backup` command. This is - used to specify the parent backup when taking an incremental backup. The - parent can be either a full backup or another incremental backup. - - - Add `latest-full` shortcut backup ID. Along with `latest`, this can be used - as a shortcut to select the parent backup for an incremental backup. While - `latest` takes the latest backup independently if it is full or incremental, - `latest-full` takes the latest full backup. - - - `barman keep` command can only be applied to full backups when - `backup_method = postgres`. If a full backup has incremental backups that - depend on it, all of the incrementals are also kept by Barman. - - - When deleting a backup all the incremental backups depending on it, if any, - are also removed. - - - Retention policies do not take incremental backups into consideration. As - incremental backups cannot be recovered without having the complete chain of - backups available up to the full backup, only full backups account for - retention policies. - - - `barman recover` needs to combine the full backup with the chain of incremental - backups when recovering. The new CLI option `--local-staging-path`, and the - corresponding `local_staging_path` configuration option, are used to specify - the path in the Barman host where the backups will be combined when recovering - an incremental backup. - -- Changes to `barman show-backup` output: - - - Add the “Estimated cluster size” field. It's useful to have an estimation - of the data directory size of a cluster when restoring a backup. It’s - particularly useful when recovering compressed backups or incremental - backups, situations where the size of the backup doesn’t reflect the size of the - data directory in Postgres. In JSON format, this is stored as - `cluster_size`. - - - Add the “WAL summarizer” field. This field shows if `summarize_wal` was - enabled in Postgres at the time the backup was taken. In JSON format, this - is stored as `server_information.summarize_wal`. This field is omitted for - Postgres 16 and older. - - - Add “Data checksums” field. This shows if `data_checkums` was enabled in - Postgres at the time the backup was taken. In JSON format, this is stored as - `server_information.data_checksums`. - - - Add the “Backup method” field. This shows the backup method used for this - backup. In JSON format, this is stored as - `base_backup_information.backup_method`. - - - Rename the field “Disk Usage” as “Backup Size”. The latter provides a more - comprehensive name which represents the size of the backup in the Barman - host. The JSON field under `base_backup_information` was also renamed from - `disk_usage` to `backup_size`. - - - Add the “WAL size” field. This shows the size of the WALs required by the - backup. In JSON format, this is stored as - `base_backup_information.wal_size`. - - - Refactor the field “Incremental size”. It is now named “Resources saving” - and it now shows an estimation of resources saved when taking incremental - backups with `rsync` or `pg_basebackup`. It compares the backup size with - the estimated cluster size to estimate the amount of disk and network - resources that were saved by taking an incremental backup. In JSON format, - the field was renamed from `incremental_size` to `resource_savings` under `base_backup_information`. - - - Add the `system_id` field to the JSON document. This field contains the - system identifier of Postgres. It was present in console format, but was - missing in JSON format. - - - Add fields related with Postgres incremental backups: - - - “Backup type”: indicates if the Postgres backup is full or incremental. In - JSON format, this is stored as `backup_type` under `base_backup_information`. - - - “Root backup”: the ID of the full backup that is the root of a chain of - one or more incremental backups. In JSON format, this is stored as - `catalog_information.root_backup_id`. - - - “Parent backup”: the ID of the full or incremental backup from which this - incremental backup was taken. In JSON format, this is stored as - `catalog_information.parent_backup_id`. - - - “Children Backup(s)”: the IDs of the incremental backups that were taken - with this backup as the parent. In JSON format, this is stored as - `catalog_information.children_backup_ids`. - - - “Backup chain size”: the number of backups in the chain from this - incremental backup up to the root backup. In JSON format, this is - stored as `catalog_information.chain_size`. - -- Changes to `barman list-backup` output: - - - It now includes the backup type in the JSON output, which can be either - `rsync` for backups taken with rsync, `full` or `incremental` for backups - taken with `pg_basebackup`, or `snapshot` for cloud snapshots. When printing - to the console the backup type is represented by the corresponding labels - `R`, `F`, `I` or `S`. - - - Remove tablespaces information from the output. That was bloating the - output. Tablespaces information can still be found in the output of - `barman show-backup`. - -- Always set a timestamp with a time zone when configuring - `recovery_target_time` through `barman recover`. Previously, if no time zone - was explicitly set through `--target-time`, Barman would configure - `recovery_target_time` without a time zone in Postgres. Without a time zone, - Postgres would assume whatever is configured through `timezone` GUC in - Postgres. From now on Barman will issue a warning and configure - `recovery_target_time` with the time zone of the Barman host if no time zone - is set by the user through `--target-time` option. - -- When recovering a backup with the “no get wal” approach and `--target-lsn` is set, - copy only the WAL files required to reach the configured target. Previously - Barman would copy all the WAL files from its archive to Postgres. - -- When recovering a backup with the “no get wal” approach and `--target-immediate` - is set, copy only the WAL files required to reach the consistent point. - Previously Barman would copy all the WAL files from its archive to Postgres. - -- `barman-wal-restore` now moves WALs from the spool directory to `pg_wal` - instead of copying them. This can improve performance if the spool directory - and the `pg_wal` directory are in the same partition. - -- `barman check-backup` now shows the reason why a backup was marked as `FAILED` - in the output and logs. Previously for a user to know why the backup was - marked as `FAILED`, they would need to run `barman show-backup` command. - -- Add configuration option `aws_await_snapshots_timeout` and the corresponding - `--aws-await-snapshots-timeout` command-line option on `barman-cloud-backup`. - This specifies the timeout in seconds to wait for snapshot backups to reach - the completed state. - -- Add a keep-alive mechanism to rsync-based backups. Previously the Postgres - session created by Barman to run `pg_backup_start()` and `pg_backup_stop()` would - stay idle for as long as the base backup copy would take. That could lead to a - firewall or router dropping the connection because it was idle for a long - time. The keep-alive mechanism sends heartbeat queries to Postgres - through that connection, thus reducing the likelihood of a connection - getting dropped. The interval between heartbeats can be controlled through the new - configuration option `keepalive_interval` and the corresponding CLI - option `--keepalive-interval` of the `barman backup` command. - -- Bug fixes: - - - When recovering a backup with the “no get wal” approach and `--target-time` - set, copy all WAL files. Previously Barman would attempt to “guess” the WAL - files required by Postgres to reach the configured target time. However, - the mechanism was not robust enough as it was based on the stats of the WAL - file in the Barman host (more specifically the creation time). For example: - if there were archiving or streaming lag between Postgres and Barman, that - could be enough for recovery to fail because Barman would miss to copy all - the required WAL files due to the weak check based on file stats. - - - Pin `python-snappy` to `0.6.1` when running Barman through Python 3.6 or - older. Newer versions of `python-snappy` require `cramjam` version `2.7.0` or - newer, and these are only available for Python 3.7 or newer. - - - `barman receive-wal` now exits with code `1` instead of `0` in the following - cases: - - - Being unable to run with `--reset` flag because `pg_receivewal` is - running. - - - Being unable to start `pg_receivewal` process because it is already - running. - - - Fix and improve information about Python in `barman diagnose` output: - - - The command now makes sure to use the same Python interpreter under which - Barman is installed when outputting the Python version through - `python_ver` JSON key. Previously, if an environment had multiple Python - installations and/or virtual environments, the output could eventually be - misleading, as it could be fetched from a different Python interpreter. - - - Added a `python_executable` key to the JSON output. That contains the path - to the exact Python interpreter being used by Barman. - -Version 3.10.1 - 12 June 2024 - -- Bug fixes: - - Make `argcomplete` optional to avoid installation issues on some - platforms. - - Load `barman.auto.conf` only when the file exists. - - Emit a warning when the `cfg_changes.queue` file is malformed. - - Correct in documentation the postgresql version where - `pg_checkpoint` is available. - - Add `--no-partial` option to `barman-cloud-wal-restore`. - -Version 3.10.0 - 24 January 2024 - -- Limit the average bandwidth used by `barman-cloud-backup` when backing - up to either AWS S3 or Azure Blob Storage according to the value set by - a new CLI option `--max-bandwidth`. - -- Add the new configuration option `lock_directory_cleanup` - That enables cron to automatically clean up the barman_lock_directory - from unused lock files. - -- Add support for a new type of configuration called `model`. - The model acts as a set of overrides for configuration options - for a given Barman server. - -- Add a new barman command `barman config-update` that allows the creation - and the update of configurations using JSON - -- Bug fixes: - - - Fix a bug that caused `--min-chunk-size` to be ignored when using - barman-cloud-backup as hook script in Barman. - - -Version 3.9.0 - 3 October 2023 - -- Allow `barman switch-wal --force` to be run against PG>=14 if the - user has the `pg_checkpoint` role (thanks to toydarian for this patch). - -- Log the current check at `info` level when a check timeout occurs. - -- The minimum size of an upload chunk when using `barman-cloud-backup` - with either S3 or Azure Blob Storage can now be specified using the - `--min-chunk-size` option. - -- `backup_compression = none` is supported when using `pg_basebackup`. - -- For PostgreSQL 15 and later: the allowed `backup_compression_level` - values for `zstd` and `lz4` have been updated to match those allowed by - `pg_basebackup`. - -- For PostgreSQL versions earlier than 15: `backup_compression_level = 0` - can now be used with `backup_compression = gzip`. - -- Bug fixes: - - - Fix `barman recover` on platforms where Multiprocessing uses spawn by - default when starting new processes. - -Version 3.8.0 - 31 August 2023 - -- Clarify package installation. barman is packaged with default python version - for each operating system. - -- The `minimum-redundancy` option is added to `barman-cloud-backup-delete`. - It allows to set the minimum number of backups that should always be available. - -- Add a new `primary_checkpoint_timeout` configuration option. Allows define - the amount of seconds that Barman will wait at the end of a backup if no - new WAL files are produced, before forcing a checkpoint on the primary server. - -- Bug fixes: - - - Fix race condition in barman retention policies application. Backup - deletions will now raise a warning if another deletion is in progress - for the requested backup. - - - Fix `barman-cloud-backup-show` man page installation. - -Version 3.7.0 - 25 July 2023 - -- Support is added for snapshot backups on AWS using EBS volumes. - -- The `--profile` option in the `barman-cloud-*` scripts is renamed - `--aws-profile`. The old name is deprecated and will be removed in - a future release. - -- Backup manifests can now be generated automatically on completion - of a backup made with `backup_method = rsync`. This is enabled by - setting the `autogenerate_manifest` configuration variable and can - be overridden using the `--manifest` and `--no-manifest` CLI options. - -- Bug fixes: - - - The `barman-cloud-*` scripts now correctly use continuation - tokens to page through objects in AWS S3-compatible object - stores. This fixes a bug where `barman-cloud-backup-delete` - would only delete the oldest 1000 eligible WALs after backup - deletion. - - - Minor documentation fixes. - -Version 3.6.0 - 15 June 2023 - -- PostgreSQL version 10 is no longer supported. - -- Support is added for snapshot backups on Microsoft Azure using - Managed Disks. - -- The `--snapshot-recovery-zone` option is renamed `--gcp-zone` for - consistency with other provider-specific options. The old name - is deprecated and will be removed in a future release. - -- The `snapshot_zone` option and `--snapshot-zone` argument are - renamed `gcp_zone` and `--gcp-zone` respectively. The old names - are deprecated and will be removed in a future release. - -- The `snapshot_gcp_project` option and `--snapshot-gcp-project` - argument are renamed to `gcp_project` and `--gcp-project`. The - old names are deprecated and will be removed in a future release. - -- Bug fixes: - - - Barman will no longer attempt to execute the `replication-status` - command for a passive node. - - - The `backup_label` is deleted from cloud storage when a - snapshot backup is deleted with `barman-cloud-backup-delete`. - - - Man pages for the `generate-manifest` and `verify-backup` - commands are added. - - - Minor documentation fixes. - -Version 3.5.0 - 29 March 2023 - -- Python 2.7 is no longer supported. The earliest Python version - supported is now 3.6. - -- The `barman`, `barman-cli` and `barman-cli-cloud` packages for - EL7 now require python 3.6 instead of python 2.7. For other - supported platforms, Barman packages already require python - versions 3.6 or later so packaging is unaffected. - -- Support for PostgreSQL 10 will be discontinued in future Barman - releases; 3.5.x is the last version of Barman with support for - PostgreSQL 10. - -- Backups and WALs uploaded to Google Cloud Storage can now be - encrypted using a specific KMS key by using the `--kms-key-name` - option with `barman-cloud-backup` or `barman-cloud-wal-archive`. - -- Backups and WALs uploaded to AWS S3 can now be encrypted using a - specific KMS key by using the `--sse-kms-key-id` option with - `barman-cloud-backup` or `barman-cloud-wal-archive` along with - `--encryption=aws:kms`. - -- Two new configuration options are provided which make it possible - to limit the rate at which parallel workers are started during - backups with `backup_method = rsync` and recoveries. - `parallel_jobs_start_batch_size` can be set to limit the amount of - parallel workers which will be started in a single batch, and - `parallel_jobs_start_batch_period` can be set to define the time - in seconds over which a single batch of workers will be started. - These can be overridden using the arguments `--jobs-start-batch-size` - and `--jobs-start-batch-period` with the `barman backup` and - `barman recover` commands. - -- A new option `--recovery-conf-filename` is added to `barman recover`. - This can be used to change the file to which Barman should write the - PostgreSQL recovery options from the default `postgresql.auto.conf` - to an alternative location. - -- Bug fixes: - - - Fix a bug which prevented `barman-cloud-backup-show` from - displaying the backup metadata for backups made with - `barman backup` and uploaded by `barman-cloud-backup` as a - post-backup hook script. - - - Fix a bug where the PostgreSQL connection used to validate backup - compression settings was left open until termination of the - Barman command. - - - Fix an issue which caused rsync-concurrent backups to fail when - running for a duration greater than `idle_session_timeout`. - - - Fix a bug where the backup name was not saved in the backup - metadata if the `--wait` flag was used with `barman backup`. - -- Thanks to mojtabash78, mhkarimi1383, epolkerman, barthisrael and - hzetters for their contributions. - -Version 3.4.0 - 26 January 2023 - -- This is the last release of Barman which will support Python 2 and - new features will henceforth require Python 3.6 or later. - -- A new `backup_method` named `snapshot` is added. This will create - backups by taking snapshots of cloud storage volumes. Currently - only Google Cloud Platform is supported however support for AWS - and Azure will follow in future Barman releases. Note that this - feature requires a minimum Python version of 3.7. Please see the - Barman manual for more information. - -- Support for snapshot backups is also added to `barman-cloud-backup`, - with minimal support for restoring a snapshot backup added to - `barman-cloud-restore`. - -- A new command `barman-cloud-backup-show` is added which displays - backup metadata stored in cloud object storage and is analogous to - `barman show-backup`. This is provided so that snapshot metadata - can be easily retrieved at restore time however it is also a - convenient way of inspecting metadata for any backup made with - `barman-cloud-backup`. - -- The instructions for installing Barman from RPMs in the docs are - updated. - -- The formatting of NFS requirements in the docs is fixed. - -- Supported PostgreSQL versions are updated in the docs (this is a - documentation fix only - the minimum supported major version is - still 10). - -Version 3.3.0 - 14 December 2022 - -- A backup can now be given a name at backup time using the new - `--name` option supported by the `barman backup` and - `barman-cloud-backup` commands. The backup name can then be used - in place of the backup ID when running commands to interact with - backups. Additionally, the commands to list and show backups have - been been updated to include the backup name in the plain text and - JSON output formats. - -- Stricter checking of PostgreSQL version to verify that Barman is - running against a supported version of PostgreSQL. - -- Bug fixes: - - - Fix inconsistencies between the barman cloud command docs and - the help output for those commands. - - - Use a new PostgreSQL connection when switching WALs on the - primary during the backup of a standby to avoid undefined - behaviour such as `SSL error` messages and failed connections. - - - Reduce log volume by changing the default log level of stdout - for commands executed in child processes to `DEBUG` (with the - exception of `pg_basebackup` which is deliberately logged at - `INFO` level due to it being a long-running process where it is - frequently useful to see the output during the execution of the - command). - -Version 3.2.0 - 20 October 2022 - -- `barman-cloud-backup-delete` now accepts a `--batch-size` option - which determines the maximum number of objects deleted in a single - request. - -- All `barman-cloud-*` commands now accept a `--read-timeout` option - which, when used with the `aws-s3` cloud provider, determines the - read timeout used by the boto3 library when making requests to S3. - -- Bug fixes: - - - Fix the failure of `barman recover` in cases where - `backup_compression` is set in the Barman configuration but the - PostgreSQL server is unavailable. - -Version 3.1.0 - 14 September 2022 - -- Backups taken with `backup_method = postgres` can now be compressed - using lz4 and zstd compression by setting `backup_compression = lz4` - or `backup_compression = zstd` respectively. These options are only - supported with PostgreSQL 15 (beta) or later. - -- A new option `backup_compression_workers` is available which sets - the number of threads used for parallel compression. This is - currently only available with `backup_method = postgres` and - `backup_compression = zstd`. - -- A new option `primary_conninfo` can be set to avoid the need for - backups of standbys to wait for a WAL switch to occur on the primary - when finalizing the backup. Barman will use the connection string - in `primary_conninfo` to perform WAL switches on the primary when - stopping the backup. - -- Support for certain Rsync versions patched for CVE-2022-29154 which - require a trailing newline in the `--files-from` argument. - -- Allow `barman receive-wal` maintenance options (`--stop`, `--reset`, - `--drop-slot` and `--create-slot`) to run against inactive servers. - -- Add `--port` option to `barman-wal-archive` and `barman-wal-restore` - commands so that a custom SSH port can be used without requiring any - SSH configuration. - -- Various documentation improvements. - -- Python 3.5 is no longer supported. - -- Bug fixes: - - - Ensure PostgreSQL connections are closed cleanly during the - execution of `barman cron`. - - - `barman generate-manifest` now treats pre-existing - backup_manifest files as an error condition. - - - backup_manifest files are renamed by appending the backup ID - during recovery operations to prevent future backups including - an old backup_manifest file. - - - Fix epoch timestamps in json output which were not - timezone-aware. - - - The output of `pg_basebackup` is now written to the Barman - log file while the backup is in progress. - -- We thank barthisrael, elhananjair, kraynopp, lucianobotti, and mxey - for their contributions to this release. - -Version 3.0.1 - 27 June 2022 - -- Bug fixes: - - - Fix package signing issue in PyPI (same sources as 3.0.0) - -Version 3.0.0 - 23 June 2022 - -- BREAKING CHANGE: PostgreSQL versions 9.6 and earlier are no longer - supported. If you are using one of these versions you will need to - use an earlier version of Barman. - -- BREAKING CHANGE: The default backup mode for Rsync backups is now - concurrent rather than exclusive. Exclusive backups have been - deprecated since PostgreSQL 9.6 and have been removed in PostgreSQL - 15. If you are running Barman against PostgreSQL versions earlier - than 15 and want to use exclusive backups you will now need to set - `exclusive_backup` in `backup_options`. - -- BREAKING CHANGE: The backup metadata stored in the `backup.info` file - for each backup has an extra field. This means that earlier versions - of Barman will not work in the presence of any backups taken with - 3.0.0. Additionally, users of pg-backup-api will need to upgrade it - to version 0.2.0 so that pg-backup-api can work with the updated - metadata. - -- Backups taken with `backup_method = postgres` can now be compressed - by pg_basebackup by setting the `backup_compression` config option. - Additional options are provided to control the compression level, - the backup format and whether the pg_basebackup client or the - PostgreSQL server applies the compression. NOTE: Recovery of these - backups requires Barman to stage the compressed files on the recovery - server in a location specified by the `recovery_staging_path` option. - -- Add support for PostgreSQL 15. Exclusive backups are not supported - by PostgreSQL 15 therefore Barman configurations for PostgreSQL 15 - servers are not allowed to specify `exclusive_backup` in - `backup_options`. - -- Various documentation improvements. - -- Use custom_compression_magic, if set, when identifying compressed - WAL files. This allows Barman to correctly identify uncompressed - WALs (such as `*.partial` files in the `streaming` directory) and - return them instead of attempting to decompress them. - -- Bug fixes: - - - Fix an ordering bug which caused Barman to log the message - "Backup failed issuing start backup command." while handling a - failure in the stop backup command. - - - Fix a bug which prevented recovery using `--target-tli` when - timelines greater than 9 were present, due to hexadecimal values - from WAL segment names being parsed as base 10 integers. - - - Fix an import error which occurs when using barman cloud with - certain python2 installations due to issues with the enum34 - dependency. - - - Fix a bug where Barman would not read more than three bytes from - a compressed WAL when attempting to identify the magic bytes. This - means that any custom compressed WALs using magic longer than three - bytes are now decompressed correctly. - - - Fix a bug which caused the `--immediate-checkpoint` flag to be - ignored during backups with `backup_method = rsync`. - -Version 2.19 - 9 March 2022 - -- Change `barman diagnose` output date format to ISO8601. - -- Add Google Cloud Storage (GCS) support to barman cloud. - -- Support `current` and `latest` recovery targets for the `--target-tli` - option of `barman recover`. - -- Add documentation for installation on SLES. - -- Bug fixes: - - - `barman-wal-archive --test` now returns a non-zero exit code when - an error occurs. - - - Fix `barman-cloud-check-wal-archive` behaviour when `-t` option is - used so that it exits after connectivity test. - - - `barman recover` now continues when `--no-get-wal` is used and - `"get-wal"` is not set in `recovery_options`. - - - Fix `barman show-servers --format=json ${server}` output for - inactive server. - - - Check for presence of `barman_home` in configuration file. - - - Passive barman servers will no longer store two copies of the - tablespace data when syncing backups taken with - `backup_method = postgres`. - -- We thank richyen for his contributions to this release. - -Version 2.18 - 21 January 2022 - -- Add snappy compression algorithm support in barman cloud (requires the - optional python-snappy dependency). - -- Allow Azure client concurrency parameters to be set when uploading - WALs with barman-cloud-wal-archive. - -- Add `--tags` option in barman cloud so that backup files and archived - WALs can be tagged in cloud storage (aws and azure). - -- Update the barman cloud exit status codes so that there is a dedicated - code (2) for connectivity errors. - -- Add the commands `barman verify-backup` and `barman generate-manifest` - to check if a backup is valid. - -- Add support for Azure Managed Identity auth in barman cloud which can - be enabled with the `--credential` option. - -- Bug fixes: - - - Change `barman-cloud-check-wal-archive` behavior when bucket does - not exist. - - - Ensure `list-files` output is always sorted regardless of the - underlying filesystem. - - - Man pages for barman-cloud-backup-keep, barman-cloud-backup-delete - and barman-cloud-check-wal-archive added to Python packaging. - -- We thank richyen and stratakis for their contributions to this - release. - -Version 2.17 - 1 December 2021 - -- Bug fixes: - - - Resolves a performance regression introduced in version 2.14 which - increased copy times for `barman backup` or `barman recover` commands - when using the `--jobs` flag. - - - Ignore rsync partial transfer errors for `sender` processes so that - such errors do not cause the backup to fail (thanks to barthisrael). - -Version 2.16 - 17 November 2021 - -- Add the commands `barman-check-wal-archive` and `barman-cloud-check-wal-archive` - to validate if a proposed archive location is safe to use for a new PostgreSQL - server. - -- Allow Barman to identify WAL that's already compressed using a custom - compression scheme to avoid compressing it again. - -- Add `last_backup_minimum_size` and `last_wal_maximum_age` options to - `barman check`. - -- Bug fixes: - - - Use argparse for command line parsing instead of the unmaintained - argh module. - - - Make timezones consistent for `begin_time` and `end_time`. - -- We thank chtitux, George Hansper, stratakis, Thoro, and vrms for their - contributions to this release. - -Version 2.15 - 12 October 2021 - -- Add plural forms for the `list-backup`, `list-server` and - `show-server` commands which are now `list-backups`, `list-servers` - and `show-servers`. The singular forms are retained for backward - compatibility. - -- Add the `last-failed` backup shortcut which references the newest - failed backup in the catalog so that you can do: - - - `barman delete last-failed` - -- Bug fixes: - - - Tablespaces will no longer be omitted from backups of EPAS - versions 9.6 and 10 due to an issue detecting the correct version - string on older versions of EPAS. - -Version 2.14 - 22 September 2021 - -- Add the `barman-cloud-backup-delete` command which allows backups in - cloud storage to be deleted by specifying either a backup ID or a - retention policy. - -- Allow backups to be retained beyond any retention policies in force by - introducing the ability to tag existing backups as archival backups - using `barman keep` and `barman-cloud-backup-keep`. - -- Allow the use of SAS authentication tokens created at the restricted - blob container level (instead of the wider storage account level) for - Azure blob storage - -- Significantly speed up `barman restore` into an empty directory for - backups that contain hundreds of thousands of files. - -- Bug fixes: - - - The backup privileges check will no longer fail if the user lacks - "userepl" permissions and will return better error messages if any - required permissions are missing (#318 and #319). - -Version 2.13 - 26 July 2021 - -- Add Azure blob storage support to barman-cloud - -- Support tablespace remapping in barman-cloud-restore via - `--tablespace name:location` - -- Allow barman-cloud-backup and barman-cloud-wal-archive to run as - Barman hook scripts, to allow data to be relayed to cloud storage - from the Barman server - -- Bug fixes: - - - Stop backups failing due to idle_in_transaction_session_timeout - (https://github.com/EnterpriseDB/barman/issues/333) - - - Fix a race condition between backup and archive-wal in updating - xlog.db entries (#328) - - - Handle PGDATA being a symlink in barman-cloud-backup, which led to - "seeking backwards is not allowed" errors on restore (#351) - - - Recreate pg_wal on restore if the original was a symlink (#327) - - - Recreate pg_tblspc symlinks for tablespaces on restore (#343) - - - Make barman-cloud-backup-list skip backups it cannot read, e.g., - because they are in Glacier storage (#332) - - - Add `-d database` option to barman-cloud-backup to specify which - database to connect to initially (#307) - - - Fix "Backup failed uploading data" errors from barman-cloud-backup - on Python 3.8 and above, caused by attempting to pickle the boto3 - client (#361) - - - Correctly enable server-side encryption in S3 for buckets that do - not have encryption enabled by default. - - In Barman 2.12, barman-cloud-backup's `--encryption` option did - not correctly enable encryption for the contents of the backup if - the backup was stored in an S3 bucket that did not have encryption - enabled. If this is the case for you, please consider deleting - your old backups and taking new backups with Barman 2.13. - - If your S3 buckets already have encryption enabled by default - (which we recommend), this does not affect you. - -Version 2.12.1 - 30 June 2021 - -- Bug fixes: - - - Allow specifying target-tli with other target-* recovery options - - Fix incorrect NAME in barman-cloud-backup-list manpage - - Don't raise an error if SIGALRM is ignored - - Fetch wal_keep_size, not wal_keep_segments, from Postgres 13 - -Version 2.12 - 5 Nov 2020 - -- Introduce a new backup_method option called local-rsync which - targets those cases where Barman is installed on the same server - where PostgreSQL is and directly uses rsync to take base backups, - bypassing the SSH layer. - -- Bug fixes: - - - Avoid corrupting boto connection in worker processes - - Avoid connection attempts to PostgreSQL during tests - -Version 2.11 - 9 Jul 2020 - -- Introduction of the barman-cli-cloud package that contains all cloud - related utilities. - -- Add barman-cloud-wal-restore to restore a WAL file previously - archived with barman-cloud-wal-archive from an object store - -- Add barman-cloud-restore to restore a backup previously taken with - barman-cloud-backup from an object store - -- Add barman-cloud-backup-list to list backups taken with - barman-cloud-backup in an object store - -- Add support for arbitrary archive size for barman-cloud-backup - -- Add support for --endpoint-url option to cloud utilities - -- Remove strict superuser requirement for PG 10+ (by Kaarel Moppel) - -- Add --log-level runtime option for barman to override default log - level for a specific command - -- Support for PostgreSQL 13 - -- Bug fixes: - - - Suppress messages and warning with SSH connections in barman-cli - (GH-257) - - Fix a race condition when retrieving uploaded parts in - barman-cloud-backup (GH-259) - - Close the PostgreSQL connection after a backup (GH-258) - - Check for uninitialized replication slots in receive-wal --reset - (GH-260) - - Ensure that begin_wal is valorised before acting on it (GH-262) - - Fix bug in XLOG/WAL arithmetic with custom segment size (GH-287) - - Fix rsync compatibility error with recent rsync - - Fix PostgreSQLClient version parsing - - Fix PostgreSQL exception handling with non ASCII messages - - Ensure each postgres connection has an empty search_path - - Avoid connecting to PostgreSQL while reading a backup.info file - -If you are using already barman-cloud-wal-archive or barman-cloud-backup -installed via RPM/Apt package and you are upgrading your system, you -must install the barman-cli-cloud package. All cloud related tools are -now part of the barman-cli-cloud package, including -barman-cloud-wal-archive and barman-cloud-backup that were previously -shipped with barman-cli. The reason is complex dependency management of -the boto3 library, which is a requirement for the cloud utilities. - -Version 2.10 - 5 Dec 2019 - -- Pull .partial WAL files with get-wal and barman-wal-restore, - allowing restore_command in a recovery scenario to fetch a partial - WAL file's content from the Barman server. This feature simplifies - and enhances RPO=0 recovery operations. - -- Store the PostgreSQL system identifier in the server directory and - inside the backup information file. Improve check command to verify - the consistency of the system identifier with active connections - (standard and replication) and data on disk. - -- A new script called barman-cloud-wal-archive has been added to the - barman-cli package to directly ship WAL files from PostgreSQL (using - archive_command) to cloud object storage services that are - compatible with AWS S3. It supports encryption and compression. - -- A new script called barman-cloud-backup has been added to the - barman-cli package to directly ship base backups from a local - PostgreSQL server to cloud object storage services that are - compatible with AWS S3. It supports encryption, parallel upload, - compression. - -- Automated creation of replication slots through the server/global - option create_slot. When set to auto, Barman creates the replication - slot, in case streaming_archiver is enabled and slot_name is - defined. The default value is manual for back-compatibility. - -- Add '-w/--wait' option to backup command, making Barman wait for all - required WAL files to be archived before considering the backup - completed. Add also the --wait-timeout option (default 0, no - timeout). - -- Redact passwords from Barman output, in particular from - barman diagnose (InfoSec) - -- Improve robustness of receive-wal --reset command, by verifying that - the last partial file is aligned with the current location or, if - present, with replication slot's. - -- Documentation improvements - -- Bug fixes: - - - Wrong string matching operation when excluding tablespaces - inside PGDATA (GH-245) - - Minor fixes in WAL delete hook scripts (GH-240) - - Fix PostgreSQL connection aliveness check (GH-239) - -Version 2.9 - 1 Aug 2019 - -- Transparently support PostgreSQL 12, by supporting the new way of - managing recovery and standby settings through GUC options and - signal files (recovery.signal and standby.signal) - -- Add --bwlimit command line option to set bandwidth limitation for - backup and recover commands - -- Ignore WAL archive failure for check command in case the latest - backup is WAITING_FOR_WALS - -- Add --target-lsn option to set recovery target Log Sequence Number - for recover command with PostgreSQL 10 or higher - -- Add --spool-dir option to barman-wal-restore so that users can - change the spool directory location from the default, avoiding - conflicts in case of multiple PostgreSQL instances on the same - server (thanks to Drazen Kacar). - -- Rename barman_xlog directory to barman_wal - -- JSON output writer to export command output as JSON objects and - facilitate integration with external tools and systems (thanks to - Marcin Onufry Hlybin). Experimental in this release. - -Bug fixes: - -- replication-status doesn’t show streamers with no slot (GH-222) - -- When checking that a connection is alive (“SELECT 1” query), - preserve the status of the PostgreSQL connection (GH-149). This - fixes those cases of connections that were terminated due to - idle-in-transaction timeout, causing concurrent backups to fail. - -Version 2.8 - 17 May 2019 - -- Add support for reuse_backup in geo-redundancy for incremental - backup copy in passive nodes - -- Improve performance of rsync based copy by using strptime instead of - the more generic dateutil.parser (#210) - -- Add ‘--test’ option to barman-wal-archive and barman-wal-restore to - verify the connection with the Barman server - -- Complain if backup_options is not explicitly set, as the future - default value will change from exclusive_backup to concurrent_backup - when PostgreSQL 9.5 will be declared EOL by the PGDG - -- Display additional settings in the show-server and diagnose - commands: archive_timeout, data_checksums, hot_standby, - max_wal_senders, max_replication_slots and wal_compression. - -- Merge the barman-cli project in Barman - -- Bug fixes: - - - Fix encoding error in get-wal on Python 3 (Jeff Janes, #221) - - Fix exclude_and_protect_filter (Jeff Janes, #217) - - Remove spurious message when resetting WAL (Jeff Janes, #215) - - Fix sync-wals error if primary has WALs older than the first - backup - - Support for double quotes in synchronous_standby_names setting - -- Minor changes: - - - Improve messaging of check --nagios for inactive servers - - Log remote SSH command with recover command - - Hide logical decoding connections in replication-status command - -This release officially supports Python 3 and deprecates Python 2 (which -might be discontinued in future releases). - -PostgreSQL 9.3 and older is deprecated from this release of Barman. -Support for backup from standby is now limited to PostgreSQL 9.4 or -higher and to WAL shipping from the standby (please refer to the -documentation for details). - -Version 2.7 - 21 Mar 2019 - -- Fix error handling during the parallel backup. Previously an - unrecoverable error during the copy could have corrupted the barman - internal state, requiring a manual kill of barman process with - SIGTERM and a manual cleanup of the running backup in PostgreSQL. - (GH#199) - -- Fix support of UTF-8 characters in input and output (GH#194 and - GH#196) - -- Ignore history/backup/partial files for first sync of geo-redundancy - (GH#198) - -- Fix network failure with geo-redundancy causing cron to break - (GH#202) - -- Fix backup validation in PostgreSQL older than 9.2 - -- Various documentation fixes - -Version 2.6 - 4 Feb 2019 - -- Add support for Geographical redundancy, introducing 3 new commands: - sync-info, sync-backup and sync-wals. Geo-redundancy allows a Barman - server to use another Barman server as data source instead of a - PostgreSQL server. - -- Add put-wal command that allows Barman to safely receive WAL files - via PostgreSQL's archive_command using the barman-wal-archive script - included in barman-cli - -- Add ANSI colour support to check command - -- Minor fixes: - - - Fix switch-wal on standby with an empty WAL directory - - Honour archiver locking in wait_for_wal method - - Fix WAL compression detection algorithm - - Fix current_action in concurrent stop backup errors - - Do not treat lock file busy as an error when validating a backup - -Version 2.5 - 23 Oct 2018 - -- Add support for PostgreSQL 11 - -- Add check-backup command to verify that WAL files required for - consistency of a base backup are present in the archive. Barman now - adds a new state (WAITING_FOR_WALS) after completing a base backup, - and sets it to DONE once it has verified that all WAL files from - start to the end of the backup exist. This command is included in - the regular cron maintenance job. Barman now notifies users - attempting to recover a backup that is in WAITING_FOR_WALS state. - -- Allow switch-xlog --archive to work on a standby (just for the - archive part) - -- Bug fixes: - - - Fix decoding errors reading external commands output (issue - #174) - - - Fix documentation regarding WAL streaming and backup from - standby - -Version 2.4 - 25 May 2018 - -- Add standard and retry hook scripts for backup deletion (pre/post) - -- Add standard and retry hook scripts for recovery (pre/post) - -- Add standard and retry hook scripts for WAL deletion (pre/post) - -- Add --standby-mode option to barman recover to add standby_mode = on - in pre-generated recovery.conf - -- Add --target-action option to barman recover, allowing users to add - shutdown, pause or promote to the pre-generated recovery.conf file - -- Improve usability of point-in-time recovery with consistency checks - (e.g. recovery time is after end time of backup) - -- Minor documentation improvements - -- Drop support for Python 3.3 - -Relevant bug fixes: - -- Fix remote get_file_content method (GitHub #151), preventing - incremental recovery from happening - -- Unicode issues with command (GitHub #143 and #150) - -- Add --wal-method=none when pg_basebackup >= 10 (GitHub #133) - -Minor bug fixes: - -- Stop process manager module from overwriting lock files content - -- Relax the rules for rsync output parsing - -- Ignore vanished files in streaming directory - -- Case insensitive slot names (GitHub #170) - -- Make DataTransferFailure.from_command_error() more resilient - (GitHub #86) - -- Rename command() to barman_command() (GitHub #118) - -- Initialise synchronous standby names list if not set (GitHub #111) - -- Correct placeholders ordering (GitHub #138) - -- Force datestyle to iso for replication connections - -- Returns error if delete command does not remove the backup - -- Fix exception when calling is_power_of_two(None) - -- Downgraded sync standby names messages to debug (GitHub #89) - -Version 2.3 - 5 Sep 2017 - -- Add support to PostgreSQL 10 - -- Follow naming changes in PostgreSQL 10: - - - The switch-xlog command has been renamed to switch-wal. - - In commands output, the xlog word has been changed to WAL and - location has been changed to LSN when appropriate. - -- Add the --network-compression/--no-network-compression options to - barman recover to enable or disable network compression at run-time - -- Add --target-immediate option to recover command, in order to exit - recovery when a consistent state is reached (end of the backup, - available from PostgreSQL 9.4) - -- Show cluster state (master or standby) with barman status command - -- Documentation improvements - -- Bug fixes: - - - Fix high memory usage with parallel_jobs > 1 (#116) - - Better handling of errors using parallel copy (#114) - - Make barman diagnose more robust with system exceptions - - Let archive-wal ignore files with .tmp extension - -Version 2.2 - 17 Jul 2017 - -- Implement parallel copy for backup/recovery through the - parallel_jobs global/server option to be overridden by the --jobs or - -j runtime option for the backup and recover command. Parallel - backup is available only for the rsync copy method. By default, it - is set to 1 (for behaviour compatibility with previous versions). - -- Support custom WAL size for PostgreSQL 8.4 and newer. At backup - time, Barman retrieves from PostgreSQL wal_segment_size and - wal_block_size values and computes the necessary calculations. - -- Improve check command to ensure that incoming directory is empty - when archiver=off, and streaming directory is empty when - streaming_archiver=off (#80). - -- Add external_configuration to backup_options so that users can - instruct Barman to ignore backup of configuration files when they - are not inside PGDATA (default for Debian/Ubuntu installations). In - this case, Barman does not display a warning anymore. - -- Add --get-wal and --no-get-wal options to barman recover - -- Add max_incoming_wals_queue global/server option for the check - command so that a non blocking error is returned in case incoming - WAL directories for both archiver and the streaming_archiver contain - more files than the specified value. - -- Documentation improvements - -- File format changes: - - - The format of backup.info file has changed. For this reason a - backup taken with Barman 2.2 cannot be read by a previous - version of Barman. But, backups taken by previous versions can - be read by Barman 2.2. - -- Minor bug fixes: - - - Allow replication-status to work against a standby - - Close any PostgreSQL connection before starting pg_basebackup - (#104, #108) - - Safely handle paths containing special characters - - Archive .partial files after promotion of streaming source - - Recursively create directories during recovery (SF#44) - - Improve xlog.db locking (#99) - - Remove tablespace_map file during recover (#95) - - Reconnect to PostgreSQL if connection drops (SF#82) - -Version 2.1 - 5 Jan 2017 - -- Add --archive and --archive-timeout options to switch-xlog command - -- Preliminary support for PostgreSQL 10 (#73) - -- Minor additions: - - - Add last archived WAL info to diagnose output - - Add start time and execution time to the output of delete - command - -- Minor bug fixes: - - - Return failure for get-wal command on inactive server - - Make streaming_archiver_names and streaming_backup_name options - global (#57) - - Fix rsync failures due to files truncated during transfer (#64) - - Correctly handle compressed history files (#66) - - Avoid de-referencing symlinks in pg_tblspc when preparing - recovery (#55) - - Fix comparison of last archiving failure (#40, #58) - - Avoid failing recovery if postgresql.conf is not writable (#68) - - Fix output of replication-status command (#56) - - Exclude files from backups like pg_basebackup (#65, #72) - - Exclude directories from other Postgres versions while copying - tablespaces (#74) - - Make retry hook script options global - -Version 2.0 - 27 Sep 2016 - -- Support for pg_basebackup and base backups over the PostgreSQL - streaming replication protocol with backup_method=postgres - (PostgreSQL 9.1 or higher required) - -- Support for physical replication slots through the slot_name - configuration option as well as the --create-slot and --drop-slot - options for the receive-wal command (PostgreSQL 9.4 or higher - required). When slot_name is specified and streaming_archiver is - enabled, receive-wal transparently integrates with pg_receivexlog, - and check makes sure that slots exist and are actively used - -- Support for the new backup API introduced in PostgreSQL 9.6, which - transparently enables concurrent backups and backups from standby - servers using the standard rsync method of backup. Concurrent backup - was only possible for PostgreSQL 9.2 to 9.5 versions through the - pgespresso extension. The new backup API will make pgespresso - redundant in the future - -- If properly configured, Barman can function as a synchronous standby - in terms of WAL streaming. By properly setting the - streaming_archiver_name in the synchronous_standby_names priority - list on the master, and enabling replication slot support, the - receive-wal command can now be part of a PostgreSQL synchronous - replication cluster, bringing RPO=0 (PostgreSQL 9.5.5 or - higher required) - -- Introduce barman-wal-restore, a standard and robust script written - in Python that can be used as restore_command in recovery.conf files - of any standby server of a cluster. It supports remote parallel - fetching of WAL files by efficiently invoking get-wal through SSH. - Currently available as a separate project called barman-cli. The - barman-cli package is required for remote recovery when get-wal is - listed in recovery_options - -- Control the maximum execution time of the check command through the - check_timeout global/server configuration option (30 seconds - by default) - -- Limit the number of WAL segments that are processed by an - archive-wal run, through the archiver_batch_size and - streaming_archiver_batch_size global/server options which control - archiving of WAL segments coming from, respectively, the standard - archiver and receive-wal - -- Removed locking of the XLOG database during check operations - -- The show-backup command is now aware of timelines and properly - displays which timelines can be used as recovery targets for a given - base backup. Internally, Barman is now capable of parsing .history - files - -- Improved the logic behind the retry mechanism when copy operations - experience problems. This involves backup (rsync and postgres) as - well as remote recovery (rsync) - -- Code refactoring involving remote command and physical copy - interfaces - -- Bug fixes: - - - Correctly handle .history files from streaming - - Fix replication-status on PostgreSQL 9.1 - - Fix replication-status when sent and write locations are not - available - - Fix misleading message on pg_receivexlog termination - -Version 1.6.1 - 23 May 2016 - -- Add --peek option to get-wal command to discover existing WAL files - from the Barman's archive - -- Add replication-status command for monitoring the status of any - streaming replication clients connected to the PostgreSQL server. - The --target option allows users to limit the request to only hot - standby servers or WAL streaming clients - -- Add the switch-xlog command to request a switch of a WAL file to the - PostgreSQL server. Through the '--force' it issues a CHECKPOINT - beforehand - -- Add streaming_archiver_name option, which sets a proper - application_name to pg_receivexlog when streaming_archiver is - enabled (only for PostgreSQL 9.3 and above) - -- Check for _superuser_ privileges with PostgreSQL's standard - connections (#30) - -- Check the WAL archive is never empty - -- Check for 'backup_label' on the master when server is down - -- Improve barman-wal-restore contrib script - -- Bug fixes: - - - Treat the "failed backups" check as non-fatal - - Rename '-x' option for get-wal as '-z' - - Add archive_mode=always support for PostgreSQL 9.5 (#32) - - Properly close PostgreSQL connections when necessary - - Fix receive-wal for pg_receive_xlog version 9.2 - -Version 1.6.0 - 29 Feb 2016 - -- Support for streaming replication connection through the - streaming_conninfo server option - -- Support for the streaming_archiver option that allows Barman to - receive WAL files through PostgreSQL's native streaming protocol. - When set to 'on', it relies on pg_receivexlog to receive WAL data, - reducing Recovery Point Objective. Currently, WAL streaming is an - additional feature (standard log archiving is still required) - -- Implement the receive-wal command that, when streaming_archiver is - on, wraps pg_receivexlog for WAL streaming. Add --stop option to - stop receiving WAL files via streaming protocol. Add --reset option - to reset the streaming status and restart from the current xlog - in Postgres. - -- Automatic management (startup and stop) of receive-wal command via - cron command - -- Support for the path_prefix configuration option - -- Introduction of the archiver option (currently fixed to on) which - enables continuous WAL archiving for a specific server, through log - shipping via PostgreSQL's archive_command - -- Support for streaming_wals_directory and errors_directory options - -- Management of WAL duplicates in archive-wal command and integration - with check command - -- Verify if pg_receivexlog is running in check command when - streaming_archiver is enabled - -- Verify if failed backups are present in check command - -- Accept compressed WAL files in incoming directory - -- Add support for the pigz compressor (thanks to Stefano Zacchiroli - zack@upsilon.cc) - -- Implement pygzip and pybzip2 compressors (based on an initial idea - of Christoph Moench-Tegeder christoph@2ndquadrant.de) - -- Creation of an implicit restore point at the end of a backup - -- Current size of the PostgreSQL data files in barman status - -- Permit archive_mode=always for PostgreSQL 9.5 servers (thanks to - Christoph Moench-Tegeder christoph@2ndquadrant.de) - -- Complete refactoring of the code responsible for connecting to - PostgreSQL - -- Improve messaging of cron command regarding sub-processes - -- Native support for Python >= 3.3 - -- Changes of behaviour: - - Stop trashing WAL files during archive-wal (commit:e3a1d16) - -- Bug fixes: - - Atomic WAL file archiving (#9 and #12) - - Propagate "-c" option to any Barman subprocess (#19) - - Fix management of backup ID during backup deletion (#22) - - Improve archive-wal robustness and log messages (#24) - - Improve error handling in case of missing parameters - -Version 1.5.1 - 16 Nov 2015 - -- Add support for the 'archive-wal' command which performs WAL - maintenance operations on a given server -- Add support for "per-server" concurrency of the 'cron' command -- Improved management of xlog.db errors -- Add support for mixed compression types in WAL files (SF.net#61) -- Bug fixes: - - Avoid retention policy checks during the recovery - - Avoid 'wal_level' check on PostgreSQL version < 9.0 (#3) - - Fix backup size calculation (#5) - -Version 1.5.0 - 28 Sep 2015 - -- Add support for the get-wal command which allows users to fetch any - WAL file from the archive of a specific server -- Add support for retry hook scripts, a special kind of hook scripts - that Barman tries to run until they succeed -- Add active configuration option for a server to temporarily disable - the server by setting it to False -- Add barman_lock_directory global option to change the location of - lock files (by default: 'barman_home') -- Execute the full suite of checks before starting a backup, and skip - it in case one or more checks fail -- Forbid to delete a running backup -- Analyse include directives of a PostgreSQL server during backup and - recover operations -- Add check for conflicting paths in the configuration of Barman, both - intra (by temporarily disabling a server) and inter-server (by - refusing any command, to any server). -- Add check for wal_level -- Add barman-wal-restore script to be used as restore_command on a - standby server, in conjunction with barman get-wal -- Implement a standard and consistent policy for error management -- Improved cache management of backups -- Improved management of configuration in unit tests -- Tutorial and man page sources have been converted to Markdown format -- Add code documentation through Sphinx -- Complete refactor of the code responsible for managing the backup - and the recover commands -- Changed internal directory structure of a backup -- Introduce copy_method option (currently fixed to rsync) -- Bug fixes: - - Manage options without '=' in PostgreSQL configuration files - - Preserve Timeline history files (Fixes: #70) - - Workaround for rsync on SUSE Linux (Closes: #13 and #26) - - Disables dangerous settings in postgresql.auto.conf - (Closes: #68) - -Version 1.4.1 - 05 May 2015 - -* Fix for WAL archival stop working if first backup is EMPTY - (Closes: #64) -* Fix exception during error handling in Barman recovery - (Closes: #65) -* After a backup, limit cron activity to WAL archiving only - (Closes: #62) -* Improved robustness and error reporting of the backup delete - command (Closes: #63) -* Fix computation of WAL production ratio as reported in the - show-backup command -* Improved management of xlogdb file, which is now correctly fsynced - when updated. Also, the rebuild-xlogdb command now operates on a - temporary new file, which overwrites the main one when finished. -* Add unit tests for dateutil module compatibility -* Modified Barman version following PEP 440 rules and added support - of tests in Python 3.4 - -Version 1.4.0 - 26 Jan 2015 - -* Incremental base backup implementation through the reuse_backup - global/server option. Possible values are off (disabled, - default), copy (preventing unmodified files from being - transferred) and link (allowing for deduplication through hard - links). -* Store and show deduplication effects when using reuse_backup= - link. -* Added transparent support of pg_stat_archiver (PostgreSQL 9.4) in - check, show-server and status commands. -* Improved administration by invoking WAL maintenance at the end of - a successful backup. -* Changed the way unused WAL files are trashed, by differentiating - between concurrent and exclusive backup cases. -* Improved performance of WAL statistics calculation. -* Treat a missing pg_ident.conf as a WARNING rather than an error. -* Refactored output layer by removing remaining yield calls. -* Check that rsync is in the system path. -* Include history files in WAL management. -* Improved robustness through more unit tests. -* Fixed bug #55: Ignore fsync EINVAL errors on directories. -* Fixed bug #58: retention policies delete. - -Version 1.3.3 - 21 Aug 2014 - -* Added "last_backup_max_age", a new global/server option that - allows administrators to set the max age of the last backup in a - catalogue, making it easier to detect any issues with periodical - backup execution -* Improved robustness of "barman backup" by introducing two global/ - server options: "basebackup_retry_times" and - "basebackup_retry_sleep". These options allow an administrator to - specify, respectively, the number of attempts for a copy - operation after a failure, and the number of seconds of wait - before retrying -* Improved the recovery process via rsync on an existing directory - (incremental recovery), by splitting the previous rsync call into - several ones - invoking checksum control only when necessary -* Added support for PostgreSQL 8.3 -* Minor changes: - - + Support for comma separated list values configuration options - + Improved backup durability by calling fsync() on backup and - WAL files during "barman backup" and "barman cron" - + Improved Nagios output for "barman check --nagios" - + Display compression ratio for WALs in "barman show-backup" - + Correctly handled keyboard interruption (CTRL-C) while - performing barman backup - + Improved error messages of failures regarding the stop of a - backup - + Wider coverage of unit tests -* Bug fixes: - - + Copies "recovery.conf" on the remote server during "barman - recover" (#45) - + Correctly detect pre/post archive hook scripts (#41) - -Version 1.3.2 - 15 Apr 2014 - -* Fixed incompatibility with PostgreSQL 8.4 (Closes #40, bug - introduced in version 1.3.1) - -Version 1.3.1 - 14 Apr 2014 - -* Added support for concurrent backup of PostgreSQL 9.2 and 9.3 - servers that use the "pgespresso" extension. This feature is - controlled by the "backup_options" configuration option (global/ - server) and activated when set to "concurrent_backup". Concurrent - backup allows DBAs to perform full backup operations from a - streaming replicated standby. -* Added the "barman diagnose" command which prints important - information about the Barman system (extremely useful for support - and problem solving) -* Improved error messages and exception handling interface -* Fixed bug in recovery of tablespaces that are created inside the - PGDATA directory (bug introduced in version 1.3.0) -* Fixed minor bug of unhandled -q option, for quiet mode of - commands to be used in cron jobs (bug introduced in version - 1.3.0) -* Minor bug fixes and code refactoring - -Version 1.3.0 - 3 Feb 2014 - -* Refactored BackupInfo class for backup metadata to use the new - FieldListFile class (infofile module) - -* Refactored output layer to use a dedicated module, in order to - facilitate integration with Nagios (NagiosOutputWriter class) - -* Refactored subprocess handling in order to isolate stdin/stderr/ - stdout channels (command_wrappers module) - -* Refactored hook scripts management - -* Extracted logging configuration and userid enforcement from the - configuration class. - -* Support for hook scripts to be executed before and after a WAL - file is archived, through the 'pre_archive_script' and - 'post_archive_script' configuration options. - -* Implemented immediate checkpoint capability with - --immediate-checkpoint command option and 'immediate_checkpoint' - configuration option - -* Implemented network compression for remote backup and recovery - through the 'network_compression' configuration option (#19) - -* Implemented the 'rebuild-xlogdb' command (Closes #27 and #28) - -* Added deduplication of tablespaces located inside the PGDATA - directory - -* Refactored remote recovery code to work the same way local - recovery does, by performing remote directory preparation - (assuming the remote user has the right permissions on the remote - server) - -* 'barman backup' now tries and create server directories before - attempting to execute a full backup (#14) - -* Fixed bug #22: improved documentation for tablespaces relocation - -* Fixed bug #31: 'barman cron' checks directory permissions for - lock file - -* Fixed bug #32: xlog.db read access during cron activities - -Version 1.2.3 - 5 September 2013 - -* Added support for PostgreSQL 9.3 - -* Added support for the "--target-name" recovery option, which allows to - restore to a named point previously specified with pg_create_restore_point - (only for PostgreSQL 9.1 and above users) - -* Fixed bug #27 about flock() usage with barman.lockfile (many thanks to - Damon Snyder ) - -* Introduced Python 3 compatibility - -Version 1.2.2 - 24 June 2013 - -* Fix python 2.6 compatibility - -Version 1.2.1 - 17 June 2013 - -* Added the "bandwidth_limit" global/server option which allows - to limit the I/O bandwidth (in KBPS) for backup and recovery operations - -* Added the "tablespace_bandwidth_limit" global/server option which allows - to limit the I/O bandwidth (in KBPS) for backup and recovery operations - on a per tablespace basis - -* Added /etc/barman/barman.conf as default location - -* Bug fix: avoid triggering the minimum_redundancy check - on FAILED backups (thanks to Jérôme Vanandruel) - -Version 1.2.0 - 31 Jan 2013 - -* Added the "retention_policy_mode" global/server option which defines - the method for enforcing retention policies (currently only "auto") - -* Added the "minimum_redundancy" global/server option which defines - the minimum number of backups to be kept for a server - -* Added the "retention_policy" global/server option which defines - retention policies management based on redundancy (e.g. REDUNDANCY 4) - or recovery window (e.g. RECOVERY WINDOW OF 3 MONTHS) - -* Added retention policy support to the logging infrastructure, the - "check" and the "status" commands - -* The "check" command now integrates minimum redundancy control - -* Added retention policy states (valid, obsolete and potentially obsolete) - to "show-backup" and "list-backup" commands - -* The 'all' keyword is now forbidden as server name - -* Added basic support for Nagios plugin output to the 'check' - command through the --nagios option - -* Barman now requires argh => 0.21.2 and argcomplete- - -* Minor bug fixes - -Version 1.1.2 - 29 Nov 2012 - -* Added "configuration_files_directory" option that allows - to include multiple server configuration files from a directory - -* Support for special backup IDs: latest, last, oldest, first - -* Management of multiple servers to the 'list-backup' command. - 'barman list-backup all' now list backups for all the configured servers. - -* Added "application_name" management for PostgreSQL >= 9.0 - -* Fixed bug #18: ignore missing WAL files if not found during delete - -Version 1.1.1 - 16 Oct 2012 - -* Fix regressions in recover command. - -Version 1.1.0 - 12 Oct 2012 - -* Support for hook scripts to be executed before and after - a 'backup' command through the 'pre_backup_script' and 'post_backup_script' - configuration options. - -* Management of multiple servers to the 'backup' command. - 'barman backup all' now iteratively backs up all the configured servers. - -* Fixed bug #9: "9.2 issue with pg_tablespace_location()" - -* Add warning in recovery when file location options have been defined - in the postgresql.conf file (issue #10) - -* Fail fast on recover command if the destination directory contains - the ':' character (Closes: #4) or if an invalid tablespace - relocation rule is passed - -* Report an informative message when pg_start_backup() invocation - fails because an exclusive backup is already running (Closes: #8) - -Version 1.0.0 - 6 July 2012 - -* Backup of multiple PostgreSQL servers, with different versions. Versions - from PostgreSQL 8.4+ are supported. - -* Support for secure remote backup (through SSH) - -* Management of a catalog of backups for every server, allowing users - to easily create new backups, delete old ones or restore them - -* Compression of WAL files that can be configured on a per server - basis using compression/decompression filters, both predefined (gzip - and bzip2) or custom - -* Support for INI configuration file with global and per-server directives. - Default location for configuration files are /etc/barman.conf or - ~/.barman.conf. The '-c' option allows users to specify a different one - -* Simple indexing of base backups and WAL segments that does not require - a local database - -* Maintenance mode (invoked through the 'cron' command) which performs - ordinary operations such as WAL archival and compression, catalog - updates, etc. - -* Added the 'backup' command which takes a full physical base backup - of the given PostgreSQL server configured in Barman - -* Added the 'recover' command which performs local recovery of a given - backup, allowing DBAs to specify a point in time. The 'recover' command - supports relocation of both the PGDATA directory and, where applicable, - the tablespaces - -* Added the '--remote-ssh-command' option to the 'recover' command for - remote recovery of a backup. Remote recovery does not currently support - relocation of tablespaces - -* Added the 'list-server' command that lists all the active servers - that have been configured in barman - -* Added the 'show-server' command that shows the relevant information - for a given server, including all configuration options - -* Added the 'status' command which shows information about the current - state of a server, including Postgres version, current transaction ID, - archive command, etc. - -* Added the 'check' command which returns 0 if everything Barman needs - is functioning correctly - -* Added the 'list-backup' command that lists all the available backups - for a given server, including size of the base backup and total size - of the related WAL segments - -* Added the 'show-backup' command that shows the relevant information - for a given backup, including time of start, size, number of related - WAL segments and their size, etc. - -* Added the 'delete' command which removes a backup from the catalog - -* Added the 'list-files' command which lists all the files for a - single backup - -* RPM Package for RHEL 5/6 diff --git a/README.rst b/README.rst index bf9e59cce..6b827517d 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ Barman: - LICENSE : GNU GPL3 details - TODO : our wishlist for Barman - barman : sources in Python -- doc : tutorial and man pages +- docs : tutorial and man pages - scripts : auxiliary scripts - tests : unit tests @@ -36,8 +36,6 @@ Web resources - Website : http://www.pgbarman.org/ - Download : http://github.com/EnterpriseDB/barman - Documentation : http://www.pgbarman.org/documentation/ -- Man page, section 1 : http://docs.pgbarman.org/barman.1.html -- Man page, section 5 : http://docs.pgbarman.org/barman.5.html - Community support : http://www.pgbarman.org/support/ - Professional support : https://www.enterprisedb.com/ - pre barman 2.13 versions : https://sourceforge.net/projects/pgbarman/files/ diff --git a/RELNOTES.md b/RELNOTES.md new file mode 100644 index 000000000..dc431e0c7 --- /dev/null +++ b/RELNOTES.md @@ -0,0 +1,2047 @@ +# Barman release notes + +© Copyright EnterpriseDB UK Limited 2024 - All rights reserved. + +## 3.12.0 (2024-11-21) + +### Minor changes + +- Add FIPS support to Barman + + The `md5` hash algorithm is not FIPS compliant, so it is going to be replaced by + `sha256`. `sha256` is FIPS compliant, vastly used, and is considered secure for most + practical purposes. + Up until this release, Barman's WAL archive client used `hashlib.md5` to generate + checksums for tar files before they were sent to the Barman server. Here, a tar file is + a file format used for bundling multiple files together with a `MD5SUMS` file that lists + the checksums and their corresponding paths. + In this release, the `md5` hashing algorithm is replaced by `sha256` as the default. + As a result, checksums for the tar files will be calculated using `sha256`, and the + `MD5SUMS` file will be named `SHA256SUMS`. Barman still has the ability to use the + nondefault `md5` algorithm and the `MD5SUMS` file from the client if there is a use + case for it. The user just needs to add the `--md5` flag to the `barman-wal-archive` + `archive_command`. + + References: BAR-155, CP-34954, CP-34391. + +- Removed el7, debian10, and ubuntu1804 support; updated Debian and SLES. + + Support for el7, debian10, and ubuntu1804 has been removed. Additionally, version 12 + and version name "bookworm" has been added for Debian, addressing a previously + missing entry. The SLES image version has also been updated from sp4 to sp5. + + References: BAR-389. + +- Add support for Postgres Extended 17 (PGE) and Postgres Advanced Server 17 (EPAS) + + Tests were conducted on Postgres Extended 17 (PGE) and Postgres Advanced Server 17 + (EPAS), confirming full compatibility with the latest features in Barman. This + validation ensures that users of the latest version of PGE and EPAS can leverage all the new + capabilities of Barman with confidence. + + References: BAR-331. + +- Improve WAL compression with `zstd`, `lz4` and `xz` algorithms + + Introduced support for xz compression on WAL files. It can be enabled by specifying + `xz` in the `compression` server parameter. WALs will be compressed when entering + the Barman's WAL archive. For the cloud, it can be enabled by specifying `--xz` + when running `barman-cloud-wal-archive`. + + Introduced support for zstandard compression on WAL files. It can be enabled by + specifying `zstd` in the `compression` server parameter. WALs will be compressed + when entering the Barman's WAL archive. For the cloud, it can be enabled by + specifying `--zstd` when running `barman-cloud-wal-archive`. + + Introduced support for lz4 compression on WAL files. It can be enabled by + specifying `lz4` in the `compression` server parameter. WALs will be compressed + when entering the Barman's WAL archive. For the cloud, it can be enabled by + specifying `--lz4` when running `barman-cloud-wal-archive`. + + References: BAR-265, BAR-423, BAR-264. + +- Improve WAL upload performance on S3 buckets by avoiding multipart uploads + + Previously, WAL files were being uploaded to S3 buckets using multipart uploads + provided by the boto3 library via the `upload_fileobj` method. It was noticed that + multipart upload is slower when used for small files, such as WAL segments, + compared to when uploading it in a single PUT request. + This has been improved by avoiding multipart uploads for files smaller than 100MB. + The average upload time of each WAL file is expected to be reduced by around 15% + with this change. + + References: BAR-374. + +- Modify behavior when enforcing retention policy for `KEEP:STANDALONE` full backups + + When enforcing the retention policy on full backups created with + `backup_method = postgres`, Barman was previously marking all dependent (child) + incremental backups as `VALID`, regardless of the KEEP target used. However, this + approach is incorrect: + + - For backups labeled `KEEP:STANDALONE`, Barman only retains the WAL files needed to + restore the server to the exact state of that backup. Because these backups are + self-contained, any dependent child backups are no longer needed once the root + backup is outside the retention policy. + + - In contrast, backups marked `KEEP:FULL` are intended for point-in-time recovery. + To support this, Barman retains all WALs, as well as any child backups, to ensure + the backup's consistency and allow recovery to the latest possible point. + + This distinction ensures that `KEEP:STANDALONE` backups serve as snapshots of a + specific moment, while `KEEP:FULL` backups retain everything needed for full + point-in-time recovery. + + References: BAR-366. + +- Update documentation and user-facing features for Barman's recovery process. + + Barman docs and the tool itself used to use the terms "recover"/"recovery" both for + referencing: + + - The Postgres recovery process; + - The process of restoring a backup and preparing it for recovery. + + Both the code and documentation have been revised to accurately reflect the usage of + the terms "restore" and "recover"/"recovery". + + Also, the `barman recover` command was renamed to `barman restore`. The old name is + still kept as an alias for backward compatibility. + + References: BAR-337. + +- Add --keep-compression flag to barman-wal-restore and get-wal + + A new `--keep-compression` option has been added to both `barman-wal-restore` and + `get-wal`. This option controls whether compressed WAL files should be decompressed + on the Barman server before being fetched. When specified with `get-wal`, default + decompression is skipped, and the output is the WAL file content in its original + state. When specified with `barman-wal-restore`, the WAL file is fetched as-is and, + if compressed, decompressed on the client side. + + References: BAR-435. + +- Ransomware protection - Add AWS Snapshot Lock Support + + Barman now supports AWS EBS Snapshot Lock, a new integrated feature to prevent + accidental or malicious deletions of Amazon EBS snapshots. When a snapshot is + locked, it can't be deleted by any user but remains fully accessible for use. This + feature enables you to store snapshots in WORM (Write-Once-Read-Many) format for a + specified duration, helping to meet regulatory requirements by keeping the data + secure and tamper-proof until the lock expires. + + Special thanks to Rui Marinho, our community contributor who started this feature. + + References: BAR-242. + +- Prevent orphan files from being left from a crash while deleting a backup + + This commit fixes an issue where backups could leave behind files if the system + crashed during the deletion of a backup. + + Now, when a backup is deleted, it will get a "delete marker" at the start. + If a crash happens while the backup is being deleted, the marker will help + recognize incomplete backup removals when the server restarts. + + The Barman cron job has been updated to look for these deleted markers. If it finds + a backup with a "delete marker", it will complete the process. + + References: BAR-244. + +- Add support for using tags with snapshots + + Barman now supports tagging the snapshots when creating backups using the + barman-cloud-backup script command. A new argument called --tags was added. + + Special thanks to Rui Marinho, our community contributor who started this feature. + + References: BAR-417. + +### Bugfixes + +- Fix barman check which returns wrong results for Replication Slot + + Previously, when using architectures which backup from a standby node and stream WALs + from the primary, Barman would incorrectly use `conninfo` (pointing to a standby server) + for replication checks, leading to errors such as: + + `replication slot (WAL streaming): FAILED (replication slot 'barman' doesn't exist. + Please execute 'barman receive-wal --create-slot pg17')` + + This fixes the following issue + [#1024](https://github.com/EnterpriseDB/barman/issues/1024) by ensuring + `wal_conninfo` is used for WAL replication checks if it's set. + + `wal_conninfo` takes precedence over `wal_streaming_conninfo`, when both are set. + With this change, if only `wal_conninfo` is set, it will be used and will not fall + back to `conninfo`. + + Also, in the documentation, changes were made so it is explicit that when `conninfo` + points to a standby server, `wal_conninfo` must be set and used for accurate + replication status checks. + + References: BAR-409. + +- Fix missing options for `barman keep` + + The error message that the Barman CLI emitted when running `barman keep` + without any options suggested there were shortcut aliases for status and + release. These aliases, -s and -r, do not exist, so the error message was + misleading. + This fixes the issue by including these short options in the Barman CLI, + aligning it with other tools like `barman-cloud-backup-keep`, where these + shortcuts already exist. + + References: BAR-356. + +- Lighten standby checks related to conninfo and primary_conninfo + + When backing up a standby server, Barman performs some checks to assert + that `conninfo` is really pointing to a standby (in recovery mode) and + that `primary_conninfo` is pointing to a primary (not in recovery). + + The problem, as reported in the issues #704 and #744, is that when a + failover occurs, the `conninfo` will now be pointing to a primary + instead and the checks will start failing, requiring the user to change + Barman configs manually whenever a failover occurs. + + This fix solved the issue by making such checks non-critical, which + means they will still fail but Barman will keep operating regardless. + Essentially, Barman will ignore `primary_conninfo` if `conninfo` does + not point to a standby. Warnings about this misconfiguration will also + be emitted whenever running any Barman command so the user can be aware. + + References: BAR-348. + +## 3.11.1 (2024-08-22) + +### Bugfixes + +- Fix failures in `barman-cloud-backup-delete`. This command was failing when + applying retention policies due to a bug introduced by the previous release. + +## 3.11.0 (2024-08-22) + +### Notable changes + +- Add support for Postgres 17+ incremental backups. This major feature is + composed of several small changes: + + - Add `--incremental` command-line option to `barman backup` command. This is + used to specify the parent backup when taking an incremental backup. The + parent can be either a full backup or another incremental backup. + + - Add `latest-full` shortcut backup ID. Along with `latest`, this can be used + as a shortcut to select the parent backup for an incremental backup. While + `latest` takes the latest backup independently if it is full or incremental, + `latest-full` takes the latest full backup. + + - `barman keep` command can only be applied to full backups when + `backup_method = postgres`. + + - Retention policies do not take incremental backups into consideration. As + incremental backups cannot be recovered without having the complete chain of + backups available up to the full backup, only full backups account for + retention policies. If a full backup has dependent incremental backups and the + retention policy is applied, the full backup will propagate its status to the + associated incremental backups. When the full backup is flagged with any `KEEP` + target, Barman will set the status of all related incremental backups to `VALID`. + + - When deleting a backup all the incremental backups depending on it, if any, + are also removed. + + - `barman recover` needs to combine the full backup with the chain of incremental + backups when recovering. The new CLI option `--local-staging-path`, and the + corresponding `local_staging_path` configuration option, are used to specify + the path in the Barman host where the backups will be combined when recovering + an incremental backup. + +- Changes to `barman show-backup` output: + + - Add the “Estimated cluster size” field. It's useful to have an estimation + of the data directory size of a cluster when restoring a backup. It’s + particularly useful when recovering compressed backups or incremental + backups, situations where the size of the backup doesn’t reflect the size of the + data directory in Postgres. In JSON format, this is stored as + `cluster_size`. + + - Add the “WAL summarizer” field. This field shows if `summarize_wal` was + enabled in Postgres at the time the backup was taken. In JSON format, this + is stored as `server_information.summarize_wal`. This field is omitted for + Postgres 16 and older. + + - Add “Data checksums” field. This shows if `data_checkums` was enabled in + Postgres at the time the backup was taken. In JSON format, this is stored as + `server_information.data_checksums`. + + - Add the “Backup method” field. This shows the backup method used for this + backup. In JSON format, this is stored as + `base_backup_information.backup_method`. + + - Rename the field “Disk Usage” as “Backup Size”. The latter provides a more + comprehensive name which represents the size of the backup in the Barman + host. The JSON field under `base_backup_information` was also renamed from + `disk_usage` to `backup_size`. + + - Add the “WAL size” field. This shows the size of the WALs required by the + backup. In JSON format, this is stored as + `base_backup_information.wal_size`. + + - Refactor the field “Incremental size”. It is now named “Resources saving” + and it now shows an estimation of resources saved when taking incremental + backups with `rsync` or `pg_basebackup`. It compares the backup size with + the estimated cluster size to estimate the amount of disk and network + resources that were saved by taking an incremental backup. In JSON format, + the field was renamed from `incremental_size` to `resource_savings` under + `base_backup_information`. + + - Add the `system_id` field to the JSON document. This field contains the + system identifier of Postgres. It was present in console format, but was + missing in JSON format. + + - Add fields related with Postgres incremental backups: + + - “Backup type”: indicates if the Postgres backup is full or incremental. In + JSON format, this is stored as `backup_type` under `base_backup_information`. + + - “Root backup”: the ID of the full backup that is the root of a chain of + one or more incremental backups. In JSON format, this is stored as + `catalog_information.root_backup_id`. + + - “Parent backup”: the ID of the full or incremental backup from which this + incremental backup was taken. In JSON format, this is stored as + `catalog_information.parent_backup_id`. + + - “Children Backup(s)”: the IDs of the incremental backups that were taken + with this backup as the parent. In JSON format, this is stored as + `catalog_information.children_backup_ids`. + + - “Backup chain size”: the number of backups in the chain from this + incremental backup up to the root backup. In JSON format, this is + stored as `catalog_information.chain_size`. + +- Changes to `barman list-backup` output: + + - It now includes the backup type in the JSON output, which can be either + `rsync` for backups taken with rsync, `full` or `incremental` for backups + taken with `pg_basebackup`, or `snapshot` for cloud snapshots. When printing + to the console the backup type is represented by the corresponding labels + `R`, `F`, `I` or `S`. + + - Remove tablespaces information from the output. That was bloating the + output. Tablespaces information can still be found in the output of + `barman show-backup`. + +- Always set a timestamp with a time zone when configuring + `recovery_target_time` through `barman recover`. Previously, if no time zone + was explicitly set through `--target-time`, Barman would configure + `recovery_target_time` without a time zone in Postgres. Without a time zone, + Postgres would assume whatever is configured through `timezone` GUC in + Postgres. From now on Barman will issue a warning and configure + `recovery_target_time` with the time zone of the Barman host if no time zone + is set by the user through `--target-time` option. + +- When recovering a backup with the “no get wal” approach and `--target-lsn` is set, + copy only the WAL files required to reach the configured target. Previously + Barman would copy all the WAL files from its archive to Postgres. + +- When recovering a backup with the “no get wal” approach and `--target-immediate` + is set, copy only the WAL files required to reach the consistent point. + Previously Barman would copy all the WAL files from its archive to Postgres. + +- `barman-wal-restore` now moves WALs from the spool directory to `pg_wal` + instead of copying them. This can improve performance if the spool directory + and the `pg_wal` directory are in the same partition. + +- `barman check-backup` now shows the reason why a backup was marked as `FAILED` + in the output and logs. Previously for a user to know why the backup was + marked as `FAILED`, they would need to run `barman show-backup` command. + +- Add configuration option `aws_await_snapshots_timeout` and the corresponding + `--aws-await-snapshots-timeout` command-line option on `barman-cloud-backup`. + This specifies the timeout in seconds to wait for snapshot backups to reach + the completed state. + +- Add a keep-alive mechanism to rsync-based backups. Previously the Postgres + session created by Barman to run `pg_backup_start()` and `pg_backup_stop()` would + stay idle for as long as the base backup copy would take. That could lead to a + firewall or router dropping the connection because it was idle for a long + time. The keep-alive mechanism sends heartbeat queries to Postgres + through that connection, thus reducing the likelihood of a connection + getting dropped. The interval between heartbeats can be controlled through the new + configuration option `keepalive_interval` and the corresponding CLI + option `--keepalive-interval` of the `barman backup` command. + +### Bugfixes + +- When recovering a backup with the “no get wal” approach and `--target-time` + set, copy all WAL files. Previously Barman would attempt to “guess” the WAL + files required by Postgres to reach the configured target time. However, + the mechanism was not robust enough as it was based on the stats of the WAL + file in the Barman host (more specifically the creation time). For example: + if there were archiving or streaming lag between Postgres and Barman, that + could be enough for recovery to fail because Barman would miss to copy all + the required WAL files due to the weak check based on file stats. + +- Pin `python-snappy` to `0.6.1` when running Barman through Python 3.6 or +older. Newer versions of `python-snappy` require `cramjam` version `2.7.0` or +newer, and these are only available for Python 3.7 or newer. + +- `barman receive-wal` now exits with code `1` instead of `0` in the following + cases: + + - Being unable to run with `--reset` flag because `pg_receivewal` is + running. + + - Being unable to start `pg_receivewal` process because it is already + running. + +- Fix and improve information about Python in `barman diagnose` output: + + - The command now makes sure to use the same Python interpreter under which + Barman is installed when outputting the Python version through + `python_ver` JSON key. Previously, if an environment had multiple Python + installations and/or virtual environments, the output could eventually be + misleading, as it could be fetched from a different Python interpreter. + + - Added a `python_executable` key to the JSON output. That contains the path + to the exact Python interpreter being used by Barman. + +## 3.10.1 (2024-06-12) + +### Bugfixes + +- Make `argcomplete` optional to avoid installation issues on some + platforms. +- Load `barman.auto.conf` only when the file exists. +- Emit a warning when the `cfg_changes.queue` file is malformed. +- Correct in documentation the postgresql version where + `pg_checkpoint` is available. +- Add `--no-partial` option to `barman-cloud-wal-restore`. + +## 3.10.0 (2024-01-24) + +### Notable changes + +- Limit the average bandwidth used by `barman-cloud-backup` when backing + up to either AWS S3 or Azure Blob Storage according to the value set by + a new CLI option `--max-bandwidth`. + +- Add the new configuration option `lock_directory_cleanup` + That enables cron to automatically clean up the barman_lock_directory + from unused lock files. + +- Add support for a new type of configuration called `model`. + The model acts as a set of overrides for configuration options + for a given Barman server. + +- Add a new barman command `barman config-update` that allows the creation + and the update of configurations using JSON + +### Bugfixes + +- Fix a bug that caused `--min-chunk-size` to be ignored when using + barman-cloud-backup as hook script in Barman. + +## 3.9.0 (2023-10-03) + +### Notable changes + +- Allow `barman switch-wal --force` to be run against PG>=14 if the + user has the `pg_checkpoint` role (thanks to toydarian for this patch). + +- Log the current check at `info` level when a check timeout occurs. + +- The minimum size of an upload chunk when using `barman-cloud-backup` + with either S3 or Azure Blob Storage can now be specified using the + `--min-chunk-size` option. + +- `backup_compression = none` is supported when using `pg_basebackup`. + +- For PostgreSQL 15 and later: the allowed `backup_compression_level` + values for `zstd` and `lz4` have been updated to match those allowed by + `pg_basebackup`. + +- For PostgreSQL versions earlier than 15: `backup_compression_level = 0` + can now be used with `backup_compression = gzip`. + +### Bugfixes + +- Fix `barman recover` on platforms where Multiprocessing uses spawn by + default when starting new processes. + +## 3.8.0 (2023-08-31) + +### Notable changes + +- Clarify package installation. barman is packaged with default python version + for each operating system. + +- The `minimum-redundancy` option is added to `barman-cloud-backup-delete`. + It allows to set the minimum number of backups that should always be available. + +- Add a new `primary_checkpoint_timeout` configuration option. Allows define + the amount of seconds that Barman will wait at the end of a backup if no + new WAL files are produced, before forcing a checkpoint on the primary server. + +### Bugfixes + +- Fix race condition in barman retention policies application. Backup + deletions will now raise a warning if another deletion is in progress + for the requested backup. + +- Fix `barman-cloud-backup-show` man page installation. + +## 3.7.0 (2023-07-25) + +### Notable changes + +- Support is added for snapshot backups on AWS using EBS volumes. + +- The `--profile` option in the `barman-cloud-*` scripts is renamed + `--aws-profile`. The old name is deprecated and will be removed in + a future release. + +- Backup manifests can now be generated automatically on completion + of a backup made with `backup_method = rsync`. This is enabled by + setting the `autogenerate_manifest` configuration variable and can + be overridden using the `--manifest` and `--no-manifest` CLI options. + +### Bugfixes + +- The `barman-cloud-*` scripts now correctly use continuation + tokens to page through objects in AWS S3-compatible object + stores. This fixes a bug where `barman-cloud-backup-delete` + would only delete the oldest 1000 eligible WALs after backup + deletion. + +- Minor documentation fixes. + +## 3.6.0 (2023-06-15) + +### Notable changes + +- PostgreSQL version 10 is no longer supported. + +- Support is added for snapshot backups on Microsoft Azure using + Managed Disks. + +- The `--snapshot-recovery-zone` option is renamed `--gcp-zone` for + consistency with other provider-specific options. The old name + is deprecated and will be removed in a future release. + +- The `snapshot_zone` option and `--snapshot-zone` argument are + renamed `gcp_zone` and `--gcp-zone` respectively. The old names + are deprecated and will be removed in a future release. + +- The `snapshot_gcp_project` option and `--snapshot-gcp-project` + argument are renamed to `gcp_project` and `--gcp-project`. The + old names are deprecated and will be removed in a future release. + +### Bugfixes + +- Barman will no longer attempt to execute the `replication-status` + command for a passive node. + +- The `backup_label` is deleted from cloud storage when a + snapshot backup is deleted with `barman-cloud-backup-delete`. + +- Man pages for the `generate-manifest` and `verify-backup` + commands are added. + +- Minor documentation fixes. + +## 3.5.0 (2023-03-29) + +### Notable changes + +- Python 2.7 is no longer supported. The earliest Python version + supported is now 3.6. + +- The `barman`, `barman-cli` and `barman-cli-cloud` packages for + EL7 now require python 3.6 instead of python 2.7. For other + supported platforms, Barman packages already require python + versions 3.6 or later so packaging is unaffected. + +- Support for PostgreSQL 10 will be discontinued in future Barman + releases; 3.5.x is the last version of Barman with support for + PostgreSQL 10. + +- Backups and WALs uploaded to Google Cloud Storage can now be + encrypted using a specific KMS key by using the `--kms-key-name` + option with `barman-cloud-backup` or `barman-cloud-wal-archive`. + +- Backups and WALs uploaded to AWS S3 can now be encrypted using a + specific KMS key by using the `--sse-kms-key-id` option with + `barman-cloud-backup` or `barman-cloud-wal-archive` along with + `--encryption=aws:kms`. + +- Two new configuration options are provided which make it possible + to limit the rate at which parallel workers are started during + backups with `backup_method = rsync` and recoveries. + `parallel_jobs_start_batch_size` can be set to limit the amount of + parallel workers which will be started in a single batch, and + `parallel_jobs_start_batch_period` can be set to define the time + in seconds over which a single batch of workers will be started. + These can be overridden using the arguments `--jobs-start-batch-size` + and `--jobs-start-batch-period` with the `barman backup` and + `barman recover` commands. + +- A new option `--recovery-conf-filename` is added to `barman recover`. + This can be used to change the file to which Barman should write the + PostgreSQL recovery options from the default `postgresql.auto.conf` + to an alternative location. + +### Bugfixes + +- Fix a bug which prevented `barman-cloud-backup-show` from + displaying the backup metadata for backups made with + `barman backup` and uploaded by `barman-cloud-backup` as a + post-backup hook script. + +- Fix a bug where the PostgreSQL connection used to validate backup + compression settings was left open until termination of the + Barman command. + +- Fix an issue which caused rsync-concurrent backups to fail when + running for a duration greater than `idle_session_timeout`. + +- Fix a bug where the backup name was not saved in the backup + metadata if the `--wait` flag was used with `barman backup`. + +- Thanks to mojtabash78, mhkarimi1383, epolkerman, barthisrael and + hzetters for their contributions. + +## 3.4.0 (2023-01-26) + +### Notable changes + +- This is the last release of Barman which will support Python 2 and + new features will henceforth require Python 3.6 or later. + +- A new `backup_method` named `snapshot` is added. This will create + backups by taking snapshots of cloud storage volumes. Currently + only Google Cloud Platform is supported however support for AWS + and Azure will follow in future Barman releases. Note that this + feature requires a minimum Python version of 3.7. Please see the + Barman manual for more information. + +- Support for snapshot backups is also added to `barman-cloud-backup`, + with minimal support for restoring a snapshot backup added to + `barman-cloud-restore`. + +- A new command `barman-cloud-backup-show` is added which displays + backup metadata stored in cloud object storage and is analogous to + `barman show-backup`. This is provided so that snapshot metadata + can be easily retrieved at restore time however it is also a + convenient way of inspecting metadata for any backup made with + `barman-cloud-backup`. + +- The instructions for installing Barman from RPMs in the docs are + updated. + +- The formatting of NFS requirements in the docs is fixed. + +- Supported PostgreSQL versions are updated in the docs (this is a + documentation fix only - the minimum supported major version is + still 10). + +## 3.3.0 (2022-12-14) + +### Notable changes + +- A backup can now be given a name at backup time using the new + `--name` option supported by the `barman backup` and + `barman-cloud-backup` commands. The backup name can then be used + in place of the backup ID when running commands to interact with + backups. Additionally, the commands to list and show backups have + been been updated to include the backup name in the plain text and + JSON output formats. + +- Stricter checking of PostgreSQL version to verify that Barman is + running against a supported version of PostgreSQL. + +### Bugfixes + +- Fix inconsistencies between the barman cloud command docs and + the help output for those commands. + +- Use a new PostgreSQL connection when switching WALs on the + primary during the backup of a standby to avoid undefined + behaviour such as `SSL error` messages and failed connections. + +- Reduce log volume by changing the default log level of stdout + for commands executed in child processes to `DEBUG` (with the + exception of `pg_basebackup` which is deliberately logged at + `INFO` level due to it being a long-running process where it is + frequently useful to see the output during the execution of the + command). + +## 3.2.0 (2022-10-20) + +### Notable changes + +- `barman-cloud-backup-delete` now accepts a `--batch-size` option + which determines the maximum number of objects deleted in a single + request. + +- All `barman-cloud-*` commands now accept a `--read-timeout` option + which, when used with the `aws-s3` cloud provider, determines the + read timeout used by the boto3 library when making requests to S3. + +### Bugfixes + +- Fix the failure of `barman recover` in cases where + `backup_compression` is set in the Barman configuration but the + PostgreSQL server is unavailable. + +## 3.1.0 (2022-09-14) + +### Notable changes + +- Backups taken with `backup_method = postgres` can now be compressed + using lz4 and zstd compression by setting `backup_compression = lz4` + or `backup_compression = zstd` respectively. These options are only + supported with PostgreSQL 15 (beta) or later. + +- A new option `backup_compression_workers` is available which sets + the number of threads used for parallel compression. This is + currently only available with `backup_method = postgres` and + `backup_compression = zstd`. + +- A new option `primary_conninfo` can be set to avoid the need for + backups of standbys to wait for a WAL switch to occur on the primary + when finalizing the backup. Barman will use the connection string + in `primary_conninfo` to perform WAL switches on the primary when + stopping the backup. + +- Support for certain Rsync versions patched for CVE-2022-29154 which + require a trailing newline in the `--files-from` argument. + +- Allow `barman receive-wal` maintenance options (`--stop`, `--reset`, + `--drop-slot` and `--create-slot`) to run against inactive servers. + +- Add `--port` option to `barman-wal-archive` and `barman-wal-restore` + commands so that a custom SSH port can be used without requiring any + SSH configuration. + +- Various documentation improvements. + +- Python 3.5 is no longer supported. + +### Bugfixes + +- Ensure PostgreSQL connections are closed cleanly during the + execution of `barman cron`. + +- `barman generate-manifest` now treats pre-existing + backup_manifest files as an error condition. + +- backup_manifest files are renamed by appending the backup ID + during recovery operations to prevent future backups including + an old backup_manifest file. + +- Fix epoch timestamps in json output which were not + timezone-aware. + +- The output of `pg_basebackup` is now written to the Barman + log file while the backup is in progress. + +- We thank barthisrael, elhananjair, kraynopp, lucianobotti, and mxey + for their contributions to this release. + +## 3.0.1 (2022-06-27) + +### Bugfixes + +- Fix package signing issue in PyPI (same sources as 3.0.0) + +## 3.0.0 (2022-06-23) + +### Breaking changes + +- PostgreSQL versions 9.6 and earlier are no longer + supported. If you are using one of these versions you will need to + use an earlier version of Barman. + +- The default backup mode for Rsync backups is now + concurrent rather than exclusive. Exclusive backups have been + deprecated since PostgreSQL 9.6 and have been removed in PostgreSQL + 15. If you are running Barman against PostgreSQL versions earlier + than 15 and want to use exclusive backups you will now need to set + `exclusive_backup` in `backup_options`. + +- The backup metadata stored in the `backup.info` file + for each backup has an extra field. This means that earlier versions + of Barman will not work in the presence of any backups taken with + 3.0.0. Additionally, users of pg-backup-api will need to upgrade it + to version 0.2.0 so that pg-backup-api can work with the updated + metadata. + +### Notable changes + +- Backups taken with `backup_method = postgres` can now be compressed + by pg_basebackup by setting the `backup_compression` config option. + Additional options are provided to control the compression level, + the backup format and whether the pg_basebackup client or the + PostgreSQL server applies the compression. NOTE: Recovery of these + backups requires Barman to stage the compressed files on the recovery + server in a location specified by the `recovery_staging_path` option. + +- Add support for PostgreSQL 15. Exclusive backups are not supported + by PostgreSQL 15 therefore Barman configurations for PostgreSQL 15 + servers are not allowed to specify `exclusive_backup` in + `backup_options`. + +- Use custom_compression_magic, if set, when identifying compressed + WAL files. This allows Barman to correctly identify uncompressed + WALs (such as `*.partial` files in the `streaming` directory) and + return them instead of attempting to decompress them. + +### Minor changes + +- Various documentation improvements. + +### Bugfixes + +- Fix an ordering bug which caused Barman to log the message + "Backup failed issuing start backup command." while handling a + failure in the stop backup command. + +- Fix a bug which prevented recovery using `--target-tli` when + timelines greater than 9 were present, due to hexadecimal values + from WAL segment names being parsed as base 10 integers. + +- Fix an import error which occurs when using barman cloud with + certain python2 installations due to issues with the enum34 + dependency. + +- Fix a bug where Barman would not read more than three bytes from + a compressed WAL when attempting to identify the magic bytes. This + means that any custom compressed WALs using magic longer than three + bytes are now decompressed correctly. + +- Fix a bug which caused the `--immediate-checkpoint` flag to be + ignored during backups with `backup_method = rsync`. + +## 2.19 (2022-03-09) + +### Notable changes + +- Change `barman diagnose` output date format to ISO8601. + +- Add Google Cloud Storage (GCS) support to barman cloud. + +- Support `current` and `latest` recovery targets for the `--target-tli` + option of `barman recover`. + +- Add documentation for installation on SLES. + +### Bugfixes + +- `barman-wal-archive --test` now returns a non-zero exit code when + an error occurs. + +- Fix `barman-cloud-check-wal-archive` behaviour when `-t` option is + used so that it exits after connectivity test. + +- `barman recover` now continues when `--no-get-wal` is used and + `"get-wal"` is not set in `recovery_options`. + +- Fix `barman show-servers --format=json ${server}` output for + inactive server. + +- Check for presence of `barman_home` in configuration file. + +- Passive barman servers will no longer store two copies of the + tablespace data when syncing backups taken with + `backup_method = postgres`. + +- We thank richyen for his contributions to this release. + +## 2.18 (2022-01-21) + +### Notable changes + +- Add snappy compression algorithm support in barman cloud (requires the + optional python-snappy dependency). + +- Allow Azure client concurrency parameters to be set when uploading + WALs with barman-cloud-wal-archive. + +- Add `--tags` option in barman cloud so that backup files and archived + WALs can be tagged in cloud storage (aws and azure). + +- Update the barman cloud exit status codes so that there is a dedicated + code (2) for connectivity errors. + +- Add the commands `barman verify-backup` and `barman generate-manifest` + to check if a backup is valid. + +- Add support for Azure Managed Identity auth in barman cloud which can + be enabled with the `--credential` option. + +### Bugfixes + +- Change `barman-cloud-check-wal-archive` behavior when bucket does + not exist. + +- Ensure `list-files` output is always sorted regardless of the + underlying filesystem. + +- Man pages for barman-cloud-backup-keep, barman-cloud-backup-delete + and barman-cloud-check-wal-archive added to Python packaging. + +- We thank richyen and stratakis for their contributions to this + release. + +## 2.17 (2021-12-01) + +### Notable changes + +- Resolves a performance regression introduced in version 2.14 which + increased copy times for `barman backup` or `barman recover` commands + when using the `--jobs` flag. + +- Ignore rsync partial transfer errors for `sender` processes so that + such errors do not cause the backup to fail (thanks to barthisrael). + +## 2.16 (2021-11-17) + +### Notable changes + +- Add the commands `barman-check-wal-archive` and `barman-cloud-check-wal-archive` + to validate if a proposed archive location is safe to use for a new PostgreSQL + server. + +- Allow Barman to identify WAL that's already compressed using a custom + compression scheme to avoid compressing it again. + +- Add `last_backup_minimum_size` and `last_wal_maximum_age` options to + `barman check`. + +### Bugfixes + +- Use argparse for command line parsing instead of the unmaintained + argh module. + +- Make timezones consistent for `begin_time` and `end_time`. + +- We thank chtitux, George Hansper, stratakis, Thoro, and vrms for their + contributions to this release. + +## 2.15 (2021-10-12) + +### Notable changes + +- Add plural forms for the `list-backup`, `list-server` and + `show-server` commands which are now `list-backups`, `list-servers` + and `show-servers`. The singular forms are retained for backward + compatibility. + +- Add the `last-failed` backup shortcut which references the newest + failed backup in the catalog so that you can do: + + - `barman delete last-failed` + +### Bugfixes + +- Tablespaces will no longer be omitted from backups of EPAS + versions 9.6 and 10 due to an issue detecting the correct version + string on older versions of EPAS. + +## 2.14 (2021-09-22) + +### Notable changes + +- Add the `barman-cloud-backup-delete` command which allows backups in + cloud storage to be deleted by specifying either a backup ID or a + retention policy. + +- Allow backups to be retained beyond any retention policies in force by + introducing the ability to tag existing backups as archival backups + using `barman keep` and `barman-cloud-backup-keep`. + +- Allow the use of SAS authentication tokens created at the restricted + blob container level (instead of the wider storage account level) for + Azure blob storage + +- Significantly speed up `barman restore` into an empty directory for + backups that contain hundreds of thousands of files. + +### Bugfixes + +- The backup privileges check will no longer fail if the user lacks + "userepl" permissions and will return better error messages if any + required permissions are missing (#318 and #319). + +## 2.13 (2021-07-26) + +### Notable changes + +- Add Azure blob storage support to barman-cloud + +- Support tablespace remapping in barman-cloud-restore via + `--tablespace name:location` + +- Allow barman-cloud-backup and barman-cloud-wal-archive to run as + Barman hook scripts, to allow data to be relayed to cloud storage + from the Barman server + +### Bugfixes + +- Stop backups failing due to idle_in_transaction_session_timeout + + +- Fix a race condition between backup and archive-wal in updating + xlog.db entries (#328) + +- Handle PGDATA being a symlink in barman-cloud-backup, which led to + "seeking backwards is not allowed" errors on restore (#351) + +- Recreate pg_wal on restore if the original was a symlink (#327) + +- Recreate pg_tblspc symlinks for tablespaces on restore (#343) + +- Make barman-cloud-backup-list skip backups it cannot read, e.g., + because they are in Glacier storage (#332) + +- Add `-d database` option to barman-cloud-backup to specify which + database to connect to initially (#307) + +- Fix "Backup failed uploading data" errors from barman-cloud-backup + on Python 3.8 and above, caused by attempting to pickle the boto3 + client (#361) + +- Correctly enable server-side encryption in S3 for buckets that do + not have encryption enabled by default. + + In Barman 2.12, barman-cloud-backup's `--encryption` option did + not correctly enable encryption for the contents of the backup if + the backup was stored in an S3 bucket that did not have encryption + enabled. If this is the case for you, please consider deleting + your old backups and taking new backups with Barman 2.13. + + If your S3 buckets already have encryption enabled by default + (which we recommend), this does not affect you. + +## 2.12.1 (2021-06-30) + +### Bugfixes + +- Allow specifying target-tli with other `target-*` recovery options. +- Fix incorrect NAME in barman-cloud-backup-list manpage. +- Don't raise an error if SIGALRM is ignored. +- Fetch wal_keep_size, not wal_keep_segments, from Postgres 13. + +## 2.12 (2020-11-05) + +### Notable changes + +- Introduce a new backup_method option called local-rsync which + targets those cases where Barman is installed on the same server + where PostgreSQL is and directly uses rsync to take base backups, + bypassing the SSH layer. + +### Bugfixes + +- Avoid corrupting boto connection in worker processes. +- Avoid connection attempts to PostgreSQL during tests. + +## 2.11 (2020-07-09) + +### Notable changes + +- Introduction of the barman-cli-cloud package that contains all cloud + related utilities. + +- Add barman-cloud-wal-restore to restore a WAL file previously + archived with barman-cloud-wal-archive from an object store. + +- Add barman-cloud-restore to restore a backup previously taken with + barman-cloud-backup from an object store. + +- Add barman-cloud-backup-list to list backups taken with + barman-cloud-backup in an object store. + +- Add support for arbitrary archive size for barman-cloud-backup. + +- Add support for --endpoint-url option to cloud utilities. + +- Remove strict superuser requirement for PG 10+ (by Kaarel Moppel). + +- Add --log-level runtime option for barman to override default log + level for a specific command. + +- Support for PostgreSQL 13 + +### Bugfixes + +- Suppress messages and warning with SSH connections in barman-cli + (GH-257). +- Fix a race condition when retrieving uploaded parts in + barman-cloud-backup (GH-259). +- Close the PostgreSQL connection after a backup (GH-258). +- Check for uninitialized replication slots in receive-wal --reset + (GH-260). +- Ensure that begin_wal is valorised before acting on it (GH-262). +- Fix bug in XLOG/WAL arithmetic with custom segment size (GH-287). +- Fix rsync compatibility error with recent rsync. +- Fix PostgreSQLClient version parsing. +- Fix PostgreSQL exception handling with non ASCII messages. +- Ensure each postgres connection has an empty search_path. +- Avoid connecting to PostgreSQL while reading a backup.info file. + +If you are using already `barman-cloud-wal-archive` or `barman-cloud-backup` +installed via RPM/Apt package and you are upgrading your system, you +must install the barman-cli-cloud package. All cloud related tools are +now part of the barman-cli-cloud package, including +`barman-cloud-wal-archive` and `barman-cloud-backup` that were previously +shipped with `barman-cli`. The reason is complex dependency management of +the boto3 library, which is a requirement for the cloud utilities. + +## 2.10 (2019-12-05) + +### Notable changes + +- Pull .partial WAL files with get-wal and barman-wal-restore, + allowing restore_command in a recovery scenario to fetch a partial + WAL file's content from the Barman server. This feature simplifies + and enhances RPO=0 recovery operations. + +- Store the PostgreSQL system identifier in the server directory and + inside the backup information file. Improve check command to verify + the consistency of the system identifier with active connections + (standard and replication) and data on disk. + +- A new script called barman-cloud-wal-archive has been added to the + barman-cli package to directly ship WAL files from PostgreSQL (using + archive_command) to cloud object storage services that are + compatible with AWS S3. It supports encryption and compression. + +- A new script called barman-cloud-backup has been added to the + barman-cli package to directly ship base backups from a local + PostgreSQL server to cloud object storage services that are + compatible with AWS S3. It supports encryption, parallel upload, + compression. + +- Automated creation of replication slots through the server/global + option create_slot. When set to auto, Barman creates the replication + slot, in case streaming_archiver is enabled and slot_name is + defined. The default value is manual for back-compatibility. + +- Add '-w/--wait' option to backup command, making Barman wait for all + required WAL files to be archived before considering the backup + completed. Add also the --wait-timeout option (default 0, no + timeout). + +- Redact passwords from Barman output, in particular from + barman diagnose (InfoSec) + +- Improve robustness of receive-wal --reset command, by verifying that + the last partial file is aligned with the current location or, if + present, with replication slot's. + +- Documentation improvements + +### Bugfixes + +- Wrong string matching operation when excluding tablespaces + inside PGDATA (GH-245). +- Minor fixes in WAL delete hook scripts (GH-240). +- Fix PostgreSQL connection aliveness check (GH-239). + +## 2.9 (2019-08-01) + +### Notable changes + +- Transparently support PostgreSQL 12, by supporting the new way of + managing recovery and standby settings through GUC options and + signal files (recovery.signal and standby.signal) + +- Add --bwlimit command line option to set bandwidth limitation for + backup and recover commands + +- Ignore WAL archive failure for check command in case the latest + backup is WAITING_FOR_WALS + +- Add --target-lsn option to set recovery target Log Sequence Number + for recover command with PostgreSQL 10 or higher + +- Add --spool-dir option to barman-wal-restore so that users can + change the spool directory location from the default, avoiding + conflicts in case of multiple PostgreSQL instances on the same + server (thanks to Drazen Kacar). + +- Rename barman_xlog directory to barman_wal + +- JSON output writer to export command output as JSON objects and + facilitate integration with external tools and systems (thanks to + Marcin Onufry Hlybin). Experimental in this release. + +### Bugfixes + +- `replication-status` doesn’t show streamers with no slot (GH-222) + +- When checking that a connection is alive (“SELECT 1” query), + preserve the status of the PostgreSQL connection (GH-149). This + fixes those cases of connections that were terminated due to + idle-in-transaction timeout, causing concurrent backups to fail. + +## 2.8 (2019-05-17) + +### Notable changes + +- Add support for reuse_backup in geo-redundancy for incremental + backup copy in passive nodes + +- Improve performance of rsync based copy by using strptime instead of + the more generic dateutil.parser (#210) + +- Add ‘--test’ option to barman-wal-archive and barman-wal-restore to + verify the connection with the Barman server + +- Complain if backup_options is not explicitly set, as the future + default value will change from exclusive_backup to concurrent_backup + when PostgreSQL 9.5 will be declared EOL by the PGDG + +- Display additional settings in the show-server and diagnose + commands: archive_timeout, data_checksums, hot_standby, + max_wal_senders, max_replication_slots and wal_compression. + +- Merge the barman-cli project in Barman + +### Minor changes + +- Improve messaging of check --nagios for inactive servers. +- Log remote SSH command with recover command. +- Hide logical decoding connections in replication-status command. + +This release officially supports Python 3 and deprecates Python 2 (which +might be discontinued in future releases). + +PostgreSQL 9.3 and older is deprecated from this release of Barman. +Support for backup from standby is now limited to PostgreSQL 9.4 or +higher and to WAL shipping from the standby (please refer to the +documentation for details). + +### Bugfixes + +- Fix encoding error in get-wal on Python 3 (Jeff Janes, #221). +- Fix exclude_and_protect_filter (Jeff Janes, #217). +- Remove spurious message when resetting WAL (Jeff Janes, #215). +- Fix sync-wals error if primary has WALs older than the first + backup. +- Support for double quotes in synchronous_standby_names setting. + +## 2.7 (2019-03-12) + +### Notable changes + +- Fix error handling during the parallel backup. Previously an + unrecoverable error during the copy could have corrupted the barman + internal state, requiring a manual kill of barman process with + SIGTERM and a manual cleanup of the running backup in PostgreSQL. + (GH#199). + +- Fix support of UTF-8 characters in input and output (GH#194 and + GH#196). + +- Ignore history/backup/partial files for first sync of geo-redundancy + (GH#198). + +- Fix network failure with geo-redundancy causing cron to break + (GH#202). + +- Fix backup validation in PostgreSQL older than 9.2. + +- Various documentation fixes. + +## 2.6 (2019-02-04) + +### Notable changes + +- Add support for Geographical redundancy, introducing 3 new commands: + sync-info, sync-backup and sync-wals. Geo-redundancy allows a Barman + server to use another Barman server as data source instead of a + PostgreSQL server. + +- Add put-wal command that allows Barman to safely receive WAL files + via PostgreSQL's archive_command using the barman-wal-archive script + included in barman-cli. + +- Add ANSI colour support to check command. + +### Bugfixes + +- Fix switch-wal on standby with an empty WAL directory. +- Honour archiver locking in wait_for_wal method. +- Fix WAL compression detection algorithm. +- Fix current_action in concurrent stop backup errors. +- Do not treat lock file busy as an error when validating a backup. + +## 2.5 (2018-10-23) + +### Notable changes + +- Add support for PostgreSQL 11 + +- Add check-backup command to verify that WAL files required for + consistency of a base backup are present in the archive. Barman now + adds a new state (WAITING_FOR_WALS) after completing a base backup, + and sets it to DONE once it has verified that all WAL files from + start to the end of the backup exist. This command is included in + the regular cron maintenance job. Barman now notifies users + attempting to recover a backup that is in WAITING_FOR_WALS state. + +- Allow switch-xlog --archive to work on a standby (just for the + archive part) + +### Bugfixes + +- Fix decoding errors reading external commands output (issue + #174). + +- Fix documentation regarding WAL streaming and backup from + standby. + +## 2.4 (2018-05-25) + +### Notable changes + +- Add standard and retry hook scripts for backup deletion (pre/post). +- Add standard and retry hook scripts for recovery (pre/post). +- Add standard and retry hook scripts for WAL deletion (pre/post). +- Add --standby-mode option to barman recover to add standby_mode = on + in pre-generated recovery.conf. +- Add --target-action option to barman recover, allowing users to add + shutdown, pause or promote to the pre-generated recovery.conf file. +- Improve usability of point-in-time recovery with consistency checks + (e.g. recovery time is after end time of backup). +- Minor documentation improvements. +- Drop support for Python 3.3. + +### Bugfixes + +- Fix remote get_file_content method (GitHub #151), preventing + incremental recovery from happening. +- Unicode issues with command (GitHub #143 and #150). +- Add --wal-method=none when pg_basebackup >= 10 (GitHub #133). +- Stop process manager module from overwriting lock files content +- Relax the rules for rsync output parsing +- Ignore vanished files in streaming directory +- Case insensitive slot names (GitHub #170) +- Make DataTransferFailure.from_command_error() more resilient + (GitHub #86) +- Rename command() to barman_command() (GitHub #118) +- Initialise synchronous standby names list if not set (GitHub #111) +- Correct placeholders ordering (GitHub #138) +- Force datestyle to iso for replication connections +- Returns error if delete command does not remove the backup +- Fix exception when calling is_power_of_two(None) +- Downgraded sync standby names messages to debug (GitHub #89) + +## 2.3 (2017-09-05) + +### Notable changes + +- Add support to PostgreSQL 10 + +- Follow naming changes in PostgreSQL 10: + + - The switch-xlog command has been renamed to switch-wal. + - In commands output, the xlog word has been changed to WAL and + location has been changed to LSN when appropriate. + +- Add the --network-compression/--no-network-compression options to + barman recover to enable or disable network compression at run-time +- Add --target-immediate option to recover command, in order to exit + recovery when a consistent state is reached (end of the backup, + available from PostgreSQL 9.4) +- Show cluster state (master or standby) with barman status command +- Documentation improvements + +### Bugfixes + +- Fix high memory usage with parallel_jobs > 1 (#116) +- Better handling of errors using parallel copy (#114) +- Make barman diagnose more robust with system exceptions +- Let archive-wal ignore files with .tmp extension + +## 2.2 (2017-07-17) + +### Notable changes + +- Implement parallel copy for backup/recovery through the + parallel_jobs global/server option to be overridden by the --jobs or + -j runtime option for the backup and recover command. Parallel + backup is available only for the rsync copy method. By default, it + is set to 1 (for behaviour compatibility with previous versions). + +- Support custom WAL size for PostgreSQL 8.4 and newer. At backup + time, Barman retrieves from PostgreSQL wal_segment_size and + wal_block_size values and computes the necessary calculations. + +- Improve check command to ensure that incoming directory is empty + when archiver=off, and streaming directory is empty when + streaming_archiver=off (#80). + +- Add external_configuration to backup_options so that users can + instruct Barman to ignore backup of configuration files when they + are not inside PGDATA (default for Debian/Ubuntu installations). In + this case, Barman does not display a warning anymore. + +- Add --get-wal and --no-get-wal options to barman recover + +- Add max_incoming_wals_queue global/server option for the check + command so that a non blocking error is returned in case incoming + WAL directories for both archiver and the streaming_archiver contain + more files than the specified value. + +- Documentation improvements + +- File format changes: + + - The format of backup.info file has changed. For this reason a + backup taken with Barman 2.2 cannot be read by a previous + version of Barman. But, backups taken by previous versions can + be read by Barman 2.2. + +### Bugfixes + +- Allow replication-status to work against a standby +- Close any PostgreSQL connection before starting pg_basebackup + (#104, #108) +- Safely handle paths containing special characters +- Archive .partial files after promotion of streaming source +- Recursively create directories during recovery (SF#44) +- Improve xlog.db locking (#99) +- Remove tablespace_map file during recover (#95) +- Reconnect to PostgreSQL if connection drops (SF#82) + +## 2.1 (2017-01-05) + +### Notable changes + +- Add --archive and --archive-timeout options to switch-xlog command. + +- Preliminary support for PostgreSQL 10 (#73). + +- Minor additions: + + - Add last archived WAL info to diagnose output. + - Add start time and execution time to the output of delete + command. + +### Bugfixes + +- Return failure for get-wal command on inactive server +- Make streaming_archiver_names and streaming_backup_name options + global (#57) +- Fix rsync failures due to files truncated during transfer (#64) +- Correctly handle compressed history files (#66) +- Avoid de-referencing symlinks in pg_tblspc when preparing + recovery (#55) +- Fix comparison of last archiving failure (#40, #58) +- Avoid failing recovery if postgresql.conf is not writable (#68) +- Fix output of replication-status command (#56) +- Exclude files from backups like pg_basebackup (#65, #72) +- Exclude directories from other Postgres versions while copying + tablespaces (#74) +- Make retry hook script options global + +## 2.0 (2016-09-27) + +### Notable changes + +- Support for pg_basebackup and base backups over the PostgreSQL + streaming replication protocol with backup_method=postgres + (PostgreSQL 9.1 or higher required) + +- Support for physical replication slots through the slot_name + configuration option as well as the --create-slot and --drop-slot + options for the receive-wal command (PostgreSQL 9.4 or higher + required). When slot_name is specified and streaming_archiver is + enabled, receive-wal transparently integrates with pg_receivexlog, + and check makes sure that slots exist and are actively used + +- Support for the new backup API introduced in PostgreSQL 9.6, which + transparently enables concurrent backups and backups from standby + servers using the standard rsync method of backup. Concurrent backup + was only possible for PostgreSQL 9.2 to 9.5 versions through the + pgespresso extension. The new backup API will make pgespresso + redundant in the future + +- If properly configured, Barman can function as a synchronous standby + in terms of WAL streaming. By properly setting the + streaming_archiver_name in the synchronous_standby_names priority + list on the master, and enabling replication slot support, the + receive-wal command can now be part of a PostgreSQL synchronous + replication cluster, bringing RPO=0 (PostgreSQL 9.5.5 or + higher required) + +- Introduce barman-wal-restore, a standard and robust script written + in Python that can be used as restore_command in recovery.conf files + of any standby server of a cluster. It supports remote parallel + fetching of WAL files by efficiently invoking get-wal through SSH. + Currently available as a separate project called barman-cli. The + barman-cli package is required for remote recovery when get-wal is + listed in recovery_options + +- Control the maximum execution time of the check command through the + check_timeout global/server configuration option (30 seconds + by default) + +- Limit the number of WAL segments that are processed by an + archive-wal run, through the archiver_batch_size and + streaming_archiver_batch_size global/server options which control + archiving of WAL segments coming from, respectively, the standard + archiver and receive-wal + +- Removed locking of the XLOG database during check operations + +- The show-backup command is now aware of timelines and properly + displays which timelines can be used as recovery targets for a given + base backup. Internally, Barman is now capable of parsing .history + files + +- Improved the logic behind the retry mechanism when copy operations + experience problems. This involves backup (rsync and postgres) as + well as remote recovery (rsync) + +- Code refactoring involving remote command and physical copy + interfaces + +### Bugfixes + +- Correctly handle .history files from streaming +- Fix replication-status on PostgreSQL 9.1 +- Fix replication-status when sent and write locations are not + available +- Fix misleading message on pg_receivexlog termination + +## 1.6.1 (2016-05-23) + +### Minor changes + +- Add --peek option to get-wal command to discover existing WAL files + from the Barman's archive + +- Add replication-status command for monitoring the status of any + streaming replication clients connected to the PostgreSQL server. + The --target option allows users to limit the request to only hot + standby servers or WAL streaming clients + +- Add the switch-xlog command to request a switch of a WAL file to the + PostgreSQL server. Through the '--force' it issues a CHECKPOINT + beforehand + +- Add streaming_archiver_name option, which sets a proper + application_name to pg_receivexlog when streaming_archiver is + enabled (only for PostgreSQL 9.3 and above) + +- Check for _superuser_ privileges with PostgreSQL's standard + connections (#30) + +- Check the WAL archive is never empty + +- Check for 'backup_label' on the master when server is down + +- Improve barman-wal-restore contrib script + +### Bugfixes + +- Treat the "failed backups" check as non-fatal +- Rename '-x' option for get-wal as '-z' +- Add archive_mode=always support for PostgreSQL 9.5 (#32) +- Properly close PostgreSQL connections when necessary +- Fix receive-wal for pg_receive_xlog version 9.2 + +## 1.6.0 (2016-02-29) + +### Notable changes + +- Support for streaming replication connection through the + streaming_conninfo server option + +- Support for the streaming_archiver option that allows Barman to + receive WAL files through PostgreSQL's native streaming protocol. + When set to 'on', it relies on pg_receivexlog to receive WAL data, + reducing Recovery Point Objective. Currently, WAL streaming is an + additional feature (standard log archiving is still required) + +- Implement the receive-wal command that, when streaming_archiver is + on, wraps pg_receivexlog for WAL streaming. Add --stop option to + stop receiving WAL files via streaming protocol. Add --reset option + to reset the streaming status and restart from the current xlog + in Postgres. + +- Automatic management (startup and stop) of receive-wal command via + cron command + +- Support for the path_prefix configuration option + +- Introduction of the archiver option (currently fixed to on) which + enables continuous WAL archiving for a specific server, through log + shipping via PostgreSQL's archive_command + +- Support for streaming_wals_directory and errors_directory options + +- Management of WAL duplicates in archive-wal command and integration + with check command + +- Verify if pg_receivexlog is running in check command when + streaming_archiver is enabled + +- Verify if failed backups are present in check command + +- Accept compressed WAL files in incoming directory + +- Add support for the pigz compressor (thanks to Stefano Zacchiroli + ) + +- Implement pygzip and pybzip2 compressors (based on an initial idea + of Christoph Moench-Tegeder ) + +- Creation of an implicit restore point at the end of a backup + +- Current size of the PostgreSQL data files in barman status + +- Permit archive_mode=always for PostgreSQL 9.5 servers (thanks to + Christoph Moench-Tegeder ) + +- Complete refactoring of the code responsible for connecting to + PostgreSQL + +- Improve messaging of cron command regarding sub-processes + +- Native support for Python >= 3.3 + +- Changes of behaviour: + - Stop trashing WAL files during archive-wal (commit:e3a1d16) + +### Bugfixes + +- Atomic WAL file archiving (#9 and #12) +- Propagate "-c" option to any Barman subprocess (#19) +- Fix management of backup ID during backup deletion (#22) +- Improve archive-wal robustness and log messages (#24) +- Improve error handling in case of missing parameters + +## 1.5.1 (2015-11-16) + +### Minor changes + +- Add support for the 'archive-wal' command which performs WAL + maintenance operations on a given server +- Add support for "per-server" concurrency of the 'cron' command +- Improved management of xlog.db errors +- Add support for mixed compression types in WAL files (SF.net#61) + +### Bugfixes + +- Avoid retention policy checks during the recovery +- Avoid 'wal_level' check on PostgreSQL version < 9.0 (#3) +- Fix backup size calculation (#5) + +## 1.5.0 (2015-09-28) + +### Notable changes + +- Add support for the get-wal command which allows users to fetch any + WAL file from the archive of a specific server +- Add support for retry hook scripts, a special kind of hook scripts + that Barman tries to run until they succeed +- Add active configuration option for a server to temporarily disable + the server by setting it to False +- Add barman_lock_directory global option to change the location of + lock files (by default: 'barman_home') +- Execute the full suite of checks before starting a backup, and skip + it in case one or more checks fail +- Forbid to delete a running backup +- Analyse include directives of a PostgreSQL server during backup and + recover operations +- Add check for conflicting paths in the configuration of Barman, both + intra (by temporarily disabling a server) and inter-server (by + refusing any command, to any server). +- Add check for wal_level +- Add barman-wal-restore script to be used as restore_command on a + standby server, in conjunction with barman get-wal +- Implement a standard and consistent policy for error management +- Improved cache management of backups +- Improved management of configuration in unit tests +- Tutorial and man page sources have been converted to Markdown format +- Add code documentation through Sphinx +- Complete refactor of the code responsible for managing the backup + and the recover commands +- Changed internal directory structure of a backup +- Introduce copy_method option (currently fixed to rsync) + +### Bugfixes + +- Manage options without '=' in PostgreSQL configuration files +- Preserve Timeline history files (Fixes: #70) +- Workaround for rsync on SUSE Linux (Closes: #13 and #26) +- Disables dangerous settings in postgresql.auto.conf + (Closes: #68) + +## 1.4.1 (2015-05-05) + +### Minor changes + +- Improved management of xlogdb file, which is now correctly fsynced + when updated. Also, the rebuild-xlogdb command now operates on a + temporary new file, which overwrites the main one when finished. +- Add unit tests for dateutil module compatibility +- Modified Barman version following PEP 440 rules and added support + of tests in Python 3.4 + +### Bugfixes + +- Fix for WAL archival stop working if first backup is EMPTY + (Closes: #64) +- Fix exception during error handling in Barman recovery + (Closes: #65) +- After a backup, limit cron activity to WAL archiving only + (Closes: #62) +- Improved robustness and error reporting of the backup delete + command (Closes: #63) +- Fix computation of WAL production ratio as reported in the + show-backup command + +## 1.4.0 (2015-01-26) + +### Notable changes + +- Incremental base backup implementation through the reuse_backup + global/server option. Possible values are off (disabled, + default), copy (preventing unmodified files from being + transferred) and link (allowing for deduplication through hard + links). +- Store and show deduplication effects when using reuse_backup= + link. +- Added transparent support of pg_stat_archiver (PostgreSQL 9.4) in + check, show-server and status commands. +- Improved administration by invoking WAL maintenance at the end of + a successful backup. +- Changed the way unused WAL files are trashed, by differentiating + between concurrent and exclusive backup cases. +- Improved performance of WAL statistics calculation. +- Treat a missing pg_ident.conf as a WARNING rather than an error. +- Refactored output layer by removing remaining yield calls. +- Check that rsync is in the system path. +- Include history files in WAL management. +- Improved robustness through more unit tests. + +### Bugfixes + +- Fixed bug #55: Ignore fsync EINVAL errors on directories. +- Fixed bug #58: retention policies delete. + +## 1.3.3 (2014-08-21) + +### Notable changes + +- Added "last_backup_max_age", a new global/server option that + allows administrators to set the max age of the last backup in a + catalogue, making it easier to detect any issues with periodical + backup execution +- Improved robustness of "barman backup" by introducing two global/ + server options: "basebackup_retry_times" and + "basebackup_retry_sleep". These options allow an administrator to + specify, respectively, the number of attempts for a copy + operation after a failure, and the number of seconds of wait + before retrying +- Improved the recovery process via rsync on an existing directory + (incremental recovery), by splitting the previous rsync call into + several ones - invoking checksum control only when necessary +- Added support for PostgreSQL 8.3 + +### Minor changes + +- Support for comma separated list values configuration options +- Improved backup durability by calling fsync() on backup and + WAL files during "barman backup" and "barman cron" +- Improved Nagios output for "barman check --nagios" +- Display compression ratio for WALs in "barman show-backup" +- Correctly handled keyboard interruption (CTRL-C) while + performing barman backup +- Improved error messages of failures regarding the stop of a + backup +- Wider coverage of unit tests + +### Bugfixes + +- Copies "recovery.conf" on the remote server during "barman + recover" (#45) +- Correctly detect pre/post archive hook scripts (#41) + +## 1.3.2 (2014-04-15) + +### Bugfixes + +- Fixed incompatibility with PostgreSQL 8.4 (Closes #40, bug + introduced in version 1.3.1) + +## 1.3.1 (2014-04-14) + +### Minor changes + +- Added support for concurrent backup of PostgreSQL 9.2 and 9.3 + servers that use the "pgespresso" extension. This feature is + controlled by the "backup_options" configuration option (global/ + server) and activated when set to "concurrent_backup". Concurrent + backup allows DBAs to perform full backup operations from a + streaming replicated standby. +- Added the "barman diagnose" command which prints important + information about the Barman system (extremely useful for support + and problem solving) +- Improved error messages and exception handling interface + +### Bugfixes + +- Fixed bug in recovery of tablespaces that are created inside the + PGDATA directory (bug introduced in version 1.3.0) +- Fixed minor bug of unhandled -q option, for quiet mode of + commands to be used in cron jobs (bug introduced in version + 1.3.0) +- Minor bug fixes and code refactoring + +## 1.3.0 (2014-02-03) + +### Notable changes + +- Refactored BackupInfo class for backup metadata to use the new + FieldListFile class (infofile module) + +- Refactored output layer to use a dedicated module, in order to + facilitate integration with Nagios (NagiosOutputWriter class) + +- Refactored subprocess handling in order to isolate stdin/stderr/ + stdout channels (command_wrappers module) + +- Refactored hook scripts management + +- Extracted logging configuration and userid enforcement from the + configuration class. + +- Support for hook scripts to be executed before and after a WAL + file is archived, through the 'pre_archive_script' and + 'post_archive_script' configuration options. + +- Implemented immediate checkpoint capability with + --immediate-checkpoint command option and 'immediate_checkpoint' + configuration option + +- Implemented network compression for remote backup and recovery + through the 'network_compression' configuration option (#19) + +- Implemented the 'rebuild-xlogdb' command (Closes #27 and #28) + +- Added deduplication of tablespaces located inside the PGDATA + directory + +- Refactored remote recovery code to work the same way local + recovery does, by performing remote directory preparation + (assuming the remote user has the right permissions on the remote + server) + +- 'barman backup' now tries and create server directories before + attempting to execute a full backup (#14) + +### Bugfixes + +- Fixed bug #22: improved documentation for tablespaces relocation + +- Fixed bug #31: 'barman cron' checks directory permissions for + lock file + +- Fixed bug #32: xlog.db read access during cron activities + +## 1.2.3 (2013-09-05) + +### Minor changes + +- Added support for PostgreSQL 9.3 + +- Added support for the "--target-name" recovery option, which allows to + restore to a named point previously specified with pg_create_restore_point + (only for PostgreSQL 9.1 and above users) + +- Introduced Python 3 compatibility + +### Bugfixes + +- Fixed bug #27 about flock() usage with barman.lockfile (many thanks to + Damon Snyder ) + +## 1.2.2 (2013-06-24) + +### Bugfixes + +- Fix python 2.6 compatibility + +## 1.2.1 (2013-06-17) + +### Minor changes + +- Added the "bandwidth_limit" global/server option which allows + to limit the I/O bandwidth (in KBPS) for backup and recovery operations + +- Added the "tablespace_bandwidth_limit" global/server option which allows + to limit the I/O bandwidth (in KBPS) for backup and recovery operations + on a per tablespace basis + +- Added /etc/barman/barman.conf as default location + +### Bugfixes + +- Avoid triggering the minimum_redundancy check + on FAILED backups (thanks to Jérôme Vanandruel) + +## 1.2.0 (2013-01-31) + +### Notable changes + +- Added the "retention_policy_mode" global/server option which defines + the method for enforcing retention policies (currently only "auto") + +- Added the "minimum_redundancy" global/server option which defines + the minimum number of backups to be kept for a server + +- Added the "retention_policy" global/server option which defines + retention policies management based on redundancy (e.g. REDUNDANCY 4) + or recovery window (e.g. RECOVERY WINDOW OF 3 MONTHS) + +- Added retention policy support to the logging infrastructure, the + "check" and the "status" commands + +- The "check" command now integrates minimum redundancy control + +- Added retention policy states (valid, obsolete and potentially obsolete) + to "show-backup" and "list-backup" commands + +- The 'all' keyword is now forbidden as server name + +- Added basic support for Nagios plugin output to the 'check' + command through the --nagios option + +- Barman now requires argh => 0.21.2 and argcomplete- + +- Minor bug fixes + +## 1.1.2 (2012-11-29) + +### Minor changes + +- Added "configuration_files_directory" option that allows + to include multiple server configuration files from a directory + +- Support for special backup IDs: latest, last, oldest, first + +- Management of multiple servers to the 'list-backup' command. + 'barman list-backup all' now list backups for all the configured servers. + +- Added "application_name" management for PostgreSQL >= 9.0 + +### Bugfixes + +- Fixed bug #18: ignore missing WAL files if not found during delete + +## 1.1.1 (2012-10-16) + +### Bugfixes + +- Fix regressions in recover command. + +## 1.1.0 (2012-10-12) + +### Notable changes + +- Support for hook scripts to be executed before and after + a 'backup' command through the 'pre_backup_script' and 'post_backup_script' + configuration options. + +- Management of multiple servers to the 'backup' command. + 'barman backup all' now iteratively backs up all the configured servers. + +- Add warning in recovery when file location options have been defined + in the postgresql.conf file (issue #10) + +- Fail fast on recover command if the destination directory contains + the ':' character (Closes: #4) or if an invalid tablespace + relocation rule is passed + +- Report an informative message when pg_start_backup() invocation + fails because an exclusive backup is already running (Closes: #8) + +### Bugfixes + +- Fixed bug #9: "9.2 issue with pg_tablespace_location()" + +## 1.0.0 (2012-07-06) + +### Notable changes + +- Backup of multiple PostgreSQL servers, with different versions. Versions + from PostgreSQL 8.4+ are supported. + +- Support for secure remote backup (through SSH) + +- Management of a catalog of backups for every server, allowing users + to easily create new backups, delete old ones or restore them + +- Compression of WAL files that can be configured on a per server + basis using compression/decompression filters, both predefined (gzip + and bzip2) or custom + +- Support for INI configuration file with global and per-server directives. + Default location for configuration files are /etc/barman.conf or + ~/.barman.conf. The '-c' option allows users to specify a different one + +- Simple indexing of base backups and WAL segments that does not require + a local database + +- Maintenance mode (invoked through the 'cron' command) which performs + ordinary operations such as WAL archival and compression, catalog + updates, etc. + +- Added the 'backup' command which takes a full physical base backup + of the given PostgreSQL server configured in Barman + +- Added the 'recover' command which performs local recovery of a given + backup, allowing DBAs to specify a point in time. The 'recover' command + supports relocation of both the PGDATA directory and, where applicable, + the tablespaces + +- Added the '--remote-ssh-command' option to the 'recover' command for + remote recovery of a backup. Remote recovery does not currently support + relocation of tablespaces + +- Added the 'list-server' command that lists all the active servers + that have been configured in barman + +- Added the 'show-server' command that shows the relevant information + for a given server, including all configuration options + +- Added the 'status' command which shows information about the current + state of a server, including Postgres version, current transaction ID, + archive command, etc. + +- Added the 'check' command which returns 0 if everything Barman needs + is functioning correctly + +- Added the 'list-backup' command that lists all the available backups + for a given server, including size of the base backup and total size + of the related WAL segments + +- Added the 'show-backup' command that shows the relevant information + for a given backup, including time of start, size, number of related + WAL segments and their size, etc. + +- Added the 'delete' command which removes a backup from the catalog + +- Added the 'list-files' command which lists all the files for a + single backup + +- RPM Package for RHEL 5/6 diff --git a/actions/build-documentation/action.yml b/actions/build-documentation/action.yml deleted file mode 100644 index c551944d6..000000000 --- a/actions/build-documentation/action.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Generate Documentation -description: | - Create documentation for barman - - -inputs: - docker-image: - description: docker image to use. will build it if not provided or not find - required: false - - barman-path: - description: path for barman - required: false - default: barman - -outputs: - html: - description: HTML documentation - value: ${{ steps.set-artefacts.outputs.html }} - pdf: - description: PDF documentation - value: ${{ steps.set-artefacts.outputs.pdf }} - -runs: - using: "composite" - - steps: - - name: pull docker image - id: pull-docker-image - continue-on-error: true - if: "inputs.docker-image" - run: | - docker pull ${{ inputs.docker-image }} - echo "PANDOC_IMAGE=${{ inputs.docker-image }}" >> $GITHUB_ENV - shell: bash - - name: build docker image - if: "!inputs.docker-image || steps.pull-docker-image.outcome == 'failure'" - run: | - docker build ${{ inputs.barman-path }}/doc -t barman-pandoc - echo "PANDOC_IMAGE=barman-pandoc" >> $GITHUB_ENV - shell: bash - - - name: build doc - run: | - cd ${{ inputs.barman-path }}/doc/build - ./build - shell: bash - env: - BASEDIR: ${{ inputs.barman-path }} - PANDOC_IMAGE: ${{ env.PANDOC_IMAGE }} - - name: check output - run: | - ls ${{ inputs.barman-path }}/doc/dist - shell: bash - - name: Upload pdf documentation - uses: actions/upload-artifact@v3 - with: - name: manual.pdf - path: ${{ inputs.barman-path }}/doc/dist/manual.pdf - if-no-files-found: error - - name: remove PDF - run: | - rm ${{ inputs.barman-path }}/doc/dist/manual.pdf - shell: bash - - name: Upload html documentation - uses: actions/upload-artifact@v3 - with: - name: documentation - path: ${{ inputs.barman-path }}/doc/dist - if-no-files-found: error - - name: define artefacts - id: set-artefacts - run: | - echo "html=documentation" >> $GITHUB_OUTPUT - echo "pdf=manual.pdf" >> $GITHUB_OUTPUT - shell: bash diff --git a/barman/backup.py b/barman/backup.py index 6195defe9..071f64121 100644 --- a/barman/backup.py +++ b/barman/backup.py @@ -32,7 +32,7 @@ import dateutil.tz from barman import output, xlog -from barman.annotations import KeepManager, KeepManagerMixin +from barman.annotations import AnnotationManagerFile, KeepManager, KeepManagerMixin from barman.backup_executor import ( PassiveBackupExecutor, PostgresBackupExecutor, @@ -77,6 +77,7 @@ class BackupManager(RemoteStatusMixin, KeepManagerMixin): """Manager of the backup archive for a server""" DEFAULT_STATUS_FILTER = BackupInfo.STATUS_COPY_DONE + DELETE_ANNOTATION = "delete_this" def __init__(self, server): """ @@ -88,6 +89,9 @@ def __init__(self, server): self.config = server.config self._backup_cache = None self.compression_manager = CompressionManager(self.config, server.path) + self.annotation_manager = AnnotationManagerFile( + self.server.config.basebackups_directory + ) self.executor = None try: if server.passive_node: @@ -423,6 +427,42 @@ def get_backup_id_from_name(self, backup_name, status_filter=DEFAULT_STATUS_FILT if backup_info is not None: return backup_info.backup_id + def put_delete_annotation(self, backup_id): + """ + Add a delete annotation to the specified backup. + + This method adds an annotation to the backup identified by *backup_id* to mark it + for deletion. The annotation is stored using the annotation manager. + + :param str backup_id: The ID of the backup to annotate. + """ + self.annotation_manager.put_annotation( + backup_id, self.DELETE_ANNOTATION, "delete" + ) + + def check_delete_annotation(self, backup_id): + """ + Check if a delete annotation exists for the specified backup. + + This method checks if the backup identified by *backup_id* has a delete annotation. + It returns ``True`` if the annotation exists, otherwise ``False``. + + :param str backup_id: The ID of the backup to check. + :return bool: ``True`` if the delete annotation exists, ``False`` otherwise. + """ + return ( + self.annotation_manager.get_annotation(backup_id, self.DELETE_ANNOTATION) + is not None + ) + + def release_delete_annotation(self, backup_id): + """ + Remove the delete annotation from the backup identified by *backup_id*. + + :param str backup_id: The ID of the backup to remove the annotation from. + """ + self.annotation_manager.delete_annotation(backup_id, self.DELETE_ANNOTATION) + @staticmethod def get_timelines_to_protect(remove_until, deleted_backup, available_backups): """ @@ -459,6 +499,9 @@ def delete_backup(self, backup, skip_wal_cleanup_if_standalone=True): backups. :return bool: True if deleted, False if could not delete the backup """ + # Set the delete annotation + self.put_delete_annotation(backup.backup_id) + # Keep track of when the delete operation started. delete_start_time = datetime.datetime.now() @@ -527,6 +570,9 @@ def delete_backup(self, backup, skip_wal_cleanup_if_standalone=True): ): output.info("\t%s", name) + # Remove the delete annotation + self.release_delete_annotation(backup.backup_id) + # As last action, remove the backup directory, # ending the delete operation try: @@ -541,7 +587,7 @@ def delete_backup(self, backup, skip_wal_cleanup_if_standalone=True): backup.get_basebackup_directory(), ) return False - self.backup_cache_remove(backup) + # Save the time of the complete removal of the backup delete_end_time = datetime.datetime.now() output.info( @@ -604,6 +650,8 @@ def delete_backup(self, backup, skip_wal_cleanup_if_standalone=True): script.env_from_backup_info(backup) script.run() + self.backup_cache_remove(backup) + return True def _set_backup_sizes(self, backup_info, fsync=False): @@ -989,9 +1037,27 @@ def cron_retention_policy(self): """ enforce_retention_policies = self.server.enforce_retention_policies retention_policy_mode = self.config.retention_policy_mode + if enforce_retention_policies and retention_policy_mode == "auto": available_backups = self.get_available_backups(BackupInfo.STATUS_ALL) retention_status = self.config.retention_policy.report() + + # Find backups with the delete annotation and mark as obsolete + for backup in available_backups.values(): + if self.check_delete_annotation(backup.backup_id): + retention_status[backup.backup_id] = BackupInfo.OBSOLETE + self.release_delete_annotation(backup.backup_id) + + # Check if the backup path still exists while the delete annotation + # was already removed + elif backup.is_orphan: + output.warning( + "WARNING: Backup directory %s contains only a non-empty " + "backup.info file which may indicate an incomplete delete operation. " + "Please manually delete the directory.", + backup.get_basebackup_directory(), + ) + for bid in sorted(retention_status.keys()): if retention_status[bid] == BackupInfo.OBSOLETE: try: @@ -1027,6 +1093,7 @@ def delete_basebackup(self, backup): """ backup_dir = backup.get_basebackup_directory() _logger.debug("Deleting base backup directory: %s" % backup_dir) + shutil.rmtree(backup_dir) def delete_backup_data(self, backup): diff --git a/barman/backup_executor.py b/barman/backup_executor.py index d061fdc07..b2a887bce 100644 --- a/barman/backup_executor.py +++ b/barman/backup_executor.py @@ -63,6 +63,10 @@ from barman.postgres_plumbing import EXCLUDE_LIST, PGDATA_EXCLUDE_LIST from barman.remote_status import RemoteStatusMixin from barman.utils import ( + check_aws_expiration_date_format, + check_aws_snapshot_lock_cool_off_period_range, + check_aws_snapshot_lock_duration_range, + check_aws_snapshot_lock_mode, force_str, human_readable_timedelta, mkpath, @@ -1535,6 +1539,59 @@ def validate_configuration(self): "%s option is required by snapshot backup_method" % config_var ) + # Check if aws_snapshot_lock_mode is set with snapshot_provider = aws. + if ( + getattr(self.server.config, "aws_snapshot_lock_mode") + and getattr(self.server.config, "snapshot_provider") == "aws" + ): + self._validate_aws_lock_configuration() + + def _validate_aws_lock_configuration(self): + """Verify configuration is valid for locking a snapshot backup using AWS + provider. + """ + if not ( + getattr(self.server.config, "aws_snapshot_lock_duration") + or getattr(self.server.config, "aws_snapshot_lock_expiration_date") + ): + self.server.config.update_msg_list_and_disable_server( + "'aws_snapshot_lock_mode' is set, you must specify " + "'aws_snapshot_lock_duration' or 'aws_snapshot_lock_expiration_date'." + ) + + if getattr(self.server.config, "aws_snapshot_lock_duration") and getattr( + self.server.config, "aws_snapshot_lock_expiration_date" + ): + self.server.config.update_msg_list_and_disable_server( + "You must specify either 'aws_snapshot_lock_duration' or " + "'aws_snapshot_lock_expiration_date' in the configuration, but not both." + ) + + if getattr( + self.server.config, "aws_snapshot_lock_mode" + ) == "governance" and getattr( + self.server.config, "aws_snapshot_lock_cool_off_period" + ): + self.server.config.update_msg_list_and_disable_server( + "'aws_snapshot_lock_cool_off_period' cannot be used with " + "'aws_snapshot_lock_mode' = 'governance'." + ) + + lock_args = { + "aws_snapshot_lock_cool_off_period": check_aws_snapshot_lock_cool_off_period_range, + "aws_snapshot_lock_duration": check_aws_snapshot_lock_duration_range, + "aws_snapshot_lock_mode": check_aws_snapshot_lock_mode, + "aws_snapshot_lock_expiration_date": check_aws_expiration_date_format, + } + for arg, parser in lock_args.items(): + lock_arg = getattr(self.server.config, arg) + if lock_arg: + try: + _ = parser(lock_arg) + except Exception as e: + error_message = str(e) + self.server.config.update_msg_list_and_disable_server(error_message) + @staticmethod def add_mount_data_to_volume_metadata(volumes, remote_cmd): """ diff --git a/barman/cli.py b/barman/cli.py index 333329c0b..ffbefd4f8 100644 --- a/barman/cli.py +++ b/barman/cli.py @@ -484,7 +484,7 @@ def backup_completer(prefix, parsed_args, **kwargs): argument( "--name", help="a name which can be used to reference this backup in barman " - "commands such as recover and delete", + "commands such as restore and delete", dest="backup_name", default=None, type=check_backup_name, @@ -749,7 +749,7 @@ def rebuild_xlogdb(args): argument( "backup_id", completer=backup_completer, - help="specifies the backup ID to recover", + help="specifies the backup ID to restore", ), argument( "destination_directory", @@ -843,7 +843,7 @@ def rebuild_xlogdb(args): dest="standby_mode", action="store_true", default=SUPPRESS, - help="Enable standby mode when starting the recovered PostgreSQL instance", + help="Enable standby mode when starting the restored PostgreSQL instance", ), argument( "--recovery-staging-path", @@ -852,7 +852,7 @@ def rebuild_xlogdb(args): "A path to a location on the recovery host where compressed backup " "files will be staged during the recovery. This location must have " "enough available space to temporarily hold the full compressed " - "backup. This option is *required* when recovering from a compressed " + "backup. This option is *required* when restoring from a compressed " "backup." ), ), @@ -862,7 +862,7 @@ def rebuild_xlogdb(args): "A path to a location on the local host where incremental backups " "will be combined during the recovery. This location must have " "enough available space to temporarily hold the new synthetic " - "backup. This option is *required* when recovering from an " + "backup. This option is *required* when restoring from an " "incremental backup." ), ), @@ -899,11 +899,12 @@ def rebuild_xlogdb(args): help="The name of the AWS region containing the EC2 VM and storage " "volumes for recovery of a snapshot backup", ), - ] + ], + cmd_aliases=["recover"], ) -def recover(args): +def restore(args): """ - Recover a server at a given time, name, LSN or xid + Restore a server at a given time, name, LSN or xid """ server = get_server(args) @@ -911,7 +912,7 @@ def recover(args): backup_id = parse_backup_id(server, args) if backup_id.status not in BackupInfo.STATUS_COPY_DONE: output.error( - "Cannot recover from backup '%s' of server '%s': " + "Cannot restore from backup '%s' of server '%s': " "backup status is not DONE", args.backup_id, server.config.name, @@ -934,7 +935,7 @@ def recover(args): # data can be staged. if server.config.recovery_staging_path is None: output.error( - "Cannot recover from backup '%s' of server '%s': " + "Cannot restore from backup '%s' of server '%s': " "backup is compressed with %s compression but no recovery " "staging path is provided. Either set recovery_staging_path " "in the Barman config or use the --recovery-staging-path " @@ -961,7 +962,7 @@ def recover(args): # data can be staged. if server.config.local_staging_path is None: output.error( - "Cannot recover from backup '%s' of server '%s': " + "Cannot restore from backup '%s' of server '%s': " "backup will be combined with pg_combinebackup in the " "barman host but no local staging path is provided. " "Either set local_staging_path in the Barman config " @@ -1535,6 +1536,12 @@ def delete(args): dest="compression", default=SUPPRESS, ), + argument( + "--keep-compression", + help="do not decompress the output if compressed", + action="store_true", + dest="keep_compression", + ), argument( "--peek", "-p", @@ -1575,13 +1582,21 @@ def get_wal(args): # the namespace doesn't contain it due to SUPPRESS default. # In that case we pick 'None' using getattr third argument. compression = getattr(args, "compression", None) + keep_compression = getattr(args, "keep_compression", False) output_directory = getattr(args, "output_directory", None) peek = getattr(args, "peek", None) + if compression and keep_compression: + output.error( + "argument `%s` not allowed with argument `keep-compression`" % compression + ) + output.close_and_exit() + with closing(server): server.get_wal( args.wal_name, compression=compression, + keep_compression=keep_compression, output_directory=output_directory, peek=peek, partial=args.partial, @@ -1813,9 +1828,14 @@ def generate_manifest(args): argument( "backup_id", completer=backup_completer, help="specifies the backup ID" ), - argument("--release", help="remove the keep annotation", action="store_true"), argument( - "--status", help="return the keep status of the backup", action="store_true" + "-r", "--release", help="remove the keep annotation", action="store_true" + ), + argument( + "-s", + "--status", + help="return the keep status of the backup", + action="store_true", ), argument( "--target", @@ -1912,13 +1932,13 @@ def check_wal_archive(args): "server_name", completer=server_completer, help="specifies the name of the server which configuration should " - "be override by the model", + "be overriden by the model", ), argument( "model_name", help="specifies the name of the model which configuration should " - "override the server configuration. Not used when called with " - "the '--reset' flag", + "override the server configuration. This is an optional argument " + "and will not be used when called with the '--reset' flag.", nargs="?", ), argument( diff --git a/barman/clients/cloud_backup.py b/barman/clients/cloud_backup.py index 4f2dac93d..0d3b77dfd 100755 --- a/barman/clients/cloud_backup.py +++ b/barman/clients/cloud_backup.py @@ -45,7 +45,15 @@ UnrecoverableHookScriptError, ) from barman.postgres import PostgreSQLConnection -from barman.utils import check_backup_name, check_positive, check_size, force_str +from barman.utils import ( + check_aws_expiration_date_format, + check_aws_snapshot_lock_cool_off_period_range, + check_aws_snapshot_lock_duration_range, + check_backup_name, + check_positive, + check_size, + force_str, +) _find_space = re.compile(r"[\s]").search @@ -124,6 +132,13 @@ def _validate_config(config): raise ConfigurationException( "Compression options cannot be used with snapshot backups" ) + if getattr(config, "aws_snapshot_lock_mode", None) == "governance" and getattr( + config, "aws_snapshot_lock_cool_off_period", None + ): + raise ConfigurationException( + "'aws_snapshot_lock_mode' = 'governance' cannot be used with " + "'aws_snapshot_lock_cool_off_period'" + ) def main(args=None): @@ -419,6 +434,35 @@ def parse_arguments(args=None): "timing out (default: 3600 seconds)", type=check_positive, ) + s3_arguments.add_argument( + "--aws-snapshot-lock-mode", + help="The lock mode to apply to the snapshot. Allowed values: " + "'governance'|'compliance'.", + choices=["governance", "compliance"], + ) + s3_arguments.add_argument( + "--aws-snapshot-lock-cool-off-period", + help="Specifies the cool-off period (in hours) for a snapshot locked in " + "'compliance' mode, allowing you to unlock or modify lock settings after it is " + "locked. Range must be from 1 to 72. To lock the snapshot immediately without " + "a cool-off period, leave this option unset.", + type=check_aws_snapshot_lock_cool_off_period_range, + ) + s3_lock_target_group = s3_arguments.add_mutually_exclusive_group() + s3_lock_target_group.add_argument( + "--aws-snapshot-lock-expiration-date", + help="The expiration date for a locked snapshot in the format " + "YYYY-MM-DDThh:mm:ss.sssZ. To lock a snapshot, you must specify either this " + "argument or --aws-snapshot-lock-duration, but not both.", + type=check_aws_expiration_date_format, + ) + s3_lock_target_group.add_argument( + "--aws-snapshot-lock-duration", + help="The duration (in days) for which the snapshot should be locked. Range " + "must be from 1 to 36500. To lock a snapshopt, you must specify either this " + "argument or --aws-snapshot-lock-expiration-date, but not both.", + type=check_aws_snapshot_lock_duration_range, + ) azure_arguments.add_argument( "--encryption-scope", help="The name of an encryption scope defined in the Azure Blob Storage " @@ -434,7 +478,9 @@ def parse_arguments(args=None): help="The name of the Azure resource group to which the compute instance and " "disks defined by the --snapshot-instance and --snapshot-disk arguments belong.", ) - return parser.parse_args(args=args) + + parsed_args = parser.parse_args(args=args) + return parsed_args if __name__ == "__main__": diff --git a/barman/clients/cloud_compression.py b/barman/clients/cloud_compression.py index 20fb97a4c..1e2418498 100644 --- a/barman/clients/cloud_compression.py +++ b/barman/clients/cloud_compression.py @@ -18,10 +18,12 @@ import bz2 import gzip +import lzma import shutil from abc import ABCMeta, abstractmethod from io import BytesIO +from barman.compression import _try_import_lz4, _try_import_zstd from barman.utils import with_metaclass @@ -115,7 +117,7 @@ def compress(wal_file, compression): compressed data. :param IOBase wal_file: A file-like object containing the WAL file data. :param str compression: The compression algorithm to apply. Can be one of: - bzip2, gzip, snappy. + bzip2, gzip, snappy, zstd, lz4, xz. :return: The compressed data :rtype: BytesIO """ @@ -125,6 +127,17 @@ def compress(wal_file, compression): snappy.stream_compress(wal_file, in_mem_snappy) in_mem_snappy.seek(0) return in_mem_snappy + elif compression == "zstd": + in_mem_zstd = BytesIO() + zstd = _try_import_zstd() + zstd.ZstdCompressor().copy_stream(wal_file, in_mem_zstd) + in_mem_zstd.seek(0) + return in_mem_zstd + elif compression == "lz4": + lz4 = _try_import_lz4() + in_mem_lz4 = BytesIO(lz4.frame.compress(wal_file.read())) + in_mem_lz4.seek(0) + return in_mem_lz4 elif compression == "gzip": # Create a BytesIO for in memory compression in_mem_gzip = BytesIO() @@ -138,6 +151,10 @@ def compress(wal_file, compression): in_mem_bz2 = BytesIO(bz2.compress(wal_file.read())) in_mem_bz2.seek(0) return in_mem_bz2 + elif compression == "xz": + in_mem_xz = BytesIO(lzma.compress(wal_file.read())) + in_mem_xz.seek(0) + return in_mem_xz else: raise ValueError("Unknown compression type: %s" % compression) @@ -170,17 +187,25 @@ def decompress_to_file(blob, dest_file, compression): :param IOBase dest_file: A file-like object into which the uncompressed data should be written. :param str compression: The compression algorithm to apply. Can be one of: - bzip2, gzip, snappy. + bzip2, gzip, snappy, zstd, lz4, xz. :rtype: None """ if compression == "snappy": snappy = _try_import_snappy() snappy.stream_decompress(blob, dest_file) return + elif compression == "zstd": + zstd = _try_import_zstd() + source_file = zstd.ZstdDecompressor().stream_reader(blob) + elif compression == "lz4": + lz4 = _try_import_lz4() + source_file = lz4.frame.open(blob, mode="rb") elif compression == "gzip": source_file = gzip.GzipFile(fileobj=blob, mode="rb") elif compression == "bzip2": source_file = bz2.BZ2File(blob, "rb") + elif compression == "xz": + source_file = lzma.open(blob, "rb") else: raise ValueError("Unknown compression type: %s" % compression) diff --git a/barman/clients/cloud_walarchive.py b/barman/clients/cloud_walarchive.py index 718bce432..0dff067dd 100755 --- a/barman/clients/cloud_walarchive.py +++ b/barman/clients/cloud_walarchive.py @@ -147,6 +147,14 @@ def parse_arguments(args=None): const="bzip2", dest="compression", ) + compression.add_argument( + "--xz", + help="xz-compress the WAL while uploading to the cloud " + "(should not be used with python < 3.3)", + action="store_const", + const="xz", + dest="compression", + ) compression.add_argument( "--snappy", help="snappy-compress the WAL while uploading to the cloud " @@ -155,6 +163,21 @@ def parse_arguments(args=None): const="snappy", dest="compression", ) + compression.add_argument( + "--zstd", + help="zstd-compress the WAL while uploading to the cloud " + "(requires optional zstandard library)", + action="store_const", + const="zstd", + ) + compression.add_argument( + "--lz4", + help="lz4-compress the WAL while uploading to the cloud " + "(requires optional lz4 library)", + action="store_const", + const="lz4", + dest="compression", + ) add_tag_argument( parser, name="tags", @@ -316,9 +339,21 @@ def retrieve_wal_name(self, wal_path): # add bz2 extension return "%s.bz2" % wal_name + elif self.compression == "xz": + # add xz extension + return "%s.xz" % wal_name + elif self.compression == "snappy": # add snappy extension return "%s.snappy" % wal_name + + elif self.compression == "zstd": + # add zst extension + return "%s.zst" % wal_name + + elif self.compression == "lz4": + # add lz4 extension + return "%s.lz4" % wal_name else: raise ValueError("Unknown compression type: %s" % self.compression) diff --git a/barman/clients/walarchive.py b/barman/clients/walarchive.py index 756cc1d16..d9023b70c 100755 --- a/barman/clients/walarchive.py +++ b/barman/clients/walarchive.py @@ -181,6 +181,12 @@ def parse_arguments(args=None): "With this option, the 'wal_name' mandatory argument is " "ignored.", ) + parser.add_argument( + "--md5", + action="store_true", + help="Use MD5 as the hash algorithm to maintain compatibility between " + "mismatched client and server versions.", + ) parser.add_argument( "barman_host", metavar="BARMAN_HOST", @@ -199,14 +205,14 @@ def parse_arguments(args=None): return parser.parse_args(args=args) -def md5copyfileobj(src, dst, length=None): +def hashCopyfileobj(src, dst, length=None, hash_algorithm="sha256"): """ Copy length bytes from fileobj src to fileobj dst. If length is None, copy the entire content. This method is used by the ChecksumTarFile.addfile(). - Returns the md5 checksum + Returns the checksum for the specified hashing algorithm. """ - checksum = hashlib.md5() + checksum = hashlib.new(hash_algorithm) if length == 0: return checksum.hexdigest() @@ -248,20 +254,24 @@ def __init__(self, *args, **kwargs): class ChecksumTarFile(tarfile.TarFile): """ - Custom TarFile class that automatically calculates md5 checksum - of each file and appends a file called 'MD5SUMS' to the stream. + Custom TarFile class that automatically calculates hash checksum + of each file and appends a file called 'MD5SUMS' or 'SHA256SUMS' to the stream, + depending on the hash algorithm specified. """ + def __init__(self, *args, **kwargs): + super(ChecksumTarFile, self).__init__(*args, **kwargs) + self.hash_algorithm = "sha256" + self.HASHSUMS_FILE = "SHA256SUMS" + tarinfo = ChecksumTarInfo # The default TarInfo class used by TarFile format = tarfile.PAX_FORMAT # Use PAX format to better preserve metadata - MD5SUMS_FILE = "MD5SUMS" - def addfile(self, tarinfo, fileobj=None): """ - Add the provided fileobj to the tar using md5copyfileobj - and saves the file md5 in the provided ChecksumTarInfo object. + Add the provided fileobj to the tar using hashCopyfileobj + and saves the file hash in the provided ChecksumTarInfo object. This method completely replaces TarFile.addfile() """ @@ -275,18 +285,19 @@ def addfile(self, tarinfo, fileobj=None): # If there's data to follow, append it. if fileobj is not None: - tarinfo.data_checksum = md5copyfileobj(fileobj, self.fileobj, tarinfo.size) + tarinfo.data_checksum = hashCopyfileobj( + fileobj, self.fileobj, tarinfo.size, self.hash_algorithm + ) blocks, remainder = divmod(tarinfo.size, tarfile.BLOCKSIZE) if remainder > 0: self.fileobj.write(tarfile.NUL * (tarfile.BLOCKSIZE - remainder)) blocks += 1 self.offset += blocks * tarfile.BLOCKSIZE - self.members.append(tarinfo) def close(self): """ - Add an MD5SUMS file to the tar just before closing. + Add a :attr:`HASHSUMS_FILE` file to the tar just before closing. This method extends TarFile.close(). """ @@ -294,16 +305,16 @@ def close(self): return if self.mode in "aw": - with BytesIO() as md5sums: + with BytesIO() as hashsums: for tarinfo in self.members: line = "%s *%s\n" % (tarinfo.data_checksum, tarinfo.name) - md5sums.write(line.encode()) - md5sums.seek(0, os.SEEK_END) - size = md5sums.tell() - md5sums.seek(0, os.SEEK_SET) - tarinfo = self.tarinfo(self.MD5SUMS_FILE) + hashsums.write(line.encode()) + hashsums.seek(0, os.SEEK_END) + size = hashsums.tell() + hashsums.seek(0, os.SEEK_SET) + tarinfo = self.tarinfo(self.HASHSUMS_FILE) tarinfo.size = size - self.addfile(tarinfo, md5sums) + self.addfile(tarinfo, hashsums) super(ChecksumTarFile, self).close() @@ -334,9 +345,15 @@ def __init__(self, config, wal_path): # Register the spawned processes in the class registry self.processes.add(self.ssh_process) + # Check if md5 flag was used. + hash_settings = {True: ("md5", "MD5SUMS"), False: ("sha256", "SHA256SUMS")} + hash_algorithm, HASHSUMS_FILE = hash_settings[config.md5] + # Send the data as a tar file (containing checksums) with self.ssh_process.stdin as dest_file: with closing(ChecksumTarFile.open(mode="w|", fileobj=dest_file)) as tar: + tar.hash_algorithm = hash_algorithm + tar.HASHSUMS_FILE = HASHSUMS_FILE tar.add(wal_path, os.path.basename(wal_path)) @classmethod diff --git a/barman/clients/walrestore.py b/barman/clients/walrestore.py index d7541698b..81156abfe 100755 --- a/barman/clients/walrestore.py +++ b/barman/clients/walrestore.py @@ -31,8 +31,11 @@ import subprocess import sys import time +from tempfile import NamedTemporaryFile +from types import SimpleNamespace import barman +from barman.compression import CompressionManager, InternalCompressor from barman.utils import force_str DEFAULT_USER = "barman" @@ -57,6 +60,13 @@ def main(args=None): connectivity_test(config) return # never reached + if config.compression is not None: + print( + "WARNING: `%s` option is deprecated and will be removed in future versions. " + "For WAL compression, please make sure to enable it directly on the Barman " + "server via the `compression` configuration option" % config.compression + ) + # Check WAL destination is not a directory if os.path.isdir(config.wal_dest): exit_with_error( @@ -201,6 +211,8 @@ def build_ssh_command(config, wal_name, peek=0): options.append("--peek '%s'" % peek) if config.compression: options.append("--%s" % config.compression) + if config.keep_compression: + options.append("--keep-compression") if config.partial: options.append("--partial") @@ -353,7 +365,8 @@ def parse_arguments(args=None): dest="partial", default=False, ) - parser.add_argument( + compression_parser = parser.add_mutually_exclusive_group() + compression_parser.add_argument( "-z", "--gzip", help="Transfer the WAL files compressed with gzip", @@ -361,7 +374,7 @@ def parse_arguments(args=None): const="gzip", dest="compression", ) - parser.add_argument( + compression_parser.add_argument( "-j", "--bzip2", help="Transfer the WAL files compressed with bzip2", @@ -369,6 +382,12 @@ def parse_arguments(args=None): const="bzip2", dest="compression", ) + compression_parser.add_argument( + "--keep-compression", + help="Preserve compression during transfer, decompress once received", + action="store_true", + dest="keep_compression", + ) parser.add_argument( "-c", "--config", @@ -425,8 +444,9 @@ def __init__(self, config, wal_name, dest_file): """ self.config = config self.wal_name = wal_name - self.decompressor = None + self.source_file = None self.dest_file = None + self.decompressor_process = None # If a string has been passed, it's the name of the destination file # We convert it in a writable binary file object @@ -434,33 +454,63 @@ def __init__(self, config, wal_name, dest_file): self.dest_file = dest_file dest_file = open(dest_file, "wb") - with dest_file: - # If compression has been required, we need to spawn two processes - if config.compression: - # Spawn a remote get-wal process - self.ssh_process = subprocess.Popen( - build_ssh_command(config, wal_name), stdout=subprocess.PIPE - ) - # Spawn the local decompressor - self.decompressor = subprocess.Popen( + # Spawn a remote get-wal process + self.ssh_process = subprocess.Popen( + build_ssh_command(config, wal_name), stdout=subprocess.PIPE + ) + + # Create a temporary file with the WAL content received + self.source_file = NamedTemporaryFile( + mode="r+b", prefix=".%s." % os.path.basename(wal_name) + ) + shutil.copyfileobj(self.ssh_process.stdout, self.source_file) + self.source_file.seek(0) + + # Close the pipe descriptor, letting the ssh process receive the SIGPIPE + self.ssh_process.stdout.close() + + # Identify the WAL compression, if any + server_config = self._get_server_config_minimal(config) + compression_manager = CompressionManager(server_config, None) + compression = compression_manager.identify_compression(self.source_file.name) + + # If there's no compression then just copy the content to the destination file + if compression is None: + shutil.copyfileobj(self.source_file, dest_file) + else: + # If compression is present we proceed differently depending on the compressor + compressor = compression_manager.get_compressor(compression) + # If InternalCompressor, we can decompress directly to the destination file + if isinstance(compressor, InternalCompressor): + compressor.decompress(self.source_file.name, dest_file.name) + else: + # Otherwise it's a CommandCompressor so we spawn the local decompressor + self.decompressor_process = subprocess.Popen( [config.compression, "-d"], - stdin=self.ssh_process.stdout, + stdin=self.source_file, stdout=dest_file, ) - # Close the pipe descriptor, letting the decompressor process - # to receive the SIGPIPE - self.ssh_process.stdout.close() - else: - # With no compression only the remote get-wal process - # is required - self.ssh_process = subprocess.Popen( - build_ssh_command(config, wal_name), stdout=dest_file - ) + # close the opened file + dest_file.close() # Register the spawned processes in the class registry self.processes.add(self.ssh_process) - if self.decompressor: - self.processes.add(self.decompressor) + if self.decompressor_process: + self.processes.add(self.decompressor_process) + + def _get_server_config_minimal(self, config): + """ + Returns a placeholder for a server config object with all compression + parameters relevant to ``CompressionManager`` filled. + + :param argparse.Namespace config: the configuration from command line + """ + return SimpleNamespace( + compression=config.compression, + custom_compression_magic=None, + custom_compression_filter=None, + custom_decompression_filter=None, + ) @classmethod def wait_for_all(cls): @@ -492,9 +542,9 @@ def returncode(self): """ if self.ssh_process.returncode != 0: return self.ssh_process.returncode - if self.decompressor: - if self.decompressor.returncode != 0: - return self.decompressor.returncode + if self.decompressor_process: + if self.decompressor_process.returncode != 0: + return self.decompressor_process.returncode return 0 diff --git a/barman/cloud.py b/barman/cloud.py index b8e3cc6ec..e4024fed0 100644 --- a/barman/cloud.py +++ b/barman/cloud.py @@ -72,7 +72,14 @@ LOGGING_FORMAT = "%(asctime)s [%(process)s] %(levelname)s: %(message)s" # Allowed compression algorithms -ALLOWED_COMPRESSIONS = {".gz": "gzip", ".bz2": "bzip2", ".snappy": "snappy"} +ALLOWED_COMPRESSIONS = { + ".gz": "gzip", + ".bz2": "bzip2", + ".xz": "xz", + ".snappy": "snappy", + ".zst": "zstd", + ".lz4": "lz4", +} DEFAULT_DELIMITER = "/" diff --git a/barman/cloud_providers/__init__.py b/barman/cloud_providers/__init__.py index ed2a75085..9feacd003 100644 --- a/barman/cloud_providers/__init__.py +++ b/barman/cloud_providers/__init__.py @@ -201,6 +201,11 @@ def get_snapshot_interface(config): config.aws_profile, config.aws_region, config.aws_await_snapshots_timeout, + config.aws_snapshot_lock_mode, + config.aws_snapshot_lock_duration, + config.aws_snapshot_lock_cool_off_period, + config.aws_snapshot_lock_expiration_date, + config.tags, ] return AwsCloudSnapshotInterface(*args) else: @@ -253,6 +258,10 @@ def get_snapshot_interface_from_server_config(server_config): server_config.aws_profile, server_config.aws_region, server_config.aws_await_snapshots_timeout, + server_config.aws_snapshot_lock_mode, + server_config.aws_snapshot_lock_duration, + server_config.aws_snapshot_lock_cool_off_period, + server_config.aws_snapshot_lock_expiration_date, ) else: raise CloudProviderUnsupported( @@ -321,10 +330,16 @@ def get_snapshot_interface_from_backup_info(backup_info, config=None): # from the backup_info, unless a region is set in the config in which case the # config region takes precedence. region = None - profile = None - if config is not None and hasattr(config, "aws_region"): - region = config.aws_region - profile = config.aws_profile + if config is not None: + if hasattr(config, "aws_region"): + region = config.aws_region + try: + if getattr(config, "aws_profile"): + profile = config.aws_profile + except AttributeError: + raise SystemExit( + "Unable to locate credentials. You should configure an AWS profile." + ) if region is None: region = backup_info.snapshots_info.region return AwsCloudSnapshotInterface(profile, region) diff --git a/barman/cloud_providers/aws_s3.py b/barman/cloud_providers/aws_s3.py index cbd2360a1..340e576c5 100644 --- a/barman/cloud_providers/aws_s3.py +++ b/barman/cloud_providers/aws_s3.py @@ -16,9 +16,11 @@ # You should have received a copy of the GNU General Public License # along with Barman. If not, see +import json import logging import math import shutil +from datetime import datetime from io import RawIOBase from barman.clients.cloud_compression import decompress_to_file @@ -49,6 +51,7 @@ try: import boto3 + from boto3.s3.transfer import TransferConfig from botocore.config import Config from botocore.exceptions import ClientError, EndpointConnectionError except ImportError: @@ -85,6 +88,11 @@ class S3CloudInterface(CloudInterface): MAX_DELETE_BATCH_SIZE = 1000 + # The minimum size for a file to be uploaded using multipart upload in upload_fileobj + # 100MB is the AWS recommendation for when to start considering using multipart upload + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html + MULTIPART_THRESHOLD = 104857600 + def __getstate__(self): state = self.__dict__.copy() # Remove boto3 client reference from the state as it cannot be pickled @@ -149,6 +157,9 @@ def __init__( self.bucket_exists = None self.path = parsed_url.path.lstrip("/") + # initialize the config object to be used in uploads + self.config = TransferConfig(multipart_threshold=self.MULTIPART_THRESHOLD) + # Build a session, so we can extract the correct resource self._reinit_session() @@ -330,7 +341,11 @@ def upload_fileobj(self, fileobj, key, override_tags=None): if tags is not None: extra_args["Tagging"] = urlencode(tags) self.s3.meta.client.upload_fileobj( - Fileobj=fileobj, Bucket=self.bucket_name, Key=key, ExtraArgs=extra_args + Fileobj=fileobj, + Bucket=self.bucket_name, + Key=key, + ExtraArgs=extra_args, + Config=self.config, ) def create_multipart_upload(self, key): @@ -463,7 +478,17 @@ class AwsCloudSnapshotInterface(CloudSnapshotInterface): https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html """ - def __init__(self, profile_name=None, region=None, await_snapshots_timeout=3600): + def __init__( + self, + profile_name=None, + region=None, + await_snapshots_timeout=3600, + lock_mode=None, + lock_duration=None, + lock_cool_off_period=None, + lock_expiration_date=None, + tags=None, + ): """ Creates the client necessary for creating and managing snapshots. @@ -471,13 +496,26 @@ def __init__(self, profile_name=None, region=None, await_snapshots_timeout=3600) :param str region: The AWS region in which snapshot resources are located. :param int await_snapshots_timeout: The maximum time in seconds to wait for snapshots to complete. + :param str lock_mode: The lock mode to apply to the snapshot. + :param int lock_duration: The duration (in days) for which the snapshot + should be locked. + :param int lock_cool_off_period: The cool-off period (in hours) for the snapshot. + :param str lock_expiration_date: The expiration date for the snapshot in the format + ``YYYY-MM-DDThh:mm:ss.sssZ``. + :param List[Tuple[str, str]] tags: Key value pairs for tags to be applied. """ + self.session = boto3.Session(profile_name=profile_name) # If a specific region was provided then this overrides any region which may be # defined in the profile self.region = region or self.session.region_name self.ec2_client = self.session.client("ec2", region_name=self.region) self.await_snapshots_timeout = await_snapshots_timeout + self.tags = tags + self.lock_mode = lock_mode + self.lock_duration = lock_duration + self.lock_cool_off_period = lock_cool_off_period + self.lock_expiration_date = lock_expiration_date def _get_waiter_config(self): delay = 15 @@ -710,13 +748,19 @@ def _create_snapshot(self, backup_info, volume_name, volume_id): volume_name, volume_id, ) + tags = [ + {"Key": "Name", "Value": snapshot_name}, + ] + + if self.tags is not None: + for key, value in self.tags: + tags.append({"Key": key, "Value": value}) + resp = self.ec2_client.create_snapshot( TagSpecifications=[ { "ResourceType": "snapshot", - "Tags": [ - {"Key": "Name", "Value": snapshot_name}, - ], + "Tags": tags, } ], VolumeId=volume_id, @@ -761,10 +805,21 @@ def take_snapshot_backup(self, backup_info, instance_identifier, volumes): snapshot_name, snapshot_resp = self._create_snapshot( backup_info, volume_identifier, volume_metadata.id ) + # Apply lock on snapshot if lock mode is specified + if self.lock_mode: + self._lock_snapshot( + snapshot_resp["SnapshotId"], + self.lock_mode, + self.lock_duration, + self.lock_cool_off_period, + self.lock_expiration_date, + ) + snapshots.append( AwsSnapshotMetadata( snapshot_id=snapshot_resp["SnapshotId"], snapshot_name=snapshot_name, + snapshot_lock_mode=self.lock_mode, device_name=attached_volumes[0]["DeviceName"], mount_options=volume_metadata.mount_options, mount_point=volume_metadata.mount_point, @@ -779,10 +834,9 @@ def take_snapshot_backup(self, backup_info, instance_identifier, volumes): logging.info("Waiting for completion of snapshots: %s", ", ".join(snapshot_ids)) waiter = self.ec2_client.get_waiter("snapshot_completed") waiter.wait( - Filters=[{"Name": "snapshot-id", "Values": snapshot_ids}], + SnapshotIds=snapshot_ids, WaiterConfig=self._get_waiter_config(), ) - backup_info.snapshots_info = AwsSnapshotsInfo( snapshots=snapshots, region=self.region, @@ -791,6 +845,36 @@ def take_snapshot_backup(self, backup_info, instance_identifier, volumes): account_id=snapshot_resp["OwnerId"], ) + def _lock_snapshot( + self, + snapshot_id, + lock_mode, + lock_duration, + lock_cool_off_period, + lock_expiration_date, + ): + lock_snapshot_default_args = {"LockMode": lock_mode, "SnapshotId": snapshot_id} + + if lock_duration: + lock_snapshot_default_args["LockDuration"] = lock_duration + + if lock_cool_off_period: + lock_snapshot_default_args["CoolOffPeriod"] = lock_cool_off_period + + if lock_expiration_date: + lock_snapshot_default_args["ExpirationDate"] = lock_expiration_date + + resp = self.ec2_client.lock_snapshot(**lock_snapshot_default_args) + + _output = {} + for key, value in resp.items(): + if key != "ResponseMetadata": + if isinstance(value, datetime): + value = value.isoformat() + _output[key] = value + + logging.info("Snapshot locked: \n%s" % json.dumps(_output, indent=4)) + def _delete_snapshot(self, snapshot_id): """ Delete the specified snapshot. @@ -805,6 +889,12 @@ def _delete_snapshot(self, snapshot_id): # otherwise we raise a CloudProviderError if error_code == "InvalidSnapshot.NotFound": logging.warning("Snapshot {} could not be found".format(snapshot_id)) + elif error_code == "SnapshotLocked": + raise SystemExit( + "Locked snapshot: %s.\n" + "Before deleting a snapshot, please ensure that it is not locked " + "or that the lock has expired." % snapshot_id, + ) else: raise CloudProviderError( "Deletion of snapshot %s failed with error code %s: %s" @@ -1003,11 +1093,16 @@ class AwsSnapshotMetadata(SnapshotMetadata): """ Specialization of SnapshotMetadata for AWS EBS snapshots. - Stores the device_name, snapshot_id and snapshot_name in the provider-specific + Stores the device_name, snapshot_id, snapshot_name and snapshot_lock_mode in the provider-specific field. """ - _provider_fields = ("device_name", "snapshot_id", "snapshot_name") + _provider_fields = ( + "device_name", + "snapshot_id", + "snapshot_name", + "snapshot_lock_mode", + ) def __init__( self, @@ -1016,6 +1111,7 @@ def __init__( device_name=None, snapshot_id=None, snapshot_name=None, + snapshot_lock_mode=None, ): """ Constructor saves additional metadata for AWS snapshots. @@ -1027,12 +1123,15 @@ def __init__( :param str device_name: The device name used in the AWS API. :param str snapshot_id: The snapshot ID used in the AWS API. :param str snapshot_name: The snapshot name stored in the `Name` tag. + :param str snapshot_lock_mode: The mode with which the snapshot has been locked + (``governance`` or ``compliance``), if set. :param str project: The AWS project name. """ super(AwsSnapshotMetadata, self).__init__(mount_options, mount_point) self.device_name = device_name self.snapshot_id = snapshot_id self.snapshot_name = snapshot_name + self.snapshot_lock_mode = snapshot_lock_mode @property def identifier(self): diff --git a/barman/compression.py b/barman/compression.py index bb4f63ac3..a77d3724c 100644 --- a/barman/compression.py +++ b/barman/compression.py @@ -24,6 +24,7 @@ import bz2 import gzip import logging +import lzma import shutil from abc import ABCMeta, abstractmethod, abstractproperty from contextlib import closing @@ -407,6 +408,84 @@ def _decompressor(self, name): return bz2.BZ2File(name, mode="rb") +class XZCompressor(InternalCompressor): + """ + Predefined compressor with XZ Python library + """ + + MAGIC = b"\xfd7zXZ\x00" + + def _compressor(self, dst): + return lzma.open(dst, mode="wb") + + def _decompressor(self, src): + return lzma.open(src, mode="rb") + + +def _try_import_zstd(): + try: + import zstandard + except ImportError: + raise SystemExit("Missing required python module: zstandard") + return zstandard + + +class ZSTDCompressor(InternalCompressor): + """ + Predefined compressor with zstd + """ + + MAGIC = b"(\xb5/\xfd" + + def __init__(self, config, compression, path=None): + """ + Constructor. + :param config: barman.config.ServerConfig + :param compression: str compression name + :param path: str|None + """ + super(ZSTDCompressor, self).__init__(config, compression, path) + self._zstd = _try_import_zstd() + + def _compressor(self, dst): + return self._zstd.ZstdCompressor().stream_writer(open(dst, mode="wb")) + + def _decompressor(self, src): + return self._zstd.ZstdDecompressor().stream_reader(open(src, mode="rb")) + + +def _try_import_lz4(): + try: + import lz4.frame + except ImportError: + raise SystemExit("Missing required python module: lz4") + return lz4 + + +class LZ4Compressor(InternalCompressor): + """ + Predefined compressor with lz4 + """ + + MAGIC = b"\x04\x22\x4D\x18" + + def __init__(self, config, compression, path=None): + """ + Constructor. + :param config: barman.config.ServerConfig + :param compression: str compression name + :param path: str|None + """ + super(LZ4Compressor, self).__init__(config, compression, path) + self._lz4 = _try_import_lz4() + + def _compressor(self, dst): + return self._lz4.frame.open(dst, mode="wb") + + def _decompressor(self, src): + return self._lz4.frame.open(src, mode="rb") + + class CustomCompressor(CommandCompressor): """ Custom compressor @@ -443,6 +522,9 @@ def __init__(self, config, compression, path=None): "bzip2": BZip2Compressor, "pygzip": PyGZipCompressor, "pybzip2": PyBZip2Compressor, + "xz": XZCompressor, + "zstd": ZSTDCompressor, + "lz4": LZ4Compressor, "custom": CustomCompressor, } diff --git a/barman/config.py b/barman/config.py index 5945c64a2..0f78e430d 100644 --- a/barman/config.py +++ b/barman/config.py @@ -489,6 +489,10 @@ class ServerConfig(BaseConfig): "archiver_batch_size", "autogenerate_manifest", "aws_await_snapshots_timeout", + "aws_snapshot_lock_mode", + "aws_snapshot_lock_duration", + "aws_snapshot_lock_cool_off_period", + "aws_snapshot_lock_expiration_date", "aws_profile", "aws_region", "azure_credential", @@ -587,6 +591,10 @@ class ServerConfig(BaseConfig): "archiver_batch_size", "autogenerate_manifest", "aws_await_snapshots_timeout", + "aws_snapshot_lock_mode", + "aws_snapshot_lock_duration", + "aws_snapshot_lock_cool_off_period", + "aws_snapshot_lock_expiration_date", "aws_profile", "aws_region", "azure_credential", @@ -710,6 +718,8 @@ class ServerConfig(BaseConfig): "archiver_batch_size": int, "autogenerate_manifest": parse_boolean, "aws_await_snapshots_timeout": int, + "aws_snapshot_lock_duration": int, + "aws_snapshot_lock_cool_off_period": int, "backup_compression": parse_backup_compression, "backup_compression_format": parse_backup_compression_format, "backup_compression_level": int, @@ -947,20 +957,18 @@ def get_wal_conninfo(self): :rtype: (str,str) :return: Tuple consisting of the ``wal_streaming_conninfo`` and - ``wal_conninfo`` defined in the configuration if ``wal_streaming_conninfo`` - is set, a tuple of ``streaming_conninfo`` and ``conninfo`` otherwise. - """ - wal_streaming_conninfo, wal_conninfo = None, None - if self.wal_streaming_conninfo is not None: - wal_streaming_conninfo = self.wal_streaming_conninfo - if self.wal_conninfo is not None: - wal_conninfo = self.wal_conninfo - else: - wal_conninfo = self.wal_streaming_conninfo + ``wal_conninfo``. + """ + # If `wal_streaming_conninfo` is not set, fall back to `streaming_conninfo` + wal_streaming_conninfo = self.wal_streaming_conninfo or self.streaming_conninfo + + # If `wal_conninfo` is not set, fall back to `wal_streaming_conninfo`. If + # `wal_streaming_conninfo` is not set, fall back to `conninfo`. + if self.wal_conninfo is not None: + wal_conninfo = self.wal_conninfo + elif self.wal_streaming_conninfo is not None: + wal_conninfo = self.wal_streaming_conninfo else: - # If wal_streaming_conninfo is not set then return the original - # streaming_conninfo and conninfo parameters - wal_streaming_conninfo = self.streaming_conninfo wal_conninfo = self.conninfo return wal_streaming_conninfo, wal_conninfo diff --git a/barman/infofile.py b/barman/infofile.py index 76fc76b47..f4df25d9a 100644 --- a/barman/infofile.py +++ b/barman/infofile.py @@ -1064,6 +1064,23 @@ def is_full_and_eligible_for_incremental(self): return True return False + @property + def is_orphan(self): + """ + Determine if the backup is an orphan. + + An orphan backup is defined as a backup directory that contains only + a non-empty backup.info file. This may indicate an incomplete delete operation. + + :return bool: ``True`` if the backup is an orphan, ``False`` otherwise. + """ + backup_dir = self.get_basebackup_directory() + backup_info_path = os.path.join(backup_dir, "backup.info") + if os.path.exists(backup_dir) and os.path.exists(backup_info_path): + if len(os.listdir(backup_dir)) == 1 and self.status != BackupInfo.EMPTY: + return True + return False + class SyntheticBackupInfo(LocalBackupInfo): def __init__( diff --git a/barman/output.py b/barman/output.py index 119411aea..d5815092c 100644 --- a/barman/output.py +++ b/barman/output.py @@ -551,7 +551,7 @@ def result_recovery(self, results): ) self.info( "You need to manually restore them " - "in order to start the recovered PostgreSQL instance:" + "in order to start the restored PostgreSQL instance:" ) self.info("") for file_name in results["missing_files"]: @@ -580,7 +580,7 @@ def result_recovery(self, results): ) self.info("") self.info( - "Recovery completed (start time: %s, elapsed time: %s)", + "Restore operation completed (start time: %s, elapsed time: %s)", results["recovery_start_time"], human_readable_timedelta( datetime.datetime.now(tz.tzlocal()) - results["recovery_start_time"] diff --git a/barman/recovery_executor.py b/barman/recovery_executor.py index aadd84382..11814753d 100644 --- a/barman/recovery_executor.py +++ b/barman/recovery_executor.py @@ -239,7 +239,7 @@ def recover( data = LocalBackupInfo(self.server, backup_info.filename) if data.status == BackupInfo.WAITING_FOR_WALS: output.warning( - "IMPORTANT: The backup we have recovered IS NOT " + "IMPORTANT: The backup we have restored IS NOT " "VALID. Required WAL files for consistency are " "missing. Please verify that WAL archiving is " "working correctly or evaluate using the 'get-wal' " @@ -1864,7 +1864,7 @@ def recover(self, backup_info, dest, remote_command=None, **kwargs): # raise a warning at the end so the user can optionally take action about it if not backup_info.is_checksum_consistent(): output.warning( - "You recovered from an incremental backup where checksums were enabled on " + "You restored from an incremental backup where checksums were enabled on " "that backup, but not all backups in the chain. It is advised to disable, and " "optionally re-enable, checksums on the destination directory to avoid failures." ) diff --git a/barman/retention_policies.py b/barman/retention_policies.py index ec8b820f7..5845a4ed3 100644 --- a/barman/retention_policies.py +++ b/barman/retention_policies.py @@ -141,10 +141,6 @@ def _propagate_retention_status_to_children(self, backup_info, report, ret_statu :param str ret_status: The status of the backup according to retention policies """ - # As KEEP status doesn't make sense for incremental backups, we simply - # set them as VALID if their root full backup has KEEP annotation - if ret_status in (BackupInfo.KEEP_STANDALONE, BackupInfo.KEEP_FULL): - ret_status = BackupInfo.VALID backup_tree = backup_info.walk_backups_tree(return_self=False) for backup in backup_tree: report[backup.backup_id] = ret_status @@ -222,6 +218,19 @@ def _backup_report(self, source): if backups[bid].has_children: status = report[bid] + # If the root backup retention status is KEEP:STANDALONE and the backup + # is still VALID for retention policy, the incremental backups will have + # the VALID retention status. But if this backup falls outside the + # retention policy, it will be kept but the incremental backups will get + # the status OBSOLETE. + if status == BackupInfo.KEEP_STANDALONE: + status = BackupInfo.VALID + if i > redundancy: + status = BackupInfo.OBSOLETE + # If the root backup retention status is KEEP:FULL, the incremental + # backups will have the VALID retention status. + elif status == BackupInfo.KEEP_FULL: + status = BackupInfo.VALID self._propagate_retention_status_to_children( backup_info=backups[bid], report=report, @@ -402,6 +411,19 @@ def _backup_report(self, source): if backups[bid].has_children: status = report[bid] + # If the root backup retention status is KEEP:STANDALONE and the backup + # is still VALID for retention policy, the incremental backups will have + # the VALID retention status. But if this backup falls outside the + # retention policy, it will be kept but the incremental backups will get + # the status OBSOLETE. + if status == BackupInfo.KEEP_STANDALONE: + status = BackupInfo.VALID + if found: + status = BackupInfo.OBSOLETE + # If the root backup retention status is KEEP:FULL, the incremental + # backups will have the VALID retention status. + elif status == BackupInfo.KEEP_FULL: + status = BackupInfo.VALID self._propagate_retention_status_to_children( backup_info=backups[bid], report=report, diff --git a/barman/server.py b/barman/server.py index 9a35986b2..2b2f070c9 100644 --- a/barman/server.py +++ b/barman/server.py @@ -90,7 +90,7 @@ from barman.retention_policies import RetentionPolicy, RetentionPolicyFactory from barman.utils import ( BarmanEncoder, - file_md5, + file_hash, force_str, fsync_dir, fsync_file, @@ -136,6 +136,7 @@ class CheckStrategy(object): "incoming WALs directory", "streaming WALs directory", "wal maximum age", + "PostgreSQL server is standby", ] def __init__(self, ignore_checks=NON_CRITICAL_CHECKS): @@ -299,7 +300,18 @@ def _init_postgres(self, config): config.slot_name, config.primary_checkpoint_timeout, ) - else: + # If primary_conninfo is set but conninfo does not point to a standby + # it could be that a failover happend and the standby has been promoted. + # In this case, don't set a standby connection and just warn the user. + # A standard connection will be set further so that Barman keeps working. + if self.postgres.is_in_recovery is False: + self.postgres.close() + self.postgres = None + output.warning( + "'primary_conninfo' is set but 'conninfo' does not point to a " + "standby server. Ignoring 'primary_conninfo'." + ) + if self.postgres is None: self.postgres = PostgreSQLConnection( config.conninfo, config.immediate_checkpoint, config.slot_name ) @@ -886,7 +898,7 @@ def check_wal_streaming(self, check_strategy): # If we have wal-specific conninfo then we must use those to get # the remote status information for the check streaming_conninfo, conninfo = self.config.get_wal_conninfo() - if streaming_conninfo != self.config.streaming_conninfo: + if conninfo != self.config.conninfo: with closing(StreamingConnection(streaming_conninfo)) as streaming, closing( PostgreSQLConnection(conninfo, slot_name=self.config.slot_name) ) as postgres: @@ -1007,9 +1019,12 @@ def _check_standby(self, check_strategy): :param CheckStrategy check_strategy: The strategy for the management of the results of the various checks. """ + is_standby_conn = isinstance(self.postgres, StandbyPostgreSQLConnection) + # Check that standby is standby check_strategy.init_check("PostgreSQL server is standby") - is_in_recovery = self.postgres.is_in_recovery + # The server only is in recovery if we have a standby connection and pg_is_in_recovery() is True + is_in_recovery = is_standby_conn and self.postgres.is_in_recovery if is_in_recovery: check_strategy.result(self.config.name, True) else: @@ -1022,6 +1037,11 @@ def _check_standby(self, check_strategy): ), ) + # if we don't have a standby connection object then we can't perform + # any of the further checks as they require a primary reference + if not is_standby_conn: + return + # Check that primary is not standby check_strategy.init_check("Primary server is not a standby") primary_is_in_recovery = self.postgres.primary.is_in_recovery @@ -2148,6 +2168,7 @@ def get_wal( self, wal_name, compression=None, + keep_compression=False, output_directory=None, peek=None, partial=False, @@ -2157,6 +2178,7 @@ def get_wal( :param str wal_name: id of the WAL file to find into the WAL archive :param str|None compression: compression format for the output + :param bool keep_compression: if True, do not uncompress compressed WAL files :param str|None output_directory: directory where to deposit the WAL file :param int|None peek: if defined list the next N WAL file @@ -2291,7 +2313,9 @@ def get_wal( try: # Try returning the wal_file to the client - self.get_wal_sendfile(wal_file, compression, destination) + self.get_wal_sendfile( + wal_file, compression, keep_compression, destination + ) # We are done, return to the caller return except CommandFailedException: @@ -2323,12 +2347,13 @@ def get_wal( source_suffix, ) - def get_wal_sendfile(self, wal_file, compression, destination): + def get_wal_sendfile(self, wal_file, compression, keep_compression, destination): """ Send a WAL file to the destination file, using the required compression :param str wal_file: WAL file path :param str compression: required compression + :param bool keep_compression: if True, do not uncompress compressed WAL files :param destination: file stream to use to write the data """ # Identify the wal file @@ -2350,37 +2375,38 @@ def get_wal_sendfile(self, wal_file, compression, destination): uncompressed_file = None compressed_file = None - # If the required compression is different from the source we - # decompress/compress it into the required format (getattr is - # used here to gracefully handle None objects) - if getattr(wal_compressor, "compression", None) != getattr( - out_compressor, "compression", None - ): - # If source is compressed, decompress it into a temporary file - if wal_compressor is not None: - uncompressed_file = NamedTemporaryFile( - dir=self.config.wals_directory, - prefix=".%s." % os.path.basename(wal_file), - suffix=".uncompressed", - ) - # decompress wal file - try: - wal_compressor.decompress(source_file, uncompressed_file.name) - except CommandFailedException as exc: - output.error("Error decompressing WAL: %s", str(exc)) - return - source_file = uncompressed_file.name - - # If output compression is required compress the source - # into a temporary file - if out_compressor is not None: - compressed_file = NamedTemporaryFile( - dir=self.config.wals_directory, - prefix=".%s." % os.path.basename(wal_file), - suffix=".compressed", - ) - out_compressor.compress(source_file, compressed_file.name) - source_file = compressed_file.name + if not keep_compression: + # If the required compression is different from the source we + # decompress/compress it into the required format (getattr is + # used here to gracefully handle None objects) + if getattr(wal_compressor, "compression", None) != getattr( + out_compressor, "compression", None + ): + # If source is compressed, decompress it into a temporary file + if wal_compressor is not None: + uncompressed_file = NamedTemporaryFile( + dir=self.config.wals_directory, + prefix=".%s." % os.path.basename(wal_file), + suffix=".uncompressed", + ) + # decompress wal file + try: + wal_compressor.decompress(source_file, uncompressed_file.name) + except CommandFailedException as exc: + output.error("Error decompressing WAL: %s", str(exc)) + return + source_file = uncompressed_file.name + + # If output compression is required compress the source + # into a temporary file + if out_compressor is not None: + compressed_file = NamedTemporaryFile( + dir=self.config.wals_directory, + prefix=".%s." % os.path.basename(wal_file), + suffix=".compressed", + ) + out_compressor.compress(source_file, compressed_file.name) + source_file = compressed_file.name # Copy the prepared source file to destination with open(source_file, "rb") as input_file: @@ -2429,7 +2455,9 @@ def put_wal(self, fileobj): # The closing wrapper is needed only for Python 2.6 extracted_files = {} validated_files = {} - md5sums = {} + hashsums = {} + extracted_files_with_checksums = {} + hash_algorithm = "sha256" try: with closing(tarfile.open(mode="r|", fileobj=fileobj)) as tar: for item in tar: @@ -2458,7 +2486,7 @@ def put_wal(self, fileobj): ) return # Checksum file - if name == "MD5SUMS": + if name in ("MD5SUMS", "SHA256SUMS"): # Parse content and store it in md5sums dictionary for line in tar.extractfile(item).readlines(): line = line.decode().rstrip() @@ -2477,7 +2505,9 @@ def put_wal(self, fileobj): # Strip leading './' from path in the checksum file if path.startswith("./"): path = path[2:] - md5sums[path] = checksum + hashsums[path] = checksum + if name == "MD5SUMS": + hash_algorithm = "md5" else: # Extract using a temp name (with PID) tmp_path = os.path.join( @@ -2488,15 +2518,25 @@ def put_wal(self, fileobj): # Set the original timestamp tar.utime(item, tmp_path) # Add the tuple to the dictionary of extracted files - extracted_files[name] = incoming_file( - name, tmp_path, path, file_md5(tmp_path) + extracted_files[name] = dict( + name=name, + tmp_path=tmp_path, + path=path, ) validated_files[name] = False + for name, _dict in extracted_files.items(): + extracted_files_with_checksums[name] = incoming_file( + _dict["name"], + _dict["tmp_path"], + _dict["path"], + file_hash(_dict["tmp_path"], hash_algorithm=hash_algorithm), + ) + # For each received checksum verify the corresponding file - for name in md5sums: + for name in hashsums: # Check that file is present in the tar archive - if name not in extracted_files: + if name not in extracted_files_with_checksums: output.error( "Checksum without corresponding file '%s' " "in put-wal for server '%s'%s", @@ -2506,13 +2546,13 @@ def put_wal(self, fileobj): ) return # Verify the checksum of the file - if extracted_files[name].checksum != md5sums[name]: + if extracted_files_with_checksums[name].checksum != hashsums[name]: output.error( "Bad file checksum '%s' (should be %s) " "for file '%s' " "in put-wal for server '%s'%s", - extracted_files[name].checksum, - md5sums[name], + extracted_files_with_checksums[name].checksum, + hashsums[name], name, self.config.name, source_suffix, @@ -2522,14 +2562,14 @@ def put_wal(self, fileobj): "Received file '%s' with checksum '%s' " "by put-wal for server '%s'%s", name, - md5sums[name], + hashsums[name], self.config.name, source_suffix, ) validated_files[name] = True # Put the files in the final place, atomically and fsync all - for item in extracted_files.values(): + for item in extracted_files_with_checksums.values(): # Final verification of checksum presence for each file if not validated_files[item.name]: output.error( @@ -2558,7 +2598,7 @@ def put_wal(self, fileobj): fsync_dir(dest_dir) finally: # Cleanup of any remaining temp files (where applicable) - for item in extracted_files.values(): + for item in extracted_files_with_checksums.values(): if os.path.exists(item.tmp_path): os.unlink(item.tmp_path) diff --git a/barman/utils.py b/barman/utils.py index 413246014..64991de8f 100644 --- a/barman/utils.py +++ b/barman/utils.py @@ -570,25 +570,27 @@ def is_power_of_two(number): return number != 0 and (number & (number - 1)) == 0 -def file_md5(file_path, buffer_size=1024 * 16): +def file_hash(file_path, buffer_size=1024 * 16, hash_algorithm="sha256"): """ - Calculate the md5 checksum for the provided file path + Calculate the checksum for the provided file path with a specific + hashing algorithm :param str file_path: path of the file to read :param int buffer_size: read buffer size, default 16k + :param str hash_algorithm: sha256 | md5 :return str: Hexadecimal md5 string """ - md5 = hashlib.md5() + hash_func = hashlib.new(hash_algorithm) with open(file_path, "rb") as file_object: while 1: buf = file_object.read(buffer_size) if not buf: break - md5.update(buf) - return md5.hexdigest() + hash_func.update(buf) + return hash_func.hexdigest() -# Might be better to use stream instead of full file content. As done in file_md5. +# Might be better to use stream instead of full file content. As done in file_hash. # Might create performance issue for large files. class ChecksumAlgorithm(with_metaclass(ABCMeta)): @abstractmethod @@ -726,6 +728,89 @@ def check_positive(value): return int_value +def check_aws_expiration_date_format(value): + """ + Check user input for aws expiration date timestamp with a specific format. + + :param value: str containing the value to check. + :raise ValueError: Fails with an invalid date. + """ + fmt = "%Y-%m-%dT%H:%M:%S.%fZ" + try: + # Attempt to parse the input date string into a datetime object + return datetime.datetime.strptime(value, fmt) + except ValueError: + raise ArgumentTypeError( + "Invalid date: '%s'. Expected format is '%s'." % (value, fmt) + ) + + +def check_aws_snapshot_lock_duration_range(value): + """ + Check for AWS Snapshot Lock duration range option + + :param value: str containing the value to check + """ + if value is None: + return None + try: + int_value = int(value) + except Exception: + raise ArgumentTypeError("'%s' is not a valid input" % value) + + if not 1 <= int_value <= 36500: + raise ValueError( + "aws_snapshot_lock_duration must be between 1 and 36,500 days." + ) + + return int_value + + +def check_aws_snapshot_lock_cool_off_period_range(value): + """ + Check for AWS Snapshot Lock cool-off period range option + + :param value: str containing the value to check + """ + if value is None: + return None + try: + int_value = int(value) + except Exception: + raise ArgumentTypeError("'%s' is not a valid input" % value) + + if not 1 <= int_value <= 72: + raise ValueError( + "aws_snapshot_lock_cool_off_period must be between 1 and 72 hours." + ) + + return int_value + + +def check_aws_snapshot_lock_mode(value): + """ + Replication slot names may only contain lower case letters, numbers, + and the underscore character. This function parse a replication slot name + + :param str value: slot_name value + :return: + """ + + AWS_SNAPSHOT_LOCK_MODE = ["governance", "compliance"] + if value is None: + return None + + value = value.lower() + if value not in AWS_SNAPSHOT_LOCK_MODE: + raise ValueError( + "Invalid AWS snapshot lock mode. " + "Please specify either 'governance' or 'compliance'. " + "Ensure that the mode you choose aligns with your snapshot locking " + "requirements." + ) + return value + + def check_tli(value): """ Check for a positive integer option, and also make "current" and "latest" acceptable values diff --git a/barman/version.py b/barman/version.py index a0430c656..9ae4d82f5 100644 --- a/barman/version.py +++ b/barman/version.py @@ -20,4 +20,4 @@ This module contains the current Barman version. """ -__version__ = "3.11.1" +__version__ = "3.12.0" diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 000000000..e2947be01 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,47 @@ +# This Dockerfile resides in this path because it is the source docker image to build the +# documentation via github actions. There is no other use for it. + +# Use Debian as the base image +FROM debian:latest + +# Switch to the root user +USER root + +# Install necessary dependencies for Sphinx +RUN set -x \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y -o Acquire::Retries=10 --no-install-recommends \ + build-essential \ + libpq-dev \ + python3 \ + python3-dev \ + python3-venv \ + python3-pip \ + python3-setuptools \ + python3-sphinx \ + latexmk \ + tex-common \ + tex-gyre \ + texlive-base \ + texlive-binaries \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-pictures \ + texlive-plain-generic \ + git \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Set sphinx version + +# Create virtual env to install python dependencies +RUN python3 -m venv /opt/venv + +# Add virtual env bin path to PATH +ENV PATH="/opt/venv/bin:$PATH" + +# Install Sphinx and any additional Python dependencies +RUN pip3 install --upgrade pip \ + && pip3 install tox diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..d4bb2cbb9 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..ec884a219 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,40 @@ +# User documentation and man pages + +The user documentation and the man pages for Barman are built using Sphinx. +All the docs content and the configuration for Sphinx are found inside the `docs` +directory. + +There is an automation through tox to build the docs, which takes care of +installing all the required Python modules. + +From the root directory, install the dependencies of tox: + +```bash +pip install -r requirements-tox.txt +``` + +Then, to generate the docs you can just use the tox environment `docs`: + +* For HTML docs: + +```bash +tox -e docs -- html +``` + +* For man pages: + +```bash +tox -e docs -- man +``` + +* For PDF docs: + +```bash +tox -e docs -- latexpdf +``` + +Once the build finishes, you can read the built documentation: + +* For HTML docs: open `docs/_build/html/index.html` with your web browser; +* For man pages: run `man docs/_build/man/barman.1`; +* For PDF docs: open `docs/_build/latex/Barman.pdf` with your PDF reader. diff --git a/docs/_build/man/barman-archive-wal.1 b/docs/_build/man/barman-archive-wal.1 new file mode 100644 index 000000000..e71d32863 --- /dev/null +++ b/docs/_build/man/barman-archive-wal.1 @@ -0,0 +1,59 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-ARCHIVE-WAL" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-archive-wal \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +archive\-wal SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Fetch WAL files received from either the standard \fBarchive_command\fP or streaming +replication with \fBpg_receivewal\fP and store them in the server\(aqs WAL archive. If you +have enabled \fBcompression\fP in the configuration file, the WAL files will be compressed +before they are archived. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-backup.1 b/docs/_build/man/barman-backup.1 new file mode 100644 index 000000000..2bfd084f2 --- /dev/null +++ b/docs/_build/man/barman-backup.1 @@ -0,0 +1,197 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-backup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +backup + [ \-\-bwlimit KBPS ] + [ \-\-incremental BACKUP_ID ] + [ \-\-immediate\-checkpoint ] + [ { \-j, \-\-jobs } PARALLEL_WORKERS ] + [ \-\-jobs\-start\-batch\-period PERIOD ] + [ \-\-jobs\-start\-batch\-size SIZE ] + [ \-\-keepalive\-interval SECONDS ] + [ \-\-manifest ] + [ \-\-name NAME ] + [ \-\-no\-immediate\-checkpoint ] + [ \-\-no\-manifest ] + [ \-\-no\-retry ] + [ \-\-retry\-sleep SECONDS ] + [ \-\-retry\-times NUMBER ] + [ \-\-reuse\-backup { off | copy | link } ] + [ { \-\-wait | \-w } ] + [ \-\-wait\-timeout SECONDS ] + SERVER_NAME [ ... ] +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Execute a PostreSQL server backup. Barman will use the parameters specified in the Global +and Server configuration files. Specify \fBall\fP shortcut instead of the server name to +execute backups from all servers configured in the Barman node. You can also specify +multiple server names in sequence to execute backups for specific servers. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-bwlimit\fP +Specify the maximum transfer rate in kilobytes per second. A value of 0 indicates no +limit. This setting overrides the \fBbandwidth_limit\fP configuration option. +.TP +.B \fB\-\-incremental\fP +Execute a block\-level incremental backup. You must provide a \fBBACKUP_ID\fP or a +shortcut to a previous backup, which will serve as the parent backup for the +incremental backup. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +The backup to be and the parent backup must have \fBbackup_method=postgres\fP\&. +.UNINDENT +.UNINDENT +.TP +.B \fB\-\-immediate\-checkpoint\fP +Forces the initial checkpoint to be executed as soon as possible, overriding any +value set for the \fBimmediate_checkpoint\fP parameter in the configuration file. +.TP +.B \fB\-j\fP / \fB\-\-jobs\fP +Specify the number of parallel workers to use for copying files during the backup. +This setting overrides the \fBparallel_jobs\fP parameter if it\(aqs specified in the +configuration file. +.TP +.B \fB\-\-jobs\-start\-batch\-period\fP +Specify the time period, in seconds, for starting a single batch of jobs. This value +overrides the \fBparallel_jobs_start_batch_period\fP parameter if it is set in the +configuration file. The default is \fB1\fP second. +.TP +.B \fB\-\-jobs\-start\-batch\-size\fP +Specify the maximum number of parallel workers to initiate in a single batch. This +value overrides the \fBparallel_jobs_start_batch_size\fP parameter if it is defined in +the configuration file. The default is \fB10\fP workers. +.TP +.B \fB\-\-keepalive\-interval\fP +Specify an interval, in seconds, for sending a heartbeat query to the server to keep +the libpq connection active during a Rsync backup. The default is \fB60\fP seconds. A +value of \fB0\fP disables the heartbeat. +.TP +.B \fB\-\-manifest\fP +Forces the creation of a backup manifest file upon completing a backup. Overrides the +\fBautogenerate_manifest\fP parameter from the configuration file. Applicable only to +rsync backup strategy. +.TP +.B \fB\-\-name\fP +Specify a friendly name for this backup which can be used in place of the backup ID +in barman commands. +.TP +.B \fB\-\-no\-immediate\-checkpoint\fP +Forces the backup to wait for the checkpoint to be executed overriding any value set +for the \fBimmediate_checkpoint\fP parameter in the configuration file. +.TP +.B \fB\-\-no\-manifest\fP +Disables the automatic creation of a backup manifest file upon completing a backup. +This setting overrides the \fBautogenerate_manifest\fP parameter from the configuration +file and applies only to rsync backup strategy. +.TP +.B \fB\-\-no\-retry\fP +There will be no retry in case of an error. It is the same as setting +\fB\-\-retry\-times 0\fP\&. +.TP +.B \fB\-\-retry\-sleep\fP +Specify the number of seconds to wait after a failed copy before retrying. This +setting applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_sleep\fP parameter if it is defined in the configuration file. +.TP +.B \fB\-\-retry\-times\fP +Specify the number of times to retry the base backup copy in case of an error. This +applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_times\fP parameter if it is set in the configuration file. +.TP +.B \fB\-\-reuse\-backup\fP +Overrides the behavior of the \fBreuse_backup\fP option configured in the configuration +file. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBoff\fP: Do not reuse the last available backup. +.IP \(bu 2 +\fBcopy\fP: Reuse the last available backup for a server and create copies of +unchanged files (reduces backup time). +.IP \(bu 2 +\fBlink\fP (default): Reuse the last available backup for a server and create +hard links to unchanged files (saves both backup time and space). +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This will only have any effect if the last available backup was +executed with \fBbackup_method=rsync\fP\&. +.UNINDENT +.UNINDENT +.TP +.B \fB\-\-wait\fP / \fB\-w\fP +Wait for all necessary WAL files required by the base backup to be archived. +.TP +.B \fB\-\-wait\-timeout\fP +Specify the duration, in seconds, to wait for the required WAL files to be archived +before timing out. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-check-backup.1 b/docs/_build/man/barman-check-backup.1 new file mode 100644 index 000000000..7eb82aff6 --- /dev/null +++ b/docs/_build/man/barman-check-backup.1 @@ -0,0 +1,99 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CHECK-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-check-backup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +check\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Check that all necessary WAL files for verifying the consistency of a physical backup are +properly archived. This command is automatically executed by the cron job and at the end +of each backup operation. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-check.1 b/docs/_build/man/barman-check.1 new file mode 100644 index 000000000..c34ce0544 --- /dev/null +++ b/docs/_build/man/barman-check.1 @@ -0,0 +1,81 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CHECK" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-check \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +check [ \-\-nagios ] SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display status information about a server, such as SSH connection, Postgres version, +configuration and backup directories, archiving and streaming processes, replication +slots, and more. Use \fBall\fP as shortcut to show diagnostic information for all +configured servers. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-nagios\fP +Nagios plugin compatible output. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-backup-delete.1 b/docs/_build/man/barman-cloud-backup-delete.1 new file mode 100644 index 000000000..188e4e5d3 --- /dev/null +++ b/docs/_build/man/barman-cloud-backup-delete.1 @@ -0,0 +1,198 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-BACKUP-DELETE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-backup-delete \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-backup\-delete + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-r | \-\-retention\-policy } RETENTION_POLICY ] + [ { \-m | \-\-minimum\-redundancy } MINIMUM_REDUNDANCY ] + [ { \-b | \-\-backup\-id } BACKUP_ID] + [ \-\-dry\-run ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [\-\-batch\-size DELETE_BATCH_SIZE] + SOURCE_URL SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +The \fBbarman\-cloud\-backup\-delete\fP script is used to delete one or more backups created +with the \fBbarman\-cloud\-backup\fP command from cloud storage and to remove the associated +WAL files. +.sp +Backups can be specified for deletion either by their backup ID +(as obtained from \fBbarman\-cloud\-backup\-list\fP) or by a retention policy. Retention +policies mirror those used by the Barman server, deleting all backups that are not required to +meet the specified policy. When a backup is deleted, any unused WAL files associated with +that backup are also removed. +.sp +WALs are considered unused if: +.INDENT 0.0 +.IP \(bu 2 +The WALs predate the begin_wal value of the oldest remaining backup. +.IP \(bu 2 +The WALs are not required by any archival backups stored in the cloud. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBIMPORTANT:\fP +.INDENT 0.0 +.INDENT 3.5 +Each backup deletion involves three separate requests to the cloud provider: one for +the backup files, one for the \fBbackup.info\fP file, and one for the associated WALs. +Deleting by retention policy may result in a high volume of delete requests if a +large number of backups are accumulated in cloud storage. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that holds the backup to be deleted. +.TP +.B \fBSOURCE_URL\fP +URL of the cloud source, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-b\fP / \fB\-\-backup\-id\fP +ID of the backup to be deleted +.TP +.B \fB\-m\fP / \fB\-\-minimum\-redundancy\fP +The minimum number of backups that should always be available. +.TP +.B \fB\-r\fP / \fB\-\-retention\-policy\fP +If specified, delete all backups eligible for deletion according to the supplied +retention policy. +.sp +Syntax: \fBREDUNDANCY value | RECOVERY WINDOW OF value { DAYS | WEEKS | MONTHS }\fP +.TP +.B \fB\-\-batch\-size\fP +The maximum number of objects to be deleted in a single request to the cloud provider. +If unset then the maximum allowed batch size for the specified cloud provider will be +used (\fB1000\fP for aws\-s3, \fB256\fP for azure\-blob\-storage and \fB100\fP for +google\-cloud\-storage). +.TP +.B \fB\-\-dry\-run\fP +Find the objects which need to be deleted but do not delete them. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-backup-keep.1 b/docs/_build/man/barman-cloud-backup-keep.1 new file mode 100644 index 000000000..5690f3fa4 --- /dev/null +++ b/docs/_build/man/barman-cloud-backup-keep.1 @@ -0,0 +1,173 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-BACKUP-KEEP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-backup-keep \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-backup\-keep + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ { \-r | \-\-release } ] + [ { \-s | \-\-status } ] + [ \-\-target { full | standalone } ] + SOURCE_URL SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +Use this script to designate backups in cloud storage as archival backups, ensuring +their indefinite retention regardless of retention policies. +.sp +This script allows you to mark backups previously created with \fBbarman\-cloud\-backup\fP +as archival backups. Once flagged as archival, these backups are preserved indefinitely +and are not subject to standard retention policies. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that holds the backup to be kept. +.TP +.B \fBSOURCE_URL\fP +URL of the cloud source, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fBBACKUP_ID\fP +The ID of the backup to be kept. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-r\fP / \fB\-\-release\fP +If specified, the command will remove the keep annotation and the backup will be +eligible for deletion. +.TP +.B \fB\-s\fP / \fB\-\-status\fP +Print the keep status of the backup. +.TP +.B \fB\-\-target\fP +Specify the recovery target for this backup. Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBfull\fP +.IP \(bu 2 +\fBstandalone\fP +.UNINDENT +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-backup-list.1 b/docs/_build/man/barman-cloud-backup-list.1 new file mode 100644 index 000000000..ee5095dc5 --- /dev/null +++ b/docs/_build/man/barman-cloud-backup-list.1 @@ -0,0 +1,151 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-BACKUP-LIST" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-backup-list \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-backup\-list + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-format ] + SOURCE_URL SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +This script lists backups stored in the cloud that were created using the +\fBbarman\-cloud\-backup\fP command. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that holds the backup to be listed. +.TP +.B \fBSOURCE_URL\fP +URL of the cloud source, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-\-format\fP +Output format (\fBconsole\fP or \fBjson\fP). Default \fBconsole\fP\&. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-backup-show.1 b/docs/_build/man/barman-cloud-backup-show.1 new file mode 100644 index 000000000..2b0fab017 --- /dev/null +++ b/docs/_build/man/barman-cloud-backup-show.1 @@ -0,0 +1,153 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-BACKUP-SHOW" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-backup-show \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-backup\-show + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-format ] + SOURCE_URL SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +This script displays detailed information about a specific backup created with the +\fBbarman\-cloud\-backup\fP command. The output is similar to the \fBbarman show\-backup\fP +from the \fI\%barman show\-backup\fP command reference, +but it has fewer information. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that holds the backup to be displayed. +.TP +.B \fBSOURCE_URL\fP +URL of the cloud source, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-\-format\fP +Output format (\fBconsole\fP or \fBjson\fP). Default \fBconsole\fP\&. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-backup.1 b/docs/_build/man/barman-cloud-backup.1 new file mode 100644 index 000000000..3848a2eab --- /dev/null +++ b/docs/_build/man/barman-cloud-backup.1 @@ -0,0 +1,327 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-backup \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-backup + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ { \-z | \-\-gzip } ] + [ { \-j | \-\-bzip2 } ] + [ \-\-snappy ] + [ { \-h | \-\-host } HOST ] + [ { \-p | \-\-port } PORT ] + [ { \-U | \-\-user } USER ] + [ { \-d | \-\-dbname } DBNAME ] + [ { \-n | \-\-name } BACKUP_NAME ] + [ { \-J | \-\-jobs } JOBS ] + [ \-S MAX_ARCHIVE_SIZE ] + [ \-\-immediate\-checkpoint ] + [ \-\-min\-chunk\-size MIN_CHUNK_SIZE ] + [ \-\-max\-bandwidth MAX_BANDWIDTH ] + [ \-\-snapshot\-instance SNAPSHOT_INSTANCE ] + [ \-\-snapshot\-disk NAME ] + [ \-\-tags [ TAGS ... ] ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ { \-e | \-\-encryption } ENCRYPTION ] + [ \-\-sse\-kms\-key\-id SSE_KMS_KEY_ID ] + [ \-\-aws\-region AWS_REGION ] + [ \-\-aws\-snapshot\-lock\-mode { compliance | governance } ] + [ \-\-aws\-snapshot\-lock\-duration DAYS ] + [ \-\-aws\-snapshot\-lock\-cool\-off\-period HOURS ] + [ \-\-aws\-snapshot\-lock\-expiration\-date DATETIME ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-encryption\-scope ENCRYPTION_SCOPE ] + [ \-\-azure\-subscription\-id AZURE_SUBSCRIPTION_ID ] + [ \-\-azure\-resource\-group AZURE_RESOURCE_GROUP ] + [ \-\-gcp\-project GCP_PROJECT ] + [ \-\-kms\-key\-name KMS_KEY_NAME ] + [ \-\-gcp\-zone GCP_ZONE ] + DESTINATION_URL SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +The \fBbarman\-cloud\-backup\fP script is used to create a local backup of a Postgres +server and transfer it to a supported cloud provider, bypassing the Barman server. It +can also be utilized as a hook script for copying Barman backups from the Barman server +to one of the supported clouds (post_backup_retry_script). +.sp +This script requires read access to PGDATA and tablespaces, typically run as the +postgres user. When used on a Barman server, it requires read access to the directory +where Barman backups are stored. If \fB\-\-snapshot\-\fP arguments are used and snapshots are +supported by the selected cloud provider, the backup will be performed using snapshots +of the specified disks (\fB\-\-snapshot\-disk\fP). The backup label and metadata will also be +uploaded to the cloud. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBIMPORTANT:\fP +.INDENT 0.0 +.INDENT 3.5 +The cloud upload may fail if any file larger than the configured \fB\-\-max\-archive\-size\fP +is present in the data directory or tablespaces. However, Postgres files up to +\fB1GB\fP are always allowed, regardless of the \fB\-\-max\-archive\-size\fP setting. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server to be backed up. +.TP +.B \fBDESTINATION_URL\fP +URL of the cloud destination, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +gzip\-compress the backup while uploading to the cloud (should not be used with python < +3.2). +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +bzip2\-compress the backup while uploading to the cloud (should not be used with python < +3.3). +.TP +.B \fB\-\-snappy\fP +snappy\-compress the backup while uploading to the cloud (requires optional +\fBpython\-snappy\fP library). +.TP +.B \fB\-h\fP / \fB\-\-host\fP +Host or Unix socket for Postgres connection (default: libpq settings). +.TP +.B \fB\-p\fP / \fB\-\-port\fP +Port for Postgres connection (default: libpq settings). +.TP +.B \fB\-U\fP / \fB\-\-user\fP +User name for Postgres connection (default: libpq settings). +.TP +.B \fB\-d\fP / \fB\-\-dbname\fP +Database name or conninfo string for Postgres connection (default: \(dqpostgres\(dq). +.TP +.B \fB\-n\fP / \fB\-\-name\fP +A name which can be used to reference this backup in commands such as +\fBbarman\-cloud\-restore\fP and \fBbarman\-cloud\-backup\-delete\fP\&. +.TP +.B \fB\-J\fP / \fB\-\-jobs\fP +Number of subprocesses to upload data to cloud storage (default: \fB2\fP). +.TP +.B \fB\-S\fP / \fB\-\-max\-archive\-size\fP +Maximum size of an archive when uploading to cloud storage (default: \fB100GB\fP). +.TP +.B \fB\-\-min\-chunk\-size\fP +Minimum size of an individual chunk when uploading to cloud storage (default: \fB5MB\fP +for \fBaws\-s3\fP, \fB64KB\fP for \fBazure\-blob\-storage\fP, not applicable for +\fBgoogle\-cloud\-storage\fP). +.TP +.B \fB\-\-max\-bandwidth\fP +The maximum amount of data to be uploaded per second when backing up to object +storages (default: \fB0\fP \- no limit). +.TP +.B \fB\-\-snapshot\-instance\fP +Instance where the disks to be backed up as snapshots are attached. +.TP +.B \fB\-\-snapshot\-disk\fP +Name of a disk from which snapshots should be taken. +.TP +.B \fB\-\-tags\fP +Tags to be added to archived WAL files in cloud storage and to snapshots created, if +snapshots are used. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.TP +.B \fB\-e\fP / \fB\-\-encryption\fP +The encryption algorithm used when storing the uploaded data in S3. +.sp +Allowed options: +.INDENT 7.0 +.IP \(bu 2 +\fBAES256\fP\&. +.IP \(bu 2 +\fBaws:kms\fP\&. +.UNINDENT +.TP +.B \fB\-\-sse\-kms\-key\-id\fP +The AWS KMS key ID that should be used for encrypting the uploaded data in S3. Can be +specified using the key ID on its own or using the full ARN for the key. Only allowed if +\fB\-e\fP / \fB\-\-encryption\fP is set to \fBaws:kms\fP\&. +.TP +.B \fB\-\-aws\-region\fP +The name of the AWS region containing the EC2 VM and storage volumes defined by the +\fB\-\-snapshot\-instance\fP and \fB\-\-snapshot\-disk\fP arguments. +.TP +.B \fB\-\-aws\-snapshot\-lock\-mode\fP +The lock mode for the snapshot. This is only valid if \fB\-\-snapshot\-instance\fP and +\fB\-\-snapshot\-disk\fP are set. +.sp +Allowed options: +.INDENT 7.0 +.IP \(bu 2 +\fBcompliance\fP\&. +.IP \(bu 2 +\fBgovernance\fP\&. +.UNINDENT +.TP +.B \fB\-\-aws\-snapshot\-lock\-duration\fP +The lock duration is the period of time (in days) for which the snapshot is to remain +locked, ranging from 1 to 36,500. Set either the lock duration or the expiration date +(not both). +.TP +.B \fB\-\-aws\-snapshot\-lock\-cool\-off\-period\fP +The cooling\-off period is an optional period of time (in hours) that you can specify +when you lock a snapshot in \fBcompliance\fP mode, ranging from 1 to 72. +.TP +.B \fB\-\-aws\-snapshot\-lock\-expiration\-date\fP +The lock duration is determined by an expiration date in the future. It must be at +least 1 day after the snapshot creation date and time, using the format +\fBYYYY\-MM\-DDTHH:MM:SS.sssZ\fP\&. Set either the lock duration or the expiration date +(not both). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.TP +.B \fB\-\-encryption\-scope\fP +The name of an encryption scope defined in the Azure Blob Storage service which is to +be used to encrypt the data in Azure. +.TP +.B \fB\-\-azure\-subscription\-id\fP +The ID of the Azure subscription which owns the instance and storage volumes defined by +the \fB\-\-snapshot\-instance\fP and \fB\-\-snapshot\-disk\fP arguments. +.TP +.B \fB\-\-azure\-resource\-group\fP +The name of the Azure resource group to which the compute instance and disks defined by +the \fB\-\-snapshot\-instance\fP and \fB\-\-snapshot\-disk\fP arguments belong. +.UNINDENT +.sp +\fBExtra options for GCP cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-gcp\-project\fP +GCP project under which disk snapshots should be stored. +.TP +.B \fB\-\-snapshot\-gcp\-project\fP (deprecated) +GCP project under which disk snapshots should be stored \- replaced by +\fB\-\-gcp\-project\fP\&. +.TP +.B \fB\-\-kms\-key\-name\fP +The name of the GCP KMS key which should be used for encrypting the uploaded data in +GCS. +.TP +.B \fB\-\-gcp\-zone\fP +Zone of the disks from which snapshots should be taken. +.TP +.B \fB\-\-snapshot\-zone\fP (deprecated) +Zone of the disks from which snapshots should be taken \- replaced by \fB\-\-gcp\-zone\fP\&. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-check-wal-archive.1 b/docs/_build/man/barman-cloud-check-wal-archive.1 new file mode 100644 index 000000000..139bff105 --- /dev/null +++ b/docs/_build/man/barman-cloud-check-wal-archive.1 @@ -0,0 +1,151 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-CHECK-WAL-ARCHIVE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-check-wal-archive \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-check\-wal\-archive + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-timeline TIMELINE ] + DESTINATION_URL SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +Verify that the WAL archive destination for a server is suitable for use with a new +Postgres cluster. By default, the check will succeed if the WAL archive is empty or if +the target bucket is not found. Any other conditions will result in a failure. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that needs to be checked. +.TP +.B \fBDESTINATION_URL\fP +URL of the cloud destination, such as a bucket in AWS S3. For example: \fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-\-timeline\fP +The earliest timeline whose WALs should cause the check to fail. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-restore.1 b/docs/_build/man/barman-cloud-restore.1 new file mode 100644 index 000000000..1ff14e144 --- /dev/null +++ b/docs/_build/man/barman-cloud-restore.1 @@ -0,0 +1,185 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-RESTORE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-restore \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-restore + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-snapshot\-recovery\-instance SNAPSHOT_RECOVERY_INSTANCE ] + [ \-\-aws\-region AWS_REGION ] + [ \-\-gcp\-zone GCP_ZONE ] + [ \-\-azure\-resource\-group AZURE_RESOURCE_GROUP ] + [ \-\-tablespace NAME:LOCATION ] + SOURCE_URL SERVER_NAME BACKUP_ID RECOVERY_DESTINATION +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +Use this script to restore a backup directly from cloud storage that was created with +the \fBbarman\-cloud\-backup\fP command. Additionally, this script can prepare for recovery +from a snapshot backup by verifying that attached disks were cloned from the correct +snapshots and by downloading the backup label from object storage. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that holds the backup to be restored. +.TP +.B \fBSOURCE_URL\fP +URL of the cloud source, such as a bucket in AWS S3. For example: +\fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fBBACKUP_ID\fP +The ID of the backup to be restored. +.TP +.B \fBRECOVERY_DESTINATION\fP +The path to a directory for recovery. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-\-snapshot\-recovery\-instance\fP +Instance where the disks recovered from the snapshots are attached. +.TP +.B \fB\-\-tablespace\fP +Tablespace relocation rule. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.TP +.B \fB\-\-aws\-region\fP +The name of the AWS region containing the EC2 VM and storage volumes defined by the +\fB\-\-snapshot\-instance\fP and \fB\-\-snapshot\-disk\fP arguments. +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.TP +.B \fB\-\-azure\-resource\-group\fP +The name of the Azure resource group to which the compute instance and disks defined by +the \fB\-\-snapshot\-instance\fP and \fB\-\-snapshot\-disk\fP arguments belong. +.UNINDENT +.sp +\fBExtra options for GCP cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-gcp\-zone\fP +Zone of the disks from which snapshots should be taken. +.TP +.B \fB\-\-snapshot\-recovery\-zone\fP (deprecated) +Zone containing the instance and disks for the snapshot recovery \- replaced by +\fB\-\-gcp\-zone\fP\&. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-wal-archive.1 b/docs/_build/man/barman-cloud-wal-archive.1 new file mode 100644 index 000000000..fadfd5d98 --- /dev/null +++ b/docs/_build/man/barman-cloud-wal-archive.1 @@ -0,0 +1,233 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-WAL-ARCHIVE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-wal-archive \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-wal\-archive + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ { \-z | \-\-gzip } ] + [ { \-j | \-\-bzip2 } ] + [ \-\-snappy ] + [ \-\-tags [ TAGS ... ] ] + [ \-\-history\-tags [ HISTORY_TAGS ... ] ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ { \-e | \-\-encryption } ENCRYPTION ] + [ \-\-sse\-kms\-key\-id SSE_KMS_KEY_ID ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-encryption\-scope ENCRYPTION_SCOPE ] + [ \-\-max\-block\-size MAX_BLOCK_SIZE ] + [ \-\-max\-concurrency MAX_CONCURRENCY ] + [ \-\-max\-single\-put\-size MAX_SINGLE_PUT_SIZE ] + [ \-\-kms\-key\-name KMS_KEY_NAME ] + DESTINATION_URL SERVER_NAME [ WAL_PATH ] +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +The \fBbarman\-cloud\-wal\-archive\fP command is designed to be used in the +\fBarchive_command\fP of a Postgres server to directly ship WAL files to cloud storage. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +If you are using Python 2 or unsupported versions of Python 3, avoid using the +compression options \fB\-\-gzip\fP or \fB\-\-bzip2\fP\&. The script cannot restore +gzip\-compressed WALs on Python < 3.2 or bzip2\-compressed WALs on Python < 3.3. +.UNINDENT +.UNINDENT +.sp +This script enables the direct transfer of WAL files to cloud storage, bypassing the +Barman server. Additionally, it can be utilized as a hook script for WAL archiving +(pre_archive_retry_script). +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that will have the WALs archived. +.TP +.B \fBDESTINATION_URL\fP +URL of the cloud destination, such as a bucket in AWS S3. For example: \fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fBWAL_PATH\fP +The value of the \(aq%p\(aq keyword (according to \fBarchive_command\fP). +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +gzip\-compress the WAL while uploading to the cloud (should not be used with python < +3.2). +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +bzip2\-compress the WAL while uploading to the cloud (should not be used with python < +3.3). +.TP +.B \fB\-\-snappy\fP +snappy\-compress the WAL while uploading to the cloud (requires optional +\fBpython\-snappy\fP library). +.TP +.B \fB\-\-tags\fP +Tags to be added to archived WAL files in cloud storage. +.TP +.B \fB\-\-history\-tags\fP +Tags to be added to archived history files in cloud storage. +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.TP +.B \fB\-e\fP / \fB\-\-encryption\fP +The encryption algorithm used when storing the uploaded data in S3. +.sp +Allowed options: +.INDENT 7.0 +.IP \(bu 2 +\fBAES256\fP\&. +.IP \(bu 2 +\fBaws:kms\fP\&. +.UNINDENT +.TP +.B \fB\-\-sse\-kms\-key\-id\fP +The AWS KMS key ID that should be used for encrypting the uploaded data in S3. Can be +specified using the key ID on its own or using the full ARN for the key. Only allowed if +\fB\-e\fP / \fB\-\-encryption\fP is set to \fBaws:kms\fP\&. +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.TP +.B \fB\-\-encryption\-scope\fP +The name of an encryption scope defined in the Azure Blob Storage service which is to +be used to encrypt the data in Azure. +.TP +.B \fB\-\-max\-block\-size\fP +The chunk size to be used when uploading an object via the concurrent chunk method +(default: \fB4MB\fP). +.TP +.B \fB\-\-max\-concurrency\fP +The maximum number of chunks to be uploaded concurrently (default: \fB1\fP). +.TP +.B \fB\-\-max\-single\-put\-size\fP +Maximum size for which the Azure client will upload an object in a single request +(default: \fB64MB\fP). If this is set lower than the Postgres WAL segment size after +any applied compression then the concurrent chunk upload method for WAL archiving will +be used. +.UNINDENT +.sp +\fBExtra options for GCP cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-kms\-key\-name\fP +The name of the GCP KMS key which should be used for encrypting the uploaded data in +GCS. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cloud-wal-restore.1 b/docs/_build/man/barman-cloud-wal-restore.1 new file mode 100644 index 000000000..1a2e81361 --- /dev/null +++ b/docs/_build/man/barman-cloud-wal-restore.1 @@ -0,0 +1,172 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CLOUD-WAL-RESTORE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cloud-wal-restore \- Barman-cloud Commands +.sp +\fBSynopsis\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-cloud\-wal\-restore + [ { \-V | \-\-version } ] + [ \-\-help ] + [ { \-v | \-\-verbose } ] + [ { \-q | \-\-quiet } ] + [ { \-t | \-\-test } ] + [ \-\-cloud\-provider { aws\-s3 | azure\-blob\-storage | google\-cloud\-storage } ] + [ \-\-endpoint\-url ENDPOINT_URL ] + [ { \-P | \-\-aws\-profile } AWS_PROFILE ] + [ \-\-read\-timeout READ_TIMEOUT ] + [ \-\-azure\-credential { azure\-cli | managed\-identity } ] + [ \-\-no\-partial ] + DESTINATION_URL SERVER_NAME WAL_NAME WAL_DEST +.EE +.UNINDENT +.UNINDENT +.sp +\fBDescription\fP +.sp +The \fBbarman\-cloud\-wal\-restore\fP script functions as the \fBrestore_command\fP for +retrieving WAL files from cloud storage and placing them directly into a Postgres +standby server, bypassing the Barman server. +.sp +This script is used to download WAL files that were previously archived with the +\fBbarman\-cloud\-wal\-archive\fP command. Disable automatic download of \fB\&.partial\fP files by +calling \fB\-\-no\-partial\fP option. +.sp +\fBIMPORTANT:\fP +.INDENT 0.0 +.INDENT 3.5 +On the target Postgres node, when \fBpg_wal\fP and the spool directory are on the +same filesystem, files are moved via renaming, which is faster than copying and +deleting. This speeds up serving WAL files significantly. If the directories are on +different filesystems, the process still involves copying and deleting, so there\(aqs +no performance gain in that case. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +For GCP, only authentication with \fBGOOGLE_APPLICATION_CREDENTIALS\fP env is supported. +.UNINDENT +.UNINDENT +.sp +\fBParameters\fP +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server that will have WALs restored. +.TP +.B \fBDESTINATION_URL\fP +URL of the cloud destination, such as a bucket in AWS S3. For example: \fBs3://bucket/path/to/folder\fP\&. +.TP +.B \fBWAL_NAME\fP +The value of the \(aq%f\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fBWAL_DEST\fP +The value of the \(aq%p\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Show version and exit. +.TP +.B \fB\-\-help\fP +show this help message and exit. +.TP +.B \fB\-v\fP / \fB\-\-verbose\fP +Increase output verbosity (e.g., \fB\-vv\fP is more than \fB\-v\fP). +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Decrease output verbosity (e.g., \fB\-qq\fP is less than \fB\-q\fP). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test cloud connectivity and exit. +.TP +.B \fB\-\-cloud\-provider\fP +The cloud provider to use as a storage backend. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBaws\-s3\fP\&. +.IP \(bu 2 +\fBazure\-blob\-storage\fP\&. +.IP \(bu 2 +\fBgoogle\-cloud\-storage\fP\&. +.UNINDENT +.TP +.B \fB\-\-no\-partial\fP +Do not download partial WAL files +.UNINDENT +.sp +\fBExtra options for the AWS cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-endpoint\-url\fP +Override default S3 endpoint URL with the given one. +.TP +.B \fB\-P\fP / \fB\-\-aws\-profile\fP +Profile name (e.g. \fBINI\fP section in AWS credentials file). +.TP +.B \fB\-\-profile\fP (deprecated) +Profile name (e.g. \fBINI\fP section in AWS credentials file) \- replaced by +\fB\-\-aws\-profile\fP\&. +.TP +.B \fB\-\-read\-timeout\fP +The time in seconds until a timeout is raised when waiting to read from a connection +(defaults to \fB60\fP seconds). +.UNINDENT +.sp +\fBExtra options for the Azure cloud provider\fP +.INDENT 0.0 +.TP +.B \fB\-\-azure\-credential / \-\-credential\fP +Optionally specify the type of credential to use when authenticating with Azure. If +omitted then Azure Blob Storage credentials will be obtained from the environment and +the default Azure authentication flow will be used for authenticating with all other +Azure services. If no credentials can be found in the environment then the default +Azure authentication flow will also be used for Azure Blob Storage. +.sp +Allowed options are: +.INDENT 7.0 +.IP \(bu 2 +\fBazure\-cli\fP\&. +.IP \(bu 2 +\fBmanaged\-identity\fP\&. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-config-switch.1 b/docs/_build/man/barman-config-switch.1 new file mode 100644 index 000000000..447c31e67 --- /dev/null +++ b/docs/_build/man/barman-config-switch.1 @@ -0,0 +1,72 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CONFIG-SWITCH" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-config-switch \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +config\-switch SERVER_NAME { \-\-reset | MODEL_NAME } +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Apply a set of configuration overrides from the model to a server in Barman. The final +configuration will combine or override the server\(aqs existing settings with the ones +specified in the model. You can reset the server configurations with the \fB\-\-reset\fP +argument. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only one model can be active at a time for a given server. +.UNINDENT +.UNINDENT +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fBMODEL_NAME\fP +Name of the model. +.TP +.B \fB\-\-reset\fP +Reset the server\(aqs configurations. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-config-update.1 b/docs/_build/man/barman-config-update.1 new file mode 100644 index 000000000..9be5f605c --- /dev/null +++ b/docs/_build/man/barman-config-update.1 @@ -0,0 +1,76 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CONFIG-UPDATE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-config-update \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +config\-update STRING +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Create or update the configurations for servers and/or models in Barman. The parameter +should be a JSON string containing an array of documents. Each document must include a +\fBscope\fP key, which can be either server or model, and either a \fBserver_name\fP or +\fBmodel_name\fP key, depending on the scope value. Additionally, the document should +include other keys representing Barman configuration options and their desired values. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The barman \fBconfig\-update\fP command writes configuration options to a file named +\fB\&.barman.auto.conf\fP, located in the \fBbarman_home\fP directory. This configuration +file has higher precedence and will override values from the global Barman +configuration file (usually \fB/etc/barman.conf\fP) and from any included files specified +in \fBconfiguration_files_directory\fP (typically files in \fB/etc/barman.d\fP). Be aware +of this if you decide to manually modify configuration options in those files later. +.UNINDENT +.UNINDENT +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSTRING\fP +List of JSON formatted string. +.UNINDENT +.SH EXAMPLE +.sp +\fBJSON_STRING=\(aq[{“scope”: “server”, “server_name”: “my_server”, “archiver”: +“on”, “streaming_archiver”: “off”}]\(aq\fP +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-cron.1 b/docs/_build/man/barman-cron.1 new file mode 100644 index 000000000..a1dd322dd --- /dev/null +++ b/docs/_build/man/barman-cron.1 @@ -0,0 +1,57 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-CRON" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-cron \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +cron [ \-\-keep\-descriptors ] +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Carry out maintenance tasks, such as enforcing retention policies or managing WAL files. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fB\-\-keep\-descriptors\fP +Keep the ^stdout^ and ^stderr^ streams of the Barman subprocesses connected to the +main process. This is especially useful for Docker\-based installations. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-delete.1 b/docs/_build/man/barman-delete.1 new file mode 100644 index 000000000..828b633e5 --- /dev/null +++ b/docs/_build/man/barman-delete.1 @@ -0,0 +1,97 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-DELETE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-delete \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +delete SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Delete the specified backup. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-diagnose.1 b/docs/_build/man/barman-diagnose.1 new file mode 100644 index 000000000..76d94919f --- /dev/null +++ b/docs/_build/man/barman-diagnose.1 @@ -0,0 +1,53 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-DIAGNOSE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-diagnose \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +diagnose +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display diagnostic information about the Barman node, which is the server where Barman +is installed, as well as all configured Postgres servers. This includes details such as +global configuration, SSH version, Python version, rsync version, the current +configuration and status of all servers, and many more. +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-generate-manifest.1 b/docs/_build/man/barman-generate-manifest.1 new file mode 100644 index 000000000..2d9702112 --- /dev/null +++ b/docs/_build/man/barman-generate-manifest.1 @@ -0,0 +1,98 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-GENERATE-MANIFEST" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-generate-manifest \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +generate\-manifest SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Generates a \fBbackup_manifest\fP file for a backup. You can use a shortcut instead of +\fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-get-wal.1 b/docs/_build/man/barman-get-wal.1 new file mode 100644 index 000000000..66b65a1b5 --- /dev/null +++ b/docs/_build/man/barman-get-wal.1 @@ -0,0 +1,103 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-GET-WAL" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-get-wal \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +get\-wal + [ \-j ] + [ \-o OUTPUT_DIRECTORY ] + [ \-p VALUE ] + [ { \-P | \-\-partial } ] + [ { \-t | \-\-test } ] + [ \-z ] + SERVER_NAME WAL_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Retrieve a WAL file from the xlog archive of a specified server. By default, if the +requested WAL file is found, it is returned as uncompressed content to \fBSTDOUT\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBWAL_NAME\fP +Id of the backup in barman catalog. +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +Output will be compressed using bzip2. +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +Output will be compressed using gzip. +.TP +.B \fB\-\-keep\-compression\fP +Do not uncompress the file content. The output will be the original compressed +file. +.TP +.B \fB\-o\fP +Destination directory where barman will store the WAL file. +.TP +.B \fB\-p\fP +Specify an integer value greater than or equal to 1 to retrieve WAL files from the +specified WAL file up to the value specified by this parameter. When using this option, +\fBget\-wal\fP returns a list of zero to the specified WAL segment names, with one name +per row. +.TP +.B \fB\-P\fP / \fB\-\-partial\fP +Additionally, collect partial WAL files (.partial). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test both the connection and configuration of the specified Postgres server in +Barman for WAL retrieval. When this option is used, the required \fBWAL_NAME\fP +argument is disregarded. +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +\fB\-z\fP / \fB\-\-gzip\fP and \fB\-j\fP / \fB\-\-bzip2\fP options are deprecated and will be +removed in the future. For WAL compression, please make sure to enable it directly +on the Barman server via the \fBcompression\fP configuration option. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-keep.1 b/docs/_build/man/barman-keep.1 new file mode 100644 index 000000000..82e537f72 --- /dev/null +++ b/docs/_build/man/barman-keep.1 @@ -0,0 +1,124 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-KEEP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-keep \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +keep + { \-\-release | \-\-status | \-\-target { full | standalone } } + SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Mark the specified backup with a \fBtarget\fP as an archival backup to be retained +indefinitely, overriding any active retention policies. You can also check the keep +\fBstatus\fP of a backup and \fBrelease\fP the keep mark from a backup. You can use a +shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fB\-\-release\fP +Release the keep mark from this backup. This will remove its archival status and +make it available for deletion, either directly or by retention policy. +.TP +.B \fB\-\-status\fP +Report the archival status of the backup. The status will be either \fBfull\fP or +\fBstandalone\fP for archival backups, or \fBnokeep\fP for backups that have not been +designated as archival. +.TP +.B \fB\-\-target\fP +Define the recovery target for the archival backup. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBfull\fP: The backup can be used to recover to the most recent point in time. To +support this, Barman will keep all necessary WALs to maintain the backup\(aqs +consistency as well as any subsequent WALs. +.IP \(bu 2 +\fBstandalone\fP: The backup can only be used to restore the server to its state at the +time of the backup. Barman will retain only the WALs required to ensure the +backup\(aqs consistency. +.UNINDENT +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-list-files.1 b/docs/_build/man/barman-list-files.1 new file mode 100644 index 000000000..73cea5bde --- /dev/null +++ b/docs/_build/man/barman-list-files.1 @@ -0,0 +1,114 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-LIST-FILES" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-list-files \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-files + [ \-\-target { data | full | standalone | wal } ] + SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +List all files in a specific backup. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fB\-\-target\fP +Define specific files to be listed. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBstandalone\fP (default): List the base backup files, including required WAL files. +.IP \(bu 2 +\fBdata\fP: List just the data files. +.IP \(bu 2 +\fBwal\fP: List all the WAL files between the start of the base backup and the end of +the log or the start of the following base backup (depending on whether the +specified base backup is the most recent one available). +.IP \(bu 2 +\fBfull\fP: same as \fBdata\fP + \fBwal\fP\&. +.UNINDENT +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-list-servers.1 b/docs/_build/man/barman-list-servers.1 new file mode 100644 index 000000000..4ce524396 --- /dev/null +++ b/docs/_build/man/barman-list-servers.1 @@ -0,0 +1,56 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-LIST-SERVERS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-list-servers \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-servers [ \-\-minimal ] +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display all configured servers along with their descriptions. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fB\-\-minimal\fP +Machine readable output. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-list_backups.1 b/docs/_build/man/barman-list_backups.1 new file mode 100644 index 000000000..6cd6b2de9 --- /dev/null +++ b/docs/_build/man/barman-list_backups.1 @@ -0,0 +1,77 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-LIST_BACKUPS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-list_backups \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-backups SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display the available backups for a server. This command is useful for retrieving both +the backup ID and the backup type. You can find details about this command in +\fI\%Catalog usage\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-lock-directory-cleanup.1 b/docs/_build/man/barman-lock-directory-cleanup.1 new file mode 100644 index 000000000..02b7bd4e2 --- /dev/null +++ b/docs/_build/man/barman-lock-directory-cleanup.1 @@ -0,0 +1,50 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-LOCK-DIRECTORY-CLEANUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-lock-directory-cleanup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +lock\-directory\-cleanup +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Automatically removes unused lock files from the \fBbarman_lock_directory\fP\&. +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-put-wal.1 b/docs/_build/man/barman-put-wal.1 new file mode 100644 index 000000000..278a93302 --- /dev/null +++ b/docs/_build/man/barman-put-wal.1 @@ -0,0 +1,66 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-PUT-WAL" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-put-wal \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +put\-wal [ { \-t | \-\-test } ] SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Receive a WAL file from a remote server and securely save it into the server incoming +directory. The WAL file should be provided via \fBSTDIN\fP, encapsulated in a tar stream +along with a \fBSHA256SUMS\fP or \fBMD5SUMS\fP file for validation (\fBsha256\fP is the default +hash algorithm, but the user can choose \fBmd5\fP when setting the \fBarchive\-command\fP via +\fBbarman\-wal\-archive\fP). This command is intended to be executed via SSH from a remote +\fBbarman\-wal\-archive\fP utility (included in the barman\-cli package). Avoid using this +command directly unless you fully manage the content of the files. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test both the connection and configuration of the specified Postgres +server in Barman for WAL retrieval. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-rebuild-xlogdb.1 b/docs/_build/man/barman-rebuild-xlogdb.1 new file mode 100644 index 000000000..53ec3da31 --- /dev/null +++ b/docs/_build/man/barman-rebuild-xlogdb.1 @@ -0,0 +1,77 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-REBUILD-XLOGDB" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-rebuild-xlogdb \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +rebuild\-xlogdb SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Rebuild the WAL file metadata for a server (or for all servers using the \fBall\fP shortcut) +based on the disk content. The WAL archive metadata is stored in the \fBxlog.db\fP file, +with each Barman server maintaining its own copy. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-receive-wal.1 b/docs/_build/man/barman-receive-wal.1 new file mode 100644 index 000000000..05d493a70 --- /dev/null +++ b/docs/_build/man/barman-receive-wal.1 @@ -0,0 +1,78 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-RECEIVE-WAL" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-receive-wal \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +receive\-wal + [ \-\-create\-slot ] + [ \-\-drop\-slot ] + [ \-\-reset ] + [ \-\-stop ] + SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Initiate the streaming of transaction logs for a server. This process uses +\fBpg_receivewal\fP or \fBpg_receivexlog\fP to receive WAL files from Postgres servers via +the streaming protocol. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-create\-slot\fP +Create the physical replication slot configured with the \fBslot_name\fP configuration +parameter. +.TP +.B \fB\-\-drop\-slot\fP +Drop the physical replication slot configured with the \fBslot_name\fP configuration +parameter. +.TP +.B \fB\-\-reset\fP +Reset the status of \fBreceive\-wal\fP, restarting the streaming from the current WAL file +of the server. +.TP +.B \fB\-\-stop\fP +Stop the process for the server. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-recover.1 b/docs/_build/man/barman-recover.1 new file mode 100644 index 000000000..6e8904390 --- /dev/null +++ b/docs/_build/man/barman-recover.1 @@ -0,0 +1,274 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-RECOVER" "1" "Oct 10, 2024" "3.11" "Barman" +.SH NAME +barman-recover \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +recover + [ \-\-aws\-region AWS_REGION } ] + [ \-\-azure\-resource\-group AZURE_RESOURCE_GRP ] + [ \-\-bwlimit KBPS ] + [ \-\-exclusive ] + [ \-\-gcp\-zone GCP_ZONE ] + [ \-\-get\-wal | \-\-no\-get\-wal ] + [ { \-j | \-\-jobs } PARALLEL_WORKERS ] + [ \-\-jobs\-start\-batch\-period SECONDS ] + [ \-\-jobs\-start\-batch\-size NUMBER ] + [ \-\-local\-staging\-path PATH ] + [ \-\-network\-compression | \-\-no\-network\-compression ] + [ \-\-no\-retry ] + [ \-\-recovery\-conf\-filename FILENAME ] + [ \-\-recovery\-staging\-path PATH ] + [ \-\-remote\-ssh\-command STRING ] + [ \-\-retry\-sleep SECONDS ] + [ \-\-retry\-times NUMBER ] + [ \-\-snapshot\-recovery\-instance INSTANCE_NAME ] + [ \-\-standby\-mode ] + [ \-\-tablespace NAME:LOCATION ] + [ \-\-target\-action { pause | shutdown | promote } ] + [ \-\-target\-immediate ] + [ \-\-target\-lsn LSN ] + [ \-\-target\-name RESTORE_POINT_NAME ] + [ \-\-target\-time TIMESTAMP ] + [ \-\-target\-tli TLI ] + [ \-\-target\-xid XID ] + SERVER_NAME BACKUP_ID DESTINATION_DIR +.ft P +.fi +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Execute a PostreSQL server recovery operation. Barman will recover the backup from a +server in the destination directory. The recovery can be performed locally (on the +barman node itself) or remotely (on another machine accessible via SSH). The location is +determined by whether or not the \fB\-\-remote\-ssh\-command\fP option is used. More +information on this command can be found in the \fI\%Recovery\fP section. You can use a +shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fBDESTINATION_DIR\fP +Destination directory to recover. +.TP +.B \fB\-\-aws\-region\fP +Specify the AWS region where the instance and disks for snapshot recovery are +located. This option allows you to override the \fBaws_region\fP value in the Barman +configuration. +.TP +.B \fB\-\-azure\-resource\-group\fP +Specify the Azure resource group containing the instance and disks for snapshot +recovery. This option allows you to override the \fBazure_resource_group\fP value in +the Barman configuration. +.TP +.B \fB\-\-bwlimit\fP +Specify the maximum transfer rate in kilobytes per second. A value of \fB0\fP +indicates no limit. This setting overrides the \fBbandwidth_limit\fP configuration +option. +.TP +.B \fB\-\-exclusive\fP +Set target (time, XID or LSN) to be non inclusive. +.TP +.B \fB\-\-gcp\-zone\fP +Specify the GCP zone where the instance and disks for snapshot recovery are located. +This option allows you to override the \fBgcp_zone\fP value in the Barman +configuration. +.TP +.B \fB\-\-get\-wal\fP / \fB\-\-no\-get\-wal\fP +Enable/disable usage of \fBget\-wal\fP for WAL fetching during recovery. Default is based on +\fBrecovery_options\fP setting. +.TP +.B \fB\-j\fP / \fB\-\-jobs\fP +Specify the number of parallel workers to use for copying files during the backup. +This setting overrides the \fBparallel_jobs\fP parameter if it is specified in the +configuration file. +.TP +.B \fB\-\-jobs\-start\-batch\-period\fP +Specify the time period, in seconds, for starting a single batch of jobs. This value +overrides the \fBparallel_jobs_start_batch_period\fP parameter if it is set in the +configuration file. The default is \fB1\fP second. +.TP +.B \fB\-\-jobs\-start\-batch\-size\fP +Specify the maximum number of parallel workers to initiate in a single batch. This +value overrides the \fBparallel_jobs_start_batch_size\fP parameter if it is defined in +the configuration file. The default is \fB10\fP workers. +.TP +.B \fB\-\-local\-staging\-path\fP +Specify path on the Barman host where the chain of backups will be combined before +being copied to the destination directory. The contents created within the staging +path will be removed upon completion of the recovery process. This option is +necessary for recovering from block\-level incremental backups and has no effect +otherwise. +.TP +.B \fB\-\-network\-compression\fP / \fB\-\-no\-network\-compression\fP +Enable/disable network compression during remote recovery. Default is based on +\fBnetwork_compression\fP configuration setting. +.TP +.B \fB\-\-no\-retry\fP +There will be no retry in case of an error. It is the same as setting +\fB\-\-retry\-times 0\fP\&. +.TP +.B \fB\-\-recovery\-conf\-filename\fP +Specify the name of the file where Barman should write recovery options when +recovering backups for Postgres versions 12 and later. By default, this is set to +\fBpostgresql.auto.conf\fP\&. However, if \fB\-\-recovery\-conf\-filename\fP is specified, +recovery options will be written to the specified value instead. While the default +value is suitable for most Postgres installations, this option allows you to specify +an alternative location if Postgres is managed by tools that alter the configuration +mechanism (for example, if \fBpostgresql.auto.conf\fP is symlinked to \fB/dev/null\fP). +.TP +.B \fB\-\-recovery\-staging\-path\fP +Specify a path on the recovery host where files for a compressed backup will be +staged before being uncompressed to the destination directory. Backups will be +staged in their own directory within the staging path, following the naming +convention: \fBbarman\-staging\-SERVER_NAME\-BACKUP_ID\fP\&. This staging directory will be +removed after the recovery process is complete. This option is mandatory for +recovering from compressed backups and has no effect otherwise. +.TP +.B \fB\-\-remote\-ssh\-command\fP +This option enables remote recovery by specifying the secure shell command to +execute on a remote host. It functions similarly to the \fBssh_command\fP server +option in the configuration file for remote recovery, that is, \fB\(aqssh USER@SERVER\(aq\fP\&. +.TP +.B \fB\-\-retry\-sleep\fP +Specify the number of seconds to wait after a failed copy before retrying. This +setting applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_sleep\fP parameter if it is defined in the configuration file. +.TP +.B \fB\-\-retry\-times\fP +Specify the number of times to retry the base backup copy in case of an error. This +applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_times\fP parameter if it is set in the configuration file. +.TP +.B \fB\-\-snapshot\-recovery\-instance\fP +Specify the name of the instance where the disks recovered from the snapshots are +attached. This option is necessary when recovering backups created with +\fBbackup_method=snapshot\fP\&. +.TP +.B \fB\-\-standby\-mode\fP +Whether to start the PostgreSQL server as a standby. +.TP +.B \fB\-\-tablespace\fP +Specify tablespace relocation rule. \fBNAME\fP is the tablespace name and \fBLOCATION\fP +is the recovery host destination path to recover the tablespace. +.TP +.B \fB\-\-target\-action\fP +Trigger the specified action when the recovery target is reached. This option +requires defining a target along with one of these actions. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBpause\fP: Once recovery target is reached, the server is started in pause state, +allowing users to inspect the instance +.IP \(bu 2 +\fBpromote\fP: Once recovery target is reached, the server will exit recovery and is +promoted as a master. +.IP \(bu 2 +\fBshutdown\fP: Once recovery target is reached, the server is shut down. +.UNINDENT +.TP +.B \fB\-\-target\-immediate\fP +Recover is completed when a consistent state is reached (end of the base backup). +.TP +.B \fB\-\-target\-lsn\fP +Recover to the specified LSN (Log Sequence Number). Requires Postgres 10 or above. +.TP +.B \fB\-\-target\-name\fP +Recover to the specified name of a restore point previously created with the +\fBpg_create_restore_point(name)\fP\&. +.TP +.B \fB\-\-target\-time\fP +Recover to the specified time. Use the format \fBYYYY\-MM\-DD HH:MM:SS.mmm\fP\&. +.TP +.B \fB\-\-target\-tli\fP +Recover the specified timeline. You can use the special values \fBcurrent\fP and +\fBlatest\fP in addition to a numeric timeline ID. For Postgres versions 12 and above, +the default is to recover to the latest timeline in the WAL archive. For Postgres +versions below 12, the default is to recover to the timeline that was current at the +time the backup was taken. +.TP +.B \fB\-\-target\-xid\fP +Recover to the specified transaction ID. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +center; +|l|l|. +_ +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +_ +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-replication-status.1 b/docs/_build/man/barman-replication-status.1 new file mode 100644 index 000000000..b0d61adab --- /dev/null +++ b/docs/_build/man/barman-replication-status.1 @@ -0,0 +1,106 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-REPLICATION-STATUS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-replication-status \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +replication\-status + [ \-\-minimal ] + [ \-\-source { backup\-host | wal\-host } ] + [ \-\-target { hot\-standby | wal\-streamer | all } ] +SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display real\-time information and status of any streaming clients connected to the +specified server. Specify \fBall\fP shortcut to diplay information for all configured +servers. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-\-minimal\fP +Machine readable output. +.TP +.B \fB\-\-source\fP +The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBbackup\-host\fP (default): List clients using the backup connection information +for a server. +.IP \(bu 2 +\fBwal\-host\fP: List clients using the WAL streaming connection information for a +server. +.UNINDENT +.TP +.B \fB\-\-target\fP +The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBhot\-standby\fP: List only hot standby servers. +.IP \(bu 2 +\fBwal\-streamer\fP: List only WAL streaming clients, such as \fBpg_receivewal\fP\&. +.IP \(bu 2 +\fBall\fP (default): List all streaming clients. +.UNINDENT +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-restore.1 b/docs/_build/man/barman-restore.1 new file mode 100644 index 000000000..9e61a1ad5 --- /dev/null +++ b/docs/_build/man/barman-restore.1 @@ -0,0 +1,271 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-RESTORE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-restore \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +restore + [ \-\-aws\-region AWS_REGION } ] + [ \-\-azure\-resource\-group AZURE_RESOURCE_GRP ] + [ \-\-bwlimit KBPS ] + [ \-\-exclusive ] + [ \-\-gcp\-zone GCP_ZONE ] + [ \-\-get\-wal | \-\-no\-get\-wal ] + [ { \-j | \-\-jobs } PARALLEL_WORKERS ] + [ \-\-jobs\-start\-batch\-period SECONDS ] + [ \-\-jobs\-start\-batch\-size NUMBER ] + [ \-\-local\-staging\-path PATH ] + [ \-\-network\-compression | \-\-no\-network\-compression ] + [ \-\-no\-retry ] + [ \-\-recovery\-conf\-filename FILENAME ] + [ \-\-recovery\-staging\-path PATH ] + [ \-\-remote\-ssh\-command STRING ] + [ \-\-retry\-sleep SECONDS ] + [ \-\-retry\-times NUMBER ] + [ \-\-snapshot\-recovery\-instance INSTANCE_NAME ] + [ \-\-standby\-mode ] + [ \-\-tablespace NAME:LOCATION ] + [ \-\-target\-action { pause | shutdown | promote } ] + [ \-\-target\-immediate ] + [ \-\-target\-lsn LSN ] + [ \-\-target\-name RESTORE_POINT_NAME ] + [ \-\-target\-time TIMESTAMP ] + [ \-\-target\-tli TLI ] + [ \-\-target\-xid XID ] + SERVER_NAME BACKUP_ID DESTINATION_DIR +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Execute a PostreSQL server restore operation. Barman will restore the backup from a +server in the destination directory. The restoration can be performed locally (on the +barman node itself) or remotely (on another machine accessible via SSH). The location is +determined by whether or not the \fB\-\-remote\-ssh\-command\fP option is used. More +information on this command can be found in the \fI\%Recovery\fP section. You can use a +shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fBDESTINATION_DIR\fP +Destination directory to restore the backup. +.TP +.B \fB\-\-aws\-region\fP +Specify the AWS region where the instance and disks for snapshot recovery are +located. This option allows you to override the \fBaws_region\fP value in the Barman +configuration. +.TP +.B \fB\-\-azure\-resource\-group\fP +Specify the Azure resource group containing the instance and disks for snapshot +recovery. This option allows you to override the \fBazure_resource_group\fP value in +the Barman configuration. +.TP +.B \fB\-\-bwlimit\fP +Specify the maximum transfer rate in kilobytes per second. A value of \fB0\fP +indicates no limit. This setting overrides the \fBbandwidth_limit\fP configuration +option. +.TP +.B \fB\-\-exclusive\fP +Set target (time, XID or LSN) to be non inclusive. +.TP +.B \fB\-\-gcp\-zone\fP +Specify the GCP zone where the instance and disks for snapshot recovery are located. +This option allows you to override the \fBgcp_zone\fP value in the Barman +configuration. +.TP +.B \fB\-\-get\-wal\fP / \fB\-\-no\-get\-wal\fP +Enable/disable usage of \fBget\-wal\fP for WAL fetching during recovery. Default is based on +\fBrecovery_options\fP setting. +.TP +.B \fB\-j\fP / \fB\-\-jobs\fP +Specify the number of parallel workers to use for copying files during the backup. +This setting overrides the \fBparallel_jobs\fP parameter if it is specified in the +configuration file. +.TP +.B \fB\-\-jobs\-start\-batch\-period\fP +Specify the time period, in seconds, for starting a single batch of jobs. This value +overrides the \fBparallel_jobs_start_batch_period\fP parameter if it is set in the +configuration file. The default is \fB1\fP second. +.TP +.B \fB\-\-jobs\-start\-batch\-size\fP +Specify the maximum number of parallel workers to initiate in a single batch. This +value overrides the \fBparallel_jobs_start_batch_size\fP parameter if it is defined in +the configuration file. The default is \fB10\fP workers. +.TP +.B \fB\-\-local\-staging\-path\fP +Specify path on the Barman host where the chain of backups will be combined before +being copied to the destination directory. The contents created within the staging +path will be removed upon completion of the restore process. This option is +necessary for restoring from block\-level incremental backups and has no effect +otherwise. +.TP +.B \fB\-\-network\-compression\fP / \fB\-\-no\-network\-compression\fP +Enable/disable network compression during remote restore. Default is based on +\fBnetwork_compression\fP configuration setting. +.TP +.B \fB\-\-no\-retry\fP +There will be no retry in case of an error. It is the same as setting +\fB\-\-retry\-times 0\fP\&. +.TP +.B \fB\-\-recovery\-conf\-filename\fP +Specify the name of the file where Barman should write recovery options when +recovering backups for Postgres versions 12 and later. By default, this is set to +\fBpostgresql.auto.conf\fP\&. However, if \fB\-\-recovery\-conf\-filename\fP is specified, +recovery options will be written to the specified value instead. While the default +value is suitable for most Postgres installations, this option allows you to specify +an alternative location if Postgres is managed by tools that alter the configuration +mechanism (for example, if \fBpostgresql.auto.conf\fP is symlinked to \fB/dev/null\fP). +.TP +.B \fB\-\-recovery\-staging\-path\fP +Specify a path on the recovery host where files for a compressed backup will be +staged before being uncompressed to the destination directory. Backups will be +staged in their own directory within the staging path, following the naming +convention: \fBbarman\-staging\-SERVER_NAME\-BACKUP_ID\fP\&. This staging directory will be +removed after the restore process is complete. This option is mandatory for +restoring from compressed backups and has no effect otherwise. +.TP +.B \fB\-\-remote\-ssh\-command\fP +This option enables remote restore by specifying the secure shell command to +execute on a remote host. It functions similarly to the \fBssh_command\fP server +option in the configuration file for remote restore, that is, \fB\(aqssh USER@SERVER\(aq\fP\&. +.TP +.B \fB\-\-retry\-sleep\fP +Specify the number of seconds to wait after a failed copy before retrying. This +setting applies to both backup and restore operations and overrides the +\fBbasebackup_retry_sleep\fP parameter if it is defined in the configuration file. +.TP +.B \fB\-\-retry\-times\fP +Specify the number of times to retry the base backup copy in case of an error. This +applies to both backup and restore operations and overrides the +\fBbasebackup_retry_times\fP parameter if it is set in the configuration file. +.TP +.B \fB\-\-snapshot\-recovery\-instance\fP +Specify the name of the instance where the disks recovered from the snapshots are +attached. This option is necessary when recovering backups created with +\fBbackup_method=snapshot\fP\&. +.TP +.B \fB\-\-standby\-mode\fP +Whether to start the Postgres server as a standby. +.TP +.B \fB\-\-tablespace\fP +Specify tablespace relocation rule. \fBNAME\fP is the tablespace name and \fBLOCATION\fP +is the recovery host destination path to restore the tablespace. +.TP +.B \fB\-\-target\-action\fP +Trigger the specified action when the recovery target is reached. This option +requires defining a target along with one of these actions. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBpause\fP: Once recovery target is reached, the server is started in pause state, +allowing users to inspect the instance +.IP \(bu 2 +\fBpromote\fP: Once recovery target is reached, the server will exit the recovery +operation and is promoted as a master. +.IP \(bu 2 +\fBshutdown\fP: Once recovery target is reached, the server is shut down. +.UNINDENT +.TP +.B \fB\-\-target\-immediate\fP +Recovery is completed when a consistent state is reached (end of the base backup). +.TP +.B \fB\-\-target\-lsn\fP +Recover to the specified LSN (Log Sequence Number). Requires Postgres 10 or above. +.TP +.B \fB\-\-target\-name\fP +Recover to the specified name of a restore point previously created with the +\fBpg_create_restore_point(name)\fP\&. +.TP +.B \fB\-\-target\-time\fP +Recover to the specified time. Use the format \fBYYYY\-MM\-DD HH:MM:SS.mmm\fP\&. +.TP +.B \fB\-\-target\-tli\fP +Recover the specified timeline. You can use the special values \fBcurrent\fP and +\fBlatest\fP in addition to a numeric timeline ID. For Postgres versions 12 and above, +the default is to recover to the latest timeline in the WAL archive. For Postgres +versions below 12, the default is to recover to the timeline that was current at the +time the backup was taken. +.TP +.B \fB\-\-target\-xid\fP +Recover to the specified transaction ID. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-show-backup.1 b/docs/_build/man/barman-show-backup.1 new file mode 100644 index 000000000..235ce2f98 --- /dev/null +++ b/docs/_build/man/barman-show-backup.1 @@ -0,0 +1,98 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SHOW-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-show-backup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +show\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display detailed information about a specific backup. You can find details about this command in +\fI\%Catalog usage\fP\&. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-show-servers.1 b/docs/_build/man/barman-show-servers.1 new file mode 100644 index 000000000..b33f35d9f --- /dev/null +++ b/docs/_build/man/barman-show-servers.1 @@ -0,0 +1,75 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SHOW-SERVERS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-show-servers \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +show\-servers SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display detailed information about a server, including \fBconninfo\fP, \fBbackup_directory\fP, +\fBwals_directory\fP, \fBarchive_command\fP, and many more. To view information about all configured +servers, specify the \fBall\fP shortcut instead of the server name. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SH SHORTCUTS +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-status.1 b/docs/_build/man/barman-status.1 new file mode 100644 index 000000000..1da8a8017 --- /dev/null +++ b/docs/_build/man/barman-status.1 @@ -0,0 +1,74 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-STATUS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-status \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +status SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Display information about a server\(aqs status, including details such as the state, +Postgres version, WAL information, available backups and more. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SH SHORTCUTS +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-switch-wal.1 b/docs/_build/man/barman-switch-wal.1 new file mode 100644 index 000000000..fc4cff718 --- /dev/null +++ b/docs/_build/man/barman-switch-wal.1 @@ -0,0 +1,82 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SWITCH-WAL" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-switch-wal \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +switch\-wal + [ \-\-archive ] + [ \-\-archive\-timeout ] + [ \-\-force ] + SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Execute \fBpg_switch_wal()\fP on the target server (Postgres versions 10 and later) or +\fBpg_switch_xlog()\fP (for Postgres versions 8.3 to 9.6). +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-\-archive\fP +Waits for one WAL file to be archived. If no WAL file is archived within a specified +time (default: \fB30\fP seconds), Barman will terminate with a failure exit code. This +option is also available on standby servers. +.TP +.B \fB\-\-archive\-timeout\fP +Specify the amount of time in seconds (default: \fB30\fP seconds) that the archiver +will wait for a new WAL file to be archived before timing out. This option is also +available on standby servers. +.TP +.B \fB\-\-force\fP +Forces the switch by executing a CHECKPOINT before \fBpg_switch_wal()\fP\&. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Running a CHECKPOINT may increase I/O load on the Postgres server, so use this +option cautiously. +.UNINDENT +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-switch-xlog.1 b/docs/_build/man/barman-switch-xlog.1 new file mode 100644 index 000000000..8c6ecd1a2 --- /dev/null +++ b/docs/_build/man/barman-switch-xlog.1 @@ -0,0 +1,41 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SWITCH-XLOG" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-switch-xlog \- Barman Sub-Commands +.SH DESCRIPTION +.sp +Alias for the \fBswitch\-wal\fP command. +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-sync-backup.1 b/docs/_build/man/barman-sync-backup.1 new file mode 100644 index 000000000..c7c1d1829 --- /dev/null +++ b/docs/_build/man/barman-sync-backup.1 @@ -0,0 +1,101 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SYNC-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-sync-backup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +This command synchronizes a passive node with its primary by copying all files from a +backup present on the server node. It is available only for passive nodes and uses +the \fBprimary_ssh_command\fP option to establish a secure connection with the primary +node. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +For some commands, instead of using the timestamp backup ID, you can use the following +shortcuts or aliases to identify a backup for a given server: +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-sync-info.1 b/docs/_build/man/barman-sync-info.1 new file mode 100644 index 000000000..732f030b2 --- /dev/null +++ b/docs/_build/man/barman-sync-info.1 @@ -0,0 +1,68 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SYNC-INFO" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-sync-info \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-info [ \-\-primary ] SERVER_NAME [ LAST_WAL [ LAST_POS ] ] +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Gather information about the current status of a Barman server for synchronization +purposes. +.sp +This command returns a JSON output for a server that includes: all successfully +completed backups, all archived WAL files, the configuration, the last WAL file read from +\fBxlog.db\fP, and its position within the file. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBLAST_WAL\fP +Instructs sync\-info to skip any WAL files that precede the specified file (for +incremental synchronization). +.TP +.B \fBLAST_POS\fP +Hint for quickly positioning in the \fBxlog.db\fP file (for incremental synchronization). +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-sync-wals.1 b/docs/_build/man/barman-sync-wals.1 new file mode 100644 index 000000000..5ad8c5197 --- /dev/null +++ b/docs/_build/man/barman-sync-wals.1 @@ -0,0 +1,58 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-SYNC-WALS" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-sync-wals \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-wals SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +This command synchronizes a passive node with its primary by copying all archived WAL +files from the server node. It is available only for passive nodes and utilizes the +\fBprimary_ssh_command\fP option to establish a secure connection with the primary node. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-verify-backup.1 b/docs/_build/man/barman-verify-backup.1 new file mode 100644 index 000000000..a450f79cc --- /dev/null +++ b/docs/_build/man/barman-verify-backup.1 @@ -0,0 +1,101 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-VERIFY-BACKUP" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-verify-backup \- Barman Sub-Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +verify\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Runs \fBpg_verifybackup\fP on a backup manifest file (available since Postgres version 13). +For rsync backups, it can be used after creating a manifest file using the +\fBgenerate\-manifest\fP command. Requires \fBpg_verifybackup\fP to be installed on the +backup server. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SH SHORTCUTS +.sp +For some commands, instead of using the timestamp backup ID, you can use the following +shortcuts or aliases to identify a backup for a given server: +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-verify.1 b/docs/_build/man/barman-verify.1 new file mode 100644 index 000000000..2c0db5e75 --- /dev/null +++ b/docs/_build/man/barman-verify.1 @@ -0,0 +1,41 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-VERIFY" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-verify \- Barman Sub-Commands +.SH DESCRIPTION +.sp +Alias for \fBverify\-backup\fP command. +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-wal-archive.1 b/docs/_build/man/barman-wal-archive.1 new file mode 100644 index 000000000..58cb9d6a4 --- /dev/null +++ b/docs/_build/man/barman-wal-archive.1 @@ -0,0 +1,102 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-WAL-ARCHIVE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-wal-archive \- Barman-cli Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-wal\-archive + [ { \-h, \-\-help } ] + [ { \-V, \-\-version } ] + [ { \-U, \-\-user } USER ] + [ \-\-port PORT ] + [ { \-c, \-\-config } CONFIG ] + [ { \-t \-\-test } ] + BARMAN_HOST SERVER_NAME WAL_PATH +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +This script can be utilized in the \fBarchive_command\fP of a Postgres server to +transfer WAL files to a Barman host using the \fBput\-wal\fP command (introduced in Barman +2.6). It establishes an SSH connection to the Barman host, enabling seamless integration +of Barman within Postgres clusters for improved business continuity. +.sp +\fBExit Statuses\fP are: +.INDENT 0.0 +.IP \(bu 2 +\fB0\fP for \fBSUCCESS\fP\&. +.IP \(bu 2 +\fBnon\-zero\fP for \fBFAILURE\fP\&. +.UNINDENT +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +The server name configured in Barman for the Postgres server from which +the WAL file is retrieved. +.TP +.B \fBBARMAN_HOST\fP +The host of the Barman server. +.TP +.B \fBWAL_PATH\fP +The value of the \(aq%p\(aq keyword (according to \fBarchive_command\fP). +.TP +.B \fB\-h\fP / \fB\-\-help\fP +Display a help message and exit. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Display the program\(aqs version number and exit. +.TP +.B \fB\-U\fP / \fB\-\-user\fP +Specify the user for the SSH connection to the Barman server (defaults to +\fBbarman\fP). +.TP +.B \fB\-\-port\fP +Define the port used for the SSH connection to the Barman server. +.TP +.B \fB\-c\fP / \fB\-\-config\fP +Specify the configuration file on the Barman server. +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test the connection and configuration of the specified Postgres server in Barman to +ensure it is ready to receive WAL files. This option ignores the mandatory arguments +\fBWAL_NAME\fP and \fBWAL_DEST\fP\&. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman-wal-restore.1 b/docs/_build/man/barman-wal-restore.1 new file mode 100644 index 000000000..b88c88958 --- /dev/null +++ b/docs/_build/man/barman-wal-restore.1 @@ -0,0 +1,149 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN-WAL-RESTORE" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman-wal-restore \- Barman-cli Commands +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-wal\-restore + [ { \-h, \-\-help } ] + [ { \-V, \-\-version } ] + [ { \-U, \-\-user } USER ] + [ \-\-port PORT ] + [ { \-s, \-\-sleep } SECONDS ] + [ { \-p, \-\-parallel } JOBS ] + [ \-\-spool\-dir SPOOL_DIR ] + [ { \-P, \-\-partial } ] + [ { \-z, \-\-gzip } ] + [ { \-j, \-\-bzip2 } ] + [ { \-c, \-\-config } CONFIG ] + [ { \-t \-\-test } ] + BARMAN_HOST SERVER_NAME WAL_NAME WAL_DEST +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +This script serves as a \fBrestore_command\fP for Postgres servers, enabling the +retrieval of WAL files through Barman\(aqs \fBget\-wal\fP feature. It establishes an SSH +connection to the Barman host and facilitates the integration of Barman within +Postgres clusters, enhancing business continuity. +.sp +\fBExit Statuses\fP are: +.INDENT 0.0 +.IP \(bu 2 +\fB0\fP for \fBSUCCESS\fP\&. +.IP \(bu 2 +\fB1\fP for remote get\-wal command \fBFAILURE\fP, likely because the requested WAL could +not be found. +.IP \(bu 2 +\fB2\fP for ssh connection \fBFAILURE\fP\&. +.IP \(bu 2 +Any other \fBnon\-zero\fP for \fBFAILURE\fP\&. +.UNINDENT +.SH PARAMETERS +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +The server name configured in Barman for the Postgres server from which the +WAL file is retrieved. +.TP +.B \fBBARMAN_HOST\fP +The host of the Barman server. +.TP +.B \fBWAL_NAME\fP +The value of the \(aq%f\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fBWAL_DEST\fP +The value of the \(aq%p\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fB\-h\fP / \fB\-\-help\fP +Display a help message and exit. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Display the program\(aqs version number and exit. +.TP +.B \fB\-U\fP / \fB\-\-user\fP +Specify the user for the SSH connection to the Barman server (defaults to +\fBbarman\fP). +.TP +.B \fB\-\-port\fP +Define the port used for the SSH connection to the Barman server. +.TP +.B \fB\-s\fP / \fB\-\-sleep\fP +Pause for \fBSECONDS\fP after a failed \fBget\-wal\fP request (defaults to \fB0\fP \- no +wait). +.TP +.B \fB\-p\fP / \fB\-\-parallel\fP +Indicate the number of files to \fBpeek\fP and transfer simultaneously (defaults to +\fB0\fP \- disabled). +.TP +.B \fB\-\-spool\-dir\fP +Specify the spool directory for WAL files (defaults to \fB/var/tmp/walrestore\fP). +.TP +.B \fB\-P\fP / \fB\-\-partial\fP +Include partial WAL files (.partial) in the retrieval. +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +Transfer WAL files compressed with \fBgzip\fP\&. +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +Transfer WAL files compressed with \fBbzip2\fP\&. +.TP +.B \fB\-\-keep\-compression\fP +If specified, compressed files will be trasnfered as\-is and decompressed on arrival +on the client\-side. +.TP +.B \fB\-c\fP / \fB\-\-config\fP +Specify the configuration file on the Barman server. +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test the connection and configuration of the specified Postgres server in Barman to +ensure it is ready to receive WAL files. This option ignores the mandatory arguments +\fBWAL_NAME\fP and \fBWAL_DEST\fP\&. +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +\fB\-z\fP / \fB\-\-gzip\fP and \fB\-j\fP / \fB\-\-bzip2\fP options are deprecated and will be +removed in the future. For WAL compression, please make sure to enable it directly +on the Barman server via the \fBcompression\fP configuration option. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman.1 b/docs/_build/man/barman.1 new file mode 100644 index 000000000..8ae8e747d --- /dev/null +++ b/docs/_build/man/barman.1 @@ -0,0 +1,1987 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN" "1" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman \- Barman Commands +.sp +Barman has a command\-line interface named \fBbarman\fP, which is used basically to +interact with Barman\(aqs backend. +.sp +Before jumping into each of the sub\-commands of \fBbarman\fP, be aware that \fBbarman\fP +has global options available for all of the sub\-commands. These options can modify the +behavior of the sub\-commands and can be used as follows: +.SH BARMAN +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman + [ { \-c | \-\-config } CONFIG ] + [ { \-color | \-\-colour } { never | always | auto } ] + [ { \-d | \-\-debug } ] + [ { \-f | \-\-format } { json | console } ] + [ { \-h | \-\-help } ] + [ \-\-log\-level { NOTSET | DEBUG | INFO | WARNING | ERROR | CRITICAL } ] + [ { \-q | \-\-quiet } ] + [ { \-v | \-\-version } ] + [ SUBCOMMAND ] +.EE +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This is the syntax for the synopsis: +.INDENT 0.0 +.IP \(bu 2 +Options between square brackets are optional. +.IP \(bu 2 +Options between curly brackets represent a choose one of set operation. +.IP \(bu 2 +Options with \fB[ ... ]\fP can be specified multiple times. +.IP \(bu 2 +Things written in uppercase represent a literal that should be given a value to. +.UNINDENT +.sp +We will use this same syntax when describing \fBbarman\fP sub\-commands in the +following sections. +.sp +Also, when describing sub\-commands in the following sections, the commands\(aq +synopsis should be seen as a replacement for the \fBSUBCOMMAND\fP\&. +.UNINDENT +.UNINDENT +.SS Parameters +.INDENT 0.0 +.TP +.B \fB\-c\fP / \fB\-\-config CONFIG\fP +Specify the configuration file to be used. Defaults to \fB/etc/barman.conf\fP if +not provided. +.TP +.B \fB\-\-color\fP / \fB\-\-colour { never | always | auto }\fP +Control whether to use colors in the output. The default is \fBauto\fP\&. Options are: +.INDENT 7.0 +.IP \(bu 2 +\fBnever\fP: Do not use color. +.IP \(bu 2 +\fBalways\fP: Always use color. +.IP \(bu 2 +\fBauto\fP: Use color if the output is to a terminal. +.UNINDENT +.TP +.B \fB\-d\fP / \fB\-\-debug\fP +Enable debug output. Default is \fBfalse\fP\&. Provides detailed logging information for +troubleshooting. +.TP +.B \fB\-f\fP / \fB\-\-format { json | console }\fP +Specify the output format. Options are: +.INDENT 7.0 +.IP \(bu 2 +\fBjson\fP: Output in JSON format. +.IP \(bu 2 +\fBconsole\fP: Output in human\-readable format (default). +.UNINDENT +.TP +.B \fB\-h\fP / \fB\-\-help\fP +Show a help message and exit. Provides information about command usage. +.TP +.B \fB\-\-log\-level { NOTSET | DEBUG | INFO | WARNING | ERROR | CRITICAL }\fP +Override the default logging level. Options are: +.INDENT 7.0 +.IP \(bu 2 +\fBNOTSET\fP: This is the default level when no specific logging level is set. It +essentially means \(dqno filtering\(dq of log messages, allowing all messages to be +processed according to the levels that are set in the configuration. +.IP \(bu 2 +\fBDEBUG\fP: This level is used for detailed, diagnostic information, often +useful for developers when diagnosing problems. It includes messages that are +more granular and detailed, intended to help trace the execution of the +program. +.IP \(bu 2 +\fBINFO\fP: This level provides general information about the application\(aqs +normal operation. It\(aqs used for messages that indicate the progress of the +application or highlight key points in the execution flow that are useful but +not indicative of any issues. +.IP \(bu 2 +\fBWARNING\fP: This level indicates that something unexpected happened or that +there might be a potential problem. It\(aqs used for messages that are not +critical but could be of concern, signaling that attention might be needed. +.IP \(bu 2 +\fBERROR\fP: This level is used when an error occurs that prevents a particular +operation from completing successfully. It\(aqs used to indicate significant +issues that need to be addressed but do not necessarily stop the application +from running. +.IP \(bu 2 +\fBCRITICAL\fP: This is the highest level of severity, indicating a serious +error that has likely caused the application to terminate or will have severe +consequences if not addressed immediately. It\(aqs used for critical issues that +demand urgent attention. +.UNINDENT +.TP +.B \fB\-q\fP / \fB\-\-quiet\fP +Suppress all output. Useful for cron jobs or automated scripts. +.TP +.B \fB\-v\fP / \fB\-\-version\fP +Show the program version number and exit. +.UNINDENT +.SH SHORTCUTS +.sp +For some commands, you can use the following shortcuts or aliases to identify a backup +for a given server. Specifically, the \fBall\fP shortcut can be used to identify all +servers: +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SH EXIT STATUSES +.sp +Status code \fB0\fP means \fBsuccess\fP, while status code \fBNon\-Zero\fP means \fBfailure\fP\&. +.SH SUB-COMMANDS +.sp +\fBbarman\fP exposes several handy operations. This section is intended to describe each +of them. +.sp +In the following sections you can find a description of each command implemented by +\fBbarman\fP\&. Some of these commands may have more detailed information in another main +section in this documentation. If that is the case, a reference is provided to help you +quickly navigate to it. +.SS \fBbarman archive\-wal\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +archive\-wal SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Fetch WAL files received from either the standard \fBarchive_command\fP or streaming +replication with \fBpg_receivewal\fP and store them in the server\(aqs WAL archive. If you +have enabled \fBcompression\fP in the configuration file, the WAL files will be compressed +before they are archived. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.UNINDENT +.SS \fBbarman backup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +backup + [ \-\-bwlimit KBPS ] + [ \-\-incremental BACKUP_ID ] + [ \-\-immediate\-checkpoint ] + [ { \-j, \-\-jobs } PARALLEL_WORKERS ] + [ \-\-jobs\-start\-batch\-period PERIOD ] + [ \-\-jobs\-start\-batch\-size SIZE ] + [ \-\-keepalive\-interval SECONDS ] + [ \-\-manifest ] + [ \-\-name NAME ] + [ \-\-no\-immediate\-checkpoint ] + [ \-\-no\-manifest ] + [ \-\-no\-retry ] + [ \-\-retry\-sleep SECONDS ] + [ \-\-retry\-times NUMBER ] + [ \-\-reuse\-backup { off | copy | link } ] + [ { \-\-wait | \-w } ] + [ \-\-wait\-timeout SECONDS ] + SERVER_NAME [ ... ] +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Execute a PostreSQL server backup. Barman will use the parameters specified in the Global +and Server configuration files. Specify \fBall\fP shortcut instead of the server name to +execute backups from all servers configured in the Barman node. You can also specify +multiple server names in sequence to execute backups for specific servers. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-bwlimit\fP +Specify the maximum transfer rate in kilobytes per second. A value of 0 indicates no +limit. This setting overrides the \fBbandwidth_limit\fP configuration option. +.TP +.B \fB\-\-incremental\fP +Execute a block\-level incremental backup. You must provide a \fBBACKUP_ID\fP or a +shortcut to a previous backup, which will serve as the parent backup for the +incremental backup. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +The backup to be and the parent backup must have \fBbackup_method=postgres\fP\&. +.UNINDENT +.UNINDENT +.TP +.B \fB\-\-immediate\-checkpoint\fP +Forces the initial checkpoint to be executed as soon as possible, overriding any +value set for the \fBimmediate_checkpoint\fP parameter in the configuration file. +.TP +.B \fB\-j\fP / \fB\-\-jobs\fP +Specify the number of parallel workers to use for copying files during the backup. +This setting overrides the \fBparallel_jobs\fP parameter if it\(aqs specified in the +configuration file. +.TP +.B \fB\-\-jobs\-start\-batch\-period\fP +Specify the time period, in seconds, for starting a single batch of jobs. This value +overrides the \fBparallel_jobs_start_batch_period\fP parameter if it is set in the +configuration file. The default is \fB1\fP second. +.TP +.B \fB\-\-jobs\-start\-batch\-size\fP +Specify the maximum number of parallel workers to initiate in a single batch. This +value overrides the \fBparallel_jobs_start_batch_size\fP parameter if it is defined in +the configuration file. The default is \fB10\fP workers. +.TP +.B \fB\-\-keepalive\-interval\fP +Specify an interval, in seconds, for sending a heartbeat query to the server to keep +the libpq connection active during a Rsync backup. The default is \fB60\fP seconds. A +value of \fB0\fP disables the heartbeat. +.TP +.B \fB\-\-manifest\fP +Forces the creation of a backup manifest file upon completing a backup. Overrides the +\fBautogenerate_manifest\fP parameter from the configuration file. Applicable only to +rsync backup strategy. +.TP +.B \fB\-\-name\fP +Specify a friendly name for this backup which can be used in place of the backup ID +in barman commands. +.TP +.B \fB\-\-no\-immediate\-checkpoint\fP +Forces the backup to wait for the checkpoint to be executed overriding any value set +for the \fBimmediate_checkpoint\fP parameter in the configuration file. +.TP +.B \fB\-\-no\-manifest\fP +Disables the automatic creation of a backup manifest file upon completing a backup. +This setting overrides the \fBautogenerate_manifest\fP parameter from the configuration +file and applies only to rsync backup strategy. +.TP +.B \fB\-\-no\-retry\fP +There will be no retry in case of an error. It is the same as setting +\fB\-\-retry\-times 0\fP\&. +.TP +.B \fB\-\-retry\-sleep\fP +Specify the number of seconds to wait after a failed copy before retrying. This +setting applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_sleep\fP parameter if it is defined in the configuration file. +.TP +.B \fB\-\-retry\-times\fP +Specify the number of times to retry the base backup copy in case of an error. This +applies to both backup and recovery operations and overrides the +\fBbasebackup_retry_times\fP parameter if it is set in the configuration file. +.TP +.B \fB\-\-reuse\-backup\fP +Overrides the behavior of the \fBreuse_backup\fP option configured in the configuration +file. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBoff\fP: Do not reuse the last available backup. +.IP \(bu 2 +\fBcopy\fP: Reuse the last available backup for a server and create copies of +unchanged files (reduces backup time). +.IP \(bu 2 +\fBlink\fP (default): Reuse the last available backup for a server and create +hard links to unchanged files (saves both backup time and space). +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This will only have any effect if the last available backup was +executed with \fBbackup_method=rsync\fP\&. +.UNINDENT +.UNINDENT +.TP +.B \fB\-\-wait\fP / \fB\-w\fP +Wait for all necessary WAL files required by the base backup to be archived. +.TP +.B \fB\-\-wait\-timeout\fP +Specify the duration, in seconds, to wait for the required WAL files to be archived +before timing out. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman check\-backup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +check\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Check that all necessary WAL files for verifying the consistency of a physical backup are +properly archived. This command is automatically executed by the cron job and at the end +of each backup operation. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman check\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +check [ \-\-nagios ] SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display status information about a server, such as SSH connection, Postgres version, +configuration and backup directories, archiving and streaming processes, replication +slots, and more. Use \fBall\fP as shortcut to show diagnostic information for all +configured servers. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-nagios\fP +Nagios plugin compatible output. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman config\-switch\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +config\-switch SERVER_NAME { \-\-reset | MODEL_NAME } +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Apply a set of configuration overrides from the model to a server in Barman. The final +configuration will combine or override the server\(aqs existing settings with the ones +specified in the model. You can reset the server configurations with the \fB\-\-reset\fP +argument. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only one model can be active at a time for a given server. +.UNINDENT +.UNINDENT +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fBMODEL_NAME\fP +Name of the model. +.TP +.B \fB\-\-reset\fP +Reset the server\(aqs configurations. +.UNINDENT +.SS \fBbarman config\-update\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +config\-update STRING +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Create or update the configurations for servers and/or models in Barman. The parameter +should be a JSON string containing an array of documents. Each document must include a +\fBscope\fP key, which can be either server or model, and either a \fBserver_name\fP or +\fBmodel_name\fP key, depending on the scope value. Additionally, the document should +include other keys representing Barman configuration options and their desired values. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The barman \fBconfig\-update\fP command writes configuration options to a file named +\fB\&.barman.auto.conf\fP, located in the \fBbarman_home\fP directory. This configuration +file has higher precedence and will override values from the global Barman +configuration file (usually \fB/etc/barman.conf\fP) and from any included files specified +in \fBconfiguration_files_directory\fP (typically files in \fB/etc/barman.d\fP). Be aware +of this if you decide to manually modify configuration options in those files later. +.UNINDENT +.UNINDENT +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSTRING\fP +List of JSON formatted string. +.UNINDENT +.SS Example +.sp +\fBJSON_STRING=\(aq[{“scope”: “server”, “server_name”: “my_server”, “archiver”: +“on”, “streaming_archiver”: “off”}]\(aq\fP +.SS \fBbarman cron\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +cron [ \-\-keep\-descriptors ] +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Carry out maintenance tasks, such as enforcing retention policies or managing WAL files. +.SS Parameters +.INDENT 0.0 +.TP +.B \fB\-\-keep\-descriptors\fP +Keep the ^stdout^ and ^stderr^ streams of the Barman subprocesses connected to the +main process. This is especially useful for Docker\-based installations. +.UNINDENT +.SS \fBbarman delete\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +delete SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Delete the specified backup. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman diagnose\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +diagnose +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display diagnostic information about the Barman node, which is the server where Barman +is installed, as well as all configured Postgres servers. This includes details such as +global configuration, SSH version, Python version, rsync version, the current +configuration and status of all servers, and many more. +.SS \fBbarman generate\-manifest\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +generate\-manifest SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Generates a \fBbackup_manifest\fP file for a backup. You can use a shortcut instead of +\fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman get\-wal\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +get\-wal + [ \-j ] + [ \-o OUTPUT_DIRECTORY ] + [ \-p VALUE ] + [ { \-P | \-\-partial } ] + [ { \-t | \-\-test } ] + [ \-z ] + SERVER_NAME WAL_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Retrieve a WAL file from the xlog archive of a specified server. By default, if the +requested WAL file is found, it is returned as uncompressed content to \fBSTDOUT\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBWAL_NAME\fP +Id of the backup in barman catalog. +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +Output will be compressed using bzip2. +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +Output will be compressed using gzip. +.TP +.B \fB\-\-keep\-compression\fP +Do not uncompress the file content. The output will be the original compressed +file. +.TP +.B \fB\-o\fP +Destination directory where barman will store the WAL file. +.TP +.B \fB\-p\fP +Specify an integer value greater than or equal to 1 to retrieve WAL files from the +specified WAL file up to the value specified by this parameter. When using this option, +\fBget\-wal\fP returns a list of zero to the specified WAL segment names, with one name +per row. +.TP +.B \fB\-P\fP / \fB\-\-partial\fP +Additionally, collect partial WAL files (.partial). +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test both the connection and configuration of the specified Postgres server in +Barman for WAL retrieval. When this option is used, the required \fBWAL_NAME\fP +argument is disregarded. +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +\fB\-z\fP / \fB\-\-gzip\fP and \fB\-j\fP / \fB\-\-bzip2\fP options are deprecated and will be +removed in the future. For WAL compression, please make sure to enable it directly +on the Barman server via the \fBcompression\fP configuration option. +.UNINDENT +.UNINDENT +.SS \fBbarman keep\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +keep + { \-\-release | \-\-status | \-\-target { full | standalone } } + SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Mark the specified backup with a \fBtarget\fP as an archival backup to be retained +indefinitely, overriding any active retention policies. You can also check the keep +\fBstatus\fP of a backup and \fBrelease\fP the keep mark from a backup. You can use a +shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fB\-\-release\fP +Release the keep mark from this backup. This will remove its archival status and +make it available for deletion, either directly or by retention policy. +.TP +.B \fB\-\-status\fP +Report the archival status of the backup. The status will be either \fBfull\fP or +\fBstandalone\fP for archival backups, or \fBnokeep\fP for backups that have not been +designated as archival. +.TP +.B \fB\-\-target\fP +Define the recovery target for the archival backup. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBfull\fP: The backup can be used to recover to the most recent point in time. To +support this, Barman will keep all necessary WALs to maintain the backup\(aqs +consistency as well as any subsequent WALs. +.IP \(bu 2 +\fBstandalone\fP: The backup can only be used to restore the server to its state at the +time of the backup. Barman will retain only the WALs required to ensure the +backup\(aqs consistency. +.UNINDENT +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman list\-backups\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-backups SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display the available backups for a server. This command is useful for retrieving both +the backup ID and the backup type. You can find details about this command in +\fI\%Catalog usage\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman list\-files\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-files + [ \-\-target { data | full | standalone | wal } ] + SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +List all files in a specific backup. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fB\-\-target\fP +Define specific files to be listed. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBstandalone\fP (default): List the base backup files, including required WAL files. +.IP \(bu 2 +\fBdata\fP: List just the data files. +.IP \(bu 2 +\fBwal\fP: List all the WAL files between the start of the base backup and the end of +the log or the start of the following base backup (depending on whether the +specified base backup is the most recent one available). +.IP \(bu 2 +\fBfull\fP: same as \fBdata\fP + \fBwal\fP\&. +.UNINDENT +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman list\-servers\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +list\-servers [ \-\-minimal ] +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display all configured servers along with their descriptions. +.SS Parameters +.INDENT 0.0 +.TP +.B \fB\-\-minimal\fP +Machine readable output. +.UNINDENT +.SS \fBbarman lock\-directory\-cleanup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +lock\-directory\-cleanup +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Automatically removes unused lock files from the \fBbarman_lock_directory\fP\&. +.SS \fBbarman put\-wal\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +put\-wal [ { \-t | \-\-test } ] SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Receive a WAL file from a remote server and securely save it into the server incoming +directory. The WAL file should be provided via \fBSTDIN\fP, encapsulated in a tar stream +along with a \fBSHA256SUMS\fP or \fBMD5SUMS\fP file for validation (\fBsha256\fP is the default +hash algorithm, but the user can choose \fBmd5\fP when setting the \fBarchive\-command\fP via +\fBbarman\-wal\-archive\fP). This command is intended to be executed via SSH from a remote +\fBbarman\-wal\-archive\fP utility (included in the barman\-cli package). Avoid using this +command directly unless you fully manage the content of the files. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test both the connection and configuration of the specified Postgres +server in Barman for WAL retrieval. +.UNINDENT +.SS \fBbarman rebuild\-xlogdb\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +rebuild\-xlogdb SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Rebuild the WAL file metadata for a server (or for all servers using the \fBall\fP shortcut) +based on the disk content. The WAL archive metadata is stored in the \fBxlog.db\fP file, +with each Barman server maintaining its own copy. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman receive\-wal\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +receive\-wal + [ \-\-create\-slot ] + [ \-\-drop\-slot ] + [ \-\-reset ] + [ \-\-stop ] + SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Initiate the streaming of transaction logs for a server. This process uses +\fBpg_receivewal\fP or \fBpg_receivexlog\fP to receive WAL files from Postgres servers via +the streaming protocol. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node. +.TP +.B \fB\-\-create\-slot\fP +Create the physical replication slot configured with the \fBslot_name\fP configuration +parameter. +.TP +.B \fB\-\-drop\-slot\fP +Drop the physical replication slot configured with the \fBslot_name\fP configuration +parameter. +.TP +.B \fB\-\-reset\fP +Reset the status of \fBreceive\-wal\fP, restarting the streaming from the current WAL file +of the server. +.TP +.B \fB\-\-stop\fP +Stop the process for the server. +.UNINDENT +.SS \fBbarman restore\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +restore + [ \-\-aws\-region AWS_REGION } ] + [ \-\-azure\-resource\-group AZURE_RESOURCE_GRP ] + [ \-\-bwlimit KBPS ] + [ \-\-exclusive ] + [ \-\-gcp\-zone GCP_ZONE ] + [ \-\-get\-wal | \-\-no\-get\-wal ] + [ { \-j | \-\-jobs } PARALLEL_WORKERS ] + [ \-\-jobs\-start\-batch\-period SECONDS ] + [ \-\-jobs\-start\-batch\-size NUMBER ] + [ \-\-local\-staging\-path PATH ] + [ \-\-network\-compression | \-\-no\-network\-compression ] + [ \-\-no\-retry ] + [ \-\-recovery\-conf\-filename FILENAME ] + [ \-\-recovery\-staging\-path PATH ] + [ \-\-remote\-ssh\-command STRING ] + [ \-\-retry\-sleep SECONDS ] + [ \-\-retry\-times NUMBER ] + [ \-\-snapshot\-recovery\-instance INSTANCE_NAME ] + [ \-\-standby\-mode ] + [ \-\-tablespace NAME:LOCATION ] + [ \-\-target\-action { pause | shutdown | promote } ] + [ \-\-target\-immediate ] + [ \-\-target\-lsn LSN ] + [ \-\-target\-name RESTORE_POINT_NAME ] + [ \-\-target\-time TIMESTAMP ] + [ \-\-target\-tli TLI ] + [ \-\-target\-xid XID ] + SERVER_NAME BACKUP_ID DESTINATION_DIR +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Execute a PostreSQL server restore operation. Barman will restore the backup from a +server in the destination directory. The restoration can be performed locally (on the +barman node itself) or remotely (on another machine accessible via SSH). The location is +determined by whether or not the \fB\-\-remote\-ssh\-command\fP option is used. More +information on this command can be found in the \fI\%Recovery\fP section. You can use a +shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.TP +.B \fBDESTINATION_DIR\fP +Destination directory to restore the backup. +.TP +.B \fB\-\-aws\-region\fP +Specify the AWS region where the instance and disks for snapshot recovery are +located. This option allows you to override the \fBaws_region\fP value in the Barman +configuration. +.TP +.B \fB\-\-azure\-resource\-group\fP +Specify the Azure resource group containing the instance and disks for snapshot +recovery. This option allows you to override the \fBazure_resource_group\fP value in +the Barman configuration. +.TP +.B \fB\-\-bwlimit\fP +Specify the maximum transfer rate in kilobytes per second. A value of \fB0\fP +indicates no limit. This setting overrides the \fBbandwidth_limit\fP configuration +option. +.TP +.B \fB\-\-exclusive\fP +Set target (time, XID or LSN) to be non inclusive. +.TP +.B \fB\-\-gcp\-zone\fP +Specify the GCP zone where the instance and disks for snapshot recovery are located. +This option allows you to override the \fBgcp_zone\fP value in the Barman +configuration. +.TP +.B \fB\-\-get\-wal\fP / \fB\-\-no\-get\-wal\fP +Enable/disable usage of \fBget\-wal\fP for WAL fetching during recovery. Default is based on +\fBrecovery_options\fP setting. +.TP +.B \fB\-j\fP / \fB\-\-jobs\fP +Specify the number of parallel workers to use for copying files during the backup. +This setting overrides the \fBparallel_jobs\fP parameter if it is specified in the +configuration file. +.TP +.B \fB\-\-jobs\-start\-batch\-period\fP +Specify the time period, in seconds, for starting a single batch of jobs. This value +overrides the \fBparallel_jobs_start_batch_period\fP parameter if it is set in the +configuration file. The default is \fB1\fP second. +.TP +.B \fB\-\-jobs\-start\-batch\-size\fP +Specify the maximum number of parallel workers to initiate in a single batch. This +value overrides the \fBparallel_jobs_start_batch_size\fP parameter if it is defined in +the configuration file. The default is \fB10\fP workers. +.TP +.B \fB\-\-local\-staging\-path\fP +Specify path on the Barman host where the chain of backups will be combined before +being copied to the destination directory. The contents created within the staging +path will be removed upon completion of the restore process. This option is +necessary for restoring from block\-level incremental backups and has no effect +otherwise. +.TP +.B \fB\-\-network\-compression\fP / \fB\-\-no\-network\-compression\fP +Enable/disable network compression during remote restore. Default is based on +\fBnetwork_compression\fP configuration setting. +.TP +.B \fB\-\-no\-retry\fP +There will be no retry in case of an error. It is the same as setting +\fB\-\-retry\-times 0\fP\&. +.TP +.B \fB\-\-recovery\-conf\-filename\fP +Specify the name of the file where Barman should write recovery options when +recovering backups for Postgres versions 12 and later. By default, this is set to +\fBpostgresql.auto.conf\fP\&. However, if \fB\-\-recovery\-conf\-filename\fP is specified, +recovery options will be written to the specified value instead. While the default +value is suitable for most Postgres installations, this option allows you to specify +an alternative location if Postgres is managed by tools that alter the configuration +mechanism (for example, if \fBpostgresql.auto.conf\fP is symlinked to \fB/dev/null\fP). +.TP +.B \fB\-\-recovery\-staging\-path\fP +Specify a path on the recovery host where files for a compressed backup will be +staged before being uncompressed to the destination directory. Backups will be +staged in their own directory within the staging path, following the naming +convention: \fBbarman\-staging\-SERVER_NAME\-BACKUP_ID\fP\&. This staging directory will be +removed after the restore process is complete. This option is mandatory for +restoring from compressed backups and has no effect otherwise. +.TP +.B \fB\-\-remote\-ssh\-command\fP +This option enables remote restore by specifying the secure shell command to +execute on a remote host. It functions similarly to the \fBssh_command\fP server +option in the configuration file for remote restore, that is, \fB\(aqssh USER@SERVER\(aq\fP\&. +.TP +.B \fB\-\-retry\-sleep\fP +Specify the number of seconds to wait after a failed copy before retrying. This +setting applies to both backup and restore operations and overrides the +\fBbasebackup_retry_sleep\fP parameter if it is defined in the configuration file. +.TP +.B \fB\-\-retry\-times\fP +Specify the number of times to retry the base backup copy in case of an error. This +applies to both backup and restore operations and overrides the +\fBbasebackup_retry_times\fP parameter if it is set in the configuration file. +.TP +.B \fB\-\-snapshot\-recovery\-instance\fP +Specify the name of the instance where the disks recovered from the snapshots are +attached. This option is necessary when recovering backups created with +\fBbackup_method=snapshot\fP\&. +.TP +.B \fB\-\-standby\-mode\fP +Whether to start the Postgres server as a standby. +.TP +.B \fB\-\-tablespace\fP +Specify tablespace relocation rule. \fBNAME\fP is the tablespace name and \fBLOCATION\fP +is the recovery host destination path to restore the tablespace. +.TP +.B \fB\-\-target\-action\fP +Trigger the specified action when the recovery target is reached. This option +requires defining a target along with one of these actions. The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBpause\fP: Once recovery target is reached, the server is started in pause state, +allowing users to inspect the instance +.IP \(bu 2 +\fBpromote\fP: Once recovery target is reached, the server will exit the recovery +operation and is promoted as a master. +.IP \(bu 2 +\fBshutdown\fP: Once recovery target is reached, the server is shut down. +.UNINDENT +.TP +.B \fB\-\-target\-immediate\fP +Recovery is completed when a consistent state is reached (end of the base backup). +.TP +.B \fB\-\-target\-lsn\fP +Recover to the specified LSN (Log Sequence Number). Requires Postgres 10 or above. +.TP +.B \fB\-\-target\-name\fP +Recover to the specified name of a restore point previously created with the +\fBpg_create_restore_point(name)\fP\&. +.TP +.B \fB\-\-target\-time\fP +Recover to the specified time. Use the format \fBYYYY\-MM\-DD HH:MM:SS.mmm\fP\&. +.TP +.B \fB\-\-target\-tli\fP +Recover the specified timeline. You can use the special values \fBcurrent\fP and +\fBlatest\fP in addition to a numeric timeline ID. For Postgres versions 12 and above, +the default is to recover to the latest timeline in the WAL archive. For Postgres +versions below 12, the default is to recover to the timeline that was current at the +time the backup was taken. +.TP +.B \fB\-\-target\-xid\fP +Recover to the specified transaction ID. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman replication\-status\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +replication\-status + [ \-\-minimal ] + [ \-\-source { backup\-host | wal\-host } ] + [ \-\-target { hot\-standby | wal\-streamer | all } ] +SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display real\-time information and status of any streaming clients connected to the +specified server. Specify \fBall\fP shortcut to diplay information for all configured +servers. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-\-minimal\fP +Machine readable output. +.TP +.B \fB\-\-source\fP +The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBbackup\-host\fP (default): List clients using the backup connection information +for a server. +.IP \(bu 2 +\fBwal\-host\fP: List clients using the WAL streaming connection information for a +server. +.UNINDENT +.TP +.B \fB\-\-target\fP +The possible values are: +.INDENT 7.0 +.IP \(bu 2 +\fBhot\-standby\fP: List only hot standby servers. +.IP \(bu 2 +\fBwal\-streamer\fP: List only WAL streaming clients, such as \fBpg_receivewal\fP\&. +.IP \(bu 2 +\fBall\fP (default): List all streaming clients. +.UNINDENT +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBSERVER_NAME\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman show\-backup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +show\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display detailed information about a specific backup. You can find details about this command in +\fI\%Catalog usage\fP\&. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +Use shortcuts instead of \fBBACKUP_ID\fP\&. +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman show\-servers\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +show\-servers SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display detailed information about a server, including \fBconninfo\fP, \fBbackup_directory\fP, +\fBwals_directory\fP, \fBarchive_command\fP, and many more. To view information about all configured +servers, specify the \fBall\fP shortcut instead of the server name. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SS Shortcuts +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman status\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +status SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Display information about a server\(aqs status, including details such as the state, +Postgres version, WAL information, available backups and more. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SS Shortcuts +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBall\fP +T} T{ +All available servers +T} +.TE +.SS \fBbarman switch\-wal\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +switch\-wal + [ \-\-archive ] + [ \-\-archive\-timeout ] + [ \-\-force ] + SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Execute \fBpg_switch_wal()\fP on the target server (Postgres versions 10 and later) or +\fBpg_switch_xlog()\fP (for Postgres versions 8.3 to 9.6). +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fB\-\-archive\fP +Waits for one WAL file to be archived. If no WAL file is archived within a specified +time (default: \fB30\fP seconds), Barman will terminate with a failure exit code. This +option is also available on standby servers. +.TP +.B \fB\-\-archive\-timeout\fP +Specify the amount of time in seconds (default: \fB30\fP seconds) that the archiver +will wait for a new WAL file to be archived before timing out. This option is also +available on standby servers. +.TP +.B \fB\-\-force\fP +Forces the switch by executing a CHECKPOINT before \fBpg_switch_wal()\fP\&. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Running a CHECKPOINT may increase I/O load on the Postgres server, so use this +option cautiously. +.UNINDENT +.UNINDENT +.UNINDENT +.SS \fBbarman switch\-xlog\fP +.SS Description +.sp +Alias for the \fBswitch\-wal\fP command. +.SS \fBbarman sync\-backup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +This command synchronizes a passive node with its primary by copying all files from a +backup present on the server node. It is available only for passive nodes and uses +the \fBprimary_ssh_command\fP option to establish a secure connection with the primary +node. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +For some commands, instead of using the timestamp backup ID, you can use the following +shortcuts or aliases to identify a backup for a given server: +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman sync\-info\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-info [ \-\-primary ] SERVER_NAME [ LAST_WAL [ LAST_POS ] ] +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Gather information about the current status of a Barman server for synchronization +purposes. +.sp +This command returns a JSON output for a server that includes: all successfully +completed backups, all archived WAL files, the configuration, the last WAL file read from +\fBxlog.db\fP, and its position within the file. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBLAST_WAL\fP +Instructs sync\-info to skip any WAL files that precede the specified file (for +incremental synchronization). +.TP +.B \fBLAST_POS\fP +Hint for quickly positioning in the \fBxlog.db\fP file (for incremental synchronization). +.UNINDENT +.SS \fBbarman sync\-wals\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +sync\-wals SERVER_NAME +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +This command synchronizes a passive node with its primary by copying all archived WAL +files from the server node. It is available only for passive nodes and utilizes the +\fBprimary_ssh_command\fP option to establish a secure connection with the primary node. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.UNINDENT +.SS \fBbarman verify\-backup\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +verify\-backup SERVER_NAME BACKUP_ID +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +Runs \fBpg_verifybackup\fP on a backup manifest file (available since Postgres version 13). +For rsync backups, it can be used after creating a manifest file using the +\fBgenerate\-manifest\fP command. Requires \fBpg_verifybackup\fP to be installed on the +backup server. You can use a shortcut instead of \fBBACKUP_ID\fP\&. +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +Name of the server in barman node +.TP +.B \fBBACKUP_ID\fP +Id of the backup in barman catalog. +.UNINDENT +.SS Shortcuts +.sp +For some commands, instead of using the timestamp backup ID, you can use the following +shortcuts or aliases to identify a backup for a given server: +.TS +box center; +l|l. +T{ +\fBShortcut\fP +T} T{ +\fBDescription\fP +T} +_ +T{ +\fBfirst/oldest\fP +T} T{ +Oldest available backup for the server, in chronological order. +T} +_ +T{ +\fBlast/latest\fP +T} T{ +Most recent available backup for the server, in chronological order. +T} +_ +T{ +\fBlast\-full/latest\-full\fP +T} T{ +Most recent full backup eligible for a block\-level incremental backup using the +\fB\-\-incremental\fP option. +T} +_ +T{ +\fBlast\-failed\fP +T} T{ +Most recent backup that failed, in chronological order. +T} +.TE +.SS \fBbarman verify\fP +.SS Description +.sp +Alias for \fBverify\-backup\fP command. +.SH BARMAN-CLI COMMANDS +.sp +The \fBbarman\-cli\fP package includes a collection of recommended client utilities that +should be installed alongside the Postgres server. Here are the command references for +both utilities. +.SS \fBbarman\-wal\-archive\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-wal\-archive + [ { \-h, \-\-help } ] + [ { \-V, \-\-version } ] + [ { \-U, \-\-user } USER ] + [ \-\-port PORT ] + [ { \-c, \-\-config } CONFIG ] + [ { \-t \-\-test } ] + BARMAN_HOST SERVER_NAME WAL_PATH +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +This script can be utilized in the \fBarchive_command\fP of a Postgres server to +transfer WAL files to a Barman host using the \fBput\-wal\fP command (introduced in Barman +2.6). It establishes an SSH connection to the Barman host, enabling seamless integration +of Barman within Postgres clusters for improved business continuity. +.sp +\fBExit Statuses\fP are: +.INDENT 0.0 +.IP \(bu 2 +\fB0\fP for \fBSUCCESS\fP\&. +.IP \(bu 2 +\fBnon\-zero\fP for \fBFAILURE\fP\&. +.UNINDENT +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +The server name configured in Barman for the Postgres server from which +the WAL file is retrieved. +.TP +.B \fBBARMAN_HOST\fP +The host of the Barman server. +.TP +.B \fBWAL_PATH\fP +The value of the \(aq%p\(aq keyword (according to \fBarchive_command\fP). +.TP +.B \fB\-h\fP / \fB\-\-help\fP +Display a help message and exit. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Display the program\(aqs version number and exit. +.TP +.B \fB\-U\fP / \fB\-\-user\fP +Specify the user for the SSH connection to the Barman server (defaults to +\fBbarman\fP). +.TP +.B \fB\-\-port\fP +Define the port used for the SSH connection to the Barman server. +.TP +.B \fB\-c\fP / \fB\-\-config\fP +Specify the configuration file on the Barman server. +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test the connection and configuration of the specified Postgres server in Barman to +ensure it is ready to receive WAL files. This option ignores the mandatory arguments +\fBWAL_NAME\fP and \fBWAL_DEST\fP\&. +.UNINDENT +.SS \fBbarman\-wal\-restore\fP +.SS Synopsis +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +barman\-wal\-restore + [ { \-h, \-\-help } ] + [ { \-V, \-\-version } ] + [ { \-U, \-\-user } USER ] + [ \-\-port PORT ] + [ { \-s, \-\-sleep } SECONDS ] + [ { \-p, \-\-parallel } JOBS ] + [ \-\-spool\-dir SPOOL_DIR ] + [ { \-P, \-\-partial } ] + [ { \-z, \-\-gzip } ] + [ { \-j, \-\-bzip2 } ] + [ { \-c, \-\-config } CONFIG ] + [ { \-t \-\-test } ] + BARMAN_HOST SERVER_NAME WAL_NAME WAL_DEST +.EE +.UNINDENT +.UNINDENT +.SS Description +.sp +This script serves as a \fBrestore_command\fP for Postgres servers, enabling the +retrieval of WAL files through Barman\(aqs \fBget\-wal\fP feature. It establishes an SSH +connection to the Barman host and facilitates the integration of Barman within +Postgres clusters, enhancing business continuity. +.sp +\fBExit Statuses\fP are: +.INDENT 0.0 +.IP \(bu 2 +\fB0\fP for \fBSUCCESS\fP\&. +.IP \(bu 2 +\fB1\fP for remote get\-wal command \fBFAILURE\fP, likely because the requested WAL could +not be found. +.IP \(bu 2 +\fB2\fP for ssh connection \fBFAILURE\fP\&. +.IP \(bu 2 +Any other \fBnon\-zero\fP for \fBFAILURE\fP\&. +.UNINDENT +.SS Parameters +.INDENT 0.0 +.TP +.B \fBSERVER_NAME\fP +The server name configured in Barman for the Postgres server from which the +WAL file is retrieved. +.TP +.B \fBBARMAN_HOST\fP +The host of the Barman server. +.TP +.B \fBWAL_NAME\fP +The value of the \(aq%f\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fBWAL_DEST\fP +The value of the \(aq%p\(aq keyword (according to \fBrestore_command\fP). +.TP +.B \fB\-h\fP / \fB\-\-help\fP +Display a help message and exit. +.TP +.B \fB\-V\fP / \fB\-\-version\fP +Display the program\(aqs version number and exit. +.TP +.B \fB\-U\fP / \fB\-\-user\fP +Specify the user for the SSH connection to the Barman server (defaults to +\fBbarman\fP). +.TP +.B \fB\-\-port\fP +Define the port used for the SSH connection to the Barman server. +.TP +.B \fB\-s\fP / \fB\-\-sleep\fP +Pause for \fBSECONDS\fP after a failed \fBget\-wal\fP request (defaults to \fB0\fP \- no +wait). +.TP +.B \fB\-p\fP / \fB\-\-parallel\fP +Indicate the number of files to \fBpeek\fP and transfer simultaneously (defaults to +\fB0\fP \- disabled). +.TP +.B \fB\-\-spool\-dir\fP +Specify the spool directory for WAL files (defaults to \fB/var/tmp/walrestore\fP). +.TP +.B \fB\-P\fP / \fB\-\-partial\fP +Include partial WAL files (.partial) in the retrieval. +.TP +.B \fB\-z\fP / \fB\-\-gzip\fP +Transfer WAL files compressed with \fBgzip\fP\&. +.TP +.B \fB\-j\fP / \fB\-\-bzip2\fP +Transfer WAL files compressed with \fBbzip2\fP\&. +.TP +.B \fB\-\-keep\-compression\fP +If specified, compressed files will be trasnfered as\-is and decompressed on arrival +on the client\-side. +.TP +.B \fB\-c\fP / \fB\-\-config\fP +Specify the configuration file on the Barman server. +.TP +.B \fB\-t\fP / \fB\-\-test\fP +Test the connection and configuration of the specified Postgres server in Barman to +ensure it is ready to receive WAL files. This option ignores the mandatory arguments +\fBWAL_NAME\fP and \fBWAL_DEST\fP\&. +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +\fB\-z\fP / \fB\-\-gzip\fP and \fB\-j\fP / \fB\-\-bzip2\fP options are deprecated and will be +removed in the future. For WAL compression, please make sure to enable it directly +on the Barman server via the \fBcompression\fP configuration option. +.UNINDENT +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/docs/_build/man/barman.5 b/docs/_build/man/barman.5 new file mode 100644 index 000000000..5e9ebde59 --- /dev/null +++ b/docs/_build/man/barman.5 @@ -0,0 +1,1349 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BARMAN" "5" "Nov 21, 2024" "3.12" "Barman" +.SH NAME +barman \- Barman Configurations +.sp +Barman follows a convention over configuration approach, which simplifies configuration +by allowing some options to be defined globally and overridden at the server level. This +means you can set a default behavior for your servers and then customize specific servers +as needed. This design reduces the need for excessive configuration while maintaining +flexibility. +.SH USAGE +.sp +Proper configuration is critical for its effective operation. Barman uses different types +of configuration files to manage global settings, server\-specific settings, and +model\-specific settings that is made up of three scopes: +.sp +1. \fBGlobal Configuration\fP: It comprises one file with a set of configurations for the +barman system, such as the main directory, system user, log file, and other general +options. Default location is \fB/etc/barman.conf\fP and it can be overridden on a per\-user +level by \fB~/.barman.conf\fP or by specifying a \fB\&.conf\fP file using the \fB\-c\fP / +\fB\-\-config\fP with the \fI\%barman command\fP directly in the CLI. +.sp +2. \fBServer Configuration\fP: It comprises one or more files with a set of +configurations for a Postgres server that you want to keep track and interact for +backup, recovery and/or replication. Default location is \fB/etc/barman.d\fP and must use +the \fB\&.conf\fP suffix. You may have one or multiple files for servers. You can override the +default location by setting the \fBconfiguration_files_directory\fP option in the global +configuration file and placing the files in that particular location. +.sp +3. \fBModel Configuration\fP: It comprises one or more files with a set of +configurations overrides that can be applied to Barman servers within the same cluster as +the model. These overrides can be implemented using the barman \fBconfig\-switch\fP command. +Default location is \fB/etc/barman.d\fP and must use the \fB\&.conf\fP suffix. The same +\fBconfiguration_files_directory\fP override option from the server configuration applies for +models. You may have one or multiple files for models. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Historically, you could have a single configuration file containing global, server, and +model options, but, for maintenance reasons, this approach is deprecated. +.UNINDENT +.UNINDENT +.sp +Configuration files follow the \fBINI\fP format and consist of sections denoted by headers +in square brackets. Each section can include various options. +.sp +Models and servers must have unique identifiers, and reserved words cannot be used as +names. +.sp +\fBReserved Words\fP +.sp +The following reserved words cannot be used as server or model names: +.INDENT 0.0 +.IP \(bu 2 +\fBbarman\fP: Identifies the global section. +.IP \(bu 2 +\fBall\fP: A special shortcut for executing commands on all managed servers. +.UNINDENT +.sp +\fBParameter Types\fP +.sp +Configuration options can be of the following types: +.INDENT 0.0 +.IP \(bu 2 +\fBString\fP: Textual data (e.g., file paths, names). +.IP \(bu 2 +\fBEnum\fP: Enumerated values, often limited to predefined choices. +.IP \(bu 2 +\fBInteger\fP: Numeric values. +.IP \(bu 2 +\fBBoolean\fP: Can be \fBon\fP, \fBtrue\fP, \fB1\fP (true) or \fBoff\fP, \fBfalse\fP, \fB0\fP +(false). +.sp +\fBNOTE:\fP +.INDENT 2.0 +.INDENT 3.5 +Some enums allow \fBoff\fP, but not \fBfalse\fP\&. +.UNINDENT +.UNINDENT +.UNINDENT +.SH OPTIONS +.sp +Options in the configuration files can have specific or shared scopes. The following +configuration options are used not only for configuring how Barman will execute backups +and recoveries, but also for configuring various aspects of how Barman interacts with the +configured Postgres servers to be able to apply your Backup and Recovery, and +High\-Availability strategies. +.SS General +.sp +These are general configurations options. +.sp +\fBactive\fP +.sp +When this option is set to \fBtrue\fP (default), the server operates fully. If set to +\fBfalse\fP, the server is restricted to diagnostic use only, meaning that operational +commands such as backup execution or WAL archiving are temporarily disabled. When +incorporating a new server into Barman, we recommend initially setting +\fBactive = false\fP\&. Verify that barman check shows no issues before activating the +server. This approach helps prevent excessive error logging in Barman during the +initial setup. +.sp +Scope: Server / Model. +.sp +\fBarchiver\fP +.sp +This option enables log file shipping through Postgres\(aq \fBarchive_command\fP for a +server. When set to \fBtrue\fP, Barman expects continuous archiving to be configured and +will manage WAL files that Postgres stores in the incoming directory +(\fBincoming_wals_directory\fP), including their checks, handling, and compression. When +set to \fBfalse\fP (default), continuous archiving is disabled. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +If neither \fBarchiver\fP nor \fBstreaming_archiver\fP is configured, Barman will +automatically set this option to \fBtrue\fP to maintain compatibility with the +previous default behavior where archiving was enabled by default. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBarchiver_batch_size\fP +.sp +This option enables batch processing of WAL files for the archiver process by setting +it to a value greater than \fB0\fP\&. If not set, the archiver will use unlimited +(default) processing mode for the WAL queue. With batch processing enabled, the +archiver process will handle a maximum of \fBarchiver_batch_size\fP WAL segments per +run. This value must be an integer. +.sp +Scope: Global / Server / Model. +.sp +\fBbandwidth_limit\fP +.sp +Specifies the maximum transfer rate in kilobytes per second for backup and recovery +operations. A value of \fB0\fP indicates no limit (default). +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = postgres | rsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbarman_home\fP +.sp +Designates the main data directory for Barman. Defaults to \fB/var/lib/barman\fP\&. +.sp +Scope: Global. +.sp +\fBbarman_lock_directory\fP +.sp +Specifies the directory for lock files. The default is \fBbarman_home\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The \fBbarman_lock_directory\fP should be on a non\-network local filesystem. +.UNINDENT +.UNINDENT +.sp +Scope: Global. +.sp +\fBbasebackup_retry_sleep\fP +.sp +Sets the number of seconds to wait after a failed base backup copy before retrying. +Default is \fB30\fP seconds. Must be a non\-negative integer. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This applies to both backup and recovery operations. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbasebackup_retry_times\fP +.sp +Defines the number of retry attempts for a base backup copy after an error occurs. +Default is \fB0\fP (no retries). Must be a non\-negative integer. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This applies to both backup and recovery operations. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBcheck_timeout\fP +.sp +Sets the maximum execution time in seconds for a Barman check command per server. Set +to \fB0\fP to disable the timeout. Default is \fB30\fP seconds. Must be a non\-negative +integer. +.sp +Scope: Global / Server / Model. +.sp +\fBcluster\fP +.sp +Tag the server or model to an associated cluster name. Barman uses this association to +override configuration for all servers/models in this cluster. If omitted for servers, +it defaults to the server\(aqs name. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Must be specified for configuration models to group applicable servers. +.UNINDENT +.UNINDENT +.sp +Scope: Server / Model. +.sp +\fBconfig_changes_queue\fP +.sp +Designates the filesystem location for Barman\(aqs queue that handles configuration changes +requested via the barman \fBconfig\-update\fP command. This queue manages the +serialization and retry of configuration change requests. By default, Barman writes to +a file named \fBcfg_changes.queue\fP under \fBbarman_home\fP\&. +.sp +Scope: Global. +.sp +\fBconfiguration_files_directory\fP +.sp +Designates the directory where server/model configuration files will be read by Barman. +Defaults to \fB/etc/barman.d/\fP\&. +.sp +Scope: Global. +.sp +\fBconninfo\fP +.sp +Specifies the connection string used by Barman to connect to the Postgres server. +This is a libpq connection string. Commonly used keys include: \fBhost\fP, \fBhostaddr\fP, +\fBport\fP, \fBdbname\fP, \fBuser\fP and \fBpassword\fP\&. See the +\X'tty: link https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING'\fI\%PostgreSQL documentation\fP\X'tty: link' +for details. +.sp +Scope: Server / Model. +.sp +\fBcreate_slot\fP +.sp +Determines whether Barman should automatically create a replication slot if it\(aqs not +already present for streaming WAL files. When set to \fBauto\fP and \fBslot_name\fP is +defined, Barman will attempt to create the slot automatically. When set to \fBmanual\fP +(default), the replication slot must be created manually. +.sp +Scope: Global / Server / Model. +.sp +\fBdescription\fP +.sp +Provides a human\-readable description of a server. +.sp +Scope: Server / Model. +.sp +\fBerrors_directory\fP +.sp +The directory where WAL files that were errored while being archived by Barman are +stored. This includes duplicate WAL files (e.g., an archived WAL file that has already +been streamed but have different hash) and unexpected files found in the WAL archive +directory. +.sp +The purpose of placing the files in this directory is so someone can later review why they +failed to be archived and take appropriate actions (dispose of, store somewhere else, +replace the duplicate file archived before, etc.) +.sp +Scope: Server. +.sp +\fBforward_config_path\fP +.sp +Determines whether a passive node should forward its configuration file path to its +primary node during \fBcron\fP or \fBsync\-info\fP commands. Set to \fBtrue\fP if Barman is +invoked with the \fB\-c\fP / \fB\-\-config\fP option and the configuration paths are identical +on both passive and primary Barman servers. Defaults to \fBfalse\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBimmediate_checkpoint\fP +.sp +Controls how Postgres handles checkpoints at the start of a backup. Set to \fBfalse\fP +(default) to allow the checkpoint to complete according to +\fBcheckpoint_completion_target\fP\&. Set to \fBtrue\fP for an immediate checkpoint, where +Postgres completes the checkpoint as quickly as possible. +.sp +Scope: Global / Server / Model. +.sp +\fBkeepalive_interval\fP +.sp +Sets the interval in seconds for sending a heartbeat query to keep the libpq +connection active during an rsync backup. Default is \fB60\fP seconds. Setting this to +\fB0\fP disables the heartbeat. +.sp +Scope: Global / Server / Model. +.sp +\fBlock_directory_cleanup\fP +.sp +Enables automatic cleanup of unused lock files in the \fBbarman_lock_directory\fP\&. +.sp +Scope: Global. +.sp +\fBlog_file\fP +.sp +Specifies the location of Barman\(aqs log file. Defaults to \fB/var/log/barman/barman.log\fP\&. +.sp +Scope: Global. +.sp +\fBlog_level\fP +.sp +Sets the level of logging. Options include: \fBDEBUG\fP, \fBINFO\fP, \fBWARNING\fP, +\fBERROR\fP and \fBCRITICAL\fP\&. +.sp +Scope: Global. +.sp +\fBminimum_redundancy\fP +.sp +Specifies the minimum number of backups to retain. Default is \fB0\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBmodel\fP +.sp +When set to \fBtrue\fP, turns a server section from a configuration file into a model for +a cluster. There is no \fBfalse\fP option in this case. If you want to simulate a +\fBfalse\fP option, comment out (\fB#model=true\fP) or remove the option in the +configuration. Defaults to the server name. +.sp +Scope: Model. +.sp +\fBnetwork_compression\fP +.sp +Enables or disables data compression for network transfers. Set to \fBfalse\fP (default) +to disable compression, or \fBtrue\fP to enable it and reduce network usage. +.sp +Scope: Global / Server / Model. +.sp +\fBparallel_jobs\fP +.sp +Controls the number of parallel workers used to copy files during backup or recovery. +It must be a positive integer. Default is \fB1\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = rsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBparallel_jobs_start_batch_period\fP +.sp +Specifies the time interval in seconds over which a single batch of parallel jobs will +start. Default is \fB1\fP second. This means that if \fBparallel_jobs_start_batch_size\fP +is \fB10\fP and \fBparallel_jobs_start_batch_period\fP is \fB1\fP, this will yield an +effective rate limit of \fB10\fP jobs per second, because there is a maximum of \fB10\fP +jobs that can be started within \fB1\fP second. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = rsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBparallel_jobs_start_batch_size\fP +.sp +Defines the maximum number of parallel jobs to start in a single batch. Default is +\fB10\fP jobs. This means that if \fBparallel_jobs_start_batch_size\fP +is \fB10\fP and \fBparallel_jobs_start_batch_period\fP is \fB2\fP, this will yield a maximum +of \fB10\fP jobs that can be started within \fB2\fP seconds. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = rsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBpath_prefix\fP +.sp +Lists one or more absolute paths, separated by colons, where Barman looks for executable +files. These paths are checked before the \fBPATH\fP environment variable. This option can +be set for each server and needs to point to the \fBbin\fP directory for the appropriate +\fBPG_MAJOR_VERSION\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBprimary_checkpoint_timeout\fP +.sp +Time to wait for new WAL files before forcing a checkpoint on the primary server. +Defaults to \fB0\fP\&. +.sp +Scope: Server / Model. +.sp +\fBprimary_conninfo\fP +.sp +Connection string for Barman to connect to the primary Postgres server during a +standby backup. +.sp +Scope: Server / Model. +.sp +\fBprimary_ssh_command\fP +.sp +SSH command for connecting to the primary Barman server if Barman is passive. +.sp +Scope: Global / Server / Model. +.sp +\fBslot_name\fP +.sp +Replication slot name for the \fBreceive\-wal\fP command when \fBstreaming_archiver\fP is +enabled. +.sp +Scope: Global / Server / Model. +.sp +\fBssh_command\fP +.sp +SSH command used by Barman to connect to the Postgres server for rsync backups. +.sp +Scope: Server / Model. +.sp +\fBstreaming_archiver\fP +.sp +Enables Postgres\(aq streaming protocol for WAL files. Defaults to \fBfalse\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +If neither \fBarchiver\fP nor \fBstreaming_archiver\fP is configured, Barman will +automatically set \fBarchiver\fP option to \fBtrue\fP to maintain compatibility with the +previous default behavior where archiving was enabled by default. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBstreaming_archiver_batch_size\fP +.sp +Batch size for processing WAL files in streaming archiver. Defaults to \fB0\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBstreaming_archiver_name\fP +.sp +Application name for the \fBreceive\-wal\fP command. Defaults to \fBbarman_receive_wal\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBstreaming_backup_name\fP +.sp +Application name for the \fBpg_basebackup\fP command. Defaults to +\fBbarman_streaming_backup\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBstreaming_conninfo\fP +.sp +Connection string for streaming replication protocol. Defaults to \fBconninfo\fP\&. +.sp +Scope: Server / Model. +.sp +\fBtablespace_bandwidth_limit\fP +.sp +Maximum transfer rate for specific tablespaces for backup and recovery operations. +A value of \fB0\fP indicates no limit (default). +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = rsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.SS Backups +.sp +These configurations options are related to how Barman will execute backups. +.sp +\fBautogenerate_manifest\fP +.sp +This is a boolean option that allows for the automatic creation of backup manifest +files. The manifest file, which is a JSON document, lists all files included in the +backup. It is generated upon completion of the backup and saved in the backup +directory. The format of the manifest file adheres to the specifications outlined in the +\X'tty: link https://www.postgresql.org/docs/current/backup-manifest-format.html'\fI\%PostgreSQL documentation\fP\X'tty: link' +and is compatible with the \fBpg_verifybackup\fP tool. Default is \fBfalse\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This option is ignored if the \fBbackup_method\fP is not \fBrsync\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_compression\fP +.sp +Specifies the compression method for the backup process. It can be set to \fBgzip\fP, +\fBlz4\fP, \fBzstd\fP, or \fBnone\fP\&. Ensure that the CLI tool for the chosen compression +method is available on both the Barman and Postgres servers. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Note that \fBlz4\fP and \fBzstd\fP require Postgres version 15 or later. Unsetting this +option or using \fBnone\fP results in an uncompressed archive (default). Only +supported when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_compression_format\fP +.sp +Determines the format \fBpg_basebackup\fP should use when saving compressed backups. +Options are \fBplain\fP or \fBtar\fP, with \fBtar\fP as the default if unset. The \fBplain\fP +format is available only if Postgres version 15 or later is in use and +\fBbackup_compression_location\fP is set to \fBserver\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_compression_level\fP +.sp +Defines the level of compression for backups as an integer. The permissible values +depend on the compression method specified in \fBbackup_compression\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_compression_location\fP +.sp +Specifies where compression should occur during the backup: either \fBclient\fP or +\fBserver\fP\&. The \fBserver\fP option is available only if Postgres version 15 or later is +being used. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_compression_workers\fP +.sp +Sets the number of threads used for compression during the backup process. This is +applicable only when \fBbackup_compression=zstd\fP\&. The default value is 0, which uses +the standard compression behavior. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_directory\fP +.sp +Specifies the directory where backup data for a server will be stored. Defaults to +\fB/\fP\&. +.sp +Scope: Server. +.sp +\fBbackup_method\fP +.sp +Defines the method Barman uses to perform backups. Options include: +.INDENT 0.0 +.IP \(bu 2 +\fBrsync\fP (default): Executes backups using the rsync command over SSH (requires +\fBssh_command\fP). +.IP \(bu 2 +\fBpostgres\fP: Uses the \fBpg_basebackup\fP command for backups. +.IP \(bu 2 +\fBlocal\-rsync\fP: Assumes Barman runs on the same server and as the same user as +the Postgres database, performing an rsync file system copy. +.IP \(bu 2 +\fBsnapshot\fP: Utilizes the API of the cloud provider specified in the +\fBsnapshot_provider\fP option to create disk snapshots as defined in +\fBsnapshot_disks\fP and saves only the backup label and metadata to its own +storage. +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbackup_options\fP +.sp +Controls how Barman interacts with Postgres during backups. This is a comma\-separated +list that can include: +.INDENT 0.0 +.IP \(bu 2 +\fBconcurrent_backup\fP (default): Uses concurrent backup, recommended for +Postgres versions 9.6 and later, and supports backups from standby servers. +.IP \(bu 2 +\fBexclusive_backup\fP: Uses the deprecated exclusive backup method. Only for Postgres +versions older than 15. This option will be removed in the future. +.IP \(bu 2 +\fBexternal_configuration\fP: Suppresses warnings about external configuration files +during backup execution. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +\fBexclusive_backup\fP and \fBconcurrent_backup\fP cannot be used together. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBbasebackups_directory\fP +.sp +Specifies the directory where base backups are stored. Defaults to +\fB/base\fP\&. +.sp +Scope: Server. +.sp +\fBreuse_backup\fP +.sp +Controls incremental backup support when using \fBbackup_method=rsync\fP by reusing the +last available backup. The options are: +.INDENT 0.0 +.IP \(bu 2 +\fBoff\fP (default): Standard full backup. +.IP \(bu 2 +\fBcopy\fP: File\-level incremental backup, by reusing the last backup for a server and +creating a copy of the unchanged files (just for backup time reduction) +.IP \(bu 2 +\fBlink\fP: File\-level incremental backup, by reusing the last backup for a server and +creating a hard link of the unchanged files (for backup space and time reduction) +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This option will be ignored when \fBbackup_method=postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.SS Cloud Backups +.sp +These configuration options are related to how Barman will execute backups in the cloud. +.sp +\fBaws_await_snapshots_timeout\fP +.sp +Specifies the duration in seconds to wait for AWS snapshots to be created before a +timeout occurs. The default value is \fB3600\fP seconds. This must be a positive +integer. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = aws\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBaws_profile\fP +.sp +The name of the AWS profile to use when authenticating with AWS (e.g. \fBINI\fP section +in AWS credentials file). +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = aws\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBaws_region\fP +.sp +Indicates the AWS region where the EC2 VM and storage volumes, as defined by +\fBsnapshot_instance\fP and \fBsnapshot_disks\fP, are located. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = aws\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBazure_credential\fP +.sp +Specifies the type of Azure credential to use for authentication, either \fBazure\-cli\fP +or \fBmanaged\-identity\fP\&. If not provided, the default Azure authentication method will +be used. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = azure\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBazure_resource_group\fP +.sp +Specifies the name of the Azure resource group containing the compute instance and +disks defined by \fBsnapshot_instance\fP and \fBsnapshot_disks\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = azure\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBazure_subscription_id\fP +.sp +Identifies the Azure subscription that owns the instance and storage volumes defined by +\fBsnapshot_instance\fP and \fBsnapshot_disks\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = azure\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBgcp_project\fP +.sp +Specifies the ID of the GCP project that owns the instance and storage volumes defined +by \fBsnapshot_instance\fP and \fBsnapshot_disks\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = gcp\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBgcp_zone\fP +.sp +Indicates the availability zone where the compute instance and disks are located for +snapshot backups. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Only supported when \fBbackup_method = snapshot\fP and \fBsnapshot_provider = gcp\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Server / Model. +.sp +\fBsnapshot_disks\fP +.sp +This option is a comma\-separated list of disks to include in cloud snapshot backups. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Required when \fBbackup_method = snapshot\fP\&. +.sp +Ensure that the \fBsnapshot_disks\fP list includes all disks that store Postgres data, +as any data not on these listed disks will not be included in the backup and will be +unavailable during recovery. +.UNINDENT +.UNINDENT +.sp +Scope: Server / Model. +.sp +\fBsnapshot_instance\fP +.sp +The name of the VM or compute instance where the storage volumes are attached. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Required when \fBbackup_method = snapshot\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Server / Model. +.sp +\fBsnapshot_provider\fP +.sp +The name of the cloud provider to use for creating snapshots. Supported value: +\fBaws\fP, \fBazure\fP and \fBgcp\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Required when \fBbackup_method = snapshot\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.SS Hook Scripts +.sp +These configuration options are related to the pre or post execution of hook scripts. +.sp +\fBpost_archive_retry_script\fP +.sp +Specifies a hook script to run after a WAL file is archived. Barman will retry this +script until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or \fBABORT_STOP\fP +(63). In a post\-archive scenario, \fBABORT_STOP\fP has the same effect as +\fBABORT_CONTINUE\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_archive_script\fP +.sp +Specifies a hook script to run after a WAL file is archived, following the +\fBpost_archive_retry_script\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_backup_retry_script\fP +.sp +Specifies a hook script to run after a base backup. Barman will retry this script until +it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or \fBABORT_STOP\fP (63). In a +post\-backup scenario, \fBABORT_STOP\fP has the same effect as \fBABORT_CONTINUE\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_backup_script\fP +.sp +Specifies a hook script to run after a base backup, following the +\fBpost_backup_retry_script\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_delete_retry_script\fP +.sp +Specifies a hook script to run after deleting a backup. Barman will retry this script +until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or \fBABORT_STOP\fP (63). In +a post\-delete scenario, \fBABORT_STOP\fP has the same effect as \fBABORT_CONTINUE\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_delete_script\fP +.sp +Specifies a hook script to run after deleting a backup, following the +\fBpost_delete_retry_script\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_recovery_retry_script\fP +.sp +Specifies a hook script to run after a recovery. Barman will retry this script until it +returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or \fBABORT_STOP\fP (63). In a +post\-recovery scenario, \fBABORT_STOP\fP has the same effect as \fBABORT_CONTINUE\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_recovery_script\fP +.sp +Specifies a hook script to run after a recovery, following the +\fBpost_recovery_retry_script\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_wal_delete_retry_script\fP +.sp +Specifies a hook script to run after deleting a WAL file. Barman will retry this script +until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or \fBABORT_STOP\fP (63). In +a post\-WAL\-delete scenario, \fBABORT_STOP\fP has the same effect as \fBABORT_CONTINUE\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpost_wal_delete_script\fP +.sp +Specifies a hook script to run after deleting a WAL file, following the +\fBpost_wal_delete_retry_script\fP\&. +.sp +Scope: Global / Server. +.sp +\fBpre_archive_retry_script\fP +.sp +Specifies a hook script that runs before a WAL file is archived during maintenance, +following the \fBpre_archive_script\fP\&. As a retry hook script, Barman will repeatedly +execute the script until it returns either \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), +or \fBABORT_STOP\fP (63). Returning \fBABORT_STOP\fP will escalate the failure and halt +the WAL archiving process. +.sp +Scope: Global / Server. +.sp +\fBpre_archive_script\fP +.sp +Specifies a hook script launched before a WAL file is archived by maintenance. +.sp +Scope: Global / Server. +.sp +\fBpre_backup_retry_script\fP +.sp +Specifies a hook script that runs before a base backup, following the +\fBpre_backup_script\fP\&. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or +\fBABORT_STOP\fP (63). Returning \fBABORT_STOP\fP will escalate the failure and interrupt +the backup process. +.sp +Scope: Global / Server. +.sp +\fBpre_backup_script\fP +.sp +Specifies a hook script to run before starting a base backup. +.sp +Scope: Global / Server. +.sp +\fBpre_delete_retry_script\fP +.sp +Specifies a retry hook script to run before backup deletion, following the +\fBpre_delete_script\fP\&. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or +\fBABORT_STOP\fP (63). Returning \fBABORT_STOP\fP will escalate the failure and interrupt +the backup deletion. +.sp +Scope: Global / Server. +.sp +\fBpre_delete_script\fP +.sp +Specifies a hook script run before deleting a backup. +.sp +Scope: Global / Server. +.sp +\fBpre_recovery_retry_script\fP +.sp +Specifies a retry hook script to run before recovery, following the +\fBpre_recovery_script\fP\&. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or +\fBABORT_STOP\fP (63). Returning \fBABORT_STOP\fP will escalate the failure and interrupt +the recover process. +.sp +Scope: Global / Server. +.sp +\fBpre_recovery_script\fP +.sp +Specifies a hook script run before starting a recovery. +.sp +Scope: Global / Server. +.sp +\fBpre_wal_delete_retry_script\fP +.sp +Specifies a retry hook script for WAL file deletion, executed before +\fBpre_wal_delete_script\fP\&. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns \fBSUCCESS\fP (0), \fBABORT_CONTINUE\fP (62), or +\fBABORT_STOP\fP (63). Returning \fBABORT_STOP\fP will escalate the failure and interrupt +the WAL file deletion. +.sp +Scope: Global / Server. +.sp +\fBpre_wal_delete_script\fP +.sp +Specifies a hook script run before deleting a WAL file. +.sp +Scope: Global / Server. +.SS Write\-Ahead Logs (WAL) +.sp +These configuration options are related to how Barman will manage the Write\-Ahead Logs +(WALs) of the PostreSQL servers. +.sp +\fBcompression\fP +.sp +Specifies the standard compression algorithm for WAL files. Options include: \fBlz4\fP, +\fBxz\fP, \fBzstd\fP, \fBgzip\fP, \fBpybzip2\fP, \fBpigz\fP, \fBbzip2\fP, \fBpybzip2\fP and \fBcustom\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +All of these options require the module to be installed in the location where the +compression will occur. +.sp +The \fBcustom\fP option is for custom compression, which requires you to set the +following options as well: +.INDENT 0.0 +.IP \(bu 2 +\fBcustom_compression_filter\fP: a compression filter. +.IP \(bu 2 +\fBcustom_decompression_filter\fP: a decompression filter +.IP \(bu 2 +\fBcustom_compression_magic\fP: a hex string to identify a custom compressed wal +file. +.UNINDENT +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBcustom_compression_filter\fP +.sp +Specifies a custom compression algorithm for WAL files. It must be a \fBstring\fP that +will be used internally to create a bash command and it will prefix to the +following string \fB> \(dq$2\(dq < \(dq$1\(dq;\fP\&. Write to standard output and do not delete input +files. +.sp +\fBTIP:\fP +.INDENT 0.0 +.INDENT 3.5 +\fBcustom_compression_filter = \(dqxz \-c\(dq\fP +.sp +This is the same as running \fBxz \-c > \(dq$2\(dq < \(dq$1\(dq;\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBcustom_compression_magic\fP +.sp +Defines a custom magic value to identify the custom compression algorithm used in WAL +files. If this is set, Barman will avoid applying custom compression to WALs that have +already been compressed with the specified algorithm. If not configured, Barman will +apply custom compression to all WAL files, even those pre\-compressed. +.sp +\fBTIP:\fP +.INDENT 0.0 +.INDENT 3.5 +For example, in the \fBxz\fP compression algorithm, the magic number is used to detect +the format of \fB\&.xz\fP files. +.INDENT 0.0 +.TP +.B For xz files, the magic number is the following sequence of bytes: +Magic Number: \fBFD 37 7A 58 5A 00\fP +.TP +.B In hexadecimal representation, this can be expressed as: +Hex String: \fBfd377a585a00\fP +.UNINDENT +.sp +Reference: \X'tty: link https://tukaani.org/xz/xz-file-format-1.0.4.txt'\fI\%xz\-file\-format\fP\X'tty: link' +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBcustom_decompression_filter\fP +.sp +Specifies a custom decompression algorithm for compressed WAL files. It must be a +\fBstring\fP that will be used internally to create a bash command and it will +prefix to the following string \fB> \(dq$2\(dq < \(dq$1\(dq;\fP\&. It must correspond with the +compression algorithm used. +.sp +\fBTIP:\fP +.INDENT 0.0 +.INDENT 3.5 +\fBcustom_compression_filter = \(dqxz \-c \-d\(dq\fP +.sp +This is the same as running \fBxz \-c \-d > \(dq$2\(dq < \(dq$1\(dq;\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBincoming_wals_directory\fP +.sp +Specifies the directory where incoming WAL files are archived. Requires \fBarchiver\fP to +be enabled. Defaults to \fB/incoming\fP\&. +.sp +Scope: Server. +.sp +\fBlast_wal_maximum_age\fP +.sp +Defines the time frame within which the latest archived WAL file must fall. If the +latest WAL file is older than this period, the barman check command will report an +error. If left empty (default), the age of the WAL files is not checked. Format is the +same as \fBlast_backup_maximum_age\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBmax_incoming_wals_queue\fP +.sp +Defines the maximum number of WAL files allowed in the incoming queue (including both +streaming and archiving pools) before the barman check command returns an error. +Default is \fBNone\fP (disabled). +.sp +Scope: Global / Server / Model. +.sp +\fBstreaming_wals_directory\fP +.sp +Directory for streaming WAL files. Defaults to \fB/streaming\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This option is applicable when \fBstreaming_archiver\fP is activated. +.UNINDENT +.UNINDENT +.sp +Scope: Server. +.sp +\fBwal_conninfo\fP +.sp +The \fBwal_conninfo\fP connection string is used by Barman for monitoring the status of +the replication slot receiving WALs. If specified, it takes precedence over +\fBwal_streaming_conninfo\fP for these checks. If \fBwal_conninfo\fP is not set but +\fBwal_streaming_conninfo\fP is, \fBwal_conninfo\fP will fall back to +\fBwal_streaming_conninfo\fP\&. If neither \fBwal_conninfo\fP nor \fBwal_streaming_conninfo\fP +is set, \fBwal_conninfo\fP will fall back to \fBconninfo\fP\&. Both connection strings must +access a Postgres instance within the same cluster as defined by \fBstreaming_conninfo\fP +and \fBconninfo\fP\&. If both \fBwal_conninfo\fP and \fBwal_streaming_conninfo\fP are set, only +\fBwal_conninfo\fP needs the appropriate permissions to read settings and check the +replication slot status. However, if only \fBwal_streaming_conninfo\fP is set, it must +have the necessary permissions to perform these tasks. The required permissions include +roles such as \fBpg_monitor\fP, both \fBpg_read_all_settings\fP and \fBpg_read_all_stats\fP, +or superuser privileges. +.sp +Scope: Server / Model. +.sp +\fBwal_streaming_conninfo\fP +.sp +This connection string is used by Barman to connect to the Postgres server for receiving +WAL segments via streaming replication and checking the replication slot status, if +\fBwal_conninfo\fP is not set. If not specified, Barman defaults to using +\fBstreaming_conninfo\fP for these tasks. \fBwal_streaming_conninfo\fP must connect to a +Postgres instance within the same cluster as defined by \fBstreaming_conninfo\fP, and it +must support streaming replication. If both \fBwal_streaming_conninfo\fP and +\fBwal_conninfo\fP are set, only \fBwal_conninfo\fP needs the required permissions to read +settings and check the replication slot status. If only \fBwal_streaming_conninfo\fP is +specified, it must have these permissions. The necessary permissions include roles such +as \fBpg_monitor\fP, both \fBpg_read_all_settings\fP and \fBpg_read_all_stats\fP, or superuser +privileges. +.sp +Scope: Server / Model. +.sp +\fBwals_directory\fP +.sp +Directory containing WAL files. Defaults to \fB/wals\fP\&. +.sp +Scope: Server. +.SS Restore +.sp +These configuration options are related to how Barman manages restoration backups. +.sp +\fBlocal_staging_path\fP +.sp +Specifies the local path for combining block\-level incremental backups during recovery. +This location must have sufficient space to temporarily store the new synthetic backup. +Required for recovery from a block\-level incremental backup. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only when \fBbackup_method = postgres\fP\&. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBrecovery_options\fP +.sp +Options for recovery operations. Currently, only \fBget\-wal\fP is supported. This option +enables the creation of a basic \fBrestore_command\fP in the recovery configuration, +which uses the barman \fBget\-wal\fP command to retrieve WAL files directly from Barman\(aqs +WAL archive. This setting accepts a comma\-separated list of values and defaults to +empty. +.sp +Scope: Global / Server / Model. +.sp +\fBrecovery_staging_path\fP +.sp +Specifies the path on the recovery host for staging files from compressed backups. This +location must have sufficient space to temporarily store the compressed backup. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Applies only for commpressed backups. +.UNINDENT +.UNINDENT +.sp +Scope: Global / Server / Model. +.SS Retention Policies +.sp +These configuration options are related to how Barman manages retention policies of the +backups. +.sp +\fBlast_backup_maximum_age\fP +.sp +Defines the time frame within which the latest backup must fall. If the latest backup +is older than this period, the barman check command will report an error. If left +empty (default), the latest backup is always considered valid. The accepted format is +\fB\(dqn {DAYS|WEEKS|MONTHS}\(dq\fP, where \fBn\fP is an integer greater than zero. +.sp +Scope: Global / Server / Model. +.sp +\fBlast_backup_minimum_size\fP +.sp +Specifies the minimum acceptable size for the latest successful backup. If the latest +backup is smaller than this size, the barman check command will report an error. If +left empty (default), the latest backup is always considered valid. The accepted +format is \fB\(dqn {k|Ki|M|Mi|G|Gi|T|Ti}\(dq\fP and case\-sensitive, where \fBn\fP is an integer +greater than zero, with an optional SI or IEC suffix. k stands for kilo with k = 1000, +while Ki stands for kilobytes Ki = 1024. The rest of the options have the same +reasoning for greater units of measure. +.sp +Scope: Global / Server / Model. +.sp +\fBretention_policy\fP +.sp +Defines how long backups and WAL files should be retained. If this option is left blank, +no retention policies will be applied. Options include redundancy and recovery window +policies. +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +retention_policy = {REDUNDANCY value | RECOVERY WINDOW OF value {DAYS | WEEKS | MONTHS}} +.EE +.UNINDENT +.UNINDENT +.INDENT 0.0 +.IP \(bu 2 +\fBretention_policy = REDUNDANCY 2\fP will keep only 2 backups in the backup catalog +automatically deleting the older one as new backups are created. The number must be +a positive integer. +.IP \(bu 2 +\fBretention_policy = RECOVERY WINDOW OF 2 DAYS\fP will only keep backups needed to +recover to any point in time in the last two days, automatically deleting backups +that are older. The period number must be a positive integer, and the following +options can be applied to it: \fBDAYS\fP, \fBWEEKS\fP, \fBMONTHS\fP\&. +.UNINDENT +.sp +Scope: Global / Server / Model. +.sp +\fBretention_policy_mode\fP +.sp +Mode for enforcing retention policies. Currently only supports \fBauto\fP\&. +.sp +Scope: Global / Server / Model. +.sp +\fBwal_retention_policy\fP +.sp +Policy for retaining WAL files. Currently only \fBmain\fP is available. +.sp +Scope: Global / Server / Model. +.SH CONFIGURATION MODELS +.sp +Configuration models provide a systematic approach to manage and apply configuration +overrides for Postgres servers by organizing them under a specific \fBcluster\fP name. +.SS Purpose +.sp +The primary goal of a configuration model is to simplify the management of configuration +settings for Postgres servers grouped by the same \fBcluster\fP\&. By using a model, you can +apply a set of common configuration overrides, enhancing operational efficiency. They are +especially beneficial in clustered environments, allowing you to create various +configuration models that can be utilized during failover events. +.SS Application +.sp +The configurations defined in a model file can be applied to Postgres servers that share +the same \fBcluster\fP name specified in the model. Consequently, any server utilizing that +model can inherit these settings, promoting a consistent and adaptable configuration +across all servers. +.SS Usage +.sp +Model options can only be defined within a model section, which is identified in the same +way as a server section. It is important to ensure that there are no conflicts between +the identifiers of server sections and model sections. +.sp +To apply a configuration model, execute the +\fBbarman config\-switch SERVER_NAME MODEL_NAME\fP\&. This command facilitates the application +of the model\(aqs overrides to the relevant Barman server associated with the specified +cluster name. +.sp +If you wish to remove the overrides, the deletion of the model configuration file alone +will not have any effect, so you can do so by using the \fB\-\-reset\fP argument with the +command, as follows: \fBbarman config\-switch SERVER_NAME \-\-reset\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The \fBconfig\-switch\fP command will only succeed if model name exists and is associated +with the same \fBcluster\fP as the server. Additionally, there can be only one active +model at a time; if you execute the command multiple times with different models, only +the overrides defined in the last model will be applied. +.sp +Not all options can be configured through models. Please review the scope of the +available configurations to determine which settings apply to models. +.UNINDENT +.UNINDENT +.SS Benefits +.INDENT 0.0 +.IP \(bu 2 +Consistency: Ensures uniform configuration across multiple Barman servers within a +cluster. +.IP \(bu 2 +Efficiency: Simplifies configuration management by allowing centralized updates and +overrides. +.IP \(bu 2 +Flexibility: Allows the use of multiple model files, providing the ability to define +various sets of overrides as necessary. +.UNINDENT +.SH AUTHOR +EnterpriseDB +.SH COPYRIGHT +© Copyright EnterpriseDB UK Limited 2011-2024 +.\" Generated by docutils manpage writer. +. diff --git a/doc/barman.conf b/docs/barman.conf similarity index 100% rename from doc/barman.conf rename to docs/barman.conf diff --git a/doc/barman.d/passive-server.conf-template b/docs/barman.d/passive-server.conf-template similarity index 100% rename from doc/barman.d/passive-server.conf-template rename to docs/barman.d/passive-server.conf-template diff --git a/doc/barman.d/ssh-server.conf-template b/docs/barman.d/ssh-server.conf-template similarity index 100% rename from doc/barman.d/ssh-server.conf-template rename to docs/barman.d/ssh-server.conf-template diff --git a/doc/barman.d/streaming-server.conf-template b/docs/barman.d/streaming-server.conf-template similarity index 100% rename from doc/barman.d/streaming-server.conf-template rename to docs/barman.d/streaming-server.conf-template diff --git a/scripts/release.sh b/docs/build/build similarity index 53% rename from scripts/release.sh rename to docs/build/build index 19c6caa9b..55f8299d0 100755 --- a/scripts/release.sh +++ b/docs/build/build @@ -1,4 +1,7 @@ -#!/bin/sh +#!/usr/bin/env bash + +# This script resides in this path because it is responsible for building documentation +# via github actions. It uses the ../Dockerfile and there is no other use for it. # © Copyright EnterpriseDB UK Limited 2011-2023 # @@ -17,14 +20,18 @@ # You should have received a copy of the GNU General Public License # along with Barman. If not, see . -set -e +set -xeu + +DOCDIR="${BASEDIR}/docs" +DISTDIR="${DOCDIR}/dist" -BASE="$(dirname $(cd $(dirname "$0"); pwd))" -cd "$BASE" +USERMAP=$(docker run --rm -v "${BASEDIR}":"${BASEDIR}" "${SPHINX_IMAGE}" \ + stat -c %u:%g "${BASEDIR}") +docker run --rm -u "${USERMAP}" -w "$(pwd)" -v "${BASEDIR}:${BASEDIR}" \ + "$SPHINX_IMAGE" tox -e docs -- html latexpdf -VERSION="$(python -c 'd={}; exec(open("barman/version.py").read(), d); print(d["__version__"])')" -./setup.py sdist -if ! git tag -s -m "Release ${VERSION}" release/${VERSION} -then - echo "Cannot tag the release as the private key is missing" -fi +pwd +ls +mkdir -p "${DISTDIR}" +cp -va "${DOCDIR}"/_build/html/* "${DISTDIR}" +cp -va "${DOCDIR}"/_build/latex/Barman.pdf "${DISTDIR}"/manual.pdf diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..e1ec233a8 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,625 @@ +# -*- coding: utf-8 -*- +# © Copyright EnterpriseDB UK Limited 2011-2023 +# +# This file is part of Barman. +# +# Barman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Barman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Barman. If not, see . + +""" +Configuration file for building user docs and man pages for Barman. + +This file is executed with the current directory set to its containing dir. + +Note that not all possible configuration values are present in this file. + +All configuration values have a default; values that are commented out serve to +show the default. + +If extensions (or modules to document with :mod:`autodoc`) are in another +directory, add these directories to ``sys.path`` here. If the directory is +relative to the documentation root, use :func:`os.path.abspath` to make it +absolute, like shown here. +""" + +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) + + +from barman.version import __version__ # noqa: E402 + +project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +module_dir = os.path.abspath(os.path.join(project_root, "barman")) +excludes = ["tests", "setup.py", "conf"] + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = "1.0" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named "sphinx.ext.*") or your custom +# ones. +extensions = [ + "myst_parser", # To support Markdown-based docs, Sphinx can use MyST-Parser. + "sphinx.ext.intersphinx", # Implicit links to Python official docs + "sphinx.ext.todo", # Support for .. todo:: directive + "sphinx.ext.mathjax", # Math symbols + "sphinx_github_style", # Generate "View on GitHub" for source code + "sphinxcontrib.apidoc", # For generating module docs from code + "sphinx.ext.autodoc", # For generating module docs from docstrings +] +apidoc_module_dir = module_dir +apidoc_output_dir = "contributor_guide/modules" +apidoc_excluded_paths = excludes +apidoc_separate_modules = True + +# Include autodoc for all members, including private ones and the ones that are +# missing a docstring. +autodoc_default_options = { + "members": True, + "undoc-members": True, + "private-members": True, +} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "Barman" +copyright = "© Copyright EnterpriseDB UK Limited 2011-2024" +author = "EnterpriseDB" + +# The version info for the project you"re documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = __version__[: __version__.rfind(".")] +# The full version, including alpha/beta/rc tags. +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# + +html_theme = "pydata_sphinx_theme" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for the theme, see the documentation at +# https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/layout.html#references +# +# PyData theme options +html_theme_options = { + # Top nav + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/EnterpriseDB/barman", + "icon": "fa-brands fa-github", + }, + { + "name": "PyPI", + "url": "https://pypi.org/project/barman", + "icon": "fa-brands fa-python", + }, + ], + # Right side bar + "show_toc_level": 4, + "use_edit_page_button": True, + # Footer + "footer_start": [], + "footer_center": [], + "footer_end": [], +} + +html_sidebars = {"**": ["sidebar-nav-bs.html"]} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["images"] + +# Replace "source" links with "edit on GitHub" when using rtd theme +html_context = { + "display_github": True, + "github_user": "EnterpriseDB", + "github_repo": "barman", + "github_version": "master", + "doc_path": "docs", + "conf_py_path": "/docs/", +} + +# sphinx-github-style options, https://sphinx-github-style.readthedocs.io/en/latest/index.html + +# The name of the top-level package. +top_level = "barman" + +# The blob to link to on GitHub - any of "head", "last_tag", or "{blob}" +# linkcode_blob = "head" + +# The link to your GitHub repository formatted as https://github.com/user/repo +# If not provided, will attempt to create the link from the html_context dict +# linkcode_url = f"https://github.com/{html_context["github_user"]}/" \ +# f"{html_context["github_repo"]}/{html_context["github_version"]}" + +# The text to use for the linkcode link +# linkcode_link_text: str = "View on GitHub" + +# A linkcode_resolve() function to use for resolving the link target +# linkcode_resolve: types.FunctionType + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = "Barmandoc" + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ("letterpaper" or "a4paper"). + # + # "papersize": "letterpaper", + # The font size ("10pt", "11pt" or "12pt"). + # + # "pointsize": "10pt", + # Additional stuff for the LaTeX preamble. + # + # "preamble": "", + # Latex figure (float) alignment + # + # "figure_align": "htbp", +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ("index_pdf", "Barman.tex", "Barman Documentation", author, "manual"), +] + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ("user_guide/configuration", "barman", "Barman Configurations", [author], 5), + ("user_guide/commands", "barman", "Barman Commands", [author], 1), + ( + "user_guide/commands/barman/archive_wal.inc", + "barman-archive-wal", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/backup.inc", + "barman-backup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/check_backup.inc", + "barman-check-backup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/check.inc", + "barman-check", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/config_switch.inc", + "barman-config-switch", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/config_update.inc", + "barman-config-update", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/cron.inc", + "barman-cron", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/delete.inc", + "barman-delete", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/diagnose.inc", + "barman-diagnose", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/generate_manifest.inc", + "barman-generate-manifest", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/get_wal.inc", + "barman-get-wal", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/keep.inc", + "barman-keep", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/list_backups.inc", + "barman-list_backups", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/list_files.inc", + "barman-list-files", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/list_servers.inc", + "barman-list-servers", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/lock_directory_cleanup.inc", + "barman-lock-directory-cleanup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/put_wal.inc", + "barman-put-wal", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/rebuild_xlogdb.inc", + "barman-rebuild-xlogdb", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/receive_wal.inc", + "barman-receive-wal", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/restore.inc", + "barman-restore", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/replication_status.inc", + "barman-replication-status", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/show_backup.inc", + "barman-show-backup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/show_servers.inc", + "barman-show-servers", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/status.inc", + "barman-status", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/switch_wal.inc", + "barman-switch-wal", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/switch_xlog.inc", + "barman-switch-xlog", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/sync_backup.inc", + "barman-sync-backup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/sync_info.inc", + "barman-sync-info", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/sync_wals.inc", + "barman-sync-wals", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/verify_backup.inc", + "barman-verify-backup", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman/verify.inc", + "barman-verify", + "Barman Sub-Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/backup.inc", + "barman-cloud-backup", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/backup_delete.inc", + "barman-cloud-backup-delete", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/backup_show.inc", + "barman-cloud-backup-show", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/backup_list.inc", + "barman-cloud-backup-list", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/backup_keep.inc", + "barman-cloud-backup-keep", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/check_wal_archive.inc", + "barman-cloud-check-wal-archive", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/restore.inc", + "barman-cloud-restore", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/wal_archive.inc", + "barman-cloud-wal-archive", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cloud/wal_restore.inc", + "barman-cloud-wal-restore", + "Barman-cloud Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cli/wal_archive.inc", + "barman-wal-archive", + "Barman-cli Commands", + [author], + 1, + ), + ( + "user_guide/commands/barman_cli/wal_restore.inc", + "barman-wal-restore", + "Barman-cli Commands", + [author], + 1, + ), +] + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {"python": ("https://docs.python.org/", None)} + +# Remove these pages from index, references, toc trees, etc. +# If the builder is not "html" then add the API docs modules index to pages to be removed. +exclude_from_builder = { + "latex": [ + "contributor_guide/modules", + ], +} +# Internal holding list, anything added here will always be excluded +_docs_to_remove = [] + + +def builder_inited(app): + """Run during Sphinx ``builder-inited`` phase. + + Set a config value to builder name and add module docs to :data:`docs_to_remove`. + """ + print(f"The builder is: {app.builder.name}") + app.add_config_value("builder", app.builder.name, "env") + + # Remove pages when builder matches any referenced in exclude_from_builder + if exclude_from_builder.get(app.builder.name): + _docs_to_remove.extend(exclude_from_builder[app.builder.name]) + + # Remove ".inc.rst" files when not building man pages. Those files only make sense + # for man builder, because we want both man pages for the entire application as well + # as separate man pages for each command. When building HTML or PDF, we only need + # the bigger page, not the split ones. + if app.builder.name != "man": + exclude_patterns.append("**/*.inc.rst") + + +def _to_be_removed(doc): + """Check if *doc* should not be rendered in the built documentation. + + :param doc: the documentation to be checked. + + :return: ``True`` if *doc* should not be rendered, ``False`` otherwise. + """ + for remove in _docs_to_remove: + if doc.startswith(remove): + return True + return False + + +def env_get_outdated(app, env, added, changed, removed): + """Run during Sphinx ``env-get-outdated`` phase. + + Remove the items listed in :data:`_docs_to_remove` from known pages. + """ + to_remove = set() + for doc in env.found_docs: + if _to_be_removed(doc): + to_remove.add(doc) + added.difference_update(to_remove) + changed.difference_update(to_remove) + removed.update(to_remove) + env.project.docnames.difference_update(to_remove) + return [] + + +def doctree_read(app, doctree): + """Run during Sphinx ``doctree-read`` phase. + + Remove the items listed in :data:`_docs_to_remove` from the table of contents. + """ + from sphinx import addnodes + + for toc_tree_node in doctree.traverse(addnodes.toctree): + for e in toc_tree_node["entries"]: + if _to_be_removed(str(e[1])): + toc_tree_node["entries"].remove(e) + + +def autodoc_skip(app, what, name, obj, would_skip, options): + """Include autodoc of ``__init__`` methods, which are skipped by default.""" + if name == "__init__": + return False + return would_skip + + +# A possibility to have an own stylesheet, to add new rules or override existing ones +# For the latter case, the CSS specificity of the rules should be higher than the +# default ones +def setup(app): + """Entry-point when setting up a ``sphinx-build`` execution.""" + if hasattr(app, "add_css_file"): + app.add_css_file("custom.css") + else: + app.add_stylesheet("custom.css") + + # Run extra steps to remove module docs when running with a non-html builder + app.connect("builder-inited", builder_inited) + app.connect("env-get-outdated", env_get_outdated) + app.connect("doctree-read", doctree_read) + app.connect("autodoc-skip-member", autodoc_skip) diff --git a/docs/contributor_guide/index.rst b/docs/contributor_guide/index.rst new file mode 100644 index 000000000..a73998607 --- /dev/null +++ b/docs/contributor_guide/index.rst @@ -0,0 +1,18 @@ +.. _contributor_guide: + +Contributing to Barman +====================== + +Barman is an open-source project and we welcome contributions from the community. + +Follow these guidelines when playing with Barman code and contributing patches to the +project. + +.. toctree:: + + setting_up_dev_env + writing_code + writing_tests + writing_docs + opening_pr + Barman API docs diff --git a/docs/contributor_guide/opening_pr.rst b/docs/contributor_guide/opening_pr.rst new file mode 100644 index 000000000..5078069c6 --- /dev/null +++ b/docs/contributor_guide/opening_pr.rst @@ -0,0 +1,4 @@ +.. _opening_pr: + +Opening a PR +============ diff --git a/docs/contributor_guide/setting_up_dev_env.rst b/docs/contributor_guide/setting_up_dev_env.rst new file mode 100644 index 000000000..b9a72c1dd --- /dev/null +++ b/docs/contributor_guide/setting_up_dev_env.rst @@ -0,0 +1,4 @@ +.. _setting_up_dev_env: + +Setting up a development installation +===================================== \ No newline at end of file diff --git a/docs/contributor_guide/writing_code.rst b/docs/contributor_guide/writing_code.rst new file mode 100644 index 000000000..c956afc39 --- /dev/null +++ b/docs/contributor_guide/writing_code.rst @@ -0,0 +1,4 @@ +.. _writing_code: + +Writing code +============ diff --git a/docs/contributor_guide/writing_docs.rst b/docs/contributor_guide/writing_docs.rst new file mode 100644 index 000000000..923723539 --- /dev/null +++ b/docs/contributor_guide/writing_docs.rst @@ -0,0 +1,419 @@ +.. _writing_docs: + +Writing and building documentation +================================== + +The documentation is written using `reStructuredText language `_ +and is built with `sphinx-build `_ +through a tox environment. + +Style guide +----------- + +Follow these guidelines when writing the documentation. + +Tense and voice +^^^^^^^^^^^^^^^ + +For reference and general task-based docs use the "imperative mood". These docs should +be straightforward and conventional. For example: + +.. code-block:: rst + + To create a user, run: + + .. code-block:: sql + + CREATE USER my_user; + +For tutorials, the docs can be more casual and conversational but must also be +straightforward and clear. For example: + +.. code-block:: rst + + In this lab, start with a fresh cluster. Make sure to stop and clean up the cluster + from the previous labs. + +Future and conditional tenses +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Avoid future tense (will) and conditional tenses (would, could, should). These tenses +lack precision and can create passive voice. + +Use future tense when an action occurs in the future, for example: + +.. code-block:: rst + + This feature will be removed in a future release. + +While present tense is strongly preferred, future tense can be useful and accurate in an +"if/then" phrase. For example, it's okay to write: + +.. code-block:: rst + + If you perform this action, another action will occur. + +The conditional tense is okay only if you explain the conditions and any action to take. +For example, use: + +.. code-block:: rst + + A message should appear. If it doesn't, restart the server. + +Person +^^^^^^ + +Use second person (you) when referring to the user. Don't use "the user" which is third +person. + +Use first person plural (we) to refer to the authors of the docs. For example, use: + +.. code-block:: rst + + We recommend that you restart your server. + +Instead of: + +.. code-block:: rst + + Developers recommend that you restart your server. + +However, don't use first person plural when talking about how the software works or in +an example. For example, use: + +.. code-block:: rst + + Next, Barman processes the instruction. + +Instead of: + +.. code-block:: rst + + Next, we process the instruction. + +Line length +^^^^^^^^^^^ + +When possible do not overflow 88 characters per line in the source files. In general, +exceptions for this rule are links. + +Sentence length +^^^^^^^^^^^^^^^ + +Avoid writing sentences with more than 26 words. Long sentences tend to make the content +complicated. + +Contractions +^^^^^^^^^^^^ + +In keeping with the casual and friendly tone, use contractions. However, use common +contractions (isn't, can't, don't). Don't use contractions that are unclear or difficult +to pronounce (there'll). + +Numbers +^^^^^^^ + +Spell out numbers zero through nine. Use digits for numbers 10 and greater. Spell out +any number that starts a sentence. For this reason, avoid starting a sentence with a +long or complex number. + +Dates +^^^^^ + +When specifying dates for human readability, use the DD mmm YYYY format with a short +month name in English. Where the date is being used in a column in a table, use a +leading 0 on the day of month for easier alignment, for example, 01 Jan 2024. + +When specifying dates as solely numbers, use `ISO8601 `_ +format; YYYY/MM/DD. This is the internationally accepted, disambiguous format. Use it +where you may expect the date to be read by automated systems. + +Capitalization +^^^^^^^^^^^^^^ + +Capitalization rules: + +* Use sentence-case for headings (including column headings in tables). +* Capitalize the first letter in each list item except for function and command names + that are naturally lower case. +* Capitalize link labels to match the case of the topic you're linking to. +* Capitalize proper nouns and match the case of UI features. +* Don't capitalize the words that make up an initialization unless they're part of + proper noun. For example, single sign-on is not a proper noun even though it's usually + written as the initialism SSO. + +Punctuation +^^^^^^^^^^^ + +Punctuation rules: + +* Avoid semicolons. Instead, use two sentences. +* Don't join related sentences using a comma. This syntax is incorrect. +* Don't end headings with a period or colon. +* Use periods at the end of list items that are a sentence or that complete a sentence. + If one item in a list uses a period, use a period for all the items in that list. +* Use the `Oxford (AKA serial) comma `_. + +"This" without a noun +^^^^^^^^^^^^^^^^^^^^^ + +Avoid using "this" without a noun following. Doing so can lead to ambiguity. For +example, use: + +.. code-block:: rst + + This error happens when… + +Instead of: + +.. code-block:: rst + + This happens when... + +Directing users up and down through a topic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Don't use words like "above" and "below" to refer to previous and following sections. +Link to the section instead or use "earlier" or "later". + +It also isn't necessary to use the words "the following" to refer to list items. These +words are empty. So, for example, use: + +.. code-block:: rst + + The color palette includes: + +Instead of: + +.. code-block:: rst + + The palette includes the following colors: + +Bold (**text**) +^^^^^^^^^^^^^^^ + +Use for UI elements. For example: + +.. code-block:: rst + + The output of ``barman show-backup`` includes: + + * **Backup Size**: the size of the backup. + * **Estimated Cluster Size**: the estimated size of the cluster once the backup is + restored. + +Also for roles and users. For example: + +.. code-block:: rst + + Run as **root**: + + .. code-block:: bash + + dnf install barman + +Courier (AKA inline code or monospace ``text``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use for parameters, commands, text in configuration files, file paths, packages and +utility names. For example: + +.. code-block:: rst + + If you need to type the ``ls`` or ``dd`` command, add a setting to a + ``configuration=file`` or just refer to ``/etc/passwd``, then this is the font + treatment to use. + +Code blocks +^^^^^^^^^^^ + +Use to provide code or configuration samples. + +Example for code sample: + +.. code-block:: rst + + Execute this query: + + .. code-block:: sql + + SELECT * + FROM pg_stat_activity; + +Example for configuration sample: + +.. code-block:: rst + + Create the file ``/etc/barman.conf`` with: + + .. code-block:: ini + + [barman] + ; System user + barman_user = barman + + ; Directory of configuration files. Place your sections in separate files with + ; .conf extension + ; For example place the 'main' server section in /etc/barman.d/main.conf + configuration_files_directory = /etc/barman.d + +Italics (*text*) +^^^^^^^^^^^^^^^^ + +Use for book titles. For example: + +.. code-block:: rst + + We recommend you read *PostgreSQL 16 Administration Cookbook*. + +Links +^^^^^ + +Avoid using the URL as the label. For example, use: + +.. code-block:: rst + + For more information about backups in Postgres, see `Backup and Restore `_. + +Instead of: + +.. code-block:: rst + + For more information about backups in Postgres, see `https://www.postgresql.org/docs/current/backup.html`_. + +Admonitions (notes, warnings, hints, etc.) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When applicable use `admonitions `_. + +For multiple, consecutive admonitions, use separate admonitions. + +Tables +^^^^^^ + +Use `tables `_ +to display structured information in an easy-to-read format. + +Lists +^^^^^ + +Use `lists `_ +to display information in items: + +* Numbered (ordered): Use to list information that must appear in order, like tutorial + steps. +* Bulleted (unordered): Use to list related information in an easy-to-read way. + +Use period at the end of each list item. + +Images +^^^^^^ + +Use `images `_ +to clarify a topic, but use them only as needed. + +Images are put inside the folder ``docs/images``. + +Cross-reference labels standard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When creating cross-reference labels in Sphinx, please follow these guidelines to ensure +consistency and clarity: + +1. Use Hyphens: Separate words in labels with a hyphen. For example: + +``.. _backup-overview:`` + +2. Hierarchical Prepending: For each ``.rst`` file, prepend labels with the higher-level +section label, followed by any intermediate sub-section labels. This way, the full +hierarchy is represented in the label. + +For example, a file called ``backup.rst`` can have the following label: + +``.. _backup:`` + +Then, any subsequent labels in this file should start with ``backup-``. For a sub-section +labeled ``Overview`` the label would be ``_backup-overview:``. For another sub-section in +``Overview`` the label would be like: + +``.. _backup-overview-other-section-under-overview:`` + +Handling Included Files +""""""""""""""""""""""" + +If your ``.rst`` file uses the ``.. include::`` directive, evaluate whether the included +files are closely related to the parent document: + +* Related Example: In a file ``commands.rst`` with the label: + + ``.. _commands:`` + + if you include another file, like ``commands/backup.rst``, which is related, you + would label the latter as: + + ``.. _commands-backup:`` + +* Independent Example: If the included section is not directly related, you may treat it + as an independent section, without the hierarchical label prepending. + +Purpose of This Standard +"""""""""""""""""""""""" + +Following this labeling standard helps us: + +* Easily trace the source of cross-references. +* Avoid label duplication. +* Simplify navigation for developers and end-users. + +By adhering to these guidelines, we can create clear and maintainable documentation that +enhances usability and understanding. + +Building the documentation +-------------------------- + +You can build the documentation in three different formats: + +* HTML: Contains the full documentation. +* PDF: Same as HTML, excluding the section :ref:`contributor_guide`. +* Linux man page: contains only the sections :ref:`configuration` and :ref:`commands`. + +The documentation is built through a tox environment named docs. + +HTML documentation +^^^^^^^^^^^^^^^^^^ + +To build the HTML documentation, run: + +.. code-block:: bash + + tox -e docs -- html + +To view the HTML documentation, open the file ``docs/_build/html/index.html`` using +your web browser. + +PDF documentation +^^^^^^^^^^^^^^^^^ + +To build the PDF documentation, run: + +.. code-block:: bash + + tox -e docs -- latexpdf + +To view the PDF documentation, open the file ``docs/_build/latex/Barman.pdf`` +using your PDF reader. + +Linux man page +^^^^^^^^^^^^^^ + +To build the Linux man page, run: + +.. code-block:: bash + + tox -e docs -- man + +To view the Linux man page, run: + +.. code-block:: bash + + man docs/_build/man/barman.1 \ No newline at end of file diff --git a/docs/contributor_guide/writing_tests.rst b/docs/contributor_guide/writing_tests.rst new file mode 100644 index 000000000..a66586eb5 --- /dev/null +++ b/docs/contributor_guide/writing_tests.rst @@ -0,0 +1,4 @@ +.. _writing_tests: + +Writing and running tests +========================= diff --git a/docs/faq/index.rst b/docs/faq/index.rst new file mode 100644 index 000000000..8911eba84 --- /dev/null +++ b/docs/faq/index.rst @@ -0,0 +1,218 @@ +.. _faq: + +FAQ +=== + +.. _faq-general: + +General +------- + +**Can Barman perform physical backups of Postgres instances?** + +Yes. Barman is an application for physical backups of Postgres servers that manages +base backups and WAL archiving. It is a disaster recovery application. Barman does not +support logical backups (aka dumps). + +**I am already using pg_dump. What is the difference between pg_dump and Barman +and why should I use Barman instead?** + +If you already use ``pg_dump``, it is a good thing. However, if your business is based +on your database, logical backups (the ones performed by ``pg_dump``) are +not enough. These dumps are snapshots of your database at a particular point in time. +Usually, people perform these activities at night. If a crash occurs during the day, +all your transactions between when the dump started and the crash will be lost forever. +In this context, you need to put in place a more robust solution for disaster recovery, +based on physical backups, which allows for point in time recovery. + +**I manage several Postgres instances. Can Barman manage multiple database servers?** + +Yes. Barman has been designed to allow remote backups of Postgres servers. It allows +:term:`DBAs` to manage backups of multiple servers from a centralized host. Barman +allows you to define a catalogue of backup servers for base backups and continuous +archiving of WAL segments. + +**Does Barman manage replication and high availability as well? How does it compare +with repmgr, OmniPITR, walmgr and similar tools?** + +No. Barman aims to be a pure disaster recovery solution. It is responsible for the sole +backup of a cluster of Postgres servers. If high availability is what you are looking +for, we encourage you to use a tool like Patroni or repmgr. Barman specifically targets +disaster recovery only, because it requires a simpler and less invasive design than the +one required to cover high availability. This is why Barman does not duplicate existing +HA tools like the ones mentioned above. You do not need to install anything on the +server. The only requirement is to configure access for the Barman client, which is +less invasive than what is required for high availability. + +**Can I define retention policies for my backups?** + +Yes. Barman 1.2.0 introduced support for retention policies both for base backups and +WAL segments, for every server you have. You can specify a retention policy in the +server configuration file. Retention policies can be based on time +(e.g. ``RECOVERY WINDOW OF 30 DAYS``) or number of base backups +(e.g. ``REDUNDANCY 3``). + +**Can I specify different retention policies for base backups and WAL segments?** + +Yes, definitely. It might happen for instance that you want to keep base backups of the +last 12 months and keep WALs for Point-In-Time-Recovery for the last month only. + +**Does Barman guarantee data protection and security?** + +Barman communicates with your remote/local Postgres server using SSH connections (for +process and file management) and the standard Postgres connection (for querying the +database). It is the system administrator's duty to make sure that SSH communications +occur in a secure way. Similarly, it is the database administrator's duty to make sure +communications with the database server occur in a secure way. + +**Is the Barman interface complex or hard to understand?** + +Barman has a simple console interface through which you can run its several +commands e.g. listing servers, listing backups, show detailed information of a backup, +etc. Launching a new base backup for a server is also trivial, as well as restoring it, +either locally or remotely. + +**Can Barman manage backups in the cloud e.g. using AWS S3 or Azure Blob Storage?** + +Yes. Barman can currently manage backups in Amazon, Azure and Google cloud providers. +This backup method is called snapshot backups in Barman terminology. In this scenario, +backups are taken via a snapshot of the storage volume where your database server +resides. In this case, Barman act mainly as a storage server for your WAL files and +backups catalog. You can check the :ref:`Barman Cloud ` and +:ref:`Cloud Snapshot Backups ` sections for further +details. + +**Do you have packages for RedHat and Debian based distributions?** + +Barman official packages are provided by :term:`PGDG`. Barman packages can be found in +alternative repositories, but we recommend using :term:`PGDG` repositories because it +ensures compatibility, stability and access to the latest updates. Refer to the +:ref:`installation ` section for further details. + +**Does Barman allow me to limit the bandwidth usage for backup and recovery?** + +Yes. Barman 1.2.1 introduces support for bandwidth limitation at global, server and +tablespace level. + +.. _faq-backup: + +Backup +------ + +**Does Barman support incremental backups** + +Yes. Barman currently supports file-level and block-level incremental backups, +depending on the backup method in use and the Postgres version to backup. + +**How many backups can Barman handle for each Postgres instance?** + +Barman allows the storage of multiple base backups per database server. The only +limit on the number of backups is the disk space on the Barman host. + +**I have continuous archiving in place, but managing WAL files and understanding which +ones “belong” to a particular base backup is not obvious. Can Barman simplify this?** + +Fortunately, yes. The way Barman works is by keeping separate the base backups from WAL +segments of a specific server. Even though they are much related, Barman sees a WAL +archive as a continuous stream of data from the first base backup to the last +available. A neat feature of Barman is to link every WAL file to a base backup so that +it is possible to determine the size of a backup in terms of two components: base +backup and WAL segments. + +**Can Barman compress base backups?** + +Currently, Barman can compress backups using ``backup_method = postgres``, thanks to +``pg_basebackup`` compression features. This can be enabled using the +``backup_compression`` config option. For Rsync-based backups, at the moment there is +no compression method, but it is feasible and the current design allows it. +You can check the :ref:`Backup Compression ` section for +further details. + +**Can Barman compress WAL segments?** + +Yes. You can specify a compression filter for WAL segments, and significantly reduce +the size of your WAL files by 5/10 times. This is done by setting the ``compression`` +option in the configurations. Refer to the :ref:`WAL configuration ` +section for further details. + +**Can Barman back up tablespaces?** + +Yes. Tablespaces are handled transparently and automatically by Barman. + +**Can I backup from a Postgres standby server?** + +Yes, Barman natively supports backup from standby servers for both ``postgres`` and +``rsync`` backup methods. + + +.. _faq-installation-and-configuration: + +Installation & Configuration +---------------------------- + +**Does Barman have to be installed on the same server as Postgres?** + +No. Barman does not necessarily need to be on the same host where Postgres is +running. It is your choice to install it locally or on another server (usually +dedicated for backup purposes). We strongly recommend having a dedicated server +for Barman. + +**Can I have multiple configurations for different users in a Barman server?** + +Yes. Barman needs a configuration file. You can have a system wide configuration +(``/etc/barman.conf``) or a user configuration (``~/.barman.conf``). For instance, you +could set up several users in your system that use Barman, each of those working on a +subset of your managed Postgres servers. This way you can protect your backups on a +user basis. + +.. _faq-recovery: + +Recovery +-------- + +**Does Barman manage recovery?** + +Yes. With Barman, you can recover a Postgres instance on your backup server or a +remote node. Recovering remotely is just a matter of specifying an SSH command in the +``recover`` command, which Barman will use to connect to the destination host in order +to restore the backup. + +**Does Barman manage recovery to a specific transaction or to a specific time?** + +Yes. Barman allows you to perform point-in-time recovery by specifying a timestamp, +transaction ID, a Log Sequence Number (LSN) or a named restore point created +previously. It is just a matter of adding an extra option to your ``recover`` command. +You can refer to :ref:`Point-in-Time Recovery ` under +Recovery section for further details. + +**Does Barman support timelines?** + +Yes, Barman handles Postgres timelines for recovery. + +**Does Barman handle tablespaces and their mapping during recovery operations?** + +Yes. By default, tablespaces are restored to the same path they had on the source +server. You can remap them as you wish by specifying the ``--tablespace`` option in +your ``recover`` command. + +**During recovery, does Barman allow me to relocate the PGDATA directory? What about +tablespaces?** + +Yes. When recovering a server, you can specify different locations for your ``PGDATA`` +directory and all your tablespaces, if any. This allows you to set up temporary sandbox +servers. This is particularly useful in cases where you want to recover a table that +you have unintentionally dropped from the master by dumping the table from the sandbox +server and then recreating it in your master server. + +.. _faq-requirements: + +Requirements +------------ + +**Does Barman work on Windows?** + +Barman can take backups of your Postgres servers on Windows. The recovery part +is not supported. Additionally, Barman will have to run on a UNIX box. + + + diff --git a/docs/images/barman-full-streaming.png b/docs/images/barman-full-streaming.png new file mode 100644 index 000000000..942c33109 Binary files /dev/null and b/docs/images/barman-full-streaming.png differ diff --git a/docs/images/barman-georedundancy.png b/docs/images/barman-georedundancy.png new file mode 100644 index 000000000..347b913bd Binary files /dev/null and b/docs/images/barman-georedundancy.png differ diff --git a/docs/images/barman-multilocation-georedundancy.png b/docs/images/barman-multilocation-georedundancy.png new file mode 100644 index 000000000..50800a1d8 Binary files /dev/null and b/docs/images/barman-multilocation-georedundancy.png differ diff --git a/docs/images/barman-remote-copy.png b/docs/images/barman-remote-copy.png new file mode 100644 index 000000000..52559c6ba Binary files /dev/null and b/docs/images/barman-remote-copy.png differ diff --git a/docs/images/barman-rsync-backup-receivewal.png b/docs/images/barman-rsync-backup-receivewal.png new file mode 100644 index 000000000..34198dede Binary files /dev/null and b/docs/images/barman-rsync-backup-receivewal.png differ diff --git a/docs/images/source/Barman-full-streaming.excalidraw b/docs/images/source/Barman-full-streaming.excalidraw new file mode 100644 index 000000000..b6defb21c --- /dev/null +++ b/docs/images/source/Barman-full-streaming.excalidraw @@ -0,0 +1,875 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "1ZzBrWEHwMbkiSQ937jS_", + "type": "rectangle", + "x": 280.55864661654135, + "y": 382.7789473684211, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 2097703460, + "version": 388, + "versionNonce": 560219537, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732175119861, + "link": null, + "locked": false + }, + { + "id": "FUELyXBPcB6gf1H-ELi3a", + "type": "rectangle", + "x": 829.2323308270677, + "y": 386.2736842105263, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": { + "type": 3 + }, + "seed": 1386606756, + "version": 611, + "versionNonce": 1243174911, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732175119861, + "link": null, + "locked": false + }, + { + "id": "ZQBQiZKK1TTwKqd7MXAMm", + "type": "text", + "x": 359.4398496240602, + "y": 538.5443609022557, + "width": 31.086517179484357, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": null, + "seed": 1697128612, + "version": 422, + "versionNonce": 13069169, + "isDeleted": false, + "boundElements": [], + "updated": 1732175119861, + "link": null, + "locked": false, + "text": "pg", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4neJBFAF6jQ35NUlbGebi", + "type": "text", + "x": 878.6578947368421, + "y": 540.5413533834587, + "width": 91.56410319010416, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1977030308, + "version": 531, + "versionNonce": 1649147935, + "isDeleted": false, + "boundElements": [ + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732175119861, + "link": null, + "locked": false, + "text": "backup", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "g8P0muvVQ88DvKGMJmV0D", + "type": "rectangle", + "x": 228.63684210526316, + "y": 236, + "width": 845.7263157894738, + "height": 664, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": null, + "seed": 2126547484, + "version": 421, + "versionNonce": 948622673, + "isDeleted": false, + "boundElements": [], + "updated": 1732175119861, + "link": null, + "locked": false + }, + { + "id": "SPCm1UV2vaWBMhVMDRUJU", + "type": "image", + "x": 337.47293233082706, + "y": 449.6781954887218, + "width": 70.89323308270677, + "height": 70.89323308270677, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": null, + "seed": 239434660, + "version": 313, + "versionNonce": 171222079, + "isDeleted": false, + "boundElements": [], + "updated": 1732175119861, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "1tSeOxu4bvvm1bBII4boa", + "type": "image", + "x": 872.7015186481054, + "y": 444.18646616541355, + "width": 86.33532345715773, + "height": 70.89323308270676, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 1149200548, + "version": 509, + "versionNonce": 1543897905, + "isDeleted": false, + "boundElements": [], + "updated": 1732175119861, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "SKIYhR2pT9ePU_N3-qjcA", + "type": "text", + "x": 242, + "y": 68.5, + "width": 802.070385105881, + "height": 73.60000000000001, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 450504476, + "version": 166, + "versionNonce": 1237256476, + "isDeleted": false, + "boundElements": [], + "updated": 1732004135233, + "link": null, + "locked": false, + "text": "Backup architecture for Postgres", + "fontSize": 54.518518518518505, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Backup architecture for Postgres", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "hVDj-LHqEF0t6Tl11s2LZ", + "type": "text", + "x": 417.16000162760423, + "y": 166.86240812442435, + "width": 512.1333618164062, + "height": 43.13759187557564, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 904209180, + "version": 567, + "versionNonce": 1370735711, + "isDeleted": false, + "boundElements": [], + "updated": 1732175119861, + "link": null, + "locked": false, + "text": "Full streaming architecture", + "fontSize": 34.51007350046051, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Full streaming architecture", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4v7wWZXi74Bxw2oKBmYHL", + "type": "rectangle", + "x": 463.3390977443609, + "y": 764.2060150375939, + "width": 24.962406015037594, + "height": 25.9609022556391, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aN", + "roundness": null, + "seed": 593654428, + "version": 351, + "versionNonce": 1655862111, + "isDeleted": false, + "boundElements": [], + "updated": 1732175151673, + "link": null, + "locked": false + }, + { + "id": "pnSRfbQP1_xcrej7vbeAU", + "type": "rectangle", + "x": 463.3390977443609, + "y": 815.6045112781954, + "width": 23.96390977443609, + "height": 23.96390977443609, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 311884572, + "version": 634, + "versionNonce": 1944760191, + "isDeleted": false, + "boundElements": [], + "updated": 1732175151673, + "link": null, + "locked": false + }, + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow", + "x": 422.34511278195487, + "y": 383.7774436090225, + "width": 459.0740840644434, + "height": 74.88721804511279, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ai", + "roundness": { + "type": 2 + }, + "seed": 592542500, + "version": 765, + "versionNonce": 939365393, + "isDeleted": false, + "boundElements": [], + "updated": 1732175129384, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 56.91428571428572, + -70.89323308270677 + ], + [ + 380.4270676691729, + -73.88872180451129 + ], + [ + 459.0740840644434, + 0.9984962406015039 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.1931402196402995, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.3213161961438585, + "gap": 1.4977443609022885, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": null, + "elbowed": false + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow", + "x": 472.26992481203007, + "y": 482.62857142857143, + "width": 355.9639097744361, + "height": 2.089573357269705, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aj", + "roundness": { + "type": 2 + }, + "seed": 1620519580, + "version": 495, + "versionNonce": 2084415903, + "isDeleted": false, + "boundElements": [], + "updated": 1732175134694, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 355.9639097744361, + 2.089573357269705 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.020247506155730458, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.022935461485079463, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow", + "x": 418.3511278195489, + "y": 588.4691729323308, + "width": 465.0958370263172, + "height": 94.85714285714286, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": { + "type": 2 + }, + "seed": 208601628, + "version": 661, + "versionNonce": 881058225, + "isDeleted": false, + "boundElements": [], + "updated": 1732175137453, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 53.918796992481205, + 94.85714285714286 + ], + [ + 389.4135338345865, + 93.85864661654135 + ], + [ + 465.0958370263172, + 1.9969924812030075 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": 0.11031710585082588, + "gap": 2.9954887218044632, + "fixedPoint": null + }, + "endBinding": { + "elementId": "4neJBFAF6jQ35NUlbGebi", + "focus": 0.236919665601773, + "gap": 14.9774436090226, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "J6xU_Pt8Qv2vG9vtlgF0o", + "type": "text", + "x": 511.2669172932332, + "y": 766.203007518797, + "width": 219.66917293233084, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "am", + "roundness": null, + "seed": 144537884, + "version": 175, + "versionNonce": 117860255, + "isDeleted": false, + "boundElements": [], + "updated": 1732175151673, + "link": null, + "locked": false, + "text": "Postgres connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "rWwqK9mZASAZ9tsCkYhZA", + "type": "text", + "x": 511.26691729323306, + "y": 815.6045112781954, + "width": 329.50375939849624, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "an", + "roundness": null, + "seed": 1368290596, + "version": 364, + "versionNonce": 171318207, + "isDeleted": false, + "boundElements": [], + "updated": 1732175151673, + "link": null, + "locked": false, + "text": "Postgres streaming connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres streaming connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "Le_pTc_Rwx0iNbqSMjzwk", + "type": "rectangle", + "x": 526.1887218045113, + "y": 271.9458646616541, + "width": 269.59398496240595, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "av", + "roundness": null, + "seed": 1342530852, + "version": 446, + "versionNonce": 799540772, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "h9kkrSHYTc0yqOK0Hc8QY", + "type": "text", + "x": 531.6205415057418, + "y": 282.9293233082707, + "width": 257.7318493193432, + "height": 45.95482352549884, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aw", + "roundness": null, + "seed": 1541742756, + "version": 466, + "versionNonce": 1351328164, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "Postgres connection\n(for management purposes)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connection\n(for management purposes)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "PQurhIwTn6hJgWWOTKjtH", + "type": "rectangle", + "x": 566.1285714285714, + "y": 451.6751879699248, + "width": 173.7383458646616, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ax", + "roundness": null, + "seed": 2067560220, + "version": 562, + "versionNonce": 1500499236, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "D4rVKgv_jWc41tiRfWVwc", + "type": "text", + "x": 566.5679099267944, + "y": 462.6586466165414, + "width": 174.85666134941846, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ay", + "roundness": null, + "seed": 458699676, + "version": 637, + "versionNonce": 465733796, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "Streaming backup\n(pg_basebackup)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Streaming backup\n(pg_basebackup)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "JWscPEsiXw56xj5PMIYAb", + "type": "rectangle", + "x": 574.1165413533835, + "y": 654.36992481203, + "width": 163.75338345864665, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "az", + "roundness": null, + "seed": 1046108708, + "version": 543, + "versionNonce": 187814948, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "kQqv-gQNveFMs3HCpPqk1", + "type": "text", + "x": 577.551368573411, + "y": 666.3518796992481, + "width": 154.88673653738834, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b00", + "roundness": null, + "seed": 2111010212, + "version": 624, + "versionNonce": 1974185892, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "WAL streaming\n(pg_receivewal)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "WAL streaming\n(pg_receivewal)", + "autoResize": false, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "46592fa2e930e621fb84c5731ee38deba57530a4": { + "mimeType": "image/png", + "id": "46592fa2e930e621fb84c5731ee38deba57530a4", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAgAElEQVR4Xu2dCdxVU/fHl6kkkaKBSoUypMhbolRCM5FU0kATmkiJlAYlFYUylDSIilQqiaRRKCUJFUIqGkzNE17/9d33nvPse557n3vuyNvz/30++3Of594z7nXO3nut9VtrHSP/j1h74Azd4UJtFwVbEf3Mo+0Ubadan8fp3z9r2xFs262/N+vfC7X9FuvJY93+mFh3iGP7fLpPcW3FtP2lbZ+2/Z7GdwfjOLafXUrpRpWC50cAjhAQygFtP2n70fp0/uaaANd+nbaa2qppQ8DJwH/1ICu0va1trrbV2v5OxoHtYyRbwPmDHVFLP8trO1sbT7YfcMO/a1ur7ZNgW6Wf38Z44wikmbYrgo1rigd7dKe92s6KZ+c49tmp+7wTFPYM/fwjjmNk2iUZAj5dj9pBW31tl2k7NhkXZh1jt/7N042w39O2KMzNMxzW03aXNh6uZF9DyC3lypVLypQpY1rBggUlf/78puXLl8988vvvv/8uv/76q/z222/m02nr16+X1atXy3//y/McERv1lwe1TU+0LxMRMILtrq2jtpOzupDcuXNLsWLFzI3v379f9u3bZz5pf/wR84O6S8/1pjae8ne13axtoDamgLAoUaKEnH322XLaaacZIfCZN29eOXDggPzyyy/y888/m8+dO3fKxo0b5a+/mEkycN5550mdOnXkiiuukHLlykmpUqXkuON4puIDwl+8eLG89957smDBAvnqq68iHWiZ/tBN28fxnUkkHgGfpCfrra1zOMEWKlRIatasadoFF1xgOpanOhIQsCP0TZs2maf7008/NZ/r1q2TP//8M6t74+k4wbsBArn22mulatWqctVVV8lZZ/kfZRE65165cqV5KMuXLy88IKnE1q1bjaDHjx8vS5Ys8Z6Kefk1bT21bYr1OmIVcFE9wSxtl9on4m3o1KmT3HzzzeYJP+aYWA8b/rIPHTokn3/+uenwhQsXyty5c83bHwkItVu3blK7du1Y+yGu7f/799+yZ/8h2U3bd0h2Bf8+dOQPyZMrp5x68oly6kknyim5A43vonXNihUrZMiQITJz5kz5W49v4bD+/ZS2/tp8L0hjkQQr0ZnaCjonZajr2rWrdOnSRU49lcVpaoHA58+fL2+88YbMnj3bzGugVq1a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", + "created": 1731966018042, + "lastRetrieved": 1732175071260 + }, + "0833b30d1a4da2b737b05a0261e434640c53058b": { + "mimeType": "image/png", + "id": "0833b30d1a4da2b737b05a0261e434640c53058b", + "dataURL": "data:image/png;base64,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", + "created": 1731966716908, + "lastRetrieved": 1732175071260 + } + } +} \ No newline at end of file diff --git a/docs/images/source/Barman-full-streaming.svg b/docs/images/source/Barman-full-streaming.svg new file mode 100644 index 000000000..47a5027b7 --- /dev/null +++ b/docs/images/source/Barman-full-streaming.svg @@ -0,0 +1,12 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nOy9WZPbSLol+H5/RVr2y4zhVmDf7lg/YN9cdFx1MDAxMlx1MDAwNEBcdTAwMDIzbWXYN2IhdqCt//sglFmKUCqUqazK21V1uyhZiFx1MDAwMThAh/s55zufL9T//LdcdTAwMWZ++HHcuuTH//jhx2SNgkdcdTAwMTH3wfLjv79cdTAwMWWfk34o2uY4hXz6fWinPvpUMlx1MDAxZsdu+Fx1MDAwZlx1MDAxMHy74iVq65+uSlx1MDAxZUmdNONwlPt/j99/+OF/fvp5nCni12thf2f7myAvRlhcdTAwMTXXXHUwMDBijZLl9c+fLv1U6C+V6ZNoXGaa7JG8nVpfa0JBLzhOXHUwMDExXHUwMDE4QcBcdTAwMDSOwSj++fR2nEYp5IUkKVx1MDAxYSNRgsJcdTAwMTBcdTAwMTj+fHYp4jE/SsA09ELCXGJJwTSOUVx1MDAxNIm83SBPiixcdTAwMWZfP1x1MDAwNEJeiM/3gHCE/Fxc5qcq/cdcdTAwMGbQ5yPD2LdVwrWPtn+t93+Dk9c/b7VcdTAwMGWDqMr6dmriz2XGPmiGLuiPZnorl1x1MDAxNo/Hddw+3f1o6qNZf/zFZ9x+flx1MDAwNORcdTAwMTfHv3XV8aFZ3iTDa1e8NUTbXHUwMDA1UTG+Nlx1MDAxNlxmvT3Fa1xyOyX+1Gv/461OfVAnymu3NdPj8flw0cTJa2f8XHUwMDE4QF98Wlx1MDAxM//8aX/p8rf+RH8+8r/e6p4k8ae2pklcdTAwMTJCMeKtLm+4Qynql0dPbfNcdIM4XHUwMDAxIUdcdTAwMTeib11TXGb8gb3x013T4DEkb13wWjXhl7h8j813+HzeUsO+qpg6XHSX7qlpf5Knbvn8mF9gNOj7dvnx85n/9e+/dl+M4tbpXCJGXHUwMDBlVjQ+565QXHUwMDFlY/FcdTAwMWZw30dTr9aV28OGxmRcdTAwMTLJpOi0ON9335/fvfX31MXBT1xyXGKTKFx1MDAwMpM4XGbTXHUwMDE08YadR9FUv1x1MDAwNMOjjaq3Nv+3d1x1MDAxNf5cdTAwMDXxRUfQtzt7jlhcIkth+U+CXqDBd1x1MDAxM59C6Fx1MDAxN1x1MDAwNEVQXHUwMDE0olx1MDAxMFx1MDAxMlwiSPJcdTAwMTe8J16QN75cdTAwMTLov3j/n8p79G/mPXx0XHUwMDE5cfQjTnzAe+KdcP+C9zCCoTCJ0e9K/Iv4/9jE9y/spfA1XHK27UV7xqRxZ4z6a+KPyTp+yXlcdTAwMTSnXzCUpjCaQDDoXHUwMDEw/C84j6PUXHUwMDBijmEoXHUwMDAx0Vx1MDAxMILgOPlcdTAwMTXnUfhcdTAwMDWiXGJcdTAwMWMmYZLGKFxmfVfkM+dR7OU9498px78o/1x1MDAwNeWJjyn/Rem/cJugXHUwMDBmqT3wg3zAbVxm+eroZ26jXHUwMDEwQVx1MDAxZlx1MDAxN/81zP4jsfxcdTAwMDbNV0hcdTAwMWVcdTAwMGbfZe86r23Ga7G/1lx1MDAxNyFfaPyd24TIL0qJQV08PiH1i1x1MDAxYjKPXCJrPlx1MDAxMThJ34HiaIuxOOz059Nj272djY77XHUwMDA1RZP0X3dR21x1MDAxN1nRXHUwMDA0XHUwMDBm+4PKXHUwMDA209hayfBTdcd+St63Qlwi/4VcdTAwMDTwXHUwMDBigv9cboGxJlFZkVx1MDAxMYnyguIn51x1MDAxMUpJWHxcdTAwMGaBKZJ6Id630JdcdTAwMDTGXHUwMDBlL/9q4VGUQjGc+prANPyCXHUwMDEzXHUwMDE4XGahR/SGIVxmfotcdTAwMTX/4u/v5S/9O/j7yZJcdTAwMWZ/vnLfn2T327GZOOIyRtLvkrI/KDb/Y8W6r/ThXHUwMDE1OFP3T6RcdTAwMTG/rPBcdTAwMWajXHUwMDEzXHUwMDE5dYbqaXYvXHUwMDE0xc+aZKi1XHUwMDBi8d+f2iOHWLwj8ju2vzZcdTAwMTCCvv3+XHUwMDE3faAw/IV8LfpzXHUwMDBiv+H1sz5cdTAwMTBcdTAwMDT2XHUwMDBmpVxi8C+O/1x1MDAxZFx1MDAxNYH7fkVAYITAMfIwUVx1MDAxZkb0byrCYbtcYlx1MDAwNCHIN1X+O4X0X0Ht9czVsONcInNwY43cNXjLUZ2vUVvUQfZcdTAwMGLEoij5gpFcYv2Wln6BWFxmo1+It4RcdTAwMTOmvsIvXHS9UPSHSe1n/H67yG+i+UOk/pdGtPQ7XHUwMDEwjdJcdTAwMTiKXHUwMDExXHUwMDFmXHUwMDBmO8Hot1x1MDAwMH3kXHUwMDEyXGKCQOQ/jkdcdTAwMWTGYJyGT+1cdTAwMWTMSfxFXHUwMDBm/tRYP2JcdTAwMDROI2mAJDRcbiVcdTAwMDRcdTAwMDKnIYVFOInCSYJScVx1MDAxMlx1MDAwNjiJo1CAvevhI8gkX1x1MDAwNOXPdTveflx1MDAxNVKj/ohDP1X3V4hcdTAwMDaP18RcXCcsnOdcdTAwMWFcdTAwMGVZRcHC9oNcdTAwMDGgXHUwMDBmiHaw54WEYFx1MDAxY6ZcYow6olx1MDAwM/ZcdTAwMGKeYS/w+yFh/CuiUcRcdTAwMGJ6+EzksJnkXHUwMDExLN7p0TeJRvyLaN8mmvI7zCSM0VxidPTZh2ZcdTAwMTKiv8k0XHUwMDFjQymapKG/ykz+vahcdTAwMDZRKFx1MDAxYaJQXGZcdTAwMDdYXHUwMDFjICGJkiGEXHUwMDA3XHUwMDEwQsDJq9xgUHQwXHKnwv9kql01xcstpLPp5Oz8+YT+6VlGzPdkbFxi9uUgXHUwMDBiQb18wCZcYnmBjlxmgcJcdTAwMGYuUlx1MDAxNPxcdTAwMDGZ0Fx1MDAxN1x1MDAwMnr3gr+fTP/tyD7gXGL5P4RI2vdcdTAwMTNcdMMhXHUwMDFjwjDyo1x1MDAwMVOY+Oro24ApSlwiR1x1MDAxNv3uuj+AR1x1MDAxMPQqtIda/i1pXHUwMDEz+ylcdTAwMGL5IeijvFx1MDAxOI+kYOqTXHUwMDFm0rb/4dxcdTAwMGVj1ifDh1x0XHUwMDE1jr1cdTAwMWNx4O3vO334XCKhXCK++LjPXHUwMDE5U3Q8WdL/J6RU3/8w351sob+WbOUuX/5Jl5+CXGKNhP2A4Vx1MDAwMdH976E4XHUwMDA2ky/wKzthXHUwMDAyIVx0XGJD3vpw+1x0Si/U63grXHUwMDA1I1x1MDAxOIZg6Nf8x2HkXHUwMDA1RlGUgKkj5YeIN8n4LFx1MDAwMFx1MDAxOHqUIHFcdTAwMWGmSPxwXHUwMDE3/0rCviVcdTAwMDDG91x1MDAwYlx1MDAwMH30XHUwMDE1dLToR5ZcdTAwMTUnyF9cdTAwMWV9XHUwMDFiVSUhXHUwMDEyPXzPXzVj8p86blwiXHUwMDFlZX84uiA5SNtkX3DnQ+6jr9yHXp/m0Fx1MDAxZlx1MDAwMsLhL1xufaY+9cVcdTAwMDf9Z4+lfNdD/EFcdTAwMDOxM7nc/HtBYuy6IK3G1p6sf/dcdTAwMDBcdTAwMGJGoIdcdTAwMGKmXyfcf5o2+YL3JIG9IFx1MDAxMHG4bOiVuOjb2b/QXHUwMDFlwV5+noj5ucxcdTAwMWKp36ZQ8aPMz1x1MDAxMzJcdTAwMDRK/664/9u0/8pcdTAwMWL8U1L+9P2UP/rhSGkw5CPvjOK/Mlx1MDAxMPu6Rlx1MDAwNoH/eMrj8PvBnL9p3KVrrlZcdTAwMWFezvCf16hPSnJcdTAwMGVcdTAwMTPmg3GXv1xuzFx1MDAxNIxcdTAwMWZcdTAwMDZcdTAwMTQ7JOrnXHUwMDE5/6/BjFx1MDAxZUD98Po3LH+zyFx1MDAxZlx1MDAwM2YkpVx1MDAxM1xm+ydcdTAwMDez+f1gRmGYoo5cdTAwMDT8o1lBXHUwMDAy/Wpk8TOY6VfTXHUwMDBiwfQ/Mph/ffHALyYnvlx1MDAwNDKCvKDvkEr9cmVcdTAwMGL6Qv5cdTAwMDWAr7L6XHUwMDE1kjGcPrKxw69cdTAwMWTKjFx1MDAxZOU+UGVcdTAwMTJ7+WlcdTAwMDTyZ0r8LiT/djr239JPr3/yXHSy4mMkf72mXHUwMDA1+fnIV2tacFx1MDAxYcExXHUwMDA0hz4yaCSBf1x1MDAwYuBHrD1U/vjxR+NcdTAwMWKh0XdcdTAwMDP2v8OfdW3xy0m5t3c/vIHl0y+f3/+Pf/+wNE680PBcdTAwMTHCXHUwMDBlXHUwMDA3+ukn8v7qP301vv1bt0Mp6Fx1MDAwNftphI6gYVx1MDAxMqG/vFx1MDAxZHog/Vx1MDAxZNTp37rdN9nz6dle6LfVJ6+m593t/u1cdTAwMTe3/fFcdTAwMTFcZiPX1nUxXHUwMDFlvXB+bcGvdHBcZvqRPVx1MDAxMHf4xC+R9fOiWeU7Vsh+MrvRp2GoP0EvMI3C2OtKyCNcdTAwMGZDaFx1MDAxYX9XKlx1MDAwYrr3ZPlEy/XLmn1cdTAwMDXkpIl/u36/vpDvXf2gl1x1MDAwM4coTFx1MDAxY7WDMZTCqVx1MDAwZqr3gtHv1I36oshv1/dTizKvoponQfyBwlx1MDAxZVx1MDAwZvT+9Fx1MDAxN92RPMJ2+S51//UlXFy/qu4k8oJcdTAwMTA0jWBHOlxyoVx1MDAxMPSlumNcdTAwMTTyQrxR42ilr+RcdTAwMWTF8S9syFx1MDAwN6NtyFx1MDAwYkTROIlcdTAwMWVJ3vFZ5LtcdTAwMTGR35b3X5qQ/7LyXv7N8lx1MDAwZVx1MDAxM8iRctL4h1x0OEZ/U9+RQ1xcMFx1MDAxOKehP1xc4FGMoP/+XHUwMDAy/02Evr6+wuY/moJCXGKEYCRcdTAwMGVcdTAwMTEwflTziFx1MDAxYdS7cv9cYlx1MDAxYXrIXCKN4tghoVx1MDAxNFx1MDAwZZE09rbE6a+s4Fei+aUqfqmYX1x06neL5q+v2flV0YSpXHUwMDE39J0j/jK3wynqXHUwMDA1+yn0/+RcdTAwMWK+dsRcdTAwMDT+XHUwMDAyXHUwMDFkPEVJ6HVxXGL5wfgkfTjiN9VFqN8x2/d/jmQ+/mbJPKSPeFx1MDAxZGf+aPyCIL45fkG9TvJS75OdP0owSVxm/6umLP5YR4y+vFx1MDAwZYzTn31cdTAwMDH+/vKvoPnbjph+ebeMkvjyboch/mK/1G9cdTAwMWHib5Hn9Vx1MDAwNVx1MDAxZob4XHUwMDBiN/OPJeeHXHUwMDFmfl0sSr6iXHUwMDA3P1x1MDAxMlxunPpazJHjXHUwMDEx/rIgXHUwMDA3wlx1MDAwZTVF3t/oj1H3X18w+0WFXHUwMDEx9JAymiDwgyfv1iW8STv28t4gXHUwMDEzv6uy/5uUXiVW58/nkbrMyCzR8/jIRKj9nqmoQ+NcdTAwMGZ3/KblX849XHUwMDFmXHTey88oe2XL18uDj7TnhXhcdTAwMWZcdD5cdTAwMWGQ/vag9Vx1MDAxZjP28ddcdTAwMGZJ/1x1MDAwMyl9/bHSf7ieXHUwMDAzOySUpD5cXFx0eEjstyRcdTAwMWSGySNcdTAwMTQg+Fx1MDAxZi7pv3dcdTAwMTDvXHKWP8/f/GWC9oeobZokXHUwMDFhj0p/PPN8oO1L8SO+KPVb00//aTPPv/5cdTAwMDB/zMxTf1ueXHUwMDFhXfvMlfHpceAqL/e/a0HJLyn+izWSvz1Qj1wi9MtfpqR+XHUwMDFhi/mDSf49du6/XHUwMDA0yZvfQXKUoFx1MDAxMFx1MDAxYcLpj1x1MDAxNpugxLfH6klcdTAwMTiFKVx1MDAwNPqrduX+72H520ztPz3ff+NR/lx1MDAxOObryZ87O/qztaxQcVxun1ej3Jfqu6fpcIR4gd9ccsh+udZcdTAwMDQhXHUwMDBmQ4m9s6dfh3jiYP9n5lx1MDAxZoD8YNvuYVjpv5iE1/76g3ft/lxyudw/0Dzd/HvIjyH44abwXHUwMDBmt+9h31xcaUa+XHUwMDFha4h8l27/XHUwMDEx5D9yNpqE6N+zzuRX0JzTVdVfZc+OoO1papBcdTAwMWNRXHUwMDE377viXHUwMDE4XG6/vI7/YUeEwUns3WL+T0CmjrTi3UaAXHUwMDBmvCpOvpCHNmI0XG7TKIZ+tGbqwPGRmSAojuBcdTAwMTj93mH9XHUwMDBix59xvPxcdTAwMGVcdTAwMWNcdTAwMWadRWLIx1vMsV9ZMYniMIq8Lm37e1x1MDAwM/l7vOr/1/xfr8tcZuugXHSyT7X4oZv6rlx1MDAxZJLh//44qlEv6OG0XHUwMDEwXHUwMDFhgyH4YOy7JZz/XHUwMDE4Ue13PtpcdTAwMTdR7stW+z1h7nyZ+lxcWeyGyNXsdjNtrVx1MDAxY+XvXHUwMDBmc0eqXG6/n8f5Qlx1MDAxZI7A90K8xSfs61x1MDAxMctcdTAwMDMghzr8NHzzKVx1MDAxNv4ryv1V6rD+jlxyQJ++fFx1MDAwMkKQj5dTfnuT+uvaw6P90T90PfVcdTAwMWZcdTAwMWPmeKx3tWz+c3mLMHgsrPTmLtF3hblcdTAwMDPIOEHS0PGExz/YL4BMIC/EO7v2dbZcdTAwMDa/LjU5bkJcdTAwMWMm4lBcdTAwMThcbvtcdTAwMDDJv4xzf/CW7f9cdTAwMWFI3n7Pxlx1MDAwMOpcdTAwMTBcdTAwMDTiw41cdTAwMDFcdTAwMDT6zXXBXHUwMDE48TotR9J/d1x1MDAxY39cdTAwMTXlrp/zmp/2KVx1MDAxZnGgy/5cdTAwMWNcdTAwMDZD8tPv/1xcge13PM1cdTAwMWZcdTAwMTTL1NtcdTAwMTCdhaG4LzixlvjZUDwm/P5YdlBcdTAwMTj+ebLgdUrhy29YO46/oG9Z8ddcdTAwMDJAXHUwMDFjkezzVMQhXHUwMDE0/0rY/jpcdTAwMDHYf4fRhTBcdTAwMDKGKPLj72vAvr2ZlVwiKfiQ6bfL/vFcIll1ec5/yi6nOVx1MDAxMY1cdTAwMDGVue78rODvimQk+YLjr1x1MDAwM1mHzGHvVkJ/QvFcdTAwMTHm0HeG7IPvXHTEX9dMXHUwMDEy5OvKvMOZUVx1MDAxZi2r/Fcg+21cdTAwMWOH0De+I/Djr1x1MDAxOYBcdTAwMGbthpBcdTAwMGa/OOj9yO9XS4RfM3Kcov/uQ1x1MDAwZl/Fslx1MDAxYqO/jdP9JP2H7ibFnCzB458rkH3vo/z+KPZvP09cdTAwMWL/XHUwMDE4dN11PLrgx7/Mrf44XHUwMDE3ycJ+m1x1MDAxYv/2s2582oL7tjjh+7e8v03i/lhcdTAwMTd1Yr/fhFx1MDAwZXbNu+9SKv7KvfRcdTAwMDekXHUwMDAyx9JfL359+1x1MDAxZp9v/f+8elx1MDAwMFx1MDAwMvv3wmVNa4E0KWuZ43W6OrngZMc7+fVcdTAwMDeLcYz3elx1MDAxY/f58Hr8mzHCQ7i4XHUwMDE2dp+QmItX11x1MDAwMVP5QVRVXHUwMDE1aOy1dbbOyMP2YXFcdTAwMDYuOlDF2HVVqFx1MDAwZsZ7iJ6zPfirUjwuz1wisCyNc1TRUZ5StZ9cdTAwMDSYXHUwMDA06Vx1MDAxOEWb+TwkOE426Dxtp3lcdTAwMDdRXGJcdTAwMDBQM8VpbCebu4k200i7Yy9fz2BcdOckxuwx5qijuLihkKJGXHUwMDBiQE5cdTAwMTjEQUOlXHUwMDFkutM9sopcdTAwMDNCIOBcdJhTjrzT4jSrXHUwMDFljVx1MDAwMrWYo4V0JlO9O0c3VFx1MDAxY8/II/RcdTAwMDFcdTAwMDT0SSle0tLUg/Tu9J3V3ThcdTAwMWOKmDJnLlv2WqwhobSDwClcYphTXGY0YVx1MDAxMCDPrrtQvLrIIKxwXHUwMDEzNFx1MDAwN/DY96GLzLi5tvLobVa4nGtedkX9TI29XHRcdTAwMGahTXppZJhgXHUwMDAwTz3pn7JcdTAwMWJxS1HKx7ClqOrQ67NcdTAwMTY+0Fx1MDAxZpOxltDIQGg+XHUwMDEwYfRYd1x1MDAwMLnY4tkzwHQpy/pUIYXjMyVcdTAwMWWXdMfeUHh8IFx1MDAxNXnKq7ufw+VcYpInXGJDXHUwMDE2lDZcdTAwMTHN2E/Gut8gNLifcmLyRZrfOPSxda6+dZfOg3s2y5xHXG6SVDfd9Vx1MDAwN3XEk/l4gdQ0gyTxXHUwMDA0d1x1MDAwNEHAXHUwMDFhQppcdTAwMWUmgDtcdTAwMWOM91xyXHUwMDA1wVxyNFwiwZrhx5LAtlx1MDAwM0D6aliGoo/9XHUwMDEzKcfO3KeOj6b7SVx1MDAxZm66uCvofChaSk9o6O94l4KLRWEmcaVAuCuDhGpcdTAwMTJcdTAwMThcctax5YM605nWXHQ0oZFRXHUwMDA0uetBXHUwMDEwRL6Scv5cdKFcdTAwMTPzzmfZed+2XHLcKIpcdTAwMDJrXG6ITTTV1lx1MDAxNlxu8Vx1MDAwMFx1MDAwMGuh2qJcdTAwMTOO41BcdTAwMWSbzb0qimmqZP2xVXXnPO/VZJ6wblL45Vx1MDAwMVCJLlGHxJFDzbPM3DyfXHUwMDA0Vci3wlx1MDAwN0f2hFDp2jhVJWdS2nFp31x1MDAwN/BuXHUwMDFhwk17WMpBpCGIW1GE18zsgsbMlcvAnSHbXHUwMDFmkDpISVxiosCTXHUwMDBm9vBcdTAwMTOxzyBIXHUwMDE5xEhiQIUt4cAyfYMg9fRcYsbbM1x1MDAxYV3XpVx1MDAxZb5cdTAwMGZWqW9cdFx1MDAwNH5cdTAwMTjf6OnimnF0wvF0itZcYvBcdTAwMTNcdTAwMGXLgJfLlZqvuDdQPqElaVx1MDAwNYc2XHUwMDAyXHUwMDFmUIHNWnEjUaCX6zo+6LbBarSFtdpG5X3fXHUwMDEzTz1cdTAwMDOBd2OoXHUwMDEw7JWzbLdVg4LAlDRLflx1MDAxOe7buOFcdTAwMTGFhvJSKaN7dMxDI+NcdPaATZrIXHUwMDAzXGY0XHJsPkjliIOGMZQjbPra2Jfz5lx1MDAxYn2Hr1x1MDAwNNU+toP6zVbUOIOhc9vcT0Xu9L5RXFxcdTAwMTRb3fFqx29cdTAwMTg9YyFcdTAwMGaA/lx1MDAxNVx1MDAwMceO0qG8rC6XXHUwMDFl8puAK9vGXHUwMDBmylx1MDAxZelv/dFZV8vB6EfkdkErMzhcdTAwMDWkOlx1MDAwMlCUXHUwMDE3XHUwMDFhTYmGuzRl7lx1MDAxM1x1MDAwZbrHXHSbND2nWFx1MDAxYZRaeTBR1os6xLuA6nNcdTAwMDVSrb5VXHUwMDE3Tlx1MDAxZTyz2fudXHUwMDFjXHUwMDFm6PCc/bi614hdliSotNeTX5ZMvlKPXHUwMDE1lMUr2e2cM0uc1+g44NxcdTAwMWagbuibLliqjiOk+8RcdTAwMDGAIPHIOJ9BK9mgnm5bXHRcdGN5esQgzfXFI5wnbux282I3OGZIPO5b9lJcdTAwMDDXmZbCOziPp7lZXHUwMDFmO1x1MDAxYcTDeFx1MDAwNub6rlx1MDAxN6tcdFx1MDAxYlx1MDAxOHV1p0k+9Vx1MDAxOM9cdTAwMDeAXHUwMDA2XHUwMDBiWIOvKcksXdT0yVOgXGJcbrhufjRcdTAwMWJ3sXhcXDvXoKk+XHUwMDFj73Kvk/qTIJCNeFx1MDAwZalcdTAwMWaZtyZUe1x1MDAxNFx1MDAxMnCqSlvQeJqmg2H2rCWNMGg4NZS+0zrGXHUwMDEzXHUwMDFltki9Urq9XFyXIz5cdTAwMGJuf1x1MDAxYVo9goO2YozzzV4wPLhGVFx1MDAwN16txNrENIfBrXqAXHUwMDEywLNIb1x1MDAxY+q1YYpxrqtbmFx1MDAwN0dcdTAwMDJcdTAwMDbeXHUwMDAzuLqQ/UqxJ1riZ7ONXGLlYttcdTAwMWRnKVCqNff01eB4Mlx1MDAwMaZKY4BoweswgtzuaFBcdTAwMTJDIFfo+VGdVJFb8/xcdTAwMGVzQ2Y2g1x1MDAwMYFoh0CrL+Ah0NfUOGU7cHfOQU1SmtxJ91x0xSjCuuWuuu1d7cOroFx1MDAwMKMrXHUwMDA2iF2VXGZYbSrgy/jq7cPCoz3/XFxjfairqbqcyFx1MDAwYovMJD3BXHUwMDFiXHUwMDA0QeiWXHUwMDFlWlx1MDAwMMA8NEhoUJ9ZyZItVlxcrzS4OjXwiMVqtrtcbrGJ8dbn6760qFx1MDAwM25qgZ5Lf1x1MDAwZbVuIVx1MDAxZlxy3lx1MDAxZIZcdTAwMDaHevh6VMipXFxvUVx1MDAwZW+dXHUwMDFlgLFANWbdSTfMXHUwMDFhXHUwMDA1jrAkIJNepPc7KrGNxvK9h8xxYGGEcUP9+IxUemqQhMiP09nTXHUwMDAzrNdcdTAwMTG0d8tLWWBnPl9ovd790T9p1TVcco9bX1NzfC5F64puptbe3DG35Y5Yhpszd35drYRk6Vx1MDAwZSSUXHUwMDEyksvxjFx1MDAxZeJccpD5pHZErFx1MDAxN6NrqeRcdTAwMTQrZlRcdTAwMWb6XHUwMDE3o4lcdTAwMDRCWOlcdTAwMGZ93dzyy9NxWDn0QzhcXI3w2V3V6sKcRZvvXG7CPeE+XflcdTAwMTddXHUwMDEzvaVcdTAwMDevRO/5y7x7SZpaVpKWeVx1MDAwZUCiJFx1MDAwN9xzbFx1MDAxN0FyOTdTku4xpziwr0s2zFd9RMh44YdTgZFkheLhOGp20kxTXFxNLGnPrqREXCKdXHUwMDBlj+OeXGKiSlx1MDAxOXFcclx1MDAwZvlzXHUwMDBly0h7MNBL6GhcdTAwMGJndKkodFx1MDAxYri7SGXJPbo8uNFPyaSLw+5Ji7Wp+ZLYM6nxfPTDiDYnSShcdTAwMTnE3VZcdJ9TqbRmPSCAvMhuSzqfTFwiLSFbM4qOXHUwMDE58ZhcdTAwMTE2XCJcdTAwMTDDXHUwMDBiXHUwMDEwXHUwMDE222VcdTAwMDBcdTAwMWWJNM84MF2pXHUwMDFjktvw0rfIVD2m5+NyVD1K54S4k1x1MDAxNFx1MDAwMvhp1UpcdTAwMDf9wX6+gvMtVDJcbuU4XG5ll/6ZVby0Tm1WeZw/2VxufZ3lfL2Fp7pcZlx1MDAwNom0R8xSW9pcdTAwMWProVx1MDAxOE1VXHUwMDA1iKd/3I6FjXuP3/J+w018c4WzmMBRcXuEh2coXHUwMDAzsj+aXHUwMDE1REO+oyb4TFx1MDAwNcBGWqfkyfUuXHUwMDA1Q+G1xl3ywvSk6o03qu17ci1CzFt9mYGYxMhcdTAwMDCBXGKHJN6y0zhNXHUwMDE0XHUwMDFhd0DijchcdTAwMWRQaaBcdTAwMWFv595ccjumQZjIzKRcdTAwMDG8XHUwMDEx4XhKTVx1MDAwMDRn3UTwIIQlfFxu2Ji+Xqmns/WS31xuNZQ0SOis0jVrp95U9lx1MDAxNq1M88zhx1x1MDAxM17UWy9cdTAwMWUtrrAsqHHpzNynqiQjaV+VXHUwMDEzwKpcdTAwMTWjiNxQ3HR3qCyMZFx1MDAxY/BcXFvA9Fx1MDAwMKF5r1BpnFt6RXVZ3mZcdTAwMWLQXHUwMDAzW5EuXCK/TTTJU92YXHUwMDExobKPVHkjLepcYm+qhGhcdTAwMTAh07J9pFx0Q2iRvnLVK/ZkSVx1MDAwMKrjp+JMKOdqN1x1MDAxZVx1MDAwN583y1x1MDAxZuCl6Vx1MDAxYobj9Vx1MDAxMIio3uOuqlDDVFPCJN1ZbIYz6Fx1MDAwNVOVZcfsQ3fPT1x1MDAxN+iQR6LfRlxydaMwRCAqXHUwMDFk+IZoz3C4XFzO+HRItlx1MDAxYo01olFr3l/SU1x1MDAwMXXcXHUwMDA2Tlx1MDAwMCaGT/Lwrp1QWth+So3ITFx1MDAxOEcyJX55slx1MDAwZoyNVi9kQthcdTAwMDNdblx1MDAwNufJXHUwMDA0jIHhXHUwMDBlXHUwMDA07Z7+RG1cdTAwMGVcdTAwMDDDw7+gXHUwMDExXHLcoFx1MDAxZc/L+Vx1MDAxNt3u21x01nTXbVxmXHUwMDAwRDdcdTAwMWPlfSqvhdZmr71Dy9iIhlx0XHUwMDE2XHUwMDAzYJLNrcOavTDFT88vXHK1XHUwMDE2o1DAS6eH6Vx1MDAxNG2WfYHKq1x1MDAwN1rhMLN2aoJdXHUwMDA2puOBx3zuN1x1MDAxODxcdTAwMWTxfmzpXGJXprxcbru2LcXKO91FXHUwMDE0q21oP+FcdTAwMWOiPSHzIEAseYBcIuyGdL/nfVx1MDAwMVIyxtyrrML4nJuEtapcdTAwMGZpcD1cIja4s46EwPNcdTAwMTTvsy48umVOxjUqredcdFx1MDAwMEFcdTAwMDKFXHUwMDAxXCJ1UNctYzxxanTIpGbai6TZgOfsuIPNbOFcdEBIdn7Km+OCiHRLXHUwMDA0Q2lcdTAwMTY53Fx1MDAwN9Fm71hAdtRNzzDG311ku5wnw0dGU0b6pyedyqBxelx1MDAwM1xia1x1MDAxM9xcdTAwMWRHR6+BbZLurrtE62KIbLMqn29mnWSXaFx1MDAxYVx1MDAxMZBizMWJs8G5ZNxlR4+4LqW9xOj4XHUwMDAzpIHDhm9JnEt02vi8/aCqnkLkU8dQg6tcdTAwMWRcdTAwMDa2h73d6pEmLeZcdTAwMDZcdTAwMWRK2iH1ero9rpRhlGuKUENUe1Ciyct+5k+GXHTJedZlV1avXHUwMDE3SLlPVu5Wr2Ek91x1MDAwNq6OTnz+tNPDKFwifi/x61x1MDAxZEaccyzvYob3OrWWnqmRXHKVKXRcXFI9oHtcdTAwMWVcdTAwMDZYw5GIKnnSS7vqp+5hYdmKMCbW4Cae4zbKXHUwMDAxRJwtT/fzeEDPpi/zbWZcdTAwMWVJd1x1MDAxZsewqJFllq4+NmHc6ZEl2lx1MDAwMVx1MDAwN77axbmbZnzBQcGEk1x1MDAxMUC4apRRk1x1MDAxZXgxvVxysk1ccnlY0mhOZlx1MDAxMcylNCbIZ1xi2rZcdTAwMWJpR16IWat4gWLzYVx1MDAxZnlcdTAwMDNcclxmXHUwMDFijLiW71x1MDAxMdGFPsHRqpcmXHUwMDEz+Fx1MDAxN1lXIX1cdTAwMTbtmFx1MDAwMJDDZ5hx2O/Xc7rQO7XdePziXHUwMDBiXHUwMDE5vcTVPlaImPusO95CK/P2cOPybH/AXHUwMDBmXHUwMDE0wYnSxi9WXHUwMDE0pM9cdTAwMTA4PLJOnlD/3mSjXHUwMDEz4p5wx5Q7SG7nhotSnVx1MDAxNOL5XHUwMDAxblxye/KQO0JcdTAwMDZKXHUwMDAwSf6er17f8Fxc2WueP1wijC4vXHUwMDFkXHUwMDBlZlx1MDAxNDtQT1x1MDAwMrFdiqduXTar0OYp2pHt2Gq4XGYkXHUwMDAz4+0kinqwqysrOca5e4hGJ0R6/YD3Z9CiLlmjXHUwMDEwcq/0c7NcXGliRETW1myCh0VIjfg1s3vPe8ooRCxiwoSGYMBX9fDSzUYgKFv4S55zUtVcXPP1eW+2XHUwMDEzQ2IhIy9nmznJXHUwMDEyxGg6RypcdTAwMTJ6JcnsRu5EvVx1MDAwMidss47stS+FqbmZXHUwMDFhI192jFx1MDAwMtPL5ZGNlFbmXHUwMDA3vowlVU0qZaqRXdrhdtb9mNbHJFx0XHUwMDA3WmPh5tJcdTAwMWYpu8iAXHUwMDA3T/tcdTAwMTiHXbkzXHUwMDFiI9hH0ZKualwiPVwiyDfupJMgebRcdTAwMWLEYaCfd5RcdTAwMTB3s+LLKclcbm9cdTAwMTKjlqfZcMEswyR8VF7wgPaGKZEkidpvhI/x0WUu5MxKn2dcdTAwMTShXHUwMDBi0YboXHUwMDEyJuzGlYK0fvQ1j5BcdTAwMDVydPih23HBXFwwz9ZcdTAwMWZcdTAwMTlcdTAwMTSoovM0JD9b7r15XHUwMDAxqKz1zlG5nEZcdTAwMWFcdTAwMDCOjPDMYPJ0ij2P9lxyXHUwMDBlxolBObJcdTAwMDZ+ZWafpDG7w31Oz6+mwOJhcHlmY4NcdTAwMWLQmOBOMSCNTKLKcrmM1lCT26VHZKJqXHUwMDA105whZ7nZvos9luikISFcblx1MDAwZWpcdTAwMDfQUC1ClVx1MDAxYp/L8FBcdTAwMDGfv2NgXHUwMDA3a1x1MDAxNFx1MDAwNYuW3y1cdTAwMDJJk/mKLUu+L2p1dUxnoJ2qMWypglx1MDAxNi9PT0J3XHUwMDFhjSm5dlx1MDAxM7zfljbzN9pWqpvImjCSpqfMPlxmZKdZSXy3OeFcdTAwMTKJsEGvI4DezpijnetcdTAwMWWO4lx01/ojXHUwMDAz0o8+XHUwMDFiU6yk0/vJLE3wjLczfMjY8643OLro9dlcdTAwMTjS5PhcdTAwMThQOu9cdTAwMDB/JL80Sk9JXHUwMDFk+Vi4YsLonVcvf8bdTolLY1x1MDAwZlx1MDAxNOiFc7Ulm+KAXHUwMDA007uZXHUwMDE5lvNk15vN1iF3viHBXHUwMDA2uk+F2dtVL5o7ku/MSvmBSCxM6VxcdyjbL7RLbb2wiDn7XHUwMDE0JvfISJh2wkxcdTAwMWI9XHUwMDA0XHUwMDFlniPyeqTa3GFOcpFcbkLWkfCFYOCZyfXM0jmUXHUwMDA25pt9iCVZZ1B2PNTz0HGn2vySwYL9djF4XCKvPFx1MDAxYfS17M5cIvGhOVhJUt05XHUwMDAyXHUwMDFl16Tp/MBjYSlW4pMv2cO9gE75flxiXHUwMDAxzqfjhVCedNGcTFx0nO6Sr2nBiU9cdTAwMDSR1lx1MDAxOG4ol4C+gypdgp4mtTHYlCueXHUwMDFiVGbwkU37XHUwMDBmddF2t0zC6ClcbmWSonDJNzky4eXO3GrpQZLB095Dl0OwUYPRddbIilwiVOGcalx1MDAwMVx1MDAxN7tPdUlcdTAwMWI0vK5cdTAwMDU3K7BT771l0aIuO1x1MDAxYySBaFx1MDAxZD2c9ei+XHUwMDE2M1I3p4bzouODXHUwMDExXHUwMDE1IGIps0Rj1aLOuoRs+TMlx1tcdTAwMDVcdTAwMGUnvGhPllVpLkKM0u5Vplx1MDAxNCy4JlrX2dVkMLmlKjdiLIFnN8IwhZaCY1qhR2Ajlju208iuNsujaZ+Bvy5cdTAwMDLDrDMw7TfHx1ZcdTAwMTnu0Um6alxulbRA+sSm1rkkTn9cdTAwMWLYtmn0XHUwMDA1YsHrfU1cZj6T5oYguDpcdTAwMTjYMl9cIrMh17XlboewnDxcdTAwMTOHwXN4lJRjyfbkgblcdTAwMTlHhKTGzIKE0FxmXHIkyiSpb5/QWFx1MDAxMZN+XHUwMDA2VVxmJCfk+bhC3bK33vjE9I1cdM/7vF7QmcSe0DJcXOvimbpdpMAuXFy24cJcdTAwMTbiXGZcdTAwMTZxStBcdTAwMWNwzbu7jlxmhKTzWDDuoJg+gFx1MDAwNDxs85w80XDFIVx0XHUwMDA3LkqcaYIz1EXQnlx1MDAxZcygiduUxbQnkFx1MDAxYknU425H56mvwZtYMDfXt8h1PNetfO/hXCKYTCafXGbuqmx5uFx1MDAxY01SXHUwMDA2q1Fx5+l6XVR+U3Z0xlm22jRppi6jY1x1MDAwMuaYSVxmulx1MDAxNsQ0PTiNVp/mabvw3e124yTDIE/w+TBcdTAwMDKFqMI8mbHcpVx1MDAxMiGlzkXvnFx1MDAwM0/2kF/AU4Jhn49cdTAwMWM6eFx1MDAwZZR03k7oWneSLjO75KbPmTtpO/bs+3k4y/Uge1vEyPx4e55GzpRMXHUwMDE0gdhcdTAwMDFTam9AqDE3XHUwMDFhu7vcdG9HXHUwMDFknrRbXUFKKqk76EZDJVx1MDAxMy6HoqCDiE2X9XneXHUwMDE5RFx1MDAxYmHoXHUwMDAw1pFmjfqkrSCaXHUwMDEzUlx1MDAxNFx1MDAxN4dcdTAwMTFcdTAwMTAquL1cdTAwMTlHvpqCplx1MDAxNV/KS7VIyYlcXPuMgVx1MDAwMlfZn1x1MDAxNoGJkI+cgnlccjhuXHUwMDE1jURK3LNmllx1MDAwZpYyoHNzb5PbNWzVgc29XHUwMDA0XG4p/lx0XHUwMDE42ayt2s419ZigVotFodRcdFO1XHTDepKPUJ0rfUO36anE4Vx1MDAxZWPz2rvJKnw0qYpcdTAwMTBcdTAwMTZH31x1MDAwNKTHyDtcdTAwMGZcdTAwMWVRy+4maN2P9CMmm1xuOVx1MDAxZd6esNE6fLPT3t2Cfj40J9XZ2VruUJtDq69cdTAwMWKWZ13OfXl+nEf5XFxcdTAwMTYqTVFVjZM7hqbKXHUwMDFlc7HSnNyTwDhnJ1x1MDAxOIg5TuYjyUqTZJhj41x1MDAxMJZ0LVx1MDAxNFx1MDAwMZ02jtky6mrauD5cYpdcdTAwMTKgVmTq+v5cdTAwMDFcdTAwMTNPVVdcdTAwMDdcdTAwMGY8ZOdcdTAwMTHMxVx1MDAwMztcdTAwMTKI1FxumLRQoNm5KKUoeZp3ylxuPrdvUOY0c3RKK1x1MDAwNjV0YbS84faIkFBxK1x0Mlx1MDAxZD++zd1QXHUwMDAyriZcbm1D7sm+ryk751x1MDAxYeU3XHUwMDEyXHUwMDA3XHUwMDA0YOeAKVx1MDAxOfjqYm4qYJu+dNKAfpRdJmhDwU+to1vI04FcYiRYwnZcdTAwMTBv/T1cdTAwMWOR+uY91ECPlH1qSJngctLQXHUwMDAwjlx1MDAwMHqURFx1MDAxYeWigolcdTAwMDQji0fe9Fx1MDAwMohh/UI25GbVm5NHTVx1MDAxMbE3zVVz2uDQXHUwMDAyo+6tSqE0IZ/dhztmzs3L1lx1MDAxZS1Tz6U9LoSiXHUwMDA3JHB+lUeurvZJ6lLMYo77nVaM87lj+n5ZLzbHRZd9Pauuknv88Fx1MDAxNCxcdTAwMDSmlrK0nCFcYplcYjBcIvmu9YhcdTAwMDJyrM9Yt8miz08/N4e7e5+LXHUwMDFiUavGmVx0Vl9kaSy6ZFx1MDAwNHdnb62F10pcdTAwMDRI3L5cdTAwMTSigYebXHUwMDEznKQprDCQJ+JcIr1ErCy3ZoZlnSOa18VGJMpbNpnzbPEyOfRayTKf+bTN9lx1MDAxNVx1MDAxZVx1MDAxOVx1MDAwZX+24Elhx/G897xBXHUwMDE5i1wiLVenxmdOvppRZkqvXHUwMDAwRlwiIDWNWlx1MDAxNzjdSJ+0/rw7UaOGXlxyXHIwoyF3XHUwMDBiy5iJNr24uNxIzLJl84ItQVx1MDAxY47mXHUwMDE1XHUwMDBm7lRcYplEbaFcckI1wfBcdTAwMDRisZPgK3Bl8Vx1MDAxYrNAXHUwMDE5QVx1MDAwMW5cdTAwMTOIXHUwMDE334N80Fx1MDAxZDTDqZhwpfDlukFwXHUwMDBm8kZx5rkjyoX1Ulx1MDAwN5tcdTAwMTKS/HpKO9JcZtgkgFx1MDAxM8DVi6XeUVtVXHUwMDBlrONCdvhcdTAwMThcdTAwMDI/yS3M7yVcdTAwMGbe/bo/p1x1MDAxN1x1MDAwYjPBkCyuvHEqhpx0YHM2tSbwLavWjSXBuN7QrrP5LCmrv1x1MDAxMIPG9FGWS9OdvuFpumfsgmZ7XHQ267rSM1WacSorWX+hXGK575Jny9meWVx1MDAxY7EgTrpo3LlbaijXgaFIjvfZ3U5AMGHBc+IjSV+jJ3uViOdcdTAwMTGTrSQhkpKV4DIjrTOSWPHUW6fePWlFxIBLK6nuXHUwMDAzzVrGqiwxJfZHbzLCkVx1MDAwZaHRyFfIXHUwMDA0nOz4jsBcdKJcdTAwMDbPyerRTE/Yli+xs2Lum0XpNdh0lLLn4/3ZXFzFUXWB5G76RItcdTAwMGKVJ4+GK05wtlx1MDAwNU9cdTAwMTKKNdrjXHUwMDBmQ1x1MDAxNVxcToPqMIbinfDSVrrWX5b6SK+4k8HKxlhcdTAwMWQpdHpaoLV/dPJcXGZcdTAwMWFcdTAwMTC0XHUwMDAxIfVVZlsxqu90oiSyimuUy7pk4tKapI7D84Tj21A8qpiBlSfsRv2du9w1XHUwMDFjy2A+kvvYMWSukWs1ronlYXluVu+43vNnP0m2XHUwMDBiO1x1MDAxMGuJlVx1MDAwMbC2XHUwMDE0uJdcdTAwMWPY2ar5dNCYa3SUv4iSeidcdTAwMTNcdO1OhZbMXHUwMDE30MsvrapwXHUwMDFlXzZptYpcdTAwMWWvUqFCgFx1MDAxNmI04XxVJU9nybxcIomBXTNZSMtVw2582DOPk+LY4jKdiVx1MDAxOFx1MDAwM1x1MDAwNrJIrtlJdO0jXHUwMDFk6ivzeitcdTAwMDdcXFx1MDAwYk2CXHUwMDEyLmSZZZQyi8zwuFx1MDAwNFxijtx76eBdRZFcdTAwMWE7XFw9XHUwMDFlplx1MDAwYlSw8/Y8dlx1MDAxY9M2JrvoXHUwMDFiRtPQYt+Bjen5dp6RXcBaTjWjyTBVQShZUD9dXHUwMDA1i3BA4YxxXHUwMDFjVPpcIoVcdTAwMWVP/0j13X/OwtXq5z71eaJa4lNBky46XCIj9uhBTtG2Q9GEq9bU1tPzWpbQ16Zp6lrm99aoh1x1MDAxYkHHd1x1MDAwYu29xqRKzi9TylnC+3pJXG5E5m3J6lx1MDAwZVx1MDAxYpVcdTAwMDNYsCTIXHUwMDE5tHNbIFdeZqAyyfJhfXiMwVJcdTAwMDNvcHeH3Fx1MDAxZCBU/Fx1MDAxMFx1MDAxNoRbxjDbQlx1MDAxZFx1MDAxY2vdSHzuhuRcdTAwMDFQrNa2XHUwMDE36mHl9vLpdqDqmVxmrLAqmVN1V+BcdTAwMTJcXMMq7qQ2XHUwMDE5M1x1MDAxNC3omNJoWPbvxY7lN02OSlx1MDAwNOrXs29ewqdcdTAwMDftc9XRXHUwMDEwdHi3M9tZa1x1MDAwN1xctoz0/KLnt+bxNEXXj9ZRIOuzXHUwMDA3goe2nlx1MDAwNoG5+Vx1MDAxMps/WsDXd6FnwrzLlZlUmUOVI5V7iop6jsOVbdJU3O06XHUwMDFiy1x1MDAxZPJqTUhQldnXObBmrmR6XHUwMDFhgNEsVWevTI/cxY6bzDeuojXaXHUwMDE55kfbXHUwMDFlXHUwMDFkJFPkI+Ugh4zhqFx1MDAxM2iPcZy1XHUwMDEyf1x1MDAxZnz5SqD+QZx8Z6tcdTAwMDDDtUWw71x1MDAxM39cdTAwMTXMzYipR4Dd25noXHUwMDFmZFxia0FBVaxcdTAwMDDf7jRnXGJcYtaLdFx1MDAxOT8t3DCV8YZccsPuXHUwMDFiT8VcdTAwMDaijOP0aJHj+pG56+pdWfHhxnM687cn4VpjxFx1MDAwNrme3IlcdTAwMDK/0TypnlP27M/5doA271x1MDAxOdtcYnuu03yn5K1cdTAwMDF5mI1tXHUwMDEwelx1MDAxNjYjVDRcdTAwMWKsXHUwMDA2K6ybJDBsXHUwMDEwQij3NsdcdTAwMWHmPt7qXHUwMDA1flx1MDAxNPdtNkQuPouTXHUwMDAwncVcckEsl2dcdTAwMTfvzIiTU+o181CKna2tZXMyXHUwMDBlIa0un5+PXHUwMDFhs2FcdTAwMDBcbp9cdTAwMWSScWonyde7K1/y4EhpVSmDr56ewJV6t7TxPsrrXHJxKIY87zp6SG3FUe5duNnNUs14/cy5w7gvlYPFMn9voT7wjtyRXHUwMDFmuURcdTAwMDW2XGKkcT9OzTY9XHUwMDE024GRyUbPT0U1XHUwMDE1qzNvZ4lXT4FcXHFHW2m2LefjaNpiUSa6mVxyjli0JlQ6XHUwMDE0XHUwMDAywrm+tutcdTAwMWNcdTAwMTNcdTAwMDUsorJJ+i2gQrXEQEaKXCJdX883TpTkYb9cdTAwMWOW37ypit0+XHUwMDFlw3Z5WJCDLoLiijWUtmDd8r6MXHUwMDExunfL0JDGKOskmnk5n+eKwWZcdTAwMDDoiFx1MDAwNVxy9SqvXHUwMDFlalx1MDAxOZmImVx1MDAwYshcXF10y6TAgSR79Fx1MDAwZYfgqJ915UitpIuY+Vx1MDAwN7tcIlr0XFzCgt3HpWzVYlx1MDAxMamzz92IkLjmvFDmsompelx1MDAwMLqbLC+i7Vx1MDAwNsudJVxmQFx1MDAxOO/sVW9Fp5RcdTAwMDfkslx1MDAxOO6TXHUwMDExLCzpXHUwMDFmqu7u9+rEN1x1MDAxYyFddZCLyyc/JbKPXHUwMDA1XHQp2M1cdTAwMDUkWlxuYL1qy8fbSN3CQYGuWbKSR1xue0lBXHRaI1x1MDAxYmQyXHUwMDBmIVx1MDAwNDJcdNF9L6fazlx1MDAwZlx1MDAwNilcdTAwMGal02ZIzVx1MDAxM1Uleq7Mn4z1ON3NnXFzu6do/pL3i+1UXHUwMDFlI1ZnQ7iRXHUwMDE2/2jiXCJDILdcbpN7UY83OF+5XHUwMDA0ryZvIVxcmjtlfTaj3l1cdTAwMDbaw9W5LH5kwFR72XQ/XG5cdTAwMGIk8nRRnOtcdTAwMWO0XHUwMDE1kjNPldxcdTAwMTia3SODlD5cdTAwMGZErTS4WUNClqg5ZEVhdjVA7DwrW2Vm4MuZclx1MDAxN1x1MDAwM8VE+0Tyfb7dg26qiNex2UQ9sm81bvbI4lCjXHUwMDE1Ulx1MDAwZdOIM7tXN/GG86JcdTAwMWL2Oo9cdTAwMTYzZduwQIFXM47UvDlcdTAwMDE+esn9+slB3WVcdDMmMlx1MDAxN1x1MDAxYjxcXKeQhVx1MDAxMVfB/pFxhzSX52C9jlx1MDAxNVx1MDAwMJLHa3bXrMxxTrN5f5BcdTAwMTZSUFx1MDAwZlx1MDAwNFx1MDAwMEFFOqqK23KN1ThcdTAwMGW5XHUwMDFiX9j7xMPBOU3nmXxcXPozuykq32DplblcdTAwMWFVXHUwMDEytcNZ88Hzao+AKlx1MDAwMvQ2ZvdHulx1MDAwNWxzQlmiXHUwMDA2fIq6XHLLuF3sXHUwMDFk5uzTestlwpCWXFzMXHUwMDEyzUaAXHUwMDEzOIdcZlx1MDAwN89cdTAwMDYw8C5cdTAwMTZcdTAwMWL4dFx1MDAxN1Nu30KItFx1MDAxZTb6XHUwMDAw1sWA22uF+qNcdTAwMTOtkFx1MDAwNpyg3lxyulxuhq6FQ4vZ0rnLhYqKKpN5VpdcdTAwMDDvbtDA6izwYuGPRTfWKWf1S/ykPNXBY5XbPY7EmTVtjuBcYnVcdTAwMDXqXHUwMDBlmVx1MDAwM1tcdTAwMTONJ0dyXHUwMDBmXFyFkteiXHUwMDBi3enWjFx1MDAxNLXm+N4l8WRccoTnXGJ1o01cdTAwMGVMb5htVbtoyNaUR042lVx1MDAwZlx1MDAwNzVYoFx1MDAwMGZcdTAwMTXsL7aHXHUwMDBiXHUwMDFjt0e+4nWCJOGbXlxiN8Y3lS12YE3Y8YU5XHRTdrnd9lx1MDAxNL3ieyE98fSqgMxgjFx1MDAxN781RTRcdTAwMWRcdTAwMDKt0m7mSTkyXHUwMDA3m7Vh9t4kp5K2Rqkq9lx1MDAxY7Ah8+RcdTAwMDftlDCHXGZmXHUwMDFk5Fx1MDAxZvlcdTAwMGV3cMZmjVxmzoT97FGq57lcdTAwMTawXFxPXHUwMDE2nFx1MDAxZEmBXHUwMDAz2/KGP3pcdTAwMDRZ5POe9ooq8/h9XHUwMDFhVOBRR4Bcck/tOKwua+aeXHUwMDE5xVn4XGKG2lJrqkhcYqlRnLrDxlDQpDPRSSDAKf72XGZcdTAwMThcdTAwMTZmXHUwMDFmXG7uqm7FXHUwMDA0fbucXHUwMDAyXHUwMDE4jZbDrTxcdTAwMDDwLMpmmkZcdTAwMTC7RDdcdTAwMWY6Y5FiJk5rXHUwMDBmaaZSQn9cdTAwMWLv0zlb53VcdTAwMWS6x+OIwpprbmLrN2jNYIR45H6e01x1MDAwMVx1MDAwZX5Sz+r5dSp91VdcdTAwMDOtgodcdTAwMThcdTAwMTK81Y5cdTAwMDFcdTAwMWTnZW+4UctGwVx1MDAxMbZcdTAwMDam9km1sXiocKdcIs2OXHUwMDE0tzF44aCr6uqySrXYYZHzZ06mgHk64Z2RijahjiYu72yKLSDQrX585OY5MjvF/YQ/l8fBzCMgsaxud5nrPDe6XHUwMDE0bZ6MabtcdTAwMTY631x1MDAwN+yHf59cdTAwMTm7RaP6Vlx1MDAxNFenV+a4XHUwMDA3Rf6S5p2cRpGXqlk98TVcdTAwMTUn3CpFuFYnzEPygSOLuHRDozxOTou61KxTuzBcdNp4kVx1MDAxZWKDhZVcdTAwMTeYpI0mXHUwMDE4eU5nudln7T5aQH+/J4plnKtBSa7+ha09tlx06VmwdVx1MDAxMmDOTcyVQyrp5pOLiIFja8PmW2T3h1wiXGbNtC5kga1cdTAwMTT6XHTG7f2qP1x1MDAwZYlcdTAwMDDZw1QqrVx1MDAxOO/t9ZS8LopcYlx1MDAxY5Dh26ySXHUwMDAzddnKLKJswyrbS5y2hjyjg36hZ1x0u5d5sorJuuh70fbnWLTL0HORSusncZ971Fx1MDAwMFx1MDAwNaWWzsy639WxYSjwzPM8rFx1MDAxZF3Ptvkk8ZyOY0T2vFx1MDAxMphWqU1cdTAwMDCH/mFcdTAwMWZOd6mx5pxcZpzt1JgusyxKzWUxYrY2St7dXHUwMDExLU/reHFcdTAwMDfSJyWfmudcdTAwMDcliyerulitOTFcdTAwMDBcdTAwMWWv/Vx1MDAxM6Ko58aigWD251x0XGZCdlFHptNogeq56Fx1MDAxZc5oXHJLQ4WEp7KW1YhyXHUwMDFhXHKhqUvr9dnDXHUwMDFkqoWywnhCk+shd4SCXHUwMDE4Yk5S4a7ez6NcdTAwMDF15Vx1MDAxMEzi0VxmXCJcYu73OyCeXHUwMDFlJ1bBKVwi1oC7xlp75Vx1MDAxOT13XG78y7BARLFunv2QZclcdTAwMTnggOYrWIpOWP6kKDe0sI4paOvOJ5r59JPbRGzUeYtl9S5cdTAwMWVcdTAwMWRVQeTjKsmJ8FxmjSsqa1xij6hOqfpcdTAwMWNa6lG4X9xMjM6q6FvuxY8pRYP2WuPHUD7abnPEXHUwMDE1XHUwMDEzuFa4RMW52M9qhVx1MDAwNFcjMWVcdTAwMTeRuChcdTAwMGWn2SNcdTAwMWQyQtEzq6uMfDN85kkhLYbZV8ypTuJt8TnrXCKvh1x1MDAxNXZcdTAwMWGC32zJictxvj3xojv8XCJCTMeLXCJcdTAwMTGzayZcdTAwMThcbjXGObO2YDMyY5uPWSBcXG282ZY336c94Vx1MDAxOE+pXHUwMDE1XHUwMDE1XHUwMDEwXHUwMDFma1x1MDAxMlJcdTAwMDOKomt5sNFcXCzEzc5XjdNX7XHtpltWk1x1MDAxN0CMnIBC73yXR1VpQlx1MDAwMLN0iNqY88Of/S5tgXvGUDVRpON8rTU/XGapXHUwMDAwg1x1MDAxOWwxQybK4qbO7p7vPid4XHUwMDE0KtKEffcsMSk4jlx1MDAwN8DZonyWW99PXHUwMDAzdDl08OE9w6ZcdTAwMTb3XHRcdTAwMTVLmrtgklnlN2pxnVx1MDAwYtfmOp5cdTAwMWa+54lb872H9ZMjmqfr+fkw0iOHvcdcZlx1MDAwNscrupkk1Vx1MDAxNKhcdTAwMTnjXHUwMDFldCS11lx1MDAxNpOwliWZwFx1MDAwMmVdSlx1MDAwNEjoO0HQXHUwMDE4X1x1MDAxNfHdXHUwMDFlXHUwMDFlIFE9gp4z0XpTOqhcdTAwMTdWPZeUy0lF+J29Y888XHLuQPpUePVcbm2322RcdTAwMWW6XHUwMDFkPcyrp03KSVklXHUwMDFhXGKJlN879F7RbceclEap1sPvXG43w4glpulHa++0izmprvCMT7hcdTAwMWZMqEffMeyud0qGtdVcdTAwMTU0JFx1MDAxM67KypEulPd0qPScL+ZcdTAwMWV65tVcdTAwMTJcdTAwMTImb2vXn4vL01x1MDAxM8iCXHLmnVx1MDAwN5VSwzpbxPZcdTAwMTk7aNXovFx1MDAwMktcZs9cdTAwMGJcIubkZHOO12yTSqv1WP9cdTAwMTRX6oYvmFx1MDAwN5XkfTeziizs/Fx1MDAwNG1Kr2VUb5TdXfFwncySROS7RVx1MDAxOYLzoShsJ7C6XHUwMDE4mPKOXHUwMDA2U1xc3aTF0Hf7seNjXHUwMDE56SYwRWrduWnOT5JRXygmeoAytzuRXHUwMDA3n5bXpavJ1bFYV7C4y1x1MDAwNbxcbvF4k4TNq5nVz1SRgIRcdTAwMDZcXCmyMlx1MDAwYn/ExmuXXHUwMDFkipWA4cDFYldcdTAwMDQ2k6yXaSN2tKvZreKxXHUwMDBi7JVcdTAwMTS0YFhcdTAwMGVcdTAwMWaBRYVcdTAwMWbctFx1MDAxYYma2Y9t9YVaRXKBZ695dl1Df0SopeFcdTAwMDONxNPLWd1nqj3H7bbrqlx1MDAxZipCqdxYX5lYj23F0+voLZee3eeleVx1MDAxNJr3XHUwMDE0NGq8YItcdTAwMDXju1x1MDAxZIVatcdwXHUwMDE1XHUwMDExu6vw/lO24919hoyNhIpdXHUwMDFjSdqoJEqQPoJMoYXTzMzyiJCRfniHZiw937NlXHUwMDBirVjAXHUwMDA3SdCTLvJjJ6stQHN85fOxXHUwMDE2civuXHUwMDFho4+F3lx1MDAwZWKdXHUwMDExd+V6g4RrM1x1MDAwMUXdyS3hXHUwMDE2uDubOsPhgrxcdTAwMDBcdTAwMDJz8m/3IzZXeUTW9Fx1MDAxOWkl5khcdTAwMDL3ocWcXHUwMDFhXFyxXHUwMDEzt56l1VStijx8XHI1J2tzRqgqPbTu4ZhXZM5wq2FCuKyr4ep6XHUwMDFj4p9MRmVcdTAwMTDDeDhcdTAwMTRcdTAwMTcxXGYliavUooGf7YX84JHWOS0lLFx1MDAwZe25kzCg95+oYiVK7j2zJ9G5XGZ1S73sflx1MDAxYq9cIp9cdTAwMGZlXHUwMDBiXHUwMDA155N5XHUwMDBizUZq6uTMJd2MwFx1MDAwZThLSb2BXGI66ovcazvmkLwyOFRcdTAwMTVah+zBYFKe7Tt5JmJoQi56XHJwOd2pl/Mztits0VSuNmBJV55ZSVx1MDAwNmNccodcdTAwMWWBsj7+dGPMdU35XHUwMDFjPVx0XHUwMDAwXGJ6nbndq+iyXFyi66JOMlx1MDAxZMWRZVx1MDAxY6FcdTAwMTU9ZTqTarrIVvqmg00kbM90PtHnOVx1MDAwZVxcblGXsMlcdTAwMTlcdTAwMWZcdTAwMTaW021cdTAwMDVcdTAwMTlDWUxcdTAwMGKAd62WXGLXOVx1MDAwZqnTNJZ2iYdQM3jZXHUwMDBlWuegXHUwMDAwXHUwMDE36cLjXHUwMDAy3SU0Z1QhOm0n73muluR5zTHNXHUwMDFkXHUwMDE5JDo52tO50Vx1MDAxMdvYN74xb2VcdTAwMDbosSo6XFz8JOSZXHUwMDAx0GAz9+KRdH4oMjmfilxcXkiNoFx1MDAxOP4pqlx1MDAxZKjNJLS+ekbs6uleaUC1qrP7rHKI39Un51xcMyVcdTAwMWbpXHUwMDBiXHUwMDAxJVdyPJG1eNFcdTAwMTFcdTAwMWVLyVx1MDAxY1x1MDAxM0qvslx1MDAxZlx1MDAxOVx1MDAwZjVY2aXgXHUwMDA15U8jyjJOXFzopsH7YI+PR/KmXHUwMDE5bFx1MDAxYtCmZlx1MDAxNNwjmVx1MDAxZlkodXZyZ8xcdTAwMDSG+PoslaqMkDE8zNsqXfZcdTAwMWFcdTAwMWFiJCRcdNTWbkdFgbsvnJS7tiFXR5MkI4zsnHFP4mmoqDVIffEpylxuXHUwMDExXHUwMDE23O7XpFxyw3Wo9adenPNgXHUwMDAyRZUoz+5d2eSkQFx1MDAwMjDer6xcdTAwMTRcYn0rJvO9VNtKaVx1MDAwNNZeY3Kaoo2vXHUwMDBiMp1AxWRbXHUwMDFh511cdTAwMTLOsZKl7GWZkPBwXHUwMDA3R7DrjDu+KkNymlxukPVZwCDM4lx1MDAxOVlYXFxcdTAwMWIlUmpb73jUXHJcXHx5wrjcVItcIlx1MDAxM0u1XHUwMDExyzCP5vtVodSbPbLYXHUwMDA0XHUwMDFlcMG8I/9FdziXXHUwMDEy2crgvFx1MDAxY4VcdTAwMTKRXHUwMDFiXHUwMDEwOcfZIYJ+cblGTNr7XqJcdTAwMTNcdTAwMGWiKCglXHUwMDAxdlx1MDAxZZm8lTlnbVx1MDAwNyvL1fdQNiHOKqhNjdyhONiLXHUwMDA381x1MDAwM8zqTlxmudi7clx1MDAwNj9tN0+h75FMoibdiqV0P5WG451cdTAwMTGOzVxmpz/0XHUwMDFlpYIqbss5dcVHXHUwMDAw2zpcdTAwMWVgS4yeNFx1MDAxNojaXHUwMDBiNi+a5stj2XjscJjQu605XGJcdTAwMWOMzHRFaTiZXHUwMDFlXHUwMDAxXopbelxyYVx1MDAxOVx1MDAxZC/jLWmsjK5cdTAwMWSxube07Vx1MDAxY9lcdTAwMWMzeOh90M/es5yl8b5A5mE+QV/VXHUwMDEwyb9ekmJ7jibvZXifXHUwMDE4Tn1YoyWtNajQt1x1MDAwYiqXMneyyIlxXHUwMDFj9SSl/NFhs54xoqT6QVx1MDAxYc9LcVx1MDAwMq1T2FxiZlxiXHUwMDAygFx0X+ycXHUwMDFi7rycQ57RytiDPE2lpctcZu1OXCJiXHUwMDFlbbrvcKnbT0bQQFx1MDAwMcRMLl9Q3Z39a31l0MWGTWJvRZklfMrj2CbKn1x1MDAxN/liXHUwMDE5RHjhXHUwMDBlvd6JbFVHQfGK9EqPmFx1MDAxNlpLVF+2zfdGkyOPpswmV/OAQlx1MDAwZaYnc1x1MDAxNbLiyG/YkMC1csFcdTAwMGZGcc9cXPNExJGZvKBcdTAwMTHkdrvnIVx1MDAwZtZIPe1cdTAwMDFgN9JsV1ZW0eHEhaKkXHUwMDAwZIbrNnXIVihQm02m/LZlXHUwMDE4s2rzVUZcdTAwMTlcdTAwMGbdXHUwMDE2SWw0eepcdTAwMTi9POnEM9TZduTSJ09ESlx1MDAxMGO7QOZ2dFx1MDAxNYndXFwyj4/bNJlv/TV0RMHSWpxuz+uJXHUwMDE5J06la1xc0WQxfEo566gt1C540lx1MDAxNuk+3GlE4HntyVRcdTAwMGaV7Vx1MDAxOSUmxtshJWaLK3NBXHUwMDBl/a2TxkdRXHUwMDFjd2JcdTAwMTRnITD9kptL4e3FNVx1MDAwMYJcdTAwMDVI005cdTAwMDFBkraTdELu9KXvRzBcdTAwMTQ21pOJyuviLKfBoWRcdTAwMGJCR9t5gWJcdTAwMDJ7XHUwMDA0vIiPMSsth6+xPZWzpcw/P2BcdTAwMGbMQGnlwaoqJGst2sPvKNftRp3X/Lwk51xin1x1MDAwN6Xmt2SHz1bBXHUwMDE4IPW68SCNrfBcdTAwMDLWyWQzTjlV6JxqU8kwvJLVl1xiu698XHUwMDE1XHRcdTAwMTktROtu0Fx1MDAwZnHR1ujmKGlcYk9cdTAwMTChzPLpNEe0dpfkVUA35oCZ83CVS3JjIPoqSrlwaEdcdTAwMTD5VEfnyF5gfCc5ZVx1MDAxNTtcdTAwMThFOVebyDiYs5hcdTAwMDeUyl1cdTAwMWQqz/2hb53YRpD+rO/ihcLEjGFcctOuuVDZkHDKb8xdXHUwMDE4PX9cIspcdTAwMDLZXGaSS/NcdTAwMWJ51UsvyO89Tn5aXHUwMDA3X6bXUuBCXHUwMDE3VUqKXqZccqLT+yRcdTAwMDLYvqU1J11MhtlPNVx1MDAxN4xcdTAwMTG7XHUwMDE14K4/IbCiL/5cdTAwMTGFIYxTc4NccnFhpVVTglwirLdiUlx1MDAxMYFgXHUwMDEwuFx1MDAwZSPhgM2Xk1x1MDAxZmld6jz00LyGXHUwMDFiWjUuiaw6du01+blGREhcZlx1MDAwNOigVyZcdTAwMTbC81JuXHUwMDAyxnWt0Vx1MDAwN6iJm51R29FcdTAwMTFvsCk71dp5XHUwMDA0XHUwMDAxXHUwMDA0Rq6w6om6d4V2XHUwMDE3sntdvbRcck9cdTAwMTdcdTAwMDM7s8ghcb26XHUwMDE0gCbgXHIoyiB8VsJMq5utcj1ywc37uT5cdTAwMTlix49GKVx1MDAxN8JcIqpnuaBYmCO39SlcXDBzxi1fiNhcdTAwMDVUMtiRMrujOPB+xH5NlHqvkpTcVVGoXHUwMDE4XHUwMDA0XG7VjrgyTJVcdTAwMGW2Z/s0b6pcdTAwMTXfPcdQlMzINN1CxbBVM1eJXHUwMDEym9StS+soNU5cdTAwMTVcdTAwMDdmJ0NgXHUwMDFlMlx1MDAxYbJ5hj7sq8XY7JwlT1x1MDAwN+PrKz5EXHUwMDEz3vJcdTAwMTD1TFx1MDAwN2Bint5cZt1cdTAwMDbPxWr3mtnGYGdWXvek4lx1MDAwYnx301OSWzOgOylWpyuOUe2PJq91zjw0N35eYYCe+Vwiycxl8rRUJ5jYKCxcdTAwMWLorlx1MDAxOXKoYVx1MDAwNXGpV/OJw2bDdVxcWa5cZlx1MDAxYeLGrts1bidwSfub9ehmRcbY1+1aXGarWlx1MDAwZS70lZpl2X//7+822vXJ297C12/8hF6/XHUwMDEy623D4uu3pVrJ2Fx1MDAxN8n8/pvPIFx1MDAxMkZcYuj9XHUwMDA22e//PyZ/79623/+fV/5ccnvbhte2evy0t41cdTAwMWQlfHO+3NtcdTAwMDbHLMK6eIiCPlx1MDAwMNBcdTAwMDLseUZ1XHUwMDExny3HaFx1MDAwMsjcXFyRReBOhlxcf4TdYKRLXHUwMDA0XHUwMDFlXHUwMDBm1IZcdTAwMWF6o8GeIOrOKpZB7lx1MDAwM+3WXVx1MDAxNra6wuS+cluFz5U6x/VcdTAwMWODs1x0JKRcdTAwMTlWeLw43JKG2WG5aFx1MDAxY1/JeVx1MDAwMlEwTbFlstOVXHUwMDA0XHJeselcctudXHUwMDFk4kNk7M0lilx1MDAxYsy+2ztSmelcdTAwMTFE71x1MDAwZkDIPcdtPHKnXHUwMDBiSjxV/CMxQZZAR6zzqWw5heW5oFx1MDAwYiZcXMFsXCLvYZjiW2ucMlx1MDAxNpRIXHUwMDEx4V2UQPebLktcdTAwMDAoN9TBITk2oTlcdTAwMTJB2z2COMNSQmks+pb5hEja+5IuLPhEn5RCTniqvZ7vqJXUJk5cdTAwMDI79VxmXGZ0JmBWNDzNfrE9Rm52zrdZ9IJK+cLT9ERcdTAwMDJCP5Nccu1nXGZwuVx1MDAxYlrWl3VaXHUwMDA09dh3gZRf/Fx1MDAxZKZDdUZ3kj0n96WNzlfolGVeWsozfLKd7dKc4KRon1p1R6R8NVLxel+5bLBzXHUwMDFjXHUwMDE1on6RoWbd5UOZ0+Tx5PjLkZVBJSic1TaK5HzB4lx1MDAwN0D7IyNcdTAwMDczeSqAy5HfoVx1MDAwNSxaXHUwMDE4rVlujefKLYRo4Vx0tf9/ZeetXHUwMDFjoZJA0Xx/hVx1MDAwMO9CzOC9h1xmz1xm3puq9++LNtpwN9VII3XTfe85paFJQEvmYEayYNGjt1x1MDAxNEG8elQookCG32WbXHUwMDEyx/LNeVx1MDAwNzpcdTAwMTbr3S7xXHK03fmgRNLeXHUwMDExtUZ81atcdTAwMTTLXHUwMDE1ntgnZdBxY68xviFV/jmI94JBeNOKYSUmXHUwMDAwgMFLaZxccvNj8alh9Vx1MDAxN/dyq/4u7vzq30lcdTAwMGKMMb3H3s/f4Kp1nfiSolx1MDAwYlx1MDAwMGiueGG3YFx1MDAxNviUi0Fq9zr7h3ZRbFVcdTAwMDdcdTAwMDGMNSNVvkRcdTAwMThh58lSXHUwMDE51/yIdcanXHUwMDEzjcdAeaJcdTAwMDApKmY6LVx1MDAxY0M9PN7Dm4Bcclx1MDAxYp/SsFx1MDAwZl1GzkW3dT6J9M16wsXnOExDfGu3LFxm+kHAXHUwMDExiDnUXHUwMDEwXHUwMDBmk5FJJ1B3lJZYO/aLXHUwMDExZrfMgiBOW3ZcdTAwMDXS0U2zqHz7I5v4tOlTu1JqiKnOvsM3SLtEzIBcdTAwMDegXHUwMDBiXG46Slx1MDAxM3Nwp9/zUKAg3D1jOdtcdTAwMTic9r30XHUwMDAzW7zL41x1MDAxZHLa2SdDWNSbxdtLicPjXHUwMDE1XHUwMDFkXHUwMDA1ZFx1MDAwNqNcdTAwMTlcbrZbP8FtNsawXHKZXVORil715c5RgN3kXkehXHUwMDAyXHUwMDA0J2Fcclx1MDAwZWNQxMq3XHUwMDE2q9RJ+fCyQlx1MDAxOc6oZLOqlzFLrfPEgVrRNlx1MDAwMLQsii2h03Va3Fx0RKnEycn2WETkqGE3XHUwMDEzXHUwMDAzXHUwMDBm7pXSvkU746SlaVxue1csKukswKHsIJS3WkGlxrCFwO13NI4hXHUwMDBiUthcdTAwMDXe0KFcdTAwMWa3Tlx1MDAxNOZcdTAwMTV26sQ0qbNcdTAwMTVa30FcdTAwMDbEODmmkXv9ScvMl1x1MDAxZM9mXHUwMDE1xs2/bEpcdJfvKE2r5CG/xJ7ysuZvQu7Cq1MnMZFcdTAwMWPTv0qOflxi9LB4VjyGO1Y6XfJcdTAwMDIm7s1folx1MDAwZn1cZmuZoFx1MDAxMsxcdTAwMGbr1YD1juvvhjm1xmj6evBcZqtAuO4jnmlUhWHKj2ArWHL6IyWa8Le24Fx1MDAxZXItXHUwMDEyOlDA7dwtdHm7N77xzVx1MDAxZCrKp0+kuvgwZN9MbF4wsd25X9KVXHUwMDAxqlx1MDAwM9LW1vwp3NLUtP9JK8Sv5iGG1Wiv+slcdTAwMTbWe0eR0PZtaHtiRdOBSN33XHUwMDFkPYhQXHUwMDBmgVxi3k+7THeU21x1MDAxZMj5uJ9cdTAwMGJcdTAwMWE4e1A+zeotb9eyfPlcdTAwMWGyUZSFXHUwMDBm7VVcdTAwMDVcdTAwMDBcdTAwMDRcdTAwMWbQ5ypDWCtcdTAwMWWfkuNcdTAwMTPG01/PZihYdPxQsKyDRKk1W0iKzZXb7ZTvaJvZUVS+mYbwXHUwMDFlmJxbYlxur4JwytM/MsFcZi0xPcazhuZnfVxc5p42xl13NXpR76vpi1Sv0qzMUu1lfuBcdTAwMGZcdTAwMGaJgN460DuBlV/IXHUwMDBm5ZBagU5cdDN+VZeeWYdfmlx1MDAwYlebKFSnzI5cdTAwMWOJiHnS6DxcYpY3a1FV0LaJl2WCUlLfoohYujpLSkbNmPX+Q69aJnQ6Wlx1MDAxMk2SXHUwMDBlXHUwMDA0z4xcdTAwMTnzS+2LQVx1MDAxY+wnXFxHXHUwMDA3Slx1MDAxNtyW0ep57defIahcdTAwMGKQUCpcdTAwMDBcdTAwMDFcdTAwMGbgZ/PkoVx1MDAwYkm+gnCsmT1cdTAwMTfFeqzlyFx1MDAwNjVhMU5fgnB2dNOFPvt7jryA51T37vFr7t4puLO6jVx1MDAxOFwiwMi14UhnxUGV8b7lVnJ6b7ai629cdTAwMWFTpFx1MDAxYYtuqLotYE/0R4v5XHUwMDA1qCwwSZ9cdTAwMTiEMlx1MDAxZubwJNuNP1x1MDAwMFx0XHUwMDBiNVx1MDAwYllOpyBcdTAwMGZ4yFFZZVNCuN9DON1cdTAwMTbXXHUwMDA0tJDbXz9KoehcdTAwMWKq1lx1MDAxOX6mhidcdTAwMWOrdEOsdFxijmmiOp9v/ig14mG29VxcxVB3bbhcdTAwMTRQz+/wIPJcdTAwMDD1Q4JBuVt3WfrdXHUwMDA2XHUwMDAz3kQ7XHUwMDAw9+835rWn/tKXwW4l05tcdTAwMThjXHUwMDE4oFx1MDAwN8p8Wjn77kGX3lx1MDAxMu7H0VwiTNKY+GlOxJNIXHUwMDFjXHUwMDE36Vx1MDAxNtWaXHUwMDBi9cnGsuH1oOZcdTAwMThcdTAwMDGQXHUwMDEwXHUwMDA1nztcdTAwMDC1L0XRvNamvPtV2MeGXTL9cthcdTAwMWW4+jSsYUOlOVx1MDAwM5Jw+MSs/PksulTvqcddSiNcdTAwMTNcdFCxXHUwMDBil+E+q3TRfMi8zsLKrlx1MDAwMlAhl69Z001cdTAwMTDYu7A0ybVcdTAwMWYwoXHyXHUwMDFigWBcdTAwMTVWgI6cTXVcYlx1MDAxN1x1MDAxNGh3N/X+JMlyJNngSXE5d/Se+Fx1MDAwYk/p0ENG8tdsxoyEXHUwMDAyVFHCXHUwMDBiXGLPb7vXmmxcdTAwMTVcdTAwMDQnXGZvXHUwMDBiLt5fMYl85S86grxRXryGu42VqpV3MbxbwfhNRqxAXHUwMDEzN1wipr6nJXn3jpdDhVx1MDAwMpWJ0ngwQ5JF/JvylzH7LUhPOINkc1x1MDAwZvBSdVtFLOR4uL+7suTEcr3rdTz2XG6SLJCRSt6Ky1x1MDAwMFx1MDAwMFVKs5pcdTAwMDfiMoajOVxuiDFzfavlR1x1MDAxMyZOJobENf6ojFjnXHUwMDA3gW+uRGxyLS51PTLUQsfiO1x1MDAxZOZcdTAwMWFcdTAwMDLnXHUwMDFkaI1s7JZ80lx1MDAxNadcdTAwMTPazU/XqOlUkvJcdTAwMTK/TclJo9ZcdTAwMWGudjIjMCejVIFK+VTfk81an/OHqW0np2GjkJlARsb5plx1MDAwMN/v4XSGhGVcblNcXP7n9+nbrlx1MDAxNv2LlMmsSZJseKtDIFFN9HpRXG71XjTdk0y+fzKE8G5V9PsrXFxVvk1cdTAwMTJcdTAwMGWqcZY9wFRcdTAwMDQkjPBNVKl9XHUwMDA0emXlI0nf/uHIazqzc0bXI8RcdTAwMWHhjXVQXHUwMDEz1+JcdTAwMDNSXHUwMDA2z/Mv+4H8h1x1MDAwMXuNwUGbwFx1MDAxMpfjU35yQTeBfFx1MDAwMae37+9HLdpcblx1MDAxM6EgcJB4XHUwMDE5TtRcdTAwMTGqXHUwMDE4Qv6zfO6ZOlkkVjZmRrudr2x4XHUwMDE5zim7kjkwq1x1MDAxN6WPt50kSCvMxlx1MDAxNqVu0z/++bHmXHUwMDFl5L7Ak1x1MDAwMcMgUadcdTAwMWQ66fzOzsxcdTAwMTjUp6/AXHUwMDEzPfAky8jDUHC80PPONIpcdTAwMDZcdTAwMTAyZVx1MDAxOI6ZtqyQRKHxu1x1MDAxOUXvXHRnUoeYXHUwMDAwSc3M9LXgnfSHfSl9XHUwMDA3k1x1MDAxZbljJ+01yFx1MDAxM1PpW3BIi4azXHUwMDE2YIFKRjOKdGRLyz+MI1x1MDAwM9tSXHUwMDA2XHUwMDE1IXNmRvTFIDJoi1x1MDAwNnwo7PAuhVx00zg05Fx1MDAwN/2tNbBcdTAwMDZUwrQnXHUwMDFmPVlp0SirXHUwMDBm6ppYopi1XHUwMDAxitLKstq2vVx1MDAwNHdcdJp8jYftOFBK30232IDD75J4N+/F6HiwfO9ZmOFcdTAwMWZXXHUwMDA3XHUwMDAyh5Gnomx8+KRcdTAwMGVWNVvxL/SVjfxnl1x1MDAxMdSCXHUwMDA2dTiNjLiQvC8/ef7CfvaDJO6HQdTjKFx1MDAxZYRHVOWug3gnYLUs+uDFvlx1MDAwMDBcdTAwMDfmXGL0YFa4XHTCb9Kx5sWTyfTgXGJcclJKze21TOHuOjYjjJrhXHUwMDFj6kggQqN3JrnYh5lcdTAwMTeSluC+Yky72W8/r2ZcdTAwMTBcdTAwMTGQ6C+mecSxujg8vENcdTAwMWWLtUFH/Fx1MDAxMVx1MDAxZUjjOFx1MDAwN9pcdTAwMTSQUVJLj1x1MDAxOFx1MDAwZkVkwucrsNOpjU2/ynzbubjsvXm3L12871x1MDAxMvc9rF90QJPrT/L2YtpJwbqwtSDyhD9nyapcXG73UJPF3Js+c6l78yhcclIvpvZGXHUwMDFhXHUwMDFmMIS4JVxmMSn3M1OaPI22V47aXHUwMDExjCZLXHUwMDFkeeA20PnpOUszdVx1MDAxOKdcdTAwMDZcdTAwMTfNW1x1MDAxZEHoUTCusbSDuFx1MDAwNieI4nbW1E5cXENl1W7XU+G5nohrXGIk/IbeNzzE6uzk27C0yiZY6bfvIFxyXHUwMDAw9qDrXHItQeZDTbJpcKGGkXVXeSBcdTAwMDFW4P1cdTAwMDMt7broSM36XHUwMDA2skF9bzpIY7FcdTAwMDSvnWD1XG6J+rJ4X61vXHUwMDE1P4Qks5u/cD2m35G3MFx1MDAwYlx1MDAxMutPZlx1MDAxYXPLpFx1MDAxN04tLY9cdTAwMTd3w5Yz+aN4wZzAclx1MDAwYueBmZ5KSkOoaM2wXHUwMDA2s8DOmSxcdTAwMGXxqSP3gKH5XHUwMDBiqtPXNZJ+24eMx8soXHUwMDAxaeNcdTAwMWGhilx1MDAwNFanpqb6nSakttqQ/GGORpGwMj++dfqknJEmXHUwMDA15Fx1MDAxNJLhW0/dsdVBqW28yt/JXFyT3ttuXHUwMDBi9XZvP3RcdTAwMWLRxPMqik4xoELniFx1MDAwMe1mejuq99ljgJKZsUVf2EkvvYU163SByS9hJNRG6flDfPKYXHUwMDFkfFx1MDAxMzJcdTAwMWOVhL/Xvcy4/iZcdTAwMWJcdTAwMWUsXYVF6JfiXHUwMDBlyGNcdTAwMDd6Zs/hXcAwXHUwMDFlrtBcdTAwMDOSqzp/Zdhix2A4I8FXgbxcdTAwMDGAcNtcdTAwMDDBtndPx+uvuvcoy37ZXGJcdTAwMWIzXHUwMDBiOFx1MDAwNYTDOFBcdTAwMTG8Oi8oKddhutiKa9xBXHUwMDFj7NCbXHUwMDFjjkNV593eJvuw9Vx1MDAxYqG2aVxcmVtcdTAwMTds0PCjhSagXtShL/bwZZZThW6QkaZcZmvPd72at7KLyPdcdTAwMDdQv2NcdTAwMTC9O+BzvOFxOzaTRnFjnFx1MDAxMLg7O/dcdTAwMTNcdTAwMTZhbWizMz+0W8lXblxmxIm/Oe06JoNBXHUwMDFmlFx1MDAxY1x0Xqk05ztB7vVcdTAwMDVZXHUwMDE4/Hhaw/RapdnFXHUwMDEwe+TefbfarS70mnRcbjKAXHUwMDA0KYe54iZcdTAwMTk6bVx1MDAxNERcdTAwMTDRuFx1MDAwMbA6aD7aIIxXwlx1MDAwMYhcdTAwMGJGJjmVo0ky57PntjR8+ZHYrt9VWHw1diU8XHJ/WlxiXHUwMDE1XHUwMDFknVx1MDAxN7pcIs1cdTAwMWLnXHUwMDA12PmaMj+Hf1x1MDAxNOxE+5Mx1Fx1MDAxMzTOdveN59hcdTAwMDD/xUPt28d5TGNcblx1MDAxN4hul8Tj4SmewptcdTAwMDXiZs7d+ClcdTAwMWIkXFzpbFx1MDAwNt2vu/hquWdScSSA1JHdc9QkwGpcdTAwMTeJun1uMlabz1xixVuXXHUwMDEy8Ef7gFe6vb6b0ZPDZM2GZ/I0XHUwMDA3tr26XHUwMDA3suN8UfIp0XuHkq3ReXdjXHUwMDEz3zmqXHUwMDA2ZVx1MDAxMttcdTAwMTH2MsdxSLjqtYhOwvFcdTAwMGJu3n7W1KhTtrlmwWiwvzWByedLkOPbXHUwMDFmXHLbfVx1MDAxZsBcdTAwMTHDqFPcyHWMfLTrZabMOVxmd8FcdTAwMTOPblxiXcxMxdSMLFx1MDAxN/C0vHc1ZdTtv09MjS2ur0cm21x0hj2GmJisTjuZkbVT8XKNitZUmPsvs01J+q4k5JSEdqdcIt64ZvNzb/ZtvlY8Ppx0aHQr7iWJXHUwMDEwrElZlNmoI2E0gFxy40yDkMpd1Vx1MDAxNdPJXuBBk+KOVo3jqiBJ06dCj/2HnXlWI1x1MDAxNosgJqvy7udcdTAwMDGqXHUwMDFmatDNOlQ1+sM8ICloYFx1MDAxZfL80De1XHUwMDExTyaWunWQx8RcdTAwMTG2T1x1MDAxZjlrXHUwMDEziumspZ57kiNcdTAwMDOrXHUwMDA2w/dcdTAwMGLhiF43ztT6XHUwMDE1aX1cdTAwMGLXn08rXHUwMDBldlx1MDAxYsx7VXNzkMqJla28WpLUXG6A241t805cbnWs2qksL9p/eIIhXHKcnoVbYVPs61x1MDAxNZ+PxS1pKL77sflcZlNcdTAwMDDQLdGLXHUwMDBmvPDjJLH9fLi9tFx1MDAwNoL+y3malNDzIYtnXG7j4lx1MDAwNGwkL1R25cHzjlx1MDAwNCwmXHUwMDAwU8dcdTAwMDfceLdcIoTemIZTuFx1MDAxNHfnd9ZaSeXBp1xmrTrNuFWjqVx1MDAxZLizyTiesPqWPejGX5svkUzNdVx1MDAxMf/+XHUwMDFkXHUwMDFhlVx1MDAxYp5zXHUwMDEwy8eSXHUwMDEw3tJFmaOZkzcjMpC05kk8XG7D5TP3XHUwMDExXerGXHUwMDE161x1MDAxMG070eWxtu+GL1krWbShhoQ7bXzA6kiFzL8q/i7TldfyN+FaZVx1MDAxNfjRPkhcdTAwMDF7rd1cdTAwMDRcdTAwMTDNPe4r74HTokqaIV6iZFx1MDAwMFxm3VxulyHBK3xyWYbXPNT7S/7VLa/OSPNFYL/NkKWEJ7TdvFxyTzdYa4KbXHUwMDE1KzqntY5cdTAwMTZkS28kS5tcdTAwMTVqS91wsKn45uNcYsCmLvRfxWuCz1lodpC62Jcr+EZ+amNGNthcdTAwMGIhi9idMzXmwFx1MDAxOZfkyTX2QXX4i8fxhKdA6aMp5OiJXHUwMDFhdWm1knXrKWu9LFx1MDAxNIR87pGsyk1nNJLJhqeMLcpRYJi0WN15MVx1MDAwN6So86Fq2/1sssNyX94lbWdcdTAwMGZ1+1x1MDAxYjdcdTAwMGWCXHUwMDE5XHUwMDA2XHUwMDE57FdcdTAwMGWa2lwicl7xq6+14lx1MDAxOUhvr0pkzHjTREchZflSfGCNkHjrz1x1MDAxOW72XppcdTAwMTFF97jJ0lh1cb9cdTAwMGVqrEQ10fnybcOuXHUwMDE1JFnn3uVcXHe6j7ysJFx1MDAwNysuzGmXaeeX31fThidbXHUwMDE5clNcdTAwMDY1XHUwMDE0wZtcdTAwMTUgQ7yCXHKo4LrFpqhcdTAwMDVCryGKuCOzXHJcdTAwMTTSpzCUbNMq3Fx1MDAwM9zOLLPJN5AhLZC2ZEc28TWrvJffWom+XHSQudztXHUwMDA1WoBSXHUwMDE1v/TIdOL3hSeredPSXHUwMDFkLq2Zvlx1MDAxMKvRPOrIYlx1MDAxYqV4XHUwMDE4ZnizoDcuXHUwMDAwb8lKzDFlvMOMPJXNzpRg4yuVbOrHu+rivP5cdTAwMTOfriF/XHUwMDFk3Fx1MDAxZF2AfXXEXHUwMDAzfpUz31LR+PNcdTAwMThLv6K5XHUwMDA2rdmfYMbx/fBcdTAwMDJdqVxyzzOIebxvvufTXHUwMDE58ckgf/vh0zul0yp628VcdTAwMTRhk5r9XHSxaDLZ99W7XHUwMDBmrGlcdTAwMTE4XHUwMDEyjGf6XFxaKvfLn7fZVmlcdTAwMTlcZkpcdTAwMWLFat3UZLB4XHUwMDEwj1x0IMWG1thccsJ/J7zHXHUwMDBizOd/qv3oXHUwMDE3dTlhPGlccnan+Vx0xJefpOBP7HhUoPGjqNVMOV3VZfw00Lhcblx1MDAwNPPHo1x1MDAwZe9AV/FcdTAwMWTs9fpQjVxiQjWDKmFcdTAwMTh1mlgkpFx1MDAxMHtcdTAwMTZcdTAwMGJGd8JcdTAwMDSQveO6/c5cYkRStlx1MDAxNTskeVx1MDAwM+l/XFyNxlx1MDAxN4YzxdlbXHUwMDBl99m1XHUwMDExs/2GsFx1MDAxNVx1MDAxZlZ+09pLklx1MDAxZvR3NlPNQFxy4Vx1MDAxZdbNXHUwMDBlwyfS8eNcdTAwMGLkXHUwMDFi+kvLpnNg139n4zt5XHUwMDA3N/2AdV9DTyvfOGXg44bZYv1cZnIrXHUwMDFjlLD4Qj4oXHUwMDFiXHUwMDBio2SDvJWY744mXHUwMDE0heBWzIPD7e+Clb6RQlx1MDAxN3m3xGXnpyz7QWVcdTAwMGWxXc2JzNbsXHT/3viqVKI+u5WVJpGkgInTlvztc7Nd0bNcdTAwMDFLV1x1MDAwN7dedfS9ky3mXHUwMDFkbsWeU7XuXHUwMDE481x1MDAwMt8tcVx1MDAxNlOM5k14YFx1MDAxNFtvkmybWLk2pbfirZOGX1x1MDAxNlwizT9nzYNka1x1MDAxN/uxTVZmrVwigtai/7zmjXl+232kXHUwMDE39atcdTAwMThy1aQ6XHUwMDAyyFxmXHUwMDE06DJ4zsWWelxyXHUwMDE3tH77PffRJOxSXHUwMDBm2NvW9T8uSNpa07b9wFx1MDAxZZT5QEUnv75yI7ctIWyWRoTP5p8zSrnLwIXn+LXUmahcdTAwMTng6lx1MDAxZoK1eVjGrOjRjIuwjWC1RNrdxt6UJ6W1ZqPDm4tcdTAwMWTFc5Tyc/5cdTAwMDA1tjhcdTAwMWT9XHR/vqf0J+ar1T2mPEMvmPOGZYL2Ovm9MXRKhcJcdTAwMGIoTL23l4DpXCKAzeZzrHDPuJlGrFx1MDAxNsqMkOe8xXljhUXZXsM0/fnrrbxk2jziXpvatph7oZUp2Lh1XHUwMDE21edcYkA8aKzo1Xfo5PgxXHUwMDA1XHUwMDEzXHUwMDE1t/xQ4/htXHUwMDAw6PNQopRhz2hcdTAwMDafWrTGKCVKTbHd0u+LcsNcZlx1MDAxMO2iN+OaXHUwMDEzXHUwMDBmoYynQFx1MDAxZDtcdTAwMGKlv0FcdTAwMWL68Fx1MDAxMIaA6DyeXHUwMDFhXGKd4ybzXHUwMDExLvudxETd9Xqee5d9cJc5L/Jh7336k9SSs4N2y1wiXFzr95LJx591vlx1MDAwMYnXfPWcOaGTXHUwMDA1SJfTWEdtm06xcXv+bmPXXHUwMDAyjNiIbrg4f1x1MDAxMJDAbXFDSKtcdTAwMDJ2mXHvZlx1MDAxOCZp3ttE8eJbwHuYMk7gpu7RXHUwMDE3yee5nXSqq29zzulcdTAwMWTW3zONjEzI/Fx1MDAxZXy7pWNaibv3VreE43CH4ed0P1x1MDAwM2QkxqozuFx1MDAwNlxix+iBaXNa+lx1MDAwNn85XHUwMDFlz8BcdTAwMTeJq9NhjvPHtLjI+sHl8oqlTf65gz5cdTAwMDdNYI8+v/J5/5YkXHUwMDBldntwvSiS3PCT+KrfbHyTXHUwMDEyX8K6OcOMtGntvDBcdTAwMTC1c3gqTaO88nGnn3qjXHUwMDFlQqTx/uI7l9m/XHUwMDE42tbB461vL85+VoGKeyVcdTAwMDQzT1x1MDAxYVxmPFx1MDAxMu92+lx1MDAwYqxpXHLgTvH9/F6f/saxjVNv1sC9XFw5SVx1MDAxOEDd8nZu0954oo6FosDuu3pHxEhcdTAwMGWWYSdA2jU00KH60o7Dglx1MDAxMaAsJVx0aj+eXFzeay8rzHOgbLdcdTAwMDVRMI7hXHUwMDAzrcFcdTAwMTBD669cdTAwMWY8b3r3Tto3vfPNffhje2k7pTlDc7VcdTAwMGZpXHUwMDE1w8PAb+CI5lx1MDAxNlx0lcdkr7mYsSpRIOEzXHUwMDBijfaW2yUzSsdyYFxih4I/ndnjXHUwMDFmXHRcdTAwMDO07l0ux7BcdTAwMTBQVu1cdTAwMWFW9mjS30bZQIOf1tn3zGKjXG5harA+VUaBXHUwMDFkjFwihVpcdTAwMTn3cVx1MDAxOFx1MDAwYlx1MDAxM2g/nOu3KIAjTft5lXLVUNbx56w+VP9x2Vx1MDAxN3VcdTAwMDaX7FhcdTAwMDMp0thIxvZcdTAwMTZaflx1MDAwNXxXYS7MwVx1MDAxN0pcdTAwMDclxHt63LO66aqVpf5RhKAyMPEg+o/1VNDCXHUwMDA0XCLCXHKNXkJ+dUGcXHUwMDAw34qcXHUwMDEwVYvpMj9cdTAwMTnTNmBcdTAwMTROzVx1MDAwZtOGxfxwakjtqNpA9Zsg1EPGO8evt3uGXHUwMDA25VmPXHSWSlx1MDAwYlJEl9NcdTAwMDJwfmneTWp7XHUwMDEx20l2YTts5kXx1bBMg/I4XHUwMDEztzzVXHUwMDE0ZLiUkL6PXFx87ZRN1OB4XHUwMDAxSrC2uoNcdTAwMDbx2nXWUpExkzXDmcT83SmB47GS6dVcdTAwMTh169NCwMjNX27ZNvWvKqWCwmPqYIrlTlJcdTAwMDZNwbj62FOKJrX60HjJu7lKXHUwMDBl8tbDYlV8YWqj5VdKyLJ2ulx1MDAwZvAssVx1MDAxNFx1MDAxN/U7KeyTJKbkJvTKSGdcdTAwMWNX5aHgNeGgXjNRmMVcdTAwMTB6XHUwMDEyjSzjY/YoXHUwMDE2326ausByW0RcdNyEZ++0ZpxZvVx1MDAwNVx1MDAwZXmoT7Fcco6hsGc2YFbfRlNgXHUwMDEzXHUwMDFms1x1MDAxOYFzr7tcdTAwMGLEccvw6yNSXHUwMDEzXHUwMDFmNim+yCq3xdPhkPiN2LTnerZcdTAwMWTRvMtcdTAwMTS3psaiM0Wedy7P3LzNMIriJF38XHUwMDE0c8OjUWbY/r7D/IBly1x1MDAwMaYhctO0K59+XHUwMDE4eEJ62Fx1MDAwYkm5sY11rVPetLSGXGYuXHUwMDFhSJZ5PMqGxDUuXHSKIKHjO5qSWnnSR8e4XHUwMDAwMzaL+uPGvcjhujqQYXoqdHfF75rO1laGyVx1MDAxYr3cjVjfJdlcdTAwMTm3J4g/tm5IXHUwMDEwp5dcdTAwMTdNf/ZTMInee5XmXHUwMDE3UZk9fGKs31x1MDAwMGFcdTAwMTAnzmlVXHUwMDEwblx1MDAxNVx1MDAxODg5MIpojDuuUb9cdKzoeypCWKclXHUwMDBistUt9sBi3m5Yy/NxpfohX/aV8tHdXHUwMDE1w4V3sDPKe7mo0zqCX/z6XCJNXHUwMDFkXHUwMDEyQlx1MDAxY9g6RVDCoNfniL1cZn1U8oOxwlx1MDAwN2HlXG6excfvuqQo+LCuXHUwMDEzkodmXHUwMDBlhXdcIsi7baY33z1r1O7tRHSz+O9MwVx1MDAxZLWq9VxmSPB4cFx1MDAxY8ZcdOJcdTAwMDXBXCK+fyb1KWtrPVb8+EnFjt6UXHUwMDFmRaOrPi9cdTAwMWTFkvXqXHTU947Kq0fTJKp+ljKvZ1xm42pIhT54xKEvXHUwMDFkhFx1MDAxZl7+mEDlXHUwMDFhXHUwMDFjXHUwMDFmuutHqT+JXHUwMDFlttMmS9mkzr00YTuiY83Da9LF32j4msJcdTAwMGaezndTeL6nR0Ha1Fx1MDAxNfhcXFx1MDAxN6zvXHUwMDA3eN1cdTAwMWWxb1x1MDAxZlx1MDAxNvv1ppBcdTAwMDZkd2/f+9qBpT5j66b99XjZZJZGTDxcdTAwMDT+wuLdaHFNuWfYz84oc3l61nDacGNcItBcdTAwMTHGfCc6W17/d82eqH4z9Im8LWPU3Z/YXHUwMDEzXHUwMDEyqYrbeEJcdTAwMDS6KSQv4CCePNztXHTQclwiXHUwMDE4lVx1MDAwZTvXSFtO+ShcdTAwMWFkOFx1MDAxZnXqXHUwMDAxxMe/RoSePulcdTAwMWGDp63IKGt9nlx1MDAwNK7vmdFUaLGWuNtZpN2KN+VqnMjERNJds+NcdTAwMTFW0NN6plx1MDAxOM0+Vk31JpXFYNTwLIOg2lpcboeXhSuWKVx1MDAwNXSIXGZXqb1ccpDgJU7yvvuYY5dv8CWtirVcdTAwMTZcdTAwMTBUaXjtnVx1MDAxONrewCtcdTAwMWQzXHUwMDAwKd6cXHUwMDE3XCJ56+IgstRcIlx1MDAwMi2FOyTefvu/XHUwMDAwdjZfS1RcdTAwMTdRy+5qXzRPXHJqNKRbZ0vRU0fvzLjRXHUwMDEyVHbJmDXEXHUwMDA3YG70v1x1MDAxYkyh5Le2N8T9rO67Ybn8Ve1cdTAwMGYtXCJTJ1TA7ktcdPHahVx1MDAxN2W7nkF33n1GQkmO6ljFslxcplx0gSMkm2DiTFx1MDAxYlx1MDAxMJ8kqKxcdTAwMTFjx6yMT8m96ntcdTAwMTGJeOBcYtUnybzZ1lx1MDAxNNyEfSjkXHUwMDFmOem9pIWZQO5cdTAwMDVlYz4hiOxcdTAwMTRlXFwyXHUwMDFhbrdvJlvSy6CJU4olW47/dYmMhrKNyy576NPgzHo0jW5DVMVv9yGb2XtNXHUwMDE0Olx1MDAxYlxmfH9cdTAwMTJcdTAwMWT5XHUwMDE1lYZcdTAwMDSLWmKWPlx1MDAxMVx1MDAwMc1cdTAwMTeeXCJBtfpcdTAwMDZcdTAwMGVrLvVe29xrgn7h3aYvQFx1MDAxZEGIQEGxXCLSM1W1payJK1xu3GH0llx1MDAxNVx1MDAxMOxM3IU27Vx1MDAwYvtrSG5cdTAwMWFcdTAwMDJaqjlNP2TPevudnThcdGGuXHUwMDA0XHUwMDA0g/7m1q0jb1x1MDAxZqry2V+8PVx1MDAxMFheJ95Zalx1MDAxZaRcdTAwMDdcdTAwMGUhc4NdbVxi5Wf03ECo9/W5XHUwMDAw+DCfNVS5O/5cbumZWmZSleFcdTAwMWOWlMNGe8ZXVVx1MDAxOS14XHUwMDAw7zTnu/r8rmnMJUy9f7NcdTAwMWVVQ8tcdTAwMDJFrDJBk6RX4Gz7Z1x1MDAwNWHH+NE/51xmXHUwMDEwxb9cZjf5fFdJX31cYpCh81U42F6Rkys6XHUwMDE15YZxXHUwMDBlxGvEzzImXHUwMDFmXe+/7jJcdTAwMWLzUGJmTVx1MDAxY8nverea+Fx1MDAwMoBcdTAwMTNcdTAwMWIh7kpjzLbjQHxWlFTy33tRnnKOK++anK9eu1wiXHUwMDFkJL90q+PMXHUwMDA3l4vctk6tl+JN8XJccnDufS8z19pcZiEyQ29cdTAwMDKXXHUwMDFiXHUwMDA1z1x1MDAxNu1Z+7VfX4qFvP7w2oInReDDNzlSJfO28KNRjVWBszxx/FxcZLYv+3h02MWakr50XHUwMDA2op8xikl0MfFOd2adZ5jVJXLmo0F02SBcdTAwMDJcdTAwMWJcdTAwMDd6zlrEcllH85bKNo7a46dcdTAwMWHY8IDPxPC+oFx1MDAwYrVKMVx1MDAxOSaZjTq6JO9mQF4xrdqRstFcdTAwMDdg4mqLnSPsl62plHqJxl1G2HI9d3xifpfS6+BPc9ZMus1muX9Njb+vLOrzOVCNVHP8dI03ZFx1MDAxM/RcdTAwMTgljKd34TZybn8lWoCb4lx1MDAwMz21XHUwMDEzsJC5us1cYmKQXFxjynstXHUwMDEwxnNJ9o72bUpccqNcdTAwMTRC5WRiPZslwzAhUnu5XHUwMDFmrSE9/k2L5pyA+yj2XHUwMDA3dqzOXHUwMDExmDdDQM1Oo+VVcodcdTAwMDNAzq/QbtBcdTAwMDVcdTAwMWN8RUfU81x1MDAxMJZcdTAwMGXLqdqjsLGC7i/OXHUwMDFkPmLbVNj2MUV+XHUwMDEyo1xiqm67J1x1MDAwN5xcdFvNQ6Sm1Vx1MDAwYnc2SVx1MDAxMbkrqVx1MDAwMlx1MDAxMyih8PRcdTAwMTNcdFe6KJ44TL5cdTAwMWRcIl1cdTAwMWMt6OMvMPp3V57ZIfSQkVx1MDAwNaItXCKzXHUwMDA0PVx1MDAxYn6vpiagsDWs2lxcIbbjl4RYoHNymG/w3dBcdTAwMGIwgOmDu1/O4nncO+xRp7tg7mtRYr4+0VHKQ5yzxCyPXG6iXHUwMDE4v8A1g+o9xUfUYJC1z8+4uVVcdTAwMDeslPamNmgktCCIL+WbSiglQWSQnoDDXHUwMDAz6q9cdTAwMWNkUIOvsqxmhFx1MDAwNK68rCe5c1x1MDAxOKNSsnJcdTAwMTHuY7A3bYUxZpItUst6XHUwMDFjyVxiypOBR8a/JVx1MDAxZd2DXHUwMDExpPdcdTAwMWXH5nDeR/gq1NU8rIftXHUwMDE4+rXFfeGLXHInXHUwMDBmpn+rXHUwMDE2xl0h+Vx1MDAwNcRcdTAwMDD531wi8W/yY0fUXHUwMDA3yqCuMiVcdTAwMWGO/CyvXGauisOah6KYO/Z6L74tXHUwMDBln5emPKPckkP5kymT4amV45Xn1+hcdTAwMTZnV1xu2PDAPUCBhCFcdTAwMDVcdTAwMDVqmWB/jVx1MDAxYZxscbr0b0CDzbnYXHUwMDFmR0WPiFQuXHUwMDAxaFx1MDAxZo23XWTsXHUwMDBmgVghk1x1MDAxN71cdTAwMDFcdTAwMWb23lx1MDAxNEFUxI91MHI7XHUwMDE30HeUdNTX94ddXHUwMDAxSN6wQWRKo02eWDOpXHUwMDFkbFx1MDAxNP9JIFx1MDAxMTaViGFcdTAwMDCGjMBcdTAwMDTwTVtcdTAwMGInv5fGXG7t+Vx1MDAwN1xi/DmPRoT50ePzvlx1MDAwMahe71x1MDAxYZKectvLicxcdTAwMDTALfl1/4ifbS/8X1xcl7EgML/PeVxcz6h1bOKXI1x1MDAxYp7WzORhW35QuFKo4LDPbPtus6NwZb5bNtWt5OuVyLO+ue/8rKQk1r7+PfaA0Myaf75cdTAwMDZcIsaI6NI5rbSxcF7AW1x1MDAxOPyPU1x1MDAxODPHuHVzv11cdTAwMTKepILjqzUjXHUwMDBlj44wXHUwMDEx2vtovu1KqkDxM+RcdTAwMDawpM1eXFz151CiiFx1MDAxNS5Op/6vYPugi1lpMVxm4PA2+cVdXHUwMDFh5fdDXHUwMDA2wm6KXHUwMDBmn9X0yFx1MDAxZUmJy/lMi9WYT+ZcdNODb+h1IVmsvj3cXHUwMDE3NJuu90t14MjzkPI8rntcckegqKhcZvL+7vFo9HXBSKgnXHUwMDEzYEY+1eLmXHUwMDE3tz+X+FBDrit/52bfXHUwMDA1nrQ6XHUwMDE3l/2L7X+fRJeWLmVcdTAwMGJyumNcdTAwMDdlx1bTbrDQNl9OeZZgIaW34PhWMkVOXHUwMDEzy1rzXHUwMDAx0URcZsdeS65kh3uZVFwiXHUwMDFl7zdeRsDFXHUwMDExXvk0Td9cdTAwMDa9hVx1MDAxNtJcIlx1MDAwYmkgJE3mPHuS1IDr5jbLpnVB0TCGy/uVymK6qlx1MDAxOGd/XFy4Y7SJyUSTdLczlXn5Y1x1MDAxOERJfX3hScAy+lx1MDAwNVt577aVuotcYqyxXHUwMDAxXHUwMDAwzFx1MDAwMlxy23dcdTAwMTXSnbvAwFxywYeJeOGqeiZyMFx1MDAwNJ2btjNcdTAwMDQsv/w4XFxqgoyrpkJcdTAwMDBcdTAwMTjl897KZWE/MU9XKPajXHUwMDAzdYJcdTAwMWFcdTAwMGJcdTAwMWK8XHUwMDA12E6xKdWcfiflZdFBnn5cdTAwMWZsKbBcdTAwMTCuXGLUJIZM5utcZt5eXHUwMDAxxzHniOZcdTAwMGKbXHUwMDA3XHUwMDE5cN+psFD5wzBcZlxi/+feNk5lnohcdTAwMTOr6MnScbnQXHUwMDFkmjz1e/tcZndhyXlZXCJihu6Ql1x1MDAwNlx1MDAxNW9dlj+aXHUwMDE18Peq0Tgp06PTME/nqp35XHUwMDE5LzG8If2+XG5cdTAwMTYwXHUwMDBimdSu1mz975Q/mYKKQVx1MDAwNqlcdTAwMWb2idyLYeAw89wrSVx1MDAxNfWz3V9cdTAwMTSv7/NbdP7p6bZH4khcdTAwMDd3qVZcdTAwMTn1cFx1MDAxM35l+H5Bx1x1MDAxOa899/4khFx1MDAwMO9cdTAwMTNrkFx1MDAxMpGnmVx1MDAwNlx1MDAxYan291x1MDAwMNOqXHUwMDFiT1xu8GV4dKHXv5aaLbKi4WNOqpJD8+mCXHS1tc1cdTAwMDPVOGu1sEL543pPXHUwMDFkXHUwMDBlzzD8XHUwMDFkYD+DxYsyKLhtLPzu6eReXHUwMDAzM2BIkv5opHeYxET9uuzV4q3vwXj5pVa6XHTjqlx1MDAxNN9cdTAwMThcdTAwMDLLXHUwMDAxzLPY5VxuXHUwMDAysSxfMa7M6V+tvk3ih+hcdTAwMTDT3eHPQts7X/1sYOA+oo0si0VRXHUwMDA1Z1x1MDAwNTF+MY6cUV1CXHUwMDAxWnHvsk2B5Fxi5k130/GNXpFmmaNx8TRcdTAwMTBcdTAwMWEy/jjWSFx1MDAxNMmMd1x1MDAxYlx1MDAxYybxQ8RQPFx0PaJcdTAwMTdqcNHjL9ghXHUwMDAynqVcdTAwMTCXevL4OVK9PP54reSTsJOyOVx1MDAwMytcYiXA6ktcdTAwMGL2cvn1UkaRpKW5XHJcdTAwMWXoI01cdTAwMDFiM1x1MDAxOPdcdTAwMTd5P1x1MDAwMX+yRVx1MDAwNOvb2rFNXHUwMDAwz8JX8Vx1MDAxNDFfZFx1MDAwN89VXHUwMDFhXHUwMDAws01cdTAwMDVAXHUwMDBigFhcdTAwMTfCv5PkXYH4XHUwMDE4d1tj+q1cdTAwMTbh00o5bUJZ4vTQfTrtcp2LXG6LJD38tKymXHUwMDE3XHUwMDAzXGKnXHUwMDBi6L786sTvXG5MjutHv5e/J+U3miNcdTAwMDCqXHRUXCJ7aTl9RGKv8/0zXHUwMDEzi+duYyBg+Usk0W9cdTAwMDW+XCLgTdJuf3pwp6PoKsd8rFx1MDAxMiqcaEjqfsImXHUwMDFmcYJt85tFXHUwMDAzXHUwMDFmjOmD576LZcdRXHUwMDE2KNLgS1x1MDAxZZVcdTAwMTH3M8+PxjRWs8GHm1B7dFN3lr34jFx1MDAxYlxca8ZZ7aqOglx1MDAwNrNcdTAwMTk20I72uH9EMl1ccpHHdoVcdTAwMTlcdTAwMTiGMU8xh2QjerNZhvxcZt8rZVx1MDAwMJvONFx1MDAxNlRcdTAwMDTewFHnXHUwMDA1XHUwMDA2priXW72zmTLU0OD4irSg4XUngcAlMD0mQcxcdTAwMWSoblx1MDAwM7hEwbxcdTAwMTVH1UHjpmYxpNutsXVcdTAwMTXPXHUwMDEwXHUwMDEwhKFb/1x1MDAxOdsnfonsh0C5XHUwMDAykuWEQauOXHUwMDA0JFltcFx1MDAwN6Mg825cYlx1MDAxYVx1MDAwZi1/XdJ5bqc5dr2Q2aIvmV/6Ylx1MDAxYTmPXGJcIontcftjiqLv7Vx1MDAwZrZcdTAwMDCnvi/zyzQska5QKLKLU0yMofJBJz5gVlx1MDAxN1x0yytcdTAwMDSfdqBiL69MUtr6XHUwMDFk4S5cIlOTb3xARMZcYueHdmRf+mc88ulM4cs73lx1MDAwMHFDk1xm427yXHUwMDBipYZxWWRcYufy6ShcdTAwMDKsW/HZivkkXHUwMDE5QNKO7yTWut97pmJSO4Ml+Vx1MDAxOdNCld/N9rMlNFx1MDAwZVtCXHUwMDEx89tLITbm3ajBXHUwMDE4hy6ob91g/og1tT6SfWFWYK+v9jHZXHUwMDE0Xswjm2eKXHUwMDEyTERcIlx1MDAxYvte0Ue3TVx1MDAxZqE9fFxcXHUwMDAxivC/XHUwMDAyXHUwMDE4ZU6ALUxcdTAwMTVcbkna7JP5qDGuXHUwMDExxvSb6W1cdTAwMTBgXHUwMDEzv8yLs3vku7VcdTAwMTNTbDlcdTAwMThcdTAwMTFcdTAwMTOARcMwWS/6XHUwMDExsTjZ2stcbtqL4ts9zSFykd2jeNWh5cep+FxcgizztXJbZ+C4ut8pvMToRPo8knhcdTAwMDGZp1x1MDAxMIvYXHUwMDE2nexaLYGVIfm+2lx1MDAwZd/MNWZDXHUwMDFigG1ws4WnbS1Cbz6kXHUwMDEyWrpbjlx1MDAwMoI2NV5Nn9WopFx1MDAwYvHnTsUufHy+IDtSleZcdTAwMTJmi8OnM6VinoCGOGCcN5OtOeTvztWVXz5DuTfc+lx1MDAxMeZCo7K9XG6yKVx061x1MDAwZrJJruznxlx1MDAwNHeC0bWrXHUwMDBl/bC3LJ+pQO/t72ZcYsGEwGnzraw5mu6iT4dcdTAwMGYy9e9k/JIuszrXZsBcdTAwMGLjXHJ1P1x1MDAxNyeu512jaFx1MDAwNVCcVdkxXHUwMDA1sN9xyFZSc1x1MDAxMVx1MDAwM5/RXG4jvFdKoFx1MDAxNlxcz3NYXGby1Vx1MDAxYVx1MDAxY1x1MDAxZqJIfnJD1i00hPGk9jGVb2nShdDgbc1cdJ7LXHUwMDE1n+pykEKHYmdYxFx1MDAwNLwuQiU+7DtNTH1ivKmB6sjGXHUwMDE59VM8b4pUXHUwMDAzOJtcdTAwMDEnVKHq9YvERVx1MDAxYlx1MDAwMyzMMr9xMthffMSdXHUwMDA2b64z4j7esy7Jclx1MDAwNZLaXHUwMDEwXHUwMDAwLsx9tlx1MDAwMyxcdTAwMDMx2CP14dFb35tcdTAwMGVcdTAwMTmbqtD4XHUwMDE3fE7XhYtUkJCGXHUwMDFkLN7SUykn8+pwj6dcdTAwMDarqlx1MDAwM1x1MDAxYlx1MDAxMHC1tp9cdTAwMTPkjjVKXHUwMDE5bCpcdTAwMTEqwza4wT1VraCukFlcIutcdTAwMTZKzsf9yTHw+JOTVzJL4N5ncMfqs1x1MDAxYS/Pclxmn9IuMLZcdTAwMDWap+Dn2Vx1MDAwZT90f1x1MDAxNjGS2UHyQVxykMe3rIaFZj8gXHUwMDBlK4j6e4TfwFdcdTAwMTVcdTAwMWVPjmVLjVx1MDAwNkbGN7VcXHSB1elFc/LsQHvUqlCxX35DTH4l91x1MDAxYovbXHUwMDBmpiSVxTLaz4rmjDhcdTAwMTOaIL5cdTAwMWQuTFx1MDAwN+dLuKe4ozBcdTAwMDUrXHUwMDBiw55OXHUwMDExUGfDKbI0pVikPFHAxI86etbjbuboXHUwMDFmSlx1MDAxNz9jXHUwMDBifVxm74dlUJvVoFx1MDAxN6+sOVosv5rzi9Lixpv2jcAncPujXHUwMDAyRuFDLE5uR5BMXG5HhsNUMYzN9ItV71FpJzXe4sWRW1xc+M2RVWhmW1h18Vx1MDAxY7SsO/d8N+tw+Pv5XHUwMDFil6iy+PNteeS0qZipWlx1MDAxNlx1MDAwMMk1e4hcci6CpZm2nPGxrV3CXHUwMDFk6JIsYmjxs+fnYzCvXHUwMDE3XHUwMDFjOt/2dntcdOLPbyNcdTAwMDChxZgq8sB0Qmc0IOinkX8nUidTOn1cdTAwMDB2yCtcdTAwMGVBrTpk/W/4slcmOVx1MDAxODZLyb5FvryxK+fJjuZ/ejmU2J3KJ+FcborDXFwtOFx1MDAxZlSr8OdbXHUwMDE3VvFJIeCKXHTj79/2fVRcdTAwMDFccjGI/Vxy/ppcdTAwMThIeFRfmepcdTAwMDBcdTAwMWZpJcHKLlx1MDAxNIKkXVHgYo5ktCZE5tNfhlx1MDAxMsHRvXSYWkuRUuO3UOF6x5jbtLTs5Vx1MDAwNyFcdTAwMWXh5JY/6O6P9+OeWnejfbHimp+k8nxOfKLx+rhcdTAwMWJQ6kexXHUwMDBlXHUwMDA0mVx1MDAxN370Znm8hDLgyUdcdTAwMTK9r6DzcFeBbGOTOL2KzVx1MDAxMlVpa28llVhcdTAwMWFG5SjUvkpcdTAwMTiA+Fx1MDAxMk9cdTAwMDVaU1RcdTAwMWRcdTAwMTWEXHK5L1xcRfXTY5y0/JKWXHUwMDA09W3qXHRBXHUwMDAwuzGLc1x1MDAwND9cdTAwMTK5bFx1MDAxNdqKXHSHliPu32FcdTAwMDCHzWnAXHIsS81kJ9/2XZd1fa91it8vNVx1MDAwN41eXGKn5paGakcvXHUwMDE5wDAhLHW6skDN2MflXHUwMDE2XHUwMDFmPWXmrtvaXFw3gk383TfW1OVcdTAwMWRKXHUwMDBid7fNXHUwMDEykFxuXG4jmVx1MDAxZWVcdTAwMDfffqUh3tVugs7KrEc7g1i55aMoh/czZNs6PV04JMdQ1+ZZmnmWXCKO4kfhXHUwMDA1WVm2XHUwMDA3XHUwMDEzNWJ4Id3khEifpbFcdTAwMGXDV7WrjLXOujqWwkguXHUwMDAzPchFXHUwMDAxqYlEpF9QpuuabIfgOVx1MDAxMIuqQ+CFiptBXHUwMDExb1JdS4v3PcKAmj83XCJcdTAwMTGYPUpGO+FcdTAwMTeiOV2qUOtcdTAwMTaYXGaDtcJNpieIfI1HOYlP28pcYmtcdTAwMTfiwPT5+qOFqvTOfltcdTAwMDaxKX1cIlx1MDAxZksjlUTC1juV9Non6CBcdTAwMTAoXHUwMDE4gjucolx1MDAxMpjt8laE5q2x0MpcdTAwMDB5Km1+3Fx1MDAxYVx1MDAwZo1PnVx1MDAwNa1cdTAwMGYhXHUwMDA293tFdUj2i1x1MDAxMkz2xNiOylx1MDAwZa8j6bFkslgpPzzuvZqDJibYlVx1MDAxNVx1MDAwMIqFUHqCc1ulKFx1MDAwNTNcdTAwMGLsuFx1MDAxOCjD31x1MDAxM0yeujzEW2dcdTAwMDDT5r6Oh2dcdTAwMTXElexVf1x1MDAxMk9plVx1MDAwNVx1MDAwZd28VXxt4a64XHUwMDFiP7/1XHUwMDAzXpCGbcpcdTAwMDNcdTAwMTDH94BcdTAwMWSqq5VHvfhYa366UjR7n5AmfFx1MDAxNUe3XHUwMDFhNlwiuE84mH1cdTAwMWZcdTAwMTLhl/KfmFLsjj2dVDe8ZLb7b3lcdTAwMTL45Fx1MDAwNMB1ud+kQXWyXHSLnjBBU1VcdTAwMTTAndPw3HAwl+/32lx1MDAxMSdGs/tVM2WB5zSRyi/Udze7d1x1MDAxM/baMcm4YfeqrFx1MDAwYu+7V6pcdTAwMTTgLIREXHUwMDFiXHUwMDFm05BeLnjKvcpk4zCDZ1x1MDAxZrwkXHUwMDA1ZvGrX+l0XHUwMDA251hcdEFcdTAwMDSv24zLv25U8sSAloPbvo+AQopcdTAwMDN9t+nRL8mt6HwyWmRq2LnNUzWYYYTh7SDH+9Detlx1MDAxMjicco2IyGO65yGXv/uuPEKNkKhna4ZMh1x1MDAxZl6cZlJy7Mr/mrdWXHJcdTAwMDLiqs2wbqVahNaAsLdaXHUwMDFhKe7s/JVcbu5CXHUwMDEzr1x1MDAwMVx1MDAwMll7yu9vq/Z2Y5dMUrPPfcDRcJf4bImqLftsXHUwMDFkxpbxKeAjfHIuytdEqktUyZVUhlx1MDAxNTw/qyQwd/jLWINcdTAwMWMhXHUwMDFhZ1x1MDAxMOT+mlx0XHUwMDFiuTMj53rAM85XueJXXGLszUe+6Ha0vU+K8NY5ROdcdTAwMTnNvXYv7fVcdTAwMTJbI5e9XHUwMDA1hIU/rlx1MDAwZYJp11x1MDAwMvSvvsK1XHUwMDA0RpZuaFxmhVDVk9ooUYbAOlcwOW225MKln3rgOCpcdTAwMTkt+O9oQ0K5iMtcdTAwMWR2RqacuKT5Z7nBWj1OQlvtQDBcInbNXHUwMDFk3q8tf1JccmE+S15NTlx1MDAwYoXJRL5VXHUwMDBiRoLv7+9cZobJ7b37xM+7P1x1MDAwNCfGXHUwMDAz+dFcdTAwMDK5rtR0XHUwMDBmXHUwMDBm7ilcdTAwMWL3XHUwMDExXHUwMDEwLW+srt5FIa/PTTvvSH3jXHUwMDFkM+c7U1Gb+SzXXHUwMDE3XHUwMDA3PFx1MDAxMT/HU+0jklx1MDAwNvKjtKrvrzpcdTAwMGVJjOVEeaLVNkzAtDyC21x1MDAxN+3nepCZscZprE4hmVx1MDAxN1x1MDAwNs/KXHUwMDAxOMApU9Kt+FuAtVxmV0zbYVx1MDAwN/5o4OVk2/LPxV5cdTAwMTlQM21cdTAwMDM4L9nNwjWaXHUwMDE3afLfIUqd3lx1MDAxZk6yduYvsVx1MDAwZVlFovyXh8YvnUKyJGGdZr5z3EcjJJxrjE3GXHUwMDBmXHJcdTAwMDAgsGH+vGpyV8I8imvKioRd8pSVMJRcdTAwMGboXHUwMDFicY1gc+F3syb+tP1cdTAwMTnz/Vx1MDAwM7RcdFx1MDAxMWlcdTAwMDJcdTAwMWVUMljWbWZcdTAwMTRcdTAwMDesXHUwMDE3WImITplcdTAwMWROjSMpv1ewq/Hw58zuMdotQIHwjNqqaJiUY7sx342cXHUwMDE5hNCa4+joxG1cdTAwMDDgKIXt3Z5gmSWX+0xcdTAwMDFcdTAwMGaLmZCfXHUwMDA0vZC+RT/uxXOSq76sYVxueWq1iFxiXFxcdTAwMTHjXHUwMDE5WC35P5OUXHUwMDBiXHUwMDE1SIZt6fvN3NTvesk4dXiyq7BpWkjtJlx1MDAwZl7wi9Tx/kakXG5zIDskxof+XHUwMDE4l/cxcd/5e45P0JP088WuN++1WIbdwU15ku6/p+eO1qxcdTAwMDZcdTAwMTlL9UbixHvI8CE4T6tDmGW4OLNTyyUjd1x1MDAwZXL3sPwzazHYPNjwPJC6bvmlvu1VlItcZuy5ja3zIFwimXOIebbqqdP9xWdcdTAwMTe/v5Iyz2uzbKHcZ21cdFI5O1x1MDAxMt715yyFYH6LXHUwMDE1MaBAXHUwMDAwXHUwMDFlVneh2EOZkSdRb9s7Ulx1MDAxYVZcdTAwMTQmKb1U2GmpUNNig0OF96yXRbx8fdxlxSbfwu/zvFx1MDAxY1x1MDAxMVwi26tQVlVa7tzojuJcdTAwMTiqrt+fpo4tXG5iXHUwMDFiKJ09ryHRXHUwMDBms0O80I8vn32EgC+jq2msXHUwMDFhbo3QvJaz7pOCfd2hSa5cYs4qXGaJPVL/jGipN3XvsdfYXTD8rtVcdPSTXHUwMDFhjGHJ2Fxu5iMnO0E/3rmfQMV1U1x1MDAxYVZxad7njOnlXHUwMDBllFam9I8zJWt1PmFcdTAwMWNwZzOORZ12Y6PfXHUwMDA1RfPCgGHG2/+f2qtcdTAwMGbzOIBcZpvRIM02h81fPrCEK9F5rVx1MDAxNslcbv07t0NcdTAwMTFccqeIPFxy/jTtzWtcdTAwMTObs1x1MDAxM9JcdTAwMDBiXHUwMDFkV5eOy1qWbZbfRVx1MDAwMlx1MDAxOaFWWuuQXHUwMDE0kVx1MDAxM0RUvqdAJHWCXHUwMDFm/WBcYoBe4ar6dq9cdFx1MDAxMu9m2Fx1MDAxY304/XBp+cH+aVD0XHUwMDBi2chcXMNvhIaR5SBcdTAwMTazv+5cdTAwMWRcdTAwMWaTaiM4kfe10qmnkVx1MDAxNqmYV1WSUEv0PJPBpcbPoX9HzVx1MDAxZSbmUMLGNEd6XHUwMDE2j/I8/SBcdTAwMTRcciEpvKZcdTAwMTHuMMH0NYhG1JEmyOHQg7GPzLVcdTAwMDLpXHUwMDA1LM2AWlnwn/p5v/tS2J/ezr5fM9DaKlQ2YCnx05tfNZqCKVx1MDAxOVx1MDAxY1x1MDAxOFx1MDAxMst0geGoXHUwMDE5dYRBXHREhldh9o+fMJjqrC5cdTAwMWRcdTAwMDa3XHKfT7rX+FhcdTAwMTJYhlx1MDAwMVx1MDAxOTqk9VxmS5s1P1x1MDAwZoVcdTAwMTVWRFI7+Muym++SXHUwMDBmPtcmnfI4v5k0XHUwMDBlUZBZ0j2/XHUwMDAwwVx1MDAwMFx1MDAxM2lFOyOU0VBhXHUwMDAzc7NcdTAwMGaLvqNcdTAwMGWBXHUwMDAw835cIj41K1x0XHUwMDE4ct18rvCVRFx1MDAwM1x1MDAxZYVtJp6UWKI4OshVQilOVjc7Sf16/lx1MDAwMJOwybSVXWCENFx1MDAxYVx1MDAxYyBcdTAwMDR6SET7bN2VRD4t/lx1MDAxY1x1MDAwNlx1MDAwMsNOcCR9OuxcdTAwMThcdTAwMWFXXHUwMDE0dlx1MDAxMIbWoUB3VmnZXHUwMDE2f4+Fo1x1MDAxOa1w9ENcdTAwMDejr/eGliF4pY6IXHUwMDFhXHUwMDFmp1x1MDAxM+jZXHUwMDE4TKlcdTAwMTm/6uqQRIq2emhpNVx1MDAwZUmp0Vx1MDAxNLWd4vqB0nBqmeK8qlxi5++e7a9cbjBcdTAwMTdcdTAwMDFbXHRHc6hy58NcdTAwMTk+YGBcdTAwMGZG8Fx1MDAwM/OdR1x1MDAxM4s1XHUwMDBiyaJ74PRAV6d3nlx1MDAwNJ1jlerH/EZcdTAwMDRcdTAwMDSexZzsM1x1MDAxZkhcdTAwMDJQ/X/nKZAwQf/XXHUwMDEz0P+H81x1MDAxNP5cdTAwMWVcdTAwMWX8r3/+XHJwpc+3In0= + + + + + pgbackupBackup architecture for PostgresFull streaming architecturePostgres connectionsPostgres streaming connectionsPostgres connection(for management purposes)Streaming backup(pg_basebackup)WAL streaming(pg_receivewal) \ No newline at end of file diff --git a/docs/images/source/Barman-georedundancy.excalidraw b/docs/images/source/Barman-georedundancy.excalidraw new file mode 100644 index 000000000..42273df76 --- /dev/null +++ b/docs/images/source/Barman-georedundancy.excalidraw @@ -0,0 +1,861 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "1ZzBrWEHwMbkiSQ937jS_", + "type": "rectangle", + "x": 306, + "y": 332, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 2097703460, + "version": 271, + "versionNonce": 1873385244, + "isDeleted": false, + "boundElements": [ + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "FUELyXBPcB6gf1H-ELi3a", + "type": "rectangle", + "x": 310.5, + "y": 653.5, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": { + "type": 3 + }, + "seed": 1386606756, + "version": 289, + "versionNonce": 1489447196, + "isDeleted": false, + "boundElements": [ + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "M3tIxB_dvEzHw2rSimRjA", + "type": "rectangle", + "x": 775.5, + "y": 471.5, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a4", + "roundness": { + "type": 3 + }, + "seed": 575574172, + "version": 452, + "versionNonce": 832701604, + "isDeleted": false, + "boundElements": [], + "updated": 1732111953054, + "link": null, + "locked": false + }, + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow", + "x": 398, + "y": 537, + "width": 1, + "height": 116, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5", + "roundness": { + "type": 2 + }, + "seed": 521562268, + "version": 733, + "versionNonce": 518545188, + "isDeleted": false, + "boundElements": null, + "updated": 1732003917192, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -1, + 116 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": 0.027058455208193558, + "gap": 2, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": -0.10250905675566882, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "ZQBQiZKK1TTwKqd7MXAMm", + "type": "text", + "x": 362, + "y": 484, + "width": 69.90733388264974, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": null, + "seed": 1697128612, + "version": 269, + "versionNonce": 52295580, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "pg.us", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg.us", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4neJBFAF6jQ35NUlbGebi", + "type": "text", + "x": 343, + "y": 807, + "width": 130.3680005391439, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1977030308, + "version": 193, + "versionNonce": 650231964, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "backup.us", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup.us", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "xRxW2MEsNZBTEEF9w54Kp", + "type": "text", + "x": 812, + "y": 627, + "width": 129.51933415730795, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": null, + "seed": 1114292388, + "version": 360, + "versionNonce": 801230884, + "isDeleted": false, + "boundElements": null, + "updated": 1732111953054, + "link": null, + "locked": false, + "text": "backup.eu", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup.eu", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "g8P0muvVQ88DvKGMJmV0D", + "type": "rectangle", + "x": 224, + "y": 241, + "width": 352, + "height": 665, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": null, + "seed": 2126547484, + "version": 203, + "versionNonce": 1692644892, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "JzipOGwJBMd7KCUAwJ5Cq", + "type": "rectangle", + "x": 704, + "y": 241.5, + "width": 352, + "height": 665, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aD", + "roundness": null, + "seed": 918536100, + "version": 287, + "versionNonce": 1807651484, + "isDeleted": false, + "boundElements": [], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "IsaMmQeDvFf1HptU3Zk_U", + "type": "text", + "x": 333, + "y": 274, + "width": 107.99600067138672, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aE", + "roundness": null, + "seed": 785900964, + "version": 115, + "versionNonce": 2081021724, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "Zone US", + "fontSize": 28, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Zone US", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "6DNJt7rRwk_6KANudUf1B", + "type": "text", + "x": 809.2839997291564, + "y": 269.5, + "width": 108.22000071207682, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aF", + "roundness": null, + "seed": 395120548, + "version": 102, + "versionNonce": 1849138076, + "isDeleted": false, + "boundElements": [], + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "Zone EU", + "fontSize": 28, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Zone EU", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "SPCm1UV2vaWBMhVMDRUJU", + "type": "image", + "x": 363, + "y": 399, + "width": 71, + "height": 71, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": null, + "seed": 239434660, + "version": 172, + "versionNonce": 549141660, + "isDeleted": false, + "boundElements": null, + "updated": 1732005135927, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "1tSeOxu4bvvm1bBII4boa", + "type": "image", + "x": 354.03465346534654, + "y": 711.5, + "width": 86.46534653465345, + "height": 70.99999999999999, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 1149200548, + "version": 193, + "versionNonce": 1463063836, + "isDeleted": false, + "boundElements": null, + "updated": 1732005130777, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "_pL88yBL7Cg0sdPqNtjii", + "type": "image", + "x": 828.7673267326734, + "y": 529.5, + "width": 86.46534653465345, + "height": 70.99999999999999, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJ", + "roundness": null, + "seed": 137907100, + "version": 357, + "versionNonce": 2128358308, + "isDeleted": false, + "boundElements": [], + "updated": 1732111953054, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "SKIYhR2pT9ePU_N3-qjcA", + "type": "text", + "x": 242, + "y": 68.5, + "width": 802.070385105881, + "height": 73.60000000000001, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 450504476, + "version": 166, + "versionNonce": 1237256476, + "isDeleted": false, + "boundElements": null, + "updated": 1732004135233, + "link": null, + "locked": false, + "text": "Backup architecture for Postgres", + "fontSize": 54.518518518518505, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Backup architecture for Postgres", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "hVDj-LHqEF0t6Tl11s2LZ", + "type": "text", + "x": 417.16000162760423, + "y": 166.86240812442435, + "width": 436.56883239746094, + "height": 43.13759187557564, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 904209180, + "version": 296, + "versionNonce": 932824868, + "isDeleted": false, + "boundElements": null, + "updated": 1732112019733, + "link": null, + "locked": false, + "text": "Geographical redundancy", + "fontSize": 34.51007350046051, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Geographical redundancy", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4v7wWZXi74Bxw2oKBmYHL", + "type": "rectangle", + "x": 453, + "y": 490, + "width": 25, + "height": 26, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aN", + "roundness": null, + "seed": 593654428, + "version": 42, + "versionNonce": 1232728860, + "isDeleted": false, + "boundElements": [], + "updated": 1732005492256, + "link": null, + "locked": false + }, + { + "id": "pnSRfbQP1_xcrej7vbeAU", + "type": "rectangle", + "x": 459, + "y": 776.5, + "width": 24, + "height": 24, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 311884572, + "version": 271, + "versionNonce": 337097892, + "isDeleted": false, + "boundElements": [ + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow" + } + ], + "updated": 1732111970403, + "link": null, + "locked": false + }, + { + "id": "HVWyBw5ZL2mrk5NKxZdPD", + "type": "rectangle", + "x": 794, + "y": 586.5, + "width": 28.000000508626307, + "height": 30, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aQ", + "roundness": null, + "seed": 1695986340, + "version": 439, + "versionNonce": 1968565148, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "kiIgEl0TRepdDcaGK3BsJ" + }, + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow" + } + ], + "updated": 1732111976904, + "link": null, + "locked": false + }, + { + "id": "kiIgEl0TRepdDcaGK3BsJ", + "type": "text", + "x": 803.464000193278, + "y": 591.5, + "width": 9.072000122070312, + "height": 20, + "angle": 0, + "strokeColor": "#ffffff", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aR", + "roundness": null, + "seed": 1695047964, + "version": 311, + "versionNonce": 1800280092, + "isDeleted": false, + "boundElements": null, + "updated": 1732111976904, + "link": null, + "locked": false, + "text": "P", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HVWyBw5ZL2mrk5NKxZdPD", + "originalText": "P", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow", + "x": 486, + "y": 781.068579031491, + "width": 298, + "height": 166.34124755124208, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aa", + "roundness": { + "type": 2 + }, + "seed": 855780900, + "version": 690, + "versionNonce": 358956444, + "isDeleted": false, + "boundElements": null, + "updated": 1732111976939, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 298, + -166.34124755124208 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "pnSRfbQP1_xcrej7vbeAU", + "focus": 0.2343159486016629, + "gap": 3, + "fixedPoint": null + }, + "endBinding": { + "elementId": "HVWyBw5ZL2mrk5NKxZdPD", + "focus": 0.007419746029177493, + "gap": 10, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Y_js-51ZT9bwmvSsmHfq5", + "type": "rectangle", + "x": 545, + "y": 665, + "width": 184, + "height": 68, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "af", + "roundness": null, + "seed": 712697500, + "version": 872, + "versionNonce": 1428561692, + "isDeleted": false, + "boundElements": [], + "updated": 1732111991866, + "link": null, + "locked": false + }, + { + "id": "5lCmnovw00DqnDnYrqmxd", + "type": "text", + "x": 546.1497772839334, + "y": 675.5, + "width": 175.70044543213294, + "height": 49.290060413085406, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ag", + "roundness": null, + "seed": 1209774876, + "version": 975, + "versionNonce": 1506532252, + "isDeleted": false, + "boundElements": [], + "updated": 1732111991866, + "link": null, + "locked": false, + "text": "sync backup from\nUS to EU", + "fontSize": 19.716024165234163, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "sync backup from US to EU", + "autoResize": false, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "46592fa2e930e621fb84c5731ee38deba57530a4": { + "mimeType": "image/png", + "id": "46592fa2e930e621fb84c5731ee38deba57530a4", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAgAElEQVR4Xu2dCdxVU/fHl6kkkaKBSoUypMhbolRCM5FU0kATmkiJlAYlFYUylDSIilQqiaRRKCUJFUIqGkzNE17/9d33nvPse557n3vuyNvz/30++3Of594z7nXO3nut9VtrHSP/j1h74Azd4UJtFwVbEf3Mo+0Ubadan8fp3z9r2xFs262/N+vfC7X9FuvJY93+mFh3iGP7fLpPcW3FtP2lbZ+2/Z7GdwfjOLafXUrpRpWC50cAjhAQygFtP2n70fp0/uaaANd+nbaa2qppQ8DJwH/1ICu0va1trrbV2v5OxoHtYyRbwPmDHVFLP8trO1sbT7YfcMO/a1ur7ZNgW6Wf38Z44wikmbYrgo1rigd7dKe92s6KZ+c49tmp+7wTFPYM/fwjjmNk2iUZAj5dj9pBW31tl2k7NhkXZh1jt/7N042w39O2KMzNMxzW03aXNh6uZF9DyC3lypVLypQpY1rBggUlf/78puXLl8988vvvv/8uv/76q/z222/m02nr16+X1atXy3//y/McERv1lwe1TU+0LxMRMILtrq2jtpOzupDcuXNLsWLFzI3v379f9u3bZz5pf/wR84O6S8/1pjae8ne13axtoDamgLAoUaKEnH322XLaaacZIfCZN29eOXDggPzyyy/y888/m8+dO3fKxo0b5a+/mEkycN5550mdOnXkiiuukHLlykmpUqXkuON4puIDwl+8eLG89957smDBAvnqq68iHWiZ/tBN28fxnUkkHgGfpCfrra1zOMEWKlRIatasadoFF1xgOpanOhIQsCP0TZs2maf7008/NZ/r1q2TP//8M6t74+k4wbsBArn22mulatWqctVVV8lZZ/kfZRE65165cqV5KMuXLy88IKnE1q1bjaDHjx8vS5Ys8Z6Kefk1bT21bYr1OmIVcFE9wSxtl9on4m3o1KmT3HzzzeYJP+aYWA8b/rIPHTokn3/+uenwhQsXyty5c83bHwkItVu3blK7du1Y+yGu7f/799+yZ/8h2U3bd0h2Bf8+dOQPyZMrp5x68oly6kknyim5A43vonXNihUrZMiQITJz5kz5W49v4bD+/ZS2/tp8L0hjkQQr0ZnaCjonZajr2rWrdOnSRU49lcVpaoHA58+fL2+88YbMnj3bzGugVq1a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", + "created": 1731966018042, + "lastRetrieved": 1731966018042 + }, + "0833b30d1a4da2b737b05a0261e434640c53058b": { + "mimeType": "image/png", + "id": "0833b30d1a4da2b737b05a0261e434640c53058b", + "dataURL": "data:image/png;base64,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", + "created": 1731966716908, + "lastRetrieved": 1731966716908 + } + } +} \ No newline at end of file diff --git a/docs/images/source/Barman-georedundancy.svg b/docs/images/source/Barman-georedundancy.svg new file mode 100644 index 000000000..9567a8482 --- /dev/null +++ b/docs/images/source/Barman-georedundancy.svg @@ -0,0 +1,10 @@ + + + + + + + + Geographical redundancy \ No newline at end of file diff --git a/docs/images/source/Barman-multilocation-georedundancy.excalidraw b/docs/images/source/Barman-multilocation-georedundancy.excalidraw new file mode 100644 index 000000000..3767f3e2e --- /dev/null +++ b/docs/images/source/Barman-multilocation-georedundancy.excalidraw @@ -0,0 +1,1289 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "1ZzBrWEHwMbkiSQ937jS_", + "type": "rectangle", + "x": 306, + "y": 332, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 2097703460, + "version": 271, + "versionNonce": 1873385244, + "isDeleted": false, + "boundElements": [ + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "QgzKO5H4O5eVDZS7D7txx", + "type": "rectangle", + "x": 780.5, + "y": 328.5, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a2", + "roundness": { + "type": 3 + }, + "seed": 1657017124, + "version": 291, + "versionNonce": 629899292, + "isDeleted": false, + "boundElements": [ + { + "id": "7-zh4wXPFD1v_RqScVjux", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "FUELyXBPcB6gf1H-ELi3a", + "type": "rectangle", + "x": 310.5, + "y": 653.5, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": { + "type": 3 + }, + "seed": 1386606756, + "version": 289, + "versionNonce": 1489447196, + "isDeleted": false, + "boundElements": [ + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "M3tIxB_dvEzHw2rSimRjA", + "type": "rectangle", + "x": 779.5, + "y": 645.5, + "width": 191.00000000000003, + "height": 203, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a4", + "roundness": { + "type": 3 + }, + "seed": 575574172, + "version": 290, + "versionNonce": 1307349532, + "isDeleted": false, + "boundElements": [ + { + "id": "7-zh4wXPFD1v_RqScVjux", + "type": "arrow" + } + ], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "eShTLYK0Xtbcu84uAonMK", + "type": "arrow", + "x": 398, + "y": 537, + "width": 1, + "height": 116, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5", + "roundness": { + "type": 2 + }, + "seed": 521562268, + "version": 733, + "versionNonce": 518545188, + "isDeleted": false, + "boundElements": null, + "updated": 1732003917192, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -1, + 116 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": 0.027058455208193558, + "gap": 2, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": -0.10250905675566882, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "ZQBQiZKK1TTwKqd7MXAMm", + "type": "text", + "x": 362, + "y": 484, + "width": 69.90733388264974, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": null, + "seed": 1697128612, + "version": 269, + "versionNonce": 52295580, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "pg.us", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg.us", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "gblMpGvLSqeXoDr0ANuXx", + "type": "text", + "x": 835.0463330586751, + "y": 480.5, + "width": 69.0586675008138, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a7", + "roundness": null, + "seed": 853079452, + "version": 325, + "versionNonce": 473211932, + "isDeleted": false, + "boundElements": [], + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "pg.eu", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg.eu", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4neJBFAF6jQ35NUlbGebi", + "type": "text", + "x": 343, + "y": 807, + "width": 130.3680005391439, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1977030308, + "version": 193, + "versionNonce": 650231964, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "backup.us", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup.us", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "xRxW2MEsNZBTEEF9w54Kp", + "type": "text", + "x": 816, + "y": 801, + "width": 129.51933415730795, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": null, + "seed": 1114292388, + "version": 199, + "versionNonce": 175590684, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "backup.eu", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup.eu", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "7-zh4wXPFD1v_RqScVjux", + "type": "arrow", + "x": 875, + "y": 533, + "width": 1, + "height": 113, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aB", + "roundness": { + "type": 2 + }, + "seed": 179210276, + "version": 698, + "versionNonce": 1965942308, + "isDeleted": false, + "boundElements": null, + "updated": 1732003917193, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 1, + 113 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "QgzKO5H4O5eVDZS7D7txx", + "focus": 0.019829248141007984, + "gap": 1.5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "M3tIxB_dvEzHw2rSimRjA", + "focus": 0.019645643991554208, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "g8P0muvVQ88DvKGMJmV0D", + "type": "rectangle", + "x": 224, + "y": 241, + "width": 352, + "height": 665, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": null, + "seed": 2126547484, + "version": 203, + "versionNonce": 1692644892, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "JzipOGwJBMd7KCUAwJ5Cq", + "type": "rectangle", + "x": 704, + "y": 241.5, + "width": 352, + "height": 665, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aD", + "roundness": null, + "seed": 918536100, + "version": 287, + "versionNonce": 1807651484, + "isDeleted": false, + "boundElements": [], + "updated": 1732003916737, + "link": null, + "locked": false + }, + { + "id": "IsaMmQeDvFf1HptU3Zk_U", + "type": "text", + "x": 333, + "y": 274, + "width": 107.99600067138672, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aE", + "roundness": null, + "seed": 785900964, + "version": 115, + "versionNonce": 2081021724, + "isDeleted": false, + "boundElements": null, + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "Zone US", + "fontSize": 28, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Zone US", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "6DNJt7rRwk_6KANudUf1B", + "type": "text", + "x": 809.2839997291564, + "y": 269.5, + "width": 108.22000071207682, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aF", + "roundness": null, + "seed": 395120548, + "version": 102, + "versionNonce": 1849138076, + "isDeleted": false, + "boundElements": [], + "updated": 1732003916737, + "link": null, + "locked": false, + "text": "Zone EU", + "fontSize": 28, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Zone EU", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "SPCm1UV2vaWBMhVMDRUJU", + "type": "image", + "x": 363, + "y": 399, + "width": 71, + "height": 71, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": null, + "seed": 239434660, + "version": 172, + "versionNonce": 549141660, + "isDeleted": false, + "boundElements": null, + "updated": 1732005135927, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "d1UnRD4HLiiY1tEo_Ivdy", + "type": "image", + "x": 834.5, + "y": 393.5, + "width": 71, + "height": 71, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aH", + "roundness": null, + "seed": 182416668, + "version": 238, + "versionNonce": 947038108, + "isDeleted": false, + "boundElements": [], + "updated": 1732005140361, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "1tSeOxu4bvvm1bBII4boa", + "type": "image", + "x": 354.03465346534654, + "y": 711.5, + "width": 86.46534653465345, + "height": 70.99999999999999, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 1149200548, + "version": 193, + "versionNonce": 1463063836, + "isDeleted": false, + "boundElements": null, + "updated": 1732005130777, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "_pL88yBL7Cg0sdPqNtjii", + "type": "image", + "x": 832.7673267326734, + "y": 703.5, + "width": 86.46534653465345, + "height": 70.99999999999999, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJ", + "roundness": null, + "seed": 137907100, + "version": 196, + "versionNonce": 1075398308, + "isDeleted": false, + "boundElements": [], + "updated": 1732005144794, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "SKIYhR2pT9ePU_N3-qjcA", + "type": "text", + "x": 242, + "y": 68.5, + "width": 802.070385105881, + "height": 73.60000000000001, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 450504476, + "version": 166, + "versionNonce": 1237256476, + "isDeleted": false, + "boundElements": null, + "updated": 1732004135233, + "link": null, + "locked": false, + "text": "Backup architecture for Postgres", + "fontSize": 54.518518518518505, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Backup architecture for Postgres", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "hVDj-LHqEF0t6Tl11s2LZ", + "type": "text", + "x": 289.16000162760423, + "y": 162.86240812442435, + "width": 720.8084991455078, + "height": 43.13759187557564, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 904209180, + "version": 242, + "versionNonce": 273797404, + "isDeleted": false, + "boundElements": null, + "updated": 1732022581295, + "link": null, + "locked": false, + "text": "Multi-location geographical redundancy", + "fontSize": 34.51007350046051, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Multi-location geographical redundancy", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4v7wWZXi74Bxw2oKBmYHL", + "type": "rectangle", + "x": 453, + "y": 490, + "width": 25, + "height": 26, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aN", + "roundness": null, + "seed": 593654428, + "version": 42, + "versionNonce": 1232728860, + "isDeleted": false, + "boundElements": [], + "updated": 1732005492256, + "link": null, + "locked": false + }, + { + "id": "pnSRfbQP1_xcrej7vbeAU", + "type": "rectangle", + "x": 456, + "y": 677.5, + "width": 24, + "height": 24, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 311884572, + "version": 187, + "versionNonce": 501685276, + "isDeleted": false, + "boundElements": [ + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow" + } + ], + "updated": 1732005544398, + "link": null, + "locked": false + }, + { + "id": "HVWyBw5ZL2mrk5NKxZdPD", + "type": "rectangle", + "x": 795, + "y": 679.5, + "width": 28.000000508626307, + "height": 30, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aQ", + "roundness": null, + "seed": 1695986340, + "version": 212, + "versionNonce": 1393920284, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "kiIgEl0TRepdDcaGK3BsJ" + }, + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow" + } + ], + "updated": 1732005642630, + "link": null, + "locked": false + }, + { + "id": "kiIgEl0TRepdDcaGK3BsJ", + "type": "text", + "x": 804.464000193278, + "y": 684.5, + "width": 9.072000122070312, + "height": 20, + "angle": 0, + "strokeColor": "#ffffff", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aR", + "roundness": null, + "seed": 1695047964, + "version": 84, + "versionNonce": 2050885020, + "isDeleted": false, + "boundElements": null, + "updated": 1732005642630, + "link": null, + "locked": false, + "text": "P", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HVWyBw5ZL2mrk5NKxZdPD", + "originalText": "P", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "Ezor3NvHw2P4ns_quiYwe", + "type": "rectangle", + "x": 798, + "y": 478, + "width": 29.000000000000004, + "height": 30, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aT", + "roundness": null, + "seed": 1531331996, + "version": 51, + "versionNonce": 45002276, + "isDeleted": false, + "boundElements": [], + "updated": 1732005404397, + "link": null, + "locked": false + }, + { + "id": "aerNVtVqYzU6gkE4iu5rJ", + "type": "rectangle", + "x": 795.5, + "y": 766, + "width": 29.000000000000004, + "height": 30, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aV", + "roundness": null, + "seed": 242833180, + "version": 86, + "versionNonce": 109928476, + "isDeleted": false, + "boundElements": [ + { + "id": "I_B2rG6hpCm3k18BJzqvg", + "type": "arrow" + } + ], + "updated": 1732005569644, + "link": null, + "locked": false + }, + { + "id": "_KSMx5nwFNxUNAjxSR_kc", + "type": "rectangle", + "x": 455.5, + "y": 767, + "width": 29.000000000000004, + "height": 30, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aX", + "roundness": null, + "seed": 1035167132, + "version": 82, + "versionNonce": 181471516, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "S6xzSzyldnfXQrFmkKLIC" + }, + { + "id": "I_B2rG6hpCm3k18BJzqvg", + "type": "arrow" + } + ], + "updated": 1732005569644, + "link": null, + "locked": false + }, + { + "id": "S6xzSzyldnfXQrFmkKLIC", + "type": "text", + "x": 465.46399993896483, + "y": 772, + "width": 9.072000122070312, + "height": 20, + "angle": 0, + "strokeColor": "#ffffff", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aY", + "roundness": null, + "seed": 2112639516, + "version": 41, + "versionNonce": 584319780, + "isDeleted": false, + "boundElements": [], + "updated": 1732005550758, + "link": null, + "locked": false, + "text": "P", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "_KSMx5nwFNxUNAjxSR_kc", + "originalText": "P", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "d2dfNUsCCeyjAXgvrGtcQ", + "type": "arrow", + "x": 483.00000000000006, + "y": 692.220507166483, + "width": 301.99999999999994, + "height": 2.0079349955447015, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aa", + "roundness": { + "type": 2 + }, + "seed": 855780900, + "version": 269, + "versionNonce": 363469596, + "isDeleted": false, + "boundElements": null, + "updated": 1732005642675, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 301.99999999999994, + 2.0079349955447015 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "pnSRfbQP1_xcrej7vbeAU", + "focus": 0.2343159486016629, + "gap": 3, + "fixedPoint": null + }, + "endBinding": { + "elementId": "HVWyBw5ZL2mrk5NKxZdPD", + "focus": 0.007419746029177493, + "gap": 10, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "I_B2rG6hpCm3k18BJzqvg", + "type": "arrow", + "x": 786, + "y": 781, + "width": 295, + "height": 3, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ab", + "roundness": { + "type": 2 + }, + "seed": 629180964, + "version": 86, + "versionNonce": 2096116260, + "isDeleted": false, + "boundElements": null, + "updated": 1732005569648, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 2, + 0 + ], + [ + -293, + 3 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "aerNVtVqYzU6gkE4iu5rJ", + "focus": 0, + "gap": 9.5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "_KSMx5nwFNxUNAjxSR_kc", + "focus": 0.14747678191786956, + "gap": 8.5, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "ZFopwfodeqwFnSJIt3thc", + "type": "rectangle", + "x": 548, + "y": 793, + "width": 184, + "height": 68, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ad", + "roundness": null, + "seed": 533697820, + "version": 626, + "versionNonce": 300507684, + "isDeleted": false, + "boundElements": null, + "updated": 1732111746034, + "link": null, + "locked": false + }, + { + "id": "4aS_BGbHzHeQV2egOu0EF", + "type": "text", + "x": 553.1497772839334, + "y": 801.5, + "width": 175.70044543213294, + "height": 49.290060413085406, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ae", + "roundness": null, + "seed": 382709916, + "version": 704, + "versionNonce": 119772324, + "isDeleted": false, + "boundElements": [], + "updated": 1732111817993, + "link": null, + "locked": false, + "text": "sync backup from\nEU to US", + "fontSize": 19.716024165234163, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "sync backup from EU to US", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "Y_js-51ZT9bwmvSsmHfq5", + "type": "rectangle", + "x": 548, + "y": 617, + "width": 184, + "height": 68, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "af", + "roundness": null, + "seed": 712697500, + "version": 689, + "versionNonce": 1335848740, + "isDeleted": false, + "boundElements": [], + "updated": 1732111788900, + "link": null, + "locked": false + }, + { + "id": "5lCmnovw00DqnDnYrqmxd", + "type": "text", + "x": 551.1497772839334, + "y": 630.5, + "width": 175.70044543213294, + "height": 49.290060413085406, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ag", + "roundness": null, + "seed": 1209774876, + "version": 757, + "versionNonce": 564527132, + "isDeleted": false, + "boundElements": [], + "updated": 1732111811215, + "link": null, + "locked": false, + "text": "sync backup from\nUS to EU", + "fontSize": 19.716024165234163, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "sync backup from US to EU", + "autoResize": false, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "46592fa2e930e621fb84c5731ee38deba57530a4": { + "mimeType": "image/png", + "id": "46592fa2e930e621fb84c5731ee38deba57530a4", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAgAElEQVR4Xu2dCdxVU/fHl6kkkaKBSoUypMhbolRCM5FU0kATmkiJlAYlFYUylDSIilQqiaRRKCUJFUIqGkzNE17/9d33nvPse557n3vuyNvz/30++3Of594z7nXO3nut9VtrHSP/j1h74Azd4UJtFwVbEf3Mo+0Ubadan8fp3z9r2xFs262/N+vfC7X9FuvJY93+mFh3iGP7fLpPcW3FtP2lbZ+2/Z7GdwfjOLafXUrpRpWC50cAjhAQygFtP2n70fp0/uaaANd+nbaa2qppQ8DJwH/1ICu0va1trrbV2v5OxoHtYyRbwPmDHVFLP8trO1sbT7YfcMO/a1ur7ZNgW6Wf38Z44wikmbYrgo1rigd7dKe92s6KZ+c49tmp+7wTFPYM/fwjjmNk2iUZAj5dj9pBW31tl2k7NhkXZh1jt/7N042w39O2KMzNMxzW03aXNh6uZF9DyC3lypVLypQpY1rBggUlf/78puXLl8988vvvv/8uv/76q/z222/m02nr16+X1atXy3//y/McERv1lwe1TU+0LxMRMILtrq2jtpOzupDcuXNLsWLFzI3v379f9u3bZz5pf/wR84O6S8/1pjae8ne13axtoDamgLAoUaKEnH322XLaaacZIfCZN29eOXDggPzyyy/y888/m8+dO3fKxo0b5a+/mEkycN5550mdOnXkiiuukHLlykmpUqXkuON4puIDwl+8eLG89957smDBAvnqq68iHWiZ/tBN28fxnUkkHgGfpCfrra1zOMEWKlRIatasadoFF1xgOpanOhIQsCP0TZs2maf7008/NZ/r1q2TP//8M6t74+k4wbsBArn22mulatWqctVVV8lZZ/kfZRE65165cqV5KMuXLy88IKnE1q1bjaDHjx8vS5Ys8Z6Kefk1bT21bYr1OmIVcFE9wSxtl9on4m3o1KmT3HzzzeYJP+aYWA8b/rIPHTokn3/+uenwhQsXyty5c83bHwkItVu3blK7du1Y+yGu7f/799+yZ/8h2U3bd0h2Bf8+dOQPyZMrp5x68oly6kknyim5A43vonXNihUrZMiQITJz5kz5W49v4bD+/ZS2/tp8L0hjkQQr0ZnaCjonZajr2rWrdOnSRU49lcVpaoHA58+fL2+88YbMnj3bzGugVq1aplN4uKLh8B9/GoHsO3BYcp2YQ/Jqx+fKmWkQCHsYOnzrz7tl3sqvZdkXm2Tjj7/IoSNZjjAhx8lx/HFS7pzCUvGCYnL5+UXl/LMLyLERJL527Vq5++675cMPP/Rey0r9ooG2bdHuld/9CrilbvuCtpzOQTn54MGD5ZRTwi+Sv9GbX/vtNvnxlz3adstP+vmXLixO1M48SVuuHNr4DDa+K1E4n5xf7AwpcnreqE868+SyZcvMXFilSpVM98rbtXHrL7Lq662y6qsfZcOWnbJr30E58kfo/MqOOU44TvKenEsK58sjZUoUMq1sycJS8LTwSwterEVrNsoLc1aokAMPWTw45aSc8p/SReRyFfh1/ykl/G+DB2rMmDHy4IMPmkWbha369/Xa1kQ7rx8BN9GDvOoc6IQTTpCRI0fKnXfemenYH6/fInM/3iDL122WX3aj6saHk3PlkNJFCxhhX1CsgOnsM0/3p20xZE5b+rm8tugz+XUPam78KHpGXu3486RWhVJyzpmZ1xEI+tVFa2TkjA/kyJ+ZH5xYzswD3rDqxdLsmkukQN7QB2v79u1y0003yfLly+1D0sG3amPBGRHRBFxS9/xUm+ldFkvTpk2T6tWrhxzwo3U/yJi3PjZvbKpw7ln5pcal50r1S86RUkVYwIeCofL52R/JdBVuLMOm3+tFwE2uLifXX3GBnKBDrY2vdaR46MW3ZdP2kLfM76FDtuPYLa4rL23rVjQji4PDhw9LmzZtZNKkSfb2R/SfOtqwioVFVgJmYvpAWwX2RMVhAXDxxRe7B9p/6Ij0HjtP3v/8+7huJp6dLitVRJ7udIOcmON4d3eG/04jZsrmnWhQqUUBHbZb1bxMbqpSJkQAPFTDpi6VN5Z9kZQLKFYwr/S6rYZwvzYeffRRefjhh+0FGHaCqtowEGVCVgIeplvf5+zxwgsvSLt27dwDsNi477k35bttKTenuudkuB7TvVGIcF9fslYef22JGg6SbuXLUlAl9Y1+rG3tTEP3wk83ysCXF8geXcQlCtZf7epdbpq9FmOKZGFrAfMqlrst3nNGEjA2VyxG5vfGjRvLa6+higWwfvNO6fj0TKMipAt5dAEy6aFbQ+biyQs+leGvv5+uS8h0HobQro2ukluqlQ35bcfve6X782+ZfkoGril/rvS/vWbIg83CC83BwrqgkDGxuogkYCZuTI9SvHhxWbNmjasG7Tt4RJo9OtmsitOJJ+6qZ+ZfB1MXr5Whry5O5yVEPFe1ciWlb8trja7rgIe/3bDp8u1P8a+y7RNeqCrV810bSm5V7QAr7JYtW8orr7xib4YxZHA0AeMg+E6bsedygNtuu83dp+eYt2X+J9+ktWPrVbpAn2AcOgGs/W6btNfO+/OvLO25ab1G5uaBd9SS8qUyrGZoEm0en2bUxGSgourOIzo3kOOPC5jasQJWrFjRvIBB/KCfvAXukj7cGzxIN+BJkAIFCsiWLVskR47AU/PmR+ul/0vzk3Gtvo9x3LHHyvT+LaTIGQFDyu97D8ptg6bIzt8jW7R8HzzJG2K06H9HTalTsbR7ZISLkBNRG+3L5NiP6IPkzMlTpkyRZs1wnrnACDLb+c8rYCSJEm18nj179pRBg5A3Q4JIwz4TZcvPqV+p2leLWtK3Vcbb208fsDn6oP1bwQP5uE4nVctm2K8xhrQfNi0pCy/u+4Fbq7vz/pEjR4zNfMcOeAUGOGDwqBl4BcxYbAb1Y/VCv/vuO+MsACvWbzYLq3TC+/bycN3c9+W0r5hjvWcWXyN1KLVVnM+/3y53DZ8hmEoTBSrU9H4t3be4d+/egvoUBOrEudqYZjMJmFcbE5jUr19f3nwzw0jSY/RbsvBTfO/pg/ft7Tthvry1/N/79to9c5IuhkbpoojFkYNXF34mT0zN5C2Kq0OfvedGY+IEzMGXXhri/8H4AXkgk4DhCuExkmeffVY6dMCPL2b+qNdzvLElpwvetxcjRqN+//631+6fU3VVjd5eUm3sgGnuzieny+qvUVsTAybN+27BvqHyUV/2GWeEMInwHbzsFTBX4a7p8WLg4AZzV2yQPuMZ2tOH2rqYGNjanUrM+bmO/zUUL3SaTO7VzLV6oV42HTBJDhyOmegQcut2/8AOwUdgsUQgCQz3CriGfrGAL5l/9+7dKyedhG9fnZDTl8kr82HNpA8sVK4O6r1YzRr2nfivn3sj9U7LmuWlS8MMjxf28scmY0eKHwzPDNMO0HhgpgSBLmw0IXuRhVkS86RhYsCmcNDhqTfk4w2ZrGDxX12UPdHzFg5rL8xjYOK7n8gI9dj8r+LYY4+RsfffIherGzJZfVqq6Bk6MuBMCuDCCy8U+F5BjNXPtl4BT9QvWvAlepXttbim2wvGSZ4u4CNlgeKg/fDkzFvpuv5w5/EO1et+2CktH3O9sDFfWsHT8shbj93h7gc1Cf94EHP00yyW7TcYb4RxFQ0dOlTuv/9+sy12VRZY6cQ9N1cxLjOAaZQHLJ0LvFTd6+21/yOdbrzSPfw9z8yWD5QZEg9wdkztk2FhZBVtWbRgYzbyChgzl1l3256jT5QRcafqb+nE1L7N3ZXngtUb5YEX4IX/7yPnCcfL7Edvl/ynBNY2X27aIa0GZzhxYrnDCjrKYZt2ALHwp5/g8Bs8q62TV8D8WpgvJ0yYIK1atTJbws7A15ouFFLazJxBGUMPplFMpEcLml1zqao3V7m302XkLPnwS96t2FBTKT6D1F0JcDxgTrYYqH306wFeAbMEM1SJyZMny623BiZwhhCGknShxqXnyNA74bAHwPTANHG0AKLC7IG3S77gW7z6mx+N4yRW3FrjEunWOKAHQz48/fQQlgt8Kjh0IXMwfJO8fAktBwosWPLZd9Lteebs9KB1nQrSoUFA/2b+rd51VHpOnMaztFRGSJeGlc0ZMX7Ue2hczM6TjjqX36FzOkDjuegiYuFcoD9Bbw4RMO6Z3Hw5a9YsueGGG8zW6Z4DcQviHgRfqP329iFT09j16TnVGafmlrmD27i2ZEgLkBdiAQ4YTLlg0aJFUqMGZgwXrOQ+8goYPcjwNt9++22XPA4HuNdYY9ZMC156sIlcVDxAvZ794Tp5ZCLhSOEB5baQqgtn5M0te5Uis2nH73IwQQtRsm7yQr2H6koEOOv0UwWTZV4lwcNK2b3/sJp+90mF0kVdPjb+7dZDX4/p1K881FRZpwE797hx4wwhzwJkSUOUs9UknMTGk0wYhfNEpNtMueSpu1zWwogZy9TIkWFBO12ffNgT1S8pKRedXTCEQcF1M9xt+3WP4UKPmr1cdu5Kr88YL9Lttf4j9fXNOjO/P5ov142HqXLn53wLmPMsfepu1/GPz+D555939uemcZ4bx4EtYPxYhqdpz8FwnTs8/YbvkyeyIU/6ArVgObjvuTmyTBmbCPW2ay/VqIAzoxLinX2hzAx8ZaF6wAjUSz0gzQ9V8yrEwFhBqEuVLq6Aou4OT3xcj1vc7SpUqCCrVhF8abBUG5w6A1vAhLgRLC39+vWTvn37mg0gj9fq8WLUkyZjA4azWQMD6hkY9/ZKgXB2dsHT4j78pPc+lSenpZaYB1GdIdNZGTsXi0Nhzcaf5DftQ6Iq9inNOG/uXGZKKaNDeEF9KACsjwa9X/J9j/YKGod/njx5hM8gMDcT9ZlJwKzVjebcqFEjef31jDnh2u5jzAWmGl77aqTzbVC24tK13xvK7k86JEPfKaCdVqJwfn3bSxiCvI1UmzrRR9FLHUC0G/3mclUxf4jo4MfVh8sPwL5sMci/2RIvG94kwJvLG2yhqf7tWk/sN5ioNRRkKV26tGzYkOGaw5KFRSvVKH/eWfJCt4B65gW6MOEo81d9I9t+y6wX4z92zJnwlnoqaZxwEAAxv+uzWUZ4xH1r3uGSKI8eo+fq4uoUQeUrWsBonnLw0B/SXxeMDgGvn66CmasBjhwcOn7xxoCWQlgNYO51/PbB/SHdGTYHsAWM7dK8tgR0EbObM2cgGGroq0tk6uLP/J4/7u2qlS0pwzoYtq4LyAbPzvxQ3v74q0wsSmiqfVpcI1V1jobwBiFv/idf69C+ShpXL2s6GLD4atz/Ffl+e/JJ+veq3bx50G5+QIdgKEUsmiaoNlAsKFyugd9YE7y76mtzTcPurm/WFiAWVZR7xtPmoHXr1iauOAhuMCSIyhbw+fqjaxMkCPuSSwJDyIz3v5BBkyKGv8QtUO+OtgGA3xi6uulCK9JqONyQDpWWWCGMM7N1PnfiiFJ1D7gBCQkF0ImhFYPh+qBWPL+YIaszva36aqs8GPyN3xmpGLHAzGVfqvCNKz4qrrvsPHmsHYycAHDtWqNtCOGO320Bs4ImYs28thMnTpQWLYz3UD7ToLI2j8emp0W90jAbwEQc3sF4uQxqPzA2Kt10sN5slYtLuKx/3h6GcdiXttEk1oWM3+tf/ORdQjQkwGeN7xrgA0aVIzqR64F0Z2NavxaCCxFMeGeVPKOjlB8M0PnXoeWSboJsBhYe0b8Dq+MgvKxKzCnmte3Ro4cbGpEukyEsxNH3ZXhIrn9ofNj51r4BhmYWHJ1uulJ26RC9WE2r47XD/tBwTpu0xzBd9d7nk24ImTu4tRvuOUoXVi9qlKUfLBvRwX0oh0xZLMRYRQPrjPlPtHPjiJ988km57z43fIzdCdInNVNEAUPUas6vdevWlbfeesvdMB1GfxiIE3uyCAyg8SOT5LsEQj+8x2uprrl16qJLJsY/0Nhlavil4nj1fRaAfiI0vUQIjFGYKYNgiDhTW0gUnvcNfkA3MLEtRYsWlc2bIVkG0OUZdWvpsj+VKFEon7zezzxfBvhK8ZnGC+a/pU/f7aZJwOyJ+TOZGNK+rtHVAaobEZfR4F07NBs42awbosFWrXbt2mWYlJaLcIzun7H6Ch7MK+C6+r372nIQJ/eG12wY7WLi+d1LQ7n7yRmyUhcnicBWKVJh9MC3i48XoJ8396HPVlVtgUWYgxr3jfYV9YCb0cl0ECZkhcVLJrefV8AwOtzX9IMPPpArrwxQTCCcQzxPJVIhYDsqER218wjjRUsabAc+McHXKr2I/CBZARWuR9PqZhOsXVXviW6mJMPAaxZFB94cQg6CXBWoR5mIc+GCzwiFM5byUaNGubk4/D6difQcBHHoOg4gpUFOSwT2G8YwyHCYTFQuU9xkHHDgZ9TBrk5cMUDPR1uIBttPzrDM8MwIGwSUm5vCHSOcgOGnmte2c+fOMmLECLMfq9LqXUcnJbYm0s1AK2XR4gAu9OYdiQW74RTHOQ4wadbtOS5aX8b0O6mR3n28nasq+dFpG1S+SB5WAw0g68+VnaFQZY0Z/VsKMUkAbx85wSy01r/DMiPDCXi0bmwmayIb7DxNfp7OaBea1e+VLiwmz3TJIHPj5Eg0Uw65NHo1DzjD/XZmrPfQR4O/b7iSDMNish7U1OvOKnaZRRmLMwe4CrMKSvOqj8RrQ6sKArcghGuX9W5ffzgBw3gzj/nxxx9v8jOdfHIgrQ86HrpeqoCTYOidGTdepctzCWfMISsA87CDZBzTe//eB/PeZ2erm3NTxG6qeEFRee6ejBG1jg7RP2eRdurRNrVNKicA/woGJVl3goARkRFf6zlrOAEX123ctDk2u+NTdX21e2JaquRr3gLeBoDj4PIOzyR8Lm/np8IzhtXqnSFtJV+eXOZ6o5EkYHtMVFu1gyaq70dK9YDO/PaQNsJUAMIYN5jTIpoZwwmY4+CNMBHMtkUr1fNw0xrlpHvjgK+aoa6GrkgTRd3Lz9eIeHJ5K8VBV7eV9KGJtsqN55ysilkdA1Iq1VcrXCQXK54g1DcHrdUMHCnHmJdm6wlRYVgmz5LrDPZeeyQBs6xj4ja+xo8/zjC/pTJOqU3dCnL3DQFGJX7eG3pNiKevQ/YhQoJICYDjnfkxFYDJ8bI6/R2MnbvSJGYLB7hk76sBxgHEfjxK4WDbrAlNIUTFwuP6d4+s7ieSgNFVTHwprkOSWjs5KbO68EQ7jgg8IvFAslQa252XrGNGuk87KBsSYD19i3EThoPtpCAonOBwLy4990wTX+yArDovv2zE4oCJOcuMOJEEjB/LNSER6U/EP4CC0jZF83DPZlfLzZqvESRrvrfZD6kwdNi97V3t2t4lr/CIKyK+CESKnmRqYYoB6LxnnnmmHDzoMmsW69dXR3rYnO8jCZjf8UwbXxQei2HDTGRpSvVh+4awe2P/ThTE7xDHA0jeghsxlYAMB8sDMCXU7zU+bIZb1EEWgAAyw8Pj5oVcFqzMGY+0dJmTYbLbkVrHNWVFuqesBExIgUkpS+QaSbkdpGoetg33i9d8K91HZXiz4hWKHcj20rxPZOQbqY0zvkp90092zPBpRxp+Qyg7YZirDynlqOFVZcxtE7mPY//rrwNsEAWZGBhlo+ZLzErAbhphIv7JA0ECcJCqFIJPdbxBnffFzTmgtjz0YmKEe3JAzxvaRvCjAr9+13gfJvYjf9UkTdngZMSFRtTg4ZcyzcX21IHOjO7sgAC8N/TtddgoGDXsZHS63ZPaQhzBka45KwETXuDSEOyMd8la4Xov6rl7b1Kai8kBE1WX9CME24rF9jdqR5MOItW4sszZMqIT+cgCCLcwHdmlgVxxYSBFlVdvfvDWq6VRtcBahLeX6i5W9D7JPfBPZvhys7ihrATMbrCpKZUjDRs2lOnTM6Lgbnt0iny1Jax1LO7+sy026IXoh4nAXtWmw1liXyvMFCdPFuE0PFy22RVDBwYPAFuUjLmAlIizBmRwyUgC27Rphvqlm4T1+0bqp2gCJpGHSXVHQhaGafJGg1SYLe1kJXRKtXtHxW2U8A7PzL3MwekC8VXEWTnwkv5mqhCd9IwkU4dHDXo0raYGk0DtCeJ+yc/95ZdfOofh7UU12uT3PqIJOIRpOWPGDJNaHkClgVKTTHhttOTFijeLOgsUFioO0jU82/1hLxoxvd6i1F3HO7Zo+J0mGA0Mf32prmvWCFGHszQDgGOWJITollsyQlR0U3wEIVFm0fo/moDZH46LYWg3b948RNFOhjvPvkA4v++p6w3bLkhklJjcO2OhE2vkQLRO8/s77r3X1b/tLPLIFEjGQFgZsDMc9FYV6R1VlQjoJiwF8PZCW6b6ShDEjhHO4JLa/VyHHwFTVawXB6M+EtXBSLoFUjHs2QwMVqAER4erlJLVzXkNDnC6GSL/CdjqDueHZ4ae7ETnQ/6o8+BYkyhtWt8WbsI0Sgex7rEwQf/G0xcT/AgY26E7eb3zzjumThFIJIlIpKv0JheJJ6rCjhqARlNXOzAVhTr89DQhrwTUkYAFkPMEW7RDlndig20VkbeXimtW1hxCe5kuYw6V9CNgrgv3YXH+oJwOVB5g0g8oQyLZcbi2cYLFFvmh/TI7CONkHnMKTr2sGfqe1kx9/yRse7j3OsgiiOpm+6zDBHRjgM5wP8VwM34FTN7DrhyXapuk68H4AeJ5w6JdnzcRC3MoEfC4K6PBzkWFW5DFVbrLD3iv8TT1E8/SOdcJhnN+Z3QhZmqC0pQwbgAcOwT/obEEgbcCk1Zcafb9Chh/mxtk+/7777vVxgjh5CKTDZsGw7EJRO8+ak7UJJ5THm4m550VyDiTzuD1aPffvv7lQrPByIJDn4fSASMkecosPKZ/PxTt+JF+9ytgXlfyaBnN3B6m+Z88WswtyQTz1CTNxWhH6MGwhFgeKT2+N/vbAC1vM+sDV4dM5uXFfCzyb07RlT3l+xwM1oSk3ZtUcx0K+N0rVapk10SiU9FgwpVwQ8cikgHDBLG+YXM9+xUw1wR5lwLMxuhBLQdq8YJU5dJCzYC75AxfnIvF0pi3VsgU1Ru95eRIv+SEjDKcQ9pLRv2imKUZYQeYHK/1vc3VcyHaOYsvTJKQK2ynjh6GujlU3MB+i+vJ/rQTY5ECCzcZIYpEGG5yLiEWAZOIydU1KEz5wANEugQWWzf3S5ziGq5fSI/AsMtQZoOF3fsaKkKWONItHVTBT1BXneNj9RtGkizh+T0ONZaoueAFCdgp0ZsEQCTnQTBMg1gEzPY8JYYVR+wSNR1gXoJU1THy5lr22wHPzfrIJHD5XusJ+lmc+T1uotsxVBOhYOcdgblasmRJm8ie6GnIUmp4tbEKGP6pG/+CIZyqaAB1BlI5VJVkAarowNa13cw6sBl+/PFHOffc0BwcWZ0P4cIOeUoTsfgJ8ErWtXuPgxvxxspllHNWKVOyFoZn3mA46F988YUp+U5NJPJPFilSxLxM3kalFb6DRota9dhjrMVcoBca8lasAmZ7JnRD0iVuifglB8nMDE+oJJVLHJ8o4RrQhqh7f+ONN5pMfFT6JtO5HzBf4w/+pxZdthMh2vUiXN5qwlP8VlOnBBLTpgVUqy9jFTD7d9TmEpZZ+TlZXvATo3cmWiiSUrIvdr/FDQfhpHfccYfJgmuDm8deCxGc5KmeAlGZ+pG1QpsnIlNUo3V8vL8zEuEKtQGlFn4bkYaO7T3e47PfvHnzvKXtR+rXXeIRMPksIeSZQBmYBnb9vETL7+APndCjsfGLOqCc6sCBmMTDo2zZsibbOfmiHEBkI9q/doXSLl+Z3/Bhk7IoFdzoSNeHuldaU/ADogkHaJwyjgc8TMRjoQdfoMHv3sLQ9vG4XjhexFexwLziorPdFTjbYV2kKruFzvr3M/EImGPAxzXJtnA8/PDDD1K4cIBohuGDCL546gqS64KkJna1bZT+cNXGnRvh7aUyNnOVAwwImCgd2OoT37XVt3jNxtQVs7Z7GZ8vvl8HFNRkQRoOuA+5dxrq088qyB3aEOrPu/abBwJtApK9E8rCcXbv3m1Gsk2bNjmHJc8UnK298QoYrglVskw8Rbdu3eSJJ56I2MFh78bzJXPtM0pjsauFQdfF//zXX+FNlNBI586dK+XKBRzkYMrCNaZQsw06ixyYTlHHGUs1a9Dk1GcN4hq88VbR4pAi9RXDeKOqZeWu6y8PydHJXF2zZk07lSGHeEqbMS3HK2D2JUjJZC3jLcbzQVgFcPJFZRVQZd8IK0zmKDtbHNXGyUFx4ECoEQciPizPJk2aSMeOHV2GCcdbuvY7U7c33PBLJAHWMZAq82o44TS4UkNFWwZCRQHxVrHUn6DyTGUdjtvWq5ipGDX26uuuu872Opnu10bKAUPBTETAHATOlvE6VKtWTRYvXuzeCAYImIJ+Flxeb8s333xjVuiOwR2VgPSKCLxKlSpuWgm7Q+FcUa83XDphckjO0+Awp2JnOvlZvZpfo+XgA8m6iftvSmKZbb8a41A4wObAcgdnmgXYZVqu1tEk7O1ZVPGAf/ttSLlBijqjyrrus0QEzPlYqbnmFzu3Fj9CQ4GOkhW8wVUQCohL5hOhEq5RvXr1LNUFONSPqlMfgoAXdA41dx3yO78ni3Od5Y0Ff6Ryd71KgegEB+jmjG6/6Lz6694DkidXTsl/6klarCO3myIp0rExLhGIQNJ2DzBX4qhfaX+fqIDJS0yWWuOEQCclOSYKuINIxG9+b6fDzp3Xk9opANInIkxiXyEWMMdGAnrtRzpKQOuJVEqdN5Zau3Y9X44XLpIg4okS/MGO1kjkUGQ8YqU8fPhwOzbYOSREeAhomVZviQqYE7iBavzD/IjK4pTF4zv4RoOnLDI1GADDEF4Uh7nPdxgyGjRoYBZNdkJy5w4Y0j7XzOgk7iThN0yIrKg8rMjpXIY5L7geeFDpwIsaPHaJBpEBLFaOHz3audkWGwMLzTlz5tjcLO+ucJmpVfhDuGMmQ8Acl/HCzUcY1NwAAAgeSURBVERCQQ/SEdtWGEyYmAxZgJF60En/x87kOiZt4tSpgfoMe/bsCdFpiaTAexQuy6z3pmBykD4Q1Yj80w44h1PJPJ1lCuxMeJgTlyxZEmJ2hEDBShgSxbZt28wnDaK75fQPJzv8oPdoyzLJZbIEjIWBZIuBYBoFNmp0WCfPVqQnliKYqEK8tQ4wR15zTcbKkzd1kc6zVIDZqHTdzVqbAT2bITiHOjtIeIaflagI9ENvAvHt27cLCzcntjYZYTHR3kB+Z/7/YGQHlz7kya3h5xDhtmEhRdpnMrdErTadLAFzISW0ESnu+impHo6Vi5VvOLAC5EHw+EANZWX+/Pkhc7m9P2oGAka4zso4Um/x4NCxPGxOJRk7K2y8vexnP28kf+XKlUOS2vg5RnAb1jmksSVYC2ZNOAJA2MMlU8CcAA8GFxGo3aZgziHlD2oUNwj1FsoPpG4+rZq3IReIhYqgq6pVA8WfYgXWtSFDhsjo0aPNOWbOnGnmePCepv21U/vGemy/23tLwHrKz4U7DIsU8kbRECo1/ejPTX7P6d0u2QLm+Ch9pJQPqdTk4wKJCmM1GLIqgj7atm1bY63BZ5qVd4VVOHPcq6++arLAWXkcQwQcSwJuH9cdcRM7+A3NgLAfKLFBkLyL/ncEyqfvN9PvdaVCwJwbnhAZ1EwNWx/AMIwOR+1zKmG6VUPsfUnnRKQdsbKMDHTaoUOHzCcLElQ0XG3hAJEcNyNYqPkweqSh4KVtA2cNUKqUW9cBnTWDnOWjg+LdJFUCdq6HvA+3ayOzilepZbFAhDfFChiGnEIMZNcmU0ogG3mSYMdVLfzkK+kxJvVqkh0DzJqCUSgIht9Q60eS7tN7mFQL2D4f7h4EjYkTlgD0n4jpf/Q3DNt3BAUdiLOMDZ/r5tQwMKMBoa9OKMiClevlgbGpTeXAOe10DmPGjJH27d1svyxGQzm0sd2b763TKWDfF+XZENIXKy2SUKGGMbcThAVNFNsk8xafZFqFHI6biCzZm7T11mbKrNrFvhau/FJ6jPVXIyHei2a/dzSBGaEroFevXjJokInEBTxd7uucyDmi7fu/IOBo95DV71h4jB8Twwu2bbBwxVrpMX5xIseNui/BZB+M6OiqcR4dmMj2jKyrUY8W/wZHu4ChOJiigFjJnFjbhcvXSI8JWTtB4u/SwJ4YW6b3z1hGeHRg1hjtEj2Hn/2PdgFDpZiQScAfrZYeL6U2II38G+ThcODRgUPKz/kRVLzbHO0CRi8yJcVsiu+i5avl/gmpFbCdYSCMDuyWYI9XcH73O9oFjGXNjMUYP2CBgMUr1kj38akdojvfVFla1TL5a4wd3NKB+coQ4vwKKZHtjnYBs+pGXTKU21atAuS391eula5jFyfSb1H3tQtWenRg9mUFnXo9TU9ytAsY3XsLPYqjvGtXw0OTL7/ZJK2GZSQeiyqtODYg5reMUmKBRwfmK0iLyQ3HjHCNR7uAUUJNGfDevXvLgAFGJZafdvwiN/RNbnEOb/++O1QThCsXDHh0YMoH4l7NujRLHA9VuF2OdgFzz1jLTqAEK/E/4OChw3LVvZSmSA3wT1O6zoFHB6Z8YCBnchqQHQRM6bQCZIuz6gxJtEIYifS9t4KbRwcmQyyZYtOC7CBgguVKY+iHauqASEgiBlIBb65Kjw5MdVCqhKYF2UHAhi922WWXhbD/m2muza+TnGvTkRgk9buCbFGI+7g5LT8wHrbE8yT7fDyyg4AxKvSH3AY3ywGFnKHupALjNL6qbLBotCfqD6cIad4zE7hTcSF6zOwgYDdofevWrSbUFERKo59oPxNAtuCJ9m5IKHFbqGhBUJo0ow5eoifzsX92EDDKqAklJBrAId6tWLdJOo5Ivi7srWpGtlii9oPAIUw64LQhOwiYziSe+aw+ffpI//79Tefu2X9Qrrt/bEyBYH6kYpdgh9/sjBi6L3ovw0d64laDF5tdBGwWWuTYJCTGgZPl1Y/g/GxD/kkiGRxioCclISyW8PxhPwePc5vsImDyez1PRiAM/8WLFzfdRbQ/meuTAUjuk3vfKujAADIgmQc4XxDkcEg9EcxzM9lFwKxcWUIfb1u06IvHNNvc9KXGHxE3yAfdvUlVIQeWA09SFGhEGaEacZ8p9h2zi4DpGUjkdU488UST6gC1CRAl0fHpmbIqzlLypFoc0LqmXFQ84FgABMOTmCbIy2buhWAXEtYZu6ji2yM7CfhW7SLjYahXr57Mnj3bjfSjECbV3Ij89wuy09fXuF+4zyfmCGQOAAzNmCatcByi/zLq0/k9QZK2y04CJhMBb5Ex9JOG0c4rRd7IF+asECp471aBhwNZcKpfUlLbOSby3knV72xL4SrKHqxc6b6s6/U3SAdEbPwjyE4CpoMra3O5OpMmTcqUW4ugNmKPt/+212S1JYFLYS0zV0TrLJQonD9isBvB2Rg1rJwi+KE5n/FH/1PIbgKmnykVY7w5OXPmNMFpDtMjHiEwFJPHi8B1C7yxqEQ4Ov5RZEcBw/Ig1UGgTp8C/Xjo0KFGrYkGIhVJ30isE83KTeXsukL/oPTNvyJRdXYUMIIgMgKLR3FboJgVIceT7LRQoUIm58i+ffuMEAlH3bBhg3lTSRATBvgeqU4DmS5scu5oD08qfs+uAqYv0WsYV4mVSgTMsTgRhmr7IZEDpWLf7Cxg+pNIRpLIUMkzlnhmLCOYP2dqS1+9vDiegOwuYKfL6AdMiRT+pSg2Qeik0CfYmDeUBgsStxBCjan6WBxySdou/wfrWRlpvIH4BgAAAABJRU5ErkJggg==", + "created": 1731966018042, + "lastRetrieved": 1731966018042 + }, + "0833b30d1a4da2b737b05a0261e434640c53058b": { + "mimeType": "image/png", + "id": "0833b30d1a4da2b737b05a0261e434640c53058b", + "dataURL": "data:image/png;base64,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", + "created": 1731966716908, + "lastRetrieved": 1731966716908 + } + } +} \ No newline at end of file diff --git a/docs/images/source/Barman-multilocation-georedundancy.svg b/docs/images/source/Barman-multilocation-georedundancy.svg new file mode 100644 index 000000000..1742116f0 --- /dev/null +++ b/docs/images/source/Barman-multilocation-georedundancy.svg @@ -0,0 +1,12 @@ + + + + + + + + pg.uspg.eubackup.usbackup.euZone USZone EUBackup architecture for PostgresMulti-location geographical redundancyPPsync backup fromEU to USsync backup fromUS to EU \ No newline at end of file diff --git a/docs/images/source/Barman-remote-copy.excalidraw b/docs/images/source/Barman-remote-copy.excalidraw new file mode 100644 index 000000000..a9643aa2c --- /dev/null +++ b/docs/images/source/Barman-remote-copy.excalidraw @@ -0,0 +1,875 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "1ZzBrWEHwMbkiSQ937jS_", + "type": "rectangle", + "x": 280.55864661654135, + "y": 382.7789473684211, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 2097703460, + "version": 386, + "versionNonce": 140378148, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "FUELyXBPcB6gf1H-ELi3a", + "type": "rectangle", + "x": 829.2323308270677, + "y": 386.2736842105263, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": { + "type": 3 + }, + "seed": 1386606756, + "version": 609, + "versionNonce": 1679478308, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "ZQBQiZKK1TTwKqd7MXAMm", + "type": "text", + "x": 359.4398496240602, + "y": 538.5443609022557, + "width": 31.086517179484357, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": null, + "seed": 1697128612, + "version": 420, + "versionNonce": 550129828, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "pg", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4neJBFAF6jQ35NUlbGebi", + "type": "text", + "x": 878.6578947368421, + "y": 540.5413533834587, + "width": 91.56410319010416, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1977030308, + "version": 529, + "versionNonce": 738237476, + "isDeleted": false, + "boundElements": [ + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "backup", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "g8P0muvVQ88DvKGMJmV0D", + "type": "rectangle", + "x": 228.63684210526316, + "y": 236, + "width": 845.7263157894738, + "height": 664, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": null, + "seed": 2126547484, + "version": 419, + "versionNonce": 2098914084, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "SPCm1UV2vaWBMhVMDRUJU", + "type": "image", + "x": 337.47293233082706, + "y": 449.6781954887218, + "width": 70.89323308270677, + "height": 70.89323308270677, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": null, + "seed": 239434660, + "version": 311, + "versionNonce": 94035620, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "1tSeOxu4bvvm1bBII4boa", + "type": "image", + "x": 872.7015186481054, + "y": 444.18646616541355, + "width": 86.33532345715773, + "height": 70.89323308270676, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 1149200548, + "version": 507, + "versionNonce": 59730468, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "SKIYhR2pT9ePU_N3-qjcA", + "type": "text", + "x": 242, + "y": 68.5, + "width": 802.070385105881, + "height": 73.60000000000001, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 450504476, + "version": 166, + "versionNonce": 1237256476, + "isDeleted": false, + "boundElements": [], + "updated": 1732004135233, + "link": null, + "locked": false, + "text": "Backup architecture for Postgres", + "fontSize": 54.518518518518505, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Backup architecture for Postgres", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "hVDj-LHqEF0t6Tl11s2LZ", + "type": "text", + "x": 431.16000162760423, + "y": 164.86240812442435, + "width": 455.23333740234375, + "height": 43.13759187557564, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 904209180, + "version": 565, + "versionNonce": 4904047, + "isDeleted": false, + "boundElements": [], + "updated": 1732174842596, + "link": null, + "locked": false, + "text": "Remote copy architecture", + "fontSize": 34.51007350046051, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Remote copy architecture", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow", + "x": 422.34511278195487, + "y": 383.7774436090225, + "width": 459.0740840644434, + "height": 74.88721804511279, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ai", + "roundness": { + "type": 2 + }, + "seed": 592542500, + "version": 769, + "versionNonce": 1149416097, + "isDeleted": false, + "boundElements": [], + "updated": 1732174877474, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 56.91428571428572, + -70.89323308270677 + ], + [ + 380.4270676691729, + -73.88872180451129 + ], + [ + 459.0740840644434, + 0.9984962406015039 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.1931402196402995, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.3213161961438585, + "gap": 1.4977443609022885, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": null, + "elbowed": false + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow", + "x": 472.26992481203007, + "y": 482.62857142857143, + "width": 355.9639097744361, + "height": 2.089573357269705, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aj", + "roundness": { + "type": 2 + }, + "seed": 1620519580, + "version": 497, + "versionNonce": 1105191855, + "isDeleted": false, + "boundElements": [], + "updated": 1732174873314, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 355.9639097744361, + 2.089573357269705 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.020247506155730458, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.022935461485079463, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow", + "x": 418.3511278195489, + "y": 588.4691729323308, + "width": 465.0958370263172, + "height": 94.85714285714286, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": { + "type": 2 + }, + "seed": 208601628, + "version": 663, + "versionNonce": 771342081, + "isDeleted": false, + "boundElements": [], + "updated": 1732174869933, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 53.918796992481205, + 94.85714285714286 + ], + [ + 389.4135338345865, + 93.85864661654135 + ], + [ + 465.0958370263172, + 1.9969924812030075 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": 0.11031710585082588, + "gap": 2.9954887218044632, + "fixedPoint": null + }, + "endBinding": { + "elementId": "4neJBFAF6jQ35NUlbGebi", + "focus": 0.236919665601773, + "gap": 14.9774436090226, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Le_pTc_Rwx0iNbqSMjzwk", + "type": "rectangle", + "x": 526.1887218045113, + "y": 271.9458646616541, + "width": 269.59398496240595, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "av", + "roundness": null, + "seed": 1342530852, + "version": 446, + "versionNonce": 799540772, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "h9kkrSHYTc0yqOK0Hc8QY", + "type": "text", + "x": 531.6205415057418, + "y": 282.9293233082707, + "width": 257.7318493193432, + "height": 45.95482352549884, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aw", + "roundness": null, + "seed": 1541742756, + "version": 466, + "versionNonce": 1351328164, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "Postgres connection\n(for management purposes)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connection\n(for management purposes)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "PQurhIwTn6hJgWWOTKjtH", + "type": "rectangle", + "x": 550.1285714285714, + "y": 450.6751879699248, + "width": 207.73834586466154, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ax", + "roundness": null, + "seed": 2067560220, + "version": 637, + "versionNonce": 1299241508, + "isDeleted": false, + "boundElements": [], + "updated": 1732173857479, + "link": null, + "locked": false + }, + { + "id": "D4rVKgv_jWc41tiRfWVwc", + "type": "text", + "x": 550.5679099267944, + "y": 461.6586466165414, + "width": 205.8566613494184, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ay", + "roundness": null, + "seed": 458699676, + "version": 730, + "versionNonce": 1712977316, + "isDeleted": false, + "boundElements": [], + "updated": 1732173857479, + "link": null, + "locked": false, + "text": "Rsync backup\n(barman to postgres)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Rsync backup\n(barman to postgres)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "JWscPEsiXw56xj5PMIYAb", + "type": "rectangle", + "x": 552.1165413533835, + "y": 654.36992481203, + "width": 214.75338345864665, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "az", + "roundness": null, + "seed": 1046108708, + "version": 605, + "versionNonce": 615621871, + "isDeleted": false, + "boundElements": [], + "updated": 1732174842596, + "link": null, + "locked": false + }, + { + "id": "kQqv-gQNveFMs3HCpPqk1", + "type": "text", + "x": 555.551368573411, + "y": 666.3518796992481, + "width": 210.88673653738843, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b00", + "roundness": null, + "seed": 2111010212, + "version": 768, + "versionNonce": 1952097665, + "isDeleted": false, + "boundElements": [], + "updated": 1732174842596, + "link": null, + "locked": false, + "text": "barman_wal_archive\n(postgres to barman)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "barman_wal_archive\n(postgres to barman)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "u83aymAN3JNKbvLtixJxp", + "type": "rectangle", + "x": 470.28421052631586, + "y": 747.4874060150375, + "width": 24.962406015037594, + "height": 25.9609022556391, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b01", + "roundness": null, + "seed": 1425346721, + "version": 440, + "versionNonce": 202845327, + "isDeleted": false, + "boundElements": [], + "updated": 1732174859770, + "link": null, + "locked": false + }, + { + "id": "5GKO2Ql90dxbqO8-p1pDh", + "type": "text", + "x": 518.2120300751882, + "y": 749.4843984962406, + "width": 219.66917293233084, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b03", + "roundness": null, + "seed": 1200626785, + "version": 264, + "versionNonce": 1276286159, + "isDeleted": false, + "boundElements": [], + "updated": 1732174859770, + "link": null, + "locked": false, + "text": "Postgres connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "FH4AP-8mT_dNw66n62yh4", + "type": "rectangle", + "x": 471.72932330827064, + "y": 797.0501879699248, + "width": 23.96390977443609, + "height": 23.96390977443609, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e03131", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b05", + "roundness": null, + "seed": 1680554017, + "version": 866, + "versionNonce": 1144670031, + "isDeleted": false, + "boundElements": [], + "updated": 1732174898320, + "link": null, + "locked": false + }, + { + "id": "EGgeBw8Ix5iVYVMCc4QkR", + "type": "text", + "x": 520.909022556391, + "y": 799.0501879699248, + "width": 231, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b06", + "roundness": null, + "seed": 288459777, + "version": 677, + "versionNonce": 1328711023, + "isDeleted": false, + "boundElements": [], + "updated": 1732174898320, + "link": null, + "locked": false, + "text": "Rsync/ssh connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Rsync/ssh connections", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "46592fa2e930e621fb84c5731ee38deba57530a4": { + "mimeType": "image/png", + "id": "46592fa2e930e621fb84c5731ee38deba57530a4", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAgAElEQVR4Xu2dCdxVU/fHl6kkkaKBSoUypMhbolRCM5FU0kATmkiJlAYlFYUylDSIilQqiaRRKCUJFUIqGkzNE17/9d33nvPse557n3vuyNvz/30++3Of594z7nXO3nut9VtrHSP/j1h74Azd4UJtFwVbEf3Mo+0Ubadan8fp3z9r2xFs262/N+vfC7X9FuvJY93+mFh3iGP7fLpPcW3FtP2lbZ+2/Z7GdwfjOLafXUrpRpWC50cAjhAQygFtP2n70fp0/uaaANd+nbaa2qppQ8DJwH/1ICu0va1trrbV2v5OxoHtYyRbwPmDHVFLP8trO1sbT7YfcMO/a1ur7ZNgW6Wf38Z44wikmbYrgo1rigd7dKe92s6KZ+c49tmp+7wTFPYM/fwjjmNk2iUZAj5dj9pBW31tl2k7NhkXZh1jt/7N042w39O2KMzNMxzW03aXNh6uZF9DyC3lypVLypQpY1rBggUlf/78puXLl8988vvvv/8uv/76q/z222/m02nr16+X1atXy3//y/McERv1lwe1TU+0LxMRMILtrq2jtpOzupDcuXNLsWLFzI3v379f9u3bZz5pf/wR84O6S8/1pjae8ne13axtoDamgLAoUaKEnH322XLaaacZIfCZN29eOXDggPzyyy/y888/m8+dO3fKxo0b5a+/mEkycN5550mdOnXkiiuukHLlykmpUqXkuON4puIDwl+8eLG89957smDBAvnqq68iHWiZ/tBN28fxnUkkHgGfpCfrra1zOMEWKlRIatasadoFF1xgOpanOhIQsCP0TZs2maf7008/NZ/r1q2TP//8M6t74+k4wbsBArn22mulatWqctVVV8lZZ/kfZRE65165cqV5KMuXLy88IKnE1q1bjaDHjx8vS5Ys8Z6Kefk1bT21bYr1OmIVcFE9wSxtl9on4m3o1KmT3HzzzeYJP+aYWA8b/rIPHTokn3/+uenwhQsXyty5c83bHwkItVu3blK7du1Y+yGu7f/799+yZ/8h2U3bd0h2Bf8+dOQPyZMrp5x68oly6kknyim5A43vonXNihUrZMiQITJz5kz5W49v4bD+/ZS2/tp8L0hjkQQr0ZnaCjonZajr2rWrdOnSRU49lcVpaoHA58+fL2+88YbMnj3bzGugVq1a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", + "created": 1731966018042, + "lastRetrieved": 1732174804744 + }, + "0833b30d1a4da2b737b05a0261e434640c53058b": { + "mimeType": "image/png", + "id": "0833b30d1a4da2b737b05a0261e434640c53058b", + "dataURL": "data:image/png;base64,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", + "created": 1731966716908, + "lastRetrieved": 1732174804744 + } + } +} \ No newline at end of file diff --git a/docs/images/source/Barman-remote-copy.svg b/docs/images/source/Barman-remote-copy.svg new file mode 100644 index 000000000..46cd3334a --- /dev/null +++ b/docs/images/source/Barman-remote-copy.svg @@ -0,0 +1,12 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nOy9WZPjRrol+H5/haz6ZcZwK7Bvd6xcdTAwMWaw71x1MDAwNFx0XHUwMDAyIIGZtjLsXHUwMDFisVx1MDAxMDvQ1v+9XHUwMDExKSkjUlx1MDAxOZJSVXmnqm5cdTAwMTcly4xcdTAwMDBA0OH+nfOd87k783/+21x1MDAwZj/8ady65E//8cOfkjVcblx1MDAxZUXcXHUwMDA3y5/+/fX4nPRD0TbHKeTT70M79dGnK/Nx7Ib/XHUwMDAwwbd3vERt/eO7kkdSJ804XHUwMDFj1/2/x+8//PA/P/15nCni1/fC/s72N0FejLAqrlx1MDAxN1x1MDAxYSXL618+vfXTRT83pk+iMWiyR/J2an1tXHRcdTAwMDW94DhFYFx1MDAwNFx1MDAwMVx1MDAxMzhcdTAwMDaj+OfT23FcdTAwMWGlkFx1MDAxN5KkaIxEXHRcbkNg+PPZpYjH/LhcdTAwMDKmoVx1MDAxN1x1MDAxMkZIXG6mcYyiSOTtXHUwMDA2eVJk+fj6IVx1MDAxMPJCfL5cdTAwMDeEI+Tna35s0n/8XHUwMDAwfT4yjH1bJVxc+2j713b/Nzh5/e+t1WFcdTAwMTBVWd9OTfz5mrFcdTAwMGaaoVx1MDAwYvqjm96uS4vH4zpun+5+dPXRrX/6xWfcfnpcdTAwMDTkXHUwMDE3x3/tXceHZnmTXGavQ/HWXHUwMDExbVx1MDAxN0TF+NpZMPT2XHUwMDE0ry3slPjTqP2Ptzb1QZ0or8PWTI/H58NFXHUwMDEzJ6+D8adcdTAwMDD64tOa+KdP+3nI38ZcdTAwMTP96cj/emt7ksSf+pomSVxixYi3trzFXHUwMDFkSlx1MDAxMb88emqbTzFcYmNcdTAwMTB6XGZcIka9tWrgj9hcdTAwMWI/3TVcclx1MDAxZUPyNlx1MDAwNK9NXHUwMDEzflx1MDAxOZfvY/NdfD5vqWFfVUydhEv31LQ/y1O3fH7ML2I06Pt2+dPnM//r33/rvlx1MDAxOMWt00WMXHUwMDFjrGh8zl2hPMbi73DfR1Ov1pXbw4bGZFx1MDAxMsmk6LQ433bfn356XHUwMDFi76mLg1x1MDAxZjtcdTAwMTAm0Vx1MDAwMz0oSZNcdTAwMTD9XHUwMDE2O4+iqX5cdTAwMTlcZo82qt76/N/eNfhcdTAwMTfAXHUwMDE3XHUwMDFkQd/u7DliiSyF5T9cdTAwMGJ6gVx1MDAwNt9cZnxcbqFfXHUwMDEwXHUwMDE0QVGIQkiIIMlf4J54Qd7wSqD/wv1/Ku7Rv1x1MDAxOffwMWTEMY74V1xiP05cdTAwMTJcdTAwMTD9q7gnyGOEqCNcZv5cdTAwMDX8f1x1MDAxMuD7XHUwMDE39lL4mlx1MDAwNtv2oj1j0rgzRv018MdkXHUwMDFkv8Q8itMvXHUwMDE4SlNcdTAwMThNIFx1MDAxOERAyFx1MDAxN5jHUepcdTAwMDXHMPRcYlx1MDAxNlxiQXCc/Fxu8yj8XHUwMDAyUVx1MDAwNFx1MDAwZZPwXHUwMDExM1x1MDAxNIa+u+Qz5lHs5T3i3zHHvyD/XHUwMDA15ImPIf/F1T9jm6BcdTAwMGaqpVxiXHUwMDE4+Vx1MDAwMNtcdTAwMTjyVab/XHUwMDE52zhcdTAwMGXBXGJNIX9cdTAwMTW0v2cwv8Xma0xcdTAwMWVP32XvRq9txmuxvzZcdTAwMTghX2j8ndyEyC+uXHUwMDEyg7p4fFxu1S9uyDyKrPmE4CR9XHUwMDE3XHUwMDE1R2eMxaGnP59cdTAwMWXb7u1sdNwvKJqk/3qM2r7IiiZ42Fx1MDAxZjQ2mMbWSoZcdTAwMWabO/ZT8r5cdTAwMTdcdTAwMTL5Z1x1MDAxNMAvXGL+XHUwMDFiXGLGmkRlRUYkylx1MDAwYoqfnEcoJWHxLVxipkjqhXjfQ19cIlx1MDAxODvE/KuGR1FcbsVw6mtcdTAwMDTT8Fx1MDAwYk5gMIRcdTAwMWXpXHUwMDFihjD4LVn8XHUwMDBiwH9cdTAwMTTA9Fx1MDAxZlx1MDAwMPAnTVx1MDAwZb1Psm9cdTAwMDDGkV9NzuThv1BcdTAwMTIj34bpO+Xmf6xcXPdcdTAwMTU9vMbN1P1cdTAwMTNRxC9cdTAwMWL8fWhcIqPOUD3N7oWi+FmTXGa1diH+2609cnDFO1x1MDAxY79cdTAwMDP7a1x1MDAwNyHo2+8/01x1MDAwM4XhL+TrpT/18Fu4fqZcdTAwMDeCwP6hXGJcdTAwMDH+xfG/IyFw305cYlxijFx1MDAxMDhGXHUwMDFlXCLqo4xcdTAwMGX/KiFcdTAwMWPunqJcdTAwMGar/u59f6eU/lx1MDAxYmF7PXM17LjIXHUwMDFj3Fgjd1xy3nJU5+uwLeog+0XIoij5gpFcYv3mS79cYllcZqNfiDfHXHRTX1x1MDAwNTBcdL1Q9Ieu9nNcdTAwMDD/+iW/XHUwMDFizlx1MDAxZobqf+mQlv5ASKM0hmLEx3Wnd4XDX0Q0jUEoTrzTsH9viTqMwThccp+6O5iT+ItcdTAwMDH8sa/+hFx1MDAxMTiNpFx1MDAwMZLQKJRcdTAwMTBcYpyGXHUwMDE0XHUwMDE24SRcbidcdErFSVx1MDAxOOAkjkJcdTAwMDH2boCPJJN8kZQ/t+348auUXHUwMDFh9UdcdTAwMWX6sbm/gTN4vCbmOmHhPNdwyCpcblx1MDAxNrZcdTAwMWZcdTAwMTSAPsDZXHUwMDAxnlx1MDAxN1x1MDAxMoJxmFwiMOrIXHUwMDBl2C9ghr3A70vC+Fc4o4hcdTAwMTf0kJnIoTLJI1mQ6O/jjPhcdTAwMTfOflx1MDAxZGfKXHUwMDFm0JIwRiPQMWZcdTAwMWZqyXdy6JdmkCZRXGIj/nG84DdcdTAwMDBccqJQNEShXHUwMDE4XHUwMDBlsDhAQlx1MDAxMiVDXGJcdTAwMGYghICTV67BoOjAXHUwMDE5ToX/yUC7aoqXW0hn08nZ+ctcdP3zs4yYb7FrXGL2ZYmFoF4+wFx1MDAxMoS8QIc9oPBcdTAwMDOJXHUwMDE0XHUwMDA1f1x1MDAwMCX0hYDeveBvh9J/O6xcdTAwMDdcdTAwMWMh/4fASPt2XHUwMDE4YTiEQ9h7a/WGXCKY+PVpksOPIYeF/uss2a/hXGKCXmn24Mq/xTSxnzzIXHUwMDBmQVx1MDAxZuXFeFiCqU9+SNv+h3M7jFmfXGZcdTAwMWbaKVx1MDAxY3s5ssDb/1x1MDAxMP7FVZ/tXHUwMDE08cXHffZL0fFkSf+fYKi+/WG+2Wqhv2W1cpcv/6zLT0GERsJ+wPCA6P63QFx1MDAxY0PhXHUwMDE3+Fx1MDAxNZ0wgZBcdTAwMDSEIW9j+CmoXHTshXqttlIwgmFcYoZ+jX9cZsdfjqE/tC9cdTAwMDZcdTAwMWRcdFx1MDAxNSU/mEnB0JeDanFcdTAwMWGmSPxcdTAwMTBcdTAwMTf/8mC/xlx1MDAwMMa3M1x1MDAwMH1cZtaRuqiPXHUwMDA0K07gvzz6M1x1MDAwM2DH+yDsLc1+jzT6alx1MDAwNFx1MDAxMZwm3ofuXHUwMDFmhb+V1O2Y/Fx1MDAxMLXd9lx1MDAwNWw+hD36XG57XGJcIlH8oFx1MDAxZVx1MDAwMsLhLy76jHrqi0/5zy6i/P5cdTAwMTN8n7LKb09M/aLw9SXYXHUwMDEx5OWQvPDnec9fzpqiLyRJvs2hfIB1+sj1r/5cdTAwMWRcIlx1MDAwZZmNvuH4LdlcdTAwMWaE8cncQj9+0Fst4Lsk+/+Wfnr9k9dei49h/vV8KfLTka/mS1x1MDAwZlx1MDAwN4dcdTAwMWaYgz5CP0n8+nTpob6xg+/p705cdTAwMDBH3JDY+3j+Vlx1MDAwMuja4pdcdTAwMTXft59+eIuWT798/vl//PuHV+PEXHUwMDBiXHJjXGJ12LpPf1wi79/9569qJ793O5SCXrBcdTAwMWbtXHUwMDFmQcPkW6X7x9uhR6i/i3X69273q/D59Gwv9NvUJoxD6LvbfSX8XHUwMDFmwTBybV1cdTAwMTfjMVxu59dcdTAwMWX8KkuMQT+yR8hcdTAwMTVN9mVo/bRcIkv5huVXn1xiNfrkcv5cZr3ANFxuXHUwMDFmOVx1MDAxZaZcdTAwMGbngtA0/u6qLOjeo+VcdTAwMTMu1y9b9lUkJ038++377VVcIu/aXHUwMDA3vVx1MDAxY3GIwsTROlx1MDAxODvMXGL1QfNeMPpcdTAwMWS9UV9cXPL77f3Uo8wrq+ZJXHUwMDEwf0Cxx1x1MDAwM70//cVwJI+wXb6p/Pjb61x1MDAwM36T3knkXHUwMDA1IWhcdTAwMWHBXHUwMDBltVx1MDAwNqFcdTAwMTD0Jb1jXHUwMDE08kK8QePopa/4XHUwMDFkPbRcdTAwMWNNoDT0Uz99YOZcdTAwMGWzR9E4iaJcdTAwMDe4iMM8vyWJ3+f3XHUwMDA0Qo8h+j+A38u/md9cdTAwMGY5fshcdTAwMWFcdTAwMWH/UN5h9K+WSWD49W2HXHUwMDEzelx1MDAxYpfvRfDogf6/O8H/aoS+vr6KzX80XHUwMDA2hVx1MDAxMFxiwUhcdTAwMWNcIuDDXHUwMDA2oUfWoN5d94/AoVx1MDAwNy3SKI5cdTAwMWRcdTAwMTR6eGmSxt6mz//KXHUwMDA2fkWaX7Lil4z5XHUwMDE1oX4zaf72hPBvkiZMXHUwMDFk1vpNXHUwMDEyv0mnT9OwXHUwMDE09YL9mPp/1FxyX0tiXHUwMDAyf4FcdTAwMGWcoiT0OvP4pjjeKJM+JPFcdTAwMWLrXCLUXHUwMDFmKCX/n0OZj7+ZMlx1MDAxMYhcIl7LXHUwMDE4XHUwMDFmXHUwMDE1lol360B+uUiBhNHDSb8rXFx+J8I8MvFfV1x1MDAxMfu+ilx1MDAxOH15LbvQn3VcdTAwMDH+/u1fhebvK2L65d1cdTAwMTJcdTAwMWTiy7tcdTAwMWSC+IvF+L8riH9ccjyvL/hcdTAwMTDEX6iZfyw6P/Tw60Ik8rXqjVx1MDAxZobioIqvuFx1MDAxMjlcdTAwMWXh58leXGI72Fx1MDAxNHl/o+/D7r+9XHUwMDE464tcdTAwMDYj6EFlNEHgXHUwMDA3Tt5Ner1RO/byXiBcdTAwMTN/qLH/PzG9nvyls6O/WMtcblx1MDAxNafweTXKfam+eVFcdI5cdTAwMTAv8DvP9mW1XHUwMDEzIY+Yw95F8Fdsf8iKXHUwMDE3nP68XHUwMDA2XHUwMDE1pz8odlx1MDAxZTFNv0brz6j7zqvG/1x1MDAwNrr/XHUwMDA3KnTOf2DG8KBn/Ei9+IfLR7FfnesgX7FcdTAwMDeR7zLyP95ak5yuqv4qe3ZcdTAwMDRtT1OD5Ii6eN9St8dR+OXVXCJgMFx1MDAwZeEk9m4tyadAPqxcdTAwMWX9blx1MDAxZMrXKylcdTAwMTGcfCFR+Ihj9LD1XHUwMDE4+oFswY44PshcdTAwMGJBcVx1MDAwNMdoivrORfv/XHUwMDFhcbz8gTg+XHUwMDA2i8SQj7c4YL8xZ3fIU1x1MDAxNKFg4u++aOotLn8qef88nfVD1DbNwbhHq/+/5v96neiqgybIPrXih27qu3ZIhv/7w1L+q/w+lDdCYzBcdTAwMDRcdTAwMWaIfSeZvqWW/582g/fXPtpcdTAwMTc1/i977Y9cdTAwMTT5z5epz5XFbohcXM1uN9PWylH+9jSHXHUwMDFm6uR9qedcdTAwMGJ2wI6zxFt+wr42NVxi9MpcdTAwMGU/KrzXXFyIf1Do/1ea+1x1MDAwNnpY/8BcdTAwMDK0T7ufXHUwMDBl2fVRxYdAf73ig7yO4ZFcdTAwMDa+79KYY/iPvPJu+uZvynM81rtaNv+lvEVcdTAwMTg8XHUwMDE2Vnpzl+ib8txcdTAwMTGrOEHS0PGQr1u9flx1MDAxMcnEkVx1MDAwNd/pNeyDSMZcdTAwMGZPQlx1MDAxY+fR15lcdTAwMGbqg0D+ZZ77zjtcdTAwMDb+a1x1MDAwNPL2R5amvFpf4sOlKST6q7t9XHUwMDBlJ4VcdTAwMWPu4/06779TXHUwMDFjf5XmrGFrolx1MDAxZn5cXCR/JIEw6I9cdTAwMWPww9j+0P2UJP65UttcdTAwMWZ5nO+UztTbXHUwMDEwnYWhuC84sZb42VA8JvxcdTAwMDPpXGY5zDbxeW/Ql5v8j+Mv6Fuh4GtcbjhsLfm5YHFQxb8821/HXHUwMDAx+1x1MDAxZtC60EHNXHUwMDEwRX64Y4iAfnV1yiE1iMObk9+9XHUwMDE490fXp/xGLFeX5/zn7HKaXHUwMDEz0Vx1MDAxOFCZ687PXG7+tlxchr/gh5YnXHUwMDBlRkKxd2vKP0UxQbzWod8qdVx1MDAxZsQx9EJRXHUwMDA0iVx1MDAxMjh6sFx1MDAxYYV9sGr5X7ns9+M4hH7layo+3ulcdTAwMDJcdTAwMWbkXHIhXHUwMDFm7l0lia/C+3M2o/HXr7J4Tzb/KCutfuT7vyzB4y+flinNyZFcdTAwMDR+pv7XNPDjXHUwMDA1/1xcOe2PP9R3ymxcdTAwMTOFXHUwMDA2W82cUPWkhbM+XHUwMDE2q7p235zZMFx1MDAxMnpB3ra44dSXO4ZcdTAwMGXh8oJR5M8rQsivV2Qh2Mu7JSMkTn8gcJHXKdOfdsVcdTAwMTPoO8f/fTjhl6u2/jk5XHUwMDAx/lx1MDAwM8nttVx1MDAxZYlcdTAwMTHku+3L71x1MDAwYpK/qnBcdTAwMTHoXHUwMDE4alx1MDAxY0W++9or/HV/7vdJbrikmcjlQUPxXHUwMDFhPk3qz1x1MDAxZNzx+Tclt4NcdTAwMTmQnydqYIpCflx1MDAxMcj0y+tXLnxe4fRBdqNfiPczrVx1MDAxZlx1MDAwNfKvXHUwMDA3+/dZXFz414fyP85Malxi/cq3sXxcdTAwMTjKXGJcdTAwMDRcdTAwMTGHsaa+UmSvz0R8tb3zrehAXHUwMDEyr9/ogNN/71j+Kr19ULj7eO/AXHUwMDExcF/OL1x1MDAxMl9cXPWPVHn8a/ZcdTAwMGL8ZtZcdTAwMTJljDn/martv8SnhSBcdTAwMWFcdTAwMDLZcuxcdTAwMGZkLfjli22uX1ZlSJp8gXDot+qL6Fx1MDAxN4t43n29z1x1MDAxYtZ/9ZLvk7V+ubDinzNr4X9cdTAwMDDqXHUwMDA0XHUwMDA14ThcdTAwMDbBX1VcdTAwMTJfY/w3plx1MDAxZmDsyHXQ0V3fXHUwMDFi6jSFXCLfKW1cdFKWsFx1MDAwYqWseOF6rsFF2KWyviltIdDh/D/QRj9cdTAwMDYy/buB/NFcdTAwMTLJvyVNfcuCn/9cdTAwMWFp6lx1MDAwZnyDXHUwMDEwcrjd18TwUehcdTAwMTJfXHUwMDFmfZs5Qyjy8G/vNjX9nUL3qyz1qVx1MDAwNlx1MDAwN1x1MDAwZUP+T5umfudcdP5wnvq3n5bz/Cnouut49Peffl7z8qe5SFx1MDAxNvbXq1x1MDAxMf/2XHUwMDEzK3zaefu2aOzb97m/La75U13Uif1+5znYNe++P6n4KzfQXHUwMDFm8Vx1MDAxMziW/vrm11x1MDAxZv/j863/nzBcdTAwMTiSI39cdTAwMTYua1pcdTAwMGKkSVnLXHUwMDFjr9PVyVx1MDAwNSc7fpJf/2AxjvFej+M+XHUwMDFmXo+/M0Z4XGJcdTAwMTfXwu5cdTAwMTNcdTAwMTJz8eo6YCo/iKqqXHUwMDAyjb22ztZcdTAwMTl52D4szsBFXHUwMDA3qlx1MDAxOLuuXG71wXhcdTAwMGbRc7ZcdTAwMDd/VYrH5VlcdTAwMDSWpXGOKjrKU6r2k1x1MDAwMJMgXHUwMDFko2gzn4dcdTAwMDTHyVx1MDAwNp2n7TTvIFxuXHUwMDAxXHUwMDAwaqZcdTAwMDeR7WRzN9FmXHUwMDFhaXfs5etcdTAwMTks4ZzEmD3GXHUwMDFjdVx1MDAxNFx1MDAxNzdcdTAwMTRS1GhcdTAwMDHIXHSDOGiotEN3ukdWcUBcYlx1MDAwNDxcdTAwMDFzypF3Wpxm1aNRoFx1MDAxNnO0kM5kqnfn6IaK41x1MDAxOXmEPoCAPinFS1qaepDenb6zulx1MDAxYodDXHUwMDExU+bMZcteL2tIKO0gcFxuXHUwMDAy5lx1MDAxNFx1MDAwM01cdTAwMThcdTAwMDTIs+suXHUwMDE0ry4yXGIr3Fx1MDAwNM1cdTAwMDE89n3oXCIzbq6tPHqbXHUwMDE1Lueal11RP1Njb8JDaJNeXHUwMDFhXHUwMDE5Jlx1MDAxOMBTT/qn7EbcUpTyMWwpqjr0+qyFj5iPyVhLaGQgNFx1MDAxZogweqw7gFxcbPHsXHUwMDE5YLqUZX2qkMLxmVx1MDAxMo9LumNvKDw+kIo85dXdz+FyXHUwMDA0yVx1MDAxM4QhXHUwMDBiSpuIZuwnY91vXHUwMDEwXHUwMDFh3E85MflcIs1vXHUwMDFj+tg6V9+6S+fBPZtlziNcdTAwMDVJqpvu+uOgXHUwMDE5aj5eIDXNIEk8wVx1MDAxZEFcdTAwMTCwhpCmh1x04Fx1MDAwZVx1MDAwN+N9Q0FwXHUwMDAzjUiwZvixJLDtXHUwMDAwkL5cdTAwMWGWoehj/0TKsTP3qeOj6X7Sh5su7lxuOqMkndJcdTAwMTNcdTAwMWH6O96l4GJRmElcXClcdTAwMTDuyiChmlx1MDAwNEaDdWz5oM50pnVcdTAwMDJNaGRcdTAwMTRB7npcdTAwMTBcdTAwMDSRr6Scf0LoxLzzWXbet21cdTAwMDM3iqLAmlx1MDAwMmJcdTAwMTNNtbWFQjxcdTAwMDDAWqi26ITjOFTHZnOvimKaKll/bFXdOc97NZknrJtcdTAwMTR+eVx1MDAwMFSiS1x1MDAxNE3j5FDzLDM3zydBXHUwMDE18q3wwZE9IVS6Nk5VyZmUdlxc2vdcdTAwMDG8m4Zw01x1MDAxZZZyXHUwMDAwaVxi4lZcdTAwMTThNTO7oDFz5TJwZ8j2XHUwMDA3pFx1MDAwZdJDs1DgyVx1MDAwN3v4idhnXHUwMDEwpFxmYiQxoMKWcGCZvkGQenpcdTAwMDTj7Vx1MDAxOY2u61JcdTAwMGbfXHUwMDA3q9S3XHUwMDA0XHUwMDAyh1x0PHq6uGZcdTAwMWODcDydojVcdTAwMDL8hMMy4OVypeYr7lxylE9oSVrBoY3AR6jAZq24kSjQy3VcdTAwMWRcdTAwMWZ022A12sJabaPyvu+Jp56BwLsxVFxi9spZttuqQUFgSpolv1xm923c8IhCQ3mplNE9XHUwMDA25qGR8Vx1MDAwNHvAJk3kXHUwMDExXGY0XHJsPkjliIOGMZQjbPra2Zfz5lx1MDAxYn2Hr1x1MDAwNNU+tlx1MDAwM/rNVtQ4g6Fz29xPRe70vlFcXFx1MDAxNFvd8WrHb1x1MDAxOD1jIVx1MDAwZoD+XHUwMDE1XHUwMDAxx47SobysLpdcdTAwMWXym4Ar28ZcdTAwMGbKXHUwMDFl6W/9MVhXy8HoR+R2QSszOFx1MDAwNaQ6XHUwMDAyUJRcdTAwMTdcdTAwMWFNiYa7NGXuXHUwMDEzXHUwMDBlusdcdJs0PadYXHUwMDFhlFp5MFHWizrEu4Dqc1x1MDAwNVKtvlVcdTAwMTdOXHUwMDFlPLPZ+51cdTAwMWNcdTAwMWbo8Jz9uLrXiF2WJKi015Nflky+Uo9cdTAwMTWUxSvZ7ZwzS5zX6Djg3Fx1MDAxZqBu6JsuWKqOI6T7xFx1MDAwMYAg8cg4n0Er2aCebltcdFx0Y3l6xCDN9cUjnCdu7HbzYjc4Zkg87lv2Ulx1MDAwMNeZlsI7OI+nuVlcdTAwMWY7XHUwMDFhxMN4XHUwMDA25vquXHUwMDE3q1x0XHUwMDFiXHUwMDE4dXWnST71XHUwMDE4z1x1MDAwN4BcdTAwMDZcdTAwMGJYg68pySxd1PTJU6BcYlxuuG5+NFx1MDAxYnexeFxcO9egqT5cdTAwMWPvcq+T+pM4XFxcdTAwMTPxXHUwMDFjUj8yb02o9igk4FSVtqDxNE1cdTAwMDfD7FlLXHUwMDFhYdBwaih9p3WMJzxskXqldHu5LkdWXHUwMDE23P40tHpcdTAwMDRcdTAwMDdtxVx1MDAxOOebvWB4cI2oXHUwMDBlvFqJtYlpXHUwMDBlg1v1XHUwMDAwJYBnkd442GvDXHUwMDE041xcV7cwXHUwMDBmUIJcdTAwMDbvXHUwMDAxXFxdyH6l2Fx1MDAxMy3xs9lGhHKx7Y6zXHUwMDE0KNWae/qqZjyZXHUwMDAwU6UxQLTgdVx1MDAxOEFudzQoiSGQK/T8qE6qyK15foe5ITObwYBAtEOg1Vx1MDAxN/BcdTAwMTDoa2qcslx1MDAxZLg756AmKU3upPuEYlx1MDAxNGHdclfd9q724VVQgNFcdTAwMTVcdTAwMDPErkpcdTAwMDasNlx1MDAxNfBlfPX2YeHRnn+usT7U1VRdTuSFRWaSnuBccjrMxJZcdTAwMWVcXFx1MDAwMMA8NEhoUJ9ZyZItVlxcrzS4OjXwiMVqtrtcbrGJ8dbn6760qFx1MDAwM25qgZ5Lf1x1MDAwZbVuIVx1MDAxZlxy3lx1MDAxZDJcdTAwMDaHevh6NMipXFxvUVx1MDAwZVx1MDAxZJ1cdTAwMWVcdTAwMDFjgWrMupNumDVcblx1MDAxY2lJQCa9SO93VGJcdTAwMWKN5XtcdTAwMGaZ48DCXGLjhvrxXHUwMDE5qfTUIFx0kVx1MDAxZqezp1x1MDAwN1ivI2jvlpeywM58vtB6vfujf9Kqa1x1MDAxYVx1MDAxZbe+pub4XFyK1lx1MDAxNd1Mrb25Y27LXHUwMDFksVxmN2fu/LpaXHTJ0lx1MDAxZEgoJSSX41x1MDAxOT3IXHUwMDFiIPNJ7YhYL0bXUskpVsyoPvgvRlx1MDAxM1x0hLDSXHUwMDFm+rq55Zen47By6IdwuFx1MDAxYeGzu6rVhTmLNt9cdTAwMTWEe8J9uvIvuiZ6S1x1MDAwZl6J3vOXefeSNLWsJC3zXHUwMDFjgERJXHUwMDBluOfYLoLkcm6mJN1jTnFgX5dsmK/6iJDxwlx1MDAwZqdcdTAwMDIjyVxuxcNx1Oykmaa4mljSnl1JiUQ6XHUwMDFkXHUwMDFlxz1cdTAwMTFElTLiXHUwMDFhXHUwMDFl9OdcdTAwMWNCkfZgoJfQ0Vx1MDAxNs7oUlHoNnB3kcqSe3R5cKOfkklcdTAwMTeH3ZNcdTAwMTZrU/MlsWdS4/noh1x1MDAxMW1OklAyiLutXHUwMDEyPqdSac16QFx1MDAwMHmR3ZZ0PplEWkK2Zlx1MDAxNFx1MDAxZDPiMSNsRCCGXHUwMDE3ICy2y1x1MDAwMDxcdTAwMTJpnnFgulI5JLfhpW+RqXpMz8flaHqUzlx0cScpXHUwMDA08NOqlVx1MDAwZfiD/XxcdTAwMDXnW6hkXHUwMDE0ynFcdTAwMTTKLv0zq3hpndqs8jh/slx1MDAxNfo6y/l6XHUwMDBiT3VcdTAwMTlcZlx1MDAxMmmPmKW2tDnWQzGaqlxuXHUwMDEwT/+4XHUwMDFkXHUwMDBiXHUwMDFi91x1MDAxZb/l/Yab+OZcbmcxgaPi9lxiXHUwMDBmzVBcdTAwMDZkf3QriIZ8R03wmVxugI20TsmT611cbobCa4275IXpSdVcdTAwMWJvVNv35FqEmLf6Mlx1MDAwMzGJkVx1MDAwMVx1MDAwMlx1MDAxMVx1MDAwZUm8Zadxmig07oDEXHUwMDFikTug0kA13s69XHUwMDFidkyDMJGZSVx1MDAwM3gjwvGUmlx1MDAwMGjOuongQVxiS/hcdTAwMTSwMX29Uk9n6yW/XHUwMDE1aihpkNBZpWvWTr2p7C1ameaZw48nvKi3Xjx6XFxhWVDj0pm5T1VJRtK+KieAVStGXHUwMDExuaG46e5QWVx1MDAxOMk44Lm2gOlcdTAwMDFC816h0ji39IrqsrzNNqBcdTAwMDe2XCJdRH6baJKnujEjQmVcdTAwMWap8kZa1JHeVFx00SBCpmX7MFx1MDAwN0Nokb5y1Sv2ZElcdTAwMDCq46fiTCjnajdcdTAwMWVcdTAwMDeeN8tcdTAwMWbgpelcdTAwMWKG4/VcdTAwMTCIqN7jrqpQw1RTwiTdWWyGM+hcdTAwMDVTlWXH7IN3z09cdTAwMTfokEei30ZccnWjMEQgKlx1MDAxZPiGaM9wuFxczvh0ULZcdTAwMWKNNaJRa95f0lNcdTAwMDF13Fx1MDAwNk5cdTAwMDAmhk/y0K6dUFrYfkqNyExcdTAwMThHMiV+ebJcdTAwMGaMjVYvZELYXHUwMDAzXW5cdTAwMDbnyVx1MDAwNIyB4Y5cYto9/YnaXHUwMDFjXHUwMDAwhod+QSNcdTAwMWG4QT2el/Mtut23XHUwMDEzrOmu21x1MDAxOFx1MDAwMIhuOMr7VF5cdTAwMGKtzV57h5axXHUwMDExXHJcdTAwMTMsXHUwMDA2wCSbW4c1e2GKn55fXHUwMDFhai1GoYCXTlx1MDAwZtMp2iz7XHUwMDAylVdcdTAwMGa0wmFm7dRcdTAwMDS7XGZMxyNcdTAwMWXzud9g8HTk+7GlI1xcmfIq7Nq2XHUwMDE0K+90XHUwMDE3Uay2of2Ec4j2hMxcdTAwMDNcdTAwMDCx5Fx1MDAwMYqwXHUwMDFi0v2e91x1MDAwNUjJXHUwMDE4c6+yXG7jc25cdTAwMTLWqj6owfWI2ODOOlx1MDAxMlx1MDAwMs9TvM+68OiWOVx1MDAxOdeotJ4nXHUwMDAwXHUwMDA0XHRcdTAwMTRcdTAwMDaI1EFdt4zxxKnRIZOaaS+SZlx1MDAwM56z41x1MDAwZTazhSdcdTAwMDAh2fkpb45cdTAwMGJcItItXHUwMDExXGalWeRwXHUwMDFmRJu9Y1x1MDAwMdlRNz3DXHUwMDE4f3eR7XKeXGZcdTAwMWZcdTAwMTlNXHUwMDE56Z+edCqDxulcciCsTXB3XHUwMDFjXHUwMDFkvVx1MDAwNrZJurvuXHUwMDEyrYshss2qfL6ZdZJdomlEQIoxXHUwMDE3J85cdTAwMDbnknGXXHUwMDFkPfK6lPZcdTAwMTKj41x1MDAwZpBcdTAwMDZcdTAwMGVcdTAwMTm+JXEu0Wnj8/aDqnpcbpFPXHUwMDFkQ1xyrnZcYthcdTAwMWX2dqtHmrSYXHUwMDFidChph9Tr6fa4UoZRrilCXHJR7UGJJi/7mT9cdTAwMTkmJOdZl11ZvV4g5T5ZuVu9ppHcXHUwMDFiuDo68fnTTlx1MDAwZqGI+L3Er3dcdTAwMThxzrG8i1x1MDAxOd7r1Fp6pkY2VKbQcUn1gO55XHUwMDE4YFxyh1x1MDAxMVXypJd21U/dQ8KyXHUwMDE1YUyswU08x22UXHUwMDAziDhbnu7n8VxiPZu+zLeZeSTdfVx1MDAxY8OiRpZZuvrYhHGnR5ZoRzjw1S7O3TTjXHUwMDBiXHUwMDBlXG4mnIxcdTAwMDDCVaOMmvTAi+ltkG1qyMOSRnMyi2AupTFBPkPQtt1IO/JCzFrFXHUwMDBiXHUwMDE0m1x1MDAwZvvwXHI0MGww4lq+R0RcdTAwMTf6XHUwMDA0R6temkzgX2RdhfRZtGNcdTAwMDJAXHUwMDBlnWHGYb9fz+lC79R24/GLL2T0XHUwMDEyV/tYIWLus+54XHUwMDBirczbw43Ls/1cdTAwMDE/UFx1MDAwNCdKXHUwMDFiv1hRkD5D4NDIOnlC/XuTjU6Ie8JcdTAwMWRT7iC5nVx1MDAxYi5KdVKI51x1MDAwN7g17MlD7lxiXHUwMDE5KFx1MDAwMST5e756fcNzZa95/ogwurx0OJhR7EA9XHTEdimeunXZrEKbp2iH27HVcFx1MDAxOUhcdTAwMDbG20lcdTAwMTT1YFdXVnKMc/dcdTAwMTCNToj0+lx1MDAwMe/PoEVdskYh5F7p52a50sSIiKyt2Vx1MDAwNFx1MDAwZouQXHUwMDFh8Wtm9573lFGIWMSEXHRccsGAr+qhpZuNQFC28Jc856Squebr895sJ4bEQkZezjZzkiWI0XSOVCT0SpLZjdyJelx1MDAwNU7YZlx1MDAxZO61L4WpuZlcdTAwMWEjX3aMXHUwMDAy08vlkY2UVuZHfFx1MDAxOUuqmlTKVCO7tMPtrPsxrY9JXHUwMDEyXHUwMDBltMbCzaU/LLvIgFx1MDAwN077XHUwMDE4h125M1x1MDAxYiPYR9GSrmpcIj1cIsg37qSTIHm0XHUwMDFixCGgn3eUXHUwMDEwd7PiyynJXG5vXHUwMDEyo5an2XDBLMMkfFRe8ID2himRJInab4SP8dFlLuTMSp9nXHUwMDE0oVx1MDAwYtGG6Fx1MDAxMibsxpWCtH70NY+QXHUwMDA1clxm+MHbccFcXDDP1lx1MDAxZlx1MDAxOVx1MDAxNKii8zQkP1vuvXlcdTAwMDGorPXOUbmcRlx1MDAxYVx1MDAwMFx1MDAwZUd4ZjB5OsWeR/tcdTAwMDZcdTAwMDfjxKBcdTAwMWOugV+Z2SdpzO5wn9PzqymweFx1MDAxOFxcntnY4Fx1MDAwNjQmuFNcZkgjk6iyXFwuozXU5HbpXHUwMDExmahawTRnyFlutu9ijyU6aUiIgoPaXHUwMDAxNFSLUOXG5zI8WMDn71x1MDAxONjBXHUwMDFhRcGi5XeLQNJkvmLLku+LWl1cdTAwMWTTXHUwMDE5aKdqXGZbqqDFy9OT0J1GY0qu3Vx1MDAwNO+3pc38jbaV6iayJoyk6SmzXHUwMDBmXHUwMDAx2WlWXHUwMDEy321OuERcImzQ61xioLcz5mjnuoejeMK1/nBA+jFmY4qVdHo/maVcdJ7xdoZcdTAwMGZcdTAwMWF73vVcdTAwMDZHXHUwMDE3vT5cdTAwMWJDmlx1MDAxY1x1MDAxZlx1MDAwM0rnXHUwMDFk4Fx1MDAwZvNLo/SU1JGPhSsmjN559fJn3O2UuDT2QIFeOFdbsilcdTAwMGVIML2bmWE5T3a92WxcdTAwMWRy51x1MDAxYlx1MDAxMmyg+1SYvV31orkj+c6slFx1MDAxZojEwpTOdYey/UK71NZcdTAwMGKLmLNPYXJcdTAwMGZHwrRcdTAwMTNm2uhB8PBcdTAwMWOR18Nqc4c4yUUqXGJZR8JcdTAwMTeCgWcm1zNL51BcdTAwMWGYb/ZBlmSdQdnxUM+Dx51q80tcdTAwMDZcdTAwMGL228XgibzyaNDXsjuLxFx1MDAwN+dgJUl151xieFxck6bzXHUwMDAzj4WlWIlPvmRcdTAwMGb3XHUwMDAyOuX7QVx1MDAwNDifjlx1MDAxN0J50kVzMiVwuku+plx1MDAwNSc+XHUwMDExRFpjuKFcXFx1MDAwMvpcdTAwMGWqdFx0eprUxmBTrnhuUJnBRzbtP9RF290yXHSjpyiUSYrCJd/kyISXO3OrpVx1MDAwN0lcdTAwMDZPe1x1MDAwZl1cdTAwMGXBRlxyRtdZIyuKUIVzqlx1MDAwNVxc7D7VJW3Q8LpcdTAwMTbcrMBOvfeWRYu67HCQXHUwMDA0onX0cNZj+FrMSN2cXHUwMDFhzouOXHUwMDBmRlSAiKXMXHUwMDEyjVWLOutcdTAwMTKy5c+UXHUwMDFjb1x1MDAxNTic8KI9WValuVxiMUq7V5lSsOCaaF1nV5PB5Jaq3IixXHUwMDA0nt1cYsNcdTAwMTRaXG6OaYVcdTAwMWWBjVju2E4ju9osj6Z9XHUwMDA2/rpcYlxms87AtN9cdTAwMWNcdTAwMWZbZbhHJ+mqKVTSXHUwMDAy6Vx1MDAxM5ta55I4/W1g26bRXHUwMDE3iFx1MDAwNa/3NTH4TJpcdTAwMWKC4OpgYMt8icyGXFzXlrtcdTAwMWTEcvJMXHUwMDFjXHUwMDA2z+FxpVx1MDAxY0u2J1x1MDAwZszNODIkNWZcdTAwMTYkhGZoIFEmSX37hMaKmPQzqGIgOSHPx1x1MDAxNeqWvfXGJ6ZvTHje5/WCziT2hJbhWlx1MDAxN8/U7VwiXHUwMDA1duGyXHJcdTAwMTe2XHUwMDEwZ7CIU4LmgGve3XVkICSdx4JxXHUwMDA3xfRcdTAwMDEk4CGb5+SJhitcdTAwMGVJOHBR4kxcdTAwMTOcoS6C9vRgXHUwMDA2TdymLKY9gdxIolx1MDAxZXc7Ok99XHLexIK5ub5FruO5buV7XHUwMDBmXHUwMDE3wWQy+WRwV2XLw+XokjJYjYo7T9frovKbsqMzzrLVpkkzdVx1MDAxOVx1MDAxZFx1MDAxMzDHTGLQtSCm6cFptPo0T9uF7263XHUwMDFiJ1x1MDAxOVx1MDAwNnmCz4dcdTAwMTAoRFx1MDAxNebJjOUulVxiKXUueudcdTAwMWN4slx1MDAwN/1cdTAwMDKeXHUwMDEyXGb7fHjo4DlQ0nk7oWvdSbrM7JKbPmfupO3Ys+/n4SzXg+xtXHUwMDExI/Pj7XlcdTAwMWE5UzJRXHUwMDA0Ylx1MDAwN0ypvVx1MDAwMaHG3Gjs7nLTvVx1MDAxZHV40m51XHUwMDA1Kamk7qBcdTAwMWJccpVMuFx1MDAxY4yCXHUwMDBlXCI2XdbneWdcdTAwMTBthKEjsFx1MDAwZZs16pO2gmhOSFFcXFx1MDAxY0JAqOD2Zlx1MDAxY341XHUwMDA1TSu+lJdqkZJcdTAwMTO59lx1MDAxOVx1MDAwM1x1MDAwNa6yPy1cdTAwMDJcdTAwMTMhXHUwMDFmOVx1MDAwNfNcdTAwMWFw3CpcdTAwMWGJlLhnzSxcdTAwMWYsZUDn5t4mt2vYqlx1MDAwM5t7XHRcdTAwMTRS/Fx1MDAxMzCyWVu1nWvqMUGtXHUwMDE2i0KpXHUwMDEzpmpcdTAwMTOG9SRcdTAwMWapOlf6hm7TU4nDPcbmtXeTVfjoUlx1MDAxNSEsjr5cdEiPkXdcdTAwMWU8spbdTdC6XHUwMDFm9iMmm1xuOVx1MDAxZd6esNE6dLPT3t2Cfj40J9XZ2VruUJtDq69cdTAwMWKWZ13OfXl+nEf5XFxcdTAwMTYqTVFVjZM7hqbKXHUwMDFlc7HSnNyTwDhnJ1x1MDAxOIg5TubDZKVJMsyxcVx1MDAxMEu6XHUwMDE2ioBOXHUwMDFix2xcdTAwMTl1NW1cXFx1MDAxZoRLXHRQKzJ1ff+Aiaeqq4NcdTAwMDdcdTAwMWW081xi5uKBXHUwMDFkXHUwMDA2XCK1XHUwMDAyJi1cdTAwMTRodi5KKUqe5p2ygs/tXHUwMDFilDnNXHUwMDFjndKKQVxyXVx1MDAxOC1vuD1cIiRU3EqCTMePb3M3lICriULbkHuy72vKzrlG+Y3EXHUwMDAxXHUwMDAx2DlgSlx1MDAwNr66mJtcbtimL500oFx1MDAxZmWXXHTaUPBT61x1MDAxOFx1MDAxNvJ0RFx1MDAwNFx1MDAxMixhO4i3/lx1MDAxZY5IffNcdTAwMWVqoEfKPjWkTHA5aWhcdTAwMDBHXHUwMDAwPUpcIo1yUcFEgpHFI296XHUwMDAxxLB+IVx1MDAxYnKz6s3Jo6aI2JvmqjltcGiBUfdWpVCakM/uw1x1MDAxZDPn5mVrj5ap59JcdTAwMWVcdTAwMTdC0Vx1MDAwM1x1MDAxMji/yiNXV/skdSlmMcf9TivG+dwxfb+sXHUwMDE3m+Oiy76eVVfJPX54XG5cdTAwMTZcdTAwMDJTS1lazlx1MDAxMIRMXHUwMDA0XHUwMDE4kXzXekRcdTAwMDE51mes22TR56efm8Pdvc/FjahV48xcdTAwMDSrL7I0XHUwMDE2XTKCu7O31sJrJVx1MDAwMiRuX1xu0cDDzVx0TtJcdTAwMTRWXHUwMDE4yFx1MDAxM3GRXlwiVpZbM8Oyzlx1MDAxMc3rYiNcdTAwMTLlLZvMebZ4mVx1MDAxY3qtZJnPfNpm+1xuj1xmhz9b8KSw43jee96gjEWRlqtT4zMnX80oM6XXXHUwMDAwRlwiIDWNWlx1MDAxNzjdSJ+0/rw7UaOGXlxyXHIwoyF3XHUwMDBiy5iJNr24uNxIzLJl84ItQVx1MDAxY47mXHUwMDE1XHUwMDBm7lRcYplEbaFcckI1wfBcdTAwMDRisZPgK3Bl8Vx1MDAxYrNAXHUwMDE5QVx1MDAwMW5cdTAwMTOIXHUwMDE334N80Fx1MDAxZDTDqZhwpfDlukFwXHUwMDBm8kZx5rkjy4X1Ulx1MDAwN5tcdTAwMTKS/HpKO9JcZtgkgFx1MDAxM8DVi6XeUVtVjljHhezQMVx1MDAwNH6SW5jfS1x1MDAxZbz7dX9OL1x1MDAxNmaCIVlcXHnjVFxmOenA5mxqTeBbVq1cdTAwMWJLgnG9oV1n81lSVn8hXHUwMDA2jemjLJemO33D03TP2Fx1MDAwNc32XHUwMDEybNZ1pWeqNONUVrL+Qlx1MDAxMXLfJc+Wsz2zOHJBnHTRuHO31FCuXHUwMDAzQ5FcdTAwMWPvs7udgGDCgufER5K+Rk/2Klx1MDAxMc8jJ1tJQiQlK8FlRlpnJLHiqbdOvXvSiohcdTAwMDGXVlLdXHUwMDA3mrWMVVliSuyP3mSEw1x1MDAwZaHRyFfIXHUwMDA0nOz4jsBcdKJcdTAwMDbPyerRTE/Yli+xs2Lum0XpNdh0lLLn4/3ZXFzFUXWB5G76RItcdTAwMGKVJ4+GK05wtlx1MDAwNU9cdTAwMTKKNdrjXHUwMDBmQVx1MDAxNVxcToPqMIbinfDSVrrWX5b6sFfcyWBlY6xcdTAwMGVcdTAwMGKdnlx1MDAxNmjtXHUwMDFmnTyXmVx1MDAwNlx1MDAwNG1ASH2V2VaM6judKIms4lx1MDAxYeWyLpm4tCap4/A84fg2XHUwMDE0jypmYOVcdLtRf+cud1xyxzKYj+Q+dlxmmWvkWo1rYnlYnpvVO673/NlPku3CXHUwMDBlxFpiZVx1MDAwMKwtXHUwMDA17iVcdTAwMDd2tmo+XHUwMDFkNOZcdTAwMWFcdTAwMWTlL6Kk3slEQrtToSXzXHUwMDA19PJLqyqcx5dNWq2ix6tUqFx1MDAxMKCFXHUwMDE4TThfVcnTWTKvSGJg10xcdTAwMTbSctWwXHUwMDFiXHUwMDFm9szjpDi2uExnXCLGgIEskmt2XHUwMDEyXfuwQ31lXm/lgGuhSVDChSyzjFJmkVx1MDAxOVx1MDAxZZdcdTAwMDDBkXsvXHUwMDFkuKsoUmOHq8fDdIFcbnbenseOY9rGZFx1MDAxN33DaFx1MDAxYVrsO7AxPd/OM7JcdTAwMGJYy6lmNFx1MDAxOaYqXGIlXHUwMDBi6qerYFx1MDAxMVx1MDAwZSicMY6DSl+k0OPpXHUwMDFmqb77z1m4Wv3cpz5PVEt8KmjSRUdkxFx1MDAxZT3IKdp2MJpw1Zraenpey1x1MDAxMvraNE1dy/zeXHUwMDFh9XAj6Phuob3XmFTJ+WVKOUt4Xy9Jgci8LVndIaNyXHUwMDAwXHUwMDBillx1MDAwNDmDdm5cdTAwMGLkystcZlQmWT6sXHUwMDBmjzFYauBccu7ukLtcdTAwMDOEilx1MDAxZsKCcMtcdTAwMThmW6hcdTAwMDNjrVx1MDAxYonP3ZA8XHUwMDAwitXa9kI9rNxePt2OqHomXHUwMDAzK6xK5lTdXHUwMDE1uFx1MDAwNNewijupTcZcZkVcdTAwMGI6pjRcdTAwMWGW/XuxY/lNk6NcdTAwMTKB+vXsm5fw6UH7XFx1NFx1MDAwNFx1MDAxZNrtzHbW2lx1MDAwMZctIz2/6PmteTxN0fWjdVx1MDAxNMj67IHgwa2nQWBuvsTmj1x1MDAxNvD1XeiZMO9yZSZV5mDlSOWeoqKe43BlmzRcdTAwMTV3u87Gcoe8Wlx1MDAxM1x1MDAxMlRl9nVcdTAwMGWsmSuZnlx1MDAwNmA0S9XZK9PDu9hxk/nGVbRGO8P8aNujXHUwMDAzZIp8WFx1MDAwZXLIXHUwMDE4jjqB9lx1MDAxOMdZK/H3wZevXHUwMDA06lx1MDAxZsDJd7ZcbjBcXFtcdTAwMDT7PvFXwdyMmHpcdTAwMDTYvZ2J/kGGsFx1MDAxNlx1MDAxNFTFXG7w7U5zhoBgvUiX8dPCXHJTXHUwMDE5b9gw7L7xVGwgyjhOj1x1MDAxNjmuXHUwMDFmmbuu3pVcdTAwMTVcdTAwMWZuPKczf3tcdTAwMTKuNUZskOvJnSjwXHUwMDFizZPqOWXP/pxvR9DmPWNcdTAwMWJhz3Wa75S8NSBcdTAwMGazsVxyQs/CZoSKZoPVYIV1k1x1MDAwNIZcckJcYuXe5ljD3MdbvcCP4r7NhsjFZ3FcdTAwMTKgs7ghiOXy7OKdXHUwMDE5cXJKvWZcdTAwMWVKsbO1tWxOxiGk1eXz81FjNlxmQOGzQzJO7ST5enflS1x1MDAxZVx1MDAxY5ZWlTL46ulcdFxcqXdLXHUwMDFi76O83lx1MDAxMIdiyPOuo1x1MDAwN9VWXHUwMDFj5d6Fm90s1YzXz5w7hPtSOVgs8/dcdTAwMTbqXHUwMDAz7/CO/MglKrBFII37cWq26cHYXHUwMDBljEw2en4qqqlYnXk7S7x6XG7kijv6SrNtOVx1MDAxZkfTXHUwMDE2izLRzWxwxKI1odKhXHUwMDEwXHUwMDEwzvW1XeeYKGBcdTAwMTGVTdJvXHUwMDAxXHUwMDE1qiVcdTAwMDYyUlx1MDAxNOn6er5xoiRcdTAwMGb75ZD85k1V7PbxXHUwMDE4tsvDglx1MDAxY3RcdTAwMTFcdTAwMTRXrKG0XHUwMDA165b3ZYzQvVuGhjRGWSfRzMv5PFdcZjZcdTAwMDNARyxoqFd59VDLyETMXFxA5uqiWyZcdTAwMDVcdTAwMGUk2aN3OFx1MDAwNEf9rCuHtZIuYuZcdTAwMWboimjRc1x0XHUwMDBidlx1MDAxZpeyVYtFpM4+dyNC4przQpnLJqbqXHUwMDAx6G6yvIi2XHUwMDFiLHeWMFx1MDAwMGG8s1e9XHUwMDE1nVJcdTAwMWWQy2K4T0awsKR/qLq736tcdTAwMTPfcIR01UEuLp/8lMg+XHUwMDE2JKRgN1x1MDAxN5BoKYD1qi1cdTAwMWZvI3VcdTAwMGJcdTAwMDdcdTAwMDW6ZslKXHUwMDFlXHUwMDE29pKCXHUwMDEytEY2yGRcdTAwMWVCXGJkXHUwMDEyovteTrWdXHUwMDFmXGJSXHUwMDFlSqfNkJonqkr0XFyZP1x1MDAxOetxups74+Z2T9H8Je9cdTAwMTfbqTxGrM6GcCMt/tHERYZAblx1MDAxNSb3olx1MDAxZW9wvnJcdF5N3kK4NHfK+mxGvbtcZrSHqnNZ/HDAVHvZdD9cblx1MDAwYiTydFGc61x1MDAxY7RcdTAwMTWSM0+V3Fx1MDAxOJrdI4OUPo+IWmlws4aELFFzyIrC7GqA2HlWtsrMwJcz5S5cdTAwMDaKifaJ5Pt8u1x1MDAwN91UXHUwMDExr7XZRD3ct1x1MDAxYTd7ZHGo0VxuKYdpxJndq5t4w3nRXHJ7nUeLmbJtWKDAq1x1MDAxOUdq3pxcdTAwMDBcdTAwMWa95H795KDusoRcdTAwMTlcdTAwMTOZi1xyXHUwMDFlqlPIwoirYP9w3CHN5TlYr2NcdTAwMDWA5PGa3TUrc5zTbN5cdTAwMWakhVx1MDAxNNQjXHUwMDAygKBcIlx1MDAxZFXFbbnGalx1MDAxY4fcjS/sfeLh4Jym80w+Lv2Z3Vx1MDAxNJVvsPTKXFyNKona4az54Hm1R0BcdTAwMTVcdTAwMDF6XHUwMDFis/sj3Vx1MDAwMrY5oSxRXHUwMDAzPkXdhmXcLvZcdTAwMGVz9mm95TJhSEsuZolmI8BcdJxDhoNnXHUwMDAzXHUwMDE4eFx1MDAxN4tccny6iym3byFEWlx1MDAwZlx1MDAxYn1cdTAwMDDrYsDttUL90YlWSFx1MDAwM05Q71x1MDAwNl1cdTAwMDVD18KhxWzp3OVCRUWVyTyrS4B3N2hgdVx1MDAxNnix8MeiXHUwMDFi65Sz+iV+Up7q4LHK7Vx1MDAxZUfizJo2R3KEulx1MDAwMnWHzIGticaTw9xcdTAwMDNXoeS16EJ3ujUjRa05vndJPFlcdTAwMDPhOULdaJNcdTAwMDPTXHUwMDFiZlvVLlx1MDAxYbI15eHJpvLhoFx1MDAwNlx1MDAwYlx1MDAxNMCsgv3F9nCB4/bIV7xOkCR801x1MDAwYuHG+KayxVx1MDAwZaxcdDu+MCdhyi63256iV3wvpCeeXlx1MDAxNZBcdTAwMTmM8eK3poimQ6BV2s08KYdzsFlcdTAwMWJm701yKmlrlKpiz1x1MDAwMVx1MDAxYjJPftBOXHRz0GDWQf7hd7hcdTAwMDMzNmtkcCbsZ49SPc+1gOV6suDsMFx1MDAwNVx1MDAwZWzLXHUwMDFi/uhcdTAwMTFkkc972iuqzOP3aVCBR1x1MDAxZFx1MDAwMTY8teOwuqyZe2ZcdTAwMTRn4SNcdTAwMThqS62pXCIhpEZx6lx1MDAwZVx1MDAxYkNBk85EJ4FcdTAwMDCn+NszYFiYfSi4q7pcdTAwMTVcdTAwMTP07XJcbmA0Wlx1MDAwZbXyXHUwMDAwwLMom2lcdTAwMWFB7Fx1MDAxMt186IxFipk4rT2kmUpcdP1tvE/nbJ3XdehcdTAwMWWPI1x1MDAwYmuuuYmt36A1g1x1MDAxMeLh/TynXHUwMDAzXHUwMDFj/KSe1fPrVPqqr1x1MDAwNlpcdTAwMDVcdTAwMGYxJHirXHUwMDFkXHUwMDAzOs7L3nCjlo2CI21cckztk2pj8VDhTkWaXHUwMDFkXHUwMDE2tzF44YCr6uqySrXYIZHzZ06mgHk64Z2RijahjiYu72yKLSDQrX58ePNcdTAwMWOZneJ+wp/L40DmkZBYVre7zHWeXHUwMDFiXYo2T8a0XVx1MDAwYp3vXHUwMDAz9sO/z4zdolF9K4qr0ytz3INcIn9J805Oo8hL1aye+JqKXHUwMDEzbpVcIlxcq1x1MDAxM+Yh+cDhXCIu3dAoj5PToi4169QuTII2XqSH2GBh5Vx1MDAwNSZpo1x0Rp7TWW72WbuPXHUwMDE20N/viWJcdTAwMTnnalCSq39ha49tQnpcdTAwMTZsnVx1MDAwNJhzXHUwMDEzc+WQSrr55FwiYuDY2rD5XHUwMDE22f2hXGJDM61cdTAwMGJZYCuFfoJxe7/qj4NcIkD2XHUwMDEwlUorxnt7PSWvi1wiXHUwMDAyXHUwMDA3ZPg2q+RAXbYyiyjbsMr2XHUwMDEyp60hz+igX+hZwu5lnqxisi76XrT9OVx1MDAxNu0y9FxcpNL6SdznXHUwMDFlNUBBqaUzs+53dWxcdTAwMThcbjzzPFx1MDAwZmvH0LNtPkk8p+NcdTAwMTiRPa9cdTAwMDSmVWpcdTAwMTPAoX/Ih9Ndaqw5J1x1MDAwM2c7NabLLItSc1mMmK2Nknd3RMvTOl7cgfRJyafm+UHJ4smqLlZrTlxmgMdr/4Qo6rmxaCCY/XlcdTAwMDKDkF3Ukek0WqB6LrqHM1rD0lAh4amsZTWinEZDaOrSen32cIdqoawwntDketBcdTAwMWShIIaYk1S4q/fzaEBdOVx1MDAwNJN4dINcYoL7/Vx1MDAwZYinx4lVcIqINeCusdZeeUbPnVx1MDAwMv8yLFx1MDAxMFGsm2c/ZFlyXHUwMDA2OKD5XG6Wolx1MDAxM5Y/Kcpcci2sY1xu2rrziWY+/eQ2XHUwMDExXHUwMDFidd5iWb2Lx0BVXHUwMDEw+bhKclwiPEPjispcdTAwMWHCI6pTqj6HlnpcdTAwMTTuXHUwMDE3N1x1MDAxM6OzKvqWe/FjStGgvdb4MZSPvttcdTAwMWNxxVx1MDAwNK5cdTAwMTUuUXEu9rNaIcHVSEzZRSQuisNp9kiHjFD0zOoqI99cZp95UkiLYfZcdTAwMTVzqpN4W3zOusjrIYWdhuA3W3LicpxvT7zoXHUwMDBlvYhcdTAwMTDT8aJIxOyaXHSGQo1xzqwt2IzM2OZjXHUwMDE2XGJXXHUwMDFib7blzfdpTzjGU2pFXHUwMDA1xMeahNSAouhaXHUwMDFlaDRcdTAwMTdcdTAwMGJxs/NV4/RVe1xcu+mW1eRcdTAwMDVcdTAwMTAjJ6DQO9/lUVWaXHUwMDEwwCxcdTAwMWSiNub88Ge/S1vgnjFUTVx1MDAxNOk4X2vNXHUwMDBmQyrAYFx1MDAwNlvMkImyuKmzu+e7z1x0XHUwMDFlhYo0Yd89S0xcbo7jXHUwMDEx4GxRPsut76dcdTAwMDG6XHUwMDFjPPjwnmFTi/uEiiXNXTDJrPJcdTAwMWK1uM6Fa3NcdTAwMWTPXHUwMDBm3fPErfnew/rJXHUwMDExzdP1/HxcdTAwMTjp4WHvMYPB8YpuJkk1XHUwMDA1asa4XHUwMDA3XHUwMDFkptbaYlx1MDAxMtayJFx1MDAxM1igrEuJXHUwMDAwXHR9J1xiXHUwMDFh46tcIr7bw1x1MDAwMySqR9BzJlpvSlx1MDAwN/XCqueScjmpXGK/s3fsmafBXHUwMDFkSJ9cbq9eoe12m8yDt6OHefW0STkpq0RcdTAwMDMhkfJ7h94ruu2Yk9Io1XroXeFmXHUwMDE4scQ0/WjtnXYxJ9VcdTAwMTWe8Vx094NcdPXoO4bd9U7JsLa6goZkwlVZOdKF8p5cdTAwMGWVnvPF3EPPvFpCwuRt7fpzcXl6XHUwMDAyWbDBvPOgUmpYZ4vYPmNcdTAwMDesXHUwMDFhnVdgieF5QcScnGzO8ZptUmm1XHUwMDFl65/iSt3wXHUwMDA186CSvO9mVpGFnZ+gTem1jOqNsrsrXHUwMDFlrpNZkoh8tyhDcD5cdTAwMTiF7Vx1MDAwNFZcdTAwMTdcdTAwMDNT3tFgiqubtFx1MDAxOPpuP3Z8LCPdXHUwMDA0pkitOzfN+Uky6lx1MDAwYsVEXHUwMDBmUOZ2J/Lg0/K6dDW5Olx1MDAxNutcblx1MDAxNne5gFchXHUwMDFlb5KweTWz+pkqXHUwMDEykNCAK0VWZuGP2HjtsoOxXHUwMDEyMFx1MDAxY7hY7IrAZpL1Mm3EjnY1u1U8doG9koJcdTAwMTZcZsvhI7Go8IObViNRM/uxrb5Qq0gu8Ow1z65r6I9cYrU0fKCReHo5q/tMtee43XZd9UNFKJVcdTAwMWLrK1x1MDAxM+uxrXh6rd5y6dl9XppHoXlPQaPGXHUwMDBitlgwvttRqFV7XGZXXHUwMDExsbtcbu8/ZTve3WfI2Eio2MVh0kYlUYL0XHUwMDExZFxuLZxmZpZHhIz0Qzs0Y+n5ni1baMVcdTAwMDI+SIKedJFcdTAwMWY7WW1cdTAwMDGa4yufj7WQW3HXXHUwMDE4fSz0dlx1MDAxMOuMuCvXXHUwMDFiJFxcm1x0KOpOblx0t8Dd2dRcdTAwMTlcdTAwMGVcdTAwMTfkXHUwMDA1XHUwMDEwmJN/u1x1MDAxZrm5yiOyps9IKzGHXHTch1x1MDAxNnNqcMVO3HqWVlO1KvLQNdScrM1cdTAwMTmhqvTguodjXpE5w62GXHThsq6Gq+txiH8yXHUwMDE5lUFcZuPhUFxcxDCUJK5Si1x1MDAwNn62XHUwMDE38oNHWue0lLA4tOdOwoDef6KKlSi598yeROcy1C31svttvIp8PpQtXHUwMDE0nE/mLTRcdTAwMWKpqZMzl3QzXHUwMDAyO+AsJfVcdTAwMDZcIuioL3Kv7ZhD8srgUFVoXHUwMDFktFx1MDAwN4NJebbv5JmIoVx0ueg1wOV0p17Oz9iusEVTudqAJV15ZiVcdTAwMTmMNVx1MDAxY3pcdTAwMDTK+vjTjTHXNeVz9CRcdTAwMDAg6HXmdq+iy3KJros6yXRcdTAwMTRHlnGkVvSU6Uyq6VwiW+mbXHUwMDBlNpGwPdP5RJ/nOHC5RV3CJmd8WFhOt1x1MDAxNWRcZmUxLVx1MDAwMN61WlwiXFznPKRO01jaJVx1MDAxZULN4GU7aJ1cdTAwMDNcdTAwMDJcXKRcdTAwMGKPXHUwMDBidJfQnFGF6LSdvOe5WpLnNcc0d2SQ6ORoT+dGR2xj3/jGvJVcdTAwMTmgx6rocPGTkGdcdTAwMDZAg83ci0fS+aHI5HwqcnkhNYJi+KeodqA2k9D66lx1MDAxObGrp3ulXHUwMDAx1arO7rPKIX5Xn5xzzZR8pC9cdTAwMDSUXFzJ8UTW4kVHeCwlc0wovcp+ZDzUYGWXglx1MDAxN5Q/jSjLOHGhm1x1MDAwNu+DPT5cdTAwMWXmTTPYNqBNzSi4RzI/slDq7OTOmFx0XGbx9VkqVVx1MDAxOSFjeJi3VbrsNTTESEhcdTAwMTKord2Ohlx1MDAwMndfOCl3bUOujiZJRlx1MDAxONk5457E01BRa5D64lOUXHUwMDE1XCIsuN2vSVx1MDAxYobrUOtPvTjnwVx1MDAwNIoqUZ7du7LJSYFcdTAwMDRgvF9ZKVx1MDAxMPpWTOZ7qbaV0lxirL3G5DRFXHUwMDFiX1x1MDAxN2Q6gYrJtjTOuyScYyVL2csyIeGhXHUwMDBljmTXXHUwMDE5d3xVhuQ0XHUwMDE1IOuzgEGYxTOysLg2SqTUtt7xqFx1MDAxYrj48oRxualcdTAwMTZFJpZqI5ZhXHUwMDFlzferQqk3e2SxXHQ8wlx1MDAwNfNcdTAwMGX/i+5wLiWylcF5OVxuJVwiNyByjrODXHUwMDA0/eJyjZi0971EJ1x1MDAxY0RRUEpcdTAwMDLsPDJ5K3PO2lx1MDAwZVaWq++hbEKcVVCbXHUwMDFhuUNxoFx1MDAxN1x1MDAwZuZcdTAwMDeY1Z1cdTAwMThysXflXGZ+2m6eQt8jmURNulx1MDAxNUvpfipccsc7I1x1MDAxY5tcdTAwMTlOf/A9Slx1MDAwNVXclnPqio9cdTAwMDC2dTzAllx1MDAxOD1pLFx1MDAxMLVcdTAwMTdsXjTNl8ey8djhXHUwMDEwoXdbc1x1MDAxMDhcdTAwMTiZ6YrScDI9XHUwMDAyvFx1MDAxNLf0XHUwMDFhwjI6XsZb0lhcdTAwMTldO2Jzb2nbOdxcdTAwMWMzeOh90M/es5yl8b5A5iE+QV/VXHUwMDEwyb9ekmJ7jibvZXifXHUwMDE4Tn1IoyWtNajQt1x1MDAwYiqXMneyyIlxXHUwMDFj9SSl/DFgs54xoqT6QVx1MDAxYc9LcVx1MDAwMq1T2FxiZlxiXHUwMDAygFx0X+ycXHUwMDFi7rycQ57RytiDPE2lpctcZu1OXCJiXHUwMDFlfbrvcKnbT0bQQFx1MDAwMcRMLl9Q3Z39a31l0MWGTWJvRZklfMrj2CbKn1x1MDAxN/liXHUwMDE5RHjhXHUwMDBlvt6JbFVHQfGK9EqPmFx1MDAxNlpLVF+2zfdGkyOPrswmV/OAQlx1MDAwZaYnc1x1MDAxNbLi8DdsSOBaueBcdTAwMDeiuGeueVwi4shMXtBcYnK73fOQXHUwMDA3a6Se9lx1MDAwMLBcdTAwMWJptisrq+hw4kJRUlx1MDAwMDLDdZs6aCtcdTAwMTSozSZTftsyjFm1+SqjjIduiyQ2mjx1jF6edOJcdTAwMTnqbDty6ZMnXCIliLFdIHM7uorEbi6Zx8dtmsy3/lx1MDAxYTqiYGktTrfn9cSMXHUwMDEzp9I1rmiyXHUwMDE4PqWcddRcdTAwMTZqXHUwMDE3PGmLdFx1MDAxZu40XCLwvPZkqofK9oxcdTAwMTJcdTAwMTPj7aBcdTAwMTKzxZW5IIf+1knjoyiOOzGKs1x1MDAxMJh+yc2l8Pbimlx1MDAwMMFcdTAwMDKkaaeAIEnbSTohd/rS9yNcdTAwMThcblx1MDAxYuvJROV1cZbT4FCyXHUwMDA1oaPtvEAxgT1cdTAwMDJexMeYlZZD19ieytlS5p9cdTAwMWawXHUwMDA3ZqC08mBVXHUwMDE1krVcdTAwMTbtoXeU63ajzmt+XpJzhM+DUvNbssNnq2BcZpB63XiQxlZ4XHUwMDAx62SyXHUwMDE5p5wqdE61qWRcdTAwMTheyepLhN1XvoqEjFx1MDAxNqJ1N+iHuGhrdHOUNIQniFBm+XSaI1q7S/IqoFx1MDAxYnOEmfNwlUtyYyD6Kkq5cHBHXHUwMDEw+VRH58heYHwnOWVcdTAwMTU7XHUwMDE4RTlXm8g4mLOYXHUwMDA3lMpdXHUwMDFkKs/9oW+d2EaQ/qzv4oXCxIxhXHLTrrlQ2ZBwym/MXVx1MDAxOD1/XCLKXHUwMDAy2VxmkkvzXHUwMDFiedVLL8jvPU5+Wlx1MDAwN1+m11LgQlx1MDAxN1VKil6mXHKi0/skXHUwMDAy2L6lNSddTIbZTzVcdTAwMTeMXHUwMDExu1x1MDAxNeCuPyGwoi/+kYUhjFNzg1xycWGlVVOCXCKst2JSXHUwMDExgWBcdTAwMTC4XHUwMDBlI+GAzZeTXHUwMDFmaV3qPPTQvIZcdTAwMWJaNS6JrDp27TX5uUZESFxmXHUwMDA06KBXJlx1MDAxNsLzUm5cdTAwMDLGda3RXHUwMDA3qImbnVHb0ZFvsCk71dp5XHUwMDA0XHUwMDAxXHUwMDA0Rq6w6om6d4V2XHUwMDE3sntdvbRcck9cdTAwMTdcdTAwMDM7s8hBcb26XHUwMDE0gCbgXHIoyiB8VsJMq5utcj1ywc37uT5cdTAwMTlix49GKVx1MDAxN8JcIqpnuaBYmCO39SlcXDBzxi1fiNhcdTAwMDVUMtiRMrujOPB+5H5NlHqvkpTcVVGoXHUwMDE4XHUwMDA0XG7VjrwyTJVcdTAwMGW2Z/s0b6pcdTAwMTXfPcdQlMzINN1CxbBVM1eJXHUwMDEym9StS+soNU5cdTAwMTVHzE6GwDxkNGTzXGZ92FeLsdk5S55cdTAwMGXG11d8iCa85SHqmVx1MDAwZcDEPL1cdTAwMTm6XHKei9XuNbONwc6svO5JxVx1MDAxN/jupqckt2ZAd1KsTldcdTAwMWOj2lx1MDAxZk1e65x5cG78vMJcdTAwMDA980WSmcvkaalOMLFRWDbQXTPkYMNcbuJSr+ZcdTAwMTOHzYbruLJcXFx1MDAxOTTEjV23a9xO4JL2N+vRzYqMsa/btVx1MDAxOFa1XHUwMDFjXFzoKzXLsv/+399tr+uTt42Er9/EXGa9flx1MDAwZvHbpszXb7G2krEvkvmL7YZcdTAwMTBGYtj77a/f/k9L/tG9bX/836z8XHUwMDFi9rZccq999fhxb1x1MDAxYjtK+OZ8ubdcco5ZhHXxXHUwMDEwXHUwMDA1fVx1MDAwMKBcdTAwMDXY84zqXCI+W47RXHUwMDA0kLm5XCKLwJ1cZrn+XGK7wUiXXGI8XHUwMDFlUVx1MDAxYmrojVx1MDAwNnuCqDurWFx1MDAwNrlcdTAwMGa0W3dZ2OpcbpP7ym1cdTAwMTU+V+pcdTAwMWPXc1xmziaQkGZY4fHicEtcdTAwMWFmh+SicXwl51x0RME0xZbJTldcdTAwMTI0eMWmN2x3dohcdTAwMGaRsTeXKG4w+27vSGWmR1x1MDAxMr0/XHUwMDAwIfdcdTAwMWO38cidLijxVPGPxFx1MDAwNFlcdTAwMDJcdTAwMWSxzqey5Vx1MDAxNJbngi6YcFx1MDAwNbOJvIdhim+tccpYUFwiRYR3UVx1MDAwMt1vuixcdTAwMDGg3FBcdTAwMDeG5NiE5khcdTAwMDRt90jiXGZLXHSlsehb5lx1MDAxM1wiae9LurDgXHUwMDEzfVJcbjnhqfZ6vqNWUps4XHTs1DMw0JmAWdHwNPvF9lx1MDAxOLnZOd9m0Vx1MDAwYirlXHUwMDBiT9NcdTAwMTNcdFxi/Uw2tJ8xwOVuaFlf1mlcdTAwMTHUY99cdTAwMDVSfvF3mFx1MDAwZdVcdTAwMTndSfac3Jc2Ol+hU5Z5aSnP8Ml2tktzgpOifWrVXHUwMDFkkfLVSMXrfeWywc5xVIj6RYaadZdcdTAwMGZmTpPHk+MvhyuDSlA4q21cdTAwMTTJ+YLFXHUwMDBmgPZHRlx1MDAwZWbyVFx1MDAwMJfD36FcdTAwMDUsWv+7svPIblx1MDAxMFmg6Ly3woCchlx1MDAwNJFzhlx1MDAxOVx1MDAxOYmcwzl/71x1MDAxZvdcdTAwMGV6atmyq6h6795jUWC06lx1MDAwND3eyGFcdTAwMDbRn1x1MDAxOVx1MDAxYVx1MDAxM9CSOZiRLFj06C1FXHUwMDEwr1x1MDAxZVx1MDAxNYookOF32abEsXxz3oGOxXq3S3xcdTAwMDNtdz4okbR3RK1cdTAwMTFf9SrFcoUn9klcdTAwMTl03NhrjG9IlX9cdTAwMGXivWBcdTAwMTDetGJYiVx0XHUwMDAwYPBSXHUwMDFhZ8P8WHxqWP3Fvdyqv4s7v/p30lx1MDAwMmNM77H38ze4al0nvqToXHUwMDAyXHUwMDAwmite2C2YXHUwMDA1PuVikNq9zv6hXVx1MDAxNFvVQVx1MDAwMGPNSJUvXHUwMDExRth5slTGNT9infHpROMxUJ4oQIqKmU5cdTAwMGLHUFx1MDAwZo/38CZgw8anNOxDl5Fz0W2dT1wifbOecPE5XHUwMDBl01x1MDAxMN/aLVx1MDAwYoN+XHUwMDEwcFx1MDAwNGJcdTAwMGU1xMNkZNJcdNRcdTAwMWSlJdaO/WKE2S2zIIjTll2BdHTTLCrf/sgmPm361K6UXHUwMDFhYqqz7/BcctIuXHUwMDExM+BcdTAwMDHogoKO0sRcdTAwMWPc6fc8XHUwMDE0KFxid89YzjZcdTAwMDanfS/9wFx1MDAxNu/yeIecdvbJXHUwMDEwXHUwMDE29Wbx9lLi8HhFR1x1MDAwMZnBaIaC7dZPcJuNMWxDZtdUpKJXfblzXHUwMDE0YDe511GoXHUwMDAwwUlYg8NcdTAwMThcdTAwMTSx8q3FKnVSPrysUIYzKtms6mXMUus8caBWtFxyXHUwMDAwLYtiS+h0nVx1MDAxNndcdTAwMDJRKnFysj1cdTAwMTZcdTAwMTE5atjNxMCDe6W0b9HOOGlpmsLeXHUwMDE1i0o6XHUwMDBicCg7XGLlrVZQqTFsIXD7XHUwMDFkjWPIglx1MDAxNHaBN3Tox61cdTAwMTOFeYWdOjFN6myF1neQXHUwMDAxMU6OaeRef9Iy82XHs1mFcfMvm1LC5TtK0yp5yC+xp7ys+ZuQu/Dq1ElMJMf0r5KjXHUwMDFmXHUwMDAyPSyeXHUwMDE1j+GOlU6XvICJe/OX6ENcdTAwMWbDWiaoXHUwMDA088N6NWC94/q7YU6tMZq+XHUwMDFlPMMqXHUwMDEwrvuIZ1x1MDAxYVVhmPIj2Fxulpz+SIkm/K0tuIdcXIuEXHUwMDBlXHUwMDE0cDt3XHUwMDBiXd7ujW98c4eK8ulcdTAwMTOpLj5cZtk3XHUwMDEzm1x1MDAxN0xsd+6XdGWA6oC0tTV/XG63NDXtf9JcbvGreYhhNdqrfrKF9d5RJLR9XHUwMDFi2p5Y0XQgUvd9R1x1MDAwZlwi1EMggvfTLtNcdTAwMWTldlx1MDAwN3I+7ueCXHUwMDA2zlx1MDAxZZRPs3rL27UsX76GbFx1MDAxNGXhQ3tVXHUwMDAxXHUwMDAwwVx1MDAwN/S5ylx1MDAxMNaKx6fk+ITx9NezXHUwMDE5XG5cdTAwMTZcdTAwMWQ/XHUwMDE0LOsgUWrNXHUwMDE2kmJz5XY75TvaZnZcdTAwMTSVb6YhvFx1MDAwNybnlpjCqyCc8vSPTDBDS0yP8ayh+VlcdTAwMWaXuaeNcdddjV7U+2r6XCLVqzQrs1R7mVx1MDAxZvjDQ1wioLdcdTAwMGX0TmDlXHUwMDE38kM5pFagU8KMX9WlZ9bhl+bC1SZcbtUpsyNHXCJinjQ6XHUwMDBmguXNWlRcdTAwMTW0beJlmaCU1LcoXCKWrs6SklEzZr3/0KuWXHSdjpZEk6RcdTAwMDPBM2PG/FL7Ylx1MDAxMFx1MDAwN/tcdNfRgZJcdTAwMDW3ZbR6Xvv1Z1xi6lx1MDAwMiSUXG5AwFx1MDAwM/jZPHnoQpKvIFx1MDAxY2tmz0WxXHUwMDFlazmyQU1YjNOXIJxcdTAwMWTddKHPYFx1MDAwNEFcdTAwMDQ8p7p3j19z907BndVtxFx1MDAxMFx1MDAwMUauXHJHOitcdTAwMGWqjPctt5LTe7NcdTAwMTVdf9OYXCLVWHRD1W1cdTAwMDF7oj9azC9AZYFJ+sQglPkwhyfZbvxcdTAwMDFIWKhZyHI6XHUwMDA1ecBDjsoqm1x1MDAxMsL9XHUwMDFlwum2uCaghdz++lFcbkXfULXO8DM1POFYpVx1MDAxYmKlQ3BMXHUwMDEz1fl880epXHUwMDExXHUwMDBms63nKoa6a8OlgHp+h1x1MDAwN5FcdTAwMDeoXHUwMDFmXHUwMDEyXGbK3brL0u82XHUwMDE48CbaXHUwMDAxuH+/Ma899Ze+XGZ2K5nexFx1MDAxOMNcdTAwMDA9UObTytl3XHUwMDBmuvSWcD+OXHUwMDE2YZLGxE9zXCKeROK4SLeo1lxcqE82llxyr1x1MDAwNzXHXGKAhCj43Fx1MDAwMah9KYrmtTbl3a/CPjbskumXw/bA1adhXHJcdTAwMWIqzVx1MDAxOZCEwydm5c9n0aV6Tz3uUlx1MDAxYZlIgIpduFxm91mli+ZD5nVcdTAwMTZWdlx1MDAxNYBcbrl8zZpugsDehaVJrv2AXHSNk99cYlx1MDAwNKuwXHUwMDAydORsqkO4oEC7u6n3J0mWI8lcdTAwMDZPisu5o/fEX3hKh1x1MDAxZTKSv2YzZiRcdTAwMTSgilx1MDAxMl5AeH7bvdZkqyA4YXhbcPH+iknkK3/RXHUwMDEx5I3y4jXcbaxUrbyL4d1cbsZvMmJcdTAwMDWauFx1MDAxMTH1PS3Ju3e8XHUwMDFjKlx1MDAxNKhMlMaDXHUwMDE5kizi35S/jNlvQXrCXHUwMDE5JJt7gJeq2ypiIcfD/d2VJSeW612v47FXkGSBjFTyVlxcXHUwMDA2XHUwMDAwqFKa1TxcdTAwMTCXMVx1MDAxY81RQIyZ61stP5owcTIxJK7xR2XEOj9cYnxzJWKTa3Gp65GhXHUwMDE2Olx1MDAxNt/pMNdcdTAwMTA470BrZGO35JOuOJ3Qbn66Rk2nkpSX+G1KTlx1MDAxYbXWcLWTXHUwMDE5gTlcdTAwMTmlXG5Uyqf6nmzW+pw/TG07OVxyXHUwMDFihcxcdTAwMDQyMs43XHUwMDA1+H5cdTAwMGanMyQsU5ji8j+/T992tehfpExmTZJkw1tcdTAwMWRcdTAwMDKJaqLXi1Ko96LpnmTy/ZMhhHerot9f4arybZJwUI2z7Fx1MDAwMaZcIiBhhG+iSu0j0CsrXHUwMDFmSfr2XHUwMDBmR17TmZ0zulx1MDAxZSHWXGJvrIOauFx1MDAxNlx1MDAxZpAyeJ5/2Vx1MDAwZuQ/XGbYa1xmXHUwMDBl2lx1MDAwNJa4XHUwMDFjn/KTXHUwMDBiulx05Fx1MDAwYji9fX8/atFWmFxiXHUwMDA1gYPEy3CijlDFXHUwMDEw8p/lc8/UyVwisbIxM9rtfGXDy3BO2ZXMgVm9KH287SRBWmE2tih1m/7xz4819yD3XHUwMDA1nlxmXHUwMDE4XHUwMDA2iTrt0Ennd3ZmxqA+fVx1MDAwNZ7ogSdZRlx1MDAxZYaC44Wed6ZRNICQKcNwzLRlhSRcbo3fzSh6TziTOsRcdTAwMDRIamamr1x1MDAwNe+kP+xL6TuY9MhcdTAwMWQ7aa9BnphK34JDWjSctVx1MDAwMFx1MDAwYlQymlGkI1ta/mFcdTAwMWNcdTAwMTnYljKoXGKZMzOiL1x1MDAwNpFBWzTgQ2GHdylMmMahIT/ob62BNaBcdTAwMTKmPfnoyUqLRll9UNfEXHUwMDEyxaxcclCUVpbVtu0luEvQ5Gs8bMeBUvpuusVcdTAwMDZcdTAwMWN+l8S7eS9Gx4Ple8/CXGb/uDpcdTAwMTA4jDxcdTAwMTVl48MndbCq2Yp/oa9s5D+7jKBcdTAwMTY0qMNpZMSF5H35yfNcdTAwMTf2s1x1MDAxZiRxP1xmolx1MDAxZUfxIDyiKndcdTAwMWTEO1x1MDAwMatl0Vx1MDAwNy/2XHUwMDA1gDkwR6BcdTAwMDezwk1cdTAwMTB+k441L55Mplx1MDAwN0dokFJqbq9lXG5317FcdTAwMTlh1Fxm51BHXHUwMDAyXHUwMDExXHUwMDFhvTPJxT7MvJC0XHUwMDA091x1MDAxNWPazX77eTWDiIBEfzHNI47VxeHhXHUwMDFk8lisXHI64o/wQFx1MDAxYcc50KaAjJJaesR4KFwiXHUwMDEzPl+BnU5tbPpV5tvOxWXvzbt96eJ9l7jvYf2iXHUwMDAzmlxcf5K3XHUwMDE3005cbtaFrVx1MDAwNZEn/DlLVuVyu4eaLObe9JlL3ZtHaZB6MbU30viAIcQtYYhJuZ+Z0uRptL1y1I5gNFnqyFx1MDAwM7eBzk/PWZqpwzg1uGje6lxiQo+CcY2lXHUwMDFkxDU4QVx1MDAxNLezpnbiXHUwMDFhKqt2u55cbs/1RFxcQyDhN/S+4SFWZyffhqVVNsFKv31cdTAwMDdpXHUwMDAwsFx1MDAwN11vaFx0Mlx1MDAxZmqSTYNcdTAwMGI1jKy7ylx1MDAwM1x0sFx1MDAwMu9cdTAwMWZoaddFR2rWN5Bccup700FcdTAwMWGLJXjtXHUwMDA0q1dI1JfF+2p9q/ghJJnd/IXrMf2OvIVZkFh/MtOYWya9cGppeby4XHUwMDFitpzJXHUwMDFmxVx1MDAwYuZcdTAwMDSWWzhcdTAwMGbM9FRSXHUwMDFhQkVrhjWYXHUwMDA1ds5kcYhPXHUwMDFkuVx1MDAwN1xmzV9Qnb6ukfTbPmQ8XkZcdEhcdTAwMWLXXGJVJLA6NTXV7zQhtdWG5Fx1MDAwZnM0ioSV+fGt0yfljDQpIKeQXGbfeuqOrVx1MDAwZUpt41X+Tuaa9N52W6i3e/uh24gmnldRdIpcdTAwMDFcdTAwMTU6R1xmaDfT21G9z1x1MDAxZVx1MDAwM5TMjC36wk566S2sWadcdTAwMGJMflx0I6E2Ss9cdTAwMWbik8fs4JuQ4agk/L3uZcb1N9nwYOkqLEK/XHUwMDE0d0BcdTAwMWU70DN7XHUwMDBl71x1MDAwMobxcIVcdTAwMWWQXFzV+SvDXHUwMDE2O1x1MDAwNsNcdTAwMTlcdL5cbuRcclx1MDAwMITbXHUwMDA2XGK2vXs6Xn/VvUdZ9stG2JhZwCkgXHUwMDFjxoGK4NV5QUm5XHUwMDBl08VWXFzjXHUwMDBl4mCH3uRwXHUwMDFjqjrv9jbZh63fXGK1TePK3Lpgg4ZcdTAwMWYtNFx1MDAwMfWiXHUwMDBlfbGHL7OcKnSDjDRlWHu+69W8lV1Evj+A+lx1MDAxZIPo3Vx1MDAwMZ/jXHKP27GZNIpcdTAwMWLjhMDd2bmfsFxia0Obnfmh3Uq+cmMgTvzNadcxXHUwMDE5XGb6oORI8EqlOd9cdHKvL8jC4MfTXHUwMDFhptcqzS6G2CP37rvVbnWh16RTkFx1MDAwMSRIOcxcdTAwMTU3ydBpoyCCiMZccoDVQfPRXHUwMDA2YbxcdTAwMTJcdTAwMGVAXFwwMsmpXHUwMDFjTZI5nz23peHLj8R2/a7C4quxK+Fp+NNCqOjovNBcdTAwMTVp3jgvwM7XlPk5/KNgJ9qfjKGeoHG2u288x1x1MDAwNvgvXHUwMDFlat8+zmNcdTAwMWFTuEB0uyRcdTAwMWVcdTAwMGZP8Vx1MDAxNN4sXHUwMDEwN3Puxk/ZIOFKZzPoft3FV8s9k4ojXHUwMDAxpI7snqMmXHUwMDAxVrtI1O1zk7HafEYo3rqUgD/aXHUwMDA3vNLt9d2Mnlx1MDAxYyZrNjyTpzmw7dU9kFx1MDAxZOeLkk+J3juUbI3Ou1x1MDAxYpv4zlE1KJPYjrCXOY5DwlWvRXRcdTAwMTKOX3Dz9rOmRp2yzTVcdTAwMGJGg/2tXHRMPl+CXHUwMDFj3/5o2O77XHUwMDAwjlx1MDAxOEad4kauY+SjXS8zZc5huFx1MDAwYp54dEPoYmYqpmZkuYCn5b2rKaNu/31iamxxfT0y2U4w7DHExGR12smMrJ2Kl2tUtKbC3H+ZbUrSdyUhpyS0O1x1MDAxNfHGNZufe7Nv87Xi8eGkQ6NbcS9JhGBNyqLMRlx1MDAxZFx0o1x1MDAwMWxcdTAwMThnXHUwMDFhhFTuqq6YTvZcdTAwMDJcdTAwMGaaXHUwMDE0d7RqXHUwMDFjV1x1MDAwNUmaPlx1MDAxNXrsP+zMs1x1MDAxYbFYXHUwMDA0MVmVdz9cdTAwMGZQ/VCDbtahqtFcdTAwMWbmXHUwMDAxSUFcdTAwMDPzkOeHvqmNeDKx1K2DPCaOsH36yFmbUExnLfXck1x1MDAxY1x1MDAxOVg1XHUwMDE4vl9cYkf0unGm1q9I61u4/nxacbDbYN6rmpuDVE6sbOXVkqRWXHUwMDAw3G5sm3dSqGPVTmV50f7DXHUwMDEzXGZp4PQs3Fxum2Jfr/h8LG5JQ/Hdj81nmFx1MDAwMoBuiV584IVcdTAwMWYnie3nw+2lNVx1MDAxMPRfztOkhJ5cdTAwMGZZPFNcdTAwMThcdTAwMTcnYCN5obIrXHUwMDBmnnckYDFcdTAwMDGYOj7gxrtcdTAwMTUh9MY0nMKluDu/s9ZKKlx1MDAwZj5laNVpxq1cdTAwMWFN7cCdTcbxhNW37EE3/tp8iWRqrov49+/QqNzwnINYPpaE8JYuylx1MDAxY82cvFx1MDAxOZGBpDVP4lFcdTAwMTgun7mP6FI3rliHaNuJLo+1fTd8yVrJolxyNSTcaeNcdTAwMDNWRypk/lXxd5muvJa/XHTXKqvAj/ZBXG7Ya+0mgGjucV95XHUwMDBmnFx1MDAxNlXSXGbxXHUwMDEyJVx1MDAwM2DoVrhcZlx0XuGTyzK85qHeX/Kvbnl1RpovXHUwMDAy+22GLCU8oe3mbXi6wVpcdTAwMTPcrFjROa11tCBbeiNZ2qxQW+qGg03FN1x1MDAxZkdcdTAwMDA2daH/Kl5cdTAwMTN8zkKzg9TFvlxcwTfyU1x1MDAxYjOywV5cYlnE7pypMVx1MDAwN864JE+usVx1MDAwZqrDXzyOJzxcdTAwMDVKXHUwMDFmTSFHT9SoS6uVrFtPWetloSDkc49kVW46o5FMNjxlbFGOXHUwMDAyw6TF6s6LOSBFnVx1MDAwZlXb7meTXHUwMDFklvvyLmk7e6jb37hxXHUwMDEwzDDIYL9y0NRcdTAwMTaR84pffa1cdTAwMTXPQHp7VVwiY8abJjpcbinLl+JcdTAwMDNrhMRbf85ws/fSjCi6x02WxqqL+3VQYyWqic6Xb1x1MDAxYnatIMk69y7nutN95GUlOVhxYU67TDu//L6aNjzZypCbMqihXGLerFx1MDAwMFx1MDAxOeJcdTAwMTVsQFx1MDAwNdctNkUtXHUwMDEwelxyUcRcdTAwMWSZbaCQPoWhZJtW4Vx1MDAxZeB2ZplNvoFcZmmBtCU7somvWeW9/NZK9E2AzOVuL9BcdTAwMDKUqvilR6ZcdTAwMTO/LzxZzZuW7nBpzfSFWI3mUUdcdTAwMTbbKMXDMMObXHUwMDA1vXFcdTAwMDF4S1ZijinjXHUwMDFkZuSpbHamXHUwMDA0XHUwMDFiX6lkUz/eVVx1MDAxN+f1n/h0XHL56+Du6Fx1MDAwMuyrI1x1MDAxZfCrnPmWisafx1j6XHUwMDE1zTVozf5cdTAwMDQzju+HXHUwMDE36EpteJ5BzON98z2fzohPXHUwMDA2+dtcdTAwMGaf3imdVtHbLqZcYpvU7E+IRZPJvq/efWBNi8CRYDzT59JSuV/+vM22SstgUNooVuumJoPFg3hMXHUwMDAwKTa0xm5cdTAwMTD+O+E9XmA+/1PtR7+oy1x040lrsDvNTyC+/CRcdTAwMDV/YsejXHUwMDAyjVx1MDAxZkWtZsrpqi7jp4HGVSCYP1x1MDAxZXV4XHUwMDA3uorvYK/Xh2pEXHUwMDEwqlx1MDAxOVRcdMOo08RcIiGF2LNYMLpcdTAwMTMmgOxcdTAwMWTX7XdGIJKyrdghyVx1MDAxYkj/42o0vjCcKc7ecrjPro2Y7TeErfiw8pvWXpL8oL+zmWpcdTAwMDZqXGL3sG52XHUwMDE4PpGOXHUwMDFmXyDf0F9aNp1cdTAwMDO7/jtcdTAwMWLfyTu46Vx1MDAwN6z7XHUwMDFhelr5xilcdTAwMDNcdTAwMWY3zFx1MDAxNutnkFvhoITFXHUwMDE38kHZWFx1MDAxOCVcdTAwMWLkrcR8dzShKFx1MDAwNLdiXHUwMDFlXHUwMDFjbn9cdTAwMTes9I1cdTAwMTS6yLslLjs/ZdlcdTAwMGYqc4jtak5ktmZP+PfGV6VcdTAwMTL12a2sNIkkXHUwMDA1TJy25G+fm+2KnlxyWLo6uPWqo++dbDHvcCv2nKp1x5hcdTAwMTf4bomzmGI0b8JcdTAwMDOj2HqTZNvEyrUpvVx1MDAxNW+dNPyyXHUwMDEwaf45a1x1MDAxZSRbu9iPbbIya1x1MDAxNVx1MDAxMbRcdTAwMTb95zVvzPPb7iO9qF/FkKsm1Vx1MDAxMUBmoECXwXMuttRruKD12++5jyZhl3rA3rau/3FB0taatu1cdTAwMDf2oMxcdTAwMDcqOvn1lVx1MDAxYrltXHRhszRcInw2/5xRyl1cdTAwMDYuPMevpc5EzVx1MDAwMFf/XHUwMDEwrM3DMmZFj2ZcXIRtXHUwMDA0qyXS7jb2pjwprTVcdTAwMWJcdTAwMWTeXFzsKJ6jlJ/zXHUwMDA3qLHF6ehP+PM9pT8xX63uMeVcdTAwMTl6wZw3LFx1MDAxM7TXye+NoVMqXHUwMDE0XkBh6r29XHUwMDA0TFx1MDAxN1x1MDAwMWw2n2OFe8bNNGK1UGaEPOctzlx1MDAxYissyvZcdTAwMWGm6c9fb+Ul0+ZcdTAwMTH32tS2xdxcdTAwMGKtTMHGrbOoPkdcdTAwMDDiQWNFr75DJ8ePKZiouOWHXHUwMDFhx29cdTAwMDNAn4dcdTAwMTKlXGZ7RjP41KI1RilRaortln5flFx1MDAxYmaAaFx1MDAxN71cdTAwMTnXnHhcYmU8XHUwMDA16thZKP1cctrQh4cwXHUwMDA0ROfx1EDoXHUwMDFjN5mPcNnvJCbqrtfz3Lvsg7vMeZFcdTAwMGZ779OfpJacXHUwMDFktFtcdTAwMTbhWr+XTD7+rPNccki85qvnzFx0nSxAupzGOmrbdIqN2/N3XHUwMDFiu1x1MDAxNmDERnTDxfmDgFx1MDAwNG6LXHUwMDFiQlpcdTAwMTWwy4x7N8MwSfPeJopcdTAwMTffXHUwMDAy3sOUcVx1MDAwMjd1j75IPs/tpFNdfZtzTu+w/p5pZGRC5vfg2y1cdTAwMWTTSty9t7olXHUwMDFjhztcZj+n+1x1MDAxOSAjMVadwTVAOEZcdTAwMGZMm9PSN/jL8XhcdTAwMDa+SFxcnVx1MDAwZXOcP6bFRdZcdTAwMGYul1csbfLPXHUwMDFk9DloXHUwMDAye/T5lc/7tyRxsNuD60WR5IafxFf9ZuOblPhcdTAwMTLWzVx1MDAxOWakTWvnhYGoncNTaVx1MDAxYeWVjzv91Fx1MDAxYvVcdTAwMTBcIo33XHUwMDE337nM/sXQtlx1MDAwZVx1MDAxZW99e3H2s1xuVNwrIZh50mDgkXi3019gTWtcdTAwMDB3iu/n9/r0N45tnHqzXHUwMDA27uXKScJcdTAwMDDqlrdzm/bGXHUwMDEzdSxcdTAwMTRcdTAwMDV239U7XCJGcrBcZjtcdTAwMDHSrqGBXHUwMDBl1Zd2XHUwMDFjXHUwMDE2jFx1MDAwMGUpSVD78eTyXntZYZ5cdTAwMDNluy2IgnFcZlx1MDAxZmhccoZcdTAwMThaf/3gedO7d9K+6Z1v7sNcdTAwMWbbS9spzVx1MDAxOZqrfUirXHUwMDE4XHUwMDFlXHUwMDA2flx1MDAwM0c0t0ioPCZ7zcWMVYlcdTAwMDJcdJ9ZaLS33C6ZUTqWXHUwMDAzQzhcdTAwMTT86cxcdTAwMWX/SFx1MDAxOKB173I5hoWAsmrXsLJHk/42ylx1MDAwNlx1MDAxYfy0zr5nXHUwMDE2XHUwMDFiVVxiU4P1qTJcbuxgXHUwMDE0KdTKuI/DWJhA++FcXL9FXHUwMDAxXHUwMDFjadrPq5SrhrKOP2f1ofqPy76oM7hkx1x1MDAxYUiRxkYytrfQ8ivgu1xuc2FcdTAwMGW+UDooId7T457VTVetLPWPXCJcdTAwMDSVgYlcdTAwMDfRf6ynglx1MDAxNiZcdTAwMTBcdTAwMTFuaPRcdTAwMTLyq1x1MDAwYuJcdTAwMDT4VuSEqFpMl/nJmLZcdTAwMDGjcGp+mDYs5odTQ2pH1Vx1MDAwNqrfXHUwMDA0oVx1MDAxZTLeOX693TM0KM96TLBUWpBcIrqcXHUwMDE2gPNL825S24vYTrJcdTAwMGLbYTMviq+GZVx1MDAxYZTHmbjlqaYgw6WE9H3k4munbKJcdTAwMDbHXHUwMDBiUIK11Vx1MDAxZDSI166zloqMmaxcdTAwMTnOJObvTlx0XHUwMDFjj5VMr8aoW59cdTAwMTZcdTAwMDJGbv5yy7apf1UpXHUwMDE1XHUwMDE0XHUwMDFlU1x1MDAwN1Msd5IyaFxuxtXHnlI0qdWHxkvezVVykLdcdTAwMWVcdTAwMTar4lx1MDAwYlNcdTAwMWItv1JClrXTfYBniaW4qN9JYZ8kMSU3oVdGOuO4Klx1MDAwZlx1MDAwNa9cdFx1MDAwN/WaicIshtCTaGRcdTAwMTlcdTAwMWazR7H4dtPUXHUwMDA1lttcIkrgJjx7pzXjzOotcMhDfYptcFxmhT2zXHUwMDAxs/o2mlx1MDAwMpv4mM1cYpx73V0gjluGX1x1MDAxZpGa+LBJ8UVWuS2eXHUwMDBlh8RvxKY917PtiOZdprg1NVx1MDAxNp0p8rxzeebmbYZRXHUwMDE0J+nip5hcdTAwMWJcdTAwMWWNMsP291x1MDAxZOZcdTAwMDcsW1x1MDAwZTBccpGbpl359MPAXHUwMDEz0sNeSMqNbaxrnfKmpTVkcNFAsszjUTYkrnFJUFx1MDAwNFx0XHUwMDFk39GU1MqTPjrGXHUwMDA1mLFZ1Fx1MDAxZjfuRVx1MDAwZdfVgVxm01Ohuyt+13S2tjJM3ujlbsT6LsnOuD1B/LF1Q4I4vbxo+rOfgkn03qs0v4jK7OFcdTAwMTNj/Vx1MDAwNlxigzhxTquCcKvAwMmBUURj3HGN+k1gRd9TXHUwMDExwjotWZCtbrFcdTAwMDdcdTAwMTbzdsNano8r1Vx1MDAwZvmyr5SP7q5cdTAwMTguvIOdUd7LRZ3WXHUwMDEx/OLXXHUwMDE3aeqQXHUwMDEw4sDWKYJcdTAwMTJcdTAwMDa9PkfsZeijklx1MDAxZoxcdTAwMTU+XGIrV/AsPn7XJUXBh3WdkDw0cyi8XHUwMDEzQd5tM7357lmjdm8nopvFf2dcbu6oVa1nQILHg+MwTlx1MDAxMC9cYlx1MDAxNvH9M6lPWVvrseLHTyp29Kb8KFx1MDAxYV31eekolqxXT6C+d1RePZomUfWzlHk9Y1x1MDAxOFdDKvTBI1x1MDAwZX3pIPzw8sdcdTAwMDQq1+D40F0/Sv1J9LCdNlnKJnXupVx021x1MDAxMVx1MDAxZGtcdTAwMWVeky7+RsPXXHUwMDE0fvB0vpvC8z09XG7Spq7A57pgfT/A6/aIffuw2K83hTQgu3v73tdcdTAwMGUs9Vx1MDAxOVs37a/HyyazNGLiIfBcdTAwMTdcdTAwMTbvRotryj3DfnZGmcvTs4bThlx1MDAxYlx1MDAxM4GOMOY70dny+r9r9kT1m6FP5G1cdTAwMTmj7v7EnpBIVdzGXHUwMDEzXCLQTSF5XHUwMDAxXHUwMDA38eThbk+Allx1MDAxM8GodNi5RtpyykfRIMP5qFNcdTAwMGYgPv41XCL09EnXXHUwMDE4PG1FRlnr8yRwfc+MpkKLtcTdzlwi7Va8KVfjRCYmku6aXHUwMDFkj7CCntYzxWj2sWqqN6ksXHUwMDA2o4ZnXHUwMDE5XHUwMDA01dZSOLwsXFyxTCmgQ2S4Su1tgFx1MDAwNC9xkvfdx1x1MDAxY7t8gy9pVay1gKBKw2vvxND2XHUwMDA2XumYXHUwMDAxSPHmvFx1MDAxMMlbXHUwMDE3XHUwMDA3kaVcdTAwMTZcdTAwMTFoKdwh8fbb/1x1MDAwNbCz+Vqiuohadlf7onlqUKMh3Tpbip46emfGjZagskvGrCE+XHUwMDAwc6P/3WBcbiW/tb0h7md131xyy+Wvan9oXHUwMDExmTqhXHUwMDAydl9KiNcuvCjb9VxmuvPuM1x1MDAxMkpyVMcqluUyTVxiXHUwMDFjIdlcdTAwMDRcdTAwMTNn2oD4JEFljVx1MDAxODtmZXxK7lXfi0jEXHUwMDAzR6g+SebNtqbgJuxDIf/ISe8lLcxcdTAwMDRyLyhcdTAwMWLzXHRBZKco45LRcLt9M9mSXlx1MDAwNk2cUizZcvyvS2Q0lG1cXHbZQ59cdTAwMDZn1qNpdFx1MDAxYqIqfrtcdTAwMGbZzN5rotDZYOD7k+jIr6g0JFjUXHUwMDEys/SJXGJovvBcdTAwMTRcdKrVN3BYc6n32uZeXHUwMDEz9Fx1MDAwYu82fVx1MDAwMepcYkJcdTAwMDRcbopcdTAwMTWRnqmqLWVNXFxR4Fx1MDAwZaO3rIBgZ+IutGlf2F9DctNcdTAwMTDQUs1p+iF71tvv7MRJXGJzJSBcdTAwMTj0N7duXHUwMDFkeftQlc/+4u2BwPI68c5S8yA9cFximVx1MDAxYuxqQyg/o+dcdTAwMDZCva/PXHUwMDA1wIf5rKHK3fFXSM/UMpOqXGbnsKRcdTAwMWM22jO+qspowVx1MDAwM3inOd/V53dNYy5h6v2b9ahcdTAwMWFaXHUwMDE2KGKVXHSaJL1cdTAwMDJn2z8rXGI7xo/+OWeAKP5luMnnu0r66kOAXGadr8LB9oqcXFzRqSg3jHMgXiN+ljH56Hr/dZfZmIdcdTAwMTIza+JIfte71cRcdTAwMTdcdTAwMDCc2FxicVdcdTAwMWFjtlx1MDAxZFx1MDAwN+KzoqSS/96L8pRzXFx51+R89dpcdTAwMTXpIPmlW1x1MDAxZGc+uFxc5LZ1ar1cdTAwMTRvipdrgHPve5m51mZcYpFcdTAwMTl6XHUwMDEzuNwoeLZoz9qv/fpSLOT1h9dcdTAwMTY8KVx1MDAwMlx1MDAxZr7JkSqZt4VcdTAwMWaNaqxcbpzliePnXCKzfdnHo8Mu1pT0pTNcdTAwMTD9jFFMoouJd7oz6zzDrC6RM1x1MDAxZlxyostcdTAwMDZcdTAwMTHYONBz1lwilss6mrdUtnHUXHUwMDFlP9XAhlx1MDAwN3wmhvdcdTAwMDVdqFWKyTDJbNTRJXk3XHUwMDAz8opp1Y6UjT5cdTAwMDBcdTAwMTNXW+xcdTAwMWNhv2xNpdRLNO4ywpbrueNcdTAwMTPzu5ReXHUwMDA3f5qzZtJtNsv9a2r8fWVRn8+BaqSa46drvCGboMcoYTy9XHUwMDBit5Fz+yvRXHUwMDAy3Fx1MDAxNFx1MDAxZuipnYCFzNVtRlx1MDAxMIPkXHUwMDFhU95rgTCeS7J3tG9Talx1MDAxOKVcdTAwMTAqJ1x1MDAxM+vZLFx1MDAxOYZcdJHay/1oXHLp8W9aNOdcdTAwMDTcR7E/sGN1jsC8XHUwMDE5XHUwMDAyanZcdTAwMWEtr5I7XHUwMDFjXHUwMDAwcn6FdoMu4OArOqKeh7B0WE7VXHUwMDFlhY1cdTAwMTV0f3Hu8Fx1MDAxMdumwraPKfKTXHUwMDE4RVB12z054EzYalx1MDAxZVwiNa1euLNJishdSVx1MDAxNZhAXHSFp59IuNJF8cRh8u1cdTAwMTDp4mhBXHUwMDFmf4HRv7vyzFx1MDAwZaGHjCxcdTAwMTBtXHUwMDExmSXo2fB7NTVcdTAwMDGFrWHV5lxusVx1MDAxZL8kxFx1MDAwMp2Tw3yD74ZegFx1MDAwMUxcdTAwMWbc/XJcdTAwMTbP495hjzrdXHUwMDA1c1+LXHUwMDEy8/WJjlJcdTAwMWXinCVmeVRcdTAwMTDF+Fx1MDAwNa5cdTAwMTlU7yk+olx1MDAwNoOsfX7Gza06YKW0N7VBI6FcdTAwMDVBfCnfVEIpXHRcIoP0XHUwMDA0XHUwMDFjXHUwMDFlUH/lIINcdTAwMWF8lWU1IyRw5WU9yZ3DXHUwMDE4lZKVi3BcdTAwMWaDvWkrjDGTbJFa1uNIRlCeXGY8Mv4t8ehcdTAwMWWMIL33ODaH8z7CV6Gu5mE9bMfQry3uXHUwMDBiX2w4eTD9W7Uw7lxuyS8gXHUwMDA2yP9cdTAwMTaJf5NcdTAwMWY7oj5QXHUwMDA2dZUp0XDkZ3llcFVcdTAwMWPWPFx1MDAxNMXcsdd78W1x+Lw05Vx1MDAxOeWWXHUwMDFjyp9MmVxmT61cdTAwMWOvPL9Gtzi7UsCGXHUwMDA37lx1MDAwMVxuJFxmKShQy1x1MDAwNPtr1OBki9Olf1x1MDAwM1x1MDAxYWzOxf44KnpEpHJcdED7aLztXCJjf1xixFxumbzoXHL4sPemXGKiXCJ+rIOR27mAvqOko76+P+xcbkDyhlxyXCJTXHUwMDFhbfLEmkntYKP4T1x1MDAwMomwqURcZlx1MDAwMzBkXHUwMDA0JoBv2lo4+b00VmjPP0Dgz3k0XCLMj1x1MDAxZZ/3XHJA9XrXkPSU215OZCZcdTAwMDBuya/7R/xse+H/4rqMXHUwMDA1gfl9zuN6Rq1jXHUwMDEzv1x1MDAxY9nwtGYmXHUwMDBm2/KDwpVCXHUwMDA1h31m23ebXHUwMDFkhSvz3bKpbiVfr0Se9c1952clJbH29e+xXHUwMDA3hGbW/PM1XHUwMDEwMUZEl85ppY2F81x1MDAwMt7C4H+cwpg5xq2b++2S8CRcdTAwMTVcdTAwMWNfrVx1MDAxOXF4dISJ0N5H821XUlx1MDAwNYqfITeAJW324qo/h1x1MDAxMkWscHE69X9cdTAwMDXbXHUwMDA3XcxKi2FcdTAwMDCHt8kv7tIov1x1MDAxZjJcdTAwMTB2U3z4rKZH9khKXFzOZ1qsxnwyT5hcdTAwMWV8Q69cdTAwMGLJYvXt4b6g2XS9X6pcdTAwMDNHnoeU53HdazhcdTAwMDJFRWWQ93ePR6OvXHUwMDBiRkI9mVx1MDAwMDPyqVx1MDAxNje/uP25xIdcdTAwMWFyXfk7N/su8KTVubjsX2z/+yS6tHQpW5DTXHUwMDFkOyg7tpp2g4W2+XLKs1x1MDAwNFx1MDAwYim9XHUwMDA1x7eSKXKaWNaaXHUwMDBmiCZiOPZaciU73MukXHUwMDEy8Xi/8TJcdTAwMDIujvDKp2n6NugttJBcdTAwMTZZSFx1MDAwMyFpMufZk6RcdTAwMDZcXDe3WTatXHUwMDBiioYxXFzer1RcdTAwMTbTVcU4++PCXHUwMDFko01MJpqku52pzMtcdTAwMWbDIErq61x1MDAwYk9cdTAwMDKW0S/Yynu3rdRdRGCNXHJcdTAwMDBgXHUwMDE2aNi+q5Du3Fx1MDAwNVx1MDAwNm5cYj5MxFx1MDAwYlfVM5GDIejctJ0hYPnlx+FSXHUwMDEzZFxcNVx1MDAxNVx1MDAwMsAon/dWLlx1MDAwYvuJebpCsVx1MDAxZlx1MDAxZKhcdTAwMTPUWNjgLcB2ik2p5vQ7KS+LXHUwMDBl8vT7YEuBhXBFoCYxZDJfZ/D2XG44jjlHNF/YPMiA+06FhcpcdTAwMWaGYUD433vbOJV5XCJOrKInS8flQndo8tTv7TPchSXnZYmIXHUwMDE5ukNeXHUwMDFhVLx1Wf5oVsDfq0bjpEyPTsM8nat25me8xPCG9PsqWMAsZFK7WrP1v1P+ZFxuKlx1MDAwNlx1MDAxOaR+2CdyL4aBw8xzryRV1M92f1G8vs9v0fmnp9tcdTAwMWWJI1x1MDAxZNylWmXUw034leH7XHUwMDA1XHUwMDFkZ7z23PuTXHUwMDEwXHUwMDAyvE+sQUpEnmZcdTAwMWFopNrfY52qbjwpwJfh0YVe/1pqtsiKho85qUpcdTAwMGXNp1x1MDAwYibU1jZcdTAwMGZU46zVwlxu5Y/rPXU4PMPwd4D9XGZcdTAwMTYvyqDgtrHwu6eTe1xyzIAhSfqjkd5hXHUwMDEyXHUwMDEz9euyV4u3vlx1MDAwN+Pll1rpJoyrUnxjXGIsXHUwMDA3MM9ilytcYsSyfMW4Mqd/tfo2iVx1MDAxZqJDTHeHP1x1MDAwYm3vfPWzgYH7iDayLFx1MDAxNkVcdTAwMTWcXHUwMDE1xPjFOHJGdVx0XHUwMDA1aMW9yzZcdTAwMDWSI5g33U3HN3pFmmWOxsXTQGjI+ONYI1EkM95tcJjEXHUwMDBmXHUwMDExQ/Ek9IheqMFFj79gh1xieJZCXFzqyePnSPXy+OO1kk/CTsrmXGasIJRcdTAwMDCrLy3Yy+XXS1x1MDAxOUWSluY2eKCPNFx1MDAwNYjNYNxf5P1cdTAwMDT8yVx1MDAxNlx1MDAxMaxva8c2XHUwMDAxPFx1MDAwYl/FU8R8kVx1MDAxZDxXaVx1MDAwMMw2XHUwMDE1XHUwMDAwLVx1MDAwMGJdXGL/TpJ3XHUwMDA14mPcbY3pt1qETyvltFx0ZYnTQ/fptMt1LioskvTw07KaXlxmIJwuoPvyq1x1MDAxM78rMDmuXHUwMDFm/V7+npTfaI5cdTAwMDCoJlCJ7KXl9Fx1MDAxMYm9zvfPTCyeu42BgOUvkUS/XHUwMDE1+IqAN0m7/enBnY6iq1x1MDAxY/OxSqhwoiGp+1x0m3zEXHS2zW9cdTAwMTZccnwwplx1MDAwZp77LpZcdTAwMWRHWaBIgy95VEbczzw/XHUwMDFh01jNXHUwMDA2XHUwMDFmbkLt0U3dWfbiM25wrVx1MDAxOWe1qzpcblx1MDAxYcxm2EA72uP+XHUwMDExyXQ1RFx1MDAxZdtcdTAwMTVmYFx1MDAxOMY8xVx1MDAxY5KN6M1mXHUwMDE58jN8r5RcdTAwMDFsOtNYUFx1MDAxMXhcdTAwMDNHnVx1MDAxN1x1MDAxOJjiXm71zmbKUEOD4yvSgobXnVx1MDAwNFx1MDAwMpfA9JhcdTAwMDQxd6C6XHLgXHUwMDEyXHUwMDA181ZcdTAwMWNVXHUwMDA3jZuaxZBut8bWVTxDQFx1MDAxMIZu/Wdsn/glslx1MDAxZlx1MDAwMuVcbkiWXHUwMDEzXHUwMDA2rTpcdTAwMTKQZLXBXHUwMDFkjILMuyFoPLT8dUnnuZ3m2PVCZou+ZH7pi2nkPFwiiCS2x+2PKYq+tz/YXHUwMDAynPq+zC/TsES6QqHILk4xMYbKXHUwMDA3nfiAWV0kLK9cdTAwMTB82oGKvbwySWnrd4S7iExNvvFcdTAwMDFcdTAwMTFcdTAwMTkjnFx1MDAxZtqRfemf8cinM4Uv73hcdTAwMDPEXHJNMoy7yS+UXHUwMDFhxmWRIZzLp6NcYrBuxWcr5pNkXHUwMDAwSTu+k1jrfu+ZikntXGaW5GdMXHUwMDBiVX4328+W0DhsXHRFzG8vhdiYd6NcdTAwMDZjXHUwMDFjuqC+dYP5I9bU+kj2hVmBvb7ax2RTeDGPbJ4pSjBcdTAwMTGJbOx7RVx1MDAxZt02fYT28HFcdTAwMDUowv9cbmCUOVx1MDAwMbYwVSgkabNP5qPGuEZcdTAwMTjTb6a3QYBN/DIvzu6R79ZOTLHlYERMXHUwMDAwXHUwMDE2XHLDZL3oR8TiZGsvK2gvim/3NIfIRXaP4lWHllx1MDAxZqfic1x0sszXym2dgePqfqfwXHUwMDEyo1x1MDAxM+nzSOJcdTAwMDVknkIsYlt0smu1XHUwMDA0Vobk+2o7fDPXmFxybVx1MDAwMLbBzVx1MDAxNp62tVxivfmQSmjpbjlcblxi2tR4NX1Wo5IuxJ87XHUwMDE1u/Dx+YLsSFWaS5gtXHUwMDBln86UinlcdTAwMDJcdTAwMWHigHHeTLbmkL87V1d++Vxm5d5w60eYXHUwMDBijcr2KsimJKw/yCa5sp9cdTAwMWJcdTAwMTPcXHRG16469MPesnymXHUwMDAyvbe/myFcdTAwMDRcdTAwMTNcdTAwMDKnzbey5mi6iz5cdTAwMWQ+yNS/k/FLuszqXFybXHUwMDAxL4w31P1cXJy4nneNolx1MDAxNUBxVmXHXHUwMDE0wH7HIVtJzUVcZnxGK4zwXimBWnA9z2ExyFdrcHyIXCL5yVxyWbfQXHUwMDEwxpPax1S+pUlcdTAwMTdCg7c1J3guV3yqy0Fcblx1MDAxZIqdYVx1MDAxMVx1MDAxM/C6XGKV+LDvNDH1ifGmXHUwMDA2qiNcdTAwMWJn1E/xvClSXHLgbFx1MDAwNpxQharXL1x1MDAxMlx1MDAxN21cZrAwy/zGyWB/8Vx1MDAxMXdcdTAwMWG8uc6I+3jPuiTLXHUwMDE1SGpDXHUwMDAwuDD32Vx1MDAwZbBcZsRgj9SHR299bzpkbKpC41/wOV1cdTAwMTcuUkFCXHUwMDFhdrB4S0+lnMyrwz2eXHUwMDFhrKpcdTAwMGVsQMDV2n5OkDvWKGWwqUSoXGbb4Fx1MDAwNvdUtYK6QmaJrFsoOVx1MDAxZvcnx8DjT05eySyBe5/BXHUwMDFkq89qvDzLMXxKu8DYXHUwMDE2aJ6Cn2c7/ND9WcRIZlx1MDAwN8lcdTAwMDc1QFx1MDAxZd+yXHUwMDFhXHUwMDE2mv2AOKwg6u9cdTAwMTF+XHUwMDAzX1V4PDmWLTVcdTAwMWFcdTAwMThcdTAwMTnf1HLRXHUwMDA1VqdcdTAwMTfNybNcdTAwMDPtUatCxX75XHIx+ZXcbyxuP5iSVFx1MDAxNstoPyuaM+JMaIL4drgwXHUwMDFknC/hnuKOwlx1MDAxNKwsXGZ7OkVAnVxyp8jSlGKR8kRcdTAwMDFcdTAwMTM/6uhZj7uZo38oXfyMLfQxvFx1MDAxZpZBbVaDXryy5mix/GrOL0qLXHUwMDFib9o3XHUwMDAyn8Dtj1xuXHUwMDE4hVx1MDAwZrE4uVx1MDAxZEEyKVx1MDAxY1x1MDAxOVx1MDAwZVPFMDbTL1a9R6Wd1HiLXHUwMDE3R25x4TdHVqGZbWHVxXPQsu7c892sw+Hv529cXKLK4s+35ZHTpmKmallcdTAwMDAk1+whNrhcYpZm2nLGx7Z2XHR3oEuyiKHFz56fj8G8XnDofNvb7SWIP7+NXHUwMDAwhFx1MDAxNmOqyFx1MDAwM9NcdJ3RgKCfRv6dSJ1M6fRcdTAwMDHYIa84XHUwMDA0teqQ9b/hy16Z5GDYLCX7XHUwMDE2+fLGrpwnO5r/6eVQYncqn4QrKFx1MDAwZXO14HxQrcKfb11YxSeFgCsmjL9/2/dRXHUwMDA1NMQg9jf4a2Ig4VF9ZapcdTAwMDN8pJVcdTAwMDQru1BcYpJ2RYGLOZLRmlx1MDAxMJlPf1x1MDAxOUpcdTAwMDRH99Jhai1FSo3fQoXrXHUwMDFkY27T0rKXXHUwMDFmhHiEk1v+oLs/3o97at2N9sWKa36SyvM58YnG6+NuQKlcdTAwMWbFOlx1MDAxMGRe+NGb5fFcdTAwMTLKgCdcdTAwMWZJ9L6CzsNdXHUwMDA1so1N4vQqNktUpa29lVRiaVx1MDAxOJWjUPsqYVx1MDAwMOJLPFx1MDAxNWhNUXVUXHUwMDEwNuS+cFx1MDAxNdVPj3HS8ktaXHUwMDEy1LepJ1x1MDAwNFx1MDAwMezGLM5cdTAwMTH8SOSyVWgrJlx1MDAxY1qOuH+HXHUwMDAxXHUwMDFjNqdcdTAwMDE3sCw1k51823dd1vW91il+v9RcdTAwMWM0eiGcmltcdTAwMWGqXHUwMDFkvWRcdTAwMDDDhLDU6cpcdTAwMDI1Y1x1MDAxZpdbfPSUmbtua3PdXGI28XffWFOXdygt3N02S0AqKIxkepRcdTAwMWR8+5WGeFe7XHQ6K7NcdTAwMWXtXGZi5ZaPolx1MDAxY97PkG3r9HThkFx1MDAxY0Ndm2dp5lmKOIpcdTAwMWaFXHUwMDE3ZGXZXHUwMDFlTNSI4YV0k1x1MDAxM1wifZbGOlxmX9WuMtY66+pYXG4juVxm9CBcdTAwMTdcdTAwMDWkJlx1MDAxMpF+QZmua7JcdTAwMWSC50Asqlx1MDAwZYFcdTAwMTcqblx1MDAwNkW8SXUtLd73XGJcdTAwMDNq/tyIRGD2KFx1MDAxOe2EX4jmdKlCrVtgMlxm1lxuN5meIPI1XHUwMDFl5SQ+bSsjrF2IXHUwMDAz0+frj1x1MDAxNqrSO/ttXHUwMDE5xKb0iXwsjVRcdTAwMTJcdFvvVNJrn6CDQKBgXGLucIpKYLbLW1x1MDAxMZq3xkIrXHUwMDAz5Km0+XFrPDQ+dVx1MDAxNrQ+hFx1MDAxONzvXHUwMDE11SHZL0ow2Vx1MDAxM2M7Kju8jqTHkslipfzwuPdqXHUwMDBlmphgV1ZcdTAwMDAoXHUwMDE2QulcdM5tlaJcdTAwMTTMLLDjYqBcZn9PMHnq8lx1MDAxMG+dXHUwMDAxTJv7Olx1MDAxZZ5VXHUwMDEwV7JX/Uk8pVVcdTAwMTY4dPNW8bWFu+Ju/PzWXHUwMDBmeEFcdTAwMWG2KVx1MDAwZkBcdTAwMWPfXHUwMDAzdqiuVlx1MDAxZfXiY6356UrR7H1CmvBVXHUwMDFj3WrYiOA+4WD2fUiEX8p/YkqxO/Z0Ut3wktnuv+VJ4JNcdTAwMTNcdTAwMDDX5X6TXHUwMDA21ckmLHrCXHUwMDA0TVVRXHUwMDAwd07Dc8PBXFy+32tHnFx1MDAxOM3uV82UXHUwMDA1ntNEKr9Q393s3k3Ya8ck44bdq7IuvO9eqVKAs1x1MDAxMFx1MDAxMm18TEN6ueAp9yqTjcNcZp598JJcdTAwMTSYxa9+pdNcdTAwMTmcYyVcdTAwMDRcdTAwMTG8bjMu/7pRyVx1MDAxM1x1MDAwM1pcdTAwMGVu+z5cdTAwMDJcbilcdTAwMGX03aZHvyS3ovPJaJGpYec2T9Vghlx1MDAxMYa3g1x1MDAxY+9De9tK4HDKNVwiXCKP6Z6HXFz+7rvyXGI1QqKerVx1MDAxOTJcdTAwMWR+eHGaScmxK/9r3lo1XGKIqzbDupVqXHUwMDExWlx1MDAwM8LeammkuLPzVyq4XHUwMDBiTbxcdTAwMDZcYmTtKb+/rdrbjV0ySc0+91x1MDAwMUfDXeKzJaq27LN1XHUwMDE4W8angI/wybkoX1x1MDAxM6kuUSVXUlx1MDAxOVbw/KySwNzhL2NccnKEaJxBkPtrJmzkzoyc61x1MDAwMc84X+WKXyGwN1x1MDAxZvmi29H2PinCW+dcdTAwMTCdZzT32r2010tsjVxc9lx1MDAxNlx1MDAxMFx1MDAxNv64Olxipl1cdTAwMGLQv/pcbtdcdTAwMTJcdTAwMThZuqExXHUwMDE0QlVPaqNEXHUwMDE5XHUwMDAy61xcweS02ZJcdTAwMGKXfuqB46hktOC/o1xyXHTlXCIud9hcdTAwMTmZcuKS5p/lXHUwMDA2a/U4XHRttVx1MDAwM8GI2DV3eL+2/Ek1hPkseTU5LVx1MDAxNCZcdTAwMTP5Vi1cdTAwMThcdL6/vzNcdTAwMTgmt/fuXHUwMDEzP+/+XHUwMDEwnFx1MDAxOFx1MDAwZuRHXHUwMDBi5LpS0z08uKds3EdAtLyxunpcdTAwMTeFvD437bwj9Y13zJzvTEVt5rNcXF9cdTAwMWPwRPxcdTAwMWNPtY9IXHUwMDFhyI/Sqr6/6jgkMZZcdTAwMTPliVbbMFx1MDAwMdPyXGJuX7Sf60Fmxlx1MDAxYaexOoVkXlx1MDAxODwrXHUwMDA34Fx1MDAwMKdMSbfib1x1MDAwMdYyXFwxbYdcdTAwMWT4o4GXk23LP1x1MDAxN3tlQM20XHLgvGQ3XHUwMDBi12hepMl/hyh1en84ydqZv8Q6ZFx1MDAxNYnyX1x1MDAxZVx1MDAxYb90XG7JkoR1mvnOcVx1MDAxZo2QcK4xNlx1MDAxOT80XHUwMDAwgMCG+fOqyV1cdPMorikrXHUwMDEydslTVsJQPqBvxDWCzYXfzZr40/ZnzPdcdTAwMGbQJkSkXHR4UMlgWbeZUVx1MDAxY7BeYCVcIjpldjg1jqT8XsGuxsOfM7vHaLdcdTAwMDBcdTAwMDXCM2qromFSju3GfDdyZlx1MDAxMEJrjqOjXHUwMDEzt1x1MDAwMYCjXHUwMDE0tnd7gmWWXFzuM1x1MDAwNTwsZkJ+XHUwMDEy9EL6XHUwMDE2/bhcdTAwMTfPSa76soYp5KnVXCJcInBFjGdgteT/TFIuVCBcdTAwMTm2pe83c1O/6yXj1OHJrsKmaSG1mzx4wS9Sx/tcdTAwMWKRKsyB7JBcdTAwMThcdTAwMWb6Y1xc3sfEfefvOT5BT9LPXHUwMDE3u96812JcdTAwMTl2XHUwMDA3N+VJuv+enjtas1x1MDAxYWQs1Vx1MDAxYolcdTAwMTPvIcOH4DytXHUwMDBlYZbh4sxOLZeM3DnI3cPyz6zFYPNgw/NA6rrll/q2V1EuMrDnNrbOg4hkziHm2aqnTvdcdTAwMTefXfz+Sso8r82yhXKftSVI5exIeNefs1x1MDAxNIL5LVbEgFx1MDAwMlx1MDAwMXhY3YViXHUwMDBmZUaeRL1t70hpWFGYpPRSYaelQk2LXHJcdTAwMGVcdTAwMTXes15cdTAwMTbx8vVxl1x1MDAxNZt8XHUwMDBiv8/zckSIbK9CWVVpuXOjO4pjqLp+f5o6tiiIbaB09ryGRD/MXHUwMDBl8UI/vnz2XHUwMDExXHUwMDAyvoyuprFquDVC81rOuk9cbvZ1hya5XCI4qzAk9kj9M6Kl3tS9x15jd8Hwu1Yn0E9qMIYlYyuYj5zsXHUwMDA0/Xjnflx1MDAwMlx1MDAxNddNaVjFpXmfM6aXO1BamdI/zpSs1fmEccCdzThcdTAwMTZ12o2Nflx1MDAxN1x1MDAxNM1cdTAwMGJcdTAwMDOGXHUwMDE5b/9/aq8+zONcdTAwMDAybEaDNNtcdTAwMWM2f/nAXHUwMDEyrkTntVokK/Tv3Fx1MDAwZUU0nFwi8jT407Q3r01szk5IXHUwMDAziHVcXF06LmtZtll+XHUwMDE3XHRkhFpprUNSRE5cdTAwMTBR+Z5cdTAwMDKR1Fx0fvSDIVx1MDAwMHqFq+rbvSZIvJthc/Th9MOl5Vx1MDAwN/unQdEvZCNzXHK/XHUwMDExXHUwMDFhRpaDWMz+und8TKqN4ETe10qnnkZapGJeVUlCLdHzTFx1MDAwNpdcdTAwMWE/h/5cdTAwMWQ1e5iYQ1x0XHUwMDFi01x1MDAxY+lZPMrz9INQNISk8JpGuMNcdTAwMDTT1yBcdTAwMWFRR5ogh0NcdTAwMGbGPjLXXG6kXHUwMDE3sDRcdTAwMDNqZcF/6uf97kthf3o7+37NQGurUNmApcRPb37VaFxupmRwYEgs01x1MDAwNYajZtRcdTAwMTFcdTAwMDYlXHUwMDEwXHUwMDE5XoXZP37CYKqzunRcdTAwMTjcNnw+6V7jY0lgXHUwMDE5XHUwMDA2ZOiQ1jMsbdb8PFx1MDAxNFZYXHUwMDExSe3gL8tuvks++Fxcm3TK4/xm0jhEQWZJ9/xcdTAwMDJcdTAwMDRcdTAwMDNMpFx1MDAxNe2MUEZDhVxyzM0+LPqOOlx1MDAwNFx1MDAwMsz7ifjUrCRgyHXzucJXXHUwMDEyXHJ4XHUwMDE0tpl4UmKJ4uggV1x0pThZ3ewk9ev5XHUwMDAzTMIm01Z2gVx1MDAxMdJocIBcdTAwMTDoIVx1MDAxMe2zdVdcdTAwMTL5tPhzXHUwMDE4XGJcZjvBkfTpsGNoXFxR2EFcdTAwMThah1x1MDAwMt1ZpWVb/D1cdTAwMTaOZrTC0Vx1MDAwZlx1MDAxZIy+3lx1MDAxYlqG4JU6XCJqfJxOoGdjMKVm/KqrQ1x1MDAxMina6qGl1TgkpUZT1HaK61x1MDAwN0rDqWWK86pcIpy/e7a/KsBcXFx1MDAwNGwlXHUwMDFjzaHKnVx1MDAwZmf4gIE9XHUwMDE4wVx1MDAwZsx3XHUwMDFlTSzWLCSL7oHTXHUwMDAzXZ3eeVx1MDAxMnSOVapcdTAwMWbzXHUwMDFiXHUwMDExXHUwMDEweFx1MDAxNnOyz3wgXHRA9d/OUyBhgoao/3Kewt/Dg//53/9cdTAwMDFivclyIn0= + + + + + pgbackupBackup architecture for PostgresRemote copy architecturePostgres connection(for management purposes)Rsync backup(barman to postgres)barman_wal_archive(postgres to barman)Postgres connectionsRsync/ssh connections \ No newline at end of file diff --git a/docs/images/source/Barman-rsync-backup-receivewal.excalidraw b/docs/images/source/Barman-rsync-backup-receivewal.excalidraw new file mode 100644 index 000000000..14ad3c9b6 --- /dev/null +++ b/docs/images/source/Barman-rsync-backup-receivewal.excalidraw @@ -0,0 +1,969 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "1ZzBrWEHwMbkiSQ937jS_", + "type": "rectangle", + "x": 280.55864661654135, + "y": 382.7789473684211, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 2097703460, + "version": 386, + "versionNonce": 140378148, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "FUELyXBPcB6gf1H-ELi3a", + "type": "rectangle", + "x": 829.2323308270677, + "y": 386.2736842105263, + "width": 190.71278195488725, + "height": 202.69473684210527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": { + "type": 3 + }, + "seed": 1386606756, + "version": 609, + "versionNonce": 1679478308, + "isDeleted": false, + "boundElements": [ + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow" + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow" + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "ZQBQiZKK1TTwKqd7MXAMm", + "type": "text", + "x": 359.4398496240602, + "y": 538.5443609022557, + "width": 31.086517179484357, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": null, + "seed": 1697128612, + "version": 420, + "versionNonce": 550129828, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "pg", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "pg", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4neJBFAF6jQ35NUlbGebi", + "type": "text", + "x": 878.6578947368421, + "y": 540.5413533834587, + "width": 91.56410319010416, + "height": 34.94736842105263, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1977030308, + "version": 529, + "versionNonce": 738237476, + "isDeleted": false, + "boundElements": [ + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow" + } + ], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "backup", + "fontSize": 27.957894736842107, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "backup", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "g8P0muvVQ88DvKGMJmV0D", + "type": "rectangle", + "x": 228.63684210526316, + "y": 236, + "width": 845.7263157894738, + "height": 664, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": null, + "seed": 2126547484, + "version": 419, + "versionNonce": 2098914084, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "SPCm1UV2vaWBMhVMDRUJU", + "type": "image", + "x": 337.47293233082706, + "y": 449.6781954887218, + "width": 70.89323308270677, + "height": 70.89323308270677, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": null, + "seed": 239434660, + "version": 311, + "versionNonce": 94035620, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "status": "saved", + "fileId": "46592fa2e930e621fb84c5731ee38deba57530a4", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "1tSeOxu4bvvm1bBII4boa", + "type": "image", + "x": 872.7015186481054, + "y": 444.18646616541355, + "width": 86.33532345715773, + "height": 70.89323308270676, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 1149200548, + "version": 507, + "versionNonce": 59730468, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "status": "saved", + "fileId": "0833b30d1a4da2b737b05a0261e434640c53058b", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "SKIYhR2pT9ePU_N3-qjcA", + "type": "text", + "x": 242, + "y": 68.5, + "width": 802.070385105881, + "height": 73.60000000000001, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 450504476, + "version": 166, + "versionNonce": 1237256476, + "isDeleted": false, + "boundElements": [], + "updated": 1732004135233, + "link": null, + "locked": false, + "text": "Backup architecture for Postgres", + "fontSize": 54.518518518518505, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Backup architecture for Postgres", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "hVDj-LHqEF0t6Tl11s2LZ", + "type": "text", + "x": 234.16000162760434, + "y": 165.86240812442435, + "width": 834.6166381835938, + "height": 43.13759187557564, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 904209180, + "version": 564, + "versionNonce": 2091641764, + "isDeleted": false, + "boundElements": [], + "updated": 1732174161426, + "link": null, + "locked": false, + "text": "Rsync backup with WAL streaming architecture", + "fontSize": 34.51007350046051, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Rsync backup with WAL streaming architecture", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "4v7wWZXi74Bxw2oKBmYHL", + "type": "rectangle", + "x": 458.3390977443609, + "y": 753.2060150375939, + "width": 24.962406015037594, + "height": 25.9609022556391, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aN", + "roundness": null, + "seed": 593654428, + "version": 363, + "versionNonce": 26635172, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false + }, + { + "id": "pnSRfbQP1_xcrej7vbeAU", + "type": "rectangle", + "x": 459.3390977443609, + "y": 801.6045112781954, + "width": 23.96390977443609, + "height": 23.96390977443609, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 311884572, + "version": 650, + "versionNonce": 1922127652, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false + }, + { + "id": "qWfMTSJ4JuEQpqKK-Hupw", + "type": "arrow", + "x": 422.34511278195487, + "y": 383.7774436090225, + "width": 459.0740840644434, + "height": 74.88721804511279, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ai", + "roundness": { + "type": 2 + }, + "seed": 592542500, + "version": 767, + "versionNonce": 1259014052, + "isDeleted": false, + "boundElements": [], + "updated": 1732174468060, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 56.91428571428572, + -70.89323308270677 + ], + [ + 380.4270676691729, + -73.88872180451129 + ], + [ + 459.0740840644434, + 0.9984962406015039 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.1931402196402995, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.3213161961438585, + "gap": 1.4977443609022885, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": null, + "elbowed": false + }, + { + "id": "48CxuQFcU4inZCVx0hd4d", + "type": "arrow", + "x": 472.26992481203007, + "y": 482.62857142857143, + "width": 355.9639097744361, + "height": 2.089573357269705, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aj", + "roundness": { + "type": 2 + }, + "seed": 1620519580, + "version": 495, + "versionNonce": 1238297500, + "isDeleted": false, + "boundElements": [], + "updated": 1732174464788, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 355.9639097744361, + 2.089573357269705 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": -0.020247506155730458, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FUELyXBPcB6gf1H-ELi3a", + "focus": 0.022935461485079463, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "lnmxRSCzbn94H72gGcNwU", + "type": "arrow", + "x": 418.3511278195489, + "y": 588.4691729323308, + "width": 465.0958370263172, + "height": 94.85714285714286, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": { + "type": 2 + }, + "seed": 208601628, + "version": 661, + "versionNonce": 403711268, + "isDeleted": false, + "boundElements": [], + "updated": 1732174457132, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 53.918796992481205, + 94.85714285714286 + ], + [ + 389.4135338345865, + 93.85864661654135 + ], + [ + 465.0958370263172, + 1.9969924812030075 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "1ZzBrWEHwMbkiSQ937jS_", + "focus": 0.11031710585082588, + "gap": 2.9954887218044632, + "fixedPoint": null + }, + "endBinding": { + "elementId": "4neJBFAF6jQ35NUlbGebi", + "focus": 0.236919665601773, + "gap": 14.9774436090226, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "J6xU_Pt8Qv2vG9vtlgF0o", + "type": "text", + "x": 506.2669172932332, + "y": 755.203007518797, + "width": 219.66917293233084, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "am", + "roundness": null, + "seed": 144537884, + "version": 187, + "versionNonce": 1814221476, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false, + "text": "Postgres connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "rWwqK9mZASAZ9tsCkYhZA", + "type": "text", + "x": 507.26691729323306, + "y": 801.6045112781954, + "width": 329.50375939849624, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "an", + "roundness": null, + "seed": 1368290596, + "version": 380, + "versionNonce": 1022942756, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false, + "text": "Postgres streaming connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres streaming connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "Le_pTc_Rwx0iNbqSMjzwk", + "type": "rectangle", + "x": 526.1887218045113, + "y": 271.9458646616541, + "width": 269.59398496240595, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "av", + "roundness": null, + "seed": 1342530852, + "version": 446, + "versionNonce": 799540772, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false + }, + { + "id": "h9kkrSHYTc0yqOK0Hc8QY", + "type": "text", + "x": 531.6205415057418, + "y": 282.9293233082707, + "width": 257.7318493193432, + "height": 45.95482352549884, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aw", + "roundness": null, + "seed": 1541742756, + "version": 466, + "versionNonce": 1351328164, + "isDeleted": false, + "boundElements": [], + "updated": 1732113797091, + "link": null, + "locked": false, + "text": "Postgres connection\n(for management purposes)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Postgres connection\n(for management purposes)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "JWscPEsiXw56xj5PMIYAb", + "type": "rectangle", + "x": 574.1165413533835, + "y": 654.36992481203, + "width": 163.75338345864665, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "az", + "roundness": null, + "seed": 1046108708, + "version": 604, + "versionNonce": 1210608420, + "isDeleted": false, + "boundElements": [], + "updated": 1732174081958, + "link": null, + "locked": false + }, + { + "id": "kQqv-gQNveFMs3HCpPqk1", + "type": "text", + "x": 577.551368573411, + "y": 666.3518796992481, + "width": 154.88673653738834, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b00", + "roundness": null, + "seed": 2111010212, + "version": 767, + "versionNonce": 2101496092, + "isDeleted": false, + "boundElements": [], + "updated": 1732174081958, + "link": null, + "locked": false, + "text": "WAL streaming\n(pg_receivewal)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "WAL streaming\n(pg_receivewal)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "MEIOIkWXtFzSqBXGvwWNV", + "type": "rectangle", + "x": 549.6308270676692, + "y": 454.2996240601503, + "width": 207.73834586466154, + "height": 65.90075187969927, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b01", + "roundness": null, + "seed": 836224028, + "version": 729, + "versionNonce": 1320451612, + "isDeleted": false, + "boundElements": [], + "updated": 1732174120810, + "link": null, + "locked": false + }, + { + "id": "38M4rhQ2TcKj9soIdHGhB", + "type": "text", + "x": 550.0701655658924, + "y": 465.28308270676683, + "width": 205.8566613494184, + "height": 45.95482352549883, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b02", + "roundness": null, + "seed": 1526784156, + "version": 822, + "versionNonce": 1882610332, + "isDeleted": false, + "boundElements": [], + "updated": 1732174120810, + "link": null, + "locked": false, + "text": "Rsync backup\n(barman to postgres)", + "fontSize": 18.381929410199533, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Rsync backup\n(barman to postgres)", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "022hXi6QrPKhcFAh5MVc2", + "type": "rectangle", + "x": 459.78421052631586, + "y": 843.7687969924813, + "width": 23.96390977443609, + "height": 23.96390977443609, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e03131", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b03", + "roundness": null, + "seed": 269628580, + "version": 745, + "versionNonce": 771848612, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false + }, + { + "id": "GevQLwM6Q5lRqny8Y1sB8", + "type": "text", + "x": 508.96390977443605, + "y": 845.7687969924813, + "width": 231, + "height": 24.962406015037594, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#1971c2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b04", + "roundness": null, + "seed": 816578596, + "version": 556, + "versionNonce": 980067620, + "isDeleted": false, + "boundElements": [], + "updated": 1732174617938, + "link": null, + "locked": false, + "text": "Rsync/ssh connections", + "fontSize": 19.969924812030076, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Rsync/ssh connections", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "RE7dcgqVFfionMygp-o8j", + "type": "frame", + "x": 206.5000000000001, + "y": 169.25, + "width": 1, + "height": 1, + "angle": 0, + "strokeColor": "#bbb", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b05", + "roundness": null, + "seed": 8047516, + "version": 3, + "versionNonce": 944318372, + "isDeleted": false, + "boundElements": null, + "updated": 1732174588293, + "link": null, + "locked": false, + "name": null + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "46592fa2e930e621fb84c5731ee38deba57530a4": { + "mimeType": "image/png", + "id": "46592fa2e930e621fb84c5731ee38deba57530a4", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAgAElEQVR4Xu2dCdxVU/fHl6kkkaKBSoUypMhbolRCM5FU0kATmkiJlAYlFYUylDSIilQqiaRRKCUJFUIqGkzNE17/9d33nvPse557n3vuyNvz/30++3Of594z7nXO3nut9VtrHSP/j1h74Azd4UJtFwVbEf3Mo+0Ubadan8fp3z9r2xFs262/N+vfC7X9FuvJY93+mFh3iGP7fLpPcW3FtP2lbZ+2/Z7GdwfjOLafXUrpRpWC50cAjhAQygFtP2n70fp0/uaaANd+nbaa2qppQ8DJwH/1ICu0va1trrbV2v5OxoHtYyRbwPmDHVFLP8trO1sbT7YfcMO/a1ur7ZNgW6Wf38Z44wikmbYrgo1rigd7dKe92s6KZ+c49tmp+7wTFPYM/fwjjmNk2iUZAj5dj9pBW31tl2k7NhkXZh1jt/7N042w39O2KMzNMxzW03aXNh6uZF9DyC3lypVLypQpY1rBggUlf/78puXLl8988vvvv/8uv/76q/z222/m02nr16+X1atXy3//y/McERv1lwe1TU+0LxMRMILtrq2jtpOzupDcuXNLsWLFzI3v379f9u3bZz5pf/wR84O6S8/1pjae8ne13axtoDamgLAoUaKEnH322XLaaacZIfCZN29eOXDggPzyyy/y888/m8+dO3fKxo0b5a+/mEkycN5550mdOnXkiiuukHLlykmpUqXkuON4puIDwl+8eLG89957smDBAvnqq68iHWiZ/tBN28fxnUkkHgGfpCfrra1zOMEWKlRIatasadoFF1xgOpanOhIQsCP0TZs2maf7008/NZ/r1q2TP//8M6t74+k4wbsBArn22mulatWqctVVV8lZZ/kfZRE65165cqV5KMuXLy88IKnE1q1bjaDHjx8vS5Ys8Z6Kefk1bT21bYr1OmIVcFE9wSxtl9on4m3o1KmT3HzzzeYJP+aYWA8b/rIPHTokn3/+uenwhQsXyty5c83bHwkItVu3blK7du1Y+yGu7f/799+yZ/8h2U3bd0h2Bf8+dOQPyZMrp5x68oly6kknyim5A43vonXNihUrZMiQITJz5kz5W49v4bD+/ZS2/tp8L0hjkQQr0ZnaCjonZajr2rWrdOnSRU49lcVpaoHA58+fL2+88YbMnj3bzGugVq1a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", + "created": 1731966018042, + "lastRetrieved": 1731966018042 + }, + "0833b30d1a4da2b737b05a0261e434640c53058b": { + "mimeType": "image/png", + "id": "0833b30d1a4da2b737b05a0261e434640c53058b", + "dataURL": "data:image/png;base64,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", + "created": 1731966716908, + "lastRetrieved": 1731966716908 + } + } +} \ No newline at end of file diff --git a/docs/images/source/Barman-rsync-backup-receivewal.svg b/docs/images/source/Barman-rsync-backup-receivewal.svg new file mode 100644 index 000000000..9d4ec6211 --- /dev/null +++ b/docs/images/source/Barman-rsync-backup-receivewal.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + pgbackupBackup architecture for PostgresRsync backup with WAL streaming architecturePostgres connectionsPostgres streaming connectionsPostgres connection(for management purposes)WAL streaming(pg_receivewal)Rsync backup(barman to postgres)Rsync/ssh connectionsFrame \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000..ea737be12 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,13 @@ +.. _index: + +Table of contents +================= + +.. toctree:: + :maxdepth: 1 + + User guide + Contributor guide + Release notes + FAQ + License diff --git a/docs/index_pdf.rst b/docs/index_pdf.rst new file mode 100644 index 000000000..8d6da8ff9 --- /dev/null +++ b/docs/index_pdf.rst @@ -0,0 +1,13 @@ +.. _index_pdf: + +Table of contents +================= + +.. toctree:: + :maxdepth: 4 + + User guide + Contributor guide + Release notes + FAQ + License diff --git a/docs/license/index.rst b/docs/license/index.rst new file mode 100644 index 000000000..14f6850e2 --- /dev/null +++ b/docs/license/index.rst @@ -0,0 +1,18 @@ +.. _license: + +License +======= + +Barman is owned by EnterpriseDB UK Limited and is licensed under the GNU General Public +License v3. + +Barman has initially received partial funding from 4CaaSt, a research project supported +by the European Commission's Seventh Framework Programme. + +We welcome contributions to Barman. These contributions will be acknowledged in the +release notes. To ensure that all Barman code remains free, EnterpriseDB UK Limited +requires contributors to complete a copyright assignment and to disclaim any +work-for-hire claims from their employers. For a Copyright Assignment Form, please +contact barman@enterprisedb.com. + +© Copyright EnterpriseDB UK Limited 2011-2024 \ No newline at end of file diff --git a/docs/releases/index.rst b/docs/releases/index.rst new file mode 100644 index 000000000..312a425dd --- /dev/null +++ b/docs/releases/index.rst @@ -0,0 +1,7 @@ +.. _releases: + +Releases Notes +============== + +.. include:: ../../RELNOTES.md + :parser: myst_parser.sphinx_ \ No newline at end of file diff --git a/docs/user_guide/architectures.rst b/docs/user_guide/architectures.rst new file mode 100644 index 000000000..d2734df73 --- /dev/null +++ b/docs/user_guide/architectures.rst @@ -0,0 +1,357 @@ +.. _architectures: + +Architectural backup designs with barman +======================================== + +An effective disaster recovery plan begins with a carefully designed architecture. +Key decisions involve determining where to host your backup server and how to transfer +backups and WAL files, among other considerations. With that in mind, this section +explores a few different setups for deploying and managing backups with Barman. + +.. _architectures-where-install-barman: + +Where to install Barman +----------------------- + +One of the foundations of Barman is the ability to operate remotely from the database +server, via the network. + +Theoretically, you could have your Barman server located in a data center in another +part of the world, thousands of miles away from your Postgres server. Realistically, +you do not want your Barman server to be too far from your Postgres server, so that +both backup and recovery times are kept under control. + +Even though there is no "one size fits all" way to set up Barman, there are a couple of +recommendations that we suggest you abide by, in particular: + +* Install Barman on a dedicated server. +* Do not share the same storage with your Postgres server. +* Integrate Barman with your infrastructure monitoring tools. +* Test everything before deploying to production. + +A good way to start modeling your disaster recovery architecture includes: + +* Design a couple of possible architectures in regards to Postgres and Barman locations, + such as: + + 1. Same data center. + 2. Different data centers in the same metropolitan area. + 3. Different data centers in different metropolitan areas. + + +* Elaborate the pros and the cons of each hypothesis. +* Evaluate the :term:`SPOF` of your system, with a cost-benefit analysis. +* Make your decision and implement an initial solution. + +With that in mind, a very common setup for Barman is for it to be installed in the +same data center where your Postgres servers are, in which case the :term:`SPOF` is +the data center itself. Though the impact of such :term:`SPOF` can be significantly +alleviated with features such as +:ref:`geographical redundancy ` (introduced in +Barman 2.6) and :ref:`Hook Scripts `. + +With geographical redundancy, you can rely on a Barman instance that is located in a +different data center/availability zone to synchronize the entire content of the Barman +server co-located in the same data center as the Postgres node. Also, given that +geo-redundancy can be configured in Barman not only at global level, but also at server +level, you can create hybrid installations of Barman where some servers are directly +connected to the local Postgres servers, and others are backing up subsets of different +Barman installations (cross-site backup). Figure below shows two availability zones +(one in Europe and one in the US), each with a primary Postgres server that is backed up +in a local Barman installation, and relayed on the other Barman server (defined as +passive) for multi-tier backup via Rsync/SSH. Further information on geo-redundancy is +available in the :ref:`geographical redundancy ` +section. + +.. image:: /images/barman-multilocation-georedundancy.png + :scale: 50% + :align: center + +Thanks to :ref:`Hook Scripts `, backups of Barman +can be exported to different media, such as tape via tar, or locations, like an object +storage bucket in a cloud provider. + +Remember that no decision is forever. You can start one way and adapt over time to the +solution that suits you best. However, try and keep it simple to start with. + + +.. _architectures-one-barman-many-servers: + +One Barman, many Postgres servers +--------------------------------- + +Another relevant feature first introduced by Barman is the support for multiple +servers. Barman can store backup data coming from multiple Postgres instances, even +with different versions, in a centralized way. As a result, you can model complex +disaster recovery architectures, forming a "star schema", where Postgres servers +rotate around a central Barman server. + +Every architecture makes sense in its own way. Choose the one that resonates with you, +and most importantly, the one you trust, based on real experimentation and testing. + + +.. _architectures-backup-strategies: + +Backup strategies +----------------- + +The choice of a backup strategy will also play a vital role in your +setup. Barman is able to take backups using either Rsync, which uses SSH as a transport +mechanism, or ``pg_basebackup``, which uses Postgres streaming replication protocol. +Choosing one of these two methods is a decision you will need to make, however for +general usage we recommend using streaming replication for all currently supported +versions of Postgres. + +.. note:: + Because Barman makes use of ``pg_basebackup`` when using streaming backups, features + such as parallel backup are currently not available. In this case, bandwidth + limitation has some restrictions - compared to the traditional method via Rsync. + In Postgres versions prior to 17, incremental backups are also not available when + using this method. + +Backup using Rsync/SSH is recommended in cases where ``pg_basebackup`` limitations pose +an issue for you. + +The reason why we recommend streaming backup is that, based on our experience, it is +easier to set up. Also, streaming backup allows you to backup a Postgres server on +Windows, and makes life easier when working with Docker. + +.. _architectures-wal-archiving-strategies: + +WAL archiving strategies +------------------------ + +Recovering a Postgres backup relies on replaying transaction logs (also known as xlog +or WAL files). It is therefore essential that WAL files be stored by Barman alongside +the base backups so that they are available at recovery time. This can be achieved using +either WAL streaming or standard WAL archiving to copy WALs into the Barman server. + +1. WAL streaming involves transferring WAL files from the Postgres server with +``pg_receivewal`` using the Postgres streaming replication protocol. With WAL streaming, +WALs are transferred while they are still being generated, which means that Barman +doesn't have to wait for WAL segments to be completely filled in order to receive them. +Such mechanism makes WAL streaming able to significantly reduce the risk of data loss, +bringing :term:`RPO` down to near zero values. It is also possible to add Barman as a +synchronous WAL receiver in your Postgres cluster and achieve zero data loss (RPO=0). +With the use of replication slots, we can also assure that no WAL file is recycled +before being successfully received by Barman. + +Refer to the +:ref:`pre-requisites for wal streaming ` +for more information on how to install ``pg_receivewal``. + +.. note:: + When using WAL streaming, it is recommended to always stream from the primary + node. This is to ensure that all WALs are received by Barman, even in the event of + a failover. + + +2. Barman also supports standard WAL file archiving, which is achieved using the +Postgres ``archive_command``, either using Rsync/SSH or ``barman-wal-archive`` +from the ``barman-cli`` package. With this method, WAL files are archived only when +Postgres switches to a new WAL file, which normally happens every 16MB worth of data +changes. This approach offers more flexibility by allowing you to pick a tool of your +choice for transferring the WAL files. + +It is required that either WAL streaming or WAL archiving be configured. It is +optionally possible to configure both WAL streaming and standard WAL archiving - in +such cases Barman will automatically de-duplicate incoming WALs. This provides a +fallback mechanism so that WALs are still copied to Barman's archive in the event that +WAL streaming fails. + +For general usage we recommend configuring WAL streaming only. + +.. note:: + Previous versions of Barman recommended that both WAL archiving and WAL streaming + were used. This was because Postgres versions older than 9.4 did not support + replication slots and therefore WAL streaming alone could not guarantee all WALs + would be safely stored in Barman's WAL archive. Since all supported versions of + Postgres now have replication slots, it is sufficient to configure only WAL + streaming. + +.. _architectures-scenarios-for-backups: + +Two typical scenarios for backups +--------------------------------- + +In order to make life easier for you, in this section we summarize the two most typical +scenarios for a given Postgres server in Barman. Bear in mind that this is a decision +that you must make for every single server that you decide to back up with Barman. +This means that you can have heterogeneous setups within the same Barman server. + +We will be using ``pg`` and ``backup`` to refer to a Postgres and Barman servers +respectively. However, in real life, your architecture will most likely contain other +technologies such as repmgr, pgBouncer, Nagios/Icinga, and so on. + + +.. _architectures-scenarios-for-backups-backup-via-streaming: + +Scenario 1: Backup via streaming protocol +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As stated in :ref:`Streaming Backups `, +this approach uses the Postgres streaming protocol for transferring cluster files to your +Barman server. This is done with the use of the ``pg_basebackup`` utility. In Barman, +this method can be set by having ``backup_method = postgres`` in your Barman server +configurations. + +With this approach, you can leverage from :ref:`block-level incremental backups ` +support provided by ``pg_basebackup``, available in Postgres 17 or later. Block-level +incremental backups tend to be much more efficient than :ref:`file-level incremental backups ` +provided by Rsync strategies in terms of deduplication ratio. + +This method is used in conjunction with WAL streaming for WAL files. In Barman's +terminology, this setup is known as streaming-only setup as it does not use any SSH +connection for backup and archiving operations. This is particularly suitable and +extremely practical for Docker environments and highly regulated environments, +for example. + +The streaming backup method is usually the recommended approach for most use cases. + +The figure below illustrates how this setup would function in practice. + +.. image:: /images/barman-full-streaming.png + :scale: 50% + :align: center + +In order to configure it, you need: + +1. A standard connection to Postgres, for management, coordination, and monitoring +purposes. + +2. A streaming replication connection to be used by both ``pg_basebackup`` +(for base backup operations) and ``pg_receivewal`` (for WAL streaming). + + +.. _architectures-scenarios-for-backups-backup-via-rsync: + +Scenario 2: Backup via rsync/SSH +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As stated in :ref:`rsync backups ` concepts, +this approach relies on Rsync to transfer backup files to your Barman server. This is +done by putting your server in backup mode and transferring your cluster files using +Rsync. + +A key advantage in this approach is the possibility of using :ref:`parallel jobs ` +when running backup operations, which can significantly decrease the overall time to take +backups. It also provides the ability to take :ref:`file-level incremental backups `, +which reuses files of a previous backup for deduplication. File-level incremental backups +can be more flexible than :ref:`block level incremental backups ` +as each backup is completely independent of the others, which means you can delete a +root backup without affecting its incremental backups in any way. + +Another advantage of this method is that it allows for a finer control over bandwidth +usage, including on a per-tablespace basis. You can check +:ref:`Managing Bandwidth Usage ` for further details. + +The figure below illustrates how this setup would function in practice. + +.. image:: /images/barman-remote-copy.png + :scale: 50% + :align: center + +In order to configure it, you will need: + +1. A standard connection to Postgres for management, coordination, and monitoring +purposes. + +2. An SSH connection to be used by Rsync for base backup operations that allow the +**barman** user on the Barman server to connect as the **postgres** user on the +Postgres server. + +3. An SSH connection for WAL archiving to be used by the ``archive_command`` in Postgres +that allows the **postgres** user on the Postgres server to connect as **barman** user +on the Barman server. + + +.. _architectures-scenarios-for-backups-hybrid-scenarios: + +Hybrid scenario +^^^^^^^^^^^^^^^ + +It is also possible to use a hybrid approach, combining rsync backups with WAL +streaming in order to achieve results that have the advantages of rsync backups +(file-level incremental backups, parallel jobs, etc) together with WAL streaming ones +(more efficient WAL transfer, optional RPO zero). + +The figure below illustrates how this setup would function in practice. + +.. image:: /images/barman-rsync-backup-receivewal.png + :scale: 50% + :align: center + +To accomplish this, you will need to configure the ``backup_method`` as ``rsync``, and +set ``streaming_archiver`` to ``on`` in your Barman server configuration. You will also +need to have a streaming replication connection to be used by ``pg_receivewal`` for WAL +archiving and an SSH connection to be used by Rsync for base backup operations. + + +WAL archiving fallback redundancy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With Barman, you can configure WAL archiving in addition to WAL streaming in order to +have a fallback mechanism in case WAL streaming fails. This can be done with either of +the ``backup_method`` configurations described above. + +1. When using the streaming-only setup, described in the +:ref:`Scenario 1 `, you can +also configure WAL archiving via SSH in addition to WAL streaming. In such scenarios, +WAL archiving would act as a fallback mechanism in case WAL streaming failed. + + +2. When using the Rsync backup method, described in +:ref:`Scenario 2 `, you can also +configure WAL streaming instead of using the ``archive_command`` in order to have a +lower :term:`RPO`. You can also opt for configuring WAL streaming in addition to WAL +archiving and have both options. + +In either cases, Barman will automatically verify that the WAL files are not duplicated +in the archive, and will only store them once. + +.. _architectures-geographical-redundancy: + +Geographical redundancy +----------------------- + +A very common setup for Barman is to have it installed in the same data center where +your PostgreSQL servers are. In this case, the single point of failure is the data +center. Fortunately, the impact of such a :term:`SPOF` can be alleviated thanks to two features +that Barman provides to increase the number of backup tiers: + + +1. geographical redundancy (introduced in Barman 2.6) +2. hook scripts + +With geographical redundancy, you can rely on another Barman instance that is located +in a different data center/availability zone, and synchronize the entire content of the +primary Barman server. + +There's more: given that geo-redundancy can be configured in Barman not only at global +level, but also at server level, you can create hybrid installations of Barman where +some servers are directly connected to the local PostgreSQL servers, and others are +backing up subsets of different Barman installations (cross-site backup). + +Figure below shows two availability zones (one in Europe and one in the US), each with +a primary PostgreSQL server that is backed up in a local Barman installation, and +relayed on the other Barman server (defined as passive) for multi-tier backup via +rsync/SSH. Further information on geo-redundancy is available in the +:ref:`Geographical Redundancy ` section. + +The image below illustrates how this setup would function in practice. + +.. image:: /images/barman-georedundancy.png + :scale: 50% + :align: center + + +.. _architectures-cloud-snaphost-backups: + +Cloud snapshot backups +---------------------- + +Barman also supports cloud snapshot backups, which takes a snapshot of the +storage volume where your Postgres server resides in the cloud. Barman currently +supports this method on Azure, Google, and AWS. The prerequisites for this method will +depend on which cloud provider where your Postgres server resides, so we recommend +checking the :ref:`backup-cloud-snapshot-backups` section for further details. \ No newline at end of file diff --git a/docs/user_guide/backup.rst b/docs/user_guide/backup.rst new file mode 100644 index 000000000..65fc4cb20 --- /dev/null +++ b/docs/user_guide/backup.rst @@ -0,0 +1,899 @@ +.. _backup: + +Backups +======= + +.. _backup-overview: + +Overview +-------- + +The backup command is used to backup an entire Postgres server according to the +configuration file parameters. To use it, run: + +``barman backup [OPTIONS] SERVER_NAME`` + +.. note:: + For detailed information on the backup command, refer to the + :ref:`backup ` command reference. + +.. important:: + Any interaction you plan to have with Barman, you will have to assure that the + server is correctly configured. Refer to :ref:`Quickstart ` and + :ref:`Configuration Reference ` sections for the steps you need to + cover before trying to create any backup. + +.. warning:: + Backup initiation will fail if WAL files are not correctly archived to Barman, either + through the ``archiver`` or the ``streaming_archiver`` options. + +Barman offers multiple backup methods for Postgres servers, each with its own approach +and requirements. + +Prior to version 2.0, Barman relied solely on rsync for both standard backups and +file-level incremental backups. Streaming backups were introduced in this version. +Starting with version 3.11, Barman also supports block-level incremental backups through +the streaming connection. + +.. important:: + For Postgres 15 and higher, ``exclusive`` backups are no longer supported. The only + method for taking backups is through ``concurrent`` backup. If ``backup_options`` is + unset, Barman will automatically set it to ``concurrent_backup``. + +.. _backup-incremental-backups: + +Incremental Backups +------------------- + +Incremental backups involve using an existing backup as a reference to copy only the +data changes that have occurred since the last backup on the Postgres server. + +The primary objectives of incremental backups in Barman are: + +* Shorten the duration of the full backup process. +* Reduce disk space usage by eliminating redundant data across periodic backups (data + deduplication). + +Barman supports two types of incremental backups: + +* File-level incremental backups (using ``rsync``) +* Block-level incremental backups (using ``pg_basebackup`` with Postgres 17) + +.. note:: + Incremental backups of different types are not compatible with each other. For + example, you cannot take a block-level incremental backup on top of an rsync backup, + nor can you take a file-level incremental backup on top of a streaming backup created + with ``pg_basebackup``. + +.. _backup-managing-bandwidth-usage: + +Managing Bandwidth Usage +------------------------ + +You can control I/O bandwidth usage with the ``bandwidth_limit`` option (global or per +server) by specifying a maximum rate in kilobytes per second. By default, this option is +set to ``0``, meaning there is no bandwidth limit. + +If you need to manage I/O workload on specific tablespaces, use the +``tablespace_bandwidth_limit`` option (global or per server) to set limits for +individual tablespaces: + +.. code-block:: text + + tablespace_bandwidth_limit = tbname:bwlimit[, tbname:bwlimit, ...] + +This option takes a comma-separated list of tablespace name and bandwidth limit pairs +(in kilobytes per second). + +When backing up a server, Barman will check for tablespaces listed in this option. If a +matching tablespace is found, the specified bandwidth limit will be applied. If no match +is found, the default bandwidth limit for the server will be used. + +.. important:: + The ``bandwidth_limit`` option is available with ``rsync`` and ``postgres`` backup + methods, but the ``tablespace_bandwidth_limit`` option is only applicable when using + ``rsync``. + +.. _backup-network-compression: + +Network Compression +------------------- + +You can reduce the size of data transferred over the network by using network compression. This +can be enabled with the ``network_compression`` option (global or per server): + +.. code-block:: text + + network_compression = true | false + +.. important:: + The ``network_compression`` option is not available with the ``postgres`` backup + method. + +Setting this option to ``true`` will enable data compression for network transfers +during both backup and recovery. By default, this option is set to ``false``. + +.. _backup-backup-compression: + +Backup Compression +------------------ + +Barman supports backup compression using the ``pg_basebackup`` tool. This feature can be +enabled with the ``backup_compression`` option (global or per server). + +.. important:: + The ``backup_compression`` option, along with other options discussed here, is only + available with the ``postgres`` backup method. + +Compression Algorithms +"""""""""""""""""""""" + +Setting the ``backup_compression`` option will compress the backup using the specified +algorithm. Supported algorithms in Barman are: ``gzip``, ``lz4``, ``zstd``, and ``none`` +(which results in an uncompressed backup). + +.. code-block:: text + + backup_compression = gzip | lz4 | zstd | none + +Barman requires the corresponding CLI utilities for the selected compression algorithm +to be installed on both the Barman server and Postgres server. These utilities can be +installed via system packages named ``gzip``, ``lz4``, and ``zstd`` on Debian, Ubuntu, +RedHat, CentOS, and SLES systems. + +* On Ubuntu 18.04 (bionic), the ``lz4`` utility is available in the ``liblz4-tool`` + package. + +* ``lz4`` and ``zstd`` are supported with Postgres 15 or higher. + +.. important:: + If using ``backup_compression``, you must also set ``recovery_staging_path`` to + enable recovery of compressed backups. Refer to the + :ref:`Recovering Compressed backups ` + section for details. + +Compression Workers +""""""""""""""""""" + +You can use multiple threads to speed up compression by setting the +``backup_compression_workers`` option (default is ``0``): + +.. code-block:: text + + backup_compression_workers = 2 + +.. note:: + This option is available only with ``zstd`` compression. ``zstd`` version must be + 1.5.0 or higher, or 1.4.4 or higher with multithreading enabled. + +Compression Level +""""""""""""""""" + +Specify the compression level with the ``backup_compression_level`` option. This should +be an integer value supported by the chosen compression algorithm. If not specified, the +default value for the algorithm will be used. + +* For ``none`` compression, ``backup_compression_level`` must be set to ``0``. + +* The available levels and default values depend on the chosen compression algorithm. + Check the :ref:`backup configuration options ` section + for details. + +* For Postgres versions prior to 15, ``gzip`` supports only + ``backup_compression_level = 0``, which uses the default compression level. + +Compression Location +"""""""""""""""""""" + +For Postgres 15 or higher, you can choose where compression occurs: on the ``server`` +or the ``client``. Set the ``backup_compression_location`` option: + +.. code-block:: text + + backup_compression_location = server | client + +* ``server``: Compression occurs on the Postgres server, reducing network bandwidth + but increasing server workload. +* ``client``: Compression is handled by ``pg_basebackup`` on the client side. + +When ``backup_compression_location`` is set to ``server``, you can also configure +``backup_compression_format``: + +.. code-block:: text + + backup_compression_format = plain | tar + +* ``plain``: ``pg_basebackup`` decompresses data before writing to disk. +* ``tar``: Backups are written as compressed tarballs (default). + +Depending on the chosen ``backup_compression`` and ``backup_compression_format``, you +may need to install additional tools on both the Postgres and Barman servers. + +Refer to the table below to select the appropriate tools for your configuration. + +.. list-table:: + :widths: 5 5 5 5 + :header-rows: 1 + + * - **backup_compression** + - **backup_compression_format** + - **Postgres** + - **Barman** + * - gzip + - plain + - tar + - None + * - gzip + - tar + - tar + - tar + * - lz4 + - plain + - tar, lz4 + - None + * - lz4 + - tar + - tar, lz4 + - tar, lz4 + * - zstd + - plain + - tar, zstd + - None + * - zstd + - tar + - tar, zstd + - tar, zstd + * - none + - tar + - tar + - tar + +.. _backup-immediate-checkpoint: + +Immediate Checkpoint +-------------------- + +Before starting a backup, Barman requests a checkpoint, which can generate additional +workload. By default, this checkpoint is managed according to Postgres' workload control +settings, which may delay the backup. + +You can modify this default behavior using the ``immediate_checkpoint`` configuration +option (default is ``false``). + +If ``immediate_checkpoint`` is set to ``true``, Postgres will perform the checkpoint at +maximum speed without throttling, allowing the backup to begin as quickly as possible. +You can override this configuration at any time by using one of the following options +with the ``barman backup`` command: + +* ``--immediate-checkpoint``: Forces an immediate checkpoint. +* ``--no-immediate-checkpoint``: Waits for the checkpoint to complete before starting + the backup. + +.. _backup-streaming-backup: + +Streaming Backup +---------------- + +Barman can perform a backup of a Postgres server using a streaming connection with +``pg_basebackup``. + +.. important:: + ``pg_basebackup`` must be installed on the Barman server. It is recommended to use + the latest version of ``pg_basebackup`` as it is backwards compatible. Multiple + versions can be installed and specified using the ``path_prefix`` option in the + configuration file. + +To configure streaming backups, set the ``backup_method`` to ``postgres``: + +.. code-block:: text + + backup_method = postgres + +Block-level Incremental Backup +"""""""""""""""""""""""""""""" + +This type of backup uses the native incremental backup feature introduced in Postgres +17. + +Block-level incremental backups deduplicate data at the page level in Postgres. This +means only pages modified since the last backup need to be stored, which is more +efficient, especially for large databases with frequent writes. + +To perform block-level incremental backups in Barman, use the ``--incremental`` option +with the backup command. You must provide a backup ID or shortcut referencing a previous +backup (full or incremental) created with ``backup_method=postgres`` for deduplication. +Alternatively, you can use ``last-full`` or ``latest-full`` to reference the most recent +eligible full backup in the catalog. + +Example command: + +``barman backup --incremental BACKUP_ID SERVER_NAME`` + +To use block-level incremental backups in Barman, you must: + +* Use Postgres 17 or later. +* This feature relies on WAL Summarization, so ``summarize_wal`` must be enabled on your + database server before taking the initial full backup. +* Use ``backup_method=postgres``. + +.. note:: + Compressed backups are currently not supported for block-level incremental backups + in Barman. + +.. important:: + If you enable ``data_checksums`` between block-level incremental backups, it's + advisable to take a new full backup. Divergent checksum configurations can + potentially cause issues during recovery. + +.. _backup-rsync-backup: + +Backup with Rsync through SSH +----------------------------- + +Barman can perform a backup of a Postgres server using Rsync, which uses SSH as a +transport mechanism. + +To configure a backup using rsync, include the following parameters in the Barman server +configuration file: + +.. code-block:: text + + backup_method = rsync + ssh_command = ssh postgres@pg + +Here, ``backup_method`` activates the rsync backup method, and ``ssh_command`` specifies +the SSH connection details from the Barman server to the Postgres server. + +.. note:: + Starting with Barman 3.11, a keep-alive mechanism is used for rsync-based backups. + This mechanism sends a simple ``SELECT 1`` query over the libpq connection to + prevent firewall or router disconnections due to idle connections. You can control or + disable this mechanism using the ``keepalive_interval`` configuration option. + +File-Level Incremental Backups +"""""""""""""""""""""""""""""" + +File-level incremental backups rely on rsync and alternatively hard links, so both the +operating system and file system where the backup data is stored must support these +features. + +The core idea is that during a subsequent base backup, files that haven't changed since +the last backup are shared, which saves disk space. This is especially beneficial in +:term:`VLDB` and those with a high percentage of read-only historical tables. + +You can enable rsync incremental backups through a global/server option called +``reuse_backup``, which manages the Barman backup command. It accepts three values: + +* ``off``: Standard full backup (default). +* ``link``: File-level incremental backup that reuses the last backup and creates hard + links for unchanged files, reducing both backup space and time. +* ``copy``: File-level incremental backup that reuses the last backup and creates copies + of unchanged files, reducing backup time but not space. + +Typically, you would set ``reuse_backup`` to ``link`` as follows: + +.. code-block:: text + + reuse_backup = link + +Setting this at the global level automatically enables incremental backups for all your +servers. + +You can override this setting with the ``--reuse-backup`` runtime option when running +the Barman backup command. For example, to run a one-off incremental backup, use: + +.. code-block:: text + + barman backup --reuse-backup=link + +.. note:: + Unlike block-level incremental backups, rsync file-level incremental backups are + self-contained. If a parent backup is deleted, the integrity of other backups is not + affected. Deduplication in rsync backups uses hard links, meaning that when a reused + backup is deleted, you don't need to create a new full backup; shared files will + remain on disk until the last backup that used those files is also deleted. + Additionally, using ``reuse_backup = on`` for the initial backup has no effect, as + it will still be treated as a full backup due to the absence of existing files to + link. + +.. _backup-concurrent-backup-of-a-standby: + +Concurrent Backup of a Standby +------------------------------ + +When performing a backup from a standby server, ensure the following configuration +options are set to point to the standby: + +* ``conninfo`` +* ``streaming_conninfo`` (if using ``backup_method = postgres`` or + ``streaming_archiver = on``) +* ``ssh_command`` (if using ``backup_method = rsync``) +* ``wal_conninfo`` (connecting to the primary if ``conninfo`` is pointing to a standby) + +The ``primary_conninfo`` option should point to the primary server. Barman will use +``primary_conninfo`` to trigger a new WAL switch on the primary, allowing the concurrent +backup from the standby to complete without waiting for a natural WAL switch. + +.. note:: + It's crucial to configure ``primary_conninfo`` if backing up a standby during periods + of minimal or no write activity on the primary. + +In Barman 3.8.0 and later, if ``primary_conninfo`` is configured, you can also set the +``primary_checkpoint_timeout`` option. This specifies the maximum wait time (in seconds) +for a new WAL file before Barman forces a checkpoint on the primary. This timeout should +exceed the ``archive_timeout`` value set on the primary. + +If ``primary_conninfo`` is not set, the backup will still proceed but will pause at the +stop backup stage until the last archived WAL segment is newer than the latest WAL +required by the backup. + +Barman requires that WAL files and backup data originate from the same Postgres +cluster. If the standby is promoted to primary, the existing backups and WALs remain +valid. However, you should update the Barman configuration to use the new standby for +future backups and WAL retrieval. + +.. note:: + In case of a failover on the Postgres cluster you can update the Barman + configuration with :ref:`Configuration Models `. + +WALs can be retrieved from the standby via WAL streaming or WAL archiving. Refer to the +:ref:`concepts ` +section for more details. If you want to start working with WAL streaming or WAL +archiving, refer to the quickstart section on +:ref:`streaming backups with wal streaming ` +or +:ref:`rsync backups with wal archiving `. + +.. note:: + For Postgres 10 and earlier, Barman cannot handle simultaneous WAL streaming and + archiving on a standby. You must disable one if the other is in use, as WALs from + Postgres 10 and earlier may differ at the binary level, leading to false-positive + detection issues in Barman. + +.. _backup-cloud-snapshot-backups: + +Cloud Snapshot Backups +---------------------- + +Barman can perform backups of Postgres servers deployed in specific cloud environments +by utilizing snapshots of storage volumes. In this setup, Postgres file backups are +represented as volume snapshots stored in the cloud, while Barman functions as the +storage server for Write-Ahead Logs (WALs) and the backup catalog. Despite the backup +data being stored in the cloud, Barman manages these backups similarly to traditional +ones created with ``rsync`` or ``postgres`` backup methods. + +.. note:: + Additionally, snapshot backups can be created without a Barman server by using the + ``barman-cloud-backup`` command directly on the Postgres server. Refer to the + :ref:`barman-cli-cloud ` section for more information + on how to properly work with this option. + +.. important:: + The following configuration options and equivalent command arguments (if applicable) + are not available when using ``backup_method=snapshot``: + + * ``backup_compression`` + * ``bandwidth_limit`` (``--bwlimit``) + * ``parallel_jobs`` (``--jobs``) + * ``network_compression`` + * ``reuse_backup`` (``--reuse-backup``) + +To configure a backup using snapshot, include the following parameters in the Barman server +configuration file: + +.. code-block:: text + + backup_method = snapshot + snapshot_provider = CLOUD_PROVIDER + snapshot_instance = INSTANCE_NAME + snapshot_disks = DISK_NAME1,DISK_NAME2 + +.. important:: + Ensure ``snapshot_disks`` includes all disks that store Postgres data. Any data + stored on a disk not listed will not be backed up and will be unavailable during + recovery. + +Requirements and Configuration +"""""""""""""""""""""""""""""" + +To use the snapshot backup method with Barman, your deployment must meet these +requirements: + +1. Postgres must be running on a compute instance provided by a supported cloud + provider. +2. All critical data, including PGDATA and tablespace data, must be stored on storage + volumes that support snapshots. +3. The ``findmnt`` command must be available on the Postgres host. + +.. important:: + Configuration files stored outside of ``PGDATA`` will not be included in the snapshots. + You will need to manage these files separately, using a configuration management + system or other mechanisms. + +Google Cloud Platform +""""""""""""""""""""" + +To use snapshot backups on :term:`GCP` with Barman, please ensure the following: + +1. **Python Libraries** + +Install the ``google-cloud-compute`` and ``grpcio`` libraries for the Python +distribution used by Barman. These libraries are optional and not included by default. + +Install them using pip: + +.. code:: bash + + pip3 install grpcio google-cloud-compute + +.. note:: + The ``google-cloud-compute`` library requires Python 3.7 or newer. GCP snapshots are + not compatible with earlier Python versions. + +2. **Disk Requirements** + +The disks used in the ``snapshot`` backup must be zonal persistent disks. Regional +persistent disks are not supported at this time. + +3. **Access Control** + +Barman needs a service account with specific permissions. You can either attach this +account to the compute instance running Barman (recommended) or use the +``GOOGLE_APPLICATION_CREDENTIALS`` environment variable to specify a credentials +file. + +.. important:: + Ensure the service account has the permissions listed below: + + * ``compute.disks.createSnapshot`` + * ``compute.disks.get`` + * ``compute.globalOperations.get`` + * ``compute.instances.get`` + * ``compute.snapshots.create`` + * ``compute.snapshots.delete`` + * ``compute.snapshots.list`` + +For provider specific credentials configurations, refer to the +`Google authentication methods `_ and +`service account impersonation `_. + +4. **Specific Configuration** + +The fields ``gcp_project`` and ``gcp_zone`` are configuration options specific to GCP. + +.. code-block:: text + + gcp_project = GCP_PROJECT_ID + gcp_zone = ZONE + +Microsoft Azure +""""""""""""""" + +To use snapshot backups on Azure with Barman, ensure the following: + +1. **Python Libraries** + +The ``azure-mgmt-compute`` and ``azure-identity`` libraries must be available for the +Python distribution used by Barman. These libraries are optional and not included by +default. + +Install them using pip: + +.. code:: bash + + pip3 install azure-mgmt-compute azure-identity + +.. note:: + The ``azure-mgmt-compute`` library requires Python 3.7 or later. Azure snapshots are + not compatible with earlier Python versions. + +2. **Disk Requirements** + +All disks involved in the snapshot backup must be managed disks attached to the VM +instance as data disks. + +3. **Access Control** + +Barman needs to access Azure using credentials obtained via managed identity or CLI +login. + +The following environment variables are supported: ``AZURE_STORAGE_CONNECTION_STRING``, +``AZURE_STORAGE_KEY`` and ``AZURE_STORAGE_SAS_TOKEN``. You can also use the +``--credential`` option to specify either ``azure-cli`` or ``managed-identity`` +credentials in order to authenticate via Azure Active Directory. + +.. important:: + Ensure the credential has the permissions listed below: + + * ``Microsoft.Compute/disks/read`` + * ``Microsoft.Compute/virtualMachines/read`` + * ``Microsoft.Compute/snapshots/read`` + * ``Microsoft.Compute/snapshots/write`` + * ``Microsoft.Compute/snapshots/delete`` + +For provider specific credential configurations, refer to the +`Azure environment variables configurations `_ +and `Identity Package `_. + +4. **Specific Configuration** + +The fields ``azure_subscription_id`` and ``azure_resource_group`` are configuration +options specific to Azure. + +.. code-block:: text + + azure_subscription_id = AZURE_SUBSCRIPTION_ID + azure_resource_group = AZURE_RESOURCE_GROUP + +Amazon Web Services +""""""""""""""""""" + +To use snapshot backups on :term:`AWS` with Barman, please ensure the following: + +1. **Python Libraries** + +The ``boto3`` library must be available for the Python distribution used by Barman. This +library is optional and not included by default. + +Install it using pip: + +.. code:: bash + + pip3 install boto3 + +2. **Disk Requirements** + +All disks involved in the snapshot backup must be non-root EBS volumes attached to the +same VM instance and NVMe volumes are not supported. + +3. **Access Control** + +Barman needs to access AWS so you must configure the AWS credentials with the ``awscli`` +tool as the postgres user, by entering the Access Key and Secret Key that must be +previously created in the IAM section of the AWS console. + +.. important:: + Ensure you have the permissions listed below: + + * ``ec2:CreateSnapshot`` + * ``ec2:CreateTags`` + * ``ec2:DeleteSnapshot`` + * ``ec2:DescribeSnapshots`` + * ``ec2:DescribeInstances`` + * ``ec2:DescribeVolumes`` + +For provider specific credentials configurations, refer to the +`AWS boto3 configurations `_. + +4. **Specific Configuration** + +The fields ``aws_region``, ``aws_profile`` and ``aws_await_snapshots_timeout`` are +configuration options specific to AWS. + +``aws_profile`` is the name of the AWS profile in the credentials file. If not used, the +default profile will be applied. If no credentials file exists, credentials will come from +the environment. + +``aws_region`` overrides any region defined in the AWS profile. + +``aws_await_snapshots_timeout`` is the timeout for waiting for snapshots to be created +(default is ``3600`` seconds). + +When specifying ``snapshot_instance`` or ``snapshot_disks``, Barman accepts either the +instance/volume ID or the name of the resource. If you use a name, Barman will query AWS +for resources with a matching ``Name`` tag. If zero or multiple matches are found, +Barman will return an error. + +.. code-block:: text + + aws_region = AWS_REGION + aws_profile = AWS_PROFILE_NAME + aws_await_snapshots_timeout = TIMEOUT_IN_SECONDS + +4. **Ransomware Protection** + +Ransomware protection is essential to secure data and maintain operational stability. +With Amazon EBS Snapshot Lock, snapshots are protected from deletion, providing an +immutable backup that safeguards against ransomware attacks. By locking snapshots, +unwanted deletions are prevented, ensuring reliable recovery options in case of +compromise. Barman can prevent unwanted deletion of backups by locking the snapshots +when creating the backup. + +.. note:: + To delete a locked backup, you must first manually remove the lock in the AWS + console. + +To lock a snapshot during backup creation, you need to configure the following options: + +1. Choose the snapshot lock mode: either ``compliance`` or ``governance``. +2. Set either the lock duration or the expiration date (not both). Lock duration is + specified in days, ranging from 1 to 36,500. If you choose an expiration date, it must + be at least 1 day after the snapshot creation date and time, using the format + ``YYYY-MM-DDTHH:MM:SS.sssZ``. +3. Optionally, set a cool-off period (in hours), from 1 to 72. This option only applies + when the lock mode is set to ``compliance``. + +.. code-block:: text + + aws_snapshot_lock_mode = compliance | governance + aws_snapshot_lock_duration = 1 + aws_snapshot_lock_cool_off_period = 1 + aws_snapshot_lock_expiration_date = "2024-10-07T21:53:00.606Z" + +.. important:: + Ensure you have the permission listed below: + + * ``ec2:LockSnapshot`` + +For the concepts behing AWS Snapshot Lock, refer to the `Amazon EBS snapshot lock concepts `_. + +Backup Process +"""""""""""""" + +Here is an overview of the snapshot backup process: + +1. Barman performs checks to validate the snapshot options, instance, and disks. + Before each backup and during the ``barman check`` command, the following checks are + performed: + + * The compute instance specified by ``snapshot_instance`` and any provider-specific + arguments exists. + * The disks listed in ``snapshot_disks`` are present. + * The disks listed in ``snapshot_disks`` are attached to the ``snapshot_instance``. + * The disks listed in ``snapshot_disks`` are mounted on the ``snapshot_instance``. + +2. Barman initiates the backup using the Postgres backup API. +3. The cloud provider API is used to create a snapshot for each specified disk. Barman + waits until each snapshot reaches a state that guarantees application consistency + before proceeding to the next disk. +4. Additional provider-specific details, such as the device name for each disk, and the + mount point and options for each disk are recorded in the backup metadata. + +Metadata +"""""""" + +Regardless of whether you provision recovery disks and instances using +infrastructure-as-code, ad-hoc automation, or manually, you will need to use Barman to +identify the necessary snapshots for a specific backup. You can do this with the barman +``show-backup`` command, which provides details for each snapshot included in the +backup. + +For example: + +.. code-block:: text + + Backup 20240813T200506: + Server Name : snapshot + System Id : 7402620047885836080 + Status : DONE + PostgreSQL Version : 160004 + PGDATA directory : /opt/postgres/data + Estimated Cluster Size : 22.7 MiB + + Server information: + Checksums : on + + Snapshot information: + provider : aws + account_id : 714574844897 + region : sa-east-1 + + device_name : /dev/sdf + snapshot_id : snap-0d2288b4f30e3f9e3 + snapshot_name : Barman_AWS:1:/dev/sdf-20240813t200506 + Mount point : /opt/postgres + Mount options : rw,noatime,seclabel + + Base backup information: + Backup Method : snapshot-concurrent + Backup Size : 1.0 KiB (16.0 MiB with WALs) + WAL Size : 16.0 MiB + Timeline : 1 + Begin WAL : 00000001000000000000001A + End WAL : 00000001000000000000001A + WAL number : 1 + Begin time : 2024-08-14 16:21:50.820618+00:00 + End time : 2024-08-14 16:22:38.264726+00:00 + Copy time : 47 seconds + Estimated throughput : 22 B/s + Begin Offset : 40 + End Offset : 312 + Begin LSN : 0/1A000028 + End LSN : 0/1A000138 + + WAL information: + No of files : 1 + Disk usage : 16.0 MiB + WAL rate : 5048.32/hour + Last available : 00000001000000000000001B + + Catalog information: + Retention Policy : not enforced + Previous Backup : - (this is the oldest base backup) + Next Backup : - (this is the latest base backup) + +The ``--format=json`` option can be used when integrating with external tooling. + +.. code-block:: json + + { + "snapshots_info": { + "provider": "gcp", + "provider_info": { + "project": "project_id" + }, + "snapshots": [ + { + "mount": { + "mount_options": "rw,noatime", + "mount_point": "/opt/postgres" + }, + "provider": { + "device_name": "pgdata", + "snapshot_name": "barman-av-ubuntu20-primary-pgdata-20230123t131430", + "snapshot_project": "project_id" + } + }, + { + "mount": { + "mount_options": "rw,noatime", + "mount_point": "/opt/postgres/tablespaces/tbs1" + }, + "provider": { + "device_name": "tbs1", + "snapshot_name": "barman-av-ubuntu20-primary-tbs1-20230123t131430", + "snapshot_project": "project_id", + } + } + ] + } + } + +The metadata found in ``snapshots_info/provider_info`` and +``snapshots_info/snapshots/*/provider`` varies depending on the cloud provider, as +detailed in the following sections. + +**GCP** + +``snapshots_info/provider_info`` + +* ``project``: The GCP project ID of the project which owns the resources involved + in backup and recovery. + +``snapshots_info/snapshots/*/provider`` + +* ``device_name``: The short device name with which the source disk for the snapshot + was attached to the backup VM at the time of the backup. +* ``snapshot_name``: The name of the snapshot. +* ``snapshot_project``: The GCP project ID which owns the snapshot. + +**Azure** + +``snapshots_info/provider_info`` + +* ``subscription_id``: The Azure subscription ID which owns the resources involved + in backup and recovery. +* ``resource_group``: The Azure resource group to which the resources involved in + the backup belong. + +``snapshots_info/snapshots/*/provider`` + +* ``location``: The Azure location of the disk from which the snapshot was taken. +* ``lun``: The LUN identifying the disk from which the snapshot was taken at the + time of the backup. +* ``snapshot_name``: The name of the snapshot. + +**AWS** + +``snapshots_info/provider_info`` + +* ``account_id``: The ID of the AWS account which owns the resources used to make + the backup. +* ``region``: The AWS region in which the resources involved in backup are located. + +``snapshots_info/snapshots/*/provider`` + +* ``device_name``: The device to which the source disk was mapped on the backup VM + at the time of the backup. +* ``snapshot_id``: The ID of the snapshot as assigned by AWS. +* ``snapshot_name``: The name of the snapshot. diff --git a/docs/user_guide/barman_check.rst b/docs/user_guide/barman_check.rst new file mode 100644 index 000000000..0d3e3e891 --- /dev/null +++ b/docs/user_guide/barman_check.rst @@ -0,0 +1,157 @@ +.. _barman-check: + +Barman check +============ + +The ``check`` command verifies the connection to a specified server and ensures the server +configuration is coherent. This command performs a series of checks to validate the +proper setup of SSH and Postgres connections are functioning, the existence of backup directories, +and the integrity of the WAL archive. It also verifies Postgres configurations, retention +policies, backup validity, and WAL archiving processes. It identifies and reports any +detected issues, making it one of the most critical features provided by Barman. + +Running this command will: + +* Ensure that WAL archiving is correctly configured. +* Validate the Postgres connection and necessary privileges. +* Verify that all required directories exist. +* Check that retention policies are properly set. +* Confirm the validity of backups and WAL files. +* Detect configuration errors and archiver issues. + +Usage +----- + +To use the ``check`` command, run: + +.. code-block:: bash + + barman check + +To run a check on all configured servers, use: + +.. code-block:: bash + + barman check all + +.. tip:: + Integrate the ``check`` command with your alerting and monitoring infrastructure to + ensure continuous oversight of your backup environment. The ``--nagios`` option is + useful for creating plugins for Nagios/Icinga, allowing you to monitor the status of + your servers seamlessly. For example, you can run: + +.. code-block:: text + + barman check --nagios + +This will output results in a format compatible with Nagios, facilitating integration +into your existing monitoring setup. + +.. tip:: + For other backup and server-specific checks, you can use the following command: + + * ``barman check-backup``: Checks that all necessary WAL files for verifying the + consistency of a physical backup are properly archived. This command is used by the + ``cron`` job and is automatically executed after each backup operation. See + :ref:`barman check-backup` for more details. + +Understanding the output +------------------------ + +Running ``barman check`` will display an output similar to the following: + +.. code-block:: text + + $ barman check example + Server example: + PostgreSQL: OK + superuser or standard user with backup privileges: OK + PostgreSQL streaming: OK + wal_level: OK + replication slot: OK + directories: OK + retention policy settings: OK + backup maximum age: OK (no last_backup_maximum_age provided) + compression settings: OK + configuration files: OK + pg_basebackup: OK + pg_basebackup compatible: OK + received WAL files: OK + archiving: OK + archive_mode: OK + archive_command: OK + continuous archiving: OK + archive_timeout: OK + +The output label can vary depending on the status of each check. For example, if a +check fails, it will be marked as ``FAILED`` and may include a hint to help troubleshoot +the issue. If a check passes but with warnings, it will be marked as ``WARNING`` with +additional context. + +The ``barman check`` command performs the checks for each of the following aspects of +Barman functioning: + +**WAL Archive** + +* Ensures that WAL archiving is set up correctly. +* Checks the number of WAL files in the incoming and streaming directories. + +.. note:: + If ``archiver = off`` in the Barman configuration and there are WALs in the incoming + directory, the check will fail. This happens because WALs in the incoming directory + suggest Postgres is still using ``archive_command`` or that the user switched from + ``archiver`` to ``streaming_archiver``, leaving WALs unsaved in Barman's archive. + + To resolve this, you must determine if the WALs in incoming are necessary or can be + safely deleted. This can be done by: + + 1. Checking if the WALs are newer than the ``begin_wal`` of the oldest backup. + 2. Verifying if these WALs are already in Barman's archive. + + The same issue applies if ``streaming_archiver = off`` and WALs are found in the + streaming directory. + +**Postgres Connection** + +* Validates the Postgres connection. +* Ensures that the server version is supported. +* Checks for necessary privileges and streaming support. + +**Local Tools Validity** + +* Ensures that local tools for taking backups and receiving WALs will work correctly + with the version of the database server, such as ``pg_basebackup`` for taking backups, + and ``pg_receivewal`` for streaming WAL files. + +**Directory** + +* Ensures that all necessary backup directories exist. +* Creates directories if they do not exist. + +**Retention Policy** + +* Validates the retention policy settings. + +**Backup Validity** + +* Ensures that the backup validity requirements are satisfied. +* Checks the maximum age and minimum size of backups. + +**WAL Validity** + +* Ensures that WAL archiving requirements are met. +* Checks the maximum age and size of WAL files. + +**Configuration** + +* Inspects the server's message list for error messages. +* Outputs any errors found. + +**Identity** + +* Verifies that the system ID retrieved from the streaming connection matches the one + from the standard connection and the one stored on disk. + +**Archiver Errors** + +* Inspects the errors directory for the presence of archiving errors. diff --git a/docs/user_guide/barman_cloud.rst b/docs/user_guide/barman_cloud.rst new file mode 100644 index 000000000..d7adef365 --- /dev/null +++ b/docs/user_guide/barman_cloud.rst @@ -0,0 +1,84 @@ +.. _barman-cloud: + +Barman for the cloud +==================== + +Barman offers two primary methods for backing up Postgres servers to the cloud: + +* *Creating disk volume snapshots as base backups.* + + You have two options to work with snapshots: + + 1. You will need to setup a barman server to store the barman metadata and WAL files, + while your backup will be created as disk volume snapshots in the cloud. This is an + integrated feature of Barman. If you choose this approach, please consult the + :ref:`cloud snapshots backups ` section for details. + 2. Interact and manage backups directly with the command line utility provided by the + ``barman-cli-cloud`` package without the need for a barman server. The barman + metadata and WAL files will be stored in a cloud object storage, while your backup + will be created as disk volume snapshots in the cloud. + +* *Creating and transfering base backups to a cloud object storage.* + + This method is similar to the second option of snapshots, but the base backup is stored + in an object storage alongside the WAL files and backup metadata. + +This section of the documentation is focused in the ``barman-cloud-*`` commands that +can be used to manage and interact with backups without the need of a dedicated barman +server. To start working with it, you will need to install the ``barman-cli-cloud`` +package on the same machine as your Postgres server. + +Understanding these options will help you select the right approach for your cloud +backup and recovery needs, ensuring you leverage Barman's full potential. + +.. _barman-cloud-barman-cli-cloud: + +barman-cli-cloud +---------------- + +The ``barman-cli-cloud`` package provides commands for managing cloud backups, both in +object storage and as disk volume snapshots, without requiring a Barman server. + +With this utility, you can: + +* Create and manage snapshot backups directly. +* Create and transfer backups to cloud object storage. + +``barman-cli-cloud`` extends beyond Barman's native capabilities, offering commands for +handling backups in cloud storage and disk volumes independently. Its operations may +differ from Barman's integrated features. + +.. note:: + Barman supports AWS S3 (and S3 compatible object stores), Azure Blob Storage + and Google Cloud Storage. + +.. _barman-cloud-installation: + +Installation +------------ + +To back up Postgres servers directly to a cloud provider, you need to install the +Barman client utility for the cloud on those servers. Keep in mind that the installation +process varies based on the distribution you are using. + +Refer to the :ref:`installation ` section for the installation process, +and make sure to note the important information for each distribution. + +.. _barman-cloud-commands-reference: + +Commands Reference +------------------ + +You have several commands available to manage backup and recovery in the cloud using +this utility. The exit statuses for them are ``SUCCESS`` (0), ``FAILURE`` (1), +``FAILED CONNECTION`` (2) and ``INPUT_ERROR`` (3). Any other non-zero is ``FAILURE``. + +.. include:: commands/barman_cloud/backup.inc.rst +.. include:: commands/barman_cloud/backup_delete.inc.rst +.. include:: commands/barman_cloud/backup_show.inc.rst +.. include:: commands/barman_cloud/backup_list.inc.rst +.. include:: commands/barman_cloud/backup_keep.inc.rst +.. include:: commands/barman_cloud/check_wal_archive.inc.rst +.. include:: commands/barman_cloud/restore.inc.rst +.. include:: commands/barman_cloud/wal_archive.inc.rst +.. include:: commands/barman_cloud/wal_restore.inc.rst \ No newline at end of file diff --git a/docs/user_guide/catalog.rst b/docs/user_guide/catalog.rst new file mode 100644 index 000000000..53ae619df --- /dev/null +++ b/docs/user_guide/catalog.rst @@ -0,0 +1,169 @@ +.. _catalog: + +Catalog information +=================== + +The backup catalog is a comprehensive record that keeps track of all servers and +backups on the Barman node. Note that servers are the Postgres database systems that +are being tracked and backed up by Barman. Each server is configured within the Barman +node to ensure that its data is regularly backed up and can be restored if needed. The +Barman node is another server that hosts the Barman software, which manages the backup +and recovery processes for these Postgres servers. It communicates with the configured +servers to perform backups, store them securely, and maintain a detailed catalog of all +backup activities. + +The backup catalog is essential for effective backup management and recovery operations, +offering a unified interface that makes it a key component of the Barman tool. It plays +a central role in organizing, monitoring, and executing backup and recovery tasks by +providing a comprehensive view and precise control over all backup activities. This +streamlined approach enhances efficiency, simplifies management, and ensures seamless +recovery processes. + +The global configuration option ``barman_home`` specifies the directory where Barman +stores and manages backups for multiple servers. By default, this directory is set to +``/var/lib/barman``, but it can be customized by modifying the global configuration file +found at ``/etc/barman.conf``. Within this directory, backups from each server are +organized into separate subdirectories, with each server's backups located under +``//base``. This structure helps keep backups organized and +easily accessible. + +Purpose +------- + +Serve as a centralized repository that keeps track of all Postgres server and +backup-related information. + +Here are some key roles it plays: + +* **Backup Metadata Storage**: It stores metadata about each backup, such as the + backup's start and end times, the status, the specific Postgres instance it was taken + from and many other metrics. This metadata helps in tracking and managing the backup + lifecycle. + +* **Backup Management**: The catalog provides a way to organize and manage backups + efficiently. By keeping detailed records, it simplifies operations such as listing + available backups, checking the status of backups, identifying the latest or + specific backups, and applying retention policies. + +* **Restore Operations**: During a restore operation, the catalog helps in quickly + identifying which backups are available and their details. This facilitates efficient + restoration by providing necessary information about the backups and their associated + archive logs. + +* **Ease of Use**: It simplifies the process of managing multiple backups and their + associated metadata, making it easier for administrators to handle large numbers of + backups and complex backup strategies. + +Usage +----- + +Barman offers a straightforward terminal interface for managing Postgres backups and +interacting with the backup catalog. This interface provides a range of sub-commands for +both server management and backup operations. All Barman sub-commands can be found in +the :ref:`sub commands ` section, including two important ones +which are ``list-backups`` and ``show-backup``. These commands can be found below with +an example. + +.. _catalog-usage-list-backups: + +``list-backups`` +"""""""""""""""" + +Show available backups for a server. This command is useful to retrieve a list of +backups with minimal yet important information, such as backup ID and the backup type. + +For example: + +.. code-block:: text + + svr_pg17 20240901T103000 - F - Mon Nov 2 15:12:03 2024 - Size: 820.0 MiB - WAL Size: 22 MiB + +* ``svr_pg17`` is the server name. +* ``20240901T103000`` is the backup ID. +* ``F`` is the backup type label. +* ``Nov 1 11:12:03 2024`` is the date and time the backup operation ended. +* ``Size: 820.0 MiB`` is the size of the backup. +* ``WAL Size: 22 MiB`` is the size of all WAL files related to this backup. + + +.. note:: + The backup type label can be ``F`` for full backups and ``I`` for block-level + incremental backups. ``R`` for rsync backups and ``S`` for cloud snapshot backups. + +.. _catalog-usage-show-backup: + +``show-backup`` +""""""""""""""" + +Show detailed information about a specific backup. For example, a block-level incremental +backup: + +.. code-block:: text + + Backup 20240902T130000: + Server Name : prod_pg17 + Status : DONE + PostgreSQL Version : 170000 + PGDATA directory : /var/lib/pgsql/17/data + Estimated Cluster Size : 244.7 GiB + + Server information: + Checksums : on + WAL summarizer : on + + Base backup information: + Backup Method : postgres + Backup Type : incremental + Backup Size : 3.4 GiB (36.7 GiB with WALs) + WAL Size : 32.3 GiB + Resources saved : 241.3 GiB (98.61%) + Timeline : 1 + Begin WAL : 0000000100000CFD000000AD + End WAL : 0000000100000D0D00000008 + WAL number : 3932 + WAL compression ratio: 79.51% + Begin time : 2024-09-02 13:00:01.633925+00:00 + End time : 2024-09-03 10:27:06.522846+00:00 + Copy time : 1 second + Estimated throughput : 2.0 MiB/s + Begin Offset : 1575048 + End Offset : 13853016 + Begin XLOG : CFD/AD180888 + End XLOG : D0D/8D36158 + + WAL information: + No of files : 35039 + Disk usage : 121.5 GiB + WAL rate : 275.50/hour + Compression ratio : 77.81% + Last available : 0000000100000D95000000E7 + + Catalog information: + Retention Policy : not enforced + Previous Backup : 20240902T120001 + Next Backup : - (this is the latest base backup) + Root Backup : 20240801T015504 + Parent Backup : 20240831T016504 + Backup chain size : 3 + Children Backup(s) : 20240903T018515,20240903T019515 + +.. note:: + The output of the ``show-backup`` command can vary depending on the version of + your Postgres server and the type of backup. + + * The fields ``Root Backup``, ``Parent Backup``, ``Backup chain size`` and + ``Children Backup(s)`` are relevant only for block-level incremental backups taken + with ``backup_method=postgres`` on Postgres 17 or newer. These fields will not be + shown for other types of backups or older Postgres versions. + * The ``show-backup`` command relies on backup metadata. If a backup was created + with Barman version 3.10 or earlier, it will not include fields introduced in + version 3.11, such as those related to block-level incremental backups in + Postgres 17. + * The field ``Resource Saved`` is available for rsync and incremental + backups, and ``Snapshot Information`` is only available for snapshot backups. + * The possible values for the field ``Backup Type`` are: + + * ``rsync``: for a backup taken with rsync. + * ``full``: for a full backup taken with pg_basebackup. + * ``incremental``: for an incremental backup taken with pg_basebackup. + * ``snapshot``: for a snapshot-based backup taken in the cloud. diff --git a/docs/user_guide/commands.rst b/docs/user_guide/commands.rst new file mode 100644 index 000000000..70e04d1f5 --- /dev/null +++ b/docs/user_guide/commands.rst @@ -0,0 +1,98 @@ +.. _commands: + +Commands Reference +================== + +Barman has a command-line interface named ``barman``, which is used basically to +interact with Barman's backend. + +Before jumping into each of the sub-commands of ``barman``, be aware that ``barman`` +has global options available for all of the sub-commands. These options can modify the +behavior of the sub-commands and can be used as follows: + +.. include:: commands/barman/barman.inc.rst + +Shortcuts +--------- + +For some commands, you can use the following shortcuts or aliases to identify a backup +for a given server. Specifically, the ``all`` shortcut can be used to identify all +servers: + +.. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. + +Exit Statuses +------------- + +Status code **0** means **success**, while status code **Non-Zero** means **failure**. + +.. _commands-sub-commands: + +Sub-Commands +------------ + +``barman`` exposes several handy operations. This section is intended to describe each +of them. + +In the following sections you can find a description of each command implemented by +``barman``. Some of these commands may have more detailed information in another main +section in this documentation. If that is the case, a reference is provided to help you +quickly navigate to it. + +.. include:: commands/barman/archive_wal.inc.rst +.. include:: commands/barman/backup.inc.rst +.. include:: commands/barman/check_backup.inc.rst +.. include:: commands/barman/check.inc.rst +.. include:: commands/barman/config_switch.inc.rst +.. include:: commands/barman/config_update.inc.rst +.. include:: commands/barman/cron.inc.rst +.. include:: commands/barman/delete.inc.rst +.. include:: commands/barman/diagnose.inc.rst +.. include:: commands/barman/generate_manifest.inc.rst +.. include:: commands/barman/get_wal.inc.rst +.. include:: commands/barman/keep.inc.rst +.. include:: commands/barman/list_backups.inc.rst +.. include:: commands/barman/list_files.inc.rst +.. include:: commands/barman/list_servers.inc.rst +.. include:: commands/barman/lock_directory_cleanup.inc.rst +.. include:: commands/barman/put_wal.inc.rst +.. include:: commands/barman/rebuild_xlogdb.inc.rst +.. include:: commands/barman/receive_wal.inc.rst +.. include:: commands/barman/restore.inc.rst +.. include:: commands/barman/replication_status.inc.rst +.. include:: commands/barman/show_backup.inc.rst +.. include:: commands/barman/show_servers.inc.rst +.. include:: commands/barman/status.inc.rst +.. include:: commands/barman/switch_wal.inc.rst +.. include:: commands/barman/switch_xlog.inc.rst +.. include:: commands/barman/sync_backup.inc.rst +.. include:: commands/barman/sync_info.inc.rst +.. include:: commands/barman/sync_wals.inc.rst +.. include:: commands/barman/verify_backup.inc.rst +.. include:: commands/barman/verify.inc.rst + +``barman-cli`` commands +----------------------- + +The ``barman-cli`` package includes a collection of recommended client utilities that +should be installed alongside the Postgres server. Here are the command references for +both utilities. + +.. include:: commands/barman_cli/wal_archive.inc.rst +.. include:: commands/barman_cli/wal_restore.inc.rst \ No newline at end of file diff --git a/docs/user_guide/commands/barman/archive_wal.inc.rst b/docs/user_guide/commands/barman/archive_wal.inc.rst new file mode 100644 index 000000000..f36f75a36 --- /dev/null +++ b/docs/user_guide/commands/barman/archive_wal.inc.rst @@ -0,0 +1,25 @@ +.. _commands-barman-archive-wal: + +``barman archive-wal`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + archive-wal SERVER_NAME + +Description +^^^^^^^^^^^ + +Fetch WAL files received from either the standard ``archive_command`` or streaming +replication with ``pg_receivewal`` and store them in the server's WAL archive. If you +have enabled ``compression`` in the configuration file, the WAL files will be compressed +before they are archived. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. diff --git a/docs/user_guide/commands/barman/backup.inc.rst b/docs/user_guide/commands/barman/backup.inc.rst new file mode 100644 index 000000000..1ffc87e5f --- /dev/null +++ b/docs/user_guide/commands/barman/backup.inc.rst @@ -0,0 +1,148 @@ +.. _commands-barman-backup: + +``barman backup`` +""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + backup + [ --bwlimit KBPS ] + [ --incremental BACKUP_ID ] + [ --immediate-checkpoint ] + [ { -j, --jobs } PARALLEL_WORKERS ] + [ --jobs-start-batch-period PERIOD ] + [ --jobs-start-batch-size SIZE ] + [ --keepalive-interval SECONDS ] + [ --manifest ] + [ --name NAME ] + [ --no-immediate-checkpoint ] + [ --no-manifest ] + [ --no-retry ] + [ --retry-sleep SECONDS ] + [ --retry-times NUMBER ] + [ --reuse-backup { off | copy | link } ] + [ { --wait | -w } ] + [ --wait-timeout SECONDS ] + SERVER_NAME [ ... ] + +Description +^^^^^^^^^^^ + +Execute a PostreSQL server backup. Barman will use the parameters specified in the Global +and Server configuration files. Specify ``all`` shortcut instead of the server name to +execute backups from all servers configured in the Barman node. You can also specify +multiple server names in sequence to execute backups for specific servers. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +``--bwlimit`` + Specify the maximum transfer rate in kilobytes per second. A value of 0 indicates no + limit. This setting overrides the ``bandwidth_limit`` configuration option. + +``--incremental`` + Execute a block-level incremental backup. You must provide a ``BACKUP_ID`` or a + shortcut to a previous backup, which will serve as the parent backup for the + incremental backup. + + .. note:: + The backup to be and the parent backup must have ``backup_method=postgres``. + +``--immediate-checkpoint`` + Forces the initial checkpoint to be executed as soon as possible, overriding any + value set for the ``immediate_checkpoint`` parameter in the configuration file. + +``-j`` / ``--jobs`` + Specify the number of parallel workers to use for copying files during the backup. + This setting overrides the ``parallel_jobs`` parameter if it's specified in the + configuration file. + +``--jobs-start-batch-period`` + Specify the time period, in seconds, for starting a single batch of jobs. This value + overrides the ``parallel_jobs_start_batch_period`` parameter if it is set in the + configuration file. The default is ``1`` second. + +``--jobs-start-batch-size`` + Specify the maximum number of parallel workers to initiate in a single batch. This + value overrides the ``parallel_jobs_start_batch_size`` parameter if it is defined in + the configuration file. The default is ``10`` workers. + +``--keepalive-interval`` + Specify an interval, in seconds, for sending a heartbeat query to the server to keep + the libpq connection active during a Rsync backup. The default is ``60`` seconds. A + value of ``0`` disables the heartbeat. + +``--manifest`` + Forces the creation of a backup manifest file upon completing a backup. Overrides the + ``autogenerate_manifest`` parameter from the configuration file. Applicable only to + rsync backup strategy. + +``--name`` + Specify a friendly name for this backup which can be used in place of the backup ID + in barman commands. + +``--no-immediate-checkpoint`` + Forces the backup to wait for the checkpoint to be executed overriding any value set + for the ``immediate_checkpoint`` parameter in the configuration file. + +``--no-manifest`` + Disables the automatic creation of a backup manifest file upon completing a backup. + This setting overrides the ``autogenerate_manifest`` parameter from the configuration + file and applies only to rsync backup strategy. + +``--no-retry`` + There will be no retry in case of an error. It is the same as setting + ``--retry-times 0``. + +``--retry-sleep`` + Specify the number of seconds to wait after a failed copy before retrying. This + setting applies to both backup and recovery operations and overrides the + ``basebackup_retry_sleep`` parameter if it is defined in the configuration file. + +``--retry-times`` + Specify the number of times to retry the base backup copy in case of an error. This + applies to both backup and recovery operations and overrides the + ``basebackup_retry_times`` parameter if it is set in the configuration file. + +``--reuse-backup`` + Overrides the behavior of the ``reuse_backup`` option configured in the configuration + file. The possible values are: + + * ``off``: Do not reuse the last available backup. + * ``copy``: Reuse the last available backup for a server and create copies of + unchanged files (reduces backup time). + * ``link`` (default): Reuse the last available backup for a server and create + hard links to unchanged files (saves both backup time and space). + + .. note:: + This will only have any effect if the last available backup was + executed with ``backup_method=rsync``. + +``--wait`` / ``-w`` + Wait for all necessary WAL files required by the base backup to be archived. + +``--wait-timeout`` + Specify the duration, in seconds, to wait for the required WAL files to be archived + before timing out. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``SERVER_NAME``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/barman.inc.rst b/docs/user_guide/commands/barman/barman.inc.rst new file mode 100644 index 000000000..7e6fbd5c1 --- /dev/null +++ b/docs/user_guide/commands/barman/barman.inc.rst @@ -0,0 +1,94 @@ +.. _commands-barman: + +``barman`` +---------- + +Synopsis +"""""""" + +.. code-block:: text + + barman + [ { -c | --config } CONFIG ] + [ { -color | --colour } { never | always | auto } ] + [ { -d | --debug } ] + [ { -f | --format } { json | console } ] + [ { -h | --help } ] + [ --log-level { NOTSET | DEBUG | INFO | WARNING | ERROR | CRITICAL } ] + [ { -q | --quiet } ] + [ { -v | --version } ] + [ SUBCOMMAND ] + +.. note:: + + This is the syntax for the synopsis: + + * Options between square brackets are optional. + * Options between curly brackets represent a choose one of set operation. + * Options with ``[ ... ]`` can be specified multiple times. + * Things written in uppercase represent a literal that should be given a value to. + + We will use this same syntax when describing ``barman`` sub-commands in the + following sections. + + Also, when describing sub-commands in the following sections, the commands' + synopsis should be seen as a replacement for the ``SUBCOMMAND``. + +Parameters +"""""""""" + +``-c`` / ``--config CONFIG`` + Specify the configuration file to be used. Defaults to ``/etc/barman.conf`` if + not provided. + +``--color`` / ``--colour { never | always | auto }`` + Control whether to use colors in the output. The default is ``auto``. Options are: + + * ``never``: Do not use color. + * ``always``: Always use color. + * ``auto``: Use color if the output is to a terminal. + +``-d`` / ``--debug`` + Enable debug output. Default is ``false``. Provides detailed logging information for + troubleshooting. + +``-f`` / ``--format { json | console }`` + Specify the output format. Options are: + + * ``json``: Output in JSON format. + * ``console``: Output in human-readable format (default). + +``-h`` / ``--help`` + Show a help message and exit. Provides information about command usage. + +``--log-level { NOTSET | DEBUG | INFO | WARNING | ERROR | CRITICAL }`` + Override the default logging level. Options are: + + * ``NOTSET``: This is the default level when no specific logging level is set. It + essentially means "no filtering" of log messages, allowing all messages to be + processed according to the levels that are set in the configuration. + * ``DEBUG``: This level is used for detailed, diagnostic information, often + useful for developers when diagnosing problems. It includes messages that are + more granular and detailed, intended to help trace the execution of the + program. + * ``INFO``: This level provides general information about the application's + normal operation. It's used for messages that indicate the progress of the + application or highlight key points in the execution flow that are useful but + not indicative of any issues. + * ``WARNING``: This level indicates that something unexpected happened or that + there might be a potential problem. It's used for messages that are not + critical but could be of concern, signaling that attention might be needed. + * ``ERROR``: This level is used when an error occurs that prevents a particular + operation from completing successfully. It's used to indicate significant + issues that need to be addressed but do not necessarily stop the application + from running. + * ``CRITICAL``: This is the highest level of severity, indicating a serious + error that has likely caused the application to terminate or will have severe + consequences if not addressed immediately. It's used for critical issues that + demand urgent attention. + +``-q`` / ``--quiet`` + Suppress all output. Useful for cron jobs or automated scripts. + +``-v`` / ``--version`` + Show the program version number and exit. diff --git a/docs/user_guide/commands/barman/check.inc.rst b/docs/user_guide/commands/barman/check.inc.rst new file mode 100644 index 000000000..331d6acb6 --- /dev/null +++ b/docs/user_guide/commands/barman/check.inc.rst @@ -0,0 +1,44 @@ +.. _commands-barman-check: + +``barman check`` +"""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + check [ --nagios ] SERVER_NAME + +Description +^^^^^^^^^^^ + +Display status information about a server, such as SSH connection, Postgres version, +configuration and backup directories, archiving and streaming processes, replication +slots, and more. Use ``all`` as shortcut to show diagnostic information for all +configured servers. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +``--nagios`` + Nagios plugin compatible output. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``SERVER_NAME``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/check_backup.inc.rst b/docs/user_guide/commands/barman/check_backup.inc.rst new file mode 100644 index 000000000..ae4791041 --- /dev/null +++ b/docs/user_guide/commands/barman/check_backup.inc.rst @@ -0,0 +1,50 @@ +.. _commands-barman-check-backup: + +``barman check-backup`` +""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + check-backup SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +Check that all necessary WAL files for verifying the consistency of a physical backup are +properly archived. This command is automatically executed by the cron job and at the end +of each backup operation. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/config_switch.inc.rst b/docs/user_guide/commands/barman/config_switch.inc.rst new file mode 100644 index 000000000..8743f4d71 --- /dev/null +++ b/docs/user_guide/commands/barman/config_switch.inc.rst @@ -0,0 +1,34 @@ +.. _commands-barman-config-switch: + +``barman config-switch`` +"""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + config-switch SERVER_NAME { --reset | MODEL_NAME } + +Description +^^^^^^^^^^^ + +Apply a set of configuration overrides from the model to a server in Barman. The final +configuration will combine or override the server's existing settings with the ones +specified in the model. You can reset the server configurations with the ``--reset`` +argument. + +.. note:: + Only one model can be active at a time for a given server. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +``MODEL_NAME`` + Name of the model. + +``--reset`` + Reset the server's configurations. diff --git a/docs/user_guide/commands/barman/config_update.inc.rst b/docs/user_guide/commands/barman/config_update.inc.rst new file mode 100644 index 000000000..897849dfc --- /dev/null +++ b/docs/user_guide/commands/barman/config_update.inc.rst @@ -0,0 +1,40 @@ +.. _commands-barman-config-update: + +``barman config-update`` +"""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + config-update STRING + +Description +^^^^^^^^^^^ + +Create or update the configurations for servers and/or models in Barman. The parameter +should be a JSON string containing an array of documents. Each document must include a +``scope`` key, which can be either server or model, and either a ``server_name`` or +``model_name`` key, depending on the scope value. Additionally, the document should +include other keys representing Barman configuration options and their desired values. + +.. note:: + The barman ``config-update`` command writes configuration options to a file named + ``.barman.auto.conf``, located in the ``barman_home`` directory. This configuration + file has higher precedence and will override values from the global Barman + configuration file (usually ``/etc/barman.conf``) and from any included files specified + in ``configuration_files_directory`` (typically files in ``/etc/barman.d``). Be aware + of this if you decide to manually modify configuration options in those files later. + +Parameters +^^^^^^^^^^ + +``STRING`` + List of JSON formatted string. + +Example +^^^^^^^ + +``JSON_STRING='[{“scope”: “server”, “server_name”: “my_server”, “archiver”: +“on”, “streaming_archiver”: “off”}]'`` diff --git a/docs/user_guide/commands/barman/cron.inc.rst b/docs/user_guide/commands/barman/cron.inc.rst new file mode 100644 index 000000000..856f8d6f1 --- /dev/null +++ b/docs/user_guide/commands/barman/cron.inc.rst @@ -0,0 +1,23 @@ +.. _commands-barman-cron: + +``barman cron`` +""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + cron [ --keep-descriptors ] + +Description +^^^^^^^^^^^ + +Carry out maintenance tasks, such as enforcing retention policies or managing WAL files. + +Parameters +^^^^^^^^^^ + +``--keep-descriptors`` + Keep the ^stdout^ and ^stderr^ streams of the Barman subprocesses connected to the + main process. This is especially useful for Docker-based installations. diff --git a/docs/user_guide/commands/barman/delete.inc.rst b/docs/user_guide/commands/barman/delete.inc.rst new file mode 100644 index 000000000..cf71845c9 --- /dev/null +++ b/docs/user_guide/commands/barman/delete.inc.rst @@ -0,0 +1,48 @@ +.. _commands-barman-delete: + +``barman delete`` +""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + delete SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +Delete the specified backup. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/diagnose.inc.rst b/docs/user_guide/commands/barman/diagnose.inc.rst new file mode 100644 index 000000000..f27efe8bf --- /dev/null +++ b/docs/user_guide/commands/barman/diagnose.inc.rst @@ -0,0 +1,19 @@ +.. _commands-barman-diagnose: + +``barman diagnose`` +""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + diagnose + +Description +^^^^^^^^^^^ + +Display diagnostic information about the Barman node, which is the server where Barman +is installed, as well as all configured Postgres servers. This includes details such as +global configuration, SSH version, Python version, rsync version, the current +configuration and status of all servers, and many more. diff --git a/docs/user_guide/commands/barman/generate_manifest.inc.rst b/docs/user_guide/commands/barman/generate_manifest.inc.rst new file mode 100644 index 000000000..be2b50d95 --- /dev/null +++ b/docs/user_guide/commands/barman/generate_manifest.inc.rst @@ -0,0 +1,49 @@ +.. _commands-barman-generate-manifest: + +``barman generate-manifest`` +"""""""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + generate-manifest SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +Generates a ``backup_manifest`` file for a backup. You can use a shortcut instead of +``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/get_wal.inc.rst b/docs/user_guide/commands/barman/get_wal.inc.rst new file mode 100644 index 000000000..8cc261d32 --- /dev/null +++ b/docs/user_guide/commands/barman/get_wal.inc.rst @@ -0,0 +1,67 @@ +.. _commands-barman-get-wal: + +``barman get-wal`` +"""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + get-wal + [ -j ] + [ -o OUTPUT_DIRECTORY ] + [ -p VALUE ] + [ { -P | --partial } ] + [ { -t | --test } ] + [ -z ] + SERVER_NAME WAL_NAME + +Description +^^^^^^^^^^^ + +Retrieve a WAL file from the xlog archive of a specified server. By default, if the +requested WAL file is found, it is returned as uncompressed content to ``STDOUT``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``WAL_NAME`` + Id of the backup in barman catalog. + +``-j`` / ``--bzip2`` + Output will be compressed using bzip2. + +``-z`` / ``--gzip`` + Output will be compressed using gzip. + +``--keep-compression`` + Do not uncompress the file content. The output will be the original compressed + file. + +``-o`` + Destination directory where barman will store the WAL file. + +``-p`` + Specify an integer value greater than or equal to 1 to retrieve WAL files from the + specified WAL file up to the value specified by this parameter. When using this option, + ``get-wal`` returns a list of zero to the specified WAL segment names, with one name + per row. + +``-P`` / ``--partial`` + Additionally, collect partial WAL files (.partial). + +``-t`` / ``--test`` + Test both the connection and configuration of the specified Postgres server in + Barman for WAL retrieval. When this option is used, the required ``WAL_NAME`` + argument is disregarded. + + +.. warning:: + + ``-z`` / ``--gzip`` and ``-j`` / ``--bzip2`` options are deprecated and will be + removed in the future. For WAL compression, please make sure to enable it directly + on the Barman server via the ``compression`` configuration option. diff --git a/docs/user_guide/commands/barman/keep.inc.rst b/docs/user_guide/commands/barman/keep.inc.rst new file mode 100644 index 000000000..2eec3e426 --- /dev/null +++ b/docs/user_guide/commands/barman/keep.inc.rst @@ -0,0 +1,73 @@ +.. _commands-barman-keep: + +``barman keep`` +""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + keep + { --release | --status | --target { full | standalone } } + SERVER_NAME BACKUP_ID + + +Description +^^^^^^^^^^^ + +Mark the specified backup with a ``target`` as an archival backup to be retained +indefinitely, overriding any active retention policies. You can also check the keep +``status`` of a backup and ``release`` the keep mark from a backup. You can use a +shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +``--release`` + Release the keep mark from this backup. This will remove its archival status and + make it available for deletion, either directly or by retention policy. + +``--status`` + Report the archival status of the backup. The status will be either ``full`` or + ``standalone`` for archival backups, or ``nokeep`` for backups that have not been + designated as archival. + +``--target`` + Define the recovery target for the archival backup. The possible values are: + + * ``full``: The backup can be used to recover to the most recent point in time. To + support this, Barman will keep all necessary WALs to maintain the backup's + consistency as well as any subsequent WALs. + * ``standalone``: The backup can only be used to restore the server to its state at the + time of the backup. Barman will retain only the WALs required to ensure the + backup's consistency. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/list_backups.inc.rst b/docs/user_guide/commands/barman/list_backups.inc.rst new file mode 100644 index 000000000..e492cbbaf --- /dev/null +++ b/docs/user_guide/commands/barman/list_backups.inc.rst @@ -0,0 +1,40 @@ +.. _commands-barman-list-backups: + +``barman list-backups`` +""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + list-backups SERVER_NAME + +Description +^^^^^^^^^^^ + +Display the available backups for a server. This command is useful for retrieving both +the backup ID and the backup type. You can find details about this command in +:ref:`Catalog usage `. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``SERVER_NAME``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/list_files.inc.rst b/docs/user_guide/commands/barman/list_files.inc.rst new file mode 100644 index 000000000..ba5338df6 --- /dev/null +++ b/docs/user_guide/commands/barman/list_files.inc.rst @@ -0,0 +1,60 @@ +.. _commands-barman-list-files: + +``barman list-files`` +""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + list-files + [ --target { data | full | standalone | wal } ] + SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +List all files in a specific backup. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +``--target`` + Define specific files to be listed. The possible values are: + + * ``standalone`` (default): List the base backup files, including required WAL files. + * ``data``: List just the data files. + * ``wal``: List all the WAL files between the start of the base backup and the end of + the log or the start of the following base backup (depending on whether the + specified base backup is the most recent one available). + * ``full``: same as ``data`` + ``wal``. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/list_servers.inc.rst b/docs/user_guide/commands/barman/list_servers.inc.rst new file mode 100644 index 000000000..724415909 --- /dev/null +++ b/docs/user_guide/commands/barman/list_servers.inc.rst @@ -0,0 +1,22 @@ +.. _commands-barman-list-servers: + +``barman list-servers`` +""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + list-servers [ --minimal ] + +Description +^^^^^^^^^^^ + +Display all configured servers along with their descriptions. + +Parameters +^^^^^^^^^^ + +``--minimal`` + Machine readable output. diff --git a/docs/user_guide/commands/barman/lock_directory_cleanup.inc.rst b/docs/user_guide/commands/barman/lock_directory_cleanup.inc.rst new file mode 100644 index 000000000..0210819a2 --- /dev/null +++ b/docs/user_guide/commands/barman/lock_directory_cleanup.inc.rst @@ -0,0 +1,16 @@ +.. _commands-barman-lock-directory-cleanup: + +``barman lock-directory-cleanup`` +""""""""""""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + lock-directory-cleanup + +Description +^^^^^^^^^^^ + +Automatically removes unused lock files from the ``barman_lock_directory``. diff --git a/docs/user_guide/commands/barman/put_wal.inc.rst b/docs/user_guide/commands/barman/put_wal.inc.rst new file mode 100644 index 000000000..276f33101 --- /dev/null +++ b/docs/user_guide/commands/barman/put_wal.inc.rst @@ -0,0 +1,32 @@ +.. _commands-barman-put-wal: + +``barman put-wal`` +"""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + put-wal [ { -t | --test } ] SERVER_NAME + +Description +^^^^^^^^^^^ + +Receive a WAL file from a remote server and securely save it into the server incoming +directory. The WAL file should be provided via ``STDIN``, encapsulated in a tar stream +along with a ``SHA256SUMS`` or ``MD5SUMS`` file for validation (``sha256`` is the default +hash algorithm, but the user can choose ``md5`` when setting the ``archive-command`` via +``barman-wal-archive``). This command is intended to be executed via SSH from a remote +``barman-wal-archive`` utility (included in the barman-cli package). Avoid using this +command directly unless you fully manage the content of the files. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``-t`` / ``--test`` + Test both the connection and configuration of the specified Postgres + server in Barman for WAL retrieval. diff --git a/docs/user_guide/commands/barman/rebuild_xlogdb.inc.rst b/docs/user_guide/commands/barman/rebuild_xlogdb.inc.rst new file mode 100644 index 000000000..baaac404a --- /dev/null +++ b/docs/user_guide/commands/barman/rebuild_xlogdb.inc.rst @@ -0,0 +1,40 @@ +.. _commands-barman-rebuild-xlogdb: + +``barman rebuild-xlogdb`` +""""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + rebuild-xlogdb SERVER_NAME + +Description +^^^^^^^^^^^ + +Rebuild the WAL file metadata for a server (or for all servers using the ``all`` shortcut) +based on the disk content. The WAL archive metadata is stored in the ``xlog.db`` file, +with each Barman server maintaining its own copy. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``SERVER_NAME``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/receive_wal.inc.rst b/docs/user_guide/commands/barman/receive_wal.inc.rst new file mode 100644 index 000000000..5815679dc --- /dev/null +++ b/docs/user_guide/commands/barman/receive_wal.inc.rst @@ -0,0 +1,44 @@ +.. _commands-barman-receive-wal: + +``barman receive-wal`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + receive-wal + [ --create-slot ] + [ --drop-slot ] + [ --reset ] + [ --stop ] + SERVER_NAME + +Description +^^^^^^^^^^^ + +Initiate the streaming of transaction logs for a server. This process uses +``pg_receivewal`` or ``pg_receivexlog`` to receive WAL files from Postgres servers via +the streaming protocol. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node. + +``--create-slot`` + Create the physical replication slot configured with the ``slot_name`` configuration + parameter. + +``--drop-slot`` + Drop the physical replication slot configured with the ``slot_name`` configuration + parameter. + +``--reset`` + Reset the status of ``receive-wal``, restarting the streaming from the current WAL file + of the server. + +``--stop`` + Stop the process for the server. diff --git a/docs/user_guide/commands/barman/replication_status.inc.rst b/docs/user_guide/commands/barman/replication_status.inc.rst new file mode 100644 index 000000000..949590350 --- /dev/null +++ b/docs/user_guide/commands/barman/replication_status.inc.rst @@ -0,0 +1,62 @@ +.. _commands-barman-replication-status: + +``barman replication-status`` +""""""""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + replication-status + [ --minimal ] + [ --source { backup-host | wal-host } ] + [ --target { hot-standby | wal-streamer | all } ] + SERVER_NAME + +Description +^^^^^^^^^^^ + +Display real-time information and status of any streaming clients connected to the +specified server. Specify ``all`` shortcut to diplay information for all configured +servers. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``--minimal`` + Machine readable output. + +``--source`` + The possible values are: + + * ``backup-host`` (default): List clients using the backup connection information + for a server. + * ``wal-host``: List clients using the WAL streaming connection information for a + server. + +``--target`` + The possible values are: + + * ``hot-standby``: List only hot standby servers. + * ``wal-streamer``: List only WAL streaming clients, such as ``pg_receivewal``. + * ``all`` (default): List all streaming clients. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``SERVER_NAME``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/restore.inc.rst b/docs/user_guide/commands/barman/restore.inc.rst new file mode 100644 index 000000000..3f4e95691 --- /dev/null +++ b/docs/user_guide/commands/barman/restore.inc.rst @@ -0,0 +1,218 @@ +.. _commands-barman-restore: + +``barman restore`` +"""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + restore + [ --aws-region AWS_REGION } ] + [ --azure-resource-group AZURE_RESOURCE_GRP ] + [ --bwlimit KBPS ] + [ --exclusive ] + [ --gcp-zone GCP_ZONE ] + [ --get-wal | --no-get-wal ] + [ { -j | --jobs } PARALLEL_WORKERS ] + [ --jobs-start-batch-period SECONDS ] + [ --jobs-start-batch-size NUMBER ] + [ --local-staging-path PATH ] + [ --network-compression | --no-network-compression ] + [ --no-retry ] + [ --recovery-conf-filename FILENAME ] + [ --recovery-staging-path PATH ] + [ --remote-ssh-command STRING ] + [ --retry-sleep SECONDS ] + [ --retry-times NUMBER ] + [ --snapshot-recovery-instance INSTANCE_NAME ] + [ --standby-mode ] + [ --tablespace NAME:LOCATION ] + [ --target-action { pause | shutdown | promote } ] + [ --target-immediate ] + [ --target-lsn LSN ] + [ --target-name RESTORE_POINT_NAME ] + [ --target-time TIMESTAMP ] + [ --target-tli TLI ] + [ --target-xid XID ] + SERVER_NAME BACKUP_ID DESTINATION_DIR + +Description +^^^^^^^^^^^ + +Execute a PostreSQL server restore operation. Barman will restore the backup from a +server in the destination directory. The restoration can be performed locally (on the +barman node itself) or remotely (on another machine accessible via SSH). The location is +determined by whether or not the ``--remote-ssh-command`` option is used. More +information on this command can be found in the :ref:`recovery` section. You can use a +shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +``DESTINATION_DIR`` + Destination directory to restore the backup. + +``--aws-region`` + Specify the AWS region where the instance and disks for snapshot recovery are + located. This option allows you to override the ``aws_region`` value in the Barman + configuration. + +``--azure-resource-group`` + Specify the Azure resource group containing the instance and disks for snapshot + recovery. This option allows you to override the ``azure_resource_group`` value in + the Barman configuration. + +``--bwlimit`` + Specify the maximum transfer rate in kilobytes per second. A value of ``0`` + indicates no limit. This setting overrides the ``bandwidth_limit`` configuration + option. + +``--exclusive`` + Set target (time, XID or LSN) to be non inclusive. + +``--gcp-zone`` + Specify the GCP zone where the instance and disks for snapshot recovery are located. + This option allows you to override the ``gcp_zone`` value in the Barman + configuration. + +``--get-wal`` / ``--no-get-wal`` + Enable/disable usage of ``get-wal`` for WAL fetching during recovery. Default is based on + ``recovery_options`` setting. + +``-j`` / ``--jobs`` + Specify the number of parallel workers to use for copying files during the backup. + This setting overrides the ``parallel_jobs`` parameter if it is specified in the + configuration file. + +``--jobs-start-batch-period`` + Specify the time period, in seconds, for starting a single batch of jobs. This value + overrides the ``parallel_jobs_start_batch_period`` parameter if it is set in the + configuration file. The default is ``1`` second. + +``--jobs-start-batch-size`` + Specify the maximum number of parallel workers to initiate in a single batch. This + value overrides the ``parallel_jobs_start_batch_size`` parameter if it is defined in + the configuration file. The default is ``10`` workers. + +``--local-staging-path`` + Specify path on the Barman host where the chain of backups will be combined before + being copied to the destination directory. The contents created within the staging + path will be removed upon completion of the restore process. This option is + necessary for restoring from block-level incremental backups and has no effect + otherwise. + +``--network-compression`` / ``--no-network-compression`` + Enable/disable network compression during remote restore. Default is based on + ``network_compression`` configuration setting. + +``--no-retry`` + There will be no retry in case of an error. It is the same as setting + ``--retry-times 0``. + +``--recovery-conf-filename`` + Specify the name of the file where Barman should write recovery options when + recovering backups for Postgres versions 12 and later. By default, this is set to + ``postgresql.auto.conf``. However, if ``--recovery-conf-filename`` is specified, + recovery options will be written to the specified value instead. While the default + value is suitable for most Postgres installations, this option allows you to specify + an alternative location if Postgres is managed by tools that alter the configuration + mechanism (for example, if ``postgresql.auto.conf`` is symlinked to ``/dev/null``). + +``--recovery-staging-path`` + Specify a path on the recovery host where files for a compressed backup will be + staged before being uncompressed to the destination directory. Backups will be + staged in their own directory within the staging path, following the naming + convention: ``barman-staging-SERVER_NAME-BACKUP_ID``. This staging directory will be + removed after the restore process is complete. This option is mandatory for + restoring from compressed backups and has no effect otherwise. + +``--remote-ssh-command`` + This option enables remote restore by specifying the secure shell command to + execute on a remote host. It functions similarly to the ``ssh_command`` server + option in the configuration file for remote restore, that is, ``'ssh USER@SERVER'``. + +``--retry-sleep`` + Specify the number of seconds to wait after a failed copy before retrying. This + setting applies to both backup and restore operations and overrides the + ``basebackup_retry_sleep`` parameter if it is defined in the configuration file. + +``--retry-times`` + Specify the number of times to retry the base backup copy in case of an error. This + applies to both backup and restore operations and overrides the + ``basebackup_retry_times`` parameter if it is set in the configuration file. + +``--snapshot-recovery-instance`` + Specify the name of the instance where the disks recovered from the snapshots are + attached. This option is necessary when recovering backups created with + ``backup_method=snapshot``. + +``--standby-mode`` + Whether to start the Postgres server as a standby. + +``--tablespace`` + Specify tablespace relocation rule. ``NAME`` is the tablespace name and ``LOCATION`` + is the recovery host destination path to restore the tablespace. + +``--target-action`` + Trigger the specified action when the recovery target is reached. This option + requires defining a target along with one of these actions. The possible values are: + + * ``pause``: Once recovery target is reached, the server is started in pause state, + allowing users to inspect the instance + * ``promote``: Once recovery target is reached, the server will exit the recovery + operation and is promoted as a master. + * ``shutdown``: Once recovery target is reached, the server is shut down. + +``--target-immediate`` + Recovery is completed when a consistent state is reached (end of the base backup). + +``--target-lsn`` + Recover to the specified LSN (Log Sequence Number). Requires Postgres 10 or above. + +``--target-name`` + Recover to the specified name of a restore point previously created with the + ``pg_create_restore_point(name)``. + +``--target-time`` + Recover to the specified time. Use the format ``YYYY-MM-DD HH:MM:SS.mmm``. + +``--target-tli`` + Recover the specified timeline. You can use the special values ``current`` and + ``latest`` in addition to a numeric timeline ID. For Postgres versions 12 and above, + the default is to recover to the latest timeline in the WAL archive. For Postgres + versions below 12, the default is to recover to the timeline that was current at the + time the backup was taken. + +``--target-xid`` + Recover to the specified transaction ID. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/show_backup.inc.rst b/docs/user_guide/commands/barman/show_backup.inc.rst new file mode 100644 index 000000000..175536066 --- /dev/null +++ b/docs/user_guide/commands/barman/show_backup.inc.rst @@ -0,0 +1,49 @@ +.. _commands-barman-show-backup: + +``barman show-backup`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + show-backup SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +Display detailed information about a specific backup. You can find details about this command in +:ref:`Catalog usage `. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + Use shortcuts instead of ``BACKUP_ID``. + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/show_servers.inc.rst b/docs/user_guide/commands/barman/show_servers.inc.rst new file mode 100644 index 000000000..84c0367dc --- /dev/null +++ b/docs/user_guide/commands/barman/show_servers.inc.rst @@ -0,0 +1,38 @@ +.. _commands-barman-show-servers: + +``barman show-servers`` +""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + show-servers SERVER_NAME + +Description +^^^^^^^^^^^ + +Display detailed information about a server, including ``conninfo``, ``backup_directory``, +``wals_directory``, ``archive_command``, and many more. To view information about all configured +servers, specify the ``all`` shortcut instead of the server name. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/status.inc.rst b/docs/user_guide/commands/barman/status.inc.rst new file mode 100644 index 000000000..dd492ecf5 --- /dev/null +++ b/docs/user_guide/commands/barman/status.inc.rst @@ -0,0 +1,37 @@ +.. _commands-barman-status: + +``barman status`` +""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + status SERVER_NAME + +Description +^^^^^^^^^^^ + +Display information about a server's status, including details such as the state, +Postgres version, WAL information, available backups and more. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **all** + - All available servers diff --git a/docs/user_guide/commands/barman/switch_wal.inc.rst b/docs/user_guide/commands/barman/switch_wal.inc.rst new file mode 100644 index 000000000..79f48adaf --- /dev/null +++ b/docs/user_guide/commands/barman/switch_wal.inc.rst @@ -0,0 +1,45 @@ +.. _commands-barman-switch-wal: + +``barman switch-wal`` +""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + switch-wal + [ --archive ] + [ --archive-timeout ] + [ --force ] + SERVER_NAME + + +Description +^^^^^^^^^^^ + +Execute ``pg_switch_wal()`` on the target server (Postgres versions 10 and later) or +``pg_switch_xlog()`` (for Postgres versions 8.3 to 9.6). + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``--archive`` + Waits for one WAL file to be archived. If no WAL file is archived within a specified + time (default: ``30`` seconds), Barman will terminate with a failure exit code. This + option is also available on standby servers. + +``--archive-timeout`` + Specify the amount of time in seconds (default: ``30`` seconds) that the archiver + will wait for a new WAL file to be archived before timing out. This option is also + available on standby servers. + +``--force`` + Forces the switch by executing a CHECKPOINT before ``pg_switch_wal()``. + + .. note:: + Running a CHECKPOINT may increase I/O load on the Postgres server, so use this + option cautiously. diff --git a/docs/user_guide/commands/barman/switch_xlog.inc.rst b/docs/user_guide/commands/barman/switch_xlog.inc.rst new file mode 100644 index 000000000..eaa6680ba --- /dev/null +++ b/docs/user_guide/commands/barman/switch_xlog.inc.rst @@ -0,0 +1,9 @@ +.. _commands-barman-switch-xlog: + +``barman switch-xlog`` +"""""""""""""""""""""" + +Description +^^^^^^^^^^^ + +Alias for the ``switch-wal`` command. diff --git a/docs/user_guide/commands/barman/sync_backup.inc.rst b/docs/user_guide/commands/barman/sync_backup.inc.rst new file mode 100644 index 000000000..0cc124a9d --- /dev/null +++ b/docs/user_guide/commands/barman/sync_backup.inc.rst @@ -0,0 +1,52 @@ +.. _commands-barman-sync-backup: + +``barman sync-backup`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + sync-backup SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +This command synchronizes a passive node with its primary by copying all files from a +backup present on the server node. It is available only for passive nodes and uses +the ``primary_ssh_command`` option to establish a secure connection with the primary +node. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + For some commands, instead of using the timestamp backup ID, you can use the following + shortcuts or aliases to identify a backup for a given server: + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman/sync_info.inc.rst b/docs/user_guide/commands/barman/sync_info.inc.rst new file mode 100644 index 000000000..25d1b182d --- /dev/null +++ b/docs/user_guide/commands/barman/sync_info.inc.rst @@ -0,0 +1,34 @@ +.. _commands-barman-sync-info: + +``barman sync-info`` +"""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + sync-info [ --primary ] SERVER_NAME [ LAST_WAL [ LAST_POS ] ] + +Description +^^^^^^^^^^^ + +Gather information about the current status of a Barman server for synchronization +purposes. + +This command returns a JSON output for a server that includes: all successfully +completed backups, all archived WAL files, the configuration, the last WAL file read from +``xlog.db``, and its position within the file. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``LAST_WAL`` + Instructs sync-info to skip any WAL files that precede the specified file (for + incremental synchronization). + +``LAST_POS`` + Hint for quickly positioning in the ``xlog.db`` file (for incremental synchronization). diff --git a/docs/user_guide/commands/barman/sync_wals.inc.rst b/docs/user_guide/commands/barman/sync_wals.inc.rst new file mode 100644 index 000000000..3d294338e --- /dev/null +++ b/docs/user_guide/commands/barman/sync_wals.inc.rst @@ -0,0 +1,24 @@ +.. _commands-barman-sync-wals: + +``barman sync-wals`` +"""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + sync-wals SERVER_NAME + +Description +^^^^^^^^^^^ + +This command synchronizes a passive node with its primary by copying all archived WAL +files from the server node. It is available only for passive nodes and utilizes the +``primary_ssh_command`` option to establish a secure connection with the primary node. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node diff --git a/docs/user_guide/commands/barman/verify.inc.rst b/docs/user_guide/commands/barman/verify.inc.rst new file mode 100644 index 000000000..60d370735 --- /dev/null +++ b/docs/user_guide/commands/barman/verify.inc.rst @@ -0,0 +1,9 @@ +.. _commands-barman-verify: + +``barman verify`` +""""""""""""""""" + +Description +^^^^^^^^^^^ + +Alias for ``verify-backup`` command. diff --git a/docs/user_guide/commands/barman/verify_backup.inc.rst b/docs/user_guide/commands/barman/verify_backup.inc.rst new file mode 100644 index 000000000..8beeb182d --- /dev/null +++ b/docs/user_guide/commands/barman/verify_backup.inc.rst @@ -0,0 +1,52 @@ +.. _commands-barman-verify-backup: + +``barman verify-backup`` +"""""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + verify-backup SERVER_NAME BACKUP_ID + +Description +^^^^^^^^^^^ + +Runs ``pg_verifybackup`` on a backup manifest file (available since Postgres version 13). +For rsync backups, it can be used after creating a manifest file using the +``generate-manifest`` command. Requires ``pg_verifybackup`` to be installed on the +backup server. You can use a shortcut instead of ``BACKUP_ID``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + Name of the server in barman node + +``BACKUP_ID`` + Id of the backup in barman catalog. + +.. only:: man + + Shortcuts + ^^^^^^^^^ + + For some commands, instead of using the timestamp backup ID, you can use the following + shortcuts or aliases to identify a backup for a given server: + + .. list-table:: + :widths: 25 100 + :header-rows: 1 + + * - **Shortcut** + - **Description** + * - **first/oldest** + - Oldest available backup for the server, in chronological order. + * - **last/latest** + - Most recent available backup for the server, in chronological order. + * - **last-full/latest-full** + - Most recent full backup eligible for a block-level incremental backup using the + ``--incremental`` option. + * - **last-failed** + - Most recent backup that failed, in chronological order. \ No newline at end of file diff --git a/docs/user_guide/commands/barman_cli/wal_archive.inc.rst b/docs/user_guide/commands/barman_cli/wal_archive.inc.rst new file mode 100644 index 000000000..8ee1ff082 --- /dev/null +++ b/docs/user_guide/commands/barman_cli/wal_archive.inc.rst @@ -0,0 +1,65 @@ +.. _commands-barman-cli-barman-wal-archive: + +``barman-wal-archive`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + barman-wal-archive + [ { -h, --help } ] + [ { -V, --version } ] + [ { -U, --user } USER ] + [ --port PORT ] + [ { -c, --config } CONFIG ] + [ { -t --test } ] + BARMAN_HOST SERVER_NAME WAL_PATH + +Description +^^^^^^^^^^^ + +This script can be utilized in the ``archive_command`` of a Postgres server to +transfer WAL files to a Barman host using the ``put-wal`` command (introduced in Barman +2.6). It establishes an SSH connection to the Barman host, enabling seamless integration +of Barman within Postgres clusters for improved business continuity. + +**Exit Statuses** are: + +* ``0`` for ``SUCCESS``. +* ``non-zero`` for ``FAILURE``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + The server name configured in Barman for the Postgres server from which + the WAL file is retrieved. + +``BARMAN_HOST`` + The host of the Barman server. + +``WAL_PATH`` + The value of the '%p' keyword (according to ``archive_command``). + +``-h`` / ``--help`` + Display a help message and exit. + +``-V`` / ``--version`` + Display the program's version number and exit. + +``-U`` / ``--user`` + Specify the user for the SSH connection to the Barman server (defaults to + ``barman``). + +``--port`` + Define the port used for the SSH connection to the Barman server. + +``-c`` / ``--config`` + Specify the configuration file on the Barman server. + +``-t`` / ``--test`` + Test the connection and configuration of the specified Postgres server in Barman to + ensure it is ready to receive WAL files. This option ignores the mandatory arguments + ``WAL_NAME`` and ``WAL_DEST``. diff --git a/docs/user_guide/commands/barman_cli/wal_restore.inc.rst b/docs/user_guide/commands/barman_cli/wal_restore.inc.rst new file mode 100644 index 000000000..42128a74b --- /dev/null +++ b/docs/user_guide/commands/barman_cli/wal_restore.inc.rst @@ -0,0 +1,108 @@ +.. _commands-barman-cli-barman-wal-restore: + +``barman-wal-restore`` +"""""""""""""""""""""" + +Synopsis +^^^^^^^^ + +.. code-block:: text + + barman-wal-restore + [ { -h, --help } ] + [ { -V, --version } ] + [ { -U, --user } USER ] + [ --port PORT ] + [ { -s, --sleep } SECONDS ] + [ { -p, --parallel } JOBS ] + [ --spool-dir SPOOL_DIR ] + [ { -P, --partial } ] + [ { -z, --gzip } ] + [ { -j, --bzip2 } ] + [ { -c, --config } CONFIG ] + [ { -t --test } ] + BARMAN_HOST SERVER_NAME WAL_NAME WAL_DEST + +Description +^^^^^^^^^^^ + +This script serves as a ``restore_command`` for Postgres servers, enabling the +retrieval of WAL files through Barman's ``get-wal`` feature. It establishes an SSH +connection to the Barman host and facilitates the integration of Barman within +Postgres clusters, enhancing business continuity. + +**Exit Statuses** are: + +* ``0`` for ``SUCCESS``. +* ``1`` for remote get-wal command ``FAILURE``, likely because the requested WAL could + not be found. +* ``2`` for ssh connection ``FAILURE``. +* Any other ``non-zero`` for ``FAILURE``. + +Parameters +^^^^^^^^^^ + +``SERVER_NAME`` + The server name configured in Barman for the Postgres server from which the + WAL file is retrieved. + +``BARMAN_HOST`` + The host of the Barman server. + +``WAL_NAME`` + The value of the '%f' keyword (according to ``restore_command``). + +``WAL_DEST`` + The value of the '%p' keyword (according to ``restore_command``). + +``-h`` / ``--help`` + Display a help message and exit. + +``-V`` / ``--version`` + Display the program's version number and exit. + +``-U`` / ``--user`` + Specify the user for the SSH connection to the Barman server (defaults to + ``barman``). + +``--port`` + Define the port used for the SSH connection to the Barman server. + +``-s`` / ``--sleep`` + Pause for ``SECONDS`` after a failed ``get-wal`` request (defaults to ``0`` - no + wait). + +``-p`` / ``--parallel`` + Indicate the number of files to ``peek`` and transfer simultaneously (defaults to + ``0`` - disabled). + +``--spool-dir`` + Specify the spool directory for WAL files (defaults to ``/var/tmp/walrestore``). + +``-P`` / ``--partial`` + Include partial WAL files (.partial) in the retrieval. + +``-z`` / ``--gzip`` + Transfer WAL files compressed with ``gzip``. + +``-j`` / ``--bzip2`` + Transfer WAL files compressed with ``bzip2``. + +``--keep-compression`` + If specified, compressed files will be trasnfered as-is and decompressed on arrival + on the client-side. + +``-c`` / ``--config`` + Specify the configuration file on the Barman server. + +``-t`` / ``--test`` + Test the connection and configuration of the specified Postgres server in Barman to + ensure it is ready to receive WAL files. This option ignores the mandatory arguments + ``WAL_NAME`` and ``WAL_DEST``. + + +.. warning:: + + ``-z`` / ``--gzip`` and ``-j`` / ``--bzip2`` options are deprecated and will be + removed in the future. For WAL compression, please make sure to enable it directly + on the Barman server via the ``compression`` configuration option. diff --git a/docs/user_guide/commands/barman_cloud/backup.inc.rst b/docs/user_guide/commands/barman_cloud/backup.inc.rst new file mode 100644 index 000000000..9f7288918 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/backup.inc.rst @@ -0,0 +1,260 @@ +.. _barman-cloud-barman-cloud-backup: + +``barman-cloud-backup`` +""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-backup + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ { -z | --gzip } ] + [ { -j | --bzip2 } ] + [ --snappy ] + [ { -h | --host } HOST ] + [ { -p | --port } PORT ] + [ { -U | --user } USER ] + [ { -d | --dbname } DBNAME ] + [ { -n | --name } BACKUP_NAME ] + [ { -J | --jobs } JOBS ] + [ -S MAX_ARCHIVE_SIZE ] + [ --immediate-checkpoint ] + [ --min-chunk-size MIN_CHUNK_SIZE ] + [ --max-bandwidth MAX_BANDWIDTH ] + [ --snapshot-instance SNAPSHOT_INSTANCE ] + [ --snapshot-disk NAME ] + [ --tags [ TAGS ... ] ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ { -e | --encryption } ENCRYPTION ] + [ --sse-kms-key-id SSE_KMS_KEY_ID ] + [ --aws-region AWS_REGION ] + [ --aws-snapshot-lock-mode { compliance | governance } ] + [ --aws-snapshot-lock-duration DAYS ] + [ --aws-snapshot-lock-cool-off-period HOURS ] + [ --aws-snapshot-lock-expiration-date DATETIME ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --encryption-scope ENCRYPTION_SCOPE ] + [ --azure-subscription-id AZURE_SUBSCRIPTION_ID ] + [ --azure-resource-group AZURE_RESOURCE_GROUP ] + [ --gcp-project GCP_PROJECT ] + [ --kms-key-name KMS_KEY_NAME ] + [ --gcp-zone GCP_ZONE ] + DESTINATION_URL SERVER_NAME + +**Description** + +The ``barman-cloud-backup`` script is used to create a local backup of a Postgres +server and transfer it to a supported cloud provider, bypassing the Barman server. It +can also be utilized as a hook script for copying Barman backups from the Barman server +to one of the supported clouds (post_backup_retry_script). + +This script requires read access to PGDATA and tablespaces, typically run as the +postgres user. When used on a Barman server, it requires read access to the directory +where Barman backups are stored. If ``--snapshot-`` arguments are used and snapshots are +supported by the selected cloud provider, the backup will be performed using snapshots +of the specified disks (``--snapshot-disk``). The backup label and metadata will also be +uploaded to the cloud. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +.. important:: + The cloud upload may fail if any file larger than the configured ``--max-archive-size`` + is present in the data directory or tablespaces. However, Postgres files up to + ``1GB`` are always allowed, regardless of the ``--max-archive-size`` setting. + +**Parameters** + +``SERVER_NAME`` + Name of the server to be backed up. + +``DESTINATION_URL`` + URL of the cloud destination, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``-z`` / ``--gzip`` + gzip-compress the backup while uploading to the cloud (should not be used with python < + 3.2). + +``-j`` / ``--bzip2`` + bzip2-compress the backup while uploading to the cloud (should not be used with python < + 3.3). + +``--snappy`` + snappy-compress the backup while uploading to the cloud (requires optional + ``python-snappy`` library). + +``-h`` / ``--host`` + Host or Unix socket for Postgres connection (default: libpq settings). + +``-p`` / ``--port`` + Port for Postgres connection (default: libpq settings). + +``-U`` / ``--user`` + User name for Postgres connection (default: libpq settings). + +``-d`` / ``--dbname`` + Database name or conninfo string for Postgres connection (default: "postgres"). + +``-n`` / ``--name`` + A name which can be used to reference this backup in commands such as + ``barman-cloud-restore`` and ``barman-cloud-backup-delete``. + +``-J`` / ``--jobs`` + Number of subprocesses to upload data to cloud storage (default: ``2``). + +``-S`` / ``--max-archive-size`` + Maximum size of an archive when uploading to cloud storage (default: ``100GB``). + +``--min-chunk-size`` + Minimum size of an individual chunk when uploading to cloud storage (default: ``5MB`` + for ``aws-s3``, ``64KB`` for ``azure-blob-storage``, not applicable for + ``google-cloud-storage``). + +``--max-bandwidth`` + The maximum amount of data to be uploaded per second when backing up to object + storages (default: ``0`` - no limit). + +``--snapshot-instance`` + Instance where the disks to be backed up as snapshots are attached. + +``--snapshot-disk`` + Name of a disk from which snapshots should be taken. + +``--tags`` + Tags to be added to archived WAL files in cloud storage and to snapshots created, if + snapshots are used. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +``-e`` / ``--encryption`` + The encryption algorithm used when storing the uploaded data in S3. + + Allowed options: + + * ``AES256``. + * ``aws:kms``. + +``--sse-kms-key-id`` + The AWS KMS key ID that should be used for encrypting the uploaded data in S3. Can be + specified using the key ID on its own or using the full ARN for the key. Only allowed if + ``-e`` / ``--encryption`` is set to ``aws:kms``. + +``--aws-region`` + The name of the AWS region containing the EC2 VM and storage volumes defined by the + ``--snapshot-instance`` and ``--snapshot-disk`` arguments. + +``--aws-snapshot-lock-mode`` + The lock mode for the snapshot. This is only valid if ``--snapshot-instance`` and + ``--snapshot-disk`` are set. + + Allowed options: + + * ``compliance``. + * ``governance``. + +``--aws-snapshot-lock-duration`` + The lock duration is the period of time (in days) for which the snapshot is to remain + locked, ranging from 1 to 36,500. Set either the lock duration or the expiration date + (not both). + +``--aws-snapshot-lock-cool-off-period`` + The cooling-off period is an optional period of time (in hours) that you can specify + when you lock a snapshot in ``compliance`` mode, ranging from 1 to 72. + +``--aws-snapshot-lock-expiration-date`` + The lock duration is determined by an expiration date in the future. It must be at + least 1 day after the snapshot creation date and time, using the format + ``YYYY-MM-DDTHH:MM:SS.sssZ``. Set either the lock duration or the expiration date + (not both). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options: + + * ``azure-cli``. + * ``managed-identity``. + +``--encryption-scope`` + The name of an encryption scope defined in the Azure Blob Storage service which is to + be used to encrypt the data in Azure. + +``--azure-subscription-id`` + The ID of the Azure subscription which owns the instance and storage volumes defined by + the ``--snapshot-instance`` and ``--snapshot-disk`` arguments. + +``--azure-resource-group`` + The name of the Azure resource group to which the compute instance and disks defined by + the ``--snapshot-instance`` and ``--snapshot-disk`` arguments belong. + +**Extra options for GCP cloud provider** + +``--gcp-project`` + GCP project under which disk snapshots should be stored. + +``--snapshot-gcp-project`` (deprecated) + GCP project under which disk snapshots should be stored - replaced by + ``--gcp-project``. + +``--kms-key-name`` + The name of the GCP KMS key which should be used for encrypting the uploaded data in + GCS. + +``--gcp-zone`` + Zone of the disks from which snapshots should be taken. + +``--snapshot-zone`` (deprecated) + Zone of the disks from which snapshots should be taken - replaced by ``--gcp-zone``. diff --git a/docs/user_guide/commands/barman_cloud/backup_delete.inc.rst b/docs/user_guide/commands/barman_cloud/backup_delete.inc.rst new file mode 100644 index 000000000..f26311260 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/backup_delete.inc.rst @@ -0,0 +1,136 @@ +.. _barman-cloud-barman-cloud-backup-delete: + +``barman-cloud-backup-delete`` +"""""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-backup-delete + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -r | --retention-policy } RETENTION_POLICY ] + [ { -m | --minimum-redundancy } MINIMUM_REDUNDANCY ] + [ { -b | --backup-id } BACKUP_ID] + [ --dry-run ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [--batch-size DELETE_BATCH_SIZE] + SOURCE_URL SERVER_NAME + +**Description** + +The ``barman-cloud-backup-delete`` script is used to delete one or more backups created +with the ``barman-cloud-backup`` command from cloud storage and to remove the associated +WAL files. + +Backups can be specified for deletion either by their backup ID +(as obtained from ``barman-cloud-backup-list``) or by a retention policy. Retention +policies mirror those used by the Barman server, deleting all backups that are not required to +meet the specified policy. When a backup is deleted, any unused WAL files associated with +that backup are also removed. + +WALs are considered unused if: + +* The WALs predate the begin_wal value of the oldest remaining backup. +* The WALs are not required by any archival backups stored in the cloud. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +.. important:: + Each backup deletion involves three separate requests to the cloud provider: one for + the backup files, one for the ``backup.info`` file, and one for the associated WALs. + Deleting by retention policy may result in a high volume of delete requests if a + large number of backups are accumulated in cloud storage. + +**Parameters** + +``SERVER_NAME`` + Name of the server that holds the backup to be deleted. + +``SOURCE_URL`` + URL of the cloud source, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``-b`` / ``--backup-id`` + ID of the backup to be deleted + +``-m`` / ``--minimum-redundancy`` + The minimum number of backups that should always be available. + +``-r`` / ``--retention-policy`` + If specified, delete all backups eligible for deletion according to the supplied + retention policy. + + Syntax: ``REDUNDANCY value | RECOVERY WINDOW OF value { DAYS | WEEKS | MONTHS }`` + +``--batch-size`` + The maximum number of objects to be deleted in a single request to the cloud provider. + If unset then the maximum allowed batch size for the specified cloud provider will be + used (``1000`` for aws-s3, ``256`` for azure-blob-storage and ``100`` for + google-cloud-storage). + +``--dry-run`` + Find the objects which need to be deleted but do not delete them. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/commands/barman_cloud/backup_keep.inc.rst b/docs/user_guide/commands/barman_cloud/backup_keep.inc.rst new file mode 100644 index 000000000..d089275af --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/backup_keep.inc.rst @@ -0,0 +1,115 @@ +.. _barman-cloud-barman-cloud-backup-keep: + +``barman-cloud-backup-keep`` +"""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-backup-keep + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ { -r | --release } ] + [ { -s | --status } ] + [ --target { full | standalone } ] + SOURCE_URL SERVER_NAME BACKUP_ID + +**Description** + +Use this script to designate backups in cloud storage as archival backups, ensuring +their indefinite retention regardless of retention policies. + +This script allows you to mark backups previously created with ``barman-cloud-backup`` +as archival backups. Once flagged as archival, these backups are preserved indefinitely +and are not subject to standard retention policies. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that holds the backup to be kept. + +``SOURCE_URL`` + URL of the cloud source, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``BACKUP_ID`` + The ID of the backup to be kept. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``-r`` / ``--release`` + If specified, the command will remove the keep annotation and the backup will be + eligible for deletion. + +``-s`` / ``--status`` + Print the keep status of the backup. + +``--target`` + Specify the recovery target for this backup. Allowed options are: + + * ``full`` + * ``standalone`` + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/commands/barman_cloud/backup_list.inc.rst b/docs/user_guide/commands/barman_cloud/backup_list.inc.rst new file mode 100644 index 000000000..28b71d515 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/backup_list.inc.rst @@ -0,0 +1,96 @@ +.. _barman-cloud-barman-cloud-backup-list: + +``barman-cloud-backup-list`` +"""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-backup-list + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --format ] + SOURCE_URL SERVER_NAME + +**Description** + +This script lists backups stored in the cloud that were created using the +``barman-cloud-backup`` command. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that holds the backup to be listed. + +``SOURCE_URL`` + URL of the cloud source, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``--format`` + Output format (``console`` or ``json``). Default ``console``. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/commands/barman_cloud/backup_show.inc.rst b/docs/user_guide/commands/barman_cloud/backup_show.inc.rst new file mode 100644 index 000000000..4c6becf31 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/backup_show.inc.rst @@ -0,0 +1,98 @@ +.. _barman-cloud-barman-cloud-backup-show: + +``barman-cloud-backup-show`` +"""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-backup-show + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --format ] + SOURCE_URL SERVER_NAME + +**Description** + +This script displays detailed information about a specific backup created with the +``barman-cloud-backup`` command. The output is similar to the ``barman show-backup`` +from the :ref:`barman show-backup ` command reference, +but it has fewer information. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that holds the backup to be displayed. + +``SOURCE_URL`` + URL of the cloud source, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``--format`` + Output format (``console`` or ``json``). Default ``console``. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/commands/barman_cloud/check_wal_archive.inc.rst b/docs/user_guide/commands/barman_cloud/check_wal_archive.inc.rst new file mode 100644 index 000000000..28b573f55 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/check_wal_archive.inc.rst @@ -0,0 +1,96 @@ +.. _barman-cloud-barman-cloud-check-wal-archive: + +``barman-cloud-check-wal-archive`` +"""""""""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-check-wal-archive + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --timeline TIMELINE ] + DESTINATION_URL SERVER_NAME + +**Description** + +Verify that the WAL archive destination for a server is suitable for use with a new +Postgres cluster. By default, the check will succeed if the WAL archive is empty or if +the target bucket is not found. Any other conditions will result in a failure. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that needs to be checked. + +``DESTINATION_URL`` + URL of the cloud destination, such as a bucket in AWS S3. For example: ``s3://bucket/path/to/folder``. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``--timeline`` + The earliest timeline whose WALs should cause the check to fail. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/commands/barman_cloud/restore.inc.rst b/docs/user_guide/commands/barman_cloud/restore.inc.rst new file mode 100644 index 000000000..5f84b39ea --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/restore.inc.rst @@ -0,0 +1,128 @@ +.. _barman-cloud-barman-cloud-restore: + +``barman-cloud-restore`` +"""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-restore + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --snapshot-recovery-instance SNAPSHOT_RECOVERY_INSTANCE ] + [ --aws-region AWS_REGION ] + [ --gcp-zone GCP_ZONE ] + [ --azure-resource-group AZURE_RESOURCE_GROUP ] + [ --tablespace NAME:LOCATION ] + SOURCE_URL SERVER_NAME BACKUP_ID RECOVERY_DESTINATION + +**Description** + +Use this script to restore a backup directly from cloud storage that was created with +the ``barman-cloud-backup`` command. Additionally, this script can prepare for recovery +from a snapshot backup by verifying that attached disks were cloned from the correct +snapshots and by downloading the backup label from object storage. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that holds the backup to be restored. + +``SOURCE_URL`` + URL of the cloud source, such as a bucket in AWS S3. For example: + ``s3://bucket/path/to/folder``. + +``BACKUP_ID`` + The ID of the backup to be restored. + +``RECOVERY_DESTINATION`` + The path to a directory for recovery. + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``--snapshot-recovery-instance`` + Instance where the disks recovered from the snapshots are attached. + +``--tablespace`` + Tablespace relocation rule. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +``--aws-region`` + The name of the AWS region containing the EC2 VM and storage volumes defined by the + ``--snapshot-instance`` and ``--snapshot-disk`` arguments. + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. + +``--azure-resource-group`` + The name of the Azure resource group to which the compute instance and disks defined by + the ``--snapshot-instance`` and ``--snapshot-disk`` arguments belong. + +**Extra options for GCP cloud provider** + +``--gcp-zone`` + Zone of the disks from which snapshots should be taken. + +``--snapshot-recovery-zone`` (deprecated) + Zone containing the instance and disks for the snapshot recovery - replaced by + ``--gcp-zone``. diff --git a/docs/user_guide/commands/barman_cloud/wal_archive.inc.rst b/docs/user_guide/commands/barman_cloud/wal_archive.inc.rst new file mode 100644 index 000000000..607530947 --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/wal_archive.inc.rst @@ -0,0 +1,169 @@ +.. _barman-cloud-barman-cloud-wal-archive: + +``barman-cloud-wal-archive`` +"""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-wal-archive + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ { -z | --gzip } ] + [ { -j | --bzip2 } ] + [ --snappy ] + [ --tags [ TAGS ... ] ] + [ --history-tags [ HISTORY_TAGS ... ] ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ { -e | --encryption } ENCRYPTION ] + [ --sse-kms-key-id SSE_KMS_KEY_ID ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --encryption-scope ENCRYPTION_SCOPE ] + [ --max-block-size MAX_BLOCK_SIZE ] + [ --max-concurrency MAX_CONCURRENCY ] + [ --max-single-put-size MAX_SINGLE_PUT_SIZE ] + [ --kms-key-name KMS_KEY_NAME ] + DESTINATION_URL SERVER_NAME [ WAL_PATH ] + +**Description** + +The ``barman-cloud-wal-archive`` command is designed to be used in the +``archive_command`` of a Postgres server to directly ship WAL files to cloud storage. + +.. note:: + If you are using Python 2 or unsupported versions of Python 3, avoid using the + compression options ``--gzip`` or ``--bzip2``. The script cannot restore + gzip-compressed WALs on Python < 3.2 or bzip2-compressed WALs on Python < 3.3. + +This script enables the direct transfer of WAL files to cloud storage, bypassing the +Barman server. Additionally, it can be utilized as a hook script for WAL archiving +(pre_archive_retry_script). + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that will have the WALs archived. + +``DESTINATION_URL`` + URL of the cloud destination, such as a bucket in AWS S3. For example: ``s3://bucket/path/to/folder``. + +``WAL_PATH`` + The value of the '%p' keyword (according to ``archive_command``). + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``-z`` / ``--gzip`` + gzip-compress the WAL while uploading to the cloud (should not be used with python < + 3.2). + +``-j`` / ``--bzip2`` + bzip2-compress the WAL while uploading to the cloud (should not be used with python < + 3.3). + +``--snappy`` + snappy-compress the WAL while uploading to the cloud (requires optional + ``python-snappy`` library). + +``--tags`` + Tags to be added to archived WAL files in cloud storage. + +``--history-tags`` + Tags to be added to archived history files in cloud storage. + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +``-e`` / ``--encryption`` + The encryption algorithm used when storing the uploaded data in S3. + + Allowed options: + + * ``AES256``. + * ``aws:kms``. + +``--sse-kms-key-id`` + The AWS KMS key ID that should be used for encrypting the uploaded data in S3. Can be + specified using the key ID on its own or using the full ARN for the key. Only allowed if + ``-e`` / ``--encryption`` is set to ``aws:kms``. + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. + +``--encryption-scope`` + The name of an encryption scope defined in the Azure Blob Storage service which is to + be used to encrypt the data in Azure. + +``--max-block-size`` + The chunk size to be used when uploading an object via the concurrent chunk method + (default: ``4MB``). + +``--max-concurrency`` + The maximum number of chunks to be uploaded concurrently (default: ``1``). + +``--max-single-put-size`` + Maximum size for which the Azure client will upload an object in a single request + (default: ``64MB``). If this is set lower than the Postgres WAL segment size after + any applied compression then the concurrent chunk upload method for WAL archiving will + be used. + +**Extra options for GCP cloud provider** + +``--kms-key-name`` + The name of the GCP KMS key which should be used for encrypting the uploaded data in + GCS. diff --git a/docs/user_guide/commands/barman_cloud/wal_restore.inc.rst b/docs/user_guide/commands/barman_cloud/wal_restore.inc.rst new file mode 100644 index 000000000..3fa69fa1c --- /dev/null +++ b/docs/user_guide/commands/barman_cloud/wal_restore.inc.rst @@ -0,0 +1,113 @@ +.. _barman-cloud-barman-cloud-wal-restore: + +``barman-cloud-wal-restore`` +"""""""""""""""""""""""""""" + +**Synopsis** + +.. code-block:: text + + barman-cloud-wal-restore + [ { -V | --version } ] + [ --help ] + [ { -v | --verbose } ] + [ { -q | --quiet } ] + [ { -t | --test } ] + [ --cloud-provider { aws-s3 | azure-blob-storage | google-cloud-storage } ] + [ --endpoint-url ENDPOINT_URL ] + [ { -P | --aws-profile } AWS_PROFILE ] + [ --read-timeout READ_TIMEOUT ] + [ --azure-credential { azure-cli | managed-identity } ] + [ --no-partial ] + DESTINATION_URL SERVER_NAME WAL_NAME WAL_DEST + +**Description** + +The ``barman-cloud-wal-restore`` script functions as the ``restore_command`` for +retrieving WAL files from cloud storage and placing them directly into a Postgres +standby server, bypassing the Barman server. + +This script is used to download WAL files that were previously archived with the +``barman-cloud-wal-archive`` command. Disable automatic download of ``.partial`` files by +calling ``--no-partial`` option. + +.. important:: + On the target Postgres node, when ``pg_wal`` and the spool directory are on the + same filesystem, files are moved via renaming, which is faster than copying and + deleting. This speeds up serving WAL files significantly. If the directories are on + different filesystems, the process still involves copying and deleting, so there's + no performance gain in that case. + +.. note:: + For GCP, only authentication with ``GOOGLE_APPLICATION_CREDENTIALS`` env is supported. + +**Parameters** + +``SERVER_NAME`` + Name of the server that will have WALs restored. + +``DESTINATION_URL`` + URL of the cloud destination, such as a bucket in AWS S3. For example: ``s3://bucket/path/to/folder``. + +``WAL_NAME`` + The value of the '%f' keyword (according to ``restore_command``). + +``WAL_DEST`` + The value of the '%p' keyword (according to ``restore_command``). + +``-V`` / ``--version`` + Show version and exit. + +``--help`` + show this help message and exit. + +``-v`` / ``--verbose`` + Increase output verbosity (e.g., ``-vv`` is more than ``-v``). + +``-q`` / ``--quiet`` + Decrease output verbosity (e.g., ``-qq`` is less than ``-q``). + +``-t`` / ``--test`` + Test cloud connectivity and exit. + +``--cloud-provider`` + The cloud provider to use as a storage backend. + + Allowed options are: + + * ``aws-s3``. + * ``azure-blob-storage``. + * ``google-cloud-storage``. + +``--no-partial`` + Do not download partial WAL files + +**Extra options for the AWS cloud provider** + +``--endpoint-url`` + Override default S3 endpoint URL with the given one. + +``-P`` / ``--aws-profile`` + Profile name (e.g. ``INI`` section in AWS credentials file). + +``--profile`` (deprecated) + Profile name (e.g. ``INI`` section in AWS credentials file) - replaced by + ``--aws-profile``. + +``--read-timeout`` + The time in seconds until a timeout is raised when waiting to read from a connection + (defaults to ``60`` seconds). + +**Extra options for the Azure cloud provider** + +``--azure-credential / --credential`` + Optionally specify the type of credential to use when authenticating with Azure. If + omitted then Azure Blob Storage credentials will be obtained from the environment and + the default Azure authentication flow will be used for authenticating with all other + Azure services. If no credentials can be found in the environment then the default + Azure authentication flow will also be used for Azure Blob Storage. + + Allowed options are: + + * ``azure-cli``. + * ``managed-identity``. diff --git a/docs/user_guide/concepts.rst b/docs/user_guide/concepts.rst new file mode 100644 index 000000000..70cf4aea8 --- /dev/null +++ b/docs/user_guide/concepts.rst @@ -0,0 +1,557 @@ +.. _concepts: + +Concepts +======== + +Creating a disaster recovery plan can be challenging, especially for those unfamiliar +with the various concepts involved in backup management. There are many different +methods for taking backups, each with its own advantages, disadvantages, and technical +requirements. The choice of the right approach will depend on your resources, +environment and technical knowledge. Knowing that not everyone might be well-grounded +in this context, this section is dedicated to explaining the most fundamental concepts +regarding database backups, particularly in the context of Postgres and Barman. + +If you are already familiar with the concepts of backups, logical and physical backups +in Postgres, feel free to skip to the :ref:`Barman concepts and terminology ` +section. + +.. _concepts-introduction: + +Introduction +------------ + +In a perfect world, backups wouldn't be necessary. However, it is important, +especially in critical business environments, to be prepared for when the unexpected +happens. In a database scenario, the "unexpected" could take any of the following +forms: + +* Data corruption. +* System failure (including hardware failure). +* Human error. +* Natural disaster. + +In such cases, any :term:`ICT` manager or :term:`DBA` should be able to fix the +incident and recover the database in the shortest time possible. We normally refer to +this discipline as disaster recovery, and more broadly as business continuity. + +Within business continuity, it is important to familiarize yourself with two +fundamental metrics, as defined by Wikipedia: + +* Recovery Point Objective (RPO): the maximum targeted period in which data might be + lost from an IT service due to a major incident. +* Recovery Time Objective (RTO): the targeted duration of time and a service level + within which a business process must be restored after a disaster (or disruption) in + order to avoid unacceptable consequences associated with a breakage in business + continuity. + +In a few words, RPO represents the maximum amount of data you can afford to lose, while +RTO represents the maximum down-time you can afford for your service. + +Understandably, we all want RPO=0 (zero data loss) and RTO=0 (zero down-time, utopia), +even if it is our grandmother's recipe website. In reality, a careful cost analysis +phase is required to determine your business continuity requirements. + +Fortunately, with an open source stack composed of Barman and Postgres, you can achieve +RPO=0 thanks to synchronous streaming replication. RTO is more the focus of a High +Availability solution, like ``Patroni`` or ``repmgr``. Therefore, by integrating Barman +with any of these tools, you can dramatically reduce RTO to nearly zero. + +In any case, it is important for us to emphasize more on cultural aspects related to +disaster recovery, rather than the actual tools. Tools without human beings are +useless. Our mission with Barman is to promote a culture of disaster recovery that: + +* Focuses on backup procedures. +* Focuses even more on recovery procedures. +* Relies on education and training on strong theoretical and practical concepts of + Postgres crash recovery, backup, Point-In-Time-Recovery, and replication for your + team members. +* Promotes testing your backups (only a backup that is tested can be considered to be + valid), either manually or automatically (be creative with Barman's hook scripts!). +* Fosters regular practice of recovery procedures, by all members of your devops team + (yes, developers too, not just system administrators and :term:`DBAs `). +* Solicits regularly scheduled drills and disaster recovery simulations with the + team every 3-6 months. +* Relies on continuous monitoring of Postgres and Barman, and that is able to promptly + identify any anomalies. + +Moreover, do everything you can to prepare yourself and your team for when the disaster +happens, because when it happens: + +* It is going to be a Friday evening, most likely right when you are about to leave the + office. +* It is going to be when you are on holiday (right in the middle of your cruise around + the world) and somebody else has to deal with it. +* It is certainly going to be stressful. +* You will regret not being sure that the last available backup is valid. +* Unless you know how long it approximately takes to recover, every second will seem + like forever. + +In 2011, with these goals in mind, 2ndQuadrant started the development of Barman, now +one of the most used backup tools for Postgres. Barman is an acronym for "Backup and +Recovery Manager". + +Be prepared, don't be scared. + + +.. _concepts-general-backup-concepts: + +General backup concepts +----------------------- + +While each database system may have its own terminology, there are fundamental backup +principles that are consistent across all relational databases. This section provides +an overview of the core concepts necessary to understand how backups work. + + +.. _concepts-general-backup-concepts-physical-and-logical-backups: + +Physical and logical backups +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the context of relational databases, a logical backup is nothing more than a series +of operations that, when executed, recreate your data in the exact state as when the +backup was taken. To put it simple, it is a sequence of SQL statements to reconstruct +the database structure and data. This method is not dependent on specific environment +specifications such as database version or system architecture, making it a suitable +choice for migrating data across incompatible systems. It also offers more flexibility +by allowing the restoration of specific database objects or tables. + +However, logical backups can be time-consuming, potentially taking several hours or +days, depending on the size of the database. Also, because the backup reflects the +database's state at the start of the backup process, any changes made during the backup +are not captured, introducing potential windows for data loss. As a result, this method +is typically recommended for smaller and less complex databases. In Postgres, logical +backups are implemented via the ``pg_dump`` and ``pg_dumpall`` utilities. + +A physical backup, on the other hand, works by copying the database files directly from +the file system. Therefore, this method is usually tied to environment specifications. +There are different approaches to taking physical backups, ranging from using basic +Unix tools like ``cp`` to more sophisticated solutions such as using backup managers, +like Barman. Backup management tools can play a vital role in physical backups, as +ensuring the files represent a consistent state of the database, while also keeping the +server running normally, can be challenging if done manually. + +Physical backups can be much faster than logical backups, not only during the backup +process but especially during recovery, since they do not require a complete replay of +operations in order to recreate the database. It also enables the possibility of +incremental backups, which significantlly reduces time and storage usage, allowing for +more frequent backups. Finally, one of the greatest advantages of this approach is the +ability to perform point-in-time recovery (PITR), which allows you to restore your +database to any specific point in time between the current time and the time of the +backup. This feature is only possible when transaction logs are archived alongside your +physical backups. + +As noticed, physical backups are more robust but also more complex. For this reason, +auxiliary backup management tools, like Barman for Postgres, play an important role in +ensuring this process is handled effectively and reliably in your disaster recovery +plan. + + +.. _concepts-general-backup-concepts-backup-types: + +Backup types +^^^^^^^^^^^^ + +Regarding physical backups, they can essentially be divided into three different types: +full, incremental and differential. + +A full backup, often also called base backup, captures all your data at a specific +point in time, essentially creating a complete snapshot of your entire database. This +type of backup contains every piece of information needed to restore the system to its +exact state as when the backup was taken. In this sense, a recovery from a consistent +full physical backup is the fastest possible, as it is inherently complete by nature. + +Incremental backups, on the other hand, are designed to capture only the changes that +have occurred since a previous backup. A previous backup could be either a full backup +or another incremental backup. Incremental backups significantly reduce the time and +storage usage, allowing for more frequent backups, consequently reducing the risks of +data loss. Generally, Incremental backups are only possible with physical backups as +they rely on low-level data structures, such as files and internal data blocks, to +determine what has actually changed. A recovery from an incremental backup requires a +chain of all backups, from the base to the most recent incremental. + +Lastly, differential backups are similar to incremental backups in that they capture +only the changes made since a previous backup. However, the key difference is that a +differential backup always records changes relative to a full backup, never being +relative to an incremental or another differential backup. In fact, every differential +backup is an incremental backup, but not every incremental backup is a differential +backup. A recovery in this case only requires the most recent differential backup and +its related base backup. + + +.. _concepts-general-backup-concepts-transaction-logs: + +Transaction logs +^^^^^^^^^^^^^^^^ + +Transaction logs are a fundamental piece of most relational databases. It consists of a +series of contiguous files that record every operation in the database before they are +executed. As a result, they possess every change that happened in the database during a +period of time. It primarily ensures that databases can effectively recover from +crashes by being able to replay any operations that were not yet flushed to disk before +the crash, thus preventing data loss. It is also a key component of many +implementations of database replication. + +Transaction logs are recycled after all its operations are persisted. However, if we +are able to archive these logs in advance, we essentially retain a complete record of +all changes made to the database that can be replayed at any time. Having a base backup +along with transaction logs archival enables for continuous backups. This is +particularly valuable for large databases where it is not possible to take full backups +regularly. You might notice that it achieves a similar goal as differential backups, +but with even more capabilities as it also enables more robust features such as +point-in-time recovery. + + +.. _concepts-general-backup-concepts-point-in-time-recovery: + +Point-time Recovery +^^^^^^^^^^^^^^^^^^^ + +Point-in-time recovery enables you to restore your database to any specific moment +from the end-time of a base backup to the furthest point covered by your archived +transaction logs. By maintaining a continuous archive of transaction logs, you have the +ability to replay every change made to the database up to the present moment. This is +done by replaying all transaction logs on top of a base backup, also providing you with +the ability to stop the replay at any point you want based on a desired timestamp or +transaction ID, for example. PITR allows for a precision of less than seconds, a huge +advantage over standard full backups, which are usually executed daily. + +This feature is especially valuable in situations where human error or unintended +changes occur, such as accidental deletions or modifications. By restoring the database +to the exact state it was just before the unwanted event, PITR significantly reduces +RPO. It provides a powerful safeguard, ensuring that critical data can be quickly and +accurately recovered without reverting the database to an earlier full backup and risk +losing all subsequent legitimate changes. + +It does not mean, however, that PITR is the solution to all problems. Replaying +transaction logs can still take a long time depending on how far they go from the base +backup. Therefore, the optimal solution is actually a combination of all strategies: +full backups with frequent incremental backups along with transaction log archiving. +This way, restoring to the most recent state is a matter of restoring the most recent +backup followed by a replay of subsequent transaction logs. Similarly, restoring to a +specific point in time is a matter of restoring the previous backup closest to the +target point followed by a replay of subsequent transaction logs up to the desired +target. + + +.. _concepts-postgres-backup-concepts: + +Postgres backup concepts and terminology +---------------------------------------- + +This section explores backup concepts in the context of Postgres, its implementations +and specific characteristics. The content is mainly based on the `Backup and Restore +section from the Postgres official documentation `_, +so we strongly recommend you read that if you want more detailed explanations on how +Postgres handles backups. + + +.. _concepts-postgres-backup-concepts-pgdump-vs-pgbasebackup: + +pg_dump vs pg_basebackup +^^^^^^^^^^^^^^^^^^^^^^^^ + +There are essentially two main tools for taking backups in Postgres: ``pg_dump`` and +``pg_basebackup``. The difference between them is essentially the difference between +logical and physical backups. Namely, ``pg_dump`` (``pg_dumpall`` included) takes +logical backups while ``pg_basebackup`` takes physical backups. + +.. note:: + + Barman does not make use of ``pg_dump`` or ``pg_dumpall`` in any way as it does not + operate with logical backups. ``pg_basebackup`` is used by Barman depending on the + backup method configured. + +``pg_basebackup`` essentially copies all files from your Postgres cluster to a +destination directory, including tablespaces, if any, using the `streaming replication +protocol `_. +It can only backup the entire cluster, not being able to backup specific databases or +objects. ``pg_basebackup`` is responsible for putting your database server in and out +of backup mode as well as making sure all required transaction logs for consistency are +stored along with the base backup. For that reason, unlike ``pg_dump``, a backup taken +with ``pg_basebackup`` also includes changes that happened while the backup was in +progress, which is a huge advantage for databases under frequent heavy load. You can +read more about ``pg_basebackup`` in its `dedicated section in the official +documentation `_. + +.. note:: + + In reality, a physical backup in Postgres is only complete/self-contained if it + also has at least the transaction logs (WALs in Postgres) that were generated + during the backup process. Otherwise the backup itself is insufficient to restore + and start a new Postgres instance. + +It is also possible to accomplish a similar result as ``pg_basebackup`` using the +`Postgres low-level backup API `_, +which is yet another way of taking physical backups in Postgres. The low-level API is +used in cases where you want to take physical backups manually using alternative +copying tools. In this scenario, you are responsible for putting the database server +in and out of backup mode manually as well as making sure all transaction logs required +for consistency are archived correctly. + +.. note:: + + Barman uses the Postgres low-level API depending on the backup method configured + e.g. ``backup_method = rsync``. + + +.. _concepts-postgres-backup-concepts-wals: + +Write-ahead logs +^^^^^^^^^^^^^^^^ + +Write-ahead logs (WAL) is how Postgres (and other databases) refer to transaction logs. +In Postgres, each WAL file supports 16 MB worth of changes (configurable). WAL files +are written sequentially, one after another, and are maintained simultaneously until a +checkpoint is performed. A checkpoint in Postgres is the act of persisting all changes +to disk so that WALs can be recycled afterwards. A checkpoint usually happens every +five minutes or after 1 GB of WAL files are generated, both options are configurable. +WAL not only helps with crash recovery, database replication and PITR, but it's also an +important component to ensure good performance, as otherwise changes would need to be +synced to disk after each transaction commit, resulting in huge I/Os. With WAL, changes +can be postponed to a checkpoint-time since it is sufficient to ensure database +consistency. + + +.. _concepts-postgres-backup-concepts-wal-archiving-and-wal-streaming: + +WAL archiving and WAL streaming +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Transaction log archiving is known as "continuous archiving" or "WAL archiving" in +Postgres. WAL archiving essentially means being able to store WAL files somewhere else +before they are recycled. In Postgres, the traditional way of doing that is via the +``archive_command`` parameter in the server configuration. + +The ``archive_command`` accepts any shell command as a value, which will be executed +for each WAL file once completely filled. Such a command is responsible for making sure +each file is copied safely to the desired destination. This provides a lot of +flexibility in the sense that Postgres does not make any assumptions on how or where +you want to store these files, thus allowing you to use any command or library you want. +This command must return a zero exit status, indicating success, otherwise Postgres +understands that the archiving has failed and will not recycle those files until they +can be successfully archived. While this is helpful for ensuring safety it can also +become a nightmare if your command starts failing for some reason as WAL files will +continue to pile up until it works again or you run out of disk space. +You can read more about `WAL archiving in the official documentation +`_. + +An alternative way of archiving WALs is by using ``pg_receivewal``, a native Postgres +utility used to transfer WAL files to a desired location using the streaming +replication protocol. A huge advantage of this method, commonly known as WAL streaming, +compared to the traditional ``archive_command`` method is that files are transferred in +real time, meaning that it doesn't need to wait for a WAL segment to be completely +filled in order to start transferring it, significantly reducing the chances of data +loss. + +Unlike the ``archive_command``, by default this method alone does not ensure that WAL +files are archived successfully before being recycled. This means that WAL files can be +recycled before being archived, essentially having its logs lost forever. For this +reason, the use of replication slots is extremely recommended in this scenario. +Replication slots are primarily used in the context of database replication to ensure +that the primary server will retain WAL files needed by its following replicas until +they are successfully received, providing an extra safety in case a replica goes +offline or gets disconnected. It achieves the same goal when used with +``pg_receivewal`` i.e. making sure WAL files are not recycled until successfully +transferred to the receiver. + +.. _concepts-postgres-backup-concepts-recovery: + +Recovery +^^^^^^^^ + +The recovery process in Postgres depends on the backup type. With logical backups, this +process is as simple as running ``pg_restore`` or simply executing all SQL commands +from the backup file, depending on the backup file format. With physical backups, +however, the process is a bit more complex. + +To successfully recover from a physical backup, you need both the cluster files and its +WAL archive. It is necessary to have at least the WAL files that were generated during +the backup process. If the backup was taken with ``pg_basebackup``, the required WAL +files will already be included in the output directory, unless specified otherwise. If +taken manually, however, using the Postgres low-level API, it is your responsibility to +make sure all required WAL files are available during recovery. + +To prepare for recovery, you need to follow a few steps. This includes specifying +a few parameters in the configuration file of the backup cluster directory, such as a +command to get the WAL files from the WAL archive as well as a target point, in case +performing :term:`PITR`, among others. For a detailed explanation of this process, +refer to the `Postgres official documentation `_. +If everything is correct, you should then be able to start a new instance from the +backup and Postgres will make sure all required WALs are applied. + +If the recovery involves Postgres incremental backups, you will then need to first +combine all the backups using ``pg_combinebackup``. It will generate a synthetic full +backup, which can be used for recovery in the same way as a standard full backup. + +.. _concepts-barman-concepts-and-terminology: + +Barman concepts and terminology +------------------------------- + +This section offers an overview of important Barman concepts as well as demonstrates +how Barman utilizes some of the concepts explained in earlier sections. + + +.. _concepts-barman-concepts-server: + +Server +^^^^^^ + +Barman can manage backups of multiple database servers simultaneously. For this reason, +a logical separation of your backup servers becomes necessary. In Barman, a backup +server, or simply server, represents the backup context of a specific database server. +It defines how Barman interacts with the database instance, how its backups are +managed, their retention policies, etc. Each server has its own dedicated directory +where all backups and WAL files are stored as well as a unique name which must be +supplied in most Barman commands to specify in which context it should run. + + +.. _concepts-barman-concepts-backup-methods: + +Backup methods +^^^^^^^^^^^^^^ + +As outlined in +:ref:`Postgres backup concepts and terminology `, +there are multiple ways to back up a Postgres server. In the context of Barman, these +are referred to as backup methods. Barman supports various backup methods, each relying +on different Postgres features, with its own set of requirements, advantages, and +disadvantages. The desired backup method can be specified using the ``backup_method`` +parameter in the server's configuration file. + + +.. _concepts-barman-concepts-rsync-backups: + +Rsync backups +^^^^^^^^^^^^^ + +Backups taken with ``backup_method = rsync``. When using this backup method, Barman +uses the Postgres low-level API and Rsync to manually transfer cluster files +over an SSH connection. Rsync is a powerful copying tool which allows you to +synchronize files and directories between two locations, either on the same host or on +different hosts over a network. Barman utilizes the low-level API to put the server in +and out of backup mode while using Rsync to copy all relevant files to the server's +designated directory on Barman. At the end of this process, Barman forces a WAL switch +on the database server to ensure that all required WAL files are archived. Finally, +integrity checks are performed to verify that the backup is consistent. + + +.. _concepts-barman-concepts-streaming-backups: + +Streaming Backups +^^^^^^^^^^^^^^^^^ + +Backups taken with ``backup_method = postgres``. When using this backup method, Barman +invokes ``pg_basebackup`` in order to back up your database server. Barman will map all +your tablespaces to the server's dedicated directory on Barman. At the end of this +process, Barman forces a WAL switch on the database server to ensure that all required +WAL files are archived. Finally, integrity checks are performed to verify that the +backup is consistent. + + +.. _concepts-barman-concepts-snapshot-backups: + +Snapshot Backups +^^^^^^^^^^^^^^^^ + +Snapshot backups can be performed either by setting ``backup_method = snapshot`` or by +directly using the Barman's cloud CLI tools. These backups work by integrating Barman +with a cloud provider where your database server resides. A snapshot of the database's +storage volume is then taken as a physical backup. In this setup, Barman manages your +backups in the cloud, acting primarily as a storage server for WAL files and the +backups catalog. + + +.. _concepts-barman-concepts-file-level-incremental-backups: + +File-level incremental backups +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +File-level incremental backups are possible when using +:ref:`rsync ` backups. It uses Rsync native features of +deduplication, which relies on filesystem hard-links. When performing a file-level +incremental backup, Barman first creates hard-links to the latest server backup +available, essentially replicating its content in a different directory without +consuming extra disk space. Rsync is then used to synchronize its contents with the +the contents of the Postgres cluster, copying only the files that have changed. +You can also have file-level incremental backups without using hard-links, in which +case Barman will first copy the contents of the previous backup to the new backup +directory, essentially duplicating it and consuming extra disk space, but still copying +only changed files from the database server. + + +.. _concepts-barman-concepts-block-level-incremental-backups: + +Block-level incremental backups +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Block-level incremental backups are possible when using +:ref:`streaming backups `. It leverages the native +``pg_basebackup`` capabilities for incremental backups, introduced in Postgres 17. This +features requires a Postgres instance with version 17 or newer that is properly +configured for native incremental backups. With block-level incremental backups, any +backup with a valid ``backup_manifest`` file can be used as a reference for +deduplication. Block-level incremental backups are more efficient than file-level +incremental backups as deduplication happens at the block level (pages in Postgres). + + +.. _concepts-barman-concepts-wal-archiving: + +WAL archiving via ``archive_command`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is one of the two ways of transferring WAL files to Barman. Commonly used along +with :ref:`rsync ` backups, this approach +involves configuring the ``archive_command`` parameter in Postgres to archive WAL files +directly to the server's dedicated directory on Barman. The command can be either an +Rsync command, where you manually specify the server's WAL directory on the Barman +host, or the ``barman-wal-archive`` utility, which only requires the server name, with +Barman handling the rest. Additionally, ``barman-wal-archive`` provides added safety by +ensuring files are fsynced as soon as they are received. + + +.. _concepts-barman-concepts-wal-streaming: + +WAL streaming +^^^^^^^^^^^^^ + +This is one of the two ways of transferring WAL files to Barman. Commonly used along +with :ref:`streaming backups `, this +approach relies on the ``pg_receivewal`` utility to transfer WAL files. It is much +simpler to configure, as no manual configuration is required on the database server. +As mentioned in :ref:`WAL archiving and WAL streaming `, +replication slots are recommended when using WAL streaming. You can create a slot +manually beforehand or let Barman create them for you by setting ``create_slot`` to +``auto`` in your backup server configurations. + +.. _concepts-barman-concepts-hook-scripts: + +Hook Scripts +^^^^^^^^^^^^ + +Barman enables developers to execute hook scripts along specific operations as +pre- and/or post-operations. This feature provides developers with the flexibility to +implement tailored and diverse behaviors. You can utilize a post-backup script to +generate a manifest for the backup when using rsync or you can create a hybrid +distributed architecture that allows you to copy backups to cloud storage as well by +combining post-backup :ref:`hook scripts with barman-cloud ` +commands. + +For a more in-depth exploration of this topic, please refer to the main section on +:ref:`hook scripts `. + +.. _concepts-barman-concepts-restore-and-recover: + +Restore and recover +^^^^^^^^^^^^^^^^^^^ + +In Barman, recovery is the process of restoring a backup along with all necessary WAL +files in a new location, effectively preparing a Postgres instance for recovery. + +As outlined in :ref:`concepts-postgres-backup-concepts-recovery`, the recovery process +in Postgres consists of several steps, from preparing the base directory to starting the +server itself. Barman is able to perform all the steps required to prepare your backup +to be recovered, a process known as "restore" in Barman's terminology. In this case, +completing the recovery is usually just a matter of starting the server so that +Postgres can apply the required WALs and go live. diff --git a/docs/user_guide/configuration.rst b/docs/user_guide/configuration.rst new file mode 100644 index 000000000..5749c0755 --- /dev/null +++ b/docs/user_guide/configuration.rst @@ -0,0 +1,1378 @@ +.. _configuration: + +Configuration Reference +======================= + +Barman follows a convention over configuration approach, which simplifies configuration +by allowing some options to be defined globally and overridden at the server level. This +means you can set a default behavior for your servers and then customize specific servers +as needed. This design reduces the need for excessive configuration while maintaining +flexibility. + +.. _configuration-usage: + +Usage +----- + +Proper configuration is critical for its effective operation. Barman uses different types +of configuration files to manage global settings, server-specific settings, and +model-specific settings that is made up of three scopes: + +1. **Global Configuration**: It comprises one file with a set of configurations for the +barman system, such as the main directory, system user, log file, and other general +options. Default location is ``/etc/barman.conf`` and it can be overridden on a per-user +level by ``~/.barman.conf`` or by specifying a ``.conf`` file using the ``-c`` / +``--config`` with the :ref:`barman command ` directly in the CLI. + +2. **Server Configuration**: It comprises one or more files with a set of +configurations for a Postgres server that you want to keep track and interact for +backup, recovery and/or replication. Default location is ``/etc/barman.d`` and must use +the ``.conf`` suffix. You may have one or multiple files for servers. You can override the +default location by setting the ``configuration_files_directory`` option in the global +configuration file and placing the files in that particular location. + +3. **Model Configuration**: It comprises one or more files with a set of +configurations overrides that can be applied to Barman servers within the same cluster as +the model. These overrides can be implemented using the barman ``config-switch`` command. +Default location is ``/etc/barman.d`` and must use the ``.conf`` suffix. The same +``configuration_files_directory`` override option from the server configuration applies for +models. You may have one or multiple files for models. + +.. note:: + Historically, you could have a single configuration file containing global, server, and + model options, but, for maintenance reasons, this approach is deprecated. + +Configuration files follow the ``INI`` format and consist of sections denoted by headers +in square brackets. Each section can include various options. + +Models and servers must have unique identifiers, and reserved words cannot be used as +names. + +**Reserved Words** + +The following reserved words cannot be used as server or model names: + +* ``barman``: Identifies the global section. +* ``all``: A special shortcut for executing commands on all managed servers. + +**Parameter Types** + +Configuration options can be of the following types: + +* **String**: Textual data (e.g., file paths, names). +* **Enum**: Enumerated values, often limited to predefined choices. +* **Integer**: Numeric values. +* **Boolean**: Can be ``on``, ``true``, ``1`` (true) or ``off``, ``false``, ``0`` + (false). + + .. note:: + Some enums allow ``off``, but not ``false``. + +.. _configuration-options: + +Options +------- + +Options in the configuration files can have specific or shared scopes. The following +configuration options are used not only for configuring how Barman will execute backups +and recoveries, but also for configuring various aspects of how Barman interacts with the +configured Postgres servers to be able to apply your Backup and Recovery, and +High-Availability strategies. + +.. _configuration-options-general: + +General +""""""" + +These are general configurations options. + +**active** + +When this option is set to ``true`` (default), the server operates fully. If set to +``false``, the server is restricted to diagnostic use only, meaning that operational +commands such as backup execution or WAL archiving are temporarily disabled. When +incorporating a new server into Barman, we recommend initially setting +``active = false``. Verify that barman check shows no issues before activating the +server. This approach helps prevent excessive error logging in Barman during the +initial setup. + +Scope: Server / Model. + +**archiver** + +This option enables log file shipping through Postgres' ``archive_command`` for a +server. When set to ``true``, Barman expects continuous archiving to be configured and +will manage WAL files that Postgres stores in the incoming directory +(``incoming_wals_directory``), including their checks, handling, and compression. When +set to ``false`` (default), continuous archiving is disabled. + +.. note:: + If neither ``archiver`` nor ``streaming_archiver`` is configured, Barman will + automatically set this option to ``true`` to maintain compatibility with the + previous default behavior where archiving was enabled by default. + +Scope: Global / Server / Model. + +**archiver_batch_size** + +This option enables batch processing of WAL files for the archiver process by setting +it to a value greater than ``0``. If not set, the archiver will use unlimited +(default) processing mode for the WAL queue. With batch processing enabled, the +archiver process will handle a maximum of ``archiver_batch_size`` WAL segments per +run. This value must be an integer. + +Scope: Global / Server / Model. + +**bandwidth_limit** + +Specifies the maximum transfer rate in kilobytes per second for backup and recovery +operations. A value of ``0`` indicates no limit (default). + +.. note:: + Applies only when ``backup_method = postgres | rsync``. + +Scope: Global / Server / Model. + +**barman_home** + +Designates the main data directory for Barman. Defaults to ``/var/lib/barman``. + +Scope: Global. + +**barman_lock_directory** + +Specifies the directory for lock files. The default is ``barman_home``. + +.. note:: + The ``barman_lock_directory`` should be on a non-network local filesystem. + +Scope: Global. + +**basebackup_retry_sleep** + +Sets the number of seconds to wait after a failed base backup copy before retrying. +Default is ``30`` seconds. Must be a non-negative integer. + +.. note:: + This applies to both backup and recovery operations. + +Scope: Global / Server / Model. + +**basebackup_retry_times** + +Defines the number of retry attempts for a base backup copy after an error occurs. +Default is ``0`` (no retries). Must be a non-negative integer. + +.. note:: + This applies to both backup and recovery operations. + +Scope: Global / Server / Model. + +**check_timeout** + +Sets the maximum execution time in seconds for a Barman check command per server. Set +to ``0`` to disable the timeout. Default is ``30`` seconds. Must be a non-negative +integer. + +Scope: Global / Server / Model. + +**cluster** + +Tag the server or model to an associated cluster name. Barman uses this association to +override configuration for all servers/models in this cluster. If omitted for servers, +it defaults to the server's name. + +.. note:: + Must be specified for configuration models to group applicable servers. + +Scope: Server / Model. + +**config_changes_queue** + +Designates the filesystem location for Barman's queue that handles configuration changes +requested via the barman ``config-update`` command. This queue manages the +serialization and retry of configuration change requests. By default, Barman writes to +a file named ``cfg_changes.queue`` under ``barman_home``. + +Scope: Global. + +**configuration_files_directory** + +Designates the directory where server/model configuration files will be read by Barman. +Defaults to ``/etc/barman.d/``. + +Scope: Global. + +**conninfo** + +Specifies the connection string used by Barman to connect to the Postgres server. +This is a libpq connection string. Commonly used keys include: ``host``, ``hostaddr``, +``port``, ``dbname``, ``user`` and ``password``. See the +`PostgreSQL documentation `_ +for details. + +Scope: Server / Model. + +**create_slot** + +Determines whether Barman should automatically create a replication slot if it's not +already present for streaming WAL files. When set to ``auto`` and ``slot_name`` is +defined, Barman will attempt to create the slot automatically. When set to ``manual`` +(default), the replication slot must be created manually. + +Scope: Global / Server / Model. + +**description** + +Provides a human-readable description of a server. + +Scope: Server / Model. + +**errors_directory** + +The directory where WAL files that were errored while being archived by Barman are +stored. This includes duplicate WAL files (e.g., an archived WAL file that has already +been streamed but have different hash) and unexpected files found in the WAL archive +directory. + +The purpose of placing the files in this directory is so someone can later review why they +failed to be archived and take appropriate actions (dispose of, store somewhere else, +replace the duplicate file archived before, etc.) + +Scope: Server. + +**forward_config_path** + +Determines whether a passive node should forward its configuration file path to its +primary node during ``cron`` or ``sync-info`` commands. Set to ``true`` if Barman is +invoked with the ``-c`` / ``--config`` option and the configuration paths are identical +on both passive and primary Barman servers. Defaults to ``false``. + +Scope: Global / Server / Model. + +**immediate_checkpoint** + +Controls how Postgres handles checkpoints at the start of a backup. Set to ``false`` +(default) to allow the checkpoint to complete according to +``checkpoint_completion_target``. Set to ``true`` for an immediate checkpoint, where +Postgres completes the checkpoint as quickly as possible. + +Scope: Global / Server / Model. + +**keepalive_interval** + +Sets the interval in seconds for sending a heartbeat query to keep the libpq +connection active during an rsync backup. Default is ``60`` seconds. Setting this to +``0`` disables the heartbeat. + +Scope: Global / Server / Model. + +**lock_directory_cleanup** + +Enables automatic cleanup of unused lock files in the ``barman_lock_directory``. + +Scope: Global. + +**log_file** + +Specifies the location of Barman's log file. Defaults to ``/var/log/barman/barman.log``. + +Scope: Global. + +**log_level** + +Sets the level of logging. Options include: ``DEBUG``, ``INFO``, ``WARNING``, +``ERROR`` and ``CRITICAL``. + +Scope: Global. + +**minimum_redundancy** + +Specifies the minimum number of backups to retain. Default is ``0``. + +Scope: Global / Server / Model. + +**model** + +When set to ``true``, turns a server section from a configuration file into a model for +a cluster. There is no ``false`` option in this case. If you want to simulate a +``false`` option, comment out (``#model=true``) or remove the option in the +configuration. Defaults to the server name. + +Scope: Model. + +**network_compression** + +Enables or disables data compression for network transfers. Set to ``false`` (default) +to disable compression, or ``true`` to enable it and reduce network usage. + +Scope: Global / Server / Model. + +.. _configuration-parallel-jobs: + +**parallel_jobs** + +Controls the number of parallel workers used to copy files during backup or recovery. +It must be a positive integer. Default is ``1``. + +.. note:: + Applies only when ``backup_method = rsync``. + +Scope: Global / Server / Model. + +**parallel_jobs_start_batch_period** + +Specifies the time interval in seconds over which a single batch of parallel jobs will +start. Default is ``1`` second. This means that if ``parallel_jobs_start_batch_size`` +is ``10`` and ``parallel_jobs_start_batch_period`` is ``1``, this will yield an +effective rate limit of ``10`` jobs per second, because there is a maximum of ``10`` +jobs that can be started within ``1`` second. + +.. note:: + Applies only when ``backup_method = rsync``. + +Scope: Global / Server / Model. + +**parallel_jobs_start_batch_size** + +Defines the maximum number of parallel jobs to start in a single batch. Default is +``10`` jobs. This means that if ``parallel_jobs_start_batch_size`` +is ``10`` and ``parallel_jobs_start_batch_period`` is ``2``, this will yield a maximum +of ``10`` jobs that can be started within ``2`` seconds. + +.. note:: + Applies only when ``backup_method = rsync``. + +Scope: Global / Server / Model. + +**path_prefix** + +Lists one or more absolute paths, separated by colons, where Barman looks for executable +files. These paths are checked before the ``PATH`` environment variable. This option can +be set for each server and needs to point to the ``bin`` directory for the appropriate +``PG_MAJOR_VERSION``. + +Scope: Global / Server / Model. + +**primary_checkpoint_timeout** + +Time to wait for new WAL files before forcing a checkpoint on the primary server. +Defaults to ``0``. + +Scope: Server / Model. + +**primary_conninfo** + +Connection string for Barman to connect to the primary Postgres server during a +standby backup. + +Scope: Server / Model. + +**primary_ssh_command** + +SSH command for connecting to the primary Barman server if Barman is passive. + +Scope: Global / Server / Model. + +**slot_name** + +Replication slot name for the ``receive-wal`` command when ``streaming_archiver`` is +enabled. + +Scope: Global / Server / Model. + +**ssh_command** + +SSH command used by Barman to connect to the Postgres server for rsync backups. + +Scope: Server / Model. + +**streaming_archiver** + +Enables Postgres' streaming protocol for WAL files. Defaults to ``false``. + +.. note:: + If neither ``archiver`` nor ``streaming_archiver`` is configured, Barman will + automatically set ``archiver`` option to ``true`` to maintain compatibility with the + previous default behavior where archiving was enabled by default. + +Scope: Global / Server / Model. + +**streaming_archiver_batch_size** + +Batch size for processing WAL files in streaming archiver. Defaults to ``0``. + +Scope: Global / Server / Model. + +**streaming_archiver_name** + +Application name for the ``receive-wal`` command. Defaults to ``barman_receive_wal``. + +Scope: Global / Server / Model. + +**streaming_backup_name** + +Application name for the ``pg_basebackup`` command. Defaults to +``barman_streaming_backup``. + +Scope: Global / Server / Model. + +**streaming_conninfo** + +Connection string for streaming replication protocol. Defaults to ``conninfo``. + +Scope: Server / Model. + +**tablespace_bandwidth_limit** + +Maximum transfer rate for specific tablespaces for backup and recovery operations. +A value of ``0`` indicates no limit (default). + +.. note:: + Applies only when ``backup_method = rsync``. + +Scope: Global / Server / Model. + +.. _configuration-options-backups: + +Backups +""""""" + +These configurations options are related to how Barman will execute backups. + +**autogenerate_manifest** + +This is a boolean option that allows for the automatic creation of backup manifest +files. The manifest file, which is a JSON document, lists all files included in the +backup. It is generated upon completion of the backup and saved in the backup +directory. The format of the manifest file adheres to the specifications outlined in the +`PostgreSQL documentation `_ +and is compatible with the ``pg_verifybackup`` tool. Default is ``false``. + +.. note:: + This option is ignored if the ``backup_method`` is not ``rsync``. + +Scope: Global / Server / Model. + +**backup_compression** + +Specifies the compression method for the backup process. It can be set to ``gzip``, +``lz4``, ``zstd``, or ``none``. Ensure that the CLI tool for the chosen compression +method is available on both the Barman and Postgres servers. + +.. note:: + Note that ``lz4`` and ``zstd`` require Postgres version 15 or later. Unsetting this + option or using ``none`` results in an uncompressed archive (default). Only + supported when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**backup_compression_format** + +Determines the format ``pg_basebackup`` should use when saving compressed backups. +Options are ``plain`` or ``tar``, with ``tar`` as the default if unset. The ``plain`` +format is available only if Postgres version 15 or later is in use and +``backup_compression_location`` is set to ``server``. + +.. note:: + Only supported when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**backup_compression_level** + +Defines the level of compression for backups as an integer. The permissible values +depend on the compression method specified in ``backup_compression``. + +.. note:: + Only supported when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**backup_compression_location** + +Specifies where compression should occur during the backup: either ``client`` or +``server``. The ``server`` option is available only if Postgres version 15 or later is +being used. + +.. note:: + Only supported when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**backup_compression_workers** + +Sets the number of threads used for compression during the backup process. This is +applicable only when ``backup_compression=zstd``. The default value is 0, which uses +the standard compression behavior. + +.. note:: + Only supported when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**backup_directory** + +Specifies the directory where backup data for a server will be stored. Defaults to +``/``. + +Scope: Server. + +**backup_method** + +Defines the method Barman uses to perform backups. Options include: + +* ``rsync`` (default): Executes backups using the rsync command over SSH (requires + ``ssh_command``). +* ``postgres``: Uses the ``pg_basebackup`` command for backups. +* ``local-rsync``: Assumes Barman runs on the same server and as the same user as + the Postgres database, performing an rsync file system copy. +* ``snapshot``: Utilizes the API of the cloud provider specified in the + ``snapshot_provider`` option to create disk snapshots as defined in + ``snapshot_disks`` and saves only the backup label and metadata to its own + storage. + +Scope: Global / Server / Model. + +**backup_options** + +Controls how Barman interacts with Postgres during backups. This is a comma-separated +list that can include: + +* ``concurrent_backup`` (default): Uses concurrent backup, recommended for + Postgres versions 9.6 and later, and supports backups from standby servers. +* ``exclusive_backup``: Uses the deprecated exclusive backup method. Only for Postgres + versions older than 15. This option will be removed in the future. +* ``external_configuration``: Suppresses warnings about external configuration files + during backup execution. + +.. note:: + ``exclusive_backup`` and ``concurrent_backup`` cannot be used together. + +Scope: Global / Server / Model. + +**basebackups_directory** + +Specifies the directory where base backups are stored. Defaults to +``/base``. + +Scope: Server. + +**reuse_backup** + +Controls incremental backup support when using ``backup_method=rsync`` by reusing the +last available backup. The options are: + +* ``off`` (default): Standard full backup. +* ``copy``: File-level incremental backup, by reusing the last backup for a server and + creating a copy of the unchanged files (just for backup time reduction) +* ``link``: File-level incremental backup, by reusing the last backup for a server and + creating a hard link of the unchanged files (for backup space and time reduction) + +.. note:: + This option will be ignored when ``backup_method=postgres``. + +Scope: Global / Server / Model. + +.. _configuration-options-cloud-backups: + +Cloud Backups +""""""""""""" + +These configuration options are related to how Barman will execute backups in the cloud. + +**aws_await_snapshots_timeout** + +Specifies the duration in seconds to wait for AWS snapshots to be created before a +timeout occurs. The default value is ``3600`` seconds. This must be a positive +integer. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = aws``. + +Scope: Global / Server / Model. + +**aws_profile** + +The name of the AWS profile to use when authenticating with AWS (e.g. ``INI`` section +in AWS credentials file). + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = aws``. + +Scope: Global / Server / Model. + +**aws_region** + +Indicates the AWS region where the EC2 VM and storage volumes, as defined by +``snapshot_instance`` and ``snapshot_disks``, are located. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = aws``. + +Scope: Global / Server / Model. + +**azure_credential** + +Specifies the type of Azure credential to use for authentication, either ``azure-cli`` +or ``managed-identity``. If not provided, the default Azure authentication method will +be used. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = azure``. + +Scope: Global / Server / Model. + +**azure_resource_group** + +Specifies the name of the Azure resource group containing the compute instance and +disks defined by ``snapshot_instance`` and ``snapshot_disks``. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = azure``. + +Scope: Global / Server / Model. + +**azure_subscription_id** + +Identifies the Azure subscription that owns the instance and storage volumes defined by +``snapshot_instance`` and ``snapshot_disks``. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = azure``. + +Scope: Global / Server / Model. + +**gcp_project** + +Specifies the ID of the GCP project that owns the instance and storage volumes defined +by ``snapshot_instance`` and ``snapshot_disks``. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = gcp``. + +Scope: Global / Server / Model. + +**gcp_zone** + +Indicates the availability zone where the compute instance and disks are located for +snapshot backups. + +.. note:: + Only supported when ``backup_method = snapshot`` and ``snapshot_provider = gcp``. + +Scope: Server / Model. + +**snapshot_disks** + +This option is a comma-separated list of disks to include in cloud snapshot backups. + +.. note:: + Required when ``backup_method = snapshot``. + + Ensure that the ``snapshot_disks`` list includes all disks that store Postgres data, + as any data not on these listed disks will not be included in the backup and will be + unavailable during recovery. + +Scope: Server / Model. + +**snapshot_instance** + +The name of the VM or compute instance where the storage volumes are attached. + +.. note:: + Required when ``backup_method = snapshot``. + +Scope: Server / Model. + +**snapshot_provider** + +The name of the cloud provider to use for creating snapshots. Supported value: +``aws``, ``azure`` and ``gcp``. + +.. note:: + Required when ``backup_method = snapshot``. + +Scope: Global / Server / Model. + +.. _configuration-options-hook-scripts: + +Hook Scripts +"""""""""""" + +These configuration options are related to the pre or post execution of hook scripts. + +**post_archive_retry_script** + +Specifies a hook script to run after a WAL file is archived. Barman will retry this +script until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or ``ABORT_STOP`` +(63). In a post-archive scenario, ``ABORT_STOP`` has the same effect as +``ABORT_CONTINUE``. + +Scope: Global / Server. + +**post_archive_script** + +Specifies a hook script to run after a WAL file is archived, following the +``post_archive_retry_script``. + +Scope: Global / Server. + +**post_backup_retry_script** + +Specifies a hook script to run after a base backup. Barman will retry this script until +it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or ``ABORT_STOP`` (63). In a +post-backup scenario, ``ABORT_STOP`` has the same effect as ``ABORT_CONTINUE``. + +Scope: Global / Server. + +**post_backup_script** + +Specifies a hook script to run after a base backup, following the +``post_backup_retry_script``. + +Scope: Global / Server. + +**post_delete_retry_script** + +Specifies a hook script to run after deleting a backup. Barman will retry this script +until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or ``ABORT_STOP`` (63). In +a post-delete scenario, ``ABORT_STOP`` has the same effect as ``ABORT_CONTINUE``. + +Scope: Global / Server. + +**post_delete_script** + +Specifies a hook script to run after deleting a backup, following the +``post_delete_retry_script``. + +Scope: Global / Server. + +**post_recovery_retry_script** + +Specifies a hook script to run after a recovery. Barman will retry this script until it +returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or ``ABORT_STOP`` (63). In a +post-recovery scenario, ``ABORT_STOP`` has the same effect as ``ABORT_CONTINUE``. + +Scope: Global / Server. + +**post_recovery_script** + +Specifies a hook script to run after a recovery, following the +``post_recovery_retry_script``. + +Scope: Global / Server. + +**post_wal_delete_retry_script** + +Specifies a hook script to run after deleting a WAL file. Barman will retry this script +until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or ``ABORT_STOP`` (63). In +a post-WAL-delete scenario, ``ABORT_STOP`` has the same effect as ``ABORT_CONTINUE``. + +Scope: Global / Server. + +**post_wal_delete_script** + +Specifies a hook script to run after deleting a WAL file, following the +``post_wal_delete_retry_script``. + +Scope: Global / Server. + +**pre_archive_retry_script** + +Specifies a hook script that runs before a WAL file is archived during maintenance, +following the ``pre_archive_script``. As a retry hook script, Barman will repeatedly +execute the script until it returns either ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), +or ``ABORT_STOP`` (63). Returning ``ABORT_STOP`` will escalate the failure and halt +the WAL archiving process. + +Scope: Global / Server. + +**pre_archive_script** + +Specifies a hook script launched before a WAL file is archived by maintenance. + +Scope: Global / Server. + +**pre_backup_retry_script** + +Specifies a hook script that runs before a base backup, following the +``pre_backup_script``. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or +``ABORT_STOP`` (63). Returning ``ABORT_STOP`` will escalate the failure and interrupt +the backup process. + +Scope: Global / Server. + +**pre_backup_script** + +Specifies a hook script to run before starting a base backup. + +Scope: Global / Server. + +**pre_delete_retry_script** + +Specifies a retry hook script to run before backup deletion, following the +``pre_delete_script``. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or +``ABORT_STOP`` (63). Returning ``ABORT_STOP`` will escalate the failure and interrupt +the backup deletion. + +Scope: Global / Server. + +**pre_delete_script** + +Specifies a hook script run before deleting a backup. + +Scope: Global / Server. + +**pre_recovery_retry_script** + +Specifies a retry hook script to run before recovery, following the +``pre_recovery_script``. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or +``ABORT_STOP`` (63). Returning ``ABORT_STOP`` will escalate the failure and interrupt +the recover process. + +Scope: Global / Server. + +**pre_recovery_script** + +Specifies a hook script run before starting a recovery. + +Scope: Global / Server. + +**pre_wal_delete_retry_script** + +Specifies a retry hook script for WAL file deletion, executed before +``pre_wal_delete_script``. As a retry hook script, Barman will attempt to execute the +script repeatedly until it returns ``SUCCESS`` (0), ``ABORT_CONTINUE`` (62), or +``ABORT_STOP`` (63). Returning ``ABORT_STOP`` will escalate the failure and interrupt +the WAL file deletion. + +Scope: Global / Server. + +**pre_wal_delete_script** + +Specifies a hook script run before deleting a WAL file. + +Scope: Global / Server. + +.. _configuration-options-wals: + +Write-Ahead Logs (WAL) +"""""""""""""""""""""" + +These configuration options are related to how Barman will manage the Write-Ahead Logs +(WALs) of the PostreSQL servers. + +**compression** + +Specifies the standard compression algorithm for WAL files. Options include: ``lz4``, +``xz``, ``zstd``, ``gzip``, ``pybzip2``, ``pigz``, ``bzip2``, ``pybzip2`` and ``custom``. + +.. note:: + All of these options require the module to be installed in the location where the + compression will occur. + + The ``custom`` option is for custom compression, which requires you to set the + following options as well: + + * ``custom_compression_filter``: a compression filter. + * ``custom_decompression_filter``: a decompression filter + * ``custom_compression_magic``: a hex string to identify a custom compressed wal + file. + +Scope: Global / Server / Model. + +**custom_compression_filter** + +Specifies a custom compression algorithm for WAL files. It must be a ``string`` that +will be used internally to create a bash command and it will prefix to the +following string ``> "$2" < "$1";``. Write to standard output and do not delete input +files. + +.. tip:: + ``custom_compression_filter = "xz -c"`` + + This is the same as running ``xz -c > "$2" < "$1";``. + +Scope: Global / Server / Model. + +**custom_compression_magic** + +Defines a custom magic value to identify the custom compression algorithm used in WAL +files. If this is set, Barman will avoid applying custom compression to WALs that have +already been compressed with the specified algorithm. If not configured, Barman will +apply custom compression to all WAL files, even those pre-compressed. + +.. tip:: + For example, in the ``xz`` compression algorithm, the magic number is used to detect + the format of ``.xz`` files. + + For xz files, the magic number is the following sequence of bytes: + Magic Number: ``FD 37 7A 58 5A 00`` + + In hexadecimal representation, this can be expressed as: + Hex String: ``fd377a585a00`` + + Reference: `xz-file-format `_ + +Scope: Global / Server / Model. + +**custom_decompression_filter** + +Specifies a custom decompression algorithm for compressed WAL files. It must be a +``string`` that will be used internally to create a bash command and it will +prefix to the following string ``> "$2" < "$1";``. It must correspond with the +compression algorithm used. + +.. tip:: + ``custom_compression_filter = "xz -c -d"`` + + This is the same as running ``xz -c -d > "$2" < "$1";``. + +Scope: Global / Server / Model. + +**incoming_wals_directory** + +Specifies the directory where incoming WAL files are archived. Requires ``archiver`` to +be enabled. Defaults to ``/incoming``. + +Scope: Server. + +**last_wal_maximum_age** + +Defines the time frame within which the latest archived WAL file must fall. If the +latest WAL file is older than this period, the barman check command will report an +error. If left empty (default), the age of the WAL files is not checked. Format is the +same as ``last_backup_maximum_age``. + +Scope: Global / Server / Model. + +**max_incoming_wals_queue** + +Defines the maximum number of WAL files allowed in the incoming queue (including both +streaming and archiving pools) before the barman check command returns an error. +Default is ``None`` (disabled). + +Scope: Global / Server / Model. + +**streaming_wals_directory** + +Directory for streaming WAL files. Defaults to ``/streaming``. + +.. note:: + This option is applicable when ``streaming_archiver`` is activated. + +Scope: Server. + +**wal_conninfo** + +The ``wal_conninfo`` connection string is used by Barman for monitoring the status of +the replication slot receiving WALs. If specified, it takes precedence over +``wal_streaming_conninfo`` for these checks. If ``wal_conninfo`` is not set but +``wal_streaming_conninfo`` is, ``wal_conninfo`` will fall back to +``wal_streaming_conninfo``. If neither ``wal_conninfo`` nor ``wal_streaming_conninfo`` +is set, ``wal_conninfo`` will fall back to ``conninfo``. Both connection strings must +access a Postgres instance within the same cluster as defined by ``streaming_conninfo`` +and ``conninfo``. If both ``wal_conninfo`` and ``wal_streaming_conninfo`` are set, only +``wal_conninfo`` needs the appropriate permissions to read settings and check the +replication slot status. However, if only ``wal_streaming_conninfo`` is set, it must +have the necessary permissions to perform these tasks. The required permissions include +roles such as ``pg_monitor``, both ``pg_read_all_settings`` and ``pg_read_all_stats``, +or superuser privileges. + +Scope: Server / Model. + +**wal_streaming_conninfo** + +This connection string is used by Barman to connect to the Postgres server for receiving +WAL segments via streaming replication and checking the replication slot status, if +``wal_conninfo`` is not set. If not specified, Barman defaults to using +``streaming_conninfo`` for these tasks. ``wal_streaming_conninfo`` must connect to a +Postgres instance within the same cluster as defined by ``streaming_conninfo``, and it +must support streaming replication. If both ``wal_streaming_conninfo`` and +``wal_conninfo`` are set, only ``wal_conninfo`` needs the required permissions to read +settings and check the replication slot status. If only ``wal_streaming_conninfo`` is +specified, it must have these permissions. The necessary permissions include roles such +as ``pg_monitor``, both ``pg_read_all_settings`` and ``pg_read_all_stats``, or superuser +privileges. + +Scope: Server / Model. + +**wals_directory** + +Directory containing WAL files. Defaults to ``/wals``. + +Scope: Server. + +.. _configuration-options-restore: + +Restore +""""""" + +These configuration options are related to how Barman manages restoration backups. + +**local_staging_path** + +Specifies the local path for combining block-level incremental backups during recovery. +This location must have sufficient space to temporarily store the new synthetic backup. +Required for recovery from a block-level incremental backup. + +.. note:: + Applies only when ``backup_method = postgres``. + +Scope: Global / Server / Model. + +**recovery_options** + +Options for recovery operations. Currently, only ``get-wal`` is supported. This option +enables the creation of a basic ``restore_command`` in the recovery configuration, +which uses the barman ``get-wal`` command to retrieve WAL files directly from Barman's +WAL archive. This setting accepts a comma-separated list of values and defaults to +empty. + +Scope: Global / Server / Model. + +**recovery_staging_path** + +Specifies the path on the recovery host for staging files from compressed backups. This +location must have sufficient space to temporarily store the compressed backup. + +.. note:: + Applies only for commpressed backups. + +Scope: Global / Server / Model. + +.. _configuration-options-retention-policies: + +Retention Policies +"""""""""""""""""" + +These configuration options are related to how Barman manages retention policies of the +backups. + +**last_backup_maximum_age** + +Defines the time frame within which the latest backup must fall. If the latest backup +is older than this period, the barman check command will report an error. If left +empty (default), the latest backup is always considered valid. The accepted format is +``"n {DAYS|WEEKS|MONTHS}"``, where ``n`` is an integer greater than zero. + +Scope: Global / Server / Model. + +**last_backup_minimum_size** + +Specifies the minimum acceptable size for the latest successful backup. If the latest +backup is smaller than this size, the barman check command will report an error. If +left empty (default), the latest backup is always considered valid. The accepted +format is ``"n {k|Ki|M|Mi|G|Gi|T|Ti}"`` and case-sensitive, where ``n`` is an integer +greater than zero, with an optional SI or IEC suffix. k stands for kilo with k = 1000, +while Ki stands for kilobytes Ki = 1024. The rest of the options have the same +reasoning for greater units of measure. + +Scope: Global / Server / Model. + +**retention_policy** + +Defines how long backups and WAL files should be retained. If this option is left blank, +no retention policies will be applied. Options include redundancy and recovery window +policies. + +.. code-block:: text + + retention_policy = {REDUNDANCY value | RECOVERY WINDOW OF value {DAYS | WEEKS | MONTHS}} + +* ``retention_policy = REDUNDANCY 2`` will keep only 2 backups in the backup catalog + automatically deleting the older one as new backups are created. The number must be + a positive integer. +* ``retention_policy = RECOVERY WINDOW OF 2 DAYS`` will only keep backups needed to + recover to any point in time in the last two days, automatically deleting backups + that are older. The period number must be a positive integer, and the following + options can be applied to it: ``DAYS``, ``WEEKS``, ``MONTHS``. + +Scope: Global / Server / Model. + +**retention_policy_mode** + +Mode for enforcing retention policies. Currently only supports ``auto``. + +Scope: Global / Server / Model. + +**wal_retention_policy** + +Policy for retaining WAL files. Currently only ``main`` is available. + +Scope: Global / Server / Model. + +.. _configuration-configuration-models: + +Configuration Models +-------------------- + +Configuration models provide a systematic approach to manage and apply configuration +overrides for Postgres servers by organizing them under a specific ``cluster`` name. + +Purpose +""""""" + +The primary goal of a configuration model is to simplify the management of configuration +settings for Postgres servers grouped by the same ``cluster``. By using a model, you can +apply a set of common configuration overrides, enhancing operational efficiency. They are +especially beneficial in clustered environments, allowing you to create various +configuration models that can be utilized during failover events. + +Application +""""""""""" + +The configurations defined in a model file can be applied to Postgres servers that share +the same ``cluster`` name specified in the model. Consequently, any server utilizing that +model can inherit these settings, promoting a consistent and adaptable configuration +across all servers. + +Usage +""""" + +Model options can only be defined within a model section, which is identified in the same +way as a server section. It is important to ensure that there are no conflicts between +the identifiers of server sections and model sections. + +To apply a configuration model, execute the +``barman config-switch SERVER_NAME MODEL_NAME``. This command facilitates the application +of the model's overrides to the relevant Barman server associated with the specified +cluster name. + +If you wish to remove the overrides, the deletion of the model configuration file alone +will not have any effect, so you can do so by using the ``--reset`` argument with the +command, as follows: ``barman config-switch SERVER_NAME --reset``. + +.. note:: + The ``config-switch`` command will only succeed if model name exists and is associated + with the same ``cluster`` as the server. Additionally, there can be only one active + model at a time; if you execute the command multiple times with different models, only + the overrides defined in the last model will be applied. + + Not all options can be configured through models. Please review the scope of the + available configurations to determine which settings apply to models. + +Benefits +"""""""" + +* Consistency: Ensures uniform configuration across multiple Barman servers within a + cluster. +* Efficiency: Simplifies configuration management by allowing centralized updates and + overrides. +* Flexibility: Allows the use of multiple model files, providing the ability to define + various sets of overrides as necessary. + +.. _configuration-examples: + +.. only:: html + + Examples + -------- + + Barman global configurations are common between all configured servers. So if you want to + have specific configurations, you should move it to the server scope instead of the barman + global scope. + + Next you can find a few examples of global, servers and models configurations with an + explanation of the fields. + + Global Configuration + """""""""""""""""""" + + .. code-block:: text + :caption: **/etc/barman.conf** + :name: /etc/barman.conf + + [barman] + + barman_home = /var/lib/barman + barman_user = barman + configuration_files_directory = /etc/barman.d + log_file = /var/log/barman/barman.log + log_level = INFO + + **barman** + * Set configuration that will be global. + * Configure locations for ``barman_home``, ``configuration_files_directory``, + ``log_file``, the ``barman_user`` and the ``log_level``. + + Server Configuration - Rsync + """""""""""""""""""""""""""" + + .. code-block:: text + :caption: **/etc/barman.d/pg_server1_rsync.conf** + :name: /etc/barman.d/pg_server1_rsync.conf + + [server1] + + description = "PostgreSQL server 1" + conninfo = host=pg1 user=barman port=5432 dbname=databasename + ssh_command = ssh postgres@pg1 + backup_method = rsync + reuse_backup = link + archiver = on + parallel_jobs = 2 + minimum_redundancy = 2 + retention_policy = REDUNDANCY 4 + + **server1** + * Connect to Postgres from Barman using the ``conninfo``. + * ``ssh_command`` is needed to correctly create an SSH connection from the Barman + server to the Postgres server when using rsync. + * Set the ``backup_method`` as ``rsync`` and ``reuse_backup`` to enable file-level + incremental backups. + * Configure the ``archiver`` option to ship WALs using the ``archive_command`` + configured in the Postgres configuration file ``postgresql.conf``. + * Jobs will use two workers for parallel processing. + * Set the ``minimum_redundancy`` and the ``retention_policy`` for backups created + from this server. + + Server Configuration - pg_basebackup + """""""""""""""""""""""""""""""""""" + + .. code-block:: text + :caption: **/etc/barman.d/pg_server2_streaming.conf** + :name: /etc/barman.d/pg_server2_streaming.conf + + [server2] + + description = "PostgreSQL server 2" + conninfo = host=pg2 user=barman port=5432 dbname=databasename + streaming_conninfo = host=pg2 user=streaming_barman port=5432 dbname=databasename + backup_method = postgres + streaming_archiver = on + slot_name = barman + create_slot = auto + minimum_redundancy = 5 + retention_policy = RECOVERY WINDOW OF 7 DAYS + local_staging_path = /var/lib/barman/staging + cluster = streaming + + **server2** + * Connect to Postgres using the ``conninfo``. This is used for backups (rsync) and + to check the status of replication slots. + * Connect to Postgres using the ``streaming_conninfo``. This is used for backups + (postgres) and to create ``pg_receivewal`` processes to stream WAL segments. + * Set the ``backup_method`` as ``postgres``. + * Configure the ``streaming_archiver`` option to ship WALs using the streaming + replication, the ``slot_name`` that will be created in the Postgres server and + ``create_slot`` as ``auto`` so Barman can automatically attempt to create the + replication slot if not present. + * Set the ``minimum_redundancy`` and the ``retention_policy`` for backups created + from this server. + * Recovery for block-level incremental backups will use the ``local_staging_path`` + as the intermediate location to combine the chain of backups. + * Group this server into the ``streaming`` cluster to be used by models. + + Model Configuration 1 + """"""""""""""""""""" + + .. code-block:: text + :caption: **/etc/barman.d/mdl_streaming_switchover.conf** + :name: /etc/barman.d/mdl_streaming_switchover.conf + + [server2:switch_over_streaming_conn_to_pg3] + + cluster = streaming + model = true + wal_conninfo = host=pg3 user=barman port=5432 dbname=databasename + wal_streaming_conninfo = host=pg3 user=streaming_barman port=5432 dbname=databasename + compression = gzip + backup_compression = gzip + recovery_staging_path = /var/lib/barman/recovery_staging + retention_policy = RECOVERY WINDOW OF 14 DAYS + + **server2:switch_over_wal_streaming_conn_to_pg3** + * Tag this model to a cluster named ``streaming`` to override configurations. + * Configure this as a model (``model = true``). + * ``wal_conninfo`` is set, so this connection will be used specifically for + monitoring WAL streaming status and perform checks. + * ``wal_streaming_conninfo`` is set, Barman will use this instead of + ``streaming_conninfo`` when receiving WAL segments via streaming replication + protocol. If ``wal_conninfo`` was unset, this option would also be used + to monitor and check WAL streaming replication statuses and it should use a user + with proper permissions. + * WAL files will be compressed with ``gzip``. + * All backups will be compressed with ``gzip``. + * Recovery for compressed backups will use the ``recovery_staging_path`` as the + intermediate location to uncompress the backup. + * Set a ``retention_policy`` for backups that are grouped in the ``streaming`` + cluster. + + *In this example we have setup a model that switches the streaming connection to pg3, + enables compression of backups and WAL files and changes the retention_policy.* **This is + a way to stream WALs and backups from different hosts.** + + The final configuration will have the following settings: + + .. code-block:: text + + [server2] + + description = "PostgreSQL server 2" + conninfo = host=pg2 user=barman port=5432 dbname=databasename + streaming_conninfo = host=pg2 user=streaming_barman port=5432 dbname=databasename + backup_method = postgres + streaming_archiver = on + slot_name = barman + create_slot = auto + minimum_redundancy = 5 + retention_policy = RECOVERY WINDOW OF 14 DAYS + local_staging_path = /var/lib/barman/staging + wal_conninfo = host=pg3 user=barman port=5433 dbname=databasename + wal_streaming_conninfo = host=pg3 user=streaming_barman port=5433 dbname=databasename + compression = gzip + backup_compression = gzip + recovery_staging_path = /var/lib/barman/recovery_staging + + Model Configuration 2 + """"""""""""""""""""" + + .. code-block:: text + :caption: **/etc/barman.d/mdl_streaming_failover** + :name: /etc/barman.d/mdl_streaming_failover + + [server2:failover_conn_to_pg3] + + cluster = streaming + model = true + conninfo = host=pg3 user=barman port=5433 dbname=databasename + streaming_conninfo = host=pg3 user=streaming_barman port=5433 dbname=databasename + + **server2:failover_conn_to_pg3** + * Tag this model to a cluster named ``streaming`` to override configurations. + * Configure this as a model (``model = true``). + * ``conninfo`` is set, so it will be used to switch the Postgres connection to + host ``pg3``. + * ``streaming_conninfo`` is set, so it will be used to switch the Postgres streaming + connection to host ``pg3``. + + *In this example we have setup a model that switches the Postgres connection and + streaming connection upon a failover from pg2 to pg3.* + + The final configuration will have the following settings: + + .. code-block:: text + + [server2] + + description = "PostgreSQL server 2" + conninfo = host=pg3 user=barman port=5432 dbname=databasename + streaming_conninfo = host=pg3 user=streaming_barman port=5432 dbname=databasename + backup_method = postgres + streaming_archiver = on + slot_name = barman + create_slot = auto + minimum_redundancy = 5 + retention_policy = RECOVERY WINDOW OF 7 DAYS + local_staging_path = /var/lib/barman/staging + + .. important:: + You will not see any in place changes in the configuration file. The overrides are + applied internally and you can check the current server configuration by using the + command ``barman show-servers SERVER_NAME`` for the complete list of settings, or in + the ``barman diagnose`` output. \ No newline at end of file diff --git a/docs/user_guide/diagnose_and_troubleshooting.rst b/docs/user_guide/diagnose_and_troubleshooting.rst new file mode 100644 index 000000000..a29dfb45d --- /dev/null +++ b/docs/user_guide/diagnose_and_troubleshooting.rst @@ -0,0 +1,111 @@ +.. _diagnose-and-troubleshooting: + +Diagnose and troubleshooting +============================ + +One of the features that tools require is the ability to troubleshoot problems +in an efficient way. Barman provides multiple ways to diagnose and troubleshoot +problems. + +Usually problems arise from errors or warning messages returned by +:ref:`barman check `, but they may come up from other sources as well. + +Barman status +------------- + +You can check the status of a specific Postgres server using the +:ref:`barman status ` command. This command provides a detailed +view of the status of the server, such as the PostgreSQL version, the current data size, +the PostgreSQL data directory, the current WAL, the archive command, the last archived +WAL, the number of available backups, and more: + +.. code:: bash + + $ barman status pg16 + Server pg16: + Description: PostgreSQL 16 Database (via SSH) + Active: True + Disabled: False + PostgreSQL version: 16.4 + Cluster state: in production + Current data size: 31.9 MiB + PostgreSQL Data directory: /var/lib/pgsql/16/data + Current WAL segment: 000000010000003B00000010 + PostgreSQL 'archive_command' setting: barman-wal-archive barman_server pg16 %p + Last archived WAL: 000000010000003B0000000F, at Mon Nov 18 07:54:54 2024 + Failures of WAL archiver: 0 + Passive node: False + Retention policies: not enforced + No. of available backups: 2 + First available backup: 20240911T085206 + Last available backup: 20240911T085736 + Minimum redundancy requirements: satisfied (2/0) + +This is a good tool to collaborate that the server's configuration aligns with the +configuration of the barman server. + +Barman show servers +------------------- + +You can use the :ref:`barman show-servers ` command to +list all the configuration options and values for a specific Postgres server configured +for backups. + +.. code:: bash + + $ barman show-servers pg16 + Server local16: + active: True + archive_command: barman-wal-archive barman-server pg16 %p + archive_mode: on + archive_timeout: 0 + archived_count: 1 + ... + + +Barman replication status +------------------------- + +You can do a quick check of the replication status for a specific Postgres server +by using the :ref:`barman replication-status ` +command. This command provides a detailed view of the status of the replication. + +.. code:: bash + + $ barman replication-status pg16 + Status of streaming clients for server 'pg16': + Current LSN on master: 3B/10000148 + Number of streaming clients: 1 + + 1. Async WAL streamer + Application name: barman_receive_wal + Sync stage : 3/3 Remote write + Communication : Unix domain socket + User name : barman + Current state : streaming (async) + Replication slot: standby + WAL sender PID : 165959 + Started at : 2024-11-18 07:49:01.837787+00:00 + Sent LSN : 3B/10000148 (diff: 0 B) + Write LSN : 3B/10000148 (diff: 0 B) + Flush LSN : 3B/10000000 (diff: -328 B) + + +Barman diagnose +--------------- + +The :ref:`barman diagnose ` command gathers important +information about the status of all the configured servers. It's an overall view of +the configured Postgres servers that are being backed up by Barman. + +.. code:: bash + + barman diagnose + + +The ``diagnose`` command output is a full snapshot of the barman server, providing useful information, such as global configuration, SSH version, +Python version, ``rsync`` version, PostgreSQL clients version, +as well as current configuration and status of all servers. + +The ``diagnose`` command is extremely useful for troubleshooting problems, +as it gives a global view on the status of your Barman installation. diff --git a/docs/user_guide/geographical_redundancy.rst b/docs/user_guide/geographical_redundancy.rst new file mode 100644 index 000000000..630e16ce2 --- /dev/null +++ b/docs/user_guide/geographical_redundancy.rst @@ -0,0 +1,101 @@ +.. _geographical-redundancy: + +Geographical Redundancy +======================= + +It's possible to set up cascading backup architectures with Barman, where the +source of a Barman backup server is another Barman installation rather than a +PostgreSQL server. + +This feature allows users to transparently keep geographically distributed +copies of PostgreSQL backups. + +In Barman jargon, a Barman backup server that is connected to another Barman +installation, rather than a PostgreSQL server, is defined as a passive node. +A passive node is configured through the ``primary_ssh_command`` option, available +both at global (for a full replica of a primary Barman installation) and server +level (for mixed scenarios, having both direct and passive servers). + +Sync information +---------------- + +The ``barman sync-info`` command is used to collect information regarding the +current status of a Barman server which is useful for synchronization purposes. +The available syntax is the following: + +.. code-block:: bash + + barman sync-info [--primary] [ []] + +The command returns a JSON object containing: + +- A map with all the backups having status ``DONE`` for that server. +- A list with all the archived WAL files. +- The configuration for the server. +- The last read position (in the xlog database file). +- The name of the last read WAL file. + +The JSON response contains all the required information for the synchronisation +between the ``primary`` and a ``passive`` node. + +If ``--primary`` is specified, the command is executed on the defined +primary node, rather than locally. + +Configuration +------------- + +Configuring a server as a passive node is a quick operation. Simply add to the server +configuration the following option: + +.. code-block:: ini + + primary_ssh_command = ssh barman@primary_barman + +This option specifies the SSH connection parameters to the primary server, +identifying the source of the backup data for the passive server. + +If you are invoking barman with the ``-c/--config`` option and you want to use +the same option when the passive node invokes barman on the primary node then +add the following option: + +.. code-block:: ini + + forward_config_path = true + +Node synchronization +-------------------- + +When a node is marked as passive it is treated in a special way by Barman: + +- It is excluded from standard maintenance operations. +- Direct operations to Postgres are forbidden, including ``barman backup``. + +Synchronization between a passive server and its primary is automatically +managed by ``barman cron`` which will transparently invoke: + +1. ``barman sync-info --primary``, in order to collect synchronization information. +2. ``barman sync-backup``, in order to create a local copy of every backup that is + available on the primary node. +3. ``barman sync-wals``, in order to copy locally all the WAL files available on the + primary node. + +Manual synchronization +---------------------- + +Although ``barman cron`` automatically manages passive/primary node synchronization, +it is possible to manually trigger synchronization of a backup through: + +.. code-block:: bash + + barman sync-backup + +Launching ``sync-backup`` barman will use the ``primary_ssh_command`` to connect to the +primary server, then, if the backup is present on the remote machine, it will begin to +copy all the files using rsync. Only one synchronization process per backup is allowed +at a time. + +WAL files can also be synchronized, through: + +.. code-block:: bash + + barman sync-wals diff --git a/docs/user_guide/glossary.rst b/docs/user_guide/glossary.rst new file mode 100644 index 000000000..88e06d08c --- /dev/null +++ b/docs/user_guide/glossary.rst @@ -0,0 +1,58 @@ +.. _glossary: + +Glossary +======== + +.. glossary:: + + AWS + Amazon Web Services + + Barman + Backup and Recovery Manager. + + DBA + Database Administrator. + + DEB + Debian Package. + + GCP + Google Cloud Platform + + IAC + Infrastructure As Code + + ICT + Information and Communication Technology. + + libpq + The C application programmer's interface to Postgres. libpq is a set + of library functions that allow client programs to pass queries to the + Postgres backend server and to receive the results of these queries. + + PGDG + Postgres Global Development Group. + + PITR + Point-in-time Recovery. + + RHEL + Red Hat Enterprise Linux. + + RPM + Red Hat Package Manager. + + RPO + Recovery Point Objective. The maximum targeted period in which data might be + lost from an IT service due to a major incident. In summary, it represents the + maximum amount of data you can afford to lose. + + SLES + SUSE Linux Enterprise Server + + SPOF + Single Point of Failure + + VLDB + Very Large DataBase diff --git a/docs/user_guide/hook_scripts.rst b/docs/user_guide/hook_scripts.rst new file mode 100644 index 000000000..8e4c05081 --- /dev/null +++ b/docs/user_guide/hook_scripts.rst @@ -0,0 +1,209 @@ +.. _hook-scripts: + +Hook Scripts +============ + +Barman allows :term:`DBAs ` to run hook scripts during specific events: + +* :ref:`Before and after creating a backup `. +* :ref:`Before and after deleting a backup `. +* :ref:`Before and after a WAL file is archived `. +* :ref:`Before and after a WAL file is deleted `. +* :ref:`Before and after restoring a backup `. + +.. important:: + These scripts can be configured using the global options, which can be overridden for + individual servers. Deletion and recovery hook scripts were introduced in ``version 2.4``. + +There are two types of hook scripts that Barman can manage: + +* **Standard Hook Scripts**: These scripts are executed once and do not have their + return codes checked. + +* **Retry Hook Scripts**: These scripts might be executed multiple times, depending on + their return codes. + +When executing a retry hook script, Barman checks the return code and will continue to +retry the script until it returns one of the following: + +* ``SUCCESS`` (standard return code ``0``) +* ``ABORT_CONTINUE`` (return code ``62``) +* ``ABORT_STOP`` (return code ``63``) + +Any other return code is treated as a transient failure, prompting Barman to retry the +script. This gives users greater control, allowing hook scripts to determine if a +failure should be considered transient. Additionally, for a pre-hook script, returning +``ABORT_STOP`` allows users to request that Barman interrupts the main operation with a +failure. + +Hook scripts are executed in the following sequence (skipped if not present): + +1. **Standard pre hook script**. + +2. **Retry pre hook script**. + +3. **Main event** (backup operation, restore operation or WAL archiving), unless the + retry pre hook script was aborted with ``ABORT_STOP``. + +4. **Retry post hook script**. + +5. **Standard post hook script**. + +All output generated by hook scripts is logged in Barman's log file.. + +.. note:: + Currently, ``ABORT_STOP`` is ignored by retry post-hook scripts. In such cases, this + will result in logging an additional warning, and ``ABORT_STOP`` will behave the same + as ``ABORT_CONTINUE``. + +.. _hook-scripts-before-and-after-creating-a-backup: + +Before and after creating a backup +---------------------------------- + +* ``pre_backup_script``: A hook script executed once before a base backup, without + checking the exit code. +* ``pre_backup_retry_script``: A retry hook script executed before a base backup, + running repeatedly until it succeeds or is aborted. +* ``post_backup_retry_script``: A retry hook script executed after a base backup, + running repeatedly until it succeeds or is aborted. +* ``post_backup_script``: A hook script executed once after a base backup, without + checking the exit code. + +The shell environment will include the following variables for **backup scripts**: + +* ``BARMAN_BACKUP_DIR``: The destination directory for the backup. +* ``BARMAN_BACKUP_ID``: The ID of the backup. +* ``BARMAN_CONFIGURATION``: The configuration file used by Barman. +* ``BARMAN_ERROR``: Any error message (only applicable in the ``post`` phase). +* ``BARMAN_PHASE``: Indicates the phase of the script, either ``pre`` or ``post``. +* ``BARMAN_PREVIOUS_ID``: The ID of the previous backup, if available. +* ``BARMAN_RETRY``: Set to ``1`` if it is a retry script; otherwise, it is ``0``. +* ``BARMAN_SERVER``: The name of the server. +* ``BARMAN_STATUS``: The status of the backup. +* ``BARMAN_VERSION``: The version of Barman. + +.. _hook-scripts-before-and-after-deleting-a-backup: + +Before and after deleting a backup +---------------------------------- + +* ``pre_delete_script``: A hook script triggered once before the backup deletion, with + no exit code check. +* ``pre_delete_retry_script``: A retry hook script that runs before the backup deletion, + executing repeatedly until it succeeds or is aborted. +* ``post_delete_retry_script``: A retry hook script that runs after the backup deletion, + executing repeatedly until it succeeds or is aborted. +* ``post_delete_script``: A hook script triggered once after the backup deletion, with + no exit code check. + +**Delete scripts** utilize the same environmental variables as **backup scripts**, plus: + +``BARMAN_NEXT_ID``: The ID of the next backup, if available. + +.. _hook-scripts-before-and-after-a-WAL-file-is-archived: + +Before and after a WAL is archived +---------------------------------- + +* ``pre_archive_script``: A hook script that runs once before a WAL file is archived by + maintenance (typically via Barman cron), without checking the exit code. +* ``pre_archive_retry_script``: A retry hook script that executes before a WAL file is + archived by maintenance, running repeatedly until it succeeds or is aborted. +* ``post_archive_retry_script``: A retry hook script that executes after a WAL file is + archived by maintenance, running repeatedly until it succeeds or is aborted. +* ``post_archive_script``: A hook script that runs once after a WAL file is archived by + maintenance, without checking the exit code. + +**WAL archive scripts** share several environmental variables with **backup scripts**: + +* ``BARMAN_CONFIGURATION``: The configuration file used by Barman. +* ``BARMAN_ERROR``: Any error message generated (only for the post phase). +* ``BARMAN_PHASE``: The phase of the script, either pre or post. +* ``BARMAN_SERVER``: The name of the server. + +Additionally, the following variables are specific to **WAL archive scripts**: + +* ``BARMAN_SEGMENT``: The name of the WAL file. +* ``BARMAN_FILE``: The full path of the WAL file. +* ``BARMAN_SIZE``: The size of the WAL file. +* ``BARMAN_TIMESTAMP``: The timestamp of the WAL file. +* ``BARMAN_COMPRESSION``: The type of compression applied to the WAL file. + +.. _hook-scripts-before-and-after-a-WAL-file-is-deleted: + +Before and after a WAL file is deleted +-------------------------------------- + +* ``pre_wal_delete_script``: A hook script that runs before a WAL file is deleted. +* ``pre_wal_delete_retry_script``: A retry hook script that executes before the deletion + of a WAL file, running repeatedly until it succeeds or is aborted. +* ``post_wal_delete_retry_script``: A retry hook script that runs after a WAL file is + deleted, executing repeatedly until it succeeds or is aborted. +* ``post_wal_delete_script``: A hook script that runs after a WAL file is deleted. + +**WAL delete scripts** utilize the same environmental variables as +**WAL archive scripts**. + +.. _hook-scripts-before-and-after-restoring-a-backup: + +Before and after restoring a backup +----------------------------------- + +* ``pre_recovery_script``: A hook script that runs once before a backup restore, + without checking the exit code. +* ``pre_recovery_retry_script``: A retry hook script that executes before a backup + restore, running repeatedly until it succeeds or is aborted. +* ``post_recovery_retry_script``: A retry hook script that runs after a backup restore, + executing repeatedly until it succeeds or is aborted. +* ``post_recovery_script``: A hook script that runs once after a backup restore, + without checking the exit code. + +**Recovery scripts** utilize the same environmental variables as **backup scripts**, +plus: + +* ``BARMAN_DESTINATION_DIRECTORY``: The directory where the new instance is restored. +* ``BARMAN_TABLESPACES``: The tablespace relocation map (in JSON format, if applicable). +* ``BARMAN_REMOTE_COMMAND``: The secure shell command used during restore (if + applicable). +* ``BARMAN_RECOVER_OPTIONS``: Additional recovery options (in JSON format, if + applicable). + +.. _hook-scripts-using-barman-cloud-scripts-as-hooks-in-barman: + +Using ``barman-cloud-*`` scripts as hooks in barman +--------------------------------------------------- + +Follow the process in the :ref:`installation section ` to start using the +:ref:`barman-cloud commands `. + +.. note:: + For detailed information on configuration options, refer to the + :ref:`configuration ` section. + +You can use ``barman-cloud-backup`` as a ``post-backup script`` for the following Barman +backup types: + +* Backups created with ``backup_method = rsync``. +* Backups created with ``backup_method = postgres`` when ``backup_compression`` is not + applied. + +To configure this, add the following line to your server configuration in Barman: + +.. code-block:: text + + post_backup_retry_script = barman-cloud-backup [ OPTIONS ] DESTINATION_URL SERVER_NAME + +.. warning:: + When used as a hook script, ``barman-cloud-backup`` requires the backup status to be + ``DONE``. It will fail if the backup has any other status. To avoid issues, it is + recommended to run backups with the ``-w`` / ``--wait`` option to ensure the hook + script is not executed while the backup status is ``WAITING_FOR_WALS``. + +Additionally, set up ``barman-cloud-wal-archive`` as a pre-WAL archive script by +adding the following line to the Barman configuration for your Postgres server: + +.. code-block:: text + + pre_archive_retry_script = barman-cloud-wal-archive [ OPTIONS ] DESTINATION_URL SERVER_NAME + diff --git a/docs/user_guide/index.rst b/docs/user_guide/index.rst new file mode 100644 index 000000000..03b0922ec --- /dev/null +++ b/docs/user_guide/index.rst @@ -0,0 +1,35 @@ +.. _user_guide: + +User Guide +========== + +:term:`Barman` is an open-source administration tool for disaster recovery of +Postgres servers written in Python. It allows your organisation to perform remote +backups of multiple servers in business critical environments to reduce risk and help +DBAs during the recovery phase. + +`Barman `_ is distributed under GNU GPL 3 and maintained by +`EnterpriseDB `_, a platinum sponsor of the +`PostgreSQL project `_. + + +.. toctree:: + + concepts + installation + quickstart + architectures + pre_requisites + barman_check + backup + wal_archiving + catalog + recovery + retention_policies + diagnose_and_troubleshooting + configuration + commands + geographical_redundancy + hook_scripts + barman_cloud + glossary diff --git a/docs/user_guide/installation.rst b/docs/user_guide/installation.rst new file mode 100644 index 000000000..1577b60fd --- /dev/null +++ b/docs/user_guide/installation.rst @@ -0,0 +1,170 @@ +.. _installation: + +Installing +========== + +Barman official packages are provided by :term:`PGDG`. These packages use the default +version of Python 3 that comes with the operating system. + +There are three packages that make up the suite of Barman features: ``barman``, +``barman-cli`` and ``barman-cli-cloud``. + +* ``barman`` is the main package and it must be installed. + +* ``barman-cli`` is an optional package that holds the ``barman-wal-restore`` and + ``barman-wal-archive`` utilites. This package is mandatory if you plan to use those + utilities as the ``archive_command`` or ``restore_command``. It must be installed on + each Postgres server that is part of the Barman cluster. + +* ``barman-cli-cloud`` is an optional package that holds the ``barman-cloud-*`` client + scripts that you can use to manage backups in a cloud provider. It must be installed + on the Postgres servers that you want to back up directly to a cloud provider, + bypassing Barman. + + +.. note:: + Barman packages can be found in several different repositories. We recommend using + PGDG repositories because it ensures compatibility, stability and access to + the latest updates. + +.. warning:: + Do not upgrade Barman using different repositories. By doing so you risk losing your + configuration as each source repository provides different packages, which use + different configuration layouts. + +.. _installation-rhel-based-distributions: + +RHEL-based distributions +------------------------ + +You can install ``barman``, ``barman-cli`` and ``barman-cli-cloud`` using :term:`RPM` +packages on :term:`RHEL` systems as well as on similar RHEL-based systems like +AlmaLinux, Oracle Linux and Rocky Linux. + +To begin with the installation, first install the +`PGDG RPM repository `_. + +.. important:: + The ``barman-cli-cloud`` scripts are part of the ``barman-cli`` package for + RHEL-based distributions from :term:`PGDG`. Therefore, you only need to install + ``barman-cli`` to use the cloud scripts. + +barman +^^^^^^ + +To install the ``barman`` package. Run as **root**: + +.. code-block:: bash + + dnf install barman + +barman-cli +^^^^^^^^^^ + +To install the ``barman-cli`` package, run as **root** in the Postgres server: + +.. code-block:: bash + + dnf install barman-cli + +.. note:: + If you want to use the barman-cloud utilities as + :ref:`hook scripts `, you + will need to install the ``barman-cli`` package in the Barman server. + +.. _installation-debian-based-distributions: + +Debian-based distributions +-------------------------- + +You can install ``barman``, ``barman-cli`` and ``barman-cli-cloud`` using :term:`DEB` packages +on Debian systems as well as on Debian-based systems like Ubuntu. + +To begin with the installation, install the PGDG APT repository. This depends on your system: + +* For Debian: `PGDG Debian repository `_. +* For Ubuntu: `PGDG Ubuntu repository `_. + +.. important:: + The ``barman-cli-cloud`` package is included among the recommended packages when you + install ``barman-cli``. + + Before starting the installation, it's essential to evaluate your use case. If you + don't plan to use the barman-cloud client scripts, such as ``barman-cloud-backup``, + you can skip installing ``barman-cli-cloud`` as a recommended package when + installing ``barman-cli``. However, if you only intend to use the barman-cloud client + scripts, you can install the ``barman-cli-cloud`` package on its own. + +barman +^^^^^^ + +To install the ``barman`` package. Run as **root**: + +.. code-block:: bash + + apt install barman + +barman-cli +^^^^^^^^^^ + +To install the ``barman-cli`` package, run as **root** in the Postgres server: + +.. code-block:: bash + + apt install barman-cli + +barman-cli-cloud +^^^^^^^^^^^^^^^^ + +To install the ``barman-cli-cloud`` package, run as **root** in the Postgres server: + +.. code-block:: bash + + apt install barman-cli-cloud + +.. note:: + If you want to use the barman-cloud utilities as + :ref:`hook scripts `, you + will need to install this package in the Barman server. + +.. _installation-sles-based-distributions: + +SLES-based distributions +------------------------ + +You can install ``barman`` on :term:`SLES` systems by utilizing the packages provided in +the `PostgreSQL Zypper Repository `_. + +To begin installation, you will need to add the appropriate repository by following the +detailed instructions available on the +`PGDG SLES Repository Configuration `_. + +**The current supported version for installation is SLES 15 SP5.** + +.. important:: + The ``barman-cli-cloud`` utilities are part of the ``barman-cli`` package for + SLES-based distributions from :term:`PGDG`. Therefore, you only need to install + ``barman-cli`` to use the cloud scripts. + +barman +^^^^^^ + +To install the ``barman`` package. Run as **root**: + +.. code-block:: bash + + zypper install barman + +barman-cli +^^^^^^^^^^ + +To install the ``barman-cli`` package, run as **root** in the Postgres server: + +.. code-block:: bash + + zypper install barman-cli + +.. note:: + If you want to use the barman-cloud utilities as + :ref:`hook scripts `, you + will need to install this package in the Barman server. \ No newline at end of file diff --git a/docs/user_guide/pre_requisites.rst b/docs/user_guide/pre_requisites.rst new file mode 100644 index 000000000..051b029b1 --- /dev/null +++ b/docs/user_guide/pre_requisites.rst @@ -0,0 +1,407 @@ +.. _pre-requisites: + +Pre-requisites +============== + +This section details some requirements and configurations necessary to set up a Barman +environment depending on your use case. + +Throughout this section, we assume the following hosts: + +* ``pghost``: The host where Postgres is running. + +* ``barmanhost``: The host where Barman will be set up. + +.. _pre-requisites-postgres-user: + +Postgres users +-------------- + +Barman requires a connection to your Postgres instance to gather information about the +server. The recommended way to set up this connection is to create a dedicated user in +Postgres named ``barman``. This user should have the necessary privileges. + +.. note:: + + The ``createuser`` commands executed below will prompt you for a password, which + you are then advised to add to a + `password file `_ + named ``.pgpass`` under your Barman home directory on ``barmanhost``. Aditionally, + you can choose the client authentication method of your preference among those + offered by Postgres. Check the `official documentation `_ + for further details. + + +To create a superuser named ``barman`` in Postgres, run the following command on +``pghost``: + +.. code-block:: bash + + createuser -s -P barman + +Or, in case you opt for a user with only the required priviledges, follow these steps: + +1. On ``pghost``, run this command to create a user named ``barman`` in Postgres: + +.. code-block:: bash + + createuser -P barman + +2. On ``pghost``, in the psql interface, run the following statements: + +.. code-block:: sql + + GRANT EXECUTE ON FUNCTION pg_backup_start(text, boolean) to barman; + GRANT EXECUTE ON FUNCTION pg_backup_stop(boolean) to barman; + GRANT EXECUTE ON FUNCTION pg_switch_wal() to barman; + GRANT EXECUTE ON FUNCTION pg_create_restore_point(text) to barman; + GRANT pg_read_all_settings TO barman; + GRANT pg_read_all_stats TO barman; + +In the case of using Postgres version 14 or a prior version, the functions +``pg_backup_start`` and ``pg_backup_stop`` will have different names and signatures. +You will therefore need to replace the first two lines in the above block with: + +.. code-block:: sql + + GRANT EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) to barman; + GRANT EXECUTE ON FUNCTION pg_stop_backup() to barman; + GRANT EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) to barman; + +.. note:: + + In Postgres version 13 and below, the ``--force`` option of the barman + ``switch-wal`` command does not work without a superuser. In Postgres version 15 or + above, it is possible to grant the ``pg_checkpoint`` role to use it without a + superuser by executing the statement ``GRANT pg_checkpoint TO barman;``. + + +.. _pre-requisites-postgres-connection: + +Postgres connection +------------------- + +A connection to your Postgres instance is required regardless of which backup method +you are using. This connection is required by Barman in order to coordinate its +activities with the database server, as well as for monitoring purposes. + +Make sure that ``barmanhost`` can connect to the database server as superuser or with +a user with the required priviledges. You can find detailed information about +setting up Postgres connections in the +`Postgres Client Authentication `_. + +With your user created, run the following command on ``barmanhost`` to assert that it +can connect to your Postgres instance: + +.. code-block:: bash + + psql -c 'SELECT version()' -U barman -h pghost postgres + + +``postgres`` can be any available database through which Barman can connect to the +Postgres instance. + +If the above command succeeds, it means that it can successfully connect to the +database server. Remember the connection parameters above as they are the ones you +need to write on your server's configuration file, in the ``conninfo`` parameter. +In this context, this parameter would be as follows: + + +.. code-block:: ini + + [my-server] + ; ... + conninfo = host=pghost user=barman dbname=postgres application_name=myapp + +``application_name`` is an optional parameter. + +.. _pre-requisites-postgres-client-tools: + +Postgres client tools +--------------------- + +The Postgres client tools are required to interact with the Postgres server. The most +commonly used tools by Barman are ``pg_basebackup`` and ``pg_receivewal``. They are +provided by the Postgres client package. + +To install the Postgres client package on Debian or Ubuntu run the following command +on the ``barmanhost``: + +.. code-block:: bash + + sudo apt-get install postgresql-client + +Alternatively, if the ``barmanhost`` is using RHEL, Rocky Linux, Alma Linux, follow +this recipe: + +.. code-block:: bash + + sudo dnf install postgresql + + +.. _pre-requisites-postgres-streaming-connection: + +Postgres streaming replication connection +----------------------------------------- + +If you plan to use streaming backups or streaming of WAL files, you need to +setup a streaming connection. Additionally, you also need to have the Postgres +client tools installed, as shared in +:ref:`pre-requisites ` section. + +We recommend creating a dedicated user in Postgres named ``streaming_barman``. You +can do so with the following command: + +.. code-block:: bash + + createuser -P --replication streaming_barman + + +.. note:: + + The ``createuser`` commands executed below prompt you for a password, which you + are then advised to add to a + `password file `_ + named ``.pgpass`` under your Barman home directory on ``barmanhost``. Aditionally, + you can choose the client authentication method of your preference among those + offered by Postgres. Check the `official documentation `_ + for further details. + +You can verify that the streaming connection works through the following command: + +.. code-block:: bash + + psql -U streaming_barman -h pghost -c "IDENTIFY_SYSTEM" replication=1 + +If the connection is working, you should see a response containing the system +identifier, current timeline ID and current WAL flush location, for example: + +.. code-block:: text + + systemid | timeline | xlogpos | dbname + ---------------------+----------+------------+-------- + 7139870358166741016 | 1 | 1/330000D8 | + (1 row) + +You also need to configure the ``max_wal_senders`` parameter in Postgres. +The number of WAL senders depends on the Postgres architecture you have implemented. +In this example, we are setting it to ``2``: + +.. code-block:: ini + + max_wal_senders = 2 + +This option represents the maximum number of concurrent streaming connections that +Postgres is allowed to manage. + +Another important parameter is ``max_replication_slots``, which represents the maximum +number of replication slots that Postgres is allowed to manage. This parameter is +relevant if you are planning to use the streaming connection to receive WAL files over +the streaming connection: + +.. code-block:: ini + + max_replication_slots = 2 + +The values proposed for ``max_replication_slots`` and ``max_wal_senders`` must be +considered as examples, and the values you use in your actual setup must be chosen +after a careful evaluation of the architecture. Please consult the Postgres +documentation for guidelines and clarifications. + + +.. _pre-requisites-ssh-connections: + +SSH connections +--------------- + +If you plan to use Rsync backups or WAL archiving via ``archive_command``, then SSH +connections are required. + +SSH is a protocol and a set of tools that allows you to open a remote shell to a remote +server and copy files between the server and the local system. You can find more +documentation about SSH usage in the `article "SSH Essentials" by Digital Ocean `_. + +SSH key exchange is a very common practice that is used to implement secure +passwordless connections between users on different machines, and it's needed to use +Rsync for WAL archiving and backups. + + +.. _pre-requisites-ssh-connections-ssh-configuration-of-postgres-user: + +SSH configuration of postgres user +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Unless you have done it before, you need to create an SSH key for the **postgres** +user. Log in as **postgres** on ``pghost`` and run: + +.. code-block:: bash + + ssh-keygen -t rsa + +As this key must be used to connect from hosts without providing a password, no +passphrase should be entered during the key pair creation. + + +.. _pre-requisites-ssh-connections-ssh-configuration-of-barman-user: + +SSH configuration of barman user +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You also need to create an SSH key for the **barman** user. Log in as **barman** on +``barmanhost`` and run: + +.. code-block:: bash + + ssh-keygen -t rsa + +Again, no passphrase should be entered. + + +.. _pre-requisites-ssh-connections-from-postgres-to-barman: + +From Postgres to Barman +^^^^^^^^^^^^^^^^^^^^^^^ + +The SSH connection from ``pghost`` to ``barmanhost`` is needed to correctly archive +WAL files using the ``archive_command``. + +To successfully connect from ``pghost`` to ``barmanhost``, the **postgres** user`s +public key has to be stored in the authorized keys of the **barman** user on +``barmanhost``. This key is located in the **postgres** user home director in a file +named ``.ssh/id_rsa.pub``, and its content should be included in a file named +``.ssh/authorized_keys`` inside the home directory of the **barman** user on +``barmanhost``. If the ``authorized_keys`` file doesn't exist, create it using +``600`` as permissions. + +The following command should succeed without any output if the SSH key pair exchange +has been completed successfully: + +.. code-block:: bash + + ssh barman@barmanhost -C true + + +.. _pre-requisites-ssh-connections-from-barman-to-postgres: + +From Barman to Postgres +^^^^^^^^^^^^^^^^^^^^^^^ + +The SSH connection between from ``barmanhost`` to ``pghost`` is used for the +traditional backup using Rsync. + +To successfully connect from ``barmanhost`` to ``pghost``, the **barman** user`s +public key has to be stored in the authorized keys of the **postgres** user on +``pghost``. This key is located in the **barman** user home directory in a file +named ``.ssh/id_rsa.pub``, and its content should be included in a file named +``.ssh/authorized_keys`` inside the home directory of the **postgres** user on +``pghost``. If the ``authorized_keys`` file doesn't exist, create it using +``600`` as permissions. + +The following command should succeed without any output if the SSH key pair exchange +has been completed successfully: + +.. code-block:: bash + + ssh postgres@pghost -C true + +.. _pre-requisites-wal-archiving-via-archive-command: + +WAL archiving via ``archive_command`` +------------------------------------- + +As stated in the :ref:`architectures-wal-archiving-strategies` section, there are two +options to archive wals with Barman. If you wish to use the streaming replication +protocol to archive WAL files, refer to the :ref:`concepts-barman-concepts-wal-streaming` +concepts and :ref:`quickstart` section, specifically the Streaming backups with WAL +streaming sub-section. Otherwise you can configure WAL archiving using the +``archive_command`` with :ref:`commands-barman-cli-barman-wal-archive` or with +Rsync/SSH. + +Using barman-wal-archive +^^^^^^^^^^^^^^^^^^^^^^^^ + +Starting from Barman 2.6, the recommended approach for securely archiving Write-Ahead +Log files is to utilize the ``barman-wal-archive`` command from the ``barman-cli`` +package. Refer to the :ref:`installation ` section on how to install this +package. + +Using ``barman-wal-archive`` instead of traditional methods like rsync or SSH minimizes +the risk of data corruption during the transfer of WAL files to the Barman server. The +conventional methods lack a guarantee that the file's content is properly flushed and +fsynced to disk at the destination. + +The ``barman-wal-archive`` utility directly interacts with +:ref:`commands-barman-put-wal` command. This command ensures that the received WAL file +is fsynced and stored in the correct incoming directory for the respective server. The +only parameter required for the ``archive_command`` is the server's name, reducing the +likelihood of misplacement. + +To verify that ``barman-wal-archive`` can connect to the Barman server and that the +Postgres server is correctly configured to accept incoming WAL files, execute the +following command: + +.. code-block:: text + + barman-wal-archive --test backup pg DUMMY + +Here, ``backup`` refers to the Barman host, ``pg`` is the Postgres server's name as +configured in Barman, and ``DUMMY`` is a placeholder for the WAL file name which is +ignored when using the ``-t`` option. + +If the setup is correct, you should see: + +.. code-block:: text + + Ready to accept WAL files for the server pg + +Since the utility communicates via SSH, ensure that SSH key authentication is set up for +the postgres user to log in as barman on the backup server. If your SSH connection uses +a port other than the default (22), you can specify the port using the ``--port`` +option. + +Refer to the +:ref:`quickstart-configuring-your-first-server-rsync-backups-with-wal-archiving` to start +working with it. + +Using Rsync/SSH +^^^^^^^^^^^^^^^ + +An **alternative approach** for configuring the ``archive_command`` is to utilize the +rsync command via SSH. Here are the initial steps to set it up effectively for a +Postgres server named ``pg``, a Barman server named ``backup`` and a user named +``barman``. + +To locate the incoming WALs directory, use the following command and check for the +``incoming_wals_directory`` value: + +.. code-block:: text + + barman show-servers pg | grep incoming_wals_directory + + incoming_wals_directory: /var/lib/barman/pg/incoming + +Next, edit the ``postgresql.conf`` file for the Postgres instance on the ``pg`` host to +enable archive mode: + +.. code-block:: text + + archive_mode = on + wal_level = 'replica' + archive_command = 'rsync -a %p barman@backup:INCOMING_WALS_DIRECTORY/%f' + +Be sure to replace the ``INCOMING_WALS_DIRECTORY`` placeholder with the actual path +retrieved from the previous command. After making these changes, restart the Postgres +server. + +For added security in the ``archive_command`` process, consider implementing stricter +checks. For instance, the following command ensures that the hostname matches before +executing the rsync: + +.. code-block:: text + + archive_command = 'test $(/bin/hostname --fqdn) = HOSTNAME \ + && rsync -a %p barman@backup:INCOMING_WALS_DIRECTORY/%f' + +Replace ``HOSTNAME`` with the output from ``hostname --fqdn``. This approach acts as a +safeguard against potential issues when servers are cloned, preventing WAL files from +being sent by recovered Postgres instances. diff --git a/docs/user_guide/quickstart.rst b/docs/user_guide/quickstart.rst new file mode 100644 index 000000000..c15bc60d8 --- /dev/null +++ b/docs/user_guide/quickstart.rst @@ -0,0 +1,386 @@ +.. _quickstart: + +Quick start +=========== + +As it is stated in :ref:`architectures`, we recommend setting up Barman in a dedicated +host. That said, the examples in this tutorial assume the following hosts: + +* ``pghost``: The host where Postgres is running. +* ``barmanhost``: The host where Barman will be set up. + +Assuming Barman is already installed in ``barmanhost`` as per +:ref:`installation `, you can continue through the next steps. + +.. _quickstart-configuring-your-first-server: + +Configuring your first server +----------------------------- + +Barman supports different backup and WAL archive strategies. Here you can find simple +recipes to set up two of the most commonly used architectures. Choose the one that best +suits your needs and proceed to the next sections. + + +.. _quickstart-configuring-your-first-server-streaming-backups-with-wal-streaming: + +Streaming backups with WAL streaming +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This strategy uses the Postgres streaming replication protocol for both backups and WAL +archiving, so you only need native Postgres connections between ``pghost`` and +``barmanhost`` in order to implement it. A key advantage of this approach is that no +SSH connection is required, making it a simpler option to set up in comparison with +other strategies. + +It relies on the ``pg_basebackup`` utility for backups and ``pg_receivewal`` for +transferring the WAL files. It is therefore required to have both tools installed on +``barmanhost`` beforehand. Check the :ref:`Postgres client tools ` +section if you need further details on how to install these tools. + +1. As a first step, let's create the required users you will need on your Postgres +server. On ``pghost``, execute the following commands: + +.. code-block:: bash + + createuser -s -P barman + +This command creates a new Postgres superuser called **barman**, which will be used by +Barman for maintenance tasks on your Postgres server. Alternatively you can create a +user without superuser privileges, but with the necessary permissions to perform the +needed operations by following the recipe in +:ref:`Postgres users pre-requisite `. + +.. code-block:: bash + + createuser -P --replication streaming_barman + +This command creates a new Postgres user called **streaming_barman** with replication +privileges, which will be used by Barman when invoking ``pg_receivewal`` and +``pg_basebackup`` to transfer files to your Barman server. + +Both ``createuser`` commands prompt you for a password, which you are then advised to +add to a `password file `_ +named ``.pgpass`` under your Barman home directory on ``barmanhost``. Check the +:ref:`pre-requisites ` section if you need +further details on how to configure streaming connections. + +From now on, this section assumes you already have both Postgres users created as well +as a Postgres server to be backed up. Also, we assume a database named ``postgres`` +is available, so Barman can connect to the Postgres server through that database. + +2. Now make sure to allow access to the previously created users from your +``barmanhost``. On ``pghost``, add these HBA rules to your ``pg_hba.conf`` file: + +.. code-block:: ini + + # allows access to the barman user from barmanhost + host all barman barmanhost/32 md5 + # allows access to the streaming_barman user from barmanhost + host replication streaming_barman barmanhost/32 md5 + +Then, reload your Postgres configuration so the new HBA rules take effect. On +``pghost``, run: + +.. code-block:: bash + + psql -c "SELECT pg_reload_conf();" + + +3. Still on ``pghost``, make sure your Postgres server is properly configured for +WAL streaming. On its ``postgresql.conf`` file, assert that +`wal_level `_ +is set to ``replica`` or ``logical``: + +.. code-block:: ini + + wal_level = replica + +If changes were made to the ``wal_level`` configuration value, then restart your +Postgres server for the changes to take effect. + +4. Now let's configure your first backup server on Barman. On ``barmanhost``, create a +file at ``/etc/barman.d/streaming-backup-server.conf`` with this content: + +.. code-block:: ini + + [streaming-backup-server] + description = "Postgres server using streaming replication" + streaming_archiver = on + backup_method = postgres + streaming_conninfo = host=pghost user=streaming_barman dbname=postgres + slot_name = barman + create_slot = auto + conninfo = host=pghost user=barman dbname=postgres + +Where: + +* ``[streaming-backup-server]`` is a name of your choice for your backup server on + Barman. + +* ``description`` is a description text for your backup server. + +* ``streaming_archiver = on`` tells Barman that WAL files of this backup server are + transferred from Postgres to Barman using streaming replication. + +* ``backup_method = postgres`` tells Barman that this server uses ``postgres`` as its + backup method, which in essence means taking backups using ``pg_basebackup``. + +* ``streaming_conninfo`` is a connection string for a :term:`libpq` connection to your + Postgres server. This is the connection ``pg_receivewal`` and ``pg_basebackup`` use + to transfer files to your Barman server. + +* ``slot_name`` is the name of the physical replication slot in Postgres which is used + by this backup server to stream WALs through ``pg_receivewal``. + +* ``create_slot = auto`` tells Barman that it should create the replication slot + automatically in Postgres, not requiring a manual creation beforehand. + +* ``conninfo`` is a connection string for a :term:`libpq` connection to your Postgres + server which Barman uses for maintenance purposes. + +On ``barmanhost``, run: + +.. code-block:: bash + + barman list-servers + +You should see an output with all configured backup servers on Barman, which confirms +that it's now aware of your new server: + +.. code-block:: text + + streaming-backup-server - Postgres server using streaming replication + +5. Once finished with the configuration of both Barman and Postgres servers, you +should be ready to go! Execute the following command on ``barmanhost`` to check +that everything is OK with your server: + +.. code-block:: bash + + barman check streaming-backup-server + +If you see failed checks related to replication slot and ``pg_receivewal``, run the +following command. + +.. code-block:: bash + + barman cron + +This command starts a background process that performs maintenance tasks on +your Barman servers. These tasks includes the creation of the replication slot in +Postgres, if ``create_slot = auto``, as well as starting up of ``pg_receivewal`` +process. + +Run the check command again and make sure no failed checks are shown: + +.. code-block:: bash + + barman check streaming-backup-server + + +This server is now ready to take backups and receive WAL files from your Postgres +server. You may go to the +:ref:`taking your first backup ` section now. + +.. _quickstart-configuring-your-first-server-rsync-backups-with-wal-archiving: + +Rsync backups with WAL archiving +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This strategy relies on Rsync and SSH connections for transferring backup and WAL +files to your Barman server. + +Since it depends on SSH connections, it is therefore required that you have a +two-way passwordless SSH connection between ``pghost`` and ``barmanhost``. For +further instructions on how to set this, please refer to the +:ref:`pre-requisites ` section. + +1. As a first step, let's create the required user you will need on your Postgres +server. On ``pghost``, execute the following command: + +.. code-block:: bash + + createuser -s -P barman + +This command creates a new Postgres superuser called **barman**, which will be used by +Barman for maintenance tasks as well as for issuing backup commands using the Postgres +low-level API. Alternatively you can create a user without superuser privileges, but +with the necessary permissions to perform the needed operations by following the recipe +in :ref:`Postgres users pre-requisite `. + +The ``createuser`` command prompts you for a password, which you are then advised to +add to a `password file `_ +named ``.pgpass`` under your Barman home directory on ``barmanhost``. + +From now on, this section assumes you already have this Postgres user created as well +as a Postgres server to be backed up. Also, we assume a database named ``postgres`` +is available, so Barman can connect to the Postgres server through that database. + +2. Now make sure to allow access to the previously created user from your +``barmanhost``. On ``pghost``, add this HBA rule to your ``pg_hba.conf`` file: + +.. code-block:: ini + + # allows access to the barman user from barmanhost + host all barman barmanhost/32 md5 + +Then, reload your Postgres configuration so the new HBA rule takes effect. On +``pghost``, run: + +.. code-block:: bash + + psql -c "SELECT pg_reload_conf();" + + +3. Still on ``pghost``, make sure your Postgres server is properly configured for WAL +archiving. On its ``postgresql.conf`` file, assert the following parameters are +properly set: + +.. code-block:: ini + + wal_level = replica + archive_mode = on + archive_command = 'barman-wal-archive barmanhost rsync-backup-server %p' + +.. note:: + Since Barman 2.6, the recommended way of archiving WAL files via the + ``archive_command`` is by using the ``barman-wal-archive`` utility, as in the + example above. For this utility to be available, make sure to also have the + ``barman-cli`` package installed on ``pghost``. Check the + :ref:`pre-requisites-wal-archiving-via-archive-command` section for further + details and for alternative command options. + +4. Now let's configure your first backup server on Barman. On ``barmanhost``, create a +configuration file at ``/etc/barman.d/rsync-backup-server.conf`` with this content: + +.. code-block:: ini + + [rsync-backup-server] + description = "Postgres server using Rsync and WAL archiving" + archiver = on + backup_method = rsync + reuse_backup = link + backup_options = concurrent_backup + ssh_command = ssh postgres@pghost + conninfo = host=pghost user=barman dbname=postgres + +Where: + +* ``[rsync-backup-server]`` is a name of your choice for your backup server on Barman. + +* ``description`` is a description text for your backup server. + +* ``archiver = on`` tells Barman that WAL files of this backup server are + transferred from Postgres to Barman using the ``archive_command`` configured + in Postgres. + +* ``backup_method = rsync`` tells Barman that this backup server uses ``rsync`` as its + backup method, which in essence means copying over cluster files with Rsync. + +* ``reuse_backup = link`` tells Barman that you want to have data deduplication by + reusing files of the previous backup, saving storage and network resources whenever + taking new backups for this server. Check :ref:`rsync backups ` + section for more details. + +* ``backup_options = concurrent_backup`` indicates that Barman is going to issue + non-exclusive backup commands on your Postgres server when taking backups. + +* ``ssh_command`` is the SSH command to be used to connect from ``barmanhost`` to + ``pghost``. Replace this configuration value accordingly. + +* ``conninfo`` is a connection string for a :term:`libpq` connection to your Postgres + server which Barman uses for maintenance purposes. + +On ``barmanhost``, run: + +.. code-block:: bash + + barman list-servers + +You should see an output with all configured backup servers on Barman, which confirms +that it's now aware of your new server: + +.. code-block:: text + + rsync-backup-server - Postgres server using Rsync and WAL archiving + +5. Once finished with the configuration of both Barman and Postgres servers, you +should be ready to go! Execute the following command on ``barmanhost`` to check +that everything is OK with your server: + +.. code-block:: bash + + barman check rsync-backup-server + +If you see a failed check related to WAL archive, don't worry. It just means that +Barman has not received any WAL files yet, probably because no WAL segment has been +switched on your Postgres server since the server was first created. You can force +a WAL switch from ``barmanhost`` with this command: + +.. code-block:: bash + + barman switch-wal --force rsync-backup-server + +Then execute the following command, which starts a background process that performs +maintenance tasks on your Barman servers: + +.. code-block:: bash + + barman cron + +Run the check command again and make sure no failed checks are shown: + +.. code-block:: bash + + barman check rsync-backup-server + +This server is now ready to take backups and receive WAL files from your Postgres +server. You may go to the +:ref:`taking your first backup ` section now. + + +.. _quickstart-taking-your-first-backup: + +Taking your first backup +------------------------ + +Regardless of which strategy you choose for your backup server, once completed with the +previous steps, you should be all set. You can run this command to take a backup: + +.. code-block:: bash + + barman backup --name first-backup + +Once the command finishes, you can list all backups of your backup server with this +command: + +.. code-block:: bash + + barman list-backups + +And show the details of a specific backup with this command: + +.. code-block:: bash + + barman show-backup first-backup + + +.. _quickstart-restoring-a-backup: + +Restoring a backup +------------------ + +If you ever need to restore a backup, you can do so with this command: + +.. code-block:: bash + + barman restore first-backup /path/to/restore + +If restoring to a remote server, a passwordless SSH connection from the Barman host to +the destination host is required and its SSH command must be specified using +the ``--remote-ssh-command`` option: + +.. code-block:: bash + + barman restore --remote-ssh-command="ssh user@host" first-backup /path/to/restore diff --git a/docs/user_guide/recovery.rst b/docs/user_guide/recovery.rst new file mode 100644 index 000000000..53da18c15 --- /dev/null +++ b/docs/user_guide/recovery.rst @@ -0,0 +1,354 @@ +.. _recovery: + +Recovery +======== + +The restore command is used to restore an entire Postgres server from a backup created +with the backup command. To use it, run: + +``barman restore [OPTIONS] SERVER_NAME BACKUP_ID DESTINATION_PATH`` + +.. note:: + * Refer to :ref:`concepts-barman-concepts-restore-and-recover` for a clearer + understanding of the recovery concept in Barman. + * Do not run the restore command on a directory where a Postgres instance is currently + running. Ensure Postgres is stopped before initiating recovery, including recovery + of tablespace directories. + * The backup is restored to the specified directory, which will be ready to start a + Postgres instance. + * Use the ``list-backups`` command to find the specific backup ID you need. + * Barman does not track symbolic links inside PGDATA (except for tablespaces). + Ensure you manage symbolic links and include them in your disaster recovery plans. + +.. _recovery-remote-recovery: + +Remote Recovery +--------------- + +Use ``--remote-ssh-command COMMAND`` to perform recovery on a remote server via SSH. +It's recommended to use the postgres user on the target node for remote recovery. + +**Known Limitations** + +* Requires at least 4GB of free space in the system's temporary directory unless + ``get-wal`` is specified. +* SSH must use public key authentication. +* The remote user must be able to create the necessary directory structure. +* Ensure there is enough free space on the remote server for the base backup and WAL + files. + +.. _recovery-tablespace-remapping: + +Tablespace Remapping +-------------------- + +Use ``--tablespace NAME:DIRECTORY`` to remap tablespaces to a new location. Barman will +attempt to create the destination directory if it doesn't exist. + +.. important:: + By default, tablespaces are restored to the same path they had on the source server. + Be cautious when restoring a backup without any remapping to a destination where a + Postgres instance already exists, as it can end up overriding existing tablespace + directories. + + +.. _recovery-point-in-time-recovery: + +Point-in-Time Recovery +---------------------- + +Specify a recovery ``target`` with one of the options: + +* ``--target-time``: Recover to a specific timestamp. +* ``--target-xid``: Recover to a specific transaction ID. +* ``--target-lsn``: Recover to a Log Sequence Number (Postgres 10+). +* ``--target-name``: Recover to a named restore point. +* ``--target-immediate``: End recovery when a consistent state is reached (default). + +.. note:: + * Recovery targets must be a value after the end of the backup. To recover to a + point in time within a backup, use the previous backup. + * Timezone defaults to the Barman host if not specified in ``--target-time``'s + timestamp. + * Use ``--exclusive`` to control whether to stop right before the target or including + the target. + * ``--target-tli`` sets the target timeline. Use numeric IDs or shortcut values + (latest or current). + +The previous targets can be used with a ``--target-action`` which can take these values: + +* ``shutdown``: Shut down Postgres when the target is reached. +* ``pause``: Pause Postgres for inspection when the target is reached. +* ``promote``: Promote Postgres to primary when the target is reached. + +You can also configure the instance as a standby by calling ``--standby-mode``. After +recovery, ensure you modify the configuration to connect to the intended upstream node +server. + +.. _recovery-fetching-wals-from-barman: + +Fetching WALs from Barman +------------------------- + +Use ``--get-wal`` to configure Postgres to fetch WALs from Barman during recovery. If not +set, Barman will copy all the WALs required for Postgres recovery as part of the restore +command. + +.. note:: + When using ``--no-get-wal`` with targets like ``--target-xid``, ``--target-name``, or + ``--target-time``, Barman will copy the entire WAL archive to ensure availability. + +Another option is to include the ``recovery_options`` configuration at the global/server +level prior to a recovery operation to retrieve WAL files during the recovery process, +effectively turning the Barman server into a WAL hub for your servers. + +.. code-block:: text + + recovery_options = 'get-wal' + +If ``get-wal`` is included during restore, Barman will set up the ``restore_command`` +to use either ``barman get-wal`` or ``barman-wal-restore`` to retrieve the required WAL +files, depending on whether the recovery is local or remote. + +If ``get-wal`` is specified in ``recovery_options`` but not needed during a specific +recovery, you can disable it using the ``--no-get-wal`` option with the restore command. + +Here's an example of a ``restore_command`` for **local recovery**: + +.. code-block:: text + + restore_command = 'sudo -u barman barman get-wal SERVER %f > %p' + +Remember that the :ref:`barman get-wal ` command should always +be executed as the ``barman`` user, with the necessary permissions to access WAL files +from the catalog, which is why ``sudo -u barman`` is used in this example. + +For remote recovery, setting ``recovery_options`` to ``get-wal`` will create a +``restore_command`` using the :ref:`commands-barman-cli-barman-wal-restore` script, +which is designed to handle SSH connection errors more robustly. + +This script offers useful features like automatic compression and decompression of WAL +files and the ``peek`` feature, allowing you to retrieve upcoming WAL files while +Postgres is processing earlier ones, optimizing bandwidth between Postgres and Barman. + +``barman-wal-restore`` is included in the ``barman-cli`` package. Here's an example of +a ``restore_command`` for **remote recovery**: + +.. code-block:: text + + restore_command = 'barman-wal-restore -U barman backup SERVER_NAME %f %p' + +Here, ``backup`` refers to the host where Barman is installed. Since it communicates via +SSH, SSH key authentication is required for the ``postgres`` user to log in as +``barman`` on the backup server. If you need to use a non-default SSH port, you can +specify it with the ``--port`` option. + +To verify that ``barman-wal-restore`` can connect to the Barman server and that the +required Postgres server is set up to send WAL files, use the following command: + +.. code-block:: text + + barman-wal-restore --test backup pg DUMMY DUMMY + +Here, ``backup`` refers to the host where Barman is installed, ``pg`` is the name of the +Postgres server configured in Barman, and ``DUMMY`` acts as a placeholder (the script +needs two arguments for the WAL file name and destination directory, which will be +ignored). + +If everything is set up correctly, you should see: + +.. code-block:: text + + Ready to retrieve WAL files from the server pg + +For further details on the ``barman-wal-restore`` command, type +``man barman-wal-restore`` on the host where ``barman-cli`` was installed or refer to +the :ref:`commands-barman-cli-barman-wal-restore` command reference. + +.. tip:: + When both the ``pg_wal`` directory and the ``spool`` directory are located on the same + filesystem, serving WAL files will be faster because the files are renamed rather than + copied. However, if these directories are on different filesystems, there will be no + performance improvement, as the operation will involve both copying the file and then + removing the original. Be mindful of the filesystem locations to optimize WAL file + management efficiency. + +.. _recovery-recovering-compressed-backups: + +Recovering Compressed Backups +----------------------------- + +If a backup is compressed using the ``backup_compression`` option, Barman can decompress +it during restore. + +The process involves a few steps: + +1. The compressed backup files are copied to a staging directory on either the local or + remote server using Rsync. +2. These files are then decompressed to the restore destination directory. +3. For remote recovery, configuration files requiring special handling are copied from the + restore destination directory to a local temporary directory in the barman node, + edited and mangled as needed, and then returned to the restore directory using + Rsync. For local recovery, the local temporary directory is the restore destination + itself, so editing and mangling operations are done in place. This intermediate step + is necessary because Barman can only access individual files in the restore + directory, as the backup directory contains only a compressed tarball file. +4. The staging directory is removed after restore is complete. + +Since Barman does not have knowledge of the deployment environment, it depends on the +``recovery_staging_path`` option to determine an appropriate location for the staging +directory. Set the option in the global/server configuration or use the +``--recovery-staging-path`` option with the barman restore command. Failing to do so +will result in an error, as Barman cannot guess a suitable location on its own. + +.. _recovery-recovering-block-level-incremental-backups: + +Recovering block-level incremental Backups +------------------------------------------ + +If you are recovering from a block-level incremental backup, Barman combines the backup +chain using ``pg_combinebackup``. This chain consists of the root backup and all +subsequent incremental backups up to the one being recovered. + +To successfully recover from a block-level incremental backup, you must specify the +``local_staging_path`` in the global/server configuration or use the +``--local-staging-path`` option with the barman restore command. Failing to do so will +result in an error, as Barman cannot automatically determine a suitable staging +location. + +The process involves the following steps: + +1. Barman creates a synthetic backup by combining the chain of backups. This is done in + a staging directory on the Barman server using ``pg_combinebackup``. Barman will + create a subfolder inside the staging directory with the ID of the backup. +2. If the recovery is local, the synthetic backup is moved directly to the target + location. If it is a remote recovery, the synthetic backup is transferred to the + target location using Rsync. +3. After the restore is complete, the temporary subfolder in the local staging + directory used for combining backups is removed. The local staging directory itself + is kept. + +.. important:: + If any backups in the chain were taken with checksums disabled, but the final backup + has checksums enabled, the resulting syntethic backup may contain pages with invalid + checksums. Please refer to the limitations in the + `pg_combinebackup documentation `_ + for more details. + +.. _recovery-limitation-of-partial-wal-files: + +Limitations of .partial WAL files +--------------------------------- + +When using ``streaming_archiver``, Barman relies on ``pg_receivewal`` to continuously +receive transaction logs from a Postgres server (either master or standby) through the +native streaming replication protocol. By default, ``pg_receivewal`` writes these logs +to files with a ``.partial`` suffix, indicating they are not yet complete. Barman looks +for these ``.partial`` files in the ``streaming_wals_directory``. Once ``pg_receivewal`` +completes the file, it removes the ``.partial`` suffix and hands it over to Barman's +``archive-wal`` command for permanent storage and compression. + +If the master Postgres server suddenly fails and cannot be recovered, the ``.partial`` +file that was streamed to Barman may contain crucial data that might not have been +delivered to the archiving process. + +Starting with Barman version 2.10, the ``get-wal`` command can retrieve the content of +the current ``.partial`` WAL file using the ``--partial`` or ``-P`` option. This is +useful for recovery, whether performing a full restore or a point-in-time recovery. When +you initiate a restore command with ``get-wal`` and without ``--standby-mode``, Barman +will automatically include the ``-P`` option in the ``barman-wal-restore`` command to +handle the ``.partial`` file. + +Moreover, ``get-wal`` will check the ``incoming`` directory for any WAL files that have +been sent to Barman but not yet archived. + +Recovering from Snapshot Backups +-------------------------------- + +Barman currently does not support fully automated recovery from snapshot backups. This +limitation arises because snapshot recovery requires provisioning and managing new +infrastructure, a task best handled by dedicated :term:`IAC` solutions like Terraform +or OpenTofu. + +However, you can still use the barman restore command to validate the snapshot recovery +instance and perform post-recovery tasks, such as checking the Postgres configuration for +unsafe settings and configuring any necessary PITR options. The command will also copy +the ``backup_label`` file into place, as this file is not included in the volume +snapshots, and will transfer any required WAL files--unless the ``--get-wal`` recovery +option is specified, in which case it configures the Postgres ``restore_command`` to fetch +the WALs. + +If restoring from a backup created with ``barman-cloud-backup``, you should use the +``barman-cloud-restore`` command instead of ``barman restore``. + +.. note:: + The same requirements and configurations apply for restore when working with a cloud + provider. See the ``Requirements and Configuration`` section and the specific cloud + provider you are working with in the + :ref:`Cloud Snapshot Backups ` section. + +Recovery Steps +"""""""""""""" + +1. Provision a new disk for each snapshot taken during the backup. +2. Provision a compute instance to which each disk from step 1 is attached and mounted + according to the backup metadata. +3. Use the ``barman restore`` or ``barman-cloud-restore`` command to validate and + finalize the recovery. + +Steps 1 and 2 are ideally managed by an existing IAC system, but they can also be +performed manually or via a custom script. + +Helpful Resources +""""""""""""""""" + +`Example recovery script for GCP `_. + +`Example runbook for Azure `_. + +These resources make assumptions about your backup and recovery environment and should be +customized before use in production. + +Running the restore command +"""""""""""""""""""""""""""" + +Once the recovery instance is provisioned and the disks cloned from the backup snapshots +are attached and mounted, execute the barman restore command with the following +additional arguments: + +* ``--remote-ssh-command``: The SSH command required to log into the recovery instance. +* ``--snapshot-recovery-instance``: The name of the recovery instance as specified by + your cloud provider. +* Any additional arguments specific to the snapshot provider. + +Example Command +^^^^^^^^^^^^^^^ + +.. code:: bash + + barman restore SERVER_NAME BACKUP_ID REMOTE_RECOVERY_DIRECTORY \ + --remote-ssh-command 'ssh USER@HOST' \ + --snapshot-recovery-instance INSTANCE_NAME + +Barman will automatically recognize the backup as a snapshot and verify that the +attached disks were cloned from the corresponding snapshots. It will then prepare +Postgres for recovery by copying the backup label and WALs into place and adjusting the +Postgres configuration with the necessary recovery options. + +Provider-Specific Arguments +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For GCP: + +* ``--gcp-zone``: The availability zone where the recovery instance is located. If + omitted, Barman will use the ``gcp_zone`` value set in the server config. + +For Azure: + +* ``--azure-resource-group``: The resource group for the recovery instance. If not + provided, Barman will refer to the ``azure_resource_group`` value in the server config. + +For AWS: + +* ``--aws-region``: The AWS region of the recovery instance. If not specified, Barman + will default to the ``aws_region`` value set in the server config. \ No newline at end of file diff --git a/docs/user_guide/retention_policies.rst b/docs/user_guide/retention_policies.rst new file mode 100644 index 000000000..e1c1e4bd2 --- /dev/null +++ b/docs/user_guide/retention_policies.rst @@ -0,0 +1,255 @@ +.. _retention-policies: + +Retention policies +================== + +.. _retention-policies-overview: + +Overview +-------- + +A retention policy for backups is a set of strategic guidelines designed to manage how +backup copies of your data are handled over time. This policy outlines the rules and +guidelines for how long backups are kept, when they should be archived or deleted, and +how they are organized. Implementing a well-defined retention policy is essential for +ensuring data protection, optimizing storage use, and meeting compliance requirements. + +.. _retention-policies-key-components: + +Key Components of Retention Policies +------------------------------------ + +Understanding the key components of these policies is crucial for designing a system +that balances data protection, storage efficiency, and compliance. + +Retention Duration +"""""""""""""""""" + +* **Time-Based Retention**: This component specifies how long backups are retained, such + as keeping backups for a fixed period (e.g., 30 days, 1 year). Time-based retention is + straightforward and ensures that backups older than a certain age are automatically + deleted. +* **Quantity-Based Retention**: Alternatively, retention policies can be based on the + number of backups retained (e.g., the last 10 backups). This method is useful for + maintaining a specific number of recent backups, regardless of their age. + +Backup Types +"""""""""""" + +* **Full Backups**: These backups capture the entire dataset and are often retained + longer due to their comprehensive nature. Different retention policies may apply to + full backups compared to other types. +* **Incremental Backups**: Incremental backups capture changes since the last backup. + Retention policies for these backups may differ, reflecting their role in the backup + chain and their dependency on other backups. + +Cleanup Rules +""""""""""""" + +* **Automated Cleanup**: Effective retention policies include automated cleanup + mechanisms that identify and remove outdated backups according to predefined rules. + This reduces manual intervention and minimizes the risk of retaining unnecessary data. + +* **Archiving and Deletion**: Cleanup rules can specify whether old backups are archived + before deletion or if they are removed directly. Archiving can be useful for + maintaining historical data for compliance or other purposes. + +.. _retention-policies-key-objectives: + +Key Objectives of Retention Policies +------------------------------------ + +Implementing a robust retention policy is fundamental to effective backup management, +encompassing some key objectives: + +Ensuring Sufficient Data Protection +""""""""""""""""""""""""""""""""""" + +* **Historical Recovery**: Retention policies define the duration for which backups are + kept to facilitate recovery from various points in time. This is crucial for + recovering data not only from recent backups but also from older ones in case of data + loss, corruption, or inadvertent changes. +* **Recovery Flexibility**: By retaining backups over different periods, you can respond + to different types of data recovery scenarios, whether it's restoring the latest data, + addressing corruption issues, or undoing erroneous operations. + +Optimizing Storage Usage +"""""""""""""""""""""""" + +* **Efficient Storage Management**: Retention policies help prevent the accumulation of + obsolete backups that consume valuable storage space. This is achieved by setting + limits on the number of backups or the duration for which they are kept, thereby + optimizing storage utilization and managing costs effectively. +* **Cost Control**: By automating the cleanup of outdated backups, organizations can + avoid unnecessary expenses related to storage infrastructure and associated + maintenance. + +Compliance and Regulation +""""""""""""""""""""""""" + +* **Meeting Legal Requirements**: Many industries have specific regulations governing + data retention, which may dictate minimum retention periods for backups. A well-defined + retention policy ensures that these regulatory requirements are met, helping + organizations stay compliant with legal and industry standards. +* **Audit Readiness**: Proper retention policies facilitate easier audits by maintaining + a clear and organized backup history that demonstrates compliance with retention + regulations. + +.. _retention-policies-minimun-redundancy-safety: + +Minimum redundancy safety +------------------------- + +You can set a minimum number of backups for your Postgres server using the +``minimum_redundancy`` option in the global or per-server configuration. By default, this +option is set to 0. + +If you set ``minimum_redundancy`` to a number greater than 0, Barman will ensure that you +always have at least that many backups available on the server. + +This setting helps protect against accidental deletion of backups. + +.. note:: + Make sure your retention policy does not conflict with the minimum redundancy + setting. Check Barman's logs regularly for any related messages. + +.. _retention-policies-scope: + +Scope of retention policies +--------------------------- +Barman allows you to define retention policies by two methods. + +Backup Redundancy +""""""""""""""""" + +Specifies the number of backups to retain. Barman keeps the most recent backups up to the +specified number. This type of policy does not consider the time period for retention but +focuses on the number of backups. + +For example, if you set a redundancy of 3, Barman will retain the three most recent +backups and discard older ones. + +Recovery Window +""""""""""""""" + +Specifies the duration for which backups must be retained to allow recovery to any point +within that window. The interval window always ends at the current time and spans +backward for the specified period. Barman retains backups and archive logs necessary for +point-in-time recovery to any moment within this window. + +For example, if you set a 7-day recovery window, Barman will keep backups and WAL files +to allow recovery to any point within the past 7 days. This means that the first backup +that falls outside the window will still be retained with its corresponding WALs, but +backups before this one and all the older WALs will be marked as obsolete and eventually +be evicted. + +Keep command +"""""""""""" + +The ``keep`` command can be used to mark a specific backup so its kept indefinitely. +This overrides the retention policy explained earlier for that backup. You can find +more information on the ``keep`` command in the +:ref:`Barman keep command documentation `. + +.. _retention-policies-use-cases: + +Use cases +--------- + +Point-In-Time Recovery +"""""""""""""""""""""" + +Base backups and archived WAL files have the same retention policy. This setup allows +you to recover the data from your Postgres server to any point in time from the end +time of the earliest available backup. + +Operational Efficiency and Space Management +""""""""""""""""""""""""""""""""""""""""""" + +You may want to maintain a certain number of recent backups while periodically removing +older ones to save on storage cost and manage storage space effectively, especially in +environments with limited resources. + +Long-Term Archival +"""""""""""""""""" + +For compliance or historical purposes, you may need to retain backups for extended +periods beyond the usual operational requirements. This is often required in regulated +industries where data must be kept for a certain period. + +.. _retention-policies-how-retention-policies-are-enforced: + +How retention policies are enforced +----------------------------------- + +Retention policies in Barman are enforced automatically by Barman's maintenance tasks +which are executed by ``barman cron``. + +.. _retention-policies-configuration-and-syntax: + +Configurations and Syntax +------------------------- + +Retention policies are configured globally or per server using the ``retention_policy`` +option offering flexibility in a multi-server environment. By default, the value of the +``retention_policy`` option is not set, so no retention is enforced. + +Retention policies have the following syntax: + +``retention_policy = {REDUNDANCY value | RECOVERY WINDOW OF value {DAYS | WEEKS | MONTHS}}`` + +* value must be an integer greater than 0. +* For backup redundancy, value must meet or exceed the server's minimum redundancy + level. +* For recovery window, value must be at least as high as the server's minimum + redundancy level in reverse order. +* If value is not assigned, a warning is generated. + +.. important:: + Block-level incremental backups are not considered in retention policies, as they + depend on their parent backups and the root backup. Only the root backup is used + to determine retention. + +.. _retention-policies-retention-policy-for-block-level-incremental-backups: + +Retention policy for block-level incremental backups +---------------------------------------------------- + +When retention policy is applied: + +* Barman will focus on the root backup. +* If the root backup is marked as ``KEEP:FULL``, all associated incremental backups are + marked as ``VALID``, regardless of whether the root backup is within the retention + policy. +* If the root backup is marked as ``KEEP:STANDALONE``and is still within the retention + policy, all associated incremental backups are marked as ``VALID``. However, if the + root backup is outside the retention policy, all associated incremental backups are + marked as ``OBSOLETE``. +* If the root backup is not marked with a ``KEEP`` flag, all associated incremental + backups inherit the same label. For instance, if the root backup is marked as + ``OBSOLETE``, all associated incremental backups are also marked as ``OBSOLETE``. + +.. _retention-policies-retention-policy-for-cloud-backups: + +Retention policy for Cloud Backups +---------------------------------- + +We can have two scenarios for Cloud Backups: + +1. Using :ref:`snapshots backups ` with a Barman Server + as the centralized Backup and Recovery manager. +2. Using :ref:`cloud backups ` with cloud object storages + to manage backups without a Barman Server. + +In the first scenario, Barman uses ``cron`` for maintenance operations and enforcing the +retention policy, as outlined in +:ref:`retention-policies-how-retention-policies-are-enforced`. In this case, ``snapshot`` +backups are treated the same as any other ``rsync`` or ``postgres`` backup. + +In the second scenario, since there is no Barman server, you won't have cron for +maintenance operations for enforcing the retention policy. Instead, you'll need to use +``barman-cloud-backup-delete`` with the ``-r RETENTION_POLICY`` option (see the +:ref:`command reference `). This will delete +any backups that do not meet the specified retention policy. Additionally, you can also +schedule these commands using hook scripts or custom scripts to simulate cron +maintenance for cloud backups. diff --git a/docs/user_guide/wal_archiving.rst b/docs/user_guide/wal_archiving.rst new file mode 100644 index 000000000..f86b46941 --- /dev/null +++ b/docs/user_guide/wal_archiving.rst @@ -0,0 +1,114 @@ +.. _wal_archiving: + +WAL archiving +============= + +Barman also offers additional features regarding WAL archiving. + +.. _wal_archiving-wal-compression: + +WAL compression +--------------- + +Barman can compress WAL files as they enter the Barman's WAL archive. This process is +handled automatically by ``barman cron`` or when the ``barman archive-wal`` command is +executed manually. + +Compression is enabled via the ``compression`` option in the configuration file. +The option can use one of the following values: + +* ``lz4``: for LZ4 compression (requires the ``lz4`` library to be installed); +* ``xz``: for XZ compression (uses Python's internal compression library); +* ``zstd``: for Zstandard compression (requires the ``zstandard`` library to be + installed); +* ``gzip``: for Gzip compression (requires the ``gzip`` utility); +* ``pygzip``: for Gzip compression (uses Python's internal compression library); +* ``pigz``: for Pigz compression (requires the ``pigz`` utility); +* ``bzip2``: for Bzip2 compression (requires the ``bzip2`` utility); +* ``pybzip2``: for Bzip2 compression (uses Python's internal compression library); +* ``custom``: for custom compression, which requires you to set the following options + as well: ``custom_compression_filter``, ``custom_decompression_filter``, + ``custom_compression_magic``. Check :ref:`configuration-options-wals` for details. + +.. note:: + When using options such as ``bzip2``, ``gzip`` and ``pigz`` Barman will fork a new + process for compression. + + +.. _wal_archiving-synchronous-WAL-streaming: + +Synchronous WAL streaming +------------------------- + +Barman can also reduce the :term:`RPO` to zero, by collecting the transaction WAL files +like a synchronous standby server would. + +To configure a scenario with :term:`RPO` zero, the Barman server must be configured to archive WALs via +a streaming connection and the receive-wal process has to be configured as a +synchronous connection to the Postgres server. + +First, you need to retrieve the application name of the Barman receive-wal process with the +``show-servers`` command: + +.. code-block:: bash + + barman show-servers pg | grep streaming_archiver_name + +Output: + +.. code-block:: text + + streaming_archiver_name: barman_receive_wal + +.. note:: + + The application name Barman uses when starting the receive-wal process is configured + with the ``streaming_archiver_name`` configuration option. The default value for this + option is ``barman_receive_wal``. + +Then the application name should be added to the ``synchronous_standby_names`` +parameter in the ``postgresql.conf`` file: + +.. code-block:: bash + + synchronous_standby_names = 'barman_receive_wal' + + +.. important:: + + Barman with :term:`RPO` zero adds more security to your backups and gives you more + recovery options. However, it should not be considered as a substitution of a + real Postgres replica. Please read the `official Postgres documentation about + "Syncronous Replication" `_ + for more information on this topic. + +The Postgres server configuration needs to be reloaded for the changes to take effect. + +If the server has been configured correctly, the ``barman replication-status`` command +should show the receive-wal process as a synchronous streaming client: + +.. code-block:: bash + + barman replication-status pg + +Output: + +.. code-block:: text + + Status of streaming clients for server 'pg': + Current xlog location on master: 0/9000098 + Number of streaming clients: 1 + + 1. #1 Sync WAL streamer + Application name: barman_receive_wal + Sync stage : 3/3 Remote write + Communication : TCP/IP + IP Address : 139.59.135.32 / Port: 58262 / Host: - + User name : streaming_barman + Current state : streaming (sync) + Replication slot: barman + WAL sender PID : 2501 + Started at : 2016-09-16 10:33:01.725883+00:00 + Sent location : 0/9000098 (diff: 0 B) + Write location : 0/9000098 (diff: 0 B) + Flush location : 0/9000098 (diff: 0 B) diff --git a/doc/.gitignore b/old_docs/.gitignore similarity index 100% rename from doc/.gitignore rename to old_docs/.gitignore diff --git a/doc/Dockerfile b/old_docs/Dockerfile similarity index 100% rename from doc/Dockerfile rename to old_docs/Dockerfile diff --git a/doc/Makefile b/old_docs/Makefile similarity index 100% rename from doc/Makefile rename to old_docs/Makefile diff --git a/doc/barman-cloud-backup-delete.1 b/old_docs/barman-cloud-backup-delete.1 similarity index 100% rename from doc/barman-cloud-backup-delete.1 rename to old_docs/barman-cloud-backup-delete.1 diff --git a/doc/barman-cloud-backup-delete.1.md b/old_docs/barman-cloud-backup-delete.1.md similarity index 100% rename from doc/barman-cloud-backup-delete.1.md rename to old_docs/barman-cloud-backup-delete.1.md diff --git a/doc/barman-cloud-backup-keep.1 b/old_docs/barman-cloud-backup-keep.1 similarity index 100% rename from doc/barman-cloud-backup-keep.1 rename to old_docs/barman-cloud-backup-keep.1 diff --git a/doc/barman-cloud-backup-keep.1.md b/old_docs/barman-cloud-backup-keep.1.md similarity index 100% rename from doc/barman-cloud-backup-keep.1.md rename to old_docs/barman-cloud-backup-keep.1.md diff --git a/doc/barman-cloud-backup-list.1 b/old_docs/barman-cloud-backup-list.1 similarity index 100% rename from doc/barman-cloud-backup-list.1 rename to old_docs/barman-cloud-backup-list.1 diff --git a/doc/barman-cloud-backup-list.1.md b/old_docs/barman-cloud-backup-list.1.md similarity index 100% rename from doc/barman-cloud-backup-list.1.md rename to old_docs/barman-cloud-backup-list.1.md diff --git a/doc/barman-cloud-backup-show.1 b/old_docs/barman-cloud-backup-show.1 similarity index 100% rename from doc/barman-cloud-backup-show.1 rename to old_docs/barman-cloud-backup-show.1 diff --git a/doc/barman-cloud-backup-show.1.md b/old_docs/barman-cloud-backup-show.1.md similarity index 100% rename from doc/barman-cloud-backup-show.1.md rename to old_docs/barman-cloud-backup-show.1.md diff --git a/doc/barman-cloud-backup.1 b/old_docs/barman-cloud-backup.1 similarity index 100% rename from doc/barman-cloud-backup.1 rename to old_docs/barman-cloud-backup.1 diff --git a/doc/barman-cloud-backup.1.md b/old_docs/barman-cloud-backup.1.md similarity index 100% rename from doc/barman-cloud-backup.1.md rename to old_docs/barman-cloud-backup.1.md diff --git a/doc/barman-cloud-check-wal-archive.1 b/old_docs/barman-cloud-check-wal-archive.1 similarity index 100% rename from doc/barman-cloud-check-wal-archive.1 rename to old_docs/barman-cloud-check-wal-archive.1 diff --git a/doc/barman-cloud-check-wal-archive.1.md b/old_docs/barman-cloud-check-wal-archive.1.md similarity index 100% rename from doc/barman-cloud-check-wal-archive.1.md rename to old_docs/barman-cloud-check-wal-archive.1.md diff --git a/doc/barman-cloud-restore.1 b/old_docs/barman-cloud-restore.1 similarity index 100% rename from doc/barman-cloud-restore.1 rename to old_docs/barman-cloud-restore.1 diff --git a/doc/barman-cloud-restore.1.md b/old_docs/barman-cloud-restore.1.md similarity index 100% rename from doc/barman-cloud-restore.1.md rename to old_docs/barman-cloud-restore.1.md diff --git a/doc/barman-cloud-wal-archive.1 b/old_docs/barman-cloud-wal-archive.1 similarity index 100% rename from doc/barman-cloud-wal-archive.1 rename to old_docs/barman-cloud-wal-archive.1 diff --git a/doc/barman-cloud-wal-archive.1.md b/old_docs/barman-cloud-wal-archive.1.md similarity index 100% rename from doc/barman-cloud-wal-archive.1.md rename to old_docs/barman-cloud-wal-archive.1.md diff --git a/doc/barman-cloud-wal-restore.1 b/old_docs/barman-cloud-wal-restore.1 similarity index 100% rename from doc/barman-cloud-wal-restore.1 rename to old_docs/barman-cloud-wal-restore.1 diff --git a/doc/barman-cloud-wal-restore.1.md b/old_docs/barman-cloud-wal-restore.1.md similarity index 100% rename from doc/barman-cloud-wal-restore.1.md rename to old_docs/barman-cloud-wal-restore.1.md diff --git a/doc/barman-wal-archive.1 b/old_docs/barman-wal-archive.1 similarity index 100% rename from doc/barman-wal-archive.1 rename to old_docs/barman-wal-archive.1 diff --git a/doc/barman-wal-archive.1.md b/old_docs/barman-wal-archive.1.md similarity index 100% rename from doc/barman-wal-archive.1.md rename to old_docs/barman-wal-archive.1.md diff --git a/doc/barman-wal-restore.1 b/old_docs/barman-wal-restore.1 similarity index 100% rename from doc/barman-wal-restore.1 rename to old_docs/barman-wal-restore.1 diff --git a/doc/barman-wal-restore.1.md b/old_docs/barman-wal-restore.1.md similarity index 100% rename from doc/barman-wal-restore.1.md rename to old_docs/barman-wal-restore.1.md diff --git a/doc/barman.1 b/old_docs/barman.1 similarity index 100% rename from doc/barman.1 rename to old_docs/barman.1 diff --git a/doc/barman.1.d/00-header.md b/old_docs/barman.1.d/00-header.md similarity index 100% rename from doc/barman.1.d/00-header.md rename to old_docs/barman.1.d/00-header.md diff --git a/doc/barman.1.d/05-name.md b/old_docs/barman.1.d/05-name.md similarity index 100% rename from doc/barman.1.d/05-name.md rename to old_docs/barman.1.d/05-name.md diff --git a/doc/barman.1.d/10-synopsis.md b/old_docs/barman.1.d/10-synopsis.md similarity index 100% rename from doc/barman.1.d/10-synopsis.md rename to old_docs/barman.1.d/10-synopsis.md diff --git a/doc/barman.1.d/15-description.md b/old_docs/barman.1.d/15-description.md similarity index 100% rename from doc/barman.1.d/15-description.md rename to old_docs/barman.1.d/15-description.md diff --git a/doc/barman.1.d/20-options.md b/old_docs/barman.1.d/20-options.md similarity index 100% rename from doc/barman.1.d/20-options.md rename to old_docs/barman.1.d/20-options.md diff --git a/doc/barman.1.d/45-commands.md b/old_docs/barman.1.d/45-commands.md similarity index 100% rename from doc/barman.1.d/45-commands.md rename to old_docs/barman.1.d/45-commands.md diff --git a/doc/barman.1.d/50-archive-wal.md b/old_docs/barman.1.d/50-archive-wal.md similarity index 100% rename from doc/barman.1.d/50-archive-wal.md rename to old_docs/barman.1.d/50-archive-wal.md diff --git a/doc/barman.1.d/50-backup.md b/old_docs/barman.1.d/50-backup.md similarity index 100% rename from doc/barman.1.d/50-backup.md rename to old_docs/barman.1.d/50-backup.md diff --git a/doc/barman.1.d/50-check-backup.md b/old_docs/barman.1.d/50-check-backup.md similarity index 100% rename from doc/barman.1.d/50-check-backup.md rename to old_docs/barman.1.d/50-check-backup.md diff --git a/doc/barman.1.d/50-check-wal-archive.md b/old_docs/barman.1.d/50-check-wal-archive.md similarity index 100% rename from doc/barman.1.d/50-check-wal-archive.md rename to old_docs/barman.1.d/50-check-wal-archive.md diff --git a/doc/barman.1.d/50-check.md b/old_docs/barman.1.d/50-check.md similarity index 100% rename from doc/barman.1.d/50-check.md rename to old_docs/barman.1.d/50-check.md diff --git a/doc/barman.1.d/50-config-switch.md b/old_docs/barman.1.d/50-config-switch.md similarity index 100% rename from doc/barman.1.d/50-config-switch.md rename to old_docs/barman.1.d/50-config-switch.md diff --git a/doc/barman.1.d/50-config-update.md b/old_docs/barman.1.d/50-config-update.md similarity index 100% rename from doc/barman.1.d/50-config-update.md rename to old_docs/barman.1.d/50-config-update.md diff --git a/doc/barman.1.d/50-cron.md b/old_docs/barman.1.d/50-cron.md similarity index 100% rename from doc/barman.1.d/50-cron.md rename to old_docs/barman.1.d/50-cron.md diff --git a/doc/barman.1.d/50-delete.md b/old_docs/barman.1.d/50-delete.md similarity index 100% rename from doc/barman.1.d/50-delete.md rename to old_docs/barman.1.d/50-delete.md diff --git a/doc/barman.1.d/50-diagnose.md b/old_docs/barman.1.d/50-diagnose.md similarity index 100% rename from doc/barman.1.d/50-diagnose.md rename to old_docs/barman.1.d/50-diagnose.md diff --git a/doc/barman.1.d/50-generate-manifest.md b/old_docs/barman.1.d/50-generate-manifest.md similarity index 100% rename from doc/barman.1.d/50-generate-manifest.md rename to old_docs/barman.1.d/50-generate-manifest.md diff --git a/doc/barman.1.d/50-get-wal.md b/old_docs/barman.1.d/50-get-wal.md similarity index 100% rename from doc/barman.1.d/50-get-wal.md rename to old_docs/barman.1.d/50-get-wal.md diff --git a/doc/barman.1.d/50-keep.md b/old_docs/barman.1.d/50-keep.md similarity index 100% rename from doc/barman.1.d/50-keep.md rename to old_docs/barman.1.d/50-keep.md diff --git a/doc/barman.1.d/50-list-backups.md b/old_docs/barman.1.d/50-list-backups.md similarity index 100% rename from doc/barman.1.d/50-list-backups.md rename to old_docs/barman.1.d/50-list-backups.md diff --git a/doc/barman.1.d/50-list-files.md b/old_docs/barman.1.d/50-list-files.md similarity index 100% rename from doc/barman.1.d/50-list-files.md rename to old_docs/barman.1.d/50-list-files.md diff --git a/doc/barman.1.d/50-list-servers.md b/old_docs/barman.1.d/50-list-servers.md similarity index 100% rename from doc/barman.1.d/50-list-servers.md rename to old_docs/barman.1.d/50-list-servers.md diff --git a/doc/barman.1.d/50-lock-directory-cleanup.md b/old_docs/barman.1.d/50-lock-directory-cleanup.md similarity index 100% rename from doc/barman.1.d/50-lock-directory-cleanup.md rename to old_docs/barman.1.d/50-lock-directory-cleanup.md diff --git a/doc/barman.1.d/50-put-wal.md b/old_docs/barman.1.d/50-put-wal.md similarity index 100% rename from doc/barman.1.d/50-put-wal.md rename to old_docs/barman.1.d/50-put-wal.md diff --git a/doc/barman.1.d/50-rebuild-xlogdb.md b/old_docs/barman.1.d/50-rebuild-xlogdb.md similarity index 100% rename from doc/barman.1.d/50-rebuild-xlogdb.md rename to old_docs/barman.1.d/50-rebuild-xlogdb.md diff --git a/doc/barman.1.d/50-receive-wal.md b/old_docs/barman.1.d/50-receive-wal.md similarity index 100% rename from doc/barman.1.d/50-receive-wal.md rename to old_docs/barman.1.d/50-receive-wal.md diff --git a/doc/barman.1.d/50-recover.md b/old_docs/barman.1.d/50-recover.md similarity index 100% rename from doc/barman.1.d/50-recover.md rename to old_docs/barman.1.d/50-recover.md diff --git a/doc/barman.1.d/50-replication-status.md b/old_docs/barman.1.d/50-replication-status.md similarity index 100% rename from doc/barman.1.d/50-replication-status.md rename to old_docs/barman.1.d/50-replication-status.md diff --git a/doc/barman.1.d/50-show-backup.md b/old_docs/barman.1.d/50-show-backup.md similarity index 100% rename from doc/barman.1.d/50-show-backup.md rename to old_docs/barman.1.d/50-show-backup.md diff --git a/doc/barman.1.d/50-show-servers.md b/old_docs/barman.1.d/50-show-servers.md similarity index 100% rename from doc/barman.1.d/50-show-servers.md rename to old_docs/barman.1.d/50-show-servers.md diff --git a/doc/barman.1.d/50-status.md b/old_docs/barman.1.d/50-status.md similarity index 100% rename from doc/barman.1.d/50-status.md rename to old_docs/barman.1.d/50-status.md diff --git a/doc/barman.1.d/50-switch-wal.md b/old_docs/barman.1.d/50-switch-wal.md similarity index 100% rename from doc/barman.1.d/50-switch-wal.md rename to old_docs/barman.1.d/50-switch-wal.md diff --git a/doc/barman.1.d/50-switch-xlog.md b/old_docs/barman.1.d/50-switch-xlog.md similarity index 100% rename from doc/barman.1.d/50-switch-xlog.md rename to old_docs/barman.1.d/50-switch-xlog.md diff --git a/doc/barman.1.d/50-sync-backup.md b/old_docs/barman.1.d/50-sync-backup.md similarity index 100% rename from doc/barman.1.d/50-sync-backup.md rename to old_docs/barman.1.d/50-sync-backup.md diff --git a/doc/barman.1.d/50-sync-info.md b/old_docs/barman.1.d/50-sync-info.md similarity index 100% rename from doc/barman.1.d/50-sync-info.md rename to old_docs/barman.1.d/50-sync-info.md diff --git a/doc/barman.1.d/50-sync-wals.md b/old_docs/barman.1.d/50-sync-wals.md similarity index 100% rename from doc/barman.1.d/50-sync-wals.md rename to old_docs/barman.1.d/50-sync-wals.md diff --git a/doc/barman.1.d/50-verify-backup.md b/old_docs/barman.1.d/50-verify-backup.md similarity index 100% rename from doc/barman.1.d/50-verify-backup.md rename to old_docs/barman.1.d/50-verify-backup.md diff --git a/doc/barman.1.d/50-verify.md b/old_docs/barman.1.d/50-verify.md similarity index 100% rename from doc/barman.1.d/50-verify.md rename to old_docs/barman.1.d/50-verify.md diff --git a/doc/barman.1.d/70-backup-id-shortcuts.md b/old_docs/barman.1.d/70-backup-id-shortcuts.md similarity index 100% rename from doc/barman.1.d/70-backup-id-shortcuts.md rename to old_docs/barman.1.d/70-backup-id-shortcuts.md diff --git a/doc/barman.1.d/75-exit-status.md b/old_docs/barman.1.d/75-exit-status.md similarity index 100% rename from doc/barman.1.d/75-exit-status.md rename to old_docs/barman.1.d/75-exit-status.md diff --git a/doc/barman.1.d/80-see-also.md b/old_docs/barman.1.d/80-see-also.md similarity index 100% rename from doc/barman.1.d/80-see-also.md rename to old_docs/barman.1.d/80-see-also.md diff --git a/doc/barman.1.d/85-bugs.md b/old_docs/barman.1.d/85-bugs.md similarity index 100% rename from doc/barman.1.d/85-bugs.md rename to old_docs/barman.1.d/85-bugs.md diff --git a/doc/barman.1.d/90-authors.md b/old_docs/barman.1.d/90-authors.md similarity index 100% rename from doc/barman.1.d/90-authors.md rename to old_docs/barman.1.d/90-authors.md diff --git a/doc/barman.1.d/95-resources.md b/old_docs/barman.1.d/95-resources.md similarity index 100% rename from doc/barman.1.d/95-resources.md rename to old_docs/barman.1.d/95-resources.md diff --git a/doc/barman.1.d/99-copying.md b/old_docs/barman.1.d/99-copying.md similarity index 100% rename from doc/barman.1.d/99-copying.md rename to old_docs/barman.1.d/99-copying.md diff --git a/doc/barman.5 b/old_docs/barman.5 similarity index 100% rename from doc/barman.5 rename to old_docs/barman.5 diff --git a/doc/barman.5.d/00-header.md b/old_docs/barman.5.d/00-header.md similarity index 100% rename from doc/barman.5.d/00-header.md rename to old_docs/barman.5.d/00-header.md diff --git a/doc/barman.5.d/05-name.md b/old_docs/barman.5.d/05-name.md similarity index 100% rename from doc/barman.5.d/05-name.md rename to old_docs/barman.5.d/05-name.md diff --git a/doc/barman.5.d/15-description.md b/old_docs/barman.5.d/15-description.md similarity index 100% rename from doc/barman.5.d/15-description.md rename to old_docs/barman.5.d/15-description.md diff --git a/doc/barman.5.d/20-configuration-file-locations.md b/old_docs/barman.5.d/20-configuration-file-locations.md similarity index 100% rename from doc/barman.5.d/20-configuration-file-locations.md rename to old_docs/barman.5.d/20-configuration-file-locations.md diff --git a/doc/barman.5.d/25-configuration-file-syntax.md b/old_docs/barman.5.d/25-configuration-file-syntax.md similarity index 100% rename from doc/barman.5.d/25-configuration-file-syntax.md rename to old_docs/barman.5.d/25-configuration-file-syntax.md diff --git a/doc/barman.5.d/30-configuration-file-directory.md b/old_docs/barman.5.d/30-configuration-file-directory.md similarity index 100% rename from doc/barman.5.d/30-configuration-file-directory.md rename to old_docs/barman.5.d/30-configuration-file-directory.md diff --git a/doc/barman.5.d/45-options.md b/old_docs/barman.5.d/45-options.md similarity index 100% rename from doc/barman.5.d/45-options.md rename to old_docs/barman.5.d/45-options.md diff --git a/doc/barman.5.d/50-active.md b/old_docs/barman.5.d/50-active.md similarity index 100% rename from doc/barman.5.d/50-active.md rename to old_docs/barman.5.d/50-active.md diff --git a/doc/barman.5.d/50-archiver.md b/old_docs/barman.5.d/50-archiver.md similarity index 100% rename from doc/barman.5.d/50-archiver.md rename to old_docs/barman.5.d/50-archiver.md diff --git a/doc/barman.5.d/50-archiver_batch_size.md b/old_docs/barman.5.d/50-archiver_batch_size.md similarity index 100% rename from doc/barman.5.d/50-archiver_batch_size.md rename to old_docs/barman.5.d/50-archiver_batch_size.md diff --git a/doc/barman.5.d/50-autogenerate_manifest.md b/old_docs/barman.5.d/50-autogenerate_manifest.md similarity index 100% rename from doc/barman.5.d/50-autogenerate_manifest.md rename to old_docs/barman.5.d/50-autogenerate_manifest.md diff --git a/doc/barman.5.d/50-aws_await_snapshots_timeout.md b/old_docs/barman.5.d/50-aws_await_snapshots_timeout.md similarity index 100% rename from doc/barman.5.d/50-aws_await_snapshots_timeout.md rename to old_docs/barman.5.d/50-aws_await_snapshots_timeout.md diff --git a/doc/barman.5.d/50-aws_profile.md b/old_docs/barman.5.d/50-aws_profile.md similarity index 100% rename from doc/barman.5.d/50-aws_profile.md rename to old_docs/barman.5.d/50-aws_profile.md diff --git a/doc/barman.5.d/50-aws_region.md b/old_docs/barman.5.d/50-aws_region.md similarity index 100% rename from doc/barman.5.d/50-aws_region.md rename to old_docs/barman.5.d/50-aws_region.md diff --git a/doc/barman.5.d/50-azure_credential.md b/old_docs/barman.5.d/50-azure_credential.md similarity index 100% rename from doc/barman.5.d/50-azure_credential.md rename to old_docs/barman.5.d/50-azure_credential.md diff --git a/doc/barman.5.d/50-azure_resource_group.md b/old_docs/barman.5.d/50-azure_resource_group.md similarity index 100% rename from doc/barman.5.d/50-azure_resource_group.md rename to old_docs/barman.5.d/50-azure_resource_group.md diff --git a/doc/barman.5.d/50-azure_subscription_id.md b/old_docs/barman.5.d/50-azure_subscription_id.md similarity index 100% rename from doc/barman.5.d/50-azure_subscription_id.md rename to old_docs/barman.5.d/50-azure_subscription_id.md diff --git a/doc/barman.5.d/50-backup_compression.md b/old_docs/barman.5.d/50-backup_compression.md similarity index 100% rename from doc/barman.5.d/50-backup_compression.md rename to old_docs/barman.5.d/50-backup_compression.md diff --git a/doc/barman.5.d/50-backup_compression_format.md b/old_docs/barman.5.d/50-backup_compression_format.md similarity index 100% rename from doc/barman.5.d/50-backup_compression_format.md rename to old_docs/barman.5.d/50-backup_compression_format.md diff --git a/doc/barman.5.d/50-backup_compression_level.md b/old_docs/barman.5.d/50-backup_compression_level.md similarity index 100% rename from doc/barman.5.d/50-backup_compression_level.md rename to old_docs/barman.5.d/50-backup_compression_level.md diff --git a/doc/barman.5.d/50-backup_compression_location.md b/old_docs/barman.5.d/50-backup_compression_location.md similarity index 100% rename from doc/barman.5.d/50-backup_compression_location.md rename to old_docs/barman.5.d/50-backup_compression_location.md diff --git a/doc/barman.5.d/50-backup_compression_workers.md b/old_docs/barman.5.d/50-backup_compression_workers.md similarity index 100% rename from doc/barman.5.d/50-backup_compression_workers.md rename to old_docs/barman.5.d/50-backup_compression_workers.md diff --git a/doc/barman.5.d/50-backup_directory.md b/old_docs/barman.5.d/50-backup_directory.md similarity index 100% rename from doc/barman.5.d/50-backup_directory.md rename to old_docs/barman.5.d/50-backup_directory.md diff --git a/doc/barman.5.d/50-backup_method.md b/old_docs/barman.5.d/50-backup_method.md similarity index 100% rename from doc/barman.5.d/50-backup_method.md rename to old_docs/barman.5.d/50-backup_method.md diff --git a/doc/barman.5.d/50-backup_options.md b/old_docs/barman.5.d/50-backup_options.md similarity index 100% rename from doc/barman.5.d/50-backup_options.md rename to old_docs/barman.5.d/50-backup_options.md diff --git a/doc/barman.5.d/50-bandwidth_limit.md b/old_docs/barman.5.d/50-bandwidth_limit.md similarity index 100% rename from doc/barman.5.d/50-bandwidth_limit.md rename to old_docs/barman.5.d/50-bandwidth_limit.md diff --git a/doc/barman.5.d/50-barman_home.md b/old_docs/barman.5.d/50-barman_home.md similarity index 100% rename from doc/barman.5.d/50-barman_home.md rename to old_docs/barman.5.d/50-barman_home.md diff --git a/doc/barman.5.d/50-barman_lock_directory.md b/old_docs/barman.5.d/50-barman_lock_directory.md similarity index 100% rename from doc/barman.5.d/50-barman_lock_directory.md rename to old_docs/barman.5.d/50-barman_lock_directory.md diff --git a/doc/barman.5.d/50-basebackup_retry_sleep.md b/old_docs/barman.5.d/50-basebackup_retry_sleep.md similarity index 100% rename from doc/barman.5.d/50-basebackup_retry_sleep.md rename to old_docs/barman.5.d/50-basebackup_retry_sleep.md diff --git a/doc/barman.5.d/50-basebackup_retry_times.md b/old_docs/barman.5.d/50-basebackup_retry_times.md similarity index 100% rename from doc/barman.5.d/50-basebackup_retry_times.md rename to old_docs/barman.5.d/50-basebackup_retry_times.md diff --git a/doc/barman.5.d/50-basebackups_directory.md b/old_docs/barman.5.d/50-basebackups_directory.md similarity index 100% rename from doc/barman.5.d/50-basebackups_directory.md rename to old_docs/barman.5.d/50-basebackups_directory.md diff --git a/doc/barman.5.d/50-check_timeout.md b/old_docs/barman.5.d/50-check_timeout.md similarity index 100% rename from doc/barman.5.d/50-check_timeout.md rename to old_docs/barman.5.d/50-check_timeout.md diff --git a/doc/barman.5.d/50-cluster.md b/old_docs/barman.5.d/50-cluster.md similarity index 100% rename from doc/barman.5.d/50-cluster.md rename to old_docs/barman.5.d/50-cluster.md diff --git a/doc/barman.5.d/50-compression.md b/old_docs/barman.5.d/50-compression.md similarity index 100% rename from doc/barman.5.d/50-compression.md rename to old_docs/barman.5.d/50-compression.md diff --git a/doc/barman.5.d/50-config_changes_queue.md b/old_docs/barman.5.d/50-config_changes_queue.md similarity index 100% rename from doc/barman.5.d/50-config_changes_queue.md rename to old_docs/barman.5.d/50-config_changes_queue.md diff --git a/doc/barman.5.d/50-conninfo.md b/old_docs/barman.5.d/50-conninfo.md similarity index 100% rename from doc/barman.5.d/50-conninfo.md rename to old_docs/barman.5.d/50-conninfo.md diff --git a/doc/barman.5.d/50-create_slot.md b/old_docs/barman.5.d/50-create_slot.md similarity index 100% rename from doc/barman.5.d/50-create_slot.md rename to old_docs/barman.5.d/50-create_slot.md diff --git a/doc/barman.5.d/50-custom_compression_filter.md b/old_docs/barman.5.d/50-custom_compression_filter.md similarity index 100% rename from doc/barman.5.d/50-custom_compression_filter.md rename to old_docs/barman.5.d/50-custom_compression_filter.md diff --git a/doc/barman.5.d/50-custom_compression_magic.md b/old_docs/barman.5.d/50-custom_compression_magic.md similarity index 100% rename from doc/barman.5.d/50-custom_compression_magic.md rename to old_docs/barman.5.d/50-custom_compression_magic.md diff --git a/doc/barman.5.d/50-custom_decompression_filter.md b/old_docs/barman.5.d/50-custom_decompression_filter.md similarity index 100% rename from doc/barman.5.d/50-custom_decompression_filter.md rename to old_docs/barman.5.d/50-custom_decompression_filter.md diff --git a/doc/barman.5.d/50-description.md b/old_docs/barman.5.d/50-description.md similarity index 100% rename from doc/barman.5.d/50-description.md rename to old_docs/barman.5.d/50-description.md diff --git a/doc/barman.5.d/50-errors_directory.md b/old_docs/barman.5.d/50-errors_directory.md similarity index 100% rename from doc/barman.5.d/50-errors_directory.md rename to old_docs/barman.5.d/50-errors_directory.md diff --git a/doc/barman.5.d/50-forward-config-path.md b/old_docs/barman.5.d/50-forward-config-path.md similarity index 100% rename from doc/barman.5.d/50-forward-config-path.md rename to old_docs/barman.5.d/50-forward-config-path.md diff --git a/doc/barman.5.d/50-gcp-project.md b/old_docs/barman.5.d/50-gcp-project.md similarity index 100% rename from doc/barman.5.d/50-gcp-project.md rename to old_docs/barman.5.d/50-gcp-project.md diff --git a/doc/barman.5.d/50-gcp-zone.md b/old_docs/barman.5.d/50-gcp-zone.md similarity index 100% rename from doc/barman.5.d/50-gcp-zone.md rename to old_docs/barman.5.d/50-gcp-zone.md diff --git a/doc/barman.5.d/50-immediate_checkpoint.md b/old_docs/barman.5.d/50-immediate_checkpoint.md similarity index 100% rename from doc/barman.5.d/50-immediate_checkpoint.md rename to old_docs/barman.5.d/50-immediate_checkpoint.md diff --git a/doc/barman.5.d/50-incoming_wals_directory.md b/old_docs/barman.5.d/50-incoming_wals_directory.md similarity index 100% rename from doc/barman.5.d/50-incoming_wals_directory.md rename to old_docs/barman.5.d/50-incoming_wals_directory.md diff --git a/doc/barman.5.d/50-keepalive-interval.md b/old_docs/barman.5.d/50-keepalive-interval.md similarity index 100% rename from doc/barman.5.d/50-keepalive-interval.md rename to old_docs/barman.5.d/50-keepalive-interval.md diff --git a/doc/barman.5.d/50-last_backup_maximum_age.md b/old_docs/barman.5.d/50-last_backup_maximum_age.md similarity index 100% rename from doc/barman.5.d/50-last_backup_maximum_age.md rename to old_docs/barman.5.d/50-last_backup_maximum_age.md diff --git a/doc/barman.5.d/50-last_backup_minimum_size.md b/old_docs/barman.5.d/50-last_backup_minimum_size.md similarity index 100% rename from doc/barman.5.d/50-last_backup_minimum_size.md rename to old_docs/barman.5.d/50-last_backup_minimum_size.md diff --git a/doc/barman.5.d/50-last_wal_maximum_age.md b/old_docs/barman.5.d/50-last_wal_maximum_age.md similarity index 100% rename from doc/barman.5.d/50-last_wal_maximum_age.md rename to old_docs/barman.5.d/50-last_wal_maximum_age.md diff --git a/doc/barman.5.d/50-local_staging_path.md b/old_docs/barman.5.d/50-local_staging_path.md similarity index 100% rename from doc/barman.5.d/50-local_staging_path.md rename to old_docs/barman.5.d/50-local_staging_path.md diff --git a/doc/barman.5.d/50-lock_directory_cleanup.md b/old_docs/barman.5.d/50-lock_directory_cleanup.md similarity index 100% rename from doc/barman.5.d/50-lock_directory_cleanup.md rename to old_docs/barman.5.d/50-lock_directory_cleanup.md diff --git a/doc/barman.5.d/50-log_file.md b/old_docs/barman.5.d/50-log_file.md similarity index 100% rename from doc/barman.5.d/50-log_file.md rename to old_docs/barman.5.d/50-log_file.md diff --git a/doc/barman.5.d/50-log_level.md b/old_docs/barman.5.d/50-log_level.md similarity index 100% rename from doc/barman.5.d/50-log_level.md rename to old_docs/barman.5.d/50-log_level.md diff --git a/doc/barman.5.d/50-max_incoming_wals_queue.md b/old_docs/barman.5.d/50-max_incoming_wals_queue.md similarity index 100% rename from doc/barman.5.d/50-max_incoming_wals_queue.md rename to old_docs/barman.5.d/50-max_incoming_wals_queue.md diff --git a/doc/barman.5.d/50-minimum_redundancy.md b/old_docs/barman.5.d/50-minimum_redundancy.md similarity index 100% rename from doc/barman.5.d/50-minimum_redundancy.md rename to old_docs/barman.5.d/50-minimum_redundancy.md diff --git a/doc/barman.5.d/50-model.md b/old_docs/barman.5.d/50-model.md similarity index 100% rename from doc/barman.5.d/50-model.md rename to old_docs/barman.5.d/50-model.md diff --git a/doc/barman.5.d/50-network_compression.md b/old_docs/barman.5.d/50-network_compression.md similarity index 100% rename from doc/barman.5.d/50-network_compression.md rename to old_docs/barman.5.d/50-network_compression.md diff --git a/doc/barman.5.d/50-parallel_jobs.md b/old_docs/barman.5.d/50-parallel_jobs.md similarity index 100% rename from doc/barman.5.d/50-parallel_jobs.md rename to old_docs/barman.5.d/50-parallel_jobs.md diff --git a/doc/barman.5.d/50-parallel_jobs_start_batch_period.md b/old_docs/barman.5.d/50-parallel_jobs_start_batch_period.md similarity index 100% rename from doc/barman.5.d/50-parallel_jobs_start_batch_period.md rename to old_docs/barman.5.d/50-parallel_jobs_start_batch_period.md diff --git a/doc/barman.5.d/50-parallel_jobs_start_batch_size.md b/old_docs/barman.5.d/50-parallel_jobs_start_batch_size.md similarity index 100% rename from doc/barman.5.d/50-parallel_jobs_start_batch_size.md rename to old_docs/barman.5.d/50-parallel_jobs_start_batch_size.md diff --git a/doc/barman.5.d/50-path_prefix.md b/old_docs/barman.5.d/50-path_prefix.md similarity index 100% rename from doc/barman.5.d/50-path_prefix.md rename to old_docs/barman.5.d/50-path_prefix.md diff --git a/doc/barman.5.d/50-post_archive_retry_script.md b/old_docs/barman.5.d/50-post_archive_retry_script.md similarity index 100% rename from doc/barman.5.d/50-post_archive_retry_script.md rename to old_docs/barman.5.d/50-post_archive_retry_script.md diff --git a/doc/barman.5.d/50-post_archive_script.md b/old_docs/barman.5.d/50-post_archive_script.md similarity index 100% rename from doc/barman.5.d/50-post_archive_script.md rename to old_docs/barman.5.d/50-post_archive_script.md diff --git a/doc/barman.5.d/50-post_backup_retry_script.md b/old_docs/barman.5.d/50-post_backup_retry_script.md similarity index 100% rename from doc/barman.5.d/50-post_backup_retry_script.md rename to old_docs/barman.5.d/50-post_backup_retry_script.md diff --git a/doc/barman.5.d/50-post_backup_script.md b/old_docs/barman.5.d/50-post_backup_script.md similarity index 100% rename from doc/barman.5.d/50-post_backup_script.md rename to old_docs/barman.5.d/50-post_backup_script.md diff --git a/doc/barman.5.d/50-post_delete_retry_script.md b/old_docs/barman.5.d/50-post_delete_retry_script.md similarity index 100% rename from doc/barman.5.d/50-post_delete_retry_script.md rename to old_docs/barman.5.d/50-post_delete_retry_script.md diff --git a/doc/barman.5.d/50-post_delete_script.md b/old_docs/barman.5.d/50-post_delete_script.md similarity index 100% rename from doc/barman.5.d/50-post_delete_script.md rename to old_docs/barman.5.d/50-post_delete_script.md diff --git a/doc/barman.5.d/50-post_recovery_retry_script.md b/old_docs/barman.5.d/50-post_recovery_retry_script.md similarity index 100% rename from doc/barman.5.d/50-post_recovery_retry_script.md rename to old_docs/barman.5.d/50-post_recovery_retry_script.md diff --git a/doc/barman.5.d/50-post_recovery_script.md b/old_docs/barman.5.d/50-post_recovery_script.md similarity index 100% rename from doc/barman.5.d/50-post_recovery_script.md rename to old_docs/barman.5.d/50-post_recovery_script.md diff --git a/doc/barman.5.d/50-post_wal_delete_retry_script.md b/old_docs/barman.5.d/50-post_wal_delete_retry_script.md similarity index 100% rename from doc/barman.5.d/50-post_wal_delete_retry_script.md rename to old_docs/barman.5.d/50-post_wal_delete_retry_script.md diff --git a/doc/barman.5.d/50-post_wal_delete_script.md b/old_docs/barman.5.d/50-post_wal_delete_script.md similarity index 100% rename from doc/barman.5.d/50-post_wal_delete_script.md rename to old_docs/barman.5.d/50-post_wal_delete_script.md diff --git a/doc/barman.5.d/50-pre_archive_retry_script.md b/old_docs/barman.5.d/50-pre_archive_retry_script.md similarity index 100% rename from doc/barman.5.d/50-pre_archive_retry_script.md rename to old_docs/barman.5.d/50-pre_archive_retry_script.md diff --git a/doc/barman.5.d/50-pre_archive_script.md b/old_docs/barman.5.d/50-pre_archive_script.md similarity index 100% rename from doc/barman.5.d/50-pre_archive_script.md rename to old_docs/barman.5.d/50-pre_archive_script.md diff --git a/doc/barman.5.d/50-pre_backup_retry_script.md b/old_docs/barman.5.d/50-pre_backup_retry_script.md similarity index 100% rename from doc/barman.5.d/50-pre_backup_retry_script.md rename to old_docs/barman.5.d/50-pre_backup_retry_script.md diff --git a/doc/barman.5.d/50-pre_backup_script.md b/old_docs/barman.5.d/50-pre_backup_script.md similarity index 100% rename from doc/barman.5.d/50-pre_backup_script.md rename to old_docs/barman.5.d/50-pre_backup_script.md diff --git a/doc/barman.5.d/50-pre_delete_retry_script.md b/old_docs/barman.5.d/50-pre_delete_retry_script.md similarity index 100% rename from doc/barman.5.d/50-pre_delete_retry_script.md rename to old_docs/barman.5.d/50-pre_delete_retry_script.md diff --git a/doc/barman.5.d/50-pre_delete_script.md b/old_docs/barman.5.d/50-pre_delete_script.md similarity index 100% rename from doc/barman.5.d/50-pre_delete_script.md rename to old_docs/barman.5.d/50-pre_delete_script.md diff --git a/doc/barman.5.d/50-pre_recovery_retry_script.md b/old_docs/barman.5.d/50-pre_recovery_retry_script.md similarity index 100% rename from doc/barman.5.d/50-pre_recovery_retry_script.md rename to old_docs/barman.5.d/50-pre_recovery_retry_script.md diff --git a/doc/barman.5.d/50-pre_recovery_script.md b/old_docs/barman.5.d/50-pre_recovery_script.md similarity index 100% rename from doc/barman.5.d/50-pre_recovery_script.md rename to old_docs/barman.5.d/50-pre_recovery_script.md diff --git a/doc/barman.5.d/50-pre_wal_delete_retry_script.md b/old_docs/barman.5.d/50-pre_wal_delete_retry_script.md similarity index 100% rename from doc/barman.5.d/50-pre_wal_delete_retry_script.md rename to old_docs/barman.5.d/50-pre_wal_delete_retry_script.md diff --git a/doc/barman.5.d/50-pre_wal_delete_script.md b/old_docs/barman.5.d/50-pre_wal_delete_script.md similarity index 100% rename from doc/barman.5.d/50-pre_wal_delete_script.md rename to old_docs/barman.5.d/50-pre_wal_delete_script.md diff --git a/doc/barman.5.d/50-primary_checkpoint_timeout.md b/old_docs/barman.5.d/50-primary_checkpoint_timeout.md similarity index 100% rename from doc/barman.5.d/50-primary_checkpoint_timeout.md rename to old_docs/barman.5.d/50-primary_checkpoint_timeout.md diff --git a/doc/barman.5.d/50-primary_conninfo.md b/old_docs/barman.5.d/50-primary_conninfo.md similarity index 100% rename from doc/barman.5.d/50-primary_conninfo.md rename to old_docs/barman.5.d/50-primary_conninfo.md diff --git a/doc/barman.5.d/50-primary_ssh_command.md b/old_docs/barman.5.d/50-primary_ssh_command.md similarity index 100% rename from doc/barman.5.d/50-primary_ssh_command.md rename to old_docs/barman.5.d/50-primary_ssh_command.md diff --git a/doc/barman.5.d/50-recovery_options.md b/old_docs/barman.5.d/50-recovery_options.md similarity index 100% rename from doc/barman.5.d/50-recovery_options.md rename to old_docs/barman.5.d/50-recovery_options.md diff --git a/doc/barman.5.d/50-recovery_staging_path.md b/old_docs/barman.5.d/50-recovery_staging_path.md similarity index 100% rename from doc/barman.5.d/50-recovery_staging_path.md rename to old_docs/barman.5.d/50-recovery_staging_path.md diff --git a/doc/barman.5.d/50-retention_policy.md b/old_docs/barman.5.d/50-retention_policy.md similarity index 100% rename from doc/barman.5.d/50-retention_policy.md rename to old_docs/barman.5.d/50-retention_policy.md diff --git a/doc/barman.5.d/50-retention_policy_mode.md b/old_docs/barman.5.d/50-retention_policy_mode.md similarity index 100% rename from doc/barman.5.d/50-retention_policy_mode.md rename to old_docs/barman.5.d/50-retention_policy_mode.md diff --git a/doc/barman.5.d/50-reuse_backup.md b/old_docs/barman.5.d/50-reuse_backup.md similarity index 100% rename from doc/barman.5.d/50-reuse_backup.md rename to old_docs/barman.5.d/50-reuse_backup.md diff --git a/doc/barman.5.d/50-slot_name.md b/old_docs/barman.5.d/50-slot_name.md similarity index 100% rename from doc/barman.5.d/50-slot_name.md rename to old_docs/barman.5.d/50-slot_name.md diff --git a/doc/barman.5.d/50-snapshot-disks.md b/old_docs/barman.5.d/50-snapshot-disks.md similarity index 100% rename from doc/barman.5.d/50-snapshot-disks.md rename to old_docs/barman.5.d/50-snapshot-disks.md diff --git a/doc/barman.5.d/50-snapshot-instance.md b/old_docs/barman.5.d/50-snapshot-instance.md similarity index 100% rename from doc/barman.5.d/50-snapshot-instance.md rename to old_docs/barman.5.d/50-snapshot-instance.md diff --git a/doc/barman.5.d/50-snapshot-provider.md b/old_docs/barman.5.d/50-snapshot-provider.md similarity index 100% rename from doc/barman.5.d/50-snapshot-provider.md rename to old_docs/barman.5.d/50-snapshot-provider.md diff --git a/doc/barman.5.d/50-ssh_command.md b/old_docs/barman.5.d/50-ssh_command.md similarity index 100% rename from doc/barman.5.d/50-ssh_command.md rename to old_docs/barman.5.d/50-ssh_command.md diff --git a/doc/barman.5.d/50-streaming_archiver.md b/old_docs/barman.5.d/50-streaming_archiver.md similarity index 100% rename from doc/barman.5.d/50-streaming_archiver.md rename to old_docs/barman.5.d/50-streaming_archiver.md diff --git a/doc/barman.5.d/50-streaming_archiver_batch_size.md b/old_docs/barman.5.d/50-streaming_archiver_batch_size.md similarity index 100% rename from doc/barman.5.d/50-streaming_archiver_batch_size.md rename to old_docs/barman.5.d/50-streaming_archiver_batch_size.md diff --git a/doc/barman.5.d/50-streaming_archiver_name.md b/old_docs/barman.5.d/50-streaming_archiver_name.md similarity index 100% rename from doc/barman.5.d/50-streaming_archiver_name.md rename to old_docs/barman.5.d/50-streaming_archiver_name.md diff --git a/doc/barman.5.d/50-streaming_backup_name.md b/old_docs/barman.5.d/50-streaming_backup_name.md similarity index 100% rename from doc/barman.5.d/50-streaming_backup_name.md rename to old_docs/barman.5.d/50-streaming_backup_name.md diff --git a/doc/barman.5.d/50-streaming_conninfo.md b/old_docs/barman.5.d/50-streaming_conninfo.md similarity index 100% rename from doc/barman.5.d/50-streaming_conninfo.md rename to old_docs/barman.5.d/50-streaming_conninfo.md diff --git a/doc/barman.5.d/50-streaming_wals_directory.md b/old_docs/barman.5.d/50-streaming_wals_directory.md similarity index 100% rename from doc/barman.5.d/50-streaming_wals_directory.md rename to old_docs/barman.5.d/50-streaming_wals_directory.md diff --git a/doc/barman.5.d/50-tablespace_bandwidth_limit.md b/old_docs/barman.5.d/50-tablespace_bandwidth_limit.md similarity index 100% rename from doc/barman.5.d/50-tablespace_bandwidth_limit.md rename to old_docs/barman.5.d/50-tablespace_bandwidth_limit.md diff --git a/doc/barman.5.d/50-wal_conninfo.md b/old_docs/barman.5.d/50-wal_conninfo.md similarity index 100% rename from doc/barman.5.d/50-wal_conninfo.md rename to old_docs/barman.5.d/50-wal_conninfo.md diff --git a/doc/barman.5.d/50-wal_retention_policy.md b/old_docs/barman.5.d/50-wal_retention_policy.md similarity index 100% rename from doc/barman.5.d/50-wal_retention_policy.md rename to old_docs/barman.5.d/50-wal_retention_policy.md diff --git a/doc/barman.5.d/50-wal_streaming_conninfo.md b/old_docs/barman.5.d/50-wal_streaming_conninfo.md similarity index 100% rename from doc/barman.5.d/50-wal_streaming_conninfo.md rename to old_docs/barman.5.d/50-wal_streaming_conninfo.md diff --git a/doc/barman.5.d/50-wals_directory.md b/old_docs/barman.5.d/50-wals_directory.md similarity index 100% rename from doc/barman.5.d/50-wals_directory.md rename to old_docs/barman.5.d/50-wals_directory.md diff --git a/doc/barman.5.d/70-hook-scripts.md b/old_docs/barman.5.d/70-hook-scripts.md similarity index 100% rename from doc/barman.5.d/70-hook-scripts.md rename to old_docs/barman.5.d/70-hook-scripts.md diff --git a/doc/barman.5.d/75-example.md b/old_docs/barman.5.d/75-example.md similarity index 100% rename from doc/barman.5.d/75-example.md rename to old_docs/barman.5.d/75-example.md diff --git a/doc/barman.5.d/80-see-also.md b/old_docs/barman.5.d/80-see-also.md similarity index 100% rename from doc/barman.5.d/80-see-also.md rename to old_docs/barman.5.d/80-see-also.md diff --git a/doc/barman.5.d/90-authors.md b/old_docs/barman.5.d/90-authors.md similarity index 100% rename from doc/barman.5.d/90-authors.md rename to old_docs/barman.5.d/90-authors.md diff --git a/doc/barman.5.d/95-resources.md b/old_docs/barman.5.d/95-resources.md similarity index 100% rename from doc/barman.5.d/95-resources.md rename to old_docs/barman.5.d/95-resources.md diff --git a/doc/barman.5.d/99-copying.md b/old_docs/barman.5.d/99-copying.md similarity index 100% rename from doc/barman.5.d/99-copying.md rename to old_docs/barman.5.d/99-copying.md diff --git a/old_docs/barman.conf b/old_docs/barman.conf new file mode 100644 index 000000000..c64ff0602 --- /dev/null +++ b/old_docs/barman.conf @@ -0,0 +1,101 @@ +; Barman, Backup and Recovery Manager for PostgreSQL +; http://www.pgbarman.org/ - http://www.enterprisedb.com/ +; +; Main configuration file + +[barman] +; System user +barman_user = barman + +; Directory of configuration files. Place your sections in separate files with .conf extension +; For example place the 'main' server section in /etc/barman.d/main.conf +configuration_files_directory = /etc/barman.d + +; Main directory +barman_home = /var/lib/barman + +; Locks directory - default: %(barman_home)s +;barman_lock_directory = /var/run/barman + +; Log location +log_file = /var/log/barman/barman.log + +; Log level (see https://docs.python.org/3/library/logging.html#levels) +log_level = INFO + +; Default compression level: possible values are None (default), bzip2, gzip, pigz, pygzip or pybzip2 +;compression = gzip + +; Pre/post backup hook scripts +;pre_backup_script = env | grep ^BARMAN +;pre_backup_retry_script = env | grep ^BARMAN +;post_backup_retry_script = env | grep ^BARMAN +;post_backup_script = env | grep ^BARMAN + +; Pre/post archive hook scripts +;pre_archive_script = env | grep ^BARMAN +;pre_archive_retry_script = env | grep ^BARMAN +;post_archive_retry_script = env | grep ^BARMAN +;post_archive_script = env | grep ^BARMAN + +; Pre/post delete scripts +;pre_delete_script = env | grep ^BARMAN +;pre_delete_retry_script = env | grep ^BARMAN +;post_delete_retry_script = env | grep ^BARMAN +;post_delete_script = env | grep ^BARMAN + +; Pre/post wal delete scripts +;pre_wal_delete_script = env | grep ^BARMAN +;pre_wal_delete_retry_script = env | grep ^BARMAN +;post_wal_delete_retry_script = env | grep ^BARMAN +;post_wal_delete_script = env | grep ^BARMAN + +; Global bandwidth limit in kilobytes per second - default 0 (meaning no limit) +;bandwidth_limit = 4000 + +; Number of parallel jobs for backup and recovery via rsync (default 1) +;parallel_jobs = 1 + +; Immediate checkpoint for backup command - default false +;immediate_checkpoint = false + +; Enable network compression for data transfers - default false +;network_compression = false + +; Number of retries of data copy during base backup after an error - default 0 +;basebackup_retry_times = 0 + +; Number of seconds of wait after a failed copy, before retrying - default 30 +;basebackup_retry_sleep = 30 + +; Maximum execution time, in seconds, per server +; for a barman check command - default 30 +;check_timeout = 30 + +; Time frame that must contain the latest backup date. +; If the latest backup is older than the time frame, barman check +; command will report an error to the user. +; If empty, the latest backup is always considered valid. +; Syntax for this option is: "i (DAYS | WEEKS | MONTHS | HOURS)" where i is an +; integer > 0 which identifies the number of days | weeks | months of +; validity of the latest backup for this check. Also known as 'smelly backup'. +;last_backup_maximum_age = + +; Time frame that must contain the latest WAL file +; If the latest WAL file is older than the time frame, barman check +; command will report an error to the user. +; Syntax for this option is: "i (DAYS | WEEKS | MONTHS | HOURS)" where i is an +; integer > 0 +;last_wal_maximum_age = + +; Minimum number of required backups (redundancy) +;minimum_redundancy = 1 + +; Global retention policy (REDUNDANCY or RECOVERY WINDOW) +; Examples of retention policies +; Retention policy (disabled, default) +;retention_policy = +; Retention policy (based on redundancy) +;retention_policy = REDUNDANCY 2 +; Retention policy (based on recovery window) +;retention_policy = RECOVERY WINDOW OF 4 WEEKS diff --git a/old_docs/barman.d/passive-server.conf-template b/old_docs/barman.d/passive-server.conf-template new file mode 100644 index 000000000..318d7ee7c --- /dev/null +++ b/old_docs/barman.d/passive-server.conf-template @@ -0,0 +1,28 @@ +; Barman, Backup and Recovery Manager for PostgreSQL +; https://www.pgbarman.org/ - https://www.enterprisedb.com/ +; +; Template configuration file for a server using +; SSH connections and rsync for copy. +; + +[passive] +; Human readable description +description = "Example of a Barman passive server" + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Passive server configuration +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Local parameter that identifies a barman server as 'passive'. +; A passive node uses as source for backups another barman server +; instead of a PostgreSQL cluster. +; If a primary ssh command is specified, barman will use it to establish a +; connection with the barman "master" server. +; Empty by default it can be also set as global value. +primary_ssh_command = ssh barman@backup + +; Incremental backup settings +;reuse_backup = link + +; Compression: must be identical to the source +;compression = gzip diff --git a/old_docs/barman.d/ssh-server.conf-template b/old_docs/barman.d/ssh-server.conf-template new file mode 100644 index 000000000..7d48270ab --- /dev/null +++ b/old_docs/barman.d/ssh-server.conf-template @@ -0,0 +1,43 @@ +; Barman, Backup and Recovery Manager for PostgreSQL +; https://www.pgbarman.org/ - https://www.enterprisedb.com/ +; +; Template configuration file for a server using +; SSH connections and rsync for copy. +; + +[ssh] +; Human readable description +description = "Example of PostgreSQL Database (via SSH)" + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; SSH options (mandatory) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +ssh_command = ssh postgres@pg + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PostgreSQL connection string (mandatory) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +conninfo = host=pg user=barman dbname=postgres + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Backup settings (via rsync over SSH) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +backup_method = rsync +; Incremental backup support: possible values are None (default), link or copy +;reuse_backup = link +; Identify the standard behavior for backup operations: possible values are +; exclusive_backup, concurrent_backup (default) +; concurrent_backup is the preferred method +backup_options = concurrent_backup + +; Number of parallel workers to perform file copy during backup and recover +;parallel_jobs = 1 + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Continuous WAL archiving (via 'archive_command') +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +archiver = on +;archiver_batch_size = 50 + +; PATH setting for this server +;path_prefix = "/usr/pgsql-12/bin" diff --git a/old_docs/barman.d/streaming-server.conf-template b/old_docs/barman.d/streaming-server.conf-template new file mode 100644 index 000000000..2bee8d1e3 --- /dev/null +++ b/old_docs/barman.d/streaming-server.conf-template @@ -0,0 +1,44 @@ +; Barman, Backup and Recovery Manager for PostgreSQL +; https://www.pgbarman.org/ - https://www.enterprisedb.com/ +; +; Template configuration file for a server using +; only streaming replication protocol +; + +[streaming-server] +; Human readable description +description = "Example of PostgreSQL Database (Streaming-Only)" + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PostgreSQL connection string (mandatory) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +conninfo = host=pg user=barman dbname=postgres + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PostgreSQL streaming connection string +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; To be used by pg_basebackup for backup and pg_receivewal for WAL streaming +; NOTE: streaming_barman is a regular user with REPLICATION privilege +streaming_conninfo = host=pg user=streaming_barman + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Backup settings (via pg_basebackup) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +backup_method = postgres +;streaming_backup_name = barman_streaming_backup + +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; WAL streaming settings (via pg_receivewal) +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +streaming_archiver = on +slot_name = barman +;create_slot = auto +;streaming_archiver_name = barman_receive_wal +;streaming_archiver_batch_size = 50 + +; Uncomment the following line if you are also using archive_command +; otherwise the "empty incoming directory" check will fail +;archiver = on + +; PATH setting for this server +;path_prefix = "/usr/pgsql-12/bin" diff --git a/doc/build/Makefile b/old_docs/build/Makefile similarity index 100% rename from doc/build/Makefile rename to old_docs/build/Makefile diff --git a/doc/build/build b/old_docs/build/build similarity index 97% rename from doc/build/build rename to old_docs/build/build index 34f90a795..00218f65d 100755 --- a/doc/build/build +++ b/old_docs/build/build @@ -41,7 +41,7 @@ docker run --rm -u "${USERMAP}" -w "$(pwd)" -v "${BASEDIR}:${BASEDIR}" \ pwd ls mkdir -p "${DISTDIR}" -cp -va *.html *.pdf "${DISTDIR}" +cp -va ./*.html ./*.pdf "${DISTDIR}" mkdir -p "${DISTDIR}/html-templates" cp -va html-templates/*.css "${DISTDIR}/html-templates" mkdir -p "${DISTDIR}/images" diff --git a/doc/build/html-templates/SOURCES.md b/old_docs/build/html-templates/SOURCES.md similarity index 100% rename from doc/build/html-templates/SOURCES.md rename to old_docs/build/html-templates/SOURCES.md diff --git a/doc/build/html-templates/barman.css b/old_docs/build/html-templates/barman.css similarity index 100% rename from doc/build/html-templates/barman.css rename to old_docs/build/html-templates/barman.css diff --git a/doc/build/html-templates/bootstrap.css b/old_docs/build/html-templates/bootstrap.css similarity index 100% rename from doc/build/html-templates/bootstrap.css rename to old_docs/build/html-templates/bootstrap.css diff --git a/doc/build/html-templates/docs.css b/old_docs/build/html-templates/docs.css similarity index 100% rename from doc/build/html-templates/docs.css rename to old_docs/build/html-templates/docs.css diff --git a/doc/build/html-templates/override.css b/old_docs/build/html-templates/override.css similarity index 100% rename from doc/build/html-templates/override.css rename to old_docs/build/html-templates/override.css diff --git a/doc/build/html-templates/template-cli.html b/old_docs/build/html-templates/template-cli.html similarity index 100% rename from doc/build/html-templates/template-cli.html rename to old_docs/build/html-templates/template-cli.html diff --git a/doc/build/html-templates/template-utils.html b/old_docs/build/html-templates/template-utils.html similarity index 100% rename from doc/build/html-templates/template-utils.html rename to old_docs/build/html-templates/template-utils.html diff --git a/doc/build/html-templates/template.css b/old_docs/build/html-templates/template.css similarity index 100% rename from doc/build/html-templates/template.css rename to old_docs/build/html-templates/template.css diff --git a/doc/build/html-templates/template.html b/old_docs/build/html-templates/template.html similarity index 100% rename from doc/build/html-templates/template.html rename to old_docs/build/html-templates/template.html diff --git a/doc/build/templates/Barman.tex b/old_docs/build/templates/Barman.tex similarity index 100% rename from doc/build/templates/Barman.tex rename to old_docs/build/templates/Barman.tex diff --git a/doc/build/templates/default.latex b/old_docs/build/templates/default.latex similarity index 100% rename from doc/build/templates/default.latex rename to old_docs/build/templates/default.latex diff --git a/doc/build/templates/default.yaml b/old_docs/build/templates/default.yaml similarity index 100% rename from doc/build/templates/default.yaml rename to old_docs/build/templates/default.yaml diff --git a/doc/build/templates/edb-enterprisedb-logo.png b/old_docs/build/templates/edb-enterprisedb-logo.png similarity index 100% rename from doc/build/templates/edb-enterprisedb-logo.png rename to old_docs/build/templates/edb-enterprisedb-logo.png diff --git a/doc/build/templates/logo-hires.png b/old_docs/build/templates/logo-hires.png similarity index 100% rename from doc/build/templates/logo-hires.png rename to old_docs/build/templates/logo-hires.png diff --git a/doc/build/templates/logo-horizontal-hires.png b/old_docs/build/templates/logo-horizontal-hires.png similarity index 100% rename from doc/build/templates/logo-horizontal-hires.png rename to old_docs/build/templates/logo-horizontal-hires.png diff --git a/doc/build/templates/postgres.pdf b/old_docs/build/templates/postgres.pdf similarity index 100% rename from doc/build/templates/postgres.pdf rename to old_docs/build/templates/postgres.pdf diff --git a/doc/images/barman-architecture-georedundancy.png b/old_docs/images/barman-architecture-georedundancy.png similarity index 100% rename from doc/images/barman-architecture-georedundancy.png rename to old_docs/images/barman-architecture-georedundancy.png diff --git a/doc/images/barman-architecture-scenario1.png b/old_docs/images/barman-architecture-scenario1.png similarity index 100% rename from doc/images/barman-architecture-scenario1.png rename to old_docs/images/barman-architecture-scenario1.png diff --git a/doc/images/barman-architecture-scenario1b.png b/old_docs/images/barman-architecture-scenario1b.png similarity index 100% rename from doc/images/barman-architecture-scenario1b.png rename to old_docs/images/barman-architecture-scenario1b.png diff --git a/doc/images/barman-architecture-scenario2.png b/old_docs/images/barman-architecture-scenario2.png similarity index 100% rename from doc/images/barman-architecture-scenario2.png rename to old_docs/images/barman-architecture-scenario2.png diff --git a/doc/images/barman-architecture-scenario2b.png b/old_docs/images/barman-architecture-scenario2b.png similarity index 100% rename from doc/images/barman-architecture-scenario2b.png rename to old_docs/images/barman-architecture-scenario2b.png diff --git a/doc/manual/.gitignore b/old_docs/manual/.gitignore similarity index 100% rename from doc/manual/.gitignore rename to old_docs/manual/.gitignore diff --git a/doc/manual/00-head.en.md b/old_docs/manual/00-head.en.md similarity index 100% rename from doc/manual/00-head.en.md rename to old_docs/manual/00-head.en.md diff --git a/doc/manual/01-intro.en.md b/old_docs/manual/01-intro.en.md similarity index 100% rename from doc/manual/01-intro.en.md rename to old_docs/manual/01-intro.en.md diff --git a/doc/manual/02-before_you_start.en.md b/old_docs/manual/02-before_you_start.en.md similarity index 100% rename from doc/manual/02-before_you_start.en.md rename to old_docs/manual/02-before_you_start.en.md diff --git a/doc/manual/10-design.en.md b/old_docs/manual/10-design.en.md similarity index 100% rename from doc/manual/10-design.en.md rename to old_docs/manual/10-design.en.md diff --git a/doc/manual/15-system_requirements.en.md b/old_docs/manual/15-system_requirements.en.md similarity index 100% rename from doc/manual/15-system_requirements.en.md rename to old_docs/manual/15-system_requirements.en.md diff --git a/doc/manual/16-installation.en.md b/old_docs/manual/16-installation.en.md similarity index 100% rename from doc/manual/16-installation.en.md rename to old_docs/manual/16-installation.en.md diff --git a/doc/manual/17-configuration.en.md b/old_docs/manual/17-configuration.en.md similarity index 100% rename from doc/manual/17-configuration.en.md rename to old_docs/manual/17-configuration.en.md diff --git a/doc/manual/20-server_setup.en.md b/old_docs/manual/20-server_setup.en.md similarity index 100% rename from doc/manual/20-server_setup.en.md rename to old_docs/manual/20-server_setup.en.md diff --git a/doc/manual/21-preliminary_steps.en.md b/old_docs/manual/21-preliminary_steps.en.md similarity index 100% rename from doc/manual/21-preliminary_steps.en.md rename to old_docs/manual/21-preliminary_steps.en.md diff --git a/doc/manual/22-config_file.en.md b/old_docs/manual/22-config_file.en.md similarity index 100% rename from doc/manual/22-config_file.en.md rename to old_docs/manual/22-config_file.en.md diff --git a/doc/manual/23-wal_streaming.en.md b/old_docs/manual/23-wal_streaming.en.md similarity index 100% rename from doc/manual/23-wal_streaming.en.md rename to old_docs/manual/23-wal_streaming.en.md diff --git a/doc/manual/24-wal_archiving.en.md b/old_docs/manual/24-wal_archiving.en.md similarity index 100% rename from doc/manual/24-wal_archiving.en.md rename to old_docs/manual/24-wal_archiving.en.md diff --git a/doc/manual/25-streaming_backup.en.md b/old_docs/manual/25-streaming_backup.en.md similarity index 100% rename from doc/manual/25-streaming_backup.en.md rename to old_docs/manual/25-streaming_backup.en.md diff --git a/doc/manual/26-rsync_backup.en.md b/old_docs/manual/26-rsync_backup.en.md similarity index 100% rename from doc/manual/26-rsync_backup.en.md rename to old_docs/manual/26-rsync_backup.en.md diff --git a/doc/manual/28-snapshots.en.md b/old_docs/manual/28-snapshots.en.md similarity index 100% rename from doc/manual/28-snapshots.en.md rename to old_docs/manual/28-snapshots.en.md diff --git a/doc/manual/30-windows-support.en.md b/old_docs/manual/30-windows-support.en.md similarity index 100% rename from doc/manual/30-windows-support.en.md rename to old_docs/manual/30-windows-support.en.md diff --git a/doc/manual/41-global-commands.en.md b/old_docs/manual/41-global-commands.en.md similarity index 100% rename from doc/manual/41-global-commands.en.md rename to old_docs/manual/41-global-commands.en.md diff --git a/doc/manual/42-server-commands.en.md b/old_docs/manual/42-server-commands.en.md similarity index 100% rename from doc/manual/42-server-commands.en.md rename to old_docs/manual/42-server-commands.en.md diff --git a/doc/manual/43-backup-commands.en.md b/old_docs/manual/43-backup-commands.en.md similarity index 100% rename from doc/manual/43-backup-commands.en.md rename to old_docs/manual/43-backup-commands.en.md diff --git a/doc/manual/50-feature-details.en.md b/old_docs/manual/50-feature-details.en.md similarity index 100% rename from doc/manual/50-feature-details.en.md rename to old_docs/manual/50-feature-details.en.md diff --git a/doc/manual/55-barman-cli.en.md b/old_docs/manual/55-barman-cli.en.md similarity index 100% rename from doc/manual/55-barman-cli.en.md rename to old_docs/manual/55-barman-cli.en.md diff --git a/doc/manual/65-troubleshooting.en.md b/old_docs/manual/65-troubleshooting.en.md similarity index 100% rename from doc/manual/65-troubleshooting.en.md rename to old_docs/manual/65-troubleshooting.en.md diff --git a/doc/manual/66-about.en.md b/old_docs/manual/66-about.en.md similarity index 100% rename from doc/manual/66-about.en.md rename to old_docs/manual/66-about.en.md diff --git a/doc/manual/99-references.en.md b/old_docs/manual/99-references.en.md similarity index 100% rename from doc/manual/99-references.en.md rename to old_docs/manual/99-references.en.md diff --git a/doc/manual/Makefile b/old_docs/manual/Makefile similarity index 100% rename from doc/manual/Makefile rename to old_docs/manual/Makefile diff --git a/doc/runbooks/snapshot_recovery_aws.md b/old_docs/runbooks/snapshot_recovery_aws.md similarity index 100% rename from doc/runbooks/snapshot_recovery_aws.md rename to old_docs/runbooks/snapshot_recovery_aws.md diff --git a/doc/runbooks/snapshot_recovery_azure.md b/old_docs/runbooks/snapshot_recovery_azure.md similarity index 100% rename from doc/runbooks/snapshot_recovery_azure.md rename to old_docs/runbooks/snapshot_recovery_azure.md diff --git a/scripts/set-version.sh b/scripts/set-version.sh deleted file mode 100755 index 422807156..000000000 --- a/scripts/set-version.sh +++ /dev/null @@ -1,175 +0,0 @@ -#!/bin/sh - -# © Copyright EnterpriseDB UK Limited 2019-2023 -# -# This file is part of Barman. -# -# Barman is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Barman is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Barman. If not, see . - -set -eu - -DOCKER=false -DATE=false -BASE="$(dirname $(cd $(dirname "$0"); pwd))" - -usage() -{ - echo "Usage: set-version.sh [ -r ] Release version to create in X.Y.Z format. - [ -d ] Specify the date in YYYY-MM-DD format. If not provided, current date will be used. - [ -D ] Use docker image to generate the documentation (must exist to run). - [ -h | --help ] Displays usage." - exit 1 -} - -while getopts ":r:d:D" opt; do - case $opt in - r) - RELEASE=${OPTARG} - echo "Release version to create in X.Y.Z format: $OPTARG" >&2 - ;; - d) - DATE=$OPTARG - echo "Specify the date in YYYY-MM-DD format. If not provided, current date will be used $OPTARG" >&2 - ;; - D) - DOCKER=true - echo "Use docker image to generate the documentation (must exist to run) " >&2 - ;; - *) - echo "invalid command: no parameter included with argument -$OPTARG" - usage - ;; - esac -done - -get_date() { - if [ "$(uname -s)" = "Darwin" ] - then - date_cmd="gdate" - else - date_cmd="date" - fi - if [ "$1" == false ] - then - # use current day - release_date=$(LANG=C ${date_cmd} +"%B %-d, %Y") - else - release_date=$(LANG=C ${date_cmd} +"%B %-d, %Y" -d "$1") - fi - echo $release_date -} - - -cd "$BASE" -release_version=$RELEASE -release_date=$(get_date $DATE) - - -require_clean_work_tree () { - git rev-parse --verify HEAD >/dev/null || exit 1 - git update-index -q --ignore-submodules --refresh - err=0 - - if ! git diff-files --quiet --ignore-submodules - then - echo >&2 "Cannot $1: You have unstaged changes." - err=1 - fi - - if ! git diff-index --cached --quiet --ignore-submodules HEAD -- - then - if [ $err = 0 ] - then - echo >&2 "Cannot $1: Your index contains uncommitted changes." - else - echo >&2 "Additionally, your index contains uncommitted changes." - fi - err=1 - fi - - if [ $err = 1 ] - then - # if there is a 2nd argument print it - test -n "${2+1}" && echo >&2 "$2" - exit 1 - fi -} - -require_clean_work_tree "set version" - -if branch=$(git symbolic-ref --short -q HEAD) && [ $branch = 'master' ] -then - echo "Setting version ${release_version}" -else - echo >&2 "Release is not possible because you are not on 'master' branch ($branch)" - exit 1 -fi - -sed -i -e "3s/^%.*/% ${release_date}/; 1s/| Version .*/| Version ${release_version}/" \ - doc/barman.1.d/00-header.md \ - doc/barman.5.d/00-header.md \ - doc/barman-wal-archive.1.md \ - doc/barman-wal-restore.1.md \ - doc/barman-cloud-backup.1.md \ - doc/barman-cloud-backup-delete.1.md \ - doc/barman-cloud-backup-keep.1.md \ - doc/barman-cloud-backup-list.1.md \ - doc/barman-cloud-backup-show.1.md \ - doc/barman-cloud-check-wal-archive.1.md \ - doc/barman-cloud-restore.1.md \ - doc/barman-cloud-wal-archive.1.md \ - doc/barman-cloud-wal-restore.1.md -sed -i -e "3s/^%.*/% ${release_date} (${release_version})/" \ - doc/manual/00-head.en.md -sed -i -e "s/__version__ = .*/__version__ = \"${release_version}\"/" \ - barman/version.py - -if [ "$DOCKER" == true ] - then - make -C doc create-all -else - make -C doc -fi - -git add doc/barman.1.d/00-header.md \ - doc/barman.5.d/00-header.md \ - doc/barman-wal-archive.1.md \ - doc/barman-wal-restore.1.md \ - doc/barman-cloud-backup.1.md \ - doc/barman-cloud-backup-delete.1.md \ - doc/barman-cloud-backup-keep.1.md \ - doc/barman-cloud-backup-list.1.md \ - doc/barman-cloud-backup-show.1.md \ - doc/barman-cloud-check-wal-archive.1.md \ - doc/barman-cloud-restore.1.md \ - doc/barman-cloud-wal-archive.1.md \ - doc/barman-cloud-wal-restore.1.md \ - doc/manual/00-head.en.md \ - barman/version.py \ - doc/barman.1 \ - doc/barman.5 \ - doc/barman-wal-archive.1 \ - doc/barman-wal-restore.1 \ - doc/barman-cloud-backup.1 \ - doc/barman-cloud-backup-delete.1 \ - doc/barman-cloud-backup-keep.1 \ - doc/barman-cloud-backup-list.1 \ - doc/barman-cloud-backup-show.1 \ - doc/barman-cloud-check-wal-archive.1 \ - doc/barman-cloud-restore.1 \ - doc/barman-cloud-wal-archive.1 \ - doc/barman-cloud-wal-restore.1 -git commit -sm "Version set to ${release_version}" - -echo "Version set to ${release_version}" diff --git a/setup.py b/setup.py index 0da075f07..6a8bc6530 100755 --- a/setup.py +++ b/setup.py @@ -62,21 +62,52 @@ ( "share/man/man1", [ - "doc/barman.1", - "doc/barman-cloud-backup.1", - "doc/barman-cloud-backup-keep.1", - "doc/barman-cloud-backup-list.1", - "doc/barman-cloud-backup-delete.1", - "doc/barman-cloud-backup-show.1", - "doc/barman-cloud-check-wal-archive.1", - "doc/barman-cloud-restore.1", - "doc/barman-cloud-wal-archive.1", - "doc/barman-cloud-wal-restore.1", - "doc/barman-wal-archive.1", - "doc/barman-wal-restore.1", + "docs/_build/man/barman.1", + "docs/_build/man/barman-archive-wal.1", + "docs/_build/man/barman-backup.1", + "docs/_build/man/barman-check.1", + "docs/_build/man/barman-check-backup.1", + "docs/_build/man/barman-cloud-backup.1", + "docs/_build/man/barman-cloud-backup-delete.1", + "docs/_build/man/barman-cloud-backup-keep.1", + "docs/_build/man/barman-cloud-backup-list.1", + "docs/_build/man/barman-cloud-backup-show.1", + "docs/_build/man/barman-cloud-check-wal-archive.1", + "docs/_build/man/barman-cloud-restore.1", + "docs/_build/man/barman-cloud-wal-archive.1", + "docs/_build/man/barman-cloud-wal-restore.1", + "docs/_build/man/barman-config-switch.1", + "docs/_build/man/barman-config-update.1", + "docs/_build/man/barman-cron.1", + "docs/_build/man/barman-delete.1", + "docs/_build/man/barman-diagnose.1", + "docs/_build/man/barman-generate-manifest.1", + "docs/_build/man/barman-get-wal.1", + "docs/_build/man/barman-keep.1", + "docs/_build/man/barman-list_backups.1", + "docs/_build/man/barman-list-files.1", + "docs/_build/man/barman-list-servers.1", + "docs/_build/man/barman-lock-directory-cleanup.1", + "docs/_build/man/barman-put-wal.1", + "docs/_build/man/barman-rebuild-xlogdb.1", + "docs/_build/man/barman-receive-wal.1", + "docs/_build/man/barman-restore.1", + "docs/_build/man/barman-replication-status.1", + "docs/_build/man/barman-show-backup.1", + "docs/_build/man/barman-show-servers.1", + "docs/_build/man/barman-status.1", + "docs/_build/man/barman-switch-wal.1", + "docs/_build/man/barman-switch-xlog.1", + "docs/_build/man/barman-sync-backup.1", + "docs/_build/man/barman-sync-info.1", + "docs/_build/man/barman-sync-wals.1", + "docs/_build/man/barman-verify.1", + "docs/_build/man/barman-verify-backup.1", + "docs/_build/man/barman-wal-restore.1", + "docs/_build/man/barman-wal-archive.1", ], ), - ("share/man/man5", ["doc/barman.5"]), + ("share/man/man5", ["docs/_build/man/barman.5"]), ], entry_points={ "console_scripts": [ @@ -116,6 +147,8 @@ 'python-snappy; python_version>="3.7"', 'cramjam >= 2.7.0; python_version>="3.7"', ], + "zstandard": ["zstandard"], + "lz4": ["lz4"], }, platforms=["Linux", "Mac OS X"], classifiers=[ diff --git a/sphinx/.gitignore b/sphinx/.gitignore deleted file mode 100644 index 30c9ea7fd..000000000 --- a/sphinx/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -_build/ -docs/*.rst -!docs/index.rst diff --git a/sphinx/Makefile b/sphinx/Makefile deleted file mode 100644 index 6902e3e2d..000000000 --- a/sphinx/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -c . -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ./docs -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -a -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Barman.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Barman.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/Barman" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Barman" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/sphinx/README.md b/sphinx/README.md deleted file mode 100644 index 19152b789..000000000 --- a/sphinx/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Generate sphinx documentation - -Generate barman code documentation using Sphinx autodoc - -## Prerequisites - -Install the python modules required to build the documentation -by executing, from the root directory of Barman: - -``` bash -pip install -r sphinx/requirements.txt -``` - -## Documentation generation - -From the root folder of Barman, launch: - -``` bash -sphinx/generate_docs.sh -``` - - -### `generate_docs.sh` options - -Is possible to use a different path to the barman source files -directory (default: the current barman source directory) passing it -as argument to the `generate_docs.sh` script. - -``` bash -sphinx/generate_docs.sh -``` - -It's also possible to pass the target format (default: `html`) -to the generate_docs.sh script using the -t option followed by -one of the available formats: - -* html to make standalone HTML files -* dirhtml to make HTML files named index.html in directories -* singlehtml to make a single large HTML file -* pickle to make pickle files -* json to make JSON files -* htmlhelp to make HTML files and a HTML help project -* qthelp to make HTML files and a qthelp project -* devhelp to make HTML files and a Devhelp project -* epub to make an epub -* latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter -* latexpdf to make LaTeX files and run them through pdflatex -* text to make text files -* man to make manual pages -* texinfo to make Texinfo files -* info to make Texinfo files and run them through makeinfo -* gettext to make PO message catalogs -* changes to make an overview of all changed/added/deprecated items -* linkcheck to check all external links for integrity -* doctest to run all doctests embedded in the documentation (if enabled) - -## Licence - -© Copyright EnterpriseDB UK Limited 2011-2023 - -Barman is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Barman is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Barman. If not, see . diff --git a/sphinx/conf.py b/sphinx/conf.py deleted file mode 100644 index 20f32b152..000000000 --- a/sphinx/conf.py +++ /dev/null @@ -1,344 +0,0 @@ -# -*- coding: utf-8 -*- -# -# barman - Backup and Recovery Manager for PostgreSQL -# -# © Copyright EnterpriseDB UK Limited 2011-2023 -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import re -import sys -from distutils.version import LooseVersion - -import sphinx_bootstrap_theme - -from sphinx import __version__ as sphinx_version - -# read barman_dir from the environment -barman_dir = os.environ.get("BARMAN_DIR") - -if not barman_dir: - raise SystemExit("Missing or invalid BARMAN_DIR environment variable") - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath(barman_dir)) - -# -- General configuration ---------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - "sphinx.ext.autodoc", - "sphinx.ext.doctest", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", - "sphinx.ext.coverage", - "sphinx.ext.mathjax", -] - -if LooseVersion(sphinx_version) > LooseVersion("1.8"): - extensions.append("sphinx.ext.imgmath") -else: - extensions.append("sphinx.ext.pngmath") - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "Barman" -copyright = "2011-2023 EnterpriseDB UK Limited]" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. - -barman = {} -with open(os.path.join(barman_dir, "barman/version.py"), "r") as fversion: - exec(fversion.read(), barman) - -# The short X.Y version. -version = re.search(r"[\d.]+", barman["__version__"]).group() - -# The full version, including alpha/beta/rc tags. -release = barman["__version__"] - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ["setup.rst"] - -# The reST default role (used for this markup: `text`) to use -# for all documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# html_theme = 'default' -# html_theme = 'sphinx_rtd_theme' -html_theme = "bootstrap" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -html_theme_options = { - "navbar_title": "Barman", - "navbar_site_name": "Barman", - "globaltoc_depth": 4, - "bootswatch_theme": "cosmo", -} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = "Barmandoc" - - -# -- Options for LaTeX output ------------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, -# documentclass [howto/manual]). -latex_documents = [ - ( - "index", - "Barman.tex", - "Barman Documentation", - "EnterpriseDB UK Limited", - "manual", - ), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output ------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ("index", "barman", "Barman Documentation", ["EnterpriseDB UK Limited"], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ----------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - "index", - "Barman", - "Barman Documentation", - "EnterpriseDB UK Limited", - "Barman", - "Barman, Backup and Recovery Manager for PostgreSQL", - "Miscellaneous", - ), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - - -# -- Options for Epub output -------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = "Barman" -epub_author = "EnterpriseDB UK Limited" -epub_publisher = "EnterpriseDB UK Limited" -epub_copyright = "2011-2023, EnterpriseDB UK Limited" - -# The language of the text. It defaults to the language option -# or en if the language is not set. -# epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -# epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# epub_identifier = '' - -# A unique identification for the text. -# epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -# epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -# epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -# epub_post_files = [] - -# A list of files that should not be packed into the epub file. -# epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -# epub_tocdepth = 3 - -# Allow duplicate toc entries. -# epub_tocdup = True - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/": None} diff --git a/sphinx/docs/index.rst b/sphinx/docs/index.rst deleted file mode 100644 index c6520cb3b..000000000 --- a/sphinx/docs/index.rst +++ /dev/null @@ -1,70 +0,0 @@ - -.. © Copyright EnterpriseDB UK Limited 2011-2023 - Barman is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Barman is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Barman. If not, see . - - -Welcome to barman |version| -=========================== - -Barman (Backup and Recovery Manager) is an open-source administration -tool for disaster recovery of PostgreSQL servers written in Python. -It allows your organisation to perform remote backups of multiple -servers in business critical environments to reduce risk and help DBAs -during the recovery phase. - -Barman is distributed under GNU GPL 3 and maintained by EnterpriseDB. - -For further information, look at the "Web resources" section below. - -Contents: - -.. toctree:: - :maxdepth: 4 - - barman - -Web resources -============= - -* Website : http://www.pgbarman.org/ -* Download : http://github.com/EnterpriseDB/barman -* Documentation : http://www.pgbarman.org/documentation/ -* Man page, section 1 : http://docs.pgbarman.org/barman.1.html -* Man page, section 5 : http://docs.pgbarman.org/barman.5.html -* Community support : http://www.pgbarman.org/support/ -* Professional support : https://www.enterprisedb.com/ - -Licence -======= - -© Copyright EnterpriseDB UK Limited 2011-2023 - -Barman is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Barman is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Barman. If not, see . - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/sphinx/generate_docs.sh b/sphinx/generate_docs.sh deleted file mode 100755 index bebb8c17b..000000000 --- a/sphinx/generate_docs.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/bash - -# © Copyright EnterpriseDB UK Limited 2011-2023 -# -# This file is part of Barman. -# -# Barman is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Barman is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Barman. If not, see . - -BASEDIR=$(cd ${0%/*}; pwd ) - -# modify GEN_MODE. It must be passed like parameter value -GEN_MODE='html' - -function die() -{ - echo "$@" - exit 1 -} - -function usage() -{ - echo "Usage: $0 [-h] [-t TARGET] DIR" - echo - echo "use -h for extended help" - echo - exit 1 -} - -function showhelp() -{ - echo "$0 [-h] [-t TARGET] DIR" - echo - echo "DIR is the source directory of the barman files" - echo - echo " -h Show this help message" - echo " -t TARGET Generate documentation using a specific " - echo " target format (default: HTML)" - echo - echo "List of available target formats:" - echo " html to make standalone HTML files" - echo " dirhtml to make HTML files named index.html in directories" - echo " singlehtml to make a single large HTML file" - echo " pickle to make pickle files" - echo " json to make JSON files" - echo " htmlhelp to make HTML files and a HTML help project" - echo " qthelp to make HTML files and a qthelp project" - echo " devhelp to make HTML files and a Devhelp project" - echo " epub to make an epub" - echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - echo " latexpdf to make LaTeX files and run them through pdflatex" - echo " text to make text files" - echo " man to make manual pages" - echo " texinfo to make Texinfo files" - echo " info to make Texinfo files and run them through makeinfo" - echo " gettext to make PO message catalogs" - echo " changes to make an overview of all changed/added/deprecated items" - echo " linkcheck to check all external links for integrity" - echo " doctest to run all doctests embedded in the documentation (if enabled)" - echo -} - -RED='\033[1;31m' -RSET='\033[0m' - -function red() -{ - printf "${RED}${1}${RSET}\n" -} - - -# if -h is the parameter it shows help -# if -t expect for a target -while getopts ht: OPT; -do - case "$OPT" in - t) - GEN_MODE=${OPTARG}; shift 2;; - --) - shift; break;; - h|*) - showhelp; exit 1;; - esac -shift; -done - -if [[ $# -gt 2 ]] -then - showhelp - exit 1 -fi - -if [[ $# -eq 0 ]] ; then - BARMAN_DIR=$(cd "$BASEDIR/.."; pwd) -else - BARMAN_DIR=$(cd "$1"; pwd) -fi - -[[ "${BARMAN_DIR}" = "." ]] && die 'Input directory . is not supported!' -[[ ! -d "${BARMAN_DIR}" ]] && die 'Input directory does not exists!' - -export BARMAN_DIR -cd "${BASEDIR}" - -# Cleans the build directory -red "Cleaning the Build directory..." -make clean - -red "Removing all generated files..." -ls "${BASEDIR}"/docs/*.rst | grep -v 'index.rst$' | xargs -trI X rm -f X - -# Generates automatically modules doc -red "Generating documentation from modules..." -sphinx-apidoc -P -e -T -M -o docs "${BARMAN_DIR}" -# Invokes html generation -red "Generating ${GEN_MODE}" -make ${GEN_MODE} - -red "DONE!!" diff --git a/sphinx/requirements.txt b/sphinx/requirements.txt deleted file mode 100644 index be1328c26..000000000 --- a/sphinx/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -argcomplete -psycopg2-binary -python-dateutil -Sphinx -sphinx-bootstrap-theme -sphinx-rtd-theme diff --git a/tests/requirements_dev.txt b/tests/requirements_dev.txt index bee6e3834..fec53a194 100644 --- a/tests/requirements_dev.txt +++ b/tests/requirements_dev.txt @@ -2,6 +2,8 @@ .[cloud] .[azure] .[snappy] +.[zstandard] +.[lz4] .[google] pytest mock diff --git a/tests/test_backup.py b/tests/test_backup.py index b080188b8..4ccefe85e 100644 --- a/tests/test_backup.py +++ b/tests/test_backup.py @@ -190,8 +190,17 @@ def test_dateutil_parser(self, tmpdir): # checked that the raised error is the correct error assert "Unable to parse the target time parameter " in str(exc.value) + @patch("barman.backup.BackupManager.release_delete_annotation") + @patch("barman.backup.BackupManager.put_delete_annotation") @patch("barman.backup.BackupManager.get_available_backups") - def test_delete_backup(self, mock_available_backups, tmpdir, caplog): + def test_delete_backup( + self, + mock_available_backups, + mock_put_annotation, + mock_delete_annotation, + tmpdir, + caplog, + ): """ Simple test for the deletion of a backup. We want to test the behaviour of the delete_backup method @@ -248,6 +257,9 @@ def test_delete_backup(self, mock_available_backups, tmpdir, caplog): "fake_backup_id": b_info, } + # Mock the put_annotation method to simulate successful annotation + mock_put_annotation.return_value = None + # Test 1: normal delete expecting no errors (old format) caplog_reset(caplog) backup_manager.server.config.minimum_redundancy = 1 @@ -391,6 +403,20 @@ def test_delete_backup(self, mock_available_backups, tmpdir, caplog): assert deleted is True set_backup_sizes.assert_called_once_with(next_backup) + # Test 9: ensure the delete annotation is created and removed during the deletion + caplog_reset(caplog) + mock_put_annotation.reset_mock() + mock_delete_annotation.reset_mock() + build_backup_directories(b_info) + mock_available_backups.return_value = { + "fake_backup_id": b_info, + } + backup_manager.delete_backup(b_info) + # Ensure the annotation was created + mock_put_annotation.assert_called_once_with(b_info.backup_id) + # Ensure the annotation was deleted + mock_delete_annotation.assert_called_once_with(b_info.backup_id) + @patch("os.stat") @patch("barman.backup.fsync_file") @patch("barman.backup.fsync_dir") @@ -907,6 +933,96 @@ def test_cron_retention_skip_OBSOLETE_backups_if_lock( assert not delete_backup.called assert "skipping retention policy application" in err + @patch("barman.backup.BackupManager.delete_backup") + @patch("barman.backup.BackupManager.get_available_backups") + @patch("barman.backup.BackupManager.check_delete_annotation") + @patch("barman.backup.BackupManager.release_delete_annotation") + def test_cron_retention_obsoletes_backups_with_delete_annotation( + self, + release_delete_annotation, + check_delete_annotation, + get_available_backups, + delete_backup, + tmpdir, + ): + """ + Verify that a backup with the delete annotation is marked as obsolete and then deleted. + """ + backup_manager = build_backup_manager() + backup_manager.server.config.name = "TestServer" + backup_manager.server.config.barman_lock_directory = tmpdir.strpath + backup_manager.server.config.backup_options = [] + backup_manager.server.config.retention_policy = Mock() + backup_manager.config.retention_policy.report.return_value = { + "test_backup": BackupInfo.VALID, + } + available_backups = { + "test_backup": build_test_backup_info( + server=backup_manager.server, backup_id="test_backup" + ) + } + get_available_backups.return_value = available_backups + check_delete_annotation.return_value = True + + backup_manager.cron_retention_policy() + + # Ensure the backup was marked as obsolete + assert ( + backup_manager.config.retention_policy.report.return_value["test_backup"] + == BackupInfo.OBSOLETE + ) + # Ensure the delete annotation was released + release_delete_annotation.assert_called_once_with("test_backup") + # Ensure the backup was deleted + delete_backup.assert_called_once_with( + available_backups["test_backup"], skip_wal_cleanup_if_standalone=False + ) + + @patch("barman.backup.BackupManager.delete_backup") + @patch("barman.backup.BackupManager.get_available_backups") + @patch("barman.backup.BackupManager.check_delete_annotation") + @patch("barman.backup.BackupManager.release_delete_annotation") + def test_cron_retention_orphan_backup_warning( + self, + release_delete_annotation, + check_delete_annotation, + get_available_backups, + delete_backup, + tmpdir, + caplog, + ): + """ + Verify that if the backup is orphaned, cron will output a warning. + """ + backup_manager = build_backup_manager() + backup_manager.server.config.name = "TestServer" + backup_manager.server.config.barman_lock_directory = tmpdir.strpath + backup_manager.server.config.backup_options = [] + backup_manager.server.config.retention_policy = Mock() + backup_manager.config.retention_policy.report.return_value = { + "test_backup": BackupInfo.VALID, + } + available_backups = { + "test_backup": build_test_backup_info( + server=backup_manager.server, backup_id="test_backup" + ) + } + get_available_backups.return_value = available_backups + check_delete_annotation.return_value = False + + # Simulate orphan backup + with patch("barman.infofile.LocalBackupInfo.is_orphan") as mock_is_orphan: + mock_is_orphan.return_value = True + backup_manager.cron_retention_policy() + + # Ensure the warning was logged + expected_warning = ( + f"WARNING: Backup directory {available_backups['test_backup'].get_basebackup_directory()} " + "contains only a non-empty backup.info file " + "which may indicate an incomplete delete operation. Please manually delete the directory." + ) + assert any(expected_warning in message for message in caplog.messages) + @pytest.mark.parametrize("should_fail", (True, False)) @patch("barman.backup.LocalBackupInfo.save") @patch("barman.backup.output") @@ -1256,6 +1372,12 @@ def open_xlog_db(): ) yield backup_manager + @pytest.fixture + def mock_put_annotation(self): + with patch("barman.backup.AnnotationManagerFile.put_annotation") as mock: + mock.return_value = None + yield mock + def _assert_wals_exist(self, wals_directory, begin_wal, end_wal): """ Assert all WALs between begin_wal and end_wal (inclusive) exist in @@ -1342,6 +1464,7 @@ def test_delete_no_wal_cleanup_if_not_oldest_backup(self, backup_manager): def test_delete_wal_cleanup(self, backup_manager): """Verify correct WALs are removed when the oldest backup is deleted""" + # GIVEN two backups oldest_backup = build_test_backup_info( backup_id="20210722T095432", @@ -2054,8 +2177,10 @@ def test_snapshot_backup_method(self, mock_snapshot_executor): @patch("barman.backup.get_snapshot_interface_from_backup_info") @patch("barman.backup.BackupManager.remove_wal_before_backup") @patch("barman.backup.BackupManager.get_available_backups") + @patch("barman.backup.AnnotationManagerFile.put_annotation") def test_snapshot_delete( self, + mock_put_annotation, mock_get_available_backups, mock_remove_wal_before_backup, mock_get_snapshot_interface, diff --git a/tests/test_barman_cloud_wal_archive.py b/tests/test_barman_cloud_wal_archive.py index 767c7997c..ff6587c2f 100644 --- a/tests/test_barman_cloud_wal_archive.py +++ b/tests/test_barman_cloud_wal_archive.py @@ -646,6 +646,7 @@ def test_upload_wal(self, rfo_mock, boto_mock): os.path.basename(source), ), ExtraArgs={}, + Config=cloud_interface.config, ) @mock.patch("barman.cloud_providers.aws_s3.boto3") @@ -677,6 +678,7 @@ def test_encrypted_upload_wal(self, rfo_mock, boto_mock): os.path.basename(source), ), ExtraArgs={"ServerSideEncryption": "AES256"}, + Config=cloud_interface.config, ) diff --git a/tests/test_barman_wal_archive.py b/tests/test_barman_wal_archive.py index 8db211966..12c9fde46 100644 --- a/tests/test_barman_wal_archive.py +++ b/tests/test_barman_wal_archive.py @@ -54,22 +54,36 @@ def save_before_close(orig_close=input_mock.close): # noinspection PyMethodMayBeStatic class TestMain(object): + @pytest.mark.parametrize( + ["hash_algorithm", "SUMS_FILE", "flag"], + [("sha256", "SHA256SUMS", ""), ("md5", "MD5SUMS", "--md5")], + ) @mock.patch("barman.clients.walarchive.subprocess.Popen") - def test_ok(self, popen_mock, tmpdir): + def test_ok(self, popen_mock, hash_algorithm, SUMS_FILE, flag, tmpdir): # Prepare some content source = tmpdir.join("wal_dir/000000080000ABFF000000C1") source.write("something", ensure=True) - source_hash = source.computehash() + source_hash = source.computehash(hash_algorithm) # Prepare the fake Pipe input_mock, output_mock = pipe_helper() popen_mock.return_value.stdin = input_mock popen_mock.return_value.returncode = 0 - walarchive.main( - ["-c", "/etc/bwa.conf", "-U", "user", "a.host", "a-server", source.strpath] - ) + args_list = [ + "-c", + "/etc/bwa.conf", + "-U", + "user", + "a.host", + "a-server", + source.strpath, + ] + + if flag: + args_list.append(flag) + walarchive.main(args_list) popen_mock.assert_called_once_with( [ "ssh", @@ -94,7 +108,7 @@ def test_ok(self, popen_mock, tmpdir): second = tar.next() with closing(tar.extractfile(second)) as fp: second_content = fp.read().decode() - assert second.name == "MD5SUMS" + assert second.name == SUMS_FILE assert second_content == "%s *000000080000ABFF000000C1\n" % source_hash assert tar.next() is None @@ -233,8 +247,12 @@ def test_connectivity_test_error(self, popen_mock, capsys): # noinspection PyMethodMayBeStatic class TestRemotePutWal(object): + @pytest.mark.parametrize( + ("hash_algorithm", "SUMS_FILE", "flag"), + [("md5", "MD5SUMS", True), ("sha256", "SHA256SUMS", False)], + ) @mock.patch("barman.clients.walarchive.subprocess.Popen") - def test_str_source_file(self, popen_mock, tmpdir): + def test_str_source_file(self, popen_mock, hash_algorithm, SUMS_FILE, flag, tmpdir): input_mock, output_mock = pipe_helper() popen_mock.return_value.stdin = input_mock @@ -246,6 +264,7 @@ def test_str_source_file(self, popen_mock, tmpdir): server_name="this-server", test=False, port=None, + md5=flag, ) source_file = tmpdir.join("test-source/000000010000000000000001") source_file.write("test-content", ensure=True) @@ -281,10 +300,11 @@ def test_str_source_file(self, popen_mock, tmpdir): second = tar.next() with closing(tar.extractfile(second)) as fp: second_content = fp.read().decode() - assert second.name == "MD5SUMS" + assert second.name == SUMS_FILE assert ( second_content - == "%s *000000010000000000000001\n" % source_file.computehash("md5") + == "%s *000000010000000000000001\n" + % source_file.computehash(hash_algorithm) ) assert tar.next() is None @@ -300,6 +320,7 @@ def test_error(self, popen_mock, tmpdir): server_name="this-server", test=False, port=None, + md5=False, ) source_file = tmpdir.join("test-source/000000010000000000000001") source_file.write("test-content", ensure=True) @@ -332,18 +353,23 @@ def test_error(self, popen_mock, tmpdir): # noinspection PyMethodMayBeStatic class TestChecksumTarFile(object): - def test_tar(self, tmpdir): + @pytest.mark.parametrize( + ["hash_algorithm", "SUMS_FILE"], [("sha256", "SHA256SUMS"), ("md5", "MD5SUMS")] + ) + def test_tar(self, hash_algorithm, SUMS_FILE, tmpdir): # Prepare some content source = tmpdir.join("source.file") source.write("something", ensure=True) source.setmtime(source.mtime() - 100) # Set mtime to 100 seconds ago - source_hash = source.computehash() + source_hash = source.computehash(hash_algorithm) # Write the content in a tar file storage = tmpdir.join("storage.tar") with closing( walarchive.ChecksumTarFile.open(storage.strpath, mode="w:") ) as tar: + tar.hash_algorithm = hash_algorithm + tar.HASHSUMS_FILE = SUMS_FILE tar.add(source.strpath, source.basename) checksum = tar.members[0].data_checksum assert checksum == source_hash @@ -357,7 +383,7 @@ def test_tar(self, tmpdir): tar.close() dest_file = lab.join(source.basename) - sum_file = lab.join("MD5SUMS") + sum_file = lab.join(SUMS_FILE) sums = {} for line in sum_file.readlines(): checksum, name = re.split(r" [* ]", line.rstrip(), 1) @@ -365,28 +391,37 @@ def test_tar(self, tmpdir): assert list(sums.keys()) == [source.basename] assert sums[source.basename] == source_hash - assert dest_file.computehash() == source_hash + assert dest_file.computehash(hash_algorithm) == source_hash # Verify file mtime # Use a round(2) comparison because float is not precise in Python 2.x assert round(dest_file.mtime(), 2) == round(source.mtime(), 2) @pytest.mark.parametrize( - ["size", "mode"], + ["hash_algorithm", "size", "mode"], [ - [0, 0], - [10, None], - [10, 0], - [10, 1], - [10, -5], - [16 * 1024, 0], - [32 * 1024 - 1, -1], - [32 * 1024 - 1, 0], - [32 * 1024 - 1, 1], + ["sha256", 0, 0], + ["sha256", 10, None], + ["sha256", 10, 0], + ["sha256", 10, 1], + ["sha256", 10, -5], + ["sha256", 16 * 1024, 0], + ["sha256", 32 * 1024 - 1, -1], + ["sha256", 32 * 1024 - 1, 0], + ["sha256", 32 * 1024 - 1, 1], + ["md5", 0, 0], + ["md5", 10, None], + ["md5", 10, 0], + ["md5", 10, 1], + ["md5", 10, -5], + ["md5", 16 * 1024, 0], + ["md5", 32 * 1024 - 1, -1], + ["md5", 32 * 1024 - 1, 0], + ["md5", 32 * 1024 - 1, 1], ], ) - def test_md5copyfileobj(self, size, mode): + def test_hashCopyfileobj(self, hash_algorithm, size, mode): """ - Test md5copyfileobj different size. + Test hashCopyfileobj different size. If mode is None, copy the whole data. If mode is <= 0, copy the data passing the exact length. @@ -406,16 +441,24 @@ def test_md5copyfileobj(self, size, mode): if mode and mode > 0: # Require more bytes than available. Make sure to get an exception with pytest.raises(IOError): - walarchive.md5copyfileobj(src, dst, size + mode) + walarchive.hashCopyfileobj( + src, dst, size + mode, hash_algorithm=hash_algorithm + ) else: if mode is None: # Copy the whole file until the end - md5 = walarchive.md5copyfileobj(src, dst) + checksum = walarchive.hashCopyfileobj( + src, dst, hash_algorithm=hash_algorithm + ) else: # Copy only a portion of the file - md5 = walarchive.md5copyfileobj(src, dst, size + mode) + checksum = walarchive.hashCopyfileobj( + src, dst, size + mode, hash_algorithm=hash_algorithm + ) src_string = src_string[0 : size + mode] # Validate the content and the checksum assert dst.getvalue() == src_string - assert md5 == hashlib.md5(bytes(src_string)).hexdigest() + assert ( + checksum == hashlib.new(hash_algorithm, bytes(src_string)).hexdigest() + ) diff --git a/tests/test_barman_wal_restore.py b/tests/test_barman_wal_restore.py index eb0b52f81..75c7a6350 100644 --- a/tests/test_barman_wal_restore.py +++ b/tests/test_barman_wal_restore.py @@ -27,7 +27,8 @@ # noinspection PyMethodMayBeStatic class TestRemoteGetWal(object): @mock.patch("barman.clients.walrestore.subprocess.Popen") - def test_string_dest_file(self, popen_mock, tmpdir): + @mock.patch("barman.clients.walrestore.shutil") + def test_string_dest_file(self, shutil_mock, popen_mock, tmpdir): config = mock.Mock( compression=False, user="barman", @@ -78,7 +79,8 @@ def test_connectivity_test_error(self, popen_mock, capsys): ) in err @mock.patch("barman.clients.walrestore.subprocess.Popen") - def test_ssh_port(self, popen_mock): + @mock.patch("barman.clients.walrestore.shutil") + def test_ssh_port(self, shutil_mock, popen_mock): # WHEN barman-wal-restore is called with the --port option with pytest.raises(SystemExit): walrestore.main( @@ -168,3 +170,68 @@ def test_exit_code_if_wal_dest_not_writable(self, isdir_mock, open_mock, capsys) assert ( "ERROR: Cannot open 'dummy_dest' (WAL_DEST) for writing: error\n" ) in err + + @mock.patch("barman.clients.walrestore.CompressionManager") + @mock.patch("barman.clients.walrestore.shutil") + @mock.patch("barman.clients.walrestore.subprocess.Popen") + @mock.patch("barman.clients.walrestore.isinstance") + @mock.patch("barman.clients.walrestore.open") + def test_decompression( + self, + _mock_open, + mock_isinstance, + mock_popen, + _mock_shutil, + mock_compression_manager, + tmpdir, + ): + """Assert that decompression happens correctly when WALs come compressed""" + + # A config args object with some compression passed + config = mock.Mock( + compression="some compression", + user="barman", + barman_host="remote.barman.host", + config=None, + server_name="this-server", + ) + dest_file = tmpdir.join("test-dest").strpath + + # Mock the compression manager to identify a compression on the WAL file and + # return a corresponding compressor + mock_compressor = mock.Mock() + mock_compression_manager.return_value.identify_compression.return_value = ( + "some compression" + ) + mock_compression_manager.return_value.get_compressor.return_value = ( + mock_compressor + ) + + # The first return means that dest_file is instance of str + # The second means that mock_compressor is not instance of InternalCompressor + mock_isinstance.side_effect = [True, True] + + walrestore.RemoteGetWal(config, "000000010000000000000001", dest_file) + + # Then the internal decompress method of the compressor should have been called + # to decompress the file directly to the destination + mock_compressor.decompress.assert_called_once() + + # Reset the mocks + mock_compression_manager.reset_mock() + mock_compressor.reset_mock() + + # The first return means that dest_file is instance of str + # The second means that mock_compressor is not instance of InternalCompressor + mock_isinstance.side_effect = [True, False] + + walrestore.RemoteGetWal(config, "000000010000000000000001", dest_file) + + # Then no decompress method is called because it is an instance of CommandCompressor + # which invokes a subprocess to decompress the file + mock_compressor.decompress.assert_not_called() + + # Assert that the subprocess was spanwed + mock_popen.assert_called_with( + ["some compression", "-d"], stdin=mock.ANY, stdout=mock.ANY + ) diff --git a/tests/test_cli.py b/tests/test_cli.py index bf2c90183..380a14983 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -52,8 +52,8 @@ manage_server_command, parse_backup_id, receive_wal, - recover, replication_status, + restore, show_servers, ) from barman.exceptions import WalArchiveContentError @@ -174,9 +174,9 @@ def test_get_server_inactive(self, monkeypatch): # If wal_streaming_conninfo is set and wal_conninfo is unset then # wal_streaming_conninfo is used for conninfo (True, "ws_conninfo", None, "ws_conninfo", "ws_conninfo"), - # If wal_streaming_conninfo is not set then conninfo and streaming_conninfo - # are not overridden even if wal_conninfo is set - (True, None, "w_conninfo", "s_conninfo", "conninfo"), + # If wal_streaming_conninfo is not set then conninfo is overridden and + # streaming_conninfo is not overridden if wal_conninfo is set + (True, None, "w_conninfo", "s_conninfo", "w_conninfo"), ), ) @patch("barman.cli.manage_server_command") @@ -412,9 +412,9 @@ def test_get_server_list_global_error_continue(self, monkeypatch): # If wal_streaming_conninfo is set and wal_conninfo is unset then # wal_streaming_conninfo is used for conninfo (True, "ws_conninfo", None, "ws_conninfo", "ws_conninfo"), - # If wal_streaming_conninfo is not set then conninfo and streaming_conninfo - # are not overridden even if wal_conninfo is set - (True, None, "w_conninfo", "s_conninfo", "conninfo"), + # If wal_streaming_conninfo is not set then conninfo is overriden and + # streaming_conninfo is not overridden if wal_conninfo is set + (True, None, "w_conninfo", "s_conninfo", "w_conninfo"), ), ) def test_get_server_list_wal_streaming( @@ -543,7 +543,7 @@ def mock_backup_info(self): return backup_info @pytest.fixture - def mock_recover_args(self): + def mock_restore_args(self): args = Mock() args.backup_id = "20170823T104400" args.server_name = "main" @@ -561,12 +561,12 @@ def mock_recover_args(self): @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_multiple_targets( + def test_restore_multiple_targets( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, monkeypatch, capsys, ): @@ -583,7 +583,7 @@ def test_recover_multiple_targets( ) # Testing mutual exclusiveness of target options - args = mock_recover_args + args = mock_restore_args args.backup_id = "20170823T104400" args.server_name = "main" args.destination_directory = "recovery_dir" @@ -591,7 +591,7 @@ def test_recover_multiple_targets( args.target_time = "2021-01-001 00:00:00.000" with pytest.raises(SystemExit): - recover(args) + restore(args) _, err = capsys.readouterr() assert ( @@ -601,12 +601,12 @@ def test_recover_multiple_targets( @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_one_target( + def test_restore_one_target( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, monkeypatch, capsys, ): @@ -623,26 +623,26 @@ def test_recover_one_target( ) # This parameters are fine - args = mock_recover_args + args = mock_restore_args args.backup_id = "20170823T104400" args.server_name = "main" args.destination_directory = "recovery_dir" args.target_action = None with pytest.raises(SystemExit): - recover(args) + restore(args) _, err = capsys.readouterr() assert "" == err @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_default_target( + def test_restore_default_target( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, monkeypatch, capsys, ): @@ -659,14 +659,14 @@ def test_recover_default_target( ) # This parameters are fine - args = mock_recover_args + args = mock_restore_args args.backup_id = "20170823T104400" args.server_name = "main" args.destination_directory = "recovery_dir" args.target_action = None with pytest.raises(SystemExit): - recover(args) + restore(args) _, err = capsys.readouterr() assert "" == err @@ -703,12 +703,12 @@ def test_recover_default_target( ) @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_get_wal( + def test_restore_get_wal( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, recovery_options, get_wal_arg, no_get_wal_arg, @@ -733,15 +733,15 @@ def test_recover_get_wal( # WHEN the specified --get-wal / --no-get-wal combinations are used if get_wal_arg: - mock_recover_args.get_wal = True + mock_restore_args.get_wal = True elif no_get_wal_arg: - mock_recover_args.get_wal = False + mock_restore_args.get_wal = False else: - del mock_recover_args.get_wal + del mock_restore_args.get_wal # WITH a barman recover command with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN then the presence of the get_wal recovery option matches expectations if expect_get_wal: @@ -800,12 +800,12 @@ def test_recover_get_wal( ) @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_recovery_staging_path( + def test_restore_recovery_staging_path( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, backup_is_compressed, recovery_staging_path_arg, recovery_staging_path_config, @@ -833,11 +833,11 @@ def test_recover_recovery_staging_path( (config,), ) # WHEN recover is called with the specified --recovery-staging-path - mock_recover_args.recovery_staging_path = recovery_staging_path_arg + mock_restore_args.recovery_staging_path = recovery_staging_path_arg # WITH a barman recover command with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN if we expected an error the error was observed _, err = capsys.readouterr() @@ -898,12 +898,12 @@ def test_recover_recovery_staging_path( ) @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_local_staging_path( + def test_restore_local_staging_path( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, backup_is_incremental, local_staging_path_arg, local_staging_path_config, @@ -929,11 +929,11 @@ def test_recover_local_staging_path( (config,), ) # WHEN recover is called with the specified --local-staging-path - mock_recover_args.local_staging_path = local_staging_path_arg + mock_restore_args.local_staging_path = local_staging_path_arg # WITH a barman recover command with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN if we expected an error the error was observed _, err = capsys.readouterr() @@ -961,14 +961,14 @@ def test_recover_local_staging_path( @patch("barman.output.error") @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_backup_status( + def test_restore_backup_status( self, get_server_mock, parse_backup_id_mock, error_mock, status, should_error, - mock_recover_args, + mock_restore_args, ): server = build_mocked_server(name="test_server") @@ -982,17 +982,17 @@ def test_recover_backup_status( ) parse_backup_id_mock.return_value = backup_info - mock_recover_args.backup_id = "test_backup_id" - mock_recover_args.snapshot_recovery_instance = None + mock_restore_args.backup_id = "test_backup_id" + mock_restore_args.snapshot_recovery_instance = None with pytest.raises( SystemExit, ): - recover(mock_recover_args) + restore(mock_restore_args) if should_error: error_mock.assert_called_once_with( - "Cannot recover from backup '%s' of server " + "Cannot restore from backup '%s' of server " "'%s': backup status is not DONE", "test_backup_id", "test_server", @@ -1059,12 +1059,12 @@ def test_recover_backup_status( ) @patch("barman.cli.get_server") @patch("barman.cli.parse_backup_id") - def test_recover_snapshots( + def test_restore_snapshots( self, parse_backup_id_mock, get_server_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, snapshots_info, snapshot_recovery_args, extra_recovery_args, @@ -1078,14 +1078,14 @@ def test_recover_snapshots( mock_backup_info.tablespaces[-1].name = "tbs1" parse_backup_id_mock.return_value = mock_backup_info # AND the specified additional recovery args - mock_recover_args.snapshot_recovery_instance = None + mock_restore_args.snapshot_recovery_instance = None extra_recovery_args.update(snapshot_recovery_args) for k, v in extra_recovery_args.items(): - setattr(mock_recover_args, k, v) + setattr(mock_restore_args, k, v) # WHEN barman recover is called with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN if we expected an error the error was observed server = get_server_mock.return_value @@ -1105,8 +1105,8 @@ def test_recover_snapshots( @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_recovery_instance_kwarg_not_passed( - self, get_server_mock, parse_backup_id_mock, mock_backup_info, mock_recover_args + def test_restore_recovery_instance_kwarg_not_passed( + self, get_server_mock, parse_backup_id_mock, mock_backup_info, mock_restore_args ): """ Verifies that recovery_instance is not passed to server.recover for @@ -1116,14 +1116,14 @@ def test_recover_recovery_instance_kwarg_not_passed( mock_backup_info.snapshots_info = None parse_backup_id_mock.return_value = mock_backup_info # AND the args do not specify a recovery instance - mock_recover_args.snapshot_recovery_instance = None + mock_restore_args.snapshot_recovery_instance = None # AND the args do not specify any other snapshot provider options - mock_recover_args.azure_resource_group = None - mock_recover_args.gcp_zone = None + mock_restore_args.azure_resource_group = None + mock_restore_args.gcp_zone = None # WHEN barman recover is called with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN recover was called once get_server_mock.return_value.recover.assert_called_once() @@ -1143,12 +1143,12 @@ def test_recover_recovery_instance_kwarg_not_passed( ) @patch("barman.cli.parse_backup_id") @patch("barman.cli.get_server") - def test_recover_snapshot_provider_args( + def test_restore_snapshot_provider_args( self, get_server_mock, parse_backup_id_mock, mock_backup_info, - mock_recover_args, + mock_restore_args, arg, arg_alias, ): @@ -1165,29 +1165,29 @@ def test_recover_snapshot_provider_args( parse_backup_id_mock.return_value = mock_backup_info # WHEN recover is called without overriding the config - setattr(mock_recover_args, arg, None) + setattr(mock_restore_args, arg, None) if arg_alias is not None: - setattr(mock_recover_args, arg_alias, None) + setattr(mock_restore_args, arg_alias, None) with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN the config value is unchanged assert getattr(config, arg) == initial_value # WHEN recover is called with the override argument updated_value = "updated" - setattr(mock_recover_args, arg, updated_value) + setattr(mock_restore_args, arg, updated_value) with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN the config value is updated assert getattr(config, arg) == updated_value # WHEN recover is called with the alias final_value = "final" if arg_alias is not None: - setattr(mock_recover_args, arg_alias, final_value) - setattr(mock_recover_args, arg, None) + setattr(mock_restore_args, arg_alias, final_value) + setattr(mock_restore_args, arg, None) with pytest.raises(SystemExit): - recover(mock_recover_args) + restore(mock_restore_args) # THEN the config value is updated assert getattr(config, arg) == final_value diff --git a/tests/test_cloud.py b/tests/test_cloud.py index 23c3711fe..a8e408a2c 100644 --- a/tests/test_cloud.py +++ b/tests/test_cloud.py @@ -602,7 +602,11 @@ def test_upload_fileobj(self, boto_mock): cloud_interface.upload_fileobj(mock_fileobj, mock_key) s3_client.upload_fileobj.assert_called_once_with( - Fileobj=mock_fileobj, Bucket="bucket", Key=mock_key, ExtraArgs={} + Fileobj=mock_fileobj, + Bucket="bucket", + Key=mock_key, + ExtraArgs={}, + Config=cloud_interface.config, ) @pytest.mark.parametrize( @@ -644,6 +648,7 @@ def test_upload_fileobj_with_encryption( Bucket="bucket", Key=mock_key, ExtraArgs=expected_extra_args, + Config=cloud_interface.config, ) @pytest.mark.parametrize( @@ -693,6 +698,7 @@ def test_upload_fileobj_with_tags( ExtraArgs={ "Tagging": expected_tagging, }, + Config=cloud_interface.config, ) @mock.patch("barman.cloud_providers.aws_s3.boto3") diff --git a/tests/test_cloud_snapshot_interface.py b/tests/test_cloud_snapshot_interface.py index 819f93aa9..3775c6527 100644 --- a/tests/test_cloud_snapshot_interface.py +++ b/tests/test_cloud_snapshot_interface.py @@ -16,6 +16,9 @@ # You should have received a copy of the GNU General Public License # along with Barman. If not, see . +import datetime +import itertools +import json import logging import mock @@ -142,13 +145,22 @@ def test_from_config_aws(self, mock_boto3): aws_region="us-east-2", aws_profile="default", aws_await_snapshots_timeout=7200, + aws_snapshot_lock_mode="compliance", + aws_snapshot_lock_duration=1, + aws_snapshot_lock_cool_off_period=2, + aws_snapshot_lock_expiration_date=datetime.datetime(2024, 1, 1), ) + # WHEN get_snapshot_interface_from_server_config is called snapshot_interface = get_snapshot_interface_from_server_config(mock_config) # THEN the config values are passed to the snapshot interface assert isinstance(snapshot_interface, AwsCloudSnapshotInterface) assert snapshot_interface.region == "us-east-2" assert snapshot_interface.await_snapshots_timeout == 7200 + assert snapshot_interface.lock_mode == "compliance" + assert snapshot_interface.lock_duration == 1 + assert snapshot_interface.lock_cool_off_period == 2 + assert snapshot_interface.lock_expiration_date == datetime.datetime(2024, 1, 1) mock_boto3.Session.assert_called_once_with(profile_name="default") @pytest.mark.parametrize( @@ -373,6 +385,11 @@ def test_from_args_aws(self, mock_boto3): aws_region="us-east-2", aws_profile="default", aws_await_snapshots_timeout=7200, + aws_snapshot_lock_mode="compliance", + aws_snapshot_lock_duration=1, + aws_snapshot_lock_cool_off_period=2, + aws_snapshot_lock_expiration_date=datetime.datetime(2024, 1, 1), + tags=None, ) # WHEN get_snapshot_interface is called snapshot_interface = get_snapshot_interface(mock_config) @@ -380,6 +397,10 @@ def test_from_args_aws(self, mock_boto3): assert isinstance(snapshot_interface, AwsCloudSnapshotInterface) assert snapshot_interface.region == "us-east-2" assert snapshot_interface.await_snapshots_timeout == 7200 + assert snapshot_interface.lock_mode == "compliance" + assert snapshot_interface.lock_duration == 1 + assert snapshot_interface.lock_cool_off_period == 2 + assert snapshot_interface.lock_expiration_date == datetime.datetime(2024, 1, 1) mock_boto3.Session.assert_called_once_with(profile_name="default") @@ -2623,6 +2644,33 @@ def _get_mock_describe_volumes_resp(self, disks): ] } + def _get_mock_lock_snapshot(self, disks): + """Helper which returns a mock lock_snapshot response.""" + lock_created_on = datetime.datetime( + 2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc + ) + + responses = iter( + [ + { + "SnapshotId": self._get_snapshot_id(disk), + "LockState": "compliance", + "LockDuration": 1, + "CoolOffPeriod": 1, + "CoolOffPeriodExpiresOn": ( + lock_created_on + datetime.timedelta(hours=1) + ), + "LockCreatedOn": lock_created_on, + } + for disk in disks + ] + ) + + def mock_fun(*args, **kwargs): + return next(responses) + + return mock_fun + def _get_snapshot_id(self, disk): """Helper which forges the expected snapshot id for the given disk id.""" return disk["id"].replace("vol", "snap") @@ -2691,12 +2739,16 @@ def test_init(self, init_args, expected_session_args, expected_region): # AND the default region is set on the snapshot interface assert snapshot_interface.region == mock_session.region_name - def test_create_snapshot(self, caplog): + @pytest.mark.parametrize( + "tags", (None, [("environment", "production"), ("project", "my-project")]) + ) + def test_create_snapshot(self, tags, caplog): """ Verify that _create_snapshot calls boto3 and returns the expected values. + Check if tags are applied when set. """ # GIVEN a new AwsCloudInterface - snapshot_interface = AwsCloudSnapshotInterface() + snapshot_interface = AwsCloudSnapshotInterface(tags=tags) # AND a backup_info for a given server name and backup ID backup_info = mock.Mock(backup_id=self.backup_id, server_name=self.server_name) # AND a mock create_snapshot function which returns a successful response @@ -2717,13 +2769,19 @@ def test_create_snapshot(self, caplog): # THEN create_snapshot is called on the EC2 client with the expected args mock_ec2_client.create_snapshot.assert_called_once() - mock_ec2_client.create_snapshot.assert_called_once_with( - TagSpecifications=[ - { - "ResourceType": "snapshot", - "Tags": [{"Key": "Name", "Value": snapshot_name}], - } + tag_specs = { + "ResourceType": "snapshot", + "Tags": [ + {"Key": "Name", "Value": snapshot_name}, ], + } + + if tags: + for key, value in tags: + tag_specs["Tags"].append({"Key": key, "Value": value}) + + mock_ec2_client.create_snapshot.assert_called_once_with( + TagSpecifications=[tag_specs], VolumeId=volume_id, ) # AND snapshot_name has the expected value @@ -2768,11 +2826,51 @@ def test_create_snapshot_failed(self): expected_snapshot_name = "my-pgdata-volume-{}".format(self.backup_id.lower()) assert "Snapshot '{}' failed".format(expected_snapshot_name) in str(exc.value) - @pytest.mark.parametrize("number_of_disks", (1, 2, 3)) - def test_take_snapshot_backup(self, number_of_disks, mock_ec2_client): + def test__lock_snapshot(self, caplog): + """ + Verify that _lock_snapshot calls boto3. + """ + args = { + "snapshot_id": "snap-123", + "lock_mode": "governance", + "lock_duration": None, + "lock_cool_off_period": None, + "lock_expiration_date": "2025-11-08T21:53:00.606Z", + } + + snapshot_interface = AwsCloudSnapshotInterface() + mock_ec2_client = self._mock_boto3.Session.return_value.client.return_value + mock_resp = mock_ec2_client.lock_snapshot.return_value + mock_resp["SnapshotId"] = args["snapshot_id"] + mock_resp["LockState"] = args["lock_mode"] + mock_resp["LockCreatedOn"] = "1991-01-01T00:00:00.000Z" + mock_resp["LockExpiresOn"] = args["lock_expiration_date"] + caplog.set_level(logging.INFO) + + _ = snapshot_interface._lock_snapshot(**args) + + mock_ec2_client.lock_snapshot.assert_called_once_with( + SnapshotId="snap-123", + LockMode="governance", + ExpirationDate="2025-11-08T21:53:00.606Z", + ) + + assert ( + "Snapshot locked: \n%s" % json.dumps(dict(mock_resp), indent=4) + in caplog.text + ) + + @pytest.mark.parametrize( + ("number_of_disks", "snapshot_lock"), + list(itertools.product((1, 2, 3), (True, False))), + ) + def test_take_snapshot_backup( + self, number_of_disks, snapshot_lock, mock_ec2_client + ): """ Verify that take_snapshot_backup waits for completion of all snapshots and - updates the backup_info when complete. + updates the backup_info when complete. Also verifies if the _lock_snapshot is + called when the interface has a lock_mode. """ # GIVEN a set of disks, represented as VolumeMetadata disks = self.aws_disks[:number_of_disks] @@ -2785,22 +2883,30 @@ def test_take_snapshot_backup(self, number_of_disks, mock_ec2_client): mock_ec2_client.describe_instances.return_value = ( self._get_mock_describe_instances_resp(disks) ) - # AND the mock EC2 client returns successful create_snapashot responses + # AND the mock EC2 client returns successful create_snapshot responses mock_ec2_client.create_snapshot.side_effect = self._get_mock_create_snapshot( disks ) # AND a new AwsCloudSnapshotInterface snapshot_interface = AwsCloudSnapshotInterface(region=self.aws_region) + snapshot_interface.lock_mode = snapshot_lock # WHEN take_snapshot_backup is called snapshot_interface.take_snapshot_backup( backup_info, self.aws_instance_id, volumes ) + # When there is a lock_mode, we check if it was called for all disks + if snapshot_interface.lock_mode: + mock_ec2_client.lock_snapshot.call_count == number_of_disks + mock_ec2_client.lock_snapshot.side_effect = self._get_mock_lock_snapshot( + disks + ) + # THEN we waited for completion of all snapshots expected_snapshot_ids = [self._get_snapshot_id(disk) for disk in disks] mock_ec2_client.get_waiter.return_value.wait.assert_called_once_with( - Filters=[{"Name": "snapshot-id", "Values": expected_snapshot_ids}], + SnapshotIds=expected_snapshot_ids, WaiterConfig={"Delay": 15, "MaxAttempts": 240}, ) @@ -2907,7 +3013,7 @@ def test_take_snapshot_backup_wait( mock_ec2_client.describe_instances.return_value = ( self._get_mock_describe_instances_resp(disks) ) - # AND the mock EC2 client returns successful create_snapashot responses + # AND the mock EC2 client returns successful create_snapshot responses mock_ec2_client.create_snapshot.side_effect = self._get_mock_create_snapshot( disks ) @@ -2925,11 +3031,11 @@ def test_take_snapshot_backup_wait( # THEN we waited for completion of all snapshots with the expected WaiterConfig expected_snapshot_ids = [self._get_snapshot_id(disk) for disk in disks] mock_ec2_client.get_waiter.return_value.wait.assert_called_once_with( - Filters=[{"Name": "snapshot-id", "Values": expected_snapshot_ids}], + SnapshotIds=expected_snapshot_ids, WaiterConfig=expected_wait_config, ) - aws_live_states = ["pending", "running", "shutting-down", "stopping", "stopped"] + AWS_LIVE_STATES = ["pending", "running", "shutting-down", "stopping", "stopped"] def test_get_instance_metadata_by_id(self, mock_ec2_client): """ @@ -2951,7 +3057,7 @@ def test_get_instance_metadata_by_id(self, mock_ec2_client): # THEN describe_instances was called once with the instance ID and filter mock_ec2_client.describe_instances.assert_called_once_with( InstanceIds=[self.aws_instance_id], - Filters=[{"Name": "instance-state-name", "Values": self.aws_live_states}], + Filters=[{"Name": "instance-state-name", "Values": self.AWS_LIVE_STATES}], ) # AND the mock instance metadata was returned @@ -2980,14 +3086,14 @@ def test_get_instance_metadata_by_id_like_name(self, mock_ec2_client): assert mock_ec2_client.describe_instances.call_args_list[0][1] == { "InstanceIds": [instance_name], "Filters": [ - {"Name": "instance-state-name", "Values": self.aws_live_states} + {"Name": "instance-state-name", "Values": self.AWS_LIVE_STATES} ], } # AND again with a tag filter assert mock_ec2_client.describe_instances.call_args_list[1][1] == { "Filters": [ {"Name": "tag:Name", "Values": [instance_name]}, - {"Name": "instance-state-name", "Values": self.aws_live_states}, + {"Name": "instance-state-name", "Values": self.AWS_LIVE_STATES}, ] } @@ -3014,7 +3120,7 @@ def test_get_instance_metadata_by_name(self, mock_ec2_client): mock_ec2_client.describe_instances.assert_called_once_with( Filters=[ {"Name": "tag:Name", "Values": [instance_name]}, - {"Name": "instance-state-name", "Values": self.aws_live_states}, + {"Name": "instance-state-name", "Values": self.AWS_LIVE_STATES}, ] ) @@ -3439,7 +3545,10 @@ def test_delete_snapshot_failed(self, mock_ec2_client, caplog): ( [], [mock.Mock(identifier="snap-0123")], - [mock.Mock(identifier="snap-0123"), mock.Mock(identifier="snap0124")], + [ + mock.Mock(identifier="snap-0123"), + mock.Mock(identifier="snap0124"), + ], ), ) def test_delete_snapshot_backup(self, snapshots_list, mock_ec2_client, caplog): @@ -3465,6 +3574,27 @@ def test_delete_snapshot_backup(self, snapshots_list, mock_ec2_client, caplog): ] mock_ec2_client.delete_snapshot.assert_has_calls(expected_calls) + def test_delete_snapshot_with_lock(self, mock_ec2_client): + """Verify that a snapshot is not deleted and an error is raised.""" + mock_ec2_client.delete_snapshot.side_effect = ( + ClientError({"Error": {"Code": "SnapshotLocked"}}, "message"), + ) + # AND a mock snapshots interface + snapshot_interface = AwsCloudSnapshotInterface(region=self.aws_region) + + snapshot_id = "snap-0123" + with pytest.raises(SystemExit) as exc: + snapshot_interface._delete_snapshot(snapshot_id) + + # AND the exception has the expected message + expected_message = ( + f"Locked snapshot: {snapshot_id}.\n" + "Before deleting a snapshot, please ensure that it is not locked " + "or that the lock has expired." + ) + + assert expected_message in str(exc.value) + class TestAwsVolumeMetadata(object): """Verify behaviour of AwsVolumeMetadata.""" diff --git a/tests/test_compressor.py b/tests/test_compressor.py index 2a836cf64..a3591abb5 100644 --- a/tests/test_compressor.py +++ b/tests/test_compressor.py @@ -35,6 +35,7 @@ GZipCompressor, GZipPgBaseBackupCompressionOption, LZ4Compression, + LZ4Compressor, LZ4PgBaseBackupCompressionOption, NoneCompression, NonePgBaseBackupCompressionOption, @@ -42,7 +43,9 @@ PgBaseBackupCompressionOption, PyBZip2Compressor, PyGZipCompressor, + XZCompressor, ZSTDCompression, + ZSTDCompressor, ZSTDPgBaseBackupCompressionOption, get_pg_basebackup_compression, ) @@ -57,6 +60,12 @@ ZIP_FILE_UNCOMPRESSED = "%s/zipfile.uncompressed" BZIP2_FILE = "%s/bzipfile.bz2" BZIP2_FILE_UNCOMPRESSED = "%s/bzipfile.uncompressed" +XZ_FILE = "%s/xzfile.xz" +XZ_FILE_UNCOMPRESSED = "%s/xzflile.uncompressed" +ZSTD_FILE = "%s/zstdfile.zst" +ZSTD_FILE_UNCOMPRESSED = "%s/zstdfile.uncompressed" +LZ4_FILE = "%s/lz4file.lz4" +LZ4_FILE_UNCOMPRESSED = "%s/lz4file.uncompressed" def _tar_file(items): @@ -127,7 +136,7 @@ def test_get_compressor_custom(self, _reset_custom_compressor): assert comp_manager.unidentified_compression is None # AND the value of MAGIC_MAX_LENGTH equals the length of the magic bytes - assert comp_manager.MAGIC_MAX_LENGTH == 4 + assert comp_manager.MAGIC_MAX_LENGTH == 6 def test_get_compressor_custom_nomagic(self, _reset_custom_compressor): # GIVEN a Barman config which specifies custom compression @@ -154,7 +163,7 @@ def test_get_compressor_custom_nomagic(self, _reset_custom_compressor): # AND the value of MAGIC_MAX_LENGTH equals the max length of the default # compressions - assert comp_manager.MAGIC_MAX_LENGTH == 3 + assert comp_manager.MAGIC_MAX_LENGTH == 6 def test_get_compressor_gzip(self): # prepare mock obj @@ -174,6 +183,29 @@ def test_get_compressor_bzip2(self): comp_manager = CompressionManager(config_mock, None) assert comp_manager.get_default_compressor() is not None + def test_get_compressor_xz(self): + # prepare mock obj + config_mock = mock.Mock() + config_mock.compression = "xz" + + # check custom compression method creation + comp_manager = CompressionManager(config_mock, None) + assert comp_manager.get_default_compressor() is not None + + def test_get_compressor_zstd(self): + # prepare mock obj + config_mock = mock.Mock() + config_mock.compression = "zstd" + + def test_get_compressor_lz4(self): + # prepare mock obj + config_mock = mock.Mock() + config_mock.compression = "lz4" + + # check custom compression method creation + comp_manager = CompressionManager(config_mock, None) + assert comp_manager.get_default_compressor() is not None + def test_get_compressor_invalid(self): # prepare mock obj config_mock = mock.Mock() @@ -370,6 +402,81 @@ def test_bzip2(self, tmpdir): f = open(BZIP2_FILE_UNCOMPRESSED % tmpdir.strpath).read() assert f == "content" + def test_xz(self, tmpdir): + config_mock = mock.Mock() + + compression_manager = CompressionManager(config_mock, tmpdir.strpath) + + compressor = XZCompressor(config=config_mock, compression="xz") + + src = tmpdir.join("sourcefile") + src.write("content") + + compressor.compress(src.strpath, XZ_FILE % tmpdir.strpath) + assert os.path.exists(XZ_FILE % tmpdir.strpath) + compression_found = compression_manager.identify_compression( + XZ_FILE % tmpdir.strpath, + ) + assert compression_found == "xz" + + compressor.decompress( + XZ_FILE % tmpdir.strpath, + XZ_FILE_UNCOMPRESSED % tmpdir.strpath, + ) + + f = open(XZ_FILE_UNCOMPRESSED % tmpdir.strpath).read() + assert f == "content" + + def test_zstd(self, tmpdir): + config_mock = mock.Mock() + + compression_manager = CompressionManager(config_mock, tmpdir.strpath) + + compressor = ZSTDCompressor(config=config_mock, compression="zstd") + + src = tmpdir.join("sourcefile") + src.write("content") + + compressor.compress(src.strpath, ZSTD_FILE % tmpdir.strpath) + assert os.path.exists(ZSTD_FILE % tmpdir.strpath) + compression_found = compression_manager.identify_compression( + ZSTD_FILE % tmpdir.strpath, + ) + assert compression_found == "zstd" + + compressor.decompress( + ZSTD_FILE % tmpdir.strpath, + ZSTD_FILE_UNCOMPRESSED % tmpdir.strpath, + ) + + f = open(ZSTD_FILE_UNCOMPRESSED % tmpdir.strpath).read() + assert f == "content" + + def test_lz4(self, tmpdir): + config_mock = mock.Mock() + + compression_manager = CompressionManager(config_mock, tmpdir.strpath) + + compressor = LZ4Compressor(config=config_mock, compression="lz4") + + src = tmpdir.join("sourcefile") + src.write("content") + + compressor.compress(src.strpath, LZ4_FILE % tmpdir.strpath) + assert os.path.exists(LZ4_FILE % tmpdir.strpath) + compression_found = compression_manager.identify_compression( + LZ4_FILE % tmpdir.strpath, + ) + assert compression_found == "lz4" + + compressor.decompress( + LZ4_FILE % tmpdir.strpath, + LZ4_FILE_UNCOMPRESSED % tmpdir.strpath, + ) + + f = open(LZ4_FILE_UNCOMPRESSED % tmpdir.strpath).read() + assert f == "content" + # noinspection PyMethodMayBeStatic class TestCustomCompressor(object): @@ -454,11 +561,11 @@ def test_get_pg_basebackup_compression( ) base_backup_compression = get_pg_basebackup_compression(server) - assert type(base_backup_compression) is expected_class + assert isinstance(base_backup_compression, expected_class) if base_backup_compression is not None: - assert type(base_backup_compression.options) is expected_option_class - assert ( - type(base_backup_compression.compression) is expected_compression_class + assert isinstance(base_backup_compression.options, expected_option_class) + assert isinstance( + base_backup_compression.compression, expected_compression_class ) def test_get_pg_basebackup_compression_not_supported(self): diff --git a/tests/test_config.py b/tests/test_config.py index 17bbb2955..7dc2e3c15 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1336,6 +1336,10 @@ def test_to_json(self, model_config): "archiver_batch_size": None, "autogenerate_manifest": None, "aws_await_snapshots_timeout": None, + "aws_snapshot_lock_mode": None, + "aws_snapshot_lock_duration": None, + "aws_snapshot_lock_cool_off_period": None, + "aws_snapshot_lock_expiration_date": None, "aws_profile": None, "aws_region": None, "azure_credential": None, @@ -1425,6 +1429,16 @@ def test_to_json_with_config_source(self, model_config): "archiver_batch_size": {"source": "SOME_SOURCE", "value": None}, "autogenerate_manifest": {"source": "SOME_SOURCE", "value": None}, "aws_await_snapshots_timeout": {"source": "SOME_SOURCE", "value": None}, + "aws_snapshot_lock_mode": {"source": "SOME_SOURCE", "value": None}, + "aws_snapshot_lock_duration": {"source": "SOME_SOURCE", "value": None}, + "aws_snapshot_lock_cool_off_period": { + "source": "SOME_SOURCE", + "value": None, + }, + "aws_snapshot_lock_expiration_date": { + "source": "SOME_SOURCE", + "value": None, + }, "aws_profile": {"source": "SOME_SOURCE", "value": None}, "aws_region": {"source": "SOME_SOURCE", "value": None}, "azure_credential": {"source": "SOME_SOURCE", "value": None}, @@ -1515,9 +1529,9 @@ def test_to_json_with_config_source(self, model_config): # If neither wal_streaming_conninfo nor wal_conninfo are set then we expect # the regular conninfo to be returned (None, None, ("s_conninfo", "conninfo")), - # If wal_streaming_conninfo is not set we expect the regular conninfo to be + # If wal_streaming_conninfo is not set we expect the wal_conninfo to be # returned - (None, "w_conninfo", ("s_conninfo", "conninfo")), + (None, "w_conninfo", ("s_conninfo", "w_conninfo")), # If wal_streaming_conninfo is set and wal_conninfo is not then we expect # wal_streaming_conninfo to be returned for both ("ws_conninfo", None, ("ws_conninfo", "ws_conninfo")), diff --git a/tests/test_infofile.py b/tests/test_infofile.py index 3d7c3dae1..53246b3fa 100644 --- a/tests/test_infofile.py +++ b/tests/test_infofile.py @@ -538,6 +538,44 @@ def test_backup_type(self, mode, parent_backup_id, expected_backup_type): assert backup_info.backup_type == expected_backup_type + def test_is_orphan(self, tmpdir): + """ + Ensure :meth:`LocalBackupInfo.is_orphan` returns the correct value. + """ + server = build_mocked_server( + main_conf={"basebackups_directory": tmpdir.strpath}, + ) + + # Case 1: Orphan backup (only backup.info file, status not empty) + backup_dir = tmpdir.mkdir("orphan_backup") + backup_info_path = backup_dir.join("backup.info") + backup_info_path.write("status = DONE\n") + b_info = LocalBackupInfo(server, backup_id="orphan_backup") + b_info.status = BackupInfo.DONE + assert b_info.is_orphan is True + + # Case 2: Not orphan (backup.info file and other files) + backup_dir = tmpdir.mkdir("not_orphan_backup") + backup_info_path = backup_dir.join("backup.info") + backup_info_path.write("status = DONE\n") + backup_dir.join("other_file").write("some content") + b_info = LocalBackupInfo(server, backup_id="not_orphan_backup") + b_info.status = BackupInfo.DONE + assert b_info.is_orphan is False + + # Case 3: Not orphan (status is empty) + backup_dir = tmpdir.mkdir("empty_status_backup") + backup_info_path = backup_dir.join("backup.info") + backup_info_path.write("status = EMPTY\n") + b_info = LocalBackupInfo(server, backup_id="empty_status_backup") + b_info.status = BackupInfo.EMPTY + assert b_info.is_orphan is False + + # Case 4: Not orphan (no backup.info file) + backup_dir = tmpdir.mkdir("no_backup_info") + b_info = LocalBackupInfo(server, backup_id="no_backup_info") + assert b_info.is_orphan is False + def test_backup_info_save(self, tmpdir): """ Test the save method of a BackupInfo object @@ -886,6 +924,7 @@ def test_with_snapshots_info_aws(self, tmpdir): device_name="/dev/sdf", snapshot_name="user-assigned name", snapshot_id="snap-0123", + snapshot_lock_mode="compliance", ) ], ) @@ -902,6 +941,7 @@ def test_with_snapshots_info_aws(self, tmpdir): assert snapshot0.device_name == "/dev/sdf" assert snapshot0.snapshot_name == "user-assigned name" assert snapshot0.snapshot_id == "snap-0123" + assert snapshot0.snapshot_lock_mode == "compliance" # AND the snapshots_info is included in the JSON output snapshots_json = b_info.to_json()["snapshots_info"] @@ -913,6 +953,7 @@ def test_with_snapshots_info_aws(self, tmpdir): assert snapshot0_json["provider"]["device_name"] == "/dev/sdf" assert snapshot0_json["provider"]["snapshot_name"] == "user-assigned name" assert snapshot0_json["provider"]["snapshot_id"] == "snap-0123" + assert snapshot0_json["provider"]["snapshot_lock_mode"] == "compliance" def test_with_no_snapshots_info(self, tmpdir): """ diff --git a/tests/test_recovery_executor.py b/tests/test_recovery_executor.py index 486be47be..b2ae5dcc5 100644 --- a/tests/test_recovery_executor.py +++ b/tests/test_recovery_executor.py @@ -1496,7 +1496,7 @@ def test_recover_waiting_for_wals( "are required for consistency." ), mock.call( - "IMPORTANT: The backup we have recovered IS NOT " + "IMPORTANT: The backup we have restored IS NOT " "VALID. Required WAL files for consistency are " "missing. Please verify that WAL archiving is " "working correctly or evaluate using the 'get-wal' " diff --git a/tests/test_retention_policies.py b/tests/test_retention_policies.py index c2c8767ad..dc49ae195 100644 --- a/tests/test_retention_policies.py +++ b/tests/test_retention_policies.py @@ -16,7 +16,6 @@ # You should have received a copy of the GNU General Public License # along with Barman. If not, see . -import itertools import logging import re from datetime import datetime, timedelta @@ -35,8 +34,66 @@ ) -class TestRetentionPolicies(object): +@pytest.fixture(scope="module") +def server_with_incremental_backups(): + backup_manager = mock.Mock() + backup_manager.get_keep_target.return_value = None + server = build_mocked_server() + server.backup_manager = backup_manager + backups_data = { + "20240628T000000": { + "parent_backup_id": None, + "children_backup_ids": ["20240628T120000"], + "end_time": datetime.now(tzlocal()) - timedelta(weeks=6, days=1), + }, + "20240628T120000": { + "parent_backup_id": "20240628T000000", + "children_backup_ids": None, + "end_time": datetime.now(tzlocal()) - timedelta(weeks=6), + }, + "20240629T000000": { + "parent_backup_id": None, + "children_backup_ids": ["20240629T120000"], + "end_time": datetime.now(tzlocal()) - timedelta(weeks=5, days=1), + }, + "20240629T120000": { + "parent_backup_id": "20240629T000000", + "children_backup_ids": None, + "end_time": datetime.now(tzlocal()) - timedelta(weeks=5), + }, + "20240630T060000": { + "parent_backup_id": None, + "children_backup_ids": ["20240630T120000"], + "end_time": datetime.now(tzlocal()) - timedelta(weeks=3, days=1), + }, + "20240630T120000": { + "parent_backup_id": "20240630T060000", + "children_backup_ids": None, + "end_time": datetime.now(tzlocal()) - timedelta(weeks=3), + }, + "20240630T000000": { + "parent_backup_id": None, + "children_backup_ids": None, + "end_time": datetime.now(tzlocal()), + }, + } + + available_backups = {} + for bkp_id, info in backups_data.items(): + available_backups[bkp_id] = build_test_backup_info( + backup_id=bkp_id, + server=server, + parent_backup_id=info["parent_backup_id"], + children_backup_ids=info["children_backup_ids"], + end_time=info["end_time"], + ) + + server.get_available_backups.return_value = available_backups + + yield server + +class TestRetentionPolicies(object): @pytest.fixture def server(self): backup_manager = mock.Mock() @@ -45,46 +102,38 @@ def server(self): server.backup_manager = backup_manager yield server - def test_redundancy_report(self, server, caplog): + def test_redundancy_report(self, server_with_incremental_backups, caplog): """ Test of the management of the minimum_redundancy parameter into the backup_report method of the RedundancyRetentionPolicy class """ rp = RetentionPolicyFactory.create( - "retention_policy", "REDUNDANCY 2", server=server + "retention_policy", "REDUNDANCY 2", server=server_with_incremental_backups ) assert isinstance(rp, RedundancyRetentionPolicy) - # Build a BackupInfo object with status to DONE - backup_info = build_test_backup_info( - server=server, backup_id="test1", end_time=datetime.now(tzlocal()) - ) - - # instruct the get_available_backups method to return a map with - # our mock as result and minimum_redundancy = 1 - server.get_available_backups.return_value = { - "test_backup": backup_info, - "test_backup2": backup_info, - "test_backup3": backup_info, - } - server.config.minimum_redundancy = 1 + server_with_incremental_backups.config.minimum_redundancy = 1 # execute retention policy report report = rp.report() # check that our mock is valid for the retention policy because # the total number of valid backups is lower than the retention policy # redundancy. assert report == { - "test_backup": BackupInfo.OBSOLETE, - "test_backup2": BackupInfo.VALID, - "test_backup3": BackupInfo.VALID, + "20240628T000000": BackupInfo.OBSOLETE, + "20240628T120000": BackupInfo.OBSOLETE, + "20240629T000000": BackupInfo.OBSOLETE, + "20240629T120000": BackupInfo.OBSOLETE, + "20240630T000000": BackupInfo.VALID, + "20240630T060000": BackupInfo.VALID, + "20240630T120000": BackupInfo.VALID, } # Expect a ValueError if passed context is invalid with pytest.raises(ValueError): rp.report(context="invalid") # Set a new minimum_redundancy parameter, enforcing the usage of the # configuration parameter instead of the retention policy default - server.config.minimum_redundancy = 3 + server_with_incremental_backups.config.minimum_redundancy = 3 # execute retention policy report rp.report() # Check for the warning inside the log @@ -97,7 +146,7 @@ def test_redundancy_report(self, server, caplog): "Enforce 3." ) - def test_recovery_window_report(self, server, caplog): + def test_recovery_window_report(self, server_with_incremental_backups, caplog): """ Basic unit test of RecoveryWindowRetentionPolicy @@ -107,42 +156,25 @@ def test_recovery_window_report(self, server, caplog): it as valid """ rp = RetentionPolicyFactory.create( - "retention_policy", "RECOVERY WINDOW OF 4 WEEKS", server=server + "retention_policy", + "RECOVERY WINDOW OF 4 WEEKS", + server=server_with_incremental_backups, ) assert isinstance(rp, RecoveryWindowRetentionPolicy) - # Build a BackupInfo object with status to DONE - backup_source = { - "test_backup3": build_test_backup_info( - server=server, - backup_id="test_backup3", - end_time=datetime.now(tzlocal()), - ) - } - # Add a obsolete backup - backup_source["test_backup2"] = build_test_backup_info( - server=server, - backup_id="test_backup2", - end_time=datetime.now(tzlocal()) - timedelta(weeks=5), - ) - # Add a second obsolete backup - backup_source["test_backup"] = build_test_backup_info( - server=server, - backup_id="test_backup", - end_time=datetime.now(tzlocal()) - timedelta(weeks=6), - ) - server.get_available_backups.return_value = backup_source - # instruct the get_available_backups method to return a map with - # our mock as result and minimum_redundancy = 1 - server.config.minimum_redundancy = 1 - server.config.name = "test" + server_with_incremental_backups.config.minimum_redundancy = 1 + server_with_incremental_backups.config.name = "test" # execute retention policy report report = rp.report() # check that our mock is valid for the retention policy assert report == { - "test_backup3": "VALID", - "test_backup2": "VALID", - "test_backup": "OBSOLETE", + "20240628T000000": BackupInfo.OBSOLETE, + "20240628T120000": BackupInfo.OBSOLETE, + "20240629T000000": BackupInfo.VALID, + "20240629T120000": BackupInfo.VALID, + "20240630T000000": BackupInfo.VALID, + "20240630T060000": BackupInfo.VALID, + "20240630T120000": BackupInfo.VALID, } # Expect a ValueError if passed context is invalid @@ -150,14 +182,14 @@ def test_recovery_window_report(self, server, caplog): rp.report(context="invalid") # Set a new minimum_redundancy parameter, enforcing the usage of the # configuration parameter instead of the retention policy default - server.config.minimum_redundancy = 4 + server_with_incremental_backups.config.minimum_redundancy = 4 # execute retention policy report rp.report() # Check for the warning inside the log caplog.set_level(logging.WARNING) log = caplog.text warn = ( - r"WARNING .*Keeping obsolete backup test_backup for " + r"WARNING .*Keeping obsolete backup 20240628T000000 for " r"server test \(older than .*\) due to minimum redundancy " r"requirements \(4\)\n" ) @@ -313,28 +345,12 @@ def test_first_backup(self, server): assert report == "test_backup" - @pytest.mark.parametrize( - ("retention_policy", "retention_status"), - itertools.product( - ("RECOVERY WINDOW OF 4 WEEKS", "REDUNDANCY 2"), - ( - BackupInfo.OBSOLETE, - BackupInfo.VALID, - BackupInfo.POTENTIALLY_OBSOLETE, - BackupInfo.KEEP_FULL, - BackupInfo.KEEP_STANDALONE, - BackupInfo.NONE, - ), - ), - ) @mock.patch("barman.retention_policies._logger.debug") @mock.patch("barman.infofile.LocalBackupInfo.walk_backups_tree") def test__propagate_retention_status_to_children( self, mock_walk_backups_tree, mock_logger, - retention_policy, - retention_status, server, tmpdir, ): @@ -364,6 +380,8 @@ def test__propagate_retention_status_to_children( children_backup_ids=b2,b4 status=DONE""", } + retention_policy = "RECOVERY WINDOW OF 4 WEEKS" + retention_status = BackupInfo.OBSOLETE backup_chain = {} for bkp in chain: infofile = tmpdir.mkdir(bkp).join("backup.info") @@ -382,195 +400,19 @@ def test__propagate_retention_status_to_children( ) report = {} + rp._propagate_retention_status_to_children(root, report, retention_status) mock_walk_backups_tree.assert_called_once() assert mock_logger.call_count == 5 - # For full backups with status KEEP, we propagate VALID status to children - if retention_status in (BackupInfo.KEEP_FULL, BackupInfo.KEEP_STANDALONE): - retention_status = BackupInfo.VALID + for backup_id in report: mock_logger.assert_any_call( "Propagating %s retention status of backup root to %s." % (retention_status, backup_id) ) - - for backup in report: - assert report[backup] == retention_status - - def test_redundancy_report_with_incrementals(self, server, caplog): - """ - Test of the management of the minimum_redundancy parameter - into the backup_report method of the RedundancyRetentionPolicy class - - """ - rp = RetentionPolicyFactory.create( - "retention_policy", "REDUNDANCY 2", server=server - ) - assert isinstance(rp, RedundancyRetentionPolicy) - - backups_data = { - "20240628T000000": { - "parent_backup_id": None, - "children_backup_ids": ["20240628T120000"], - "end_time": datetime.now(tzlocal()) - timedelta(weeks=6, days=1), - }, - "20240628T120000": { - "parent_backup_id": "20240628T000000", - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()) - timedelta(weeks=6), - }, - "20240629T000000": { - "parent_backup_id": None, - "children_backup_ids": ["20240629T120000"], - "end_time": datetime.now(tzlocal()) - timedelta(weeks=5, days=1), - }, - "20240629T120000": { - "parent_backup_id": "20240629T000000", - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()) - timedelta(weeks=5), - }, - "20240630T000000": { - "parent_backup_id": None, - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()), - }, - } - - available_backups = {} - for bkp_id, info in backups_data.items(): - available_backups[bkp_id] = build_test_backup_info( - backup_id=bkp_id, - server=server, - parent_backup_id=info["parent_backup_id"], - children_backup_ids=info["children_backup_ids"], - end_time=info["end_time"], - ) - - # instruct the get_available_backups method to return a map with - # our mock as result and minimum_redundancy = 1 - server.get_available_backups.return_value = available_backups - - server.config.minimum_redundancy = 1 - - # execute retention policy report - report = rp.report() - # check that our mock is valid for the retention policy because - # the total number of valid backups is lower than the retention policy - # redundancy. - assert report == { - "20240630T000000": "VALID", - "20240629T000000": "VALID", - "20240629T120000": "VALID", - "20240628T000000": "OBSOLETE", - "20240628T120000": "OBSOLETE", - } - - # Expect a ValueError if passed context is invalid - with pytest.raises(ValueError): - rp.report(context="invalid") - # Set a new minimum_redundancy parameter, enforcing the usage of the - # configuration parameter instead of the retention policy default - server.config.minimum_redundancy = 3 - # execute retention policy report - rp.report() - # Check for the warning inside the log - caplog.set_level(logging.WARNING) - - log = caplog.text - assert log.find( - "WARNING Retention policy redundancy (2) " - "is lower than the required minimum redundancy (3). " - "Enforce 3." - ) - - def test_recovery_window_report_with_incrementals(self, server, caplog): - """ - Test of the management of the minimum_redundancy parameter - into the backup_report method of the RecoveryWindowRetentionPolicy class - - """ - rp = RetentionPolicyFactory.create( - "retention_policy", "RECOVERY WINDOW OF 4 WEEKS", server=server - ) - assert isinstance(rp, RecoveryWindowRetentionPolicy) - - backups_data = { - "20240628T000000": { - "parent_backup_id": None, - "children_backup_ids": ["20240628T120000"], - "end_time": datetime.now(tzlocal()) - timedelta(weeks=6, days=1), - }, - "20240628T120000": { - "parent_backup_id": "20240628T000000", - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()) - timedelta(weeks=6), - }, - "20240629T000000": { - "parent_backup_id": None, - "children_backup_ids": ["20240629T120000"], - "end_time": datetime.now(tzlocal()) - timedelta(weeks=5, days=1), - }, - "20240629T120000": { - "parent_backup_id": "20240629T000000", - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()) - timedelta(weeks=5), - }, - "20240630T000000": { - "parent_backup_id": None, - "children_backup_ids": None, - "end_time": datetime.now(tzlocal()), - }, - } - - available_backups = {} - for bkp_id, info in backups_data.items(): - available_backups[bkp_id] = build_test_backup_info( - backup_id=bkp_id, - server=server, - parent_backup_id=info["parent_backup_id"], - children_backup_ids=info["children_backup_ids"], - end_time=info["end_time"], - ) - - # instruct the get_available_backups method to return a map with - # our mock as result and minimum_redundancy = 1 - server.get_available_backups.return_value = available_backups - - server.config.minimum_redundancy = 1 - server.config.name = "test" - - # execute retention policy report - report = rp.report() - # check that our mock is valid for the retention policy because - # the total number of valid backups is lower than the retention policy - # redundancy. - assert report == { - "20240630T000000": "VALID", - "20240629T000000": "VALID", - "20240629T120000": "VALID", - "20240628T000000": "OBSOLETE", - "20240628T120000": "OBSOLETE", - } - - # Expect a ValueError if passed context is invalid - with pytest.raises(ValueError): - rp.report(context="invalid") - # Set a new minimum_redundancy parameter, enforcing the usage of the - # configuration parameter instead of the retention policy default - server.config.minimum_redundancy = 4 - # execute retention policy report - rp.report() - # Check for the warning inside the log - caplog.set_level(logging.WARNING) - log = caplog.text - warn = ( - r"WARNING .*Keeping obsolete backup 20240628T000000 for " - r"server test \(older than .*\) due to minimum redundancy " - r"requirements \(4\)\n" - ) - assert re.search(warn, log) + assert report[backup_id] == retention_status class TestRedundancyRetentionPolicyWithKeepAnnotation(object): @@ -625,9 +467,40 @@ def test_keep_standalone_within_policy(self, mock_server, mock_backup_manager): "test_backup3": BackupInfo.KEEP_STANDALONE, } + def test_keep_standalone_with_incrementals(self, server_with_incremental_backups): + """ + Test that a keep:standalone backup properly propagated status to children. + This test has one root backup within the policy and the rest are out of policy. + Incremental backups that have their root within policy are VALID. If out of + policy, the incremental backups will get obsolete. + """ + server_with_incremental_backups.backup_manager.get_keep_target.return_value = ( + KeepManager.TARGET_STANDALONE + ) + server_with_incremental_backups.config.minimum_redundancy = 2 + rp = RetentionPolicyFactory.create( + "retention_policy", + "REDUNDANCY 2", + server=server_with_incremental_backups, + ) + + report = rp.report() + assert report == { + "20240628T000000": BackupInfo.KEEP_STANDALONE, + "20240628T120000": BackupInfo.OBSOLETE, + "20240629T000000": BackupInfo.KEEP_STANDALONE, + "20240629T120000": BackupInfo.OBSOLETE, + "20240630T000000": BackupInfo.KEEP_STANDALONE, + "20240630T060000": BackupInfo.KEEP_STANDALONE, + "20240630T120000": BackupInfo.VALID, + } + def test_keep_full_within_policy(self, mock_server, mock_backup_manager): """ - Test that a keep:full backup within policy is reported as KEEP_FULL. + Test that a keep:full backup properly propagated status to children. + This test has one root backup within the policy and the rest are out of policy. + For KEEP FULL, all incremental backups are VALID independently of in or out of + policy. """ mock_server.backup_manager = mock_backup_manager rp = RetentionPolicyFactory.create( @@ -642,6 +515,31 @@ def test_keep_full_within_policy(self, mock_server, mock_backup_manager): "test_backup3": BackupInfo.KEEP_FULL, } + def test_keep_full_with_incrementals(self, server_with_incremental_backups): + """ + Test that a keep:full backup is reported as KEEP_FULL. + """ + server_with_incremental_backups.backup_manager.get_keep_target.return_value = ( + KeepManager.TARGET_FULL + ) + server_with_incremental_backups.config.minimum_redundancy = 0 + rp = RetentionPolicyFactory.create( + "retention_policy", + "REDUNDANCY 2", + server=server_with_incremental_backups, + ) + + report = rp.report() + assert report == { + "20240628T000000": BackupInfo.KEEP_FULL, + "20240628T120000": BackupInfo.VALID, + "20240629T000000": BackupInfo.KEEP_FULL, + "20240629T120000": BackupInfo.VALID, + "20240630T000000": BackupInfo.KEEP_FULL, + "20240630T060000": BackupInfo.KEEP_FULL, + "20240630T120000": BackupInfo.VALID, + } + def test_keep_standalone_out_of_policy(self, mock_server, mock_backup_manager): """ Test that a keep:standalone backup out-of-policy is reported as @@ -767,6 +665,34 @@ def test_keep_standalone_within_policy(self, mock_server, mock_backup_manager): "test_backup4": BackupInfo.KEEP_STANDALONE, } + def test_keep_standalone_with_incrementals(self, server_with_incremental_backups): + """ + Test that a keep:standalone backup properly propagated status to children. + This test has one root backup within the policy and the rest are out of policy. + Incremental backups that have their root within policy are VALID. If out of + policy, the incremental backups will get obsolete. + """ + server_with_incremental_backups.backup_manager.get_keep_target.return_value = ( + KeepManager.TARGET_STANDALONE + ) + server_with_incremental_backups.config.minimum_redundancy = 0 + rp = RetentionPolicyFactory.create( + "retention_policy", + "RECOVERY WINDOW OF 4 WEEKS", + server=server_with_incremental_backups, + ) + + report = rp.report() + assert report == { + "20240628T000000": BackupInfo.KEEP_STANDALONE, + "20240628T120000": BackupInfo.OBSOLETE, + "20240629T000000": BackupInfo.KEEP_STANDALONE, + "20240629T120000": BackupInfo.OBSOLETE, + "20240630T000000": BackupInfo.KEEP_STANDALONE, + "20240630T060000": BackupInfo.KEEP_STANDALONE, + "20240630T120000": BackupInfo.VALID, + } + def test_keep_full_within_policy(self, mock_server, mock_backup_manager): """ Test that a keep:full backup within policy is reported as KEEP_FULL. @@ -785,6 +711,34 @@ def test_keep_full_within_policy(self, mock_server, mock_backup_manager): "test_backup4": BackupInfo.KEEP_FULL, } + def test_keep_full_with_incrementals(self, server_with_incremental_backups): + """ + Test that a keep:full backup properly propagated status to children. + This test has one root backup within the policy and the rest are out of policy. + For KEEP FULL, all incremental backups are VALID independently of in or out of + policy. + """ + server_with_incremental_backups.backup_manager.get_keep_target.return_value = ( + KeepManager.TARGET_FULL + ) + server_with_incremental_backups.config.minimum_redundancy = 0 + rp = RetentionPolicyFactory.create( + "retention_policy", + "RECOVERY WINDOW OF 4 WEEKS", + server=server_with_incremental_backups, + ) + + report = rp.report() + assert report == { + "20240628T000000": BackupInfo.KEEP_FULL, + "20240628T120000": BackupInfo.VALID, + "20240629T000000": BackupInfo.KEEP_FULL, + "20240629T120000": BackupInfo.VALID, + "20240630T000000": BackupInfo.KEEP_FULL, + "20240630T060000": BackupInfo.KEEP_FULL, + "20240630T120000": BackupInfo.VALID, + } + def test_keep_standalone_out_of_policy(self, mock_server, mock_backup_manager): """ Test that a keep:standalone backup out-of-policy is reported as diff --git a/tests/test_server.py b/tests/test_server.py index 413be11d3..6e6737440 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -54,7 +54,7 @@ ServerWalArchiveLock, ServerWalReceiveLock, ) -from barman.postgres import PostgreSQLConnection +from barman.postgres import PostgreSQLConnection, StandbyPostgreSQLConnection from barman.process import ProcessInfo from barman.server import CheckOutputStrategy, CheckStrategy, Server @@ -94,6 +94,15 @@ def get_wal_names_from_indices_selection(wal_info_files, indices): return expected_wals +def get_BytesIO_with_hash(hash_algorithm=None): + class HashableBytesIO(BytesIO): + def __init__(self, hash_algorithm=hash_algorithm, *args, **kwargs): + super().__init__(*args, **kwargs) + self.hash_algorithm = hash_algorithm + + return HashableBytesIO() + + # noinspection PyMethodMayBeStatic class TestServer(object): def test_init(self): @@ -178,15 +187,29 @@ def test_primary_init(self): assert not hasattr(server.postgres, "primary") def test_standby_init(self): - """Verify standby properties exist when primary_conninfo is set""" + """Verify standby properties exist when the server is in recovery""" # GIVEN a server with primary_conninfo set cfg = build_config_from_dicts( main_conf={"primary_conninfo": "db=primary"}, ).get_server("main") - # WHEN the server is instantiated - server = Server(cfg) - # THEN the postgres connection has a primary connection - assert server.postgres.primary is not None + + # When the server is not in recovery, uses a standard connection and primary does no exist + with patch( + "barman.server.PostgreSQLConnection.is_in_recovery" + ) as is_in_recovery: + is_in_recovery.__get__ = Mock(return_value=False) + server = Server(cfg) + assert isinstance(server.postgres, PostgreSQLConnection) + assert hasattr(server.postgres, "primary") is False + + # When the server is in recovery, uses a standby connection and the primary attribute exists + with patch( + "barman.server.PostgreSQLConnection.is_in_recovery" + ) as is_in_recovery: + is_in_recovery.__get__ = Mock(return_value=True) + server = Server(cfg) + assert isinstance(server.postgres, StandbyPostgreSQLConnection) + assert server.postgres.primary is not None def test_check_config_missing(self, tmpdir): """ @@ -1028,8 +1051,10 @@ def test_check_wal_streaming_with_different_connections( @patch("barman.server.StandbyPostgreSQLConnection") @patch("barman.server.PostgreSQLConnection") @patch("barman.server.Server.get_remote_status") + @patch("barman.server.isinstance", return_value=True) def test_check_standby( self, + _mock_is_instance, _mock_remote_status, _pgconn_mock, _standby_pgconn_mock, @@ -2237,7 +2262,9 @@ def test_get_wal_sendfile_uncompress_fail( ) # WHEN get_wal_sendfile is called - server.get_wal_sendfile("test_wal_file", "some compression", "/path/to/dest") + server.get_wal_sendfile( + "test_wal_file", "some compression", False, "/path/to/dest" + ) # THEN output indicates an error assert output.error_occurred @@ -2246,18 +2273,159 @@ def test_get_wal_sendfile_uncompress_fail( _out, err = capsys.readouterr() assert "ERROR: Error decompressing WAL: an error happened" in err + @patch("barman.server.open") + @patch("barman.server.shutil") + @patch("barman.server.NamedTemporaryFile") + @patch("barman.backup.CompressionManager") + def test_get_wal_keep_compression( + self, + mock_compression_manager, + _mock_named_temporary_file, + _mock_shutil, + _mock_open, + ): + """Assert `--keep-compression` option works in the ``get_wal_sendfile`` method""" + # GIVEN a server + server = build_real_server() + # AND a mock compressor, which is only present if the WAL is compressed + mock_compressor = Mock() + mock_compressor.compression = "some compression" + mock_compression_manager.return_value.get_compressor.side_effect = [ + mock_compressor, + Mock(), + ] + + # WHEN get_wal_sendfile is called and keep_compression is False + keep_compression = False + server.get_wal_sendfile( + "test_wal_file", "some compression", keep_compression, "/path/to/dest" + ) + # THEN decompression should occur + mock_compressor.decompress.assert_called_once() + + # Reset mock and side effect + mock_compressor.reset_mock() + mock_compression_manager.return_value.get_compressor.side_effect = [ + mock_compressor, + Mock(), + ] + + # WHEN get_wal_sendfile is called and keep_compression is True + keep_compression = True + server.get_wal_sendfile( + "test_wal_file", "some compression", keep_compression, "/path/to/dest" + ) + # THEN decompression should not occur + mock_compressor.decompress.assert_not_called() + @pytest.mark.parametrize( - "mode, success, error_msg", + "obj, HASHSUMS_FILE, hash_algorithm, checksum, mode, success, error_msg", [ - ["plain", True, None], - ["relative", True, None], - ["bad_sum_line", True, "Bad checksum line"], - ["bad_file_type", False, "Unsupported file type"], - ["subdir", False, "Unsupported filename"], + [ + BytesIO(), + "MD5SUMS", + "md5", + "34743e1e454e967eb76a16c66372b0ef", + "plain", + True, + None, + ], + [ + BytesIO(), + "MD5SUMS", + "md5", + "34743e1e454e967eb76a16c66372b0ef", + "relative", + True, + None, + ], + [ + BytesIO(), + "MD5SUMS", + "md5", + "34743e1e454e967eb76a16c66372b0ef", + "bad_sum_line", + True, + "Bad checksum line", + ], + [ + BytesIO(), + "MD5SUMS", + "md5", + "34743e1e454e967eb76a16c66372b0ef", + "bad_file_type", + False, + "Unsupported file type", + ], + [ + BytesIO(), + "MD5SUMS", + "md5", + "34743e1e454e967eb76a16c66372b0ef", + "subdir", + False, + "Unsupported filename", + ], + [ + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + "plain", + True, + None, + ], + [ + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + "relative", + True, + None, + ], + [ + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + "bad_sum_line", + True, + "Bad checksum line", + ], + [ + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + "bad_file_type", + False, + "Unsupported file type", + ], + [ + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + "subdir", + False, + "Unsupported filename", + ], ], ) def test_put_wal( - self, mode, success, error_msg, tmpdir, capsys, caplog, monkeypatch + self, + obj, + HASHSUMS_FILE, + hash_algorithm, + checksum, + mode, + success, + error_msg, + tmpdir, + capsys, + caplog, + monkeypatch, ): # See all logs caplog.set_level(0) @@ -2283,29 +2451,28 @@ def test_put_wal( file_name = "test/" + file_name # Generate some test data in an in_memory tar - tar_file = BytesIO() + tar_file = obj tar = tarfile.open(mode="w|", fileobj=tar_file, dereference=False) wal = lab.join(file_name) if mode == "bad_file_type": # Create a file with wrong file type wal.mksymlinkto("/nowhere") - file_hash = hashlib.md5().hexdigest() + file_hash = hashlib.new(hash_algorithm).hexdigest() else: wal.write("some random content", ensure=True) - file_hash = wal.computehash("md5") + file_hash = wal.computehash(hash_algorithm) tar.add(wal.strpath, file_name) - md5 = lab.join("MD5SUMS") + hashsums = lab.join(HASHSUMS_FILE) if mode == "bad_sum_line": - md5.write("bad_line\n") - md5.write("%s *%s\n" % (file_hash, file_name), mode="a") - tar.add(md5.strpath, md5.basename) + hashsums.write("bad_line\n") + hashsums.write("%s *%s\n" % (file_hash, file_name), mode="a") + tar.add(hashsums.strpath, hashsums.basename) tar.close() # Feed the data to put-wal tar_file.seek(0) server.put_wal(tar_file) out, err = capsys.readouterr() - # Output is always empty assert not out @@ -2319,24 +2486,69 @@ def test_put_wal( # Verify the result if success if success: dest_file = incoming.join(wal.basename) - assert dest_file.computehash() == wal.computehash() + assert dest_file.computehash(hash_algorithm) == wal.computehash( + hash_algorithm + ) assert ( "Received file '00000001000000EF000000AB' " - "with checksum '34743e1e454e967eb76a16c66372b0ef' " + f"with checksum '{checksum}' " "by put-wal for server 'main' " "(SSH host: 192.168.66.99)\n" in caplog.text ) @pytest.mark.parametrize( - "mode, error_msg", + "HASHSUMS_FILE, hash_algorithm, mode, error_msg", [ - ["file_absent", "Checksum without corresponding file"], - ["sum_absent", "Missing checksum for file"], - ["sum_mismatch", "Bad file checksum"], - ["dest_exists", "Impossible to write already existing"], + ( + "MD5SUMS", + "md5", + "file_absent", + "Checksum without corresponding file", + ), + ("MD5SUMS", "md5", "sum_absent", "Missing checksum for file"), + ("MD5SUMS", "md5", "sum_mismatch", "Bad file checksum"), + ( + "MD5SUMS", + "md5", + "dest_exists", + "Impossible to write already existing", + ), + ( + "SHA256SUMS", + "sha256", + "file_absent", + "Checksum without corresponding file", + ), + ( + "SHA256SUMS", + "sha256", + "sum_absent", + "Missing checksum for file", + ), + ( + "SHA256SUMS", + "sha256", + "sum_mismatch", + "Bad file checksum", + ), + ( + "SHA256SUMS", + "sha256", + "dest_exists", + "Impossible to write already existing", + ), ], ) - def test_put_wal_fail(self, mode, error_msg, tmpdir, capsys, monkeypatch): + def test_put_wal_fail( + self, + HASHSUMS_FILE, + hash_algorithm, + mode, + error_msg, + tmpdir, + capsys, + monkeypatch, + ): lab = tmpdir.mkdir("lab") incoming = tmpdir.mkdir("incoming") server = build_real_server( @@ -2356,14 +2568,16 @@ def test_put_wal_fail(self, mode, error_msg, tmpdir, capsys, monkeypatch): wal.write("some random content", ensure=True) if mode != "file_absent": tar.add(wal.strpath, wal.basename) - md5 = lab.join("MD5SUMS") + hashsum = lab.join(HASHSUMS_FILE) if mode != "sum_mismatch": - md5.write("%s *%s\n" % (wal.computehash("md5"), wal.basename)) + hashsum.write("%s *%s\n" % (wal.computehash(hash_algorithm), wal.basename)) else: # put an incorrect checksum in the file - md5.write("%s *%s\n" % (hashlib.md5().hexdigest(), wal.basename)) + hashsum.write( + "%s *%s\n" % (hashlib.new(hash_algorithm).hexdigest(), wal.basename) + ) if mode != "sum_absent": - tar.add(md5.strpath, md5.basename) + tar.add(hashsum.strpath, hashsum.basename) tar.close() # If requested create a colliding file in the incoming directory @@ -2386,9 +2600,32 @@ def test_put_wal_fail(self, mode, error_msg, tmpdir, capsys, monkeypatch): ) assert output.error_occurred + @pytest.mark.parametrize( + "obj, HASHSUMS_FILE, hash_algorithm, checksum", + [ + (BytesIO(), "MD5SUMS", "md5", "34743e1e454e967eb76a16c66372b0ef"), + ( + get_BytesIO_with_hash(hash_algorithm="sha256"), + "SHA256SUMS", + "sha256", + "2432a5281590f6c17323a8dc9c5442757e79fdc4d2028ae36bcb0010410dfc64", + ), + ], + ) @patch("barman.server.fsync_file") @patch("barman.server.fsync_dir") - def test_put_wal_fsync(self, fd_mock, ff_mock, tmpdir, capsys, caplog): + def test_put_wal_fsync( + self, + fd_mock, + ff_mock, + obj, + HASHSUMS_FILE, + hash_algorithm, + checksum, + tmpdir, + capsys, + caplog, + ): # See all logs caplog.set_level(0) @@ -2403,16 +2640,15 @@ def test_put_wal_fsync(self, fd_mock, ff_mock, tmpdir, capsys, caplog): ) output.error_occurred = False - # Generate some test data in an in_memory tar - tar_file = BytesIO() + tar_file = obj tar = tarfile.open(mode="w|", fileobj=tar_file, format=tarfile.PAX_FORMAT) wal = lab.join("00000001000000EF000000AB") wal.write("some random content", ensure=True) wal.setmtime(wal.mtime() - 100) # Set mtime to 100 seconds ago tar.add(wal.strpath, wal.basename) - md5 = lab.join("MD5SUMS") - md5.write("%s *%s\n" % (wal.computehash("md5"), wal.basename)) - tar.add(md5.strpath, md5.basename) + hashsum = lab.join(HASHSUMS_FILE) + hashsum.write("%s *%s\n" % (wal.computehash(hash_algorithm), wal.basename)) + tar.add(hashsum.strpath, hashsum.basename) tar.close() # Feed the data to put-wal @@ -2430,7 +2666,7 @@ def test_put_wal_fsync(self, fd_mock, ff_mock, tmpdir, capsys, caplog): assert dest_file.computehash() == wal.computehash() assert ( "Received file '00000001000000EF000000AB' " - "with checksum '34743e1e454e967eb76a16c66372b0ef' " + f"with checksum '{checksum}' " "by put-wal for server 'main'" in caplog.text ) @@ -2920,6 +3156,14 @@ def test_get_backup_ext_info( for field in key_pairs_check: assert field[0] in ext_info and field[1] == ext_info[field[0]] + def get_HashableTarfile(self, hash_algorithm=None): + class HashableTarfile(tarfile.TarFile): + def __init__(self, hash_algorithm=hash_algorithm, *args, **kwargs): + super().__init__(*args, **kwargs) + self.hash_algorithm = hash_algorithm + + return HashableTarfile() + class TestCheckStrategy(object): """ diff --git a/tests/test_utils.py b/tests/test_utils.py index 62d8bcfa5..b07f78e84 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1021,6 +1021,88 @@ def test_get_backup_info_from_name_no_match(self, mock_backup_info_list): assert backup_info is None +class TestAWSSnapshotLock(object): + """ + Tests AWS Snapshot Lock checks + """ + + def test_check_aws_expiration_date_format(self): + """ + Tests if check_aws_expiration_date properly creates a datetime object + with the specific format. + """ + assert isinstance( + barman.utils.check_aws_expiration_date_format("2024-01-01T00:00:00.000Z"), + datetime, + ) + + @pytest.mark.parametrize( + "timestamp", ["2024-01-01", "2024-01-01T00:00:00", "2024-01-01T00:00:00.000"] + ) + def test_check_aws_expiration_date_format_error(self, timestamp): + """ + Tests if check_aws_expiration_date raises an ArgumentTypeError if the value + is in the wrong format. + """ + with pytest.raises(ArgumentTypeError): + barman.utils.check_aws_expiration_date_format(timestamp) + + @pytest.mark.parametrize("duration", ["1", "12000", "36500"]) + def test_check_aws_snapshot_lock_duration_range(self, duration): + """ + Tests if check_aws_snapshot_lock_duration_range is properly set as an integer + in the range limit. + """ + assert barman.utils.check_aws_snapshot_lock_duration_range(duration) == int( + duration + ) + + @pytest.mark.parametrize("duration", ["-1", "0", "36501"]) + def test_check_aws_snapshot_lock_duration_range_error(self, duration): + """ + Tests if check_aws_snapshot_lock_duration_range raises an ArgumentTypeError if + the value is outside the range. + """ + with pytest.raises(ValueError): + barman.utils.check_aws_snapshot_lock_duration_range(duration) + + @pytest.mark.parametrize("duration", ["1", "30", "72"]) + def test_check_aws_snapshot_lock_cool_off_period_range(self, duration): + """ + Tests if check_aws_snapshot_lock_cool_off_period_range is properly set as an + integer in the range limit. + """ + assert barman.utils.check_aws_snapshot_lock_cool_off_period_range( + duration + ) == int(duration) + + @pytest.mark.parametrize("duration", ["-1", "0", "73"]) + def test_check_aws_snapshot_lock_cool_off_period_range_error(self, duration): + """ + Tests if check_aws_snapshot_lock_cool_off_period_range raises an + ArgumentTypeError if the value is outside the range. + """ + with pytest.raises(ValueError): + barman.utils.check_aws_snapshot_lock_cool_off_period_range(duration) + + @pytest.mark.parametrize("mode", ["governance", "compliance"]) + def test_check_aws_snapshot_lock_mode(self, mode): + """ + Tests if check_aws_snapshot_lock_cool_off_period_range raises an + ArgumentTypeError if the value is outside the range. + """ + assert barman.utils.check_aws_snapshot_lock_mode(mode) == str(mode) + + @pytest.mark.parametrize("mode", ["nogovernance", "nocompliance"]) + def test_check_aws_snapshot_lock_mode_error(self, mode): + """ + Tests if check_aws_snapshot_lock_cool_off_period_range raises an + ArgumentTypeError if the value is outside the range. + """ + with pytest.raises(ValueError): + barman.utils.check_aws_snapshot_lock_mode(mode) == str(mode) + + class TestEditConfig: def test_edit_config_existing_section(self, tmpdir): # Create a temporary file diff --git a/tests/testing_helpers.py b/tests/testing_helpers.py index 13b0f7a28..f36624307 100644 --- a/tests/testing_helpers.py +++ b/tests/testing_helpers.py @@ -283,6 +283,10 @@ def build_config_dictionary(config_keys=None): "archiver_batch_size": 0, "autogenerate_manifest": False, "aws_await_snapshots_timeout": 3600, + "aws_snapshot_lock_mode": None, + "aws_snapshot_lock_duration": None, + "aws_snapshot_lock_cool_off_period": None, + "aws_snapshot_lock_expiration_date": None, "aws_profile": None, "aws_region": None, "azure_credential": None, diff --git a/tox.ini b/tox.ini index 88da36ae3..eea3e0de0 100644 --- a/tox.ini +++ b/tox.ini @@ -41,3 +41,23 @@ python = 3.8: py38 3.9: py39 3.10: py310 + +[testenv:docs] +deps = sphinx + sphinx-github-style + sphinxcontrib-apidoc + pydata-sphinx-theme + myst_parser +setenv = + PYTHONPATH=. +commands = make -C docs {posargs:html man} +allowlist_externals = + make + +[testenv:docs-clean] +deps = sphinx +setenv = + PYTHONPATH=. +commands = make -C docs clean +allowlist_externals = + make