├── sphinx ├── .gitignore ├── requirements.txt ├── README.md ├── docs │ └── index.rst ├── generate_docs.sh └── Makefile ├── doc ├── .gitignore ├── manual │ ├── .gitignore │ ├── 20-server_setup.en.md │ ├── Makefile │ ├── 00-head.en.md │ ├── 22-config_file.en.md │ ├── 26-rsync_backup.en.md │ ├── 02-before_you_start.en.md │ ├── 27-windows-support.en.md │ ├── 25-streaming_backup.en.md │ ├── 65-troubleshooting.en.md │ ├── 70-feature-matrix.en.md │ ├── 41-global-commands.en.md │ ├── 24-wal_archiving.en.md │ ├── 15-system_requirements.en.md │ ├── 99-references.en.md │ ├── 16-installation.en.md │ ├── 17-configuration.en.md │ ├── 01-intro.en.md │ ├── 66-about.en.md │ ├── 23-wal_streaming.en.md │ ├── 43-backup-commands.en.md │ ├── 21-preliminary_steps.en.md │ ├── 42-server-commands.en.md │ └── 10-design.en.md ├── images │ ├── barman-architecture-scenario1.png │ ├── barman-architecture-scenario2.png │ ├── barman-architecture-scenario1b.png │ └── barman-architecture-scenario2b.png ├── Makefile ├── barman.d │ ├── ssh-server.conf-template │ └── streaming-server.conf-template └── barman.conf ├── scripts ├── barman.bash_completion ├── release.sh └── gitlog-to-changelog ├── setup.cfg ├── INSTALL ├── .travis.yml ├── MANIFEST.in ├── .gitignore ├── rpm ├── rhel5 │ ├── setup.cfg.patch │ ├── python26-argh.spec │ ├── python26-argcomplete.spec │ ├── python-dateutil-1.4.1-remove-embedded-timezone-data.patch │ ├── python26-dateutil.spec │ └── python26-psycopg2.spec ├── rhel6 │ ├── python-argh.spec │ └── python-argcomplete.spec ├── rhel7 │ └── python-argh.spec └── barman.spec ├── TODO ├── barman ├── version.py ├── __init__.py ├── remote_status.py ├── diagnose.py ├── process.py ├── exceptions.py ├── hooks.py └── lockfile.py ├── bin └── barman ├── tox.ini ├── AUTHORS ├── README.rst ├── setup.py └── tests ├── test_process.py ├── test_compressor.py └── test_cli.py /sphinx/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | docs/*.rst 3 | docs/!index.rst 4 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | barman-tutorial.en.pdf 2 | barman-tutorial.en.html 3 | -------------------------------------------------------------------------------- /doc/manual/.gitignore: -------------------------------------------------------------------------------- 1 | barman-manual.en.html 2 | barman-manual.en.pdf 3 | -------------------------------------------------------------------------------- /scripts/barman.bash_completion: -------------------------------------------------------------------------------- 1 | eval "$(register-python-argcomplete barman)" 2 | -------------------------------------------------------------------------------- /doc/images/barman-architecture-scenario1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secwall/barman/HEAD/doc/images/barman-architecture-scenario1.png -------------------------------------------------------------------------------- /doc/images/barman-architecture-scenario2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secwall/barman/HEAD/doc/images/barman-architecture-scenario2.png -------------------------------------------------------------------------------- /doc/images/barman-architecture-scenario1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secwall/barman/HEAD/doc/images/barman-architecture-scenario1b.png -------------------------------------------------------------------------------- /doc/images/barman-architecture-scenario2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secwall/barman/HEAD/doc/images/barman-architecture-scenario2b.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | 4 | [aliases] 5 | test=pytest 6 | 7 | [isort] 8 | known_first_party=barman 9 | known_third_party=setuptools,distutils,argh,argcomplete,dateutil,psycopg2,mock,pytest 10 | skip=.tox 11 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Barman INSTALL instructions 2 | Copyright (C) 2011-2016 2ndQuadrant Italia Srl 3 | 4 | For further information, see the "Installation" section in the 5 | official manual of Barman or the Markdown source file: 6 | doc/manual/16-installation.en.md. 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | - "3.5" 5 | env: 6 | - TOX_ENV=py26 7 | - TOX_ENV=py27 8 | - TOX_ENV=py33 9 | - TOX_ENV=py34 10 | - TOX_ENV=py35 11 | - TOX_ENV=flake8 12 | - TOX_ENV=minimal 13 | install: 14 | - travis_retry pip install tox 15 | script: 16 | - tox -e $TOX_ENV 17 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include barman *.py 2 | recursive-include rpm * 3 | recursive-include doc *.md 4 | recursive-include doc/barman.d * 5 | include doc/Makefile doc/barman.1 doc/barman.5 doc/barman.conf 6 | include scripts/barman.bash_completion 7 | include AUTHORS NEWS ChangeLog LICENSE MANIFEST.in setup.py INSTALL README.rst 8 | -------------------------------------------------------------------------------- /sphinx/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.6 2 | argcomplete==0.9.0 3 | argh==0.26.1 4 | argparse==1.3.0 5 | Babel==1.3 6 | docutils==0.12 7 | Jinja2==2.7.3 8 | MarkupSafe==0.23 9 | psycopg2==2.6.1 10 | Pygments==2.0.2 11 | python-dateutil==2.4.0 12 | pytz==2015.4 13 | six==1.9.0 14 | snowballstemmer==1.2.0 15 | Sphinx==1.3.1 16 | sphinx-bootstrap-theme==0.4.6 17 | sphinx-rtd-theme==0.1.8 18 | wheel==0.24.0 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled python sources 2 | *.pyc 3 | *.pyo 4 | 5 | # python modules 6 | *.egg 7 | .eggs 8 | 9 | # editor backups 10 | *~ 11 | \#*\# 12 | .*.swp 13 | 14 | # eclipse project files 15 | /.project 16 | /.pydevproject 17 | /.settings 18 | 19 | # PyCharm 20 | /.idea 21 | 22 | # tox testing 23 | .tox/ 24 | .cache/ 25 | 26 | # setuptools 27 | /MANIFEST 28 | /dist 29 | /build 30 | /barman.egg-info 31 | 32 | # OSX 33 | .DS_Store 34 | -------------------------------------------------------------------------------- /doc/manual/20-server_setup.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Setup of a new server in Barman 4 | 5 | As mentioned in the _"Design and architecture"_ section, we will use the 6 | following conventions: 7 | 8 | - `pg` as server ID and host name where PostgreSQL is installed 9 | - `backup` as host name where Barman is located 10 | - `barman` as the user running Barman on the `backup` server (identified by 11 | the parameter `barman_user` in the configuration) 12 | - `postgres` as the user running PostgreSQL on the `pg` server 13 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | MANPAGES=barman.1 barman.5 2 | DOCS= 3 | SUBDIRS=manual 4 | 5 | .PHONY: all clean help subdirs $(SUBDIRS) 6 | 7 | all: $(MANPAGES) $(DOCS) $(SUBDIRS) 8 | 9 | barman.1: barman.1.md 10 | pandoc -s -t man -o $@ $< 11 | 12 | barman.5: barman.5.md 13 | pandoc -s -t man -o $@ $< 14 | 15 | clean: 16 | rm -f $(MANPAGES) $(DOCS) 17 | for dir in $(SUBDIRS); do \ 18 | $(MAKE) -C $$dir clean; \ 19 | done 20 | 21 | help: 22 | @echo "Usage:" 23 | @echo " $$ make" 24 | 25 | subdirs: $(SUBDIRS) 26 | 27 | $(SUBDIRS): 28 | $(MAKE) -C $@ 29 | 30 | -------------------------------------------------------------------------------- /rpm/rhel5/setup.cfg.patch: -------------------------------------------------------------------------------- 1 | --- setup.cfg.old 2011-08-22 12:16:18.703486005 +0300 2 | +++ setup.cfg 2011-08-22 12:16:31.596486005 +0300 3 | @@ -26,7 +26,7 @@ 4 | # libraries needed to build psycopg2. If pg_config is not in the path or 5 | # is installed under a different name uncomment the following option and 6 | # set it to the pg_config full path. 7 | -#pg_config= 8 | +pg_config=/usr/pgsql-9.0/bin/pg_config 9 | 10 | # If "pg_config" is not available, "include_dirs" can be used to locate 11 | # postgresql headers and libraries. Some extra checks on sys.platform will 12 | -------------------------------------------------------------------------------- /doc/manual/Makefile: -------------------------------------------------------------------------------- 1 | DOCS= \ 2 | barman-manual.en.pdf barman-manual.en.html 3 | 4 | MDS = \ 5 | ??-*.en.md 6 | #00-head.en.md \ 7 | #01-intro.en.md \ 8 | #02-before_you_start.en.md \ 9 | #10-design.en.md 10 | 11 | all: $(DOCS) 12 | 13 | barman-manual.en.pdf: $(MDS) ../images/*.png 14 | pandoc -o $@ -s -f markdown --toc $(MDS) 15 | 16 | barman-manual.en.html: $(MDS) ../images/*.png 17 | pandoc -o $@ -t html5 -f markdown -s -S --toc $(MDS) 18 | 19 | clean: 20 | rm -f $(DOCS) 21 | 22 | help: 23 | @echo "Usage:" 24 | @echo " $$ make" 25 | 26 | .PHONY: all clean help 27 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Barman TODO - Backlog of features for Barman 2 | Copyright (C) 2011-2016 2ndQuadrant Italia Srl 3 | 4 | * TAR storage strategy for backups 5 | * SSH only connections 6 | * Centralised WAL hub capability (streaming server) 7 | * Barman passive nodes (for asynchronous geographical redundancy) 8 | * Hook scripts for backup delete, WAL archiving, etc. 9 | * Export/Import of backups 10 | * External backup sources (e.g. S3) 11 | * Improve recovery support 12 | * Sandbox recovery 13 | * Logical backup integration (pg_dump on sandbox instances) 14 | * JSON output for full automation 15 | * Backup validation 16 | * Windows support 17 | * ... 18 | -------------------------------------------------------------------------------- /doc/manual/00-head.en.md: -------------------------------------------------------------------------------- 1 | % Barman Manual 2 | % 2ndQuadrant Italia 3 | % January 20, 2017 (v2.2a1) 4 | 5 | **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. 6 | 7 | [Barman] [11] is distributed under GNU GPL 3 and maintained by [2ndQuadrant] [13], a platinum sponsor of the [PostgreSQL project] [31]. 8 | 9 | > **IMPORTANT:** \newline 10 | > This manual assumes that you are familiar with theoretical disaster 11 | > recovery concepts, and that you have a grasp of PostgreSQL fundamentals in 12 | > terms of physical backup and disaster recovery. See section _"Before you start"_ below for details. 13 | -------------------------------------------------------------------------------- /barman/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | ''' 19 | This module contains the current Barman version. 20 | ''' 21 | 22 | __version__ = '2.2a1' 23 | -------------------------------------------------------------------------------- /bin/barman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 4 | # 5 | # This file is part of Barman. 6 | # 7 | # Barman is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # Barman is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Barman. If not, see . 19 | # 20 | # PYTHON_ARGCOMPLETE_OK 21 | 22 | from barman.cli import main 23 | 24 | if __name__ == '__main__': 25 | main() 26 | else: 27 | raise NotImplementedError 28 | -------------------------------------------------------------------------------- /barman/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | """ 19 | The main Barman module 20 | """ 21 | 22 | from __future__ import absolute_import 23 | from .version import __version__ 24 | 25 | __config__ = None 26 | 27 | __all__ = ['__version__', '__config__'] 28 | -------------------------------------------------------------------------------- /doc/manual/22-config_file.en.md: -------------------------------------------------------------------------------- 1 | ## The server configuration file 2 | 3 | Create a new file, called `pg.conf`, in `/etc/barman.d` directory, with the following content: 4 | 5 | ``` ini 6 | [pg] 7 | description = "Our main PostgreSQL server" 8 | conninfo = host=pg user=barman dbname=postgres 9 | backup_method = postgres 10 | # backup_method = rsync 11 | ``` 12 | 13 | The `conninfo` option is set accordingly to the section _"Preliminary 14 | steps: PostgreSQL connection"_. 15 | 16 | The meaning of the `backup_method` option will be covered in the 17 | backup section of this guide. 18 | 19 | If you plan to use the streaming connection for WAL archiving or to 20 | create a backup of your server, you also need a `streaming_conninfo` 21 | parameter in your server configuration file: 22 | 23 | ``` ini 24 | streaming_conninfo = host=pg user=streaming_barman dbname=postgres 25 | ``` 26 | 27 | This value must be choosen accordingly as described in the section 28 | _"Preliminary steps: PostgreSQL connection"_. 29 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py26, py27, py33, py34, py35, flake8, minimal 3 | 4 | [testenv] 5 | deps = pytest 6 | mock 7 | pytest-catchlog>=1.2.1 8 | pytest-timeout 9 | python-dateutil 10 | commands = py.test {posargs:tests} 11 | 12 | [testenv:minimal] 13 | basepython = python2.6 14 | deps = pytest 15 | mock 16 | pytest-catchlog>=1.2.1 17 | pytest-timeout 18 | psycopg2==2.4.2 19 | argh==0.21.2 20 | python-dateutil==1.5 21 | commands = py.test {posargs:tests} 22 | passenv = USER 23 | 24 | [testenv:flake8] 25 | basepython = python2.7 26 | commands = flake8 {posargs} 27 | deps = flake8 28 | flake8-mock 29 | flake8-string-format 30 | flake8-copyright 31 | flake8-isort 32 | # Workaround for https://github.com/gforcada/flake8-isort/issues/9 33 | pep8 34 | 35 | [flake8] 36 | copyright-check = True 37 | copyright-regexp = Copyright\s+(\(C\)\s+)?(\d{4}-)?2016\s+%(author)s 38 | copyright-author = 2ndQuadrant Italia Srl 39 | -------------------------------------------------------------------------------- /doc/manual/26-rsync_backup.en.md: -------------------------------------------------------------------------------- 1 | ## Backup with `rsync`/SSH 2 | 3 | The backup over `rsync` was the only available method before 2.0, and 4 | is currently the only backup method that supports the incremental 5 | backup feature. Please consult the _"Features in detail"_ section for 6 | more information. 7 | 8 | To take a backup using `rsync` you need to put these parameters inside 9 | the Barman server configuration file: 10 | 11 | ``` ini 12 | backup_method = rsync 13 | ssh_command = ssh postgres@pg 14 | ``` 15 | 16 | The `backup_method` option activates the `rsync` backup method, and 17 | the `ssh_command` option is needed to correctly create an SSH 18 | connection from the Barman server to the PostgreSQL server. 19 | 20 | > **IMPORTANT:** Keep in mind that if the WAL archiving is not 21 | > currently configured, you will not be able to start a backup. 22 | 23 | To check if the server configuration is valid you can use the `barman 24 | check` command: 25 | 26 | ``` bash 27 | barman@backup$ barman check pg 28 | ``` 29 | 30 | To take a backup use the `barman backup` command: 31 | 32 | ``` bash 33 | barman@backup$ barman backup pg 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /doc/manual/02-before_you_start.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Before you start 4 | 5 | Before you start using Barman, it is fundamental that you get familiar 6 | with PostgreSQL and the concepts around physical backups, Point-In-Time-Recovery and replication, such as base backups, WAL archiving, etc. 7 | 8 | Below you can find a non exhaustive list of resources that we recommend for you to read: 9 | 10 | - _PostgreSQL documentation_: 11 | - [SQL Dump] [sqldump] [^pgdump] 12 | - [File System Level Backup] [physicalbackup] 13 | - [Continuous Archiving and Point-in-Time Recovery (PITR)] [pitr] 14 | - [Recovery Configuration] [recoveryconfig] 15 | - [Reliability and the Write-Ahead Log] [wal] 16 | - _Book_: [PostgreSQL 9 Administration Cookbook - 2nd edition] [adminbook] 17 | 18 | [^pgdump]: It is important that you know the difference between logical and physical backup, therefore between `pg_dump` and a tool like Barman. 19 | 20 | Professional training on these topics is another effective way of 21 | learning these concepts. At any time of the year you can find many 22 | courses available all over the world, delivered by PostgreSQL 23 | companies such as 2ndQuadrant. 24 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 4 | # 5 | # This file is part of Barman. 6 | # 7 | # Barman is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # Barman is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Barman. If not, see . 19 | 20 | set -e 21 | 22 | BASE="$(dirname $(cd $(dirname "$0"); pwd))" 23 | cd "$BASE" 24 | 25 | VERSION="$(python -c 'd={}; exec(open("barman/version.py").read(), d); print(d["__version__"])')" 26 | scripts/gitlog-to-changelog > ChangeLog 27 | git add ChangeLog 28 | git commit -m "Update the ChangeLog file" 29 | scripts/gitlog-to-changelog > ChangeLog 30 | git add ChangeLog 31 | git commit -m "Update the ChangeLog file" --amend 32 | ./setup.py sdist 33 | if ! git tag -s -m "Release ${VERSION}" release/${VERSION} 34 | then 35 | echo "Cannot tag the release as the private key is missing" 36 | fi 37 | -------------------------------------------------------------------------------- /doc/manual/27-windows-support.en.md: -------------------------------------------------------------------------------- 1 | ## How to setup a Windows based server 2 | 3 | You can backup a PostgreSQL server running on Windows using the 4 | streaming connection for both WAL archiving and for backups. 5 | 6 | > **IMPORTANT:** This feature is still experimental because it is not 7 | > yet part of our continuous integration system. 8 | 9 | Follow every step discussed previously for a streaming connection 10 | setup. 11 | 12 | > **WARNING:**: At this moment, `pg_basebackup` interoperability from 13 | > Windows to Linux is still experimental. If you are having issues 14 | > taking a backup from a Windows server and your PostgreSQL locale is 15 | > not in English, a possible workaround for the issue is instructing 16 | > your PostgreSQL to emit messages in English. You can do this by 17 | > putting the following parameter in your `postgresql.conf` file: 18 | > 19 | > ``` ini 20 | > lc_messages = 'English' 21 | > ``` 22 | > 23 | > This has been reported to fix the issue. 24 | 25 | You can backup your server as usual. 26 | 27 | Remote recovery is not supported for Windows servers, so you must 28 | recover your cluster locally in the Barman server and then copy all 29 | the files on a Windows server or use a folder shared between the 30 | PostgreSQL server and the Barman server. 31 | 32 | Additionally, make sure that the system user chosen to run PostgreSQL 33 | has the permission needed to access the restored data. Basically, it 34 | must have full control over the PostgreSQL data directory. 35 | -------------------------------------------------------------------------------- /doc/manual/25-streaming_backup.en.md: -------------------------------------------------------------------------------- 1 | ## Streaming backup 2 | 3 | Barman can backup a PostgreSQL server using the streaming connection, 4 | relying on `pg_basebackup`, a utility that has been available from 5 | PostgreSQL 9.1. 6 | 7 | > **IMPORTANT:** Barman requires that `pg_basebackup` is installed in 8 | > the same server. For PostgreSQL 9.2 servers, you need the 9 | > `pg_basebackup` of version 9.2 installed alongside with Barman. For 10 | > PostgreSQL 9.3 and above, it is recommented to install the last 11 | > available version of `pg_basebackup`, as it is back compatible. You 12 | > can even install multiple versions of `pg_basebackup` on the Barman 13 | > server and properly point to the specific version for a server, 14 | > using the `path_prefix` option in the configuration file. 15 | 16 | To successfully backup your server with the streaming connection, you 17 | need to use `postgres` as your backup method: 18 | 19 | ``` ini 20 | backup_method = postgres 21 | ``` 22 | 23 | > **IMPORTANT:** keep in mind that if the WAL archiving is not 24 | > currently configured, you will not be able to start a backup. 25 | 26 | To check if the server configuration is valid you can use the `barman 27 | check` command: 28 | 29 | ``` bash 30 | barman@backup$ barman check pg 31 | ``` 32 | 33 | To start a backup you can use the `barman backup` command: 34 | 35 | ``` bash 36 | barman@backup$ barman backup pg 37 | ``` 38 | 39 | > **IMPORTANT:** `pg_basebackup` 9.4 or higher is required for 40 | > tablespace support if you use the `postgres` backup method. 41 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Barman Core Team (in alphabetical order): 2 | 3 | * Gabriele Bartolini (project leader) 4 | * Jonathan Battiato (QA/testing) 5 | * Stefano Bianucci (developer, intern from University of Florence) 6 | * Giuseppe Broccolo (QA/testing) 7 | * Giulio Calacoci (developer) 8 | * Francesco Canovai (QA/testing) 9 | * Leonardo Cecchi (developer) 10 | * Gianni Ciolli (QA/testing) 11 | * Britt Cole (documentation) 12 | * Marco Nenciarini (lead developer) 13 | * Rubens Souza (QA/testing) 14 | 15 | Past contributors: 16 | 17 | * Carlo Ascani 18 | 19 | Many thanks go to our sponsors (in alphabetical order): 20 | 21 | * 4Caast - http://4caast.morfeo-project.org/ (Founding sponsor) 22 | * Adyen - http://www.adyen.com/ 23 | * Agile Business Group - http://www.agilebg.com/ 24 | * BIJ12 - http://www.bij12.nl/ 25 | * CSI Piemonte - http://www.csipiemonte.it/ (Founding sponsor) 26 | * Ecometer - http://www.ecometer.it/ 27 | * GestionaleAuto - http://www.gestionaleauto.com/ (Founding sponsor) 28 | * Jobrapido - http://www.jobrapido.com/ 29 | * Navionics - http://www.navionics.com/ (Founding sponsor) 30 | * Sovon Vogelonderzoek Nederland - https://www.sovon.nl/ 31 | * Subito.it - http://www.subito.it/ 32 | * XCon Internet Services - http://www.xcon.it/ (Founding sponsor) 33 | -------------------------------------------------------------------------------- /doc/barman.d/ssh-server.conf-template: -------------------------------------------------------------------------------- 1 | ; Barman, Backup and Recovery Manager for PostgreSQL 2 | ; http://www.pgbarman.org/ - http://www.2ndQuadrant.com/ 3 | ; 4 | ; Template configuration file for a server using 5 | ; SSH connections and rsync for copy. 6 | ; 7 | 8 | [ssh] 9 | ; Human readable description 10 | description = "Example of PostgreSQL Database (via SSH)" 11 | 12 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | ; SSH options (mandatory) 14 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 15 | ssh_command = ssh postgres@pg 16 | 17 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | ; PostgreSQL connection string (mandatory) 19 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 | conninfo = host=pg user=barman dbname=postgres 21 | 22 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 23 | ; Backup settings (via rsync over SSH) 24 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 25 | backup_method = rsync 26 | ; Incremental backup support: possible values are None (default), link or copy 27 | ;reuse_backup = link 28 | ; Identify the standard behavior for backup operations: possible values are 29 | ; exclusive_backup (default), concurrent_backup 30 | ;backup_options = exclusive_backup 31 | 32 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 33 | ; Continuous WAL archiving (via 'archive_command') 34 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 35 | archiver = on 36 | ;archiver_batch_size = 50 37 | 38 | ; PATH setting for this server 39 | ;path_prefix = "/usr/pgsql-9.6/bin" 40 | -------------------------------------------------------------------------------- /doc/barman.d/streaming-server.conf-template: -------------------------------------------------------------------------------- 1 | ; Barman, Backup and Recovery Manager for PostgreSQL 2 | ; http://www.pgbarman.org/ - http://www.2ndQuadrant.com/ 3 | ; 4 | ; Template configuration file for a server using 5 | ; only streaming replication protocol 6 | ; 7 | 8 | [streaming] 9 | ; Human readable description 10 | description = "Example of PostgreSQL Database (Streaming-Only)" 11 | 12 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | ; PostgreSQL connection string (mandatory) 14 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 15 | conninfo = host=pg user=barman dbname=postgres 16 | 17 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | ; PostgreSQL streaming connection string 19 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 | ; To be used by pg_basebackup for backup and pg_receivexlog for WAL streaming 21 | ; NOTE: streaming_barman is a regular user with REPLICATION privilege 22 | streaming_conninfo = host=pg user=streaming_barman 23 | 24 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 25 | ; Backup settings (via pg_basebackup) 26 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 27 | backup_method = postgres 28 | ;streaming_backup_name = barman_streaming_backup 29 | 30 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 31 | ; WAL streaming settings (via pg_receivexlog) 32 | ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 33 | streaming_archiver = on 34 | slot_name = barman 35 | ;streaming_archiver_name = barman_receive_wal 36 | ;streaming_archiver_batch_size = 50 37 | 38 | ; PATH setting for this server 39 | ;path_prefix = "/usr/pgsql-9.6/bin" 40 | -------------------------------------------------------------------------------- /rpm/rhel6/python-argh.spec: -------------------------------------------------------------------------------- 1 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 2 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 3 | 4 | Summary: A simple argparse wrapper 5 | Name: python-argh 6 | Version: 0.23.0 7 | Release: 1%{?dist} 8 | License: LGPLv3 9 | Group: Development/Libraries 10 | Url: http://bitbucket.org/neithere/argh/ 11 | Source0: http://pypi.python.org/packages/source/a/argh/argh-%{version}.tar.gz 12 | BuildRequires: python-devel, python-setuptools 13 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 14 | BuildArch: noarch 15 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 16 | Requires: python-argparse 17 | 18 | %description 19 | Argh, argparse! 20 | =============== 21 | 22 | Did you ever say "argh" trying to remember the details of optparse or argparse 23 | API? If yes, this package may be useful for you. It provides a very simple 24 | wrapper for argparse with support for hierarchical commands that can be bound 25 | to modules or classes. Argparse can do it; argh makes it easy. 26 | 27 | %prep 28 | %setup -n argh-%{version} -q 29 | 30 | %build 31 | %{__python} setup.py build 32 | 33 | %install 34 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 35 | 36 | %clean 37 | rm -rf $RPM_BUILD_ROOT 38 | 39 | %files 40 | %defattr(-,root,root) 41 | %doc README 42 | %{python_sitelib}/argh-%{version}-py2.6.egg-info 43 | %{python_sitelib}/argh/ 44 | 45 | %changelog 46 | * Thu Jan 31 2013 - Marco Neciarini 0.23.0-1 47 | - Update to version 0.23.0 48 | 49 | * Wed May 9 2012 - Marco Neciarini 0.15.0-1 50 | - Update to version 0.15.0 51 | 52 | * Sat Dec 4 2011 - Marco Neciarini 0.14.2-1 53 | - Initial packaging. 54 | -------------------------------------------------------------------------------- /doc/manual/65-troubleshooting.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Troubleshooting 4 | 5 | ## Diagnose a Barman installation 6 | 7 | You can gather important information about the status of all 8 | the configured servers using: 9 | 10 | ``` bash 11 | barman diagnose 12 | ``` 13 | 14 | The `diagnose` command output is a full snapshot of the barman server, 15 | providing useful information, such as global configuration, SSH version, 16 | Python version, `rsync` version, PostgreSQL clients version, 17 | as well as current configuration and status of all servers. 18 | 19 | The `diagnose` command is extremely useful for troubleshooting problems, 20 | as it gives a global view on the status of your Barman installation. 21 | 22 | ## Requesting help 23 | 24 | Although Barman is extensively documented, there are a lot of scenarios that 25 | are not covered. 26 | 27 | For any questions about Barman and disaster recovery scenarios using Barman, 28 | you can reach the dev team using the community mailing list: 29 | 30 | https://groups.google.com/group/pgbarman 31 | 32 | or the IRC channel on freenode: 33 | irc://irc.freenode.net/barman 34 | 35 | In the event you discover a bug, you can open a ticket using Github: 36 | https://github.com/2ndquadrant-it/barman/issues 37 | 38 | 2ndQuadrant provides professional support for Barman, including 24/7 service. 39 | 40 | ### Submitting a bug 41 | 42 | Barman has been extensively tested and is currently being used in 43 | several production environments. However, as any software, Barman is 44 | not bug free. 45 | 46 | If you discover a bug, please follow this procedure: 47 | 48 | - execute the `barman diagnose` command 49 | - file a bug through the Github issue tracker, by attaching the 50 | output obtained by the diagnostics command above (`barman 51 | diagnose`) 52 | 53 | > **WARNING:** 54 | > Be careful when submitting the output of the diagnose command 55 | > as it might disclose information that are potentially dangerous 56 | > from a security point of view. 57 | -------------------------------------------------------------------------------- /doc/manual/70-feature-matrix.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | \appendix 4 | 5 | # Feature matrix 6 | 7 | Below you will find a matrix of PostgreSQL versions and Barman features for backup and archiving: 8 | 9 | | **Version** | **Backup with rsync/SSH** | **Backup with pg_basebackup** | **Standard WAL archiving** | **WAL Streaming** | **RPO=0** | 10 | |:---------:|:---------------------:|:-------------------------:|:----------------------:|:----------------------:|:-------:| 11 | | **9.6** | Yes | Yes | Yes | Yes | Yes | 12 | | **9.5** | Yes | Yes | Yes | Yes | Yes ~(d)~ | 13 | | **9.4** | Yes | Yes | Yes | Yes | Yes ~(d)~ | 14 | | **9.3** | Yes | Yes ~(c)~ | Yes | Yes ~(b)~ | No | 15 | | **9.2** | Yes | Yes ~(a)~~(c)~ | Yes | Yes ~(a)~~(b)~ | No | 16 | | _9.1_ | Yes | No | Yes | No | No | 17 | | _9.0_ | Yes | No | Yes | No | No | 18 | | _8.4_ | Yes | No | Yes | No | No | 19 | | _8.3_ | Yes | No | Yes | No | No | 20 | 21 | 22 | **NOTE:** 23 | 24 | a) `pg_basebackup` and `pg_receivexlog` 9.2 required 25 | b) WAL streaming-only not supported (standard archiving required) 26 | c) Backup of tablespaces not supported 27 | d) When using `pg_receivexlog` 9.5, minor version 9.5.5 or higher required [^commitsync] 28 | 29 | [^commitsync]: The commit ["Fix pg_receivexlog --synchronous"] [49340627f9821e447f135455d942f7d5e96cae6d] is required (included in version 9.5.5) 30 | 31 | It is required by Barman that `pg_basebackup` and `pg_receivexlog` of the same version of the PostgreSQL server (or higher) are installed on the same server where Barman resides. The only exception is that PostgreSQL 9.2 users are required to install version 9.2 of `pg_basebackup` and `pg_receivexlog` alongside with Barman. 32 | 33 | >> **TIP:** We recommend that the last major, stable version of the PostgreSQL clients (e.g. 9.6) is installed on the Barman server if you plan to use backup and WAL archiving over streaming replication through `pg_basebackup` and `pg_receivexlog`, for PostgreSQL 9.3 or higher servers. 34 | 35 | >> **TIP:** For "RPO=0" architectures, it is recommended to have at least one synchronous standby server. 36 | 37 | -------------------------------------------------------------------------------- /rpm/rhel7/python-argh.spec: -------------------------------------------------------------------------------- 1 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 2 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 3 | 4 | Summary: A simple argparse wrapper 5 | Name: python-argh 6 | Version: 0.26.1 7 | Release: 1%{?dist} 8 | License: LGPLv3 9 | Group: Development/Libraries 10 | Url: http://bitbucket.org/neithere/argh/ 11 | Source0: http://pypi.python.org/packages/source/a/argh/argh-%{version}.tar.gz 12 | BuildRequires: python-devel, python-setuptools 13 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 14 | BuildArch: noarch 15 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 16 | Requires: python-argparse 17 | 18 | %description 19 | Argh, argparse! 20 | =============== 21 | 22 | Did you ever say "argh" trying to remember the details of optparse or argparse 23 | API? If yes, this package may be useful for you. It provides a very simple 24 | wrapper for argparse with support for hierarchical commands that can be bound 25 | to modules or classes. Argparse can do it; argh makes it easy. 26 | 27 | %prep 28 | %setup -n argh-%{version} -q 29 | 30 | %build 31 | %{__python} setup.py build 32 | 33 | %install 34 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 35 | 36 | %clean 37 | rm -rf $RPM_BUILD_ROOT 38 | 39 | %files 40 | %defattr(-,root,root) 41 | %doc README.rst 42 | %{python_sitelib}/argh-%{version}-py2.7.egg-info 43 | %{python_sitelib}/argh/ 44 | 45 | %changelog 46 | 47 | * Tue Jan 20 2015 - Francesco Canovai 0.26.1-1 48 | - Update to version 0.26.1 49 | 50 | * Thu Jan 31 2013 - Marco Nenciarini 0.23.0-1 51 | - Update to version 0.23.0 52 | 53 | * Wed May 9 2012 - Marco Nenciarini 0.15.0-1 54 | - Update to version 0.15.0 55 | 56 | * Sat Dec 3 2011 - Marco Nenciarini 0.14.2-1 57 | - Initial packaging. 58 | -------------------------------------------------------------------------------- /rpm/rhel6/python-argcomplete.spec: -------------------------------------------------------------------------------- 1 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 2 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 3 | 4 | Summary: Bash tab completion for argparse 5 | Name: python-argcomplete 6 | Version: 0.3.5 7 | Release: 1%{?dist} 8 | License: ASL 2.0 9 | Group: Development/Libraries 10 | Url: https://github.com/kislyuk/argcomplete 11 | Source0: http://pypi.python.org/packages/source/a/argcomplete/argcomplete-%{version}.tar.gz 12 | BuildRequires: python-devel,python-setuptools 13 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 14 | BuildArch: noarch 15 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 16 | Requires: python-argparse 17 | 18 | %description 19 | Argcomplete provides easy, extensible command line tab completion of 20 | arguments for your Python script. 21 | 22 | It makes two assumptions: 23 | 24 | * You're using bash as your shell 25 | * You're using argparse to manage your command line arguments/options 26 | 27 | Argcomplete is particularly useful if your program has lots of 28 | options or subparsers, and if your program can dynamically suggest 29 | completions for your argument/option values (for example, if the user 30 | is browsing resources over the network). 31 | 32 | %prep 33 | %setup -n argcomplete-%{version} -q 34 | 35 | %build 36 | %{__python} setup.py build 37 | 38 | %install 39 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 40 | 41 | %clean 42 | rm -rf $RPM_BUILD_ROOT 43 | 44 | %files 45 | %defattr(-,root,root) 46 | %doc README.rst 47 | %{python_sitelib}/argcomplete-%{version}-py2.6.egg-info 48 | %{python_sitelib}/argcomplete/ 49 | %{_bindir}/activate-global-python-argcomplete 50 | %{_bindir}/python-argcomplete-check-easy-install-script 51 | %{_bindir}/register-python-argcomplete 52 | 53 | %changelog 54 | * Thu Jan 31 2013 - Marco Neciarini 0.3.5-1 55 | - Initial packaging. 56 | -------------------------------------------------------------------------------- /doc/manual/41-global-commands.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # General commands 4 | 5 | Barman has many commands and, for the sake of exposition, we can 6 | organize them by scope. 7 | 8 | The scope of the **general commands** is the entire Barman server, 9 | that can backup many PostgreSQL servers. **Server commands**, instead, 10 | act only on a specified server. **Backup commands** work on a backup, 11 | which is taken from a certain server. 12 | 13 | The following list includes the general commands. 14 | 15 | 16 | ## `cron` 17 | 18 | You can perform maintenance operations, on both WAL files and backups, 19 | using the `cron` command: 20 | 21 | ``` bash 22 | barman cron 23 | ``` 24 | 25 | > **NOTE:** 26 | > This command should be executed in a _cron script_. Our 27 | > recommendation is to schedule `barman cron` to run every minute. If 28 | > you installed Barman using the rpm or debian package, a cron entry 29 | > running on every minute will be created for you. 30 | 31 | `barman cron` executes WAL archiving operations concurrently on a 32 | server basis, and this also enforces retention policies on those 33 | servers that have: 34 | 35 | - `retention_policy` not empty and valid; 36 | - `retention_policy_mode` set to `auto`. 37 | 38 | The `cron` command ensures that WAL streaming is started for those 39 | servers that have requested it, by transparently executing the 40 | `receive-wal` command. 41 | 42 | 43 | ## `diagnose` 44 | 45 | The `diagnose` command creates a JSON report useful for diagnostic and 46 | support purposes. This report contains information for all configured 47 | servers. 48 | 49 | > **IMPORTANT:** 50 | > Even if the diagnose is written in JSON and that format is thought 51 | > to be machine readable, its structure is not to be considered part 52 | > of the interface. Format can change between different Barman versions. 53 | 54 | 55 | ## `list-server` 56 | 57 | You can display the list of active servers that have been configured 58 | for your backup system with: 59 | 60 | ``` bash 61 | barman list-server 62 | ``` 63 | 64 | A machine readble output can be obtained with the `--minimal` option: 65 | 66 | ``` bash 67 | barman list-server --minimal 68 | ``` 69 | -------------------------------------------------------------------------------- /doc/manual/24-wal_archiving.en.md: -------------------------------------------------------------------------------- 1 | ## WAL archiving via `archive_command` 2 | 3 | The `archive_command` is the traditional method to archive WAL files. 4 | 5 | The value of this PostgreSQL configuration parameter must be a shell 6 | command to be executed by the PostgreSQL server to copy the WAL files 7 | to the Barman incoming directory. 8 | 9 | You can retrieve the incoming WALs directory using the `show-server` 10 | Barman command and looking for the `incoming_wals_directory` value: 11 | 12 | ``` bash 13 | barman@backup$ barman show-server pg |grep incoming_wals_directory 14 | incoming_wals_directory: /var/lib/barman/pg/incoming 15 | ``` 16 | 17 | > **IMPORTANT:** 18 | > PostgreSQL 9.5 introduced support for WAL file archiving using 19 | > `archive_command` from a standby. This feature is not yet implemented 20 | > in Barman. 21 | 22 | Edit the `postgresql.conf` file of the PostgreSQL instance on the `pg` 23 | database and activate the archive mode: 24 | 25 | ``` ini 26 | archive_mode = on 27 | wal_level = 'replica' 28 | archive_command = 'rsync -a %p barman@backup:INCOMING_WALS_DIRECTORY/%f' 29 | ``` 30 | 31 | Make sure you change the `INCOMING_WALS_DIRECTORY` placeholder with 32 | the value returned by the `barman show-server pg` command above. 33 | 34 | Restart the PostgreSQL server. 35 | 36 | In order to test that continuous archiving is on and properly working, 37 | you need to check both the PostgreSQL server and the backup server. In 38 | particular, you need to check that WAL files are correctly collected 39 | in the destination directory. 40 | 41 | 42 | ## Verification of WAL archiving configuration 43 | 44 | In order to improve the verification of the WAL archiving process, the 45 | `switch-xlog` command has been developed: 46 | 47 | ``` bash 48 | barman@backup$ barman switch-xlog --force --archive pg 49 | ``` 50 | 51 | The above command will force PostgreSQL to switch WAL file and 52 | trigger the archiving process in Barman. Barman will wait for one 53 | file to arrive within 30 seconds (you can change the timeout through 54 | the `--archive-timeout` option). If no WAL file is received, an error 55 | is returned. 56 | 57 | You can verify if the WAL archiving has been correctly configured using 58 | the `barman check` command. 59 | -------------------------------------------------------------------------------- /rpm/rhel5/python26-argh.spec: -------------------------------------------------------------------------------- 1 | # Use Python 2.6 2 | %global pybasever 2.6 3 | %global __python_ver 26 4 | %global __python %{_bindir}/python%{pybasever} 5 | %global __os_install_post %{__multiple_python_os_install_post} 6 | 7 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 8 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 9 | 10 | Summary: A simple argparse wrapper 11 | Name: python%{__python_ver}-argh 12 | Version: 0.23.0 13 | Release: 1%{?dist} 14 | License: LGPLv3 15 | Group: Development/Libraries 16 | Url: http://bitbucket.org/neithere/argh/ 17 | Source0: http://pypi.python.org/packages/source/a/argh/argh-%{version}.tar.gz 18 | BuildRequires: python%{__python_ver}-devel,python%{__python_ver}-setuptools 19 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 20 | BuildArch: noarch 21 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 22 | 23 | %if "%{__python_ver}" == "26" 24 | Requires: python%{__python_ver}-argparse 25 | %endif 26 | 27 | %description 28 | Agrh, argparse! 29 | =============== 30 | 31 | Did you ever say "argh" trying to remember the details of optparse or argparse 32 | API? If yes, this package may be useful for you. It provides a very simple 33 | wrapper for argparse with support for hierarchical commands that can be bound 34 | to modules or classes. Argparse can do it; argh makes it easy. 35 | 36 | %prep 37 | %setup -n argh-%{version} -q 38 | 39 | %build 40 | %{__python} setup.py build 41 | 42 | %install 43 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 44 | 45 | %clean 46 | rm -rf $RPM_BUILD_ROOT 47 | 48 | %files 49 | %defattr(-,root,root) 50 | %doc README 51 | %{python_sitelib}/argh-%{version}-py%{pybasever}.egg-info 52 | %{python_sitelib}/argh/ 53 | 54 | %changelog 55 | * Thu Jan 31 2013 - Marco Neciarini 0.23.0-1 56 | - Update to version 0.23.0 57 | 58 | * Wed May 9 2012 - Marco Neciarini 0.15.0-1 59 | - Update to version 0.15.0 60 | 61 | * Sat Dec 4 2011 - Marco Neciarini 0.14.2-1 62 | - Initial packaging. 63 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Barman, Backup and Recovery Manager for PostgreSQL 2 | ================================================== 3 | 4 | Barman (Backup and Recovery Manager) is an open-source administration 5 | tool for disaster recovery of PostgreSQL servers written in Python. It 6 | allows your organisation to perform remote backups of multiple servers 7 | in business critical environments to reduce risk and help DBAs during 8 | the recovery phase. 9 | 10 | Barman is distributed under GNU GPL 3 and maintained by 2ndQuadrant. 11 | 12 | For further information, look at the "Web resources" section below. 13 | 14 | Source content 15 | -------------- 16 | 17 | Here you can find a description of files and directory distributed with 18 | Barman: 19 | 20 | - AUTHORS : development team of Barman 21 | - NEWS : release notes 22 | - ChangeLog : log of changes 23 | - LICENSE : GNU GPL3 details 24 | - TODO : our wishlist for Barman 25 | - barman : sources in Python 26 | - doc : tutorial and man pages 27 | - rpm : SPEC files for RHEL distributions 28 | - scripts : auxiliary scripts 29 | - tests : unit tests 30 | 31 | Web resources 32 | ------------- 33 | 34 | - Website : http://www.pgbarman.org/ 35 | - Download : http://sourceforge.net/projects/pgbarman/files/ 36 | - Documentation : http://www.pgbarman.org/documentation/ 37 | - Man page, section 1 : http://docs.pgbarman.org/barman.1.html 38 | - Man page, section 5 : http://docs.pgbarman.org/barman.5.html 39 | - Community support : http://www.pgbarman.org/support/ 40 | - Professional support : http://www.2ndquadrant.com/ 41 | - Client utilities : https://github.com/2ndquadrant-it/barman-cli 42 | - pgespresso extension : https://github.com/2ndquadrant-it/pgespresso 43 | 44 | Licence 45 | ------- 46 | 47 | Copyright (C) 2011-2016 2ndQuadrant Italia Srl 48 | 49 | Barman is free software: you can redistribute it and/or modify it under 50 | the terms of the GNU General Public License as published by the Free 51 | Software Foundation, either version 3 of the License, or (at your 52 | option) any later version. 53 | 54 | Barman is distributed in the hope that it will be useful, but WITHOUT 55 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 56 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 57 | more details. 58 | 59 | You should have received a copy of the GNU General Public License along 60 | with Barman. If not, see http://www.gnu.org/licenses/. 61 | -------------------------------------------------------------------------------- /rpm/rhel5/python26-argcomplete.spec: -------------------------------------------------------------------------------- 1 | # Use Python 2.6 2 | %global pybasever 2.6 3 | %global __python_ver 26 4 | %global __python %{_bindir}/python%{pybasever} 5 | %global __os_install_post %{__multiple_python_os_install_post} 6 | 7 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 8 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 9 | 10 | Summary: Bash tab completion for argparse 11 | Name: python%{__python_ver}-argcomplete 12 | Version: 0.3.5 13 | Release: 1%{?dist} 14 | License: ASL 2.0 15 | Group: Development/Libraries 16 | Url: https://github.com/kislyuk/argcomplete 17 | Source0: http://pypi.python.org/packages/source/a/argcomplete/argcomplete-%{version}.tar.gz 18 | BuildRequires: python%{__python_ver}-devel,python%{__python_ver}-setuptools 19 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 20 | BuildArch: noarch 21 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 22 | 23 | %if "%{__python_ver}" == "26" 24 | Requires: python%{__python_ver}-argparse 25 | %endif 26 | 27 | %description 28 | Argcomplete provides easy, extensible command line tab completion of 29 | arguments for your Python script. 30 | 31 | It makes two assumptions: 32 | 33 | * You're using bash as your shell 34 | * You're using argparse to manage your command line arguments/options 35 | 36 | Argcomplete is particularly useful if your program has lots of 37 | options or subparsers, and if your program can dynamically suggest 38 | completions for your argument/option values (for example, if the user 39 | is browsing resources over the network). 40 | 41 | %prep 42 | %setup -n argcomplete-%{version} -q 43 | 44 | %build 45 | %{__python} setup.py build 46 | 47 | %install 48 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 49 | 50 | %clean 51 | rm -rf $RPM_BUILD_ROOT 52 | 53 | %files 54 | %defattr(-,root,root) 55 | %doc README.rst 56 | %{python_sitelib}/argcomplete-%{version}-py%{pybasever}.egg-info 57 | %{python_sitelib}/argcomplete/ 58 | %{_bindir}/activate-global-python-argcomplete 59 | %{_bindir}/python-argcomplete-check-easy-install-script 60 | %{_bindir}/register-python-argcomplete 61 | 62 | %changelog 63 | * Thu Jan 31 2013 - Marco Neciarini 0.3.5-1 64 | - Initial packaging. 65 | -------------------------------------------------------------------------------- /barman/remote_status.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | """ 19 | Remote Status module 20 | 21 | A Remote Status class implements a standard interface for 22 | retrieving and caching the results of a remote component 23 | (such as Postgres server, WAL archiver, etc.). It follows 24 | the Mixin pattern. 25 | """ 26 | 27 | from abc import ABCMeta, abstractmethod 28 | 29 | from barman.utils import with_metaclass 30 | 31 | 32 | class RemoteStatusMixin(with_metaclass(ABCMeta, object)): 33 | """ 34 | Abstract base class that implements remote status capabilities 35 | following the Mixin pattern. 36 | """ 37 | 38 | def __init__(self, *args, **kwargs): 39 | """ 40 | Base constructor (Mixin pattern) 41 | """ 42 | self._remote_status = None 43 | super(RemoteStatusMixin, self).__init__(*args, **kwargs) 44 | 45 | @abstractmethod 46 | def fetch_remote_status(self): 47 | """ 48 | Retrieve status information from the remote component 49 | 50 | The implementation of this method must not raise any exception in case 51 | of errors, but should set the missing values to None in the resulting 52 | dictionary. 53 | 54 | :rtype: dict[str, None|str] 55 | """ 56 | 57 | def get_remote_status(self): 58 | """ 59 | Get the status of the remote component 60 | 61 | This method does not raise any exception in case of errors, 62 | but set the missing values to None in the resulting dictionary. 63 | 64 | :rtype: dict[str, None|str] 65 | """ 66 | if self._remote_status is None: 67 | self._remote_status = self.fetch_remote_status() 68 | return self._remote_status 69 | 70 | def reset_remote_status(self): 71 | """ 72 | Reset the cached result 73 | """ 74 | self._remote_status = None 75 | -------------------------------------------------------------------------------- /doc/manual/15-system_requirements.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # System requirements 4 | 5 | - Linux/Unix 6 | - Python 2.6 or 2.7 7 | - Python modules: 8 | - argcomplete 9 | - argh >= 0.21.2 <= 0.26.2 10 | - argparse (Python 2.6 only) 11 | - psycopg2 >= 2.4.2 12 | - python-dateutil <> 2.0 13 | - setuptools 14 | - PostgreSQL >= 8.3 15 | - rsync >= 3.0.4 (optional for PostgreSQL >= 9.2) 16 | 17 | > **IMPORTANT:** 18 | > Users of RedHat Enterprise Linux, CentOS and Scientific Linux are 19 | > required to install the 20 | > [Extra Packages Enterprise Linux (EPEL) repository] [epel]. 21 | 22 | > **NOTE:** 23 | > Python 3 support is experimental. Report any bug through 24 | > the ticketing system on Github or the mailing list. 25 | 26 | ## Requirements for backup 27 | 28 | The most critical requirement for a Barman server is the amount of disk space available. 29 | You are recommended to plan the required disk space based on the size of the cluster, number of WAL files generated per day, frequency of backups, and retention policies. 30 | 31 | Although the only file systems that we officially support are XFS and Ext4, we are aware of users that deploy Barman on different file systems including ZFS and NFS. 32 | 33 | ## Requirements for recovery 34 | 35 | Barman allows you to recover a PostgreSQL instance either 36 | locally (where Barman resides) or remotely (on a separate server). 37 | 38 | Remote recovery is definitely the most common way to restore a PostgreSQL 39 | server with Barman. 40 | 41 | Either way, the same [requirements for PostgreSQL's Log shipping and Point-In-Time-Recovery apply] [requirements_recovery]: 42 | 43 | - identical hardware architecture 44 | - identical major version of PostgreSQL 45 | 46 | In general, it is **highly recommended** to create recovery environments that are as similar as possible, if not identical, to the original server, because they are easier to maintain. For example, we suggest that you use the same operating system, the same PostgreSQL version, the same disk layouts, and so on. 47 | 48 | Additionally, dedicated recovery environments for each PostgreSQL server, even on demand, allows you to nurture the disaster recovery culture in your team. You can be prepared for when something unexpected happens by practising 49 | recovery operations and becoming familiar with them. 50 | 51 | Based on our experience, designated recovery environments reduce the impact of stress in real failure situations, and therefore increase the effectiveness of recovery operations. 52 | 53 | Finally, it is important that time is synchronised between the servers, using NTP for example. 54 | -------------------------------------------------------------------------------- /sphinx/README.md: -------------------------------------------------------------------------------- 1 | # Generate sphinx documentation 2 | 3 | Generate barman code documentation using Sphinx autodoc 4 | 5 | ## Prerequisites 6 | 7 | Install the python modules required to build the documentation 8 | by executing, from the root directory of Barman: 9 | 10 | ``` bash 11 | pip install -r sphinx/requirements.txt 12 | ``` 13 | 14 | ## Documentation generation 15 | 16 | From the root folder of Barman, launch: 17 | 18 | ``` bash 19 | sphinx/generate_docs.sh 20 | ``` 21 | 22 | 23 | ### `generate_docs.sh` options 24 | 25 | Is possible to use a different path to the barman source files 26 | directory (default: the current barman source directory) passing it 27 | as argument to the `generate_docs.sh` script. 28 | 29 | ``` bash 30 | sphinx/generate_docs.sh 31 | ``` 32 | 33 | It's also possible to pass the target format (default: `html`) 34 | to the generate_docs.sh script using the -t option followed by 35 | one of the available formats: 36 | 37 | * html to make standalone HTML files 38 | * dirhtml to make HTML files named index.html in directories 39 | * singlehtml to make a single large HTML file 40 | * pickle to make pickle files 41 | * json to make JSON files 42 | * htmlhelp to make HTML files and a HTML help project 43 | * qthelp to make HTML files and a qthelp project 44 | * devhelp to make HTML files and a Devhelp project 45 | * epub to make an epub 46 | * latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 47 | * latexpdf to make LaTeX files and run them through pdflatex 48 | * text to make text files 49 | * man to make manual pages 50 | * texinfo to make Texinfo files 51 | * info to make Texinfo files and run them through makeinfo 52 | * gettext to make PO message catalogs 53 | * changes to make an overview of all changed/added/deprecated items 54 | * linkcheck to check all external links for integrity 55 | * doctest to run all doctests embedded in the documentation (if enabled) 56 | 57 | ## Licence 58 | 59 | Copyright (C) 2011-2016 2ndQuadrant Italia Srl 60 | 61 | Barman is free software: you can redistribute it and/or modify 62 | it under the terms of the GNU General Public License as published by 63 | the Free Software Foundation, either version 3 of the License, or 64 | (at your option) any later version. 65 | 66 | Barman is distributed in the hope that it will be useful, 67 | but WITHOUT ANY WARRANTY; without even the implied warranty of 68 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 69 | GNU General Public License for more details. 70 | 71 | You should have received a copy of the GNU General Public License 72 | along with Barman. If not, see . 73 | -------------------------------------------------------------------------------- /sphinx/docs/index.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright (C) 2011-2016 2ndQuadrant Italia Srl 3 | Barman is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | Barman is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with Barman. If not, see . 13 | 14 | 15 | Welcome to barman |version| 16 | =========================== 17 | 18 | Barman (Backup and Recovery Manager) is an open-source administration 19 | tool for disaster recovery of PostgreSQL servers written in Python. 20 | It allows your organisation to perform remote backups of multiple 21 | servers in business critical environments to reduce risk and help DBAs 22 | during the recovery phase. 23 | 24 | Barman is distributed under GNU GPL 3 and maintained by 2ndQuadrant. 25 | 26 | For further information, look at the "Web resources" section below. 27 | 28 | Contents: 29 | 30 | .. toctree:: 31 | :maxdepth: 4 32 | 33 | barman 34 | 35 | Web resources 36 | ============= 37 | 38 | * Website : http://www.pgbarman.org/ 39 | * Download : http://sourceforge.net/projects/pgbarman/files/ 40 | * Documentation : http://www.pgbarman.org/documentation/ 41 | * Man page, section 1 : http://docs.pgbarman.org/barman.1.html 42 | * Man page, section 5 : http://docs.pgbarman.org/barman.5.html 43 | * Community support : http://www.pgbarman.org/support/ 44 | * Professional support : http://www.2ndquadrant.com/ 45 | * Client utilities : https://github.com/2ndquadrant-it/barman-cli 46 | * pgespresso extension : https://github.com/2ndquadrant-it/pgespresso 47 | 48 | Licence 49 | ======= 50 | 51 | Copyright (C) 2011-2016 2ndQuadrant Italia Srl 52 | 53 | Barman is free software: you can redistribute it and/or modify 54 | it under the terms of the GNU General Public License as published by 55 | the Free Software Foundation, either version 3 of the License, or 56 | (at your option) any later version. 57 | 58 | Barman is distributed in the hope that it will be useful, 59 | but WITHOUT ANY WARRANTY; without even the implied warranty of 60 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 61 | GNU General Public License for more details. 62 | 63 | You should have received a copy of the GNU General Public License 64 | along with Barman. If not, see . 65 | 66 | 67 | Indices and tables 68 | ================== 69 | 70 | * :ref:`genindex` 71 | * :ref:`modindex` 72 | * :ref:`search` 73 | -------------------------------------------------------------------------------- /doc/manual/99-references.en.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [rpo]: https://en.wikipedia.org/wiki/Recovery_point_objective 4 | [rto]: https://en.wikipedia.org/wiki/Recovery_time_objective 5 | [repmgr]: http://www.repmgr.org/ 6 | [sqldump]: https://www.postgresql.org/docs/current/static/backup-dump.html 7 | [recoveryconfig]: https://www.postgresql.org/docs/current/static/recovery-config.html 8 | [physicalbackup]: https://www.postgresql.org/docs/current/static/backup-file.html 9 | [pitr]: https://www.postgresql.org/docs/current/static/continuous-archiving.html 10 | [adminbook]: http://www.2ndquadrant.com/en/books/postgresql-9-administration-cookbook/ 11 | [wal]: https://www.postgresql.org/docs/current/static/wal.html 12 | [49340627f9821e447f135455d942f7d5e96cae6d]: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=49340627f9821e447f135455d942f7d5e96cae6d 13 | [requirements_recovery]: https://www.postgresql.org/docs/current/static/warm-standby.html#STANDBY-PLANNING 14 | [yumpgdg]: http://yum.postgresql.org/ 15 | [aptpgdg]: http://apt.postgresql.org/ 16 | [aptpgdgwiki]: https://wiki.postgresql.org/wiki/Apt 17 | [epel]: http://fedoraproject.org/wiki/EPEL 18 | [man5]: http://docs.pgbarman.org/barman.5.html 19 | [setup_user]: https://docs.python.org/3/install/index.html#alternate-installation-the-user-scheme 20 | [pypi]: https://pypi.python.org/pypi/barman/ 21 | [pgpass]: https://www.postgresql.org/docs/current/static/libpq-pgpass.html 22 | [pghba]: http://www.postgresql.org/docs/current/static/client-authentication.html 23 | [authpghba]: http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html 24 | [streamprot]: http://www.postgresql.org/docs/current/static/protocol-replication.html 25 | [roles]: http://www.postgresql.org/docs/current/static/role-attributes.html 26 | [replication-slots]: https://www.postgresql.org/docs/current/static/warm-standby.html#STREAMING-REPLICATION-SLOTS 27 | [synch]: http://www.postgresql.org/docs/current/static/warm-standby.html#SYNCHRONOUS-REPLICATION 28 | 29 | 30 | 31 | 32 | [3]: https://sourceforge.net/projects/pgbarman/files/ 33 | [8]: http://en.wikipedia.org/wiki/Hard_link 34 | [9]: https://github.com/2ndquadrant-it/pgespresso 35 | [11]: http://www.pgbarman.org/ 36 | [12]: http://www.pgbarman.org/support/ 37 | [13]: http://www.2ndquadrant.com/ 38 | [14]: http://www.pgbarman.org/faq/ 39 | [15]: http://blog.2ndquadrant.com/tag/barman/ 40 | [16]: https://github.com/hamann/check-barman 41 | [17]: https://github.com/2ndquadrant-it/puppet-barman 42 | [18]: http://4caast.morfeo-project.org/ 43 | [19]: http://www.2ndquadrant.it/ 44 | [20]: http://www.postgresql.org/docs/current/static/functions-admin.html 45 | [24]: http://www.postgresql.org/docs/current/static/warm-standby.html#STREAMING-REPLICATION 46 | [25]: http://www.postgresql.org/docs/current/static/app-pgreceivexlog.html 47 | [26]: https://goo.gl/218Ghl 48 | [27]: https://github.com/emin100/barmanapi 49 | 50 | [31]: http://www.postgresql.org/ 51 | -------------------------------------------------------------------------------- /barman/diagnose.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | """ 19 | This module represents the barman diagnostic tool. 20 | """ 21 | 22 | import json 23 | import logging 24 | import sys 25 | 26 | import barman 27 | from barman import fs, output 28 | from barman.backup import BackupInfo 29 | from barman.exceptions import FsOperationFailed 30 | from barman.utils import BarmanEncoder 31 | 32 | _logger = logging.getLogger(__name__) 33 | 34 | 35 | def exec_diagnose(servers, errors_list): 36 | """ 37 | Diagnostic command: gathers information from backup server 38 | and from all the configured servers. 39 | 40 | Gathered information should be used for support and problems detection 41 | 42 | :param dict(str,barman.server.Server) servers: list of configured servers 43 | :param list errors_list: list of global errors 44 | """ 45 | # global section. info about barman server 46 | diagnosis = {'global': {}, 'servers': {}} 47 | # barman global config 48 | diagnosis['global']['config'] = dict(barman.__config__._global_config) 49 | diagnosis['global']['config']['errors_list'] = errors_list 50 | command = fs.UnixLocalCommand() 51 | # basic system info 52 | diagnosis['global']['system_info'] = command.get_system_info() 53 | diagnosis['global']['system_info']['barman_ver'] = barman.__version__ 54 | # per server section 55 | for name in sorted(servers): 56 | server = servers[name] 57 | if server is None: 58 | output.error("Unknown server '%s'" % name) 59 | continue 60 | # server configuration 61 | diagnosis['servers'][name] = {} 62 | diagnosis['servers'][name]['config'] = vars(server.config) 63 | del diagnosis['servers'][name]['config']['config'] 64 | # server system info 65 | if server.config.ssh_command: 66 | try: 67 | command = fs.UnixRemoteCommand( 68 | ssh_command=server.config.ssh_command, 69 | path=server.path 70 | ) 71 | diagnosis['servers'][name]['system_info'] = ( 72 | command.get_system_info()) 73 | except FsOperationFailed: 74 | pass 75 | # barman statuts information for the server 76 | diagnosis['servers'][name]['status'] = server.get_remote_status() 77 | # backup list 78 | backups = server.get_available_backups(BackupInfo.STATUS_ALL) 79 | diagnosis['servers'][name]['backups'] = backups 80 | # wal status 81 | diagnosis['servers'][name]['wals'] = { 82 | 'last_archived_wal_per_timeline': 83 | server.backup_manager.get_latest_archived_wals_info(), 84 | } 85 | # Release any PostgreSQL resource 86 | server.close() 87 | output.info(json.dumps(diagnosis, sys.stdout, cls=BarmanEncoder, indent=4, 88 | sort_keys=True)) 89 | -------------------------------------------------------------------------------- /doc/manual/16-installation.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Installation 4 | 5 | > **IMPORTANT:** 6 | > The recommended way to install Barman is by using the available 7 | > packages for your GNU/Linux distribution. 8 | 9 | ## Installation on RedHat/CentOS using RPM packages 10 | 11 | Barman can be installed on RHEL7, RHEL6 and RHEL5 Linux systems using 12 | RPM packages. It is required to install the Extra Packages Enterprise 13 | Linux (EPEL) repository beforehand. 14 | 15 | RPM packages for Barman are available via Yum through the 16 | [PostgreSQL Global Development Group RPM repository] [yumpgdg]. 17 | You need to follow the instructions for your distribution (for example RedHat, 18 | CentOS, or Fedora) and architecture as detailed at 19 | [yum.postgresql.org] [yumpgdg]. 20 | 21 | Then, as `root` simply type: 22 | 23 | ``` bash 24 | yum install barman 25 | ``` 26 | 27 | 2ndQuadrant also maintains RPM packages for Barman and distributes 28 | them through [Sourceforge.net] [3]. 29 | 30 | ## Installation on Debian/Ubuntu using packages 31 | 32 | Barman can be installed on Debian and Ubuntu Linux systems using 33 | packages. 34 | 35 | It is directly available in the official repository for Debian and Ubuntu, however, these repositories might not contain the latest available version. 36 | If you want to have the latest version of Barman, the recommended method is to install it through the [PostgreSQL Community APT repository] [aptpgdg]. 37 | Instructions can be found in the [APT section of the PostgreSQL Wiki] [aptpgdgwiki]. 38 | 39 | > **NOTE:** 40 | > Thanks to the direct involvement of Barman developers in the 41 | > PostgreSQL Community APT repository project, you will always have access 42 | > to the most updated versions of Barman. 43 | 44 | Installing Barman is as easy. As `root` user simply type: 45 | 46 | ``` bash 47 | apt-get install barman 48 | ``` 49 | 50 | ## Installation from sources 51 | 52 | > **WARNING:** 53 | > Manual installation of Barman from sources should only be performed 54 | > by expert GNU/Linux users. Installing Barman this way requires 55 | > system administration activities such as dependencies management, 56 | > `barman` user creation, configuration of the `barman.conf` file, 57 | > cron setup for the `barman cron` command, log management, and so on. 58 | 59 | Create a system user called `barman` on the `backup` server. 60 | As `barman` user, download the sources and uncompress them. 61 | 62 | For a system-wide installation, type: 63 | 64 | ``` bash 65 | barman@backup$ ./setup.py build 66 | # run this command with root privileges or through sudo 67 | barman@backup# ./setup.py install 68 | ``` 69 | 70 | For a local installation, type: 71 | 72 | ``` bash 73 | barman@backup$ ./setup.py install --user 74 | ``` 75 | 76 | The `barman` application will be installed in your user directory ([make sure that your `PATH` environment variable is set properly] [setup_user]). 77 | 78 | [Barman is also available on the Python Package Index (PyPI)] [pypi] and can be installed through `pip`. 79 | 80 | ## Upgrading from Barman 1.X 81 | 82 | Version 2.0 requires that users explicitly configure 83 | their archiving strategy. Before, the file based 84 | archiver, controlled by `archiver`, was enabled by default. 85 | 86 | When you upgrade your Barman installation to 2.0, make sure 87 | you add the following line either globally or for any server 88 | that requires it: 89 | 90 | ``` ini 91 | archiver = on 92 | ``` 93 | 94 | Additionally, for a few releases, Barman will transparently set 95 | `archiver = on` with any server that has not explicitly set 96 | an archiving strategy and emit a warning. 97 | 98 | Besides that, version 2.0 is fully compatible with older ones. 99 | -------------------------------------------------------------------------------- /doc/manual/17-configuration.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Configuration 4 | 5 | There are two types of configuration files in Barman: 6 | 7 | - **global/general configuration** 8 | - **server configuration** 9 | 10 | The main configuration file (set to `/etc/barman.conf` by default) contains general options such as main directory, system user, log file, and so on. 11 | 12 | Server configuration files, one for each server to be backed up by Barman, are located in the `/etc/barman.d` directory and must have a `.conf` suffix. 13 | 14 | > **IMPORTANT**: For historical reasons, you can still have one single 15 | > configuration file containing both global and server options. However, 16 | > for maintenance reasons, this approach is deprecated. 17 | 18 | Configuration files in Barman follow the _INI_ format. 19 | 20 | ## Options scope 21 | 22 | Every configuration option has a _scope_: 23 | 24 | - global 25 | - server 26 | - global/server: server options that can be generally set at global level 27 | 28 | Global options are allowed in the _general section_, which is identified in the INI file by the `[barman]` label: 29 | 30 | ``` ini 31 | [barman] 32 | ; ... global and global/server options go here 33 | ``` 34 | 35 | Server options can only be specified in a _server section_, which is identified by a line in the configuration file, in square brackets (`[` and `]`). The server section represents the ID of that server in Barman. The following example specifies a section for the server named `pg`: 36 | 37 | ``` ini 38 | [pg] 39 | ; Configuration options for the 40 | ; server named 'pg' go here 41 | ``` 42 | 43 | There are two reserved words that cannot be used as server names in Barman: 44 | 45 | - `barman`: identifier of the global section 46 | - `all`: a handy shortcut that allows you to execute some commands on every server managed by Barman in sequence 47 | 48 | Barman implements the **convention over configuration** design paradigm, which attempts to reduce the number of options that you are required to configure without losing flexibility. Therefore, some server options can be defined at global level and overridden at server level, allowing users to specify a generic behavior and refine it for one or more servers. These options have a global/server scope. 49 | 50 | For a list of all the available configurations 51 | and their scope, please refer to [section 5 of the 'man' page] [man5]. 52 | 53 | ``` bash 54 | man 5 barman 55 | ``` 56 | 57 | ## Examples of configuration 58 | 59 | The following is a basic example of main configuration file: 60 | 61 | ``` ini 62 | [barman] 63 | barman_user = barman 64 | configuration_files_directory = /etc/barman.d 65 | barman_home = /var/lib/barman 66 | log_file = /var/log/barman/barman.log 67 | log_level = INFO 68 | compression = gzip 69 | ``` 70 | 71 | The example below, on the other hand, is a server configuration file that uses streaming backup: 72 | 73 | ``` ini 74 | [streaming-pg] 75 | description = "Example of PostgreSQL Database (Streaming-Only)" 76 | conninfo = host=pg user=barman dbname=postgres 77 | streaming_conninfo = host=pg user=streaming_barman 78 | backup_method = postgres 79 | streaming_archiver = on 80 | slot_name = barman 81 | ``` 82 | 83 | The following code shows a basic example of traditional backup using `rsync`/SSH: 84 | 85 | ``` ini 86 | [ssh-pg] 87 | description = "Example of PostgreSQL Database (via Ssh)" 88 | ssh_command = ssh postgres@pg 89 | conninfo = host=pg user=barman dbname=postgres 90 | backup_method = rsync 91 | reuse_backup = link 92 | archiver = on 93 | ``` 94 | 95 | For more detailed information, please refer to the distributed 96 | `barman.conf` file, as well as the `ssh-server.conf-template` and `streaming-server.conf-template` template files. 97 | -------------------------------------------------------------------------------- /rpm/rhel5/python-dateutil-1.4.1-remove-embedded-timezone-data.patch: -------------------------------------------------------------------------------- 1 | diff -up python-dateutil-1.4.1/dateutil/tz.py.remove-embedded-timezone-data python-dateutil-1.4.1/dateutil/tz.py 2 | --- python-dateutil-1.4.1/dateutil/tz.py.remove-embedded-timezone-data 2008-02-27 20:45:41.000000000 -0500 3 | +++ python-dateutil-1.4.1/dateutil/tz.py 2010-07-13 14:40:30.228122861 -0400 4 | @@ -930,9 +930,6 @@ def gettz(name=None): 5 | except OSError: 6 | pass 7 | if not tz: 8 | - from dateutil.zoneinfo import gettz 9 | - tz = gettz(name) 10 | - if not tz: 11 | for c in name: 12 | # name must have at least one offset to be a tzstr 13 | if c in "0123456789": 14 | diff -up python-dateutil-1.4.1/dateutil/zoneinfo/__init__.py.remove-embedded-timezone-data python-dateutil-1.4.1/dateutil/zoneinfo/__init__.py 15 | --- python-dateutil-1.4.1/dateutil/zoneinfo/__init__.py.remove-embedded-timezone-data 2005-12-22 13:13:50.000000000 -0500 16 | +++ python-dateutil-1.4.1/dateutil/zoneinfo/__init__.py 2010-07-13 14:40:30.228122861 -0400 17 | @@ -3,6 +3,10 @@ Copyright (c) 2003-2005 Gustavo Niemeye 18 | 19 | This module offers extensions to the standard python 2.3+ 20 | datetime module. 21 | + 22 | +This version of the code has been modified to remove the embedded copy 23 | +of zoneinfo-2008e.tar.gz and instead use the system data from the tzdata 24 | +package 25 | """ 26 | from dateutil.tz import tzfile 27 | from tarfile import TarFile 28 | @@ -13,49 +17,12 @@ __license__ = "PSF License" 29 | 30 | __all__ = ["setcachesize", "gettz", "rebuild"] 31 | 32 | -CACHE = [] 33 | -CACHESIZE = 10 34 | - 35 | -class tzfile(tzfile): 36 | - def __reduce__(self): 37 | - return (gettz, (self._filename,)) 38 | - 39 | -def getzoneinfofile(): 40 | - filenames = os.listdir(os.path.join(os.path.dirname(__file__))) 41 | - filenames.sort() 42 | - filenames.reverse() 43 | - for entry in filenames: 44 | - if entry.startswith("zoneinfo") and ".tar." in entry: 45 | - return os.path.join(os.path.dirname(__file__), entry) 46 | - return None 47 | - 48 | -ZONEINFOFILE = getzoneinfofile() 49 | - 50 | -del getzoneinfofile 51 | - 52 | def setcachesize(size): 53 | - global CACHESIZE, CACHE 54 | - CACHESIZE = size 55 | - del CACHE[size:] 56 | + pass 57 | 58 | def gettz(name): 59 | - tzinfo = None 60 | - if ZONEINFOFILE: 61 | - for cachedname, tzinfo in CACHE: 62 | - if cachedname == name: 63 | - break 64 | - else: 65 | - tf = TarFile.open(ZONEINFOFILE) 66 | - try: 67 | - zonefile = tf.extractfile(name) 68 | - except KeyError: 69 | - tzinfo = None 70 | - else: 71 | - tzinfo = tzfile(zonefile) 72 | - tf.close() 73 | - CACHE.insert(0, (name, tzinfo)) 74 | - del CACHE[CACHESIZE:] 75 | - return tzinfo 76 | + from dateutil.tz import gettz 77 | + return gettz(name) 78 | 79 | def rebuild(filename, tag=None, format="gz"): 80 | import tempfile, shutil 81 | diff -up python-dateutil-1.4.1/MANIFEST.in.remove-embedded-timezone-data python-dateutil-1.4.1/MANIFEST.in 82 | --- python-dateutil-1.4.1/MANIFEST.in.remove-embedded-timezone-data 2010-07-13 14:42:07.974118722 -0400 83 | +++ python-dateutil-1.4.1/MANIFEST.in 2010-07-13 14:42:14.409994960 -0400 84 | @@ -1,4 +1,4 @@ 85 | -recursive-include dateutil *.py *.tar.* 86 | +recursive-include dateutil *.py 87 | recursive-include sandbox *.py 88 | include setup.py setup.cfg MANIFEST.in README LICENSE NEWS Makefile 89 | include test.py example.py 90 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # barman - Backup and Recovery Manager for PostgreSQL 4 | # 5 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | """Backup and Recovery Manager for PostgreSQL 21 | 22 | Barman (Backup and Recovery Manager) is an open-source administration 23 | tool for disaster recovery of PostgreSQL servers written in Python. 24 | It allows your organisation to perform remote backups of multiple 25 | servers in business critical environments to reduce risk and help DBAs 26 | during the recovery phase. 27 | 28 | Barman is distributed under GNU GPL 3 and maintained by 2ndQuadrant. 29 | """ 30 | 31 | import sys 32 | 33 | try: 34 | from setuptools import setup 35 | except ImportError: 36 | from distutils.core import setup 37 | 38 | if sys.version_info < (2, 6): 39 | raise SystemExit('ERROR: Barman needs at least python 2.6 to work') 40 | 41 | # Depend on pytest_runner only when the tests are actually invoked 42 | needs_pytest = set(['pytest', 'test']).intersection(sys.argv) 43 | pytest_runner = ['pytest_runner'] if needs_pytest else [] 44 | 45 | setup_requires = pytest_runner 46 | 47 | install_requires = [ 48 | 'psycopg2 >= 2.4.2', 49 | 'argh >= 0.21.2, <= 0.26.2', 50 | 'python-dateutil', 51 | 'argcomplete', 52 | ] 53 | 54 | if sys.version_info < (2, 7): 55 | install_requires += [ 56 | 'argparse', 57 | ] 58 | 59 | if sys.version_info < (3, 3): 60 | install_requires.append('backports.lzma') 61 | 62 | barman = {} 63 | with open('barman/version.py', 'r') as fversion: 64 | exec(fversion.read(), barman) 65 | 66 | setup( 67 | name='barman', 68 | version=barman['__version__'], 69 | author='2ndQuadrant Italia Srl', 70 | author_email='info@2ndquadrant.it', 71 | url='http://www.pgbarman.org/', 72 | packages=['barman', ], 73 | scripts=['bin/barman', 'bin/barman-incr'], 74 | data_files=[ 75 | ('share/man/man1', ['doc/barman.1']), 76 | ('share/man/man5', ['doc/barman.5']), 77 | ], 78 | license='GPL-3.0', 79 | description=__doc__.split("\n")[0], 80 | long_description="\n".join(__doc__.split("\n")[2:]), 81 | install_requires=install_requires, 82 | platforms=['Linux', 'Mac OS X'], 83 | classifiers=[ 84 | 'Environment :: Console', 85 | 'Development Status :: 5 - Production/Stable', 86 | 'Topic :: System :: Archiving :: Backup', 87 | 'Topic :: Database', 88 | 'Topic :: System :: Recovery Tools', 89 | 'Intended Audience :: System Administrators', 90 | 'License :: OSI Approved :: GNU General Public License v3 or later ' 91 | '(GPLv3+)', 92 | 'Programming Language :: Python', 93 | 'Programming Language :: Python :: 2.6', 94 | 'Programming Language :: Python :: 2.7', 95 | 'Programming Language :: Python :: 3.3', 96 | 'Programming Language :: Python :: 3.4', 97 | 'Programming Language :: Python :: 3.5', 98 | ], 99 | setup_requires=setup_requires, 100 | tests_require=[ 101 | 'mock', 102 | 'pytest-catchlog>=1.2.1', 103 | 'pytest-timeout', 104 | 'pytest', 105 | ], 106 | ) 107 | -------------------------------------------------------------------------------- /doc/barman.conf: -------------------------------------------------------------------------------- 1 | ; Barman, Backup and Recovery Manager for PostgreSQL 2 | ; http://www.pgbarman.org/ - http://www.2ndQuadrant.com/ 3 | ; 4 | ; Main configuration file 5 | 6 | [barman] 7 | ; System user 8 | barman_user = barman 9 | 10 | ; Directory of configuration files. Place your sections in separate files with .conf extension 11 | ; For example place the 'main' server section in /etc/barman.d/main.conf 12 | configuration_files_directory = /etc/barman.d 13 | 14 | ; Main directory 15 | barman_home = /var/lib/barman 16 | 17 | ; Locks directory - default: %(barman_home)s 18 | ;barman_lock_directory = /var/run/barman 19 | 20 | ; Log location 21 | log_file = /var/log/barman/barman.log 22 | 23 | ; Log level (see https://docs.python.org/3/library/logging.html#levels) 24 | log_level = INFO 25 | 26 | ; Default compression level: possible values are None (default), bzip2, gzip, pigz, pygzip or pybzip2 27 | ;compression = gzip 28 | 29 | ; Pre/post backup hook scripts 30 | ;pre_backup_script = env | grep ^BARMAN 31 | ;pre_backup_retry_script = env | grep ^BARMAN 32 | ;post_backup_retry_script = env | grep ^BARMAN 33 | ;post_backup_script = env | grep ^BARMAN 34 | 35 | ; Pre/post archive hook scripts 36 | ;pre_archive_script = env | grep ^BARMAN 37 | ;pre_archive_retry_script = env | grep ^BARMAN 38 | ;post_archive_retry_script = env | grep ^BARMAN 39 | ;post_archive_script = env | grep ^BARMAN 40 | 41 | ; Global retention policy (REDUNDANCY or RECOVERY WINDOW) - default empty 42 | ;retention_policy = 43 | 44 | ; Global bandwidth limit in KBPS - default 0 (meaning no limit) 45 | ;bandwidth_limit = 4000 46 | 47 | ; Immediate checkpoint for backup command - default false 48 | ;immediate_checkpoint = false 49 | 50 | ; Enable network compression for data transfers - default false 51 | ;network_compression = false 52 | 53 | ; Number of retries of data copy during base backup after an error - default 0 54 | ;basebackup_retry_times = 0 55 | 56 | ; Number of seconds of wait after a failed copy, before retrying - default 30 57 | ;basebackup_retry_sleep = 30 58 | 59 | ; Maximum execution time, in seconds, per server 60 | ; for a barman check command - default 30 61 | ;check_timeout = 30 62 | 63 | ; Time frame that must contain the latest backup date. 64 | ; If the latest backup is older than the time frame, barman check 65 | ; command will report an error to the user. 66 | ; If empty, the latest backup is always considered valid. 67 | ; Syntax for this option is: "i (DAYS | WEEKS | MONTHS)" where i is an 68 | ; integer > 0 which identifies the number of days | weeks | months of 69 | ; validity of the latest backup for this check. Also known as 'smelly backup'. 70 | ;last_backup_maximum_age = 71 | 72 | ; Minimum number of required backups (redundancy) 73 | ;minimum_redundancy = 1 74 | 75 | ; Examples of retention policies 76 | ; Retention policy (disabled) 77 | ;retention_policy = 78 | ; Retention policy (based on redundancy) 79 | ;retention_policy = REDUNDANCY 2 80 | ; Retention policy (based on recovery window) 81 | ;retention_policy = RECOVERY WINDOW OF 4 WEEKS 82 | ;; 83 | ;; ; Page-level incremental backups 84 | ;; ; Allow sequences of incremental backups (set to "full" to disable) 85 | ;; incr_allow_root = incr 86 | ;; 87 | ;; ; Compress backups with lzma -9 (gzip, bzip and none are also supported) 88 | ;; ; You could set compression level like this: - 89 | ;; ; Default level is 6 90 | ;; incr_compress = lzma-9 91 | ;; 92 | ;; ; Barman server hostname (socket.getfqdn() call result used by default) 93 | ;; incr_host = barman.example.com 94 | ;; 95 | ;; ; Max number of increments before taking full (6 - take full every week) 96 | ;; incr_max_increments = 6 97 | ;; 98 | ;; ; Number of workers for incr backup 99 | ;; incr_parallel = 1 100 | ;; 101 | ;; ; Pass additional options to rsync 102 | ;; incr_rsync_options = -a 103 | ;; 104 | ;; ; Pass relative path to barman-incr 105 | ;; ; If you announced /var/lib/barman via rsync as barman you need to set: 106 | ;; incr_rsync_relpath = /var/lib 107 | ;; 108 | ;; ; Pass extra args to barman-incr 109 | ;; incr_extra_args = -vvv 110 | -------------------------------------------------------------------------------- /doc/manual/01-intro.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Introduction 4 | 5 | In a perfect world, there would be no need for a backup. However, it is 6 | important, especially in business environments, to be prepared for 7 | when the _"unexpected"_ happens. In a database scenario, the 8 | unexpected could take any of the following forms: 9 | 10 | - data corruption 11 | - system failure (including hardware failure) 12 | - human error 13 | - natural disaster 14 | 15 | In such cases, any ICT manager or DBA should be able to fix the 16 | incident and recover the database in the shortest time possible. We 17 | normally refer to this discipline as **disaster recovery**, and more 18 | broadly *business continuity*. 19 | 20 | Within business continuity, it is important to familiarise with two fundamental metrics, as defined by Wikipedia: 21 | 22 | - [**Recovery Point Objective (RPO)**] [rpo]: _"maximum targeted period in which data might be lost from an IT service due to a major incident"_ 23 | - [**Recovery Time Objective (RTO)**] [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 break in business continuity"_ 24 | 25 | 26 | 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. 27 | 28 | Understandably, we all want **RPO=0** (*"zero data loss"*) and **RTO=0** (*zero down-time*, utopia) - even if it is our grandmothers's recipe website. 29 | In reality, a careful cost analysis phase allows you to determine your business continuity requirements. 30 | 31 | Fortunately, with an open source stack composed of **Barman** and **PostgreSQL**, you can achieve RPO=0 thanks to synchronous streaming replication. RTO is more the focus of a *High Availability* solution, like [**repmgr**] [repmgr]. Therefore, by integrating Barman and repmgr, you can dramatically reduce RTO to nearly zero. 32 | 33 | Based on our experience at 2ndQuadrant, we can confirm that PostgreSQL open source clusters with Barman and repmgr can easily achieve more than 99.99% uptime over a year, if properly configured and monitored. 34 | 35 | In any case, it is important for us to emphasise more on cultural aspects related to disaster recovery, rather than the actual tools. Tools without human beings are useless. 36 | 37 | Our mission with Barman is to promote a culture of disaster recovery that: 38 | 39 | - focuses on backup procedures 40 | - focuses even more on recovery procedures 41 | - relies on education and training on strong theoretical and practical concepts of PostgreSQL's crash recovery, backup, Point-In-Time-Recovery, and replication for your team members 42 | - 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!) 43 | - fosters regular practice of recovery procedures, by all members of your devops team (yes, developers too, not just system administrators and DBAs) 44 | - solicites to regularly scheduled drills and disaster recovery simulations with the team every 3-6 months 45 | - relies on continuous monitoring of PostgreSQL and Barman, and that is able to promptly identify any anomalies 46 | 47 | Moreover, do everything you can to prepare yourself and your team for when the disaster happens (yes, *when*), because when it happens: 48 | 49 | - It is going to be a Friday evening, most likely right when you are about to leave the office. 50 | - 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. 51 | - It is certainly going to be stressful. 52 | - You will regret not being sure that the last available backup is valid. 53 | - Unless you know how long it approximately takes to recover, every second will seems like forever. 54 | 55 | Be prepared, don't be scared. 56 | 57 | In 2011, with these goals in mind, 2ndQuadrant started the development of 58 | Barman, now one of the most used backup tools for PostgreSQL. Barman is an acronym for "Backup and Recovery Manager". 59 | 60 | Currently, Barman works only on Linux and Unix operating systems. 61 | -------------------------------------------------------------------------------- /doc/manual/66-about.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # The Barman project 4 | 5 | ## Support and sponsor opportunities 6 | 7 | Barman is free software, written and maintained by 2ndQuadrant. If you 8 | require support on using Barman, or if you need new features, please 9 | get in touch with 2ndQuadrant. You can sponsor the development of new 10 | features of Barman and PostgreSQL which will be made publicly 11 | available as open source. 12 | 13 | For further information, please visit: 14 | 15 | - [Barman website] [11] 16 | - [Support section] [12] 17 | - [2ndQuadrant website] [13] 18 | - [Barman FAQs] [14] 19 | - [2ndQuadrant blog: Barman] [15] 20 | 21 | ## Contributing to Barman 22 | 23 | 2ndQuadrant has a team of software engineers, architects, database 24 | administrators, system administrators, QA engineers, developers and 25 | managers that dedicate their time and expertise to improve Barman's code. 26 | We adopt lean and agile methodologies for software development, and 27 | we believe in the _devops_ culture that allowed us to implement rigorous 28 | testing procedures through cross-functional collaboration. 29 | Every Barman commit is the contribution of multiple individuals, at different 30 | stages of the production pipeline. 31 | 32 | Even though this is our preferred way of developing Barman, we gladly 33 | accept patches from external developers, as long as: 34 | 35 | - user documentation (tutorial and man pages) is provided. 36 | - source code is properly documented and contains relevant comments. 37 | - code supplied is covered by unit tests. 38 | - no unrelated feature is compromised or broken. 39 | - source code is rebased on the current master branch. 40 | - commits and pull requests are limited to a single feature (multi-feature 41 | patches are hard to test and review). 42 | - changes to the user interface are discussed beforehand with 2ndQuadrant. 43 | 44 | We also require that any contributions provide a copyright assignment 45 | and a disclaimer of any work-for-hire ownership claims from the employer 46 | of the developer. 47 | 48 | You can use Github's pull requests system for this purpose. 49 | 50 | ## Authors 51 | 52 | In alphabetical order: 53 | 54 | - Gabriele Bartolini, (project leader) 55 | - Jonathan Battiato, (QA/testing) 56 | - Stefano Bianucci, (developer, intern from University of Florence) 57 | - Giuseppe Broccolo, (QA/testing) 58 | - Giulio Calacoci, (developer) 59 | - Francesco Canovai, (QA/testing) 60 | - Leonardo Cecchi, (developer) 61 | - Gianni Ciolli, (QA/testing) 62 | - Britt Cole, (documentation) 63 | - Marco Nenciarini, (lead developer) 64 | - Rubens Souza, (QA/testing) 65 | 66 | Past contributors: 67 | 68 | - Carlo Ascani 69 | 70 | ## Links 71 | 72 | - [check-barman] [16]: a Nagios plugin for Barman, written by Holger 73 | Hamann (MIT license) 74 | - [puppet-barman] [17]: Barman module for Puppet (GPL) 75 | - [Tutorial on "How To Back Up, Restore, and Migrate PostgreSQL Databases with Barman on CentOS 7"] [26], by Sadequl Hussain (available on DigitalOcean Community) 76 | - [BarmanAPI] [27]: RESTFul API for Barman, written by Mehmet Emin Karakaş (GPL) 77 | 78 | ## License and Contributions 79 | 80 | Barman is the property of 2ndQuadrant Italia and its code is 81 | distributed under GNU General Public License 3. 82 | 83 | Copyright (C) 2011-2016 [2ndQuadrant.it S.r.l.] [19]. 84 | 85 | Barman has been partially funded through [4CaaSt] [18], a research 86 | project funded by the European Commission's Seventh Framework 87 | programme. 88 | 89 | Contributions to Barman are welcome, and will be listed in the 90 | `AUTHORS` file. 2ndQuadrant Italia requires that any contributions 91 | provide a copyright assignment and a disclaimer of any work-for-hire 92 | ownership claims from the employer of the developer. This lets us make 93 | sure that all of the Barman distribution remains free code. Please 94 | contact info@2ndQuadrant.it for a copy of the relevant Copyright 95 | Assignment Form. 96 | -------------------------------------------------------------------------------- /doc/manual/23-wal_streaming.en.md: -------------------------------------------------------------------------------- 1 | ## WAL streaming 2 | 3 | Barman can reduce the Recovery Point Objective (RPO) by allowing users 4 | to add continuous WAL streaming from a PostgreSQL server, on top of 5 | the standard `archive_command` strategy 6 | 7 | Barman relies on [`pg_receivexlog`] [25], a utility that has been 8 | available from PostgreSQL 9.2 which exploits the native streaming 9 | replication protocol and continuously receives transaction logs from a 10 | PostgreSQL server (master or standby). 11 | 12 | > **IMPORTANT:** 13 | > Barman requires that `pg_receivexlog` is installed on the same 14 | > server. For PostgreSQL 9.2 servers, you need `pg_receivexlog` of 15 | > version 9.2 installed alongside Barman. For PostgreSQL 9.3 and 16 | > above, it is recommended to install the latest available version of 17 | > `pg_receivexlog`, as it is back compatible. Otherwise, users can 18 | > install multiple versions of `pg_receivexlog` on the Barman server 19 | > and properly point to the specific version for a server, using the 20 | > `path_prefix` option in the configuration file. 21 | 22 | In order to enable streaming of transaction logs, you need to: 23 | 24 | 1. setup a streaming connection as previously described 25 | 2. set the `streaming_archiver` option to `on` 26 | 27 | The `cron` command, if the aforementioned requirements are met, 28 | transparently manages log streaming through the execution of the 29 | `receive-wal` command. This is the recommended scenario. 30 | 31 | However, users can manually execute the `receive-wal` command: 32 | 33 | ``` bash 34 | barman receive-wal 35 | ``` 36 | 37 | > **NOTE:** 38 | > The `receive-wal` command is a foreground process. 39 | 40 | Transaction logs are streamed directly in the directory specified by the 41 | `streaming_wals_directory` configuration option and are then archived 42 | by the `archive-wal` command. 43 | 44 | Unless otherwise specified in the `streaming_archiver_name` parameter, 45 | and only for PostgreSQL 9.3 or above, Barman will set `application_name` 46 | of the WAL streamer process to `barman_receive_wal`, allowing you to 47 | monitor its status in the `pg_stat_replication` system view of the 48 | PostgreSQL server. 49 | 50 | 51 | ### Replication slots 52 | 53 | > **IMPORTANT:** replication slots are available since PostgreSQL 9.4 54 | 55 | Replication slots are an automated way to ensure that the PostgreSQL 56 | server will not remove WAL files until they were received by all 57 | archivers. Barman uses this mechanism to receive the transaction logs 58 | from PostgreSQL. 59 | 60 | You can find more information about replication slots in the 61 | [PostgreSQL manual][replication-slots]. 62 | 63 | You can even base your backup architecture on streaming connection 64 | only. This scenario is useful to configure Docker-based PostgreSQL 65 | servers and even to work with PostgreSQL servers running on Windows. 66 | 67 | > **IMPORTANT:** 68 | > In this moment, the Windows support is still experimental, as it is 69 | > not yet part of our continuous integration system. 70 | 71 | 72 | ### How to configure the WAL streaming 73 | 74 | First, the PostgreSQL server must be configured to stream the 75 | transaction log files to the Barman server. 76 | 77 | To configure the streaming connection from Barman to the PostgreSQL 78 | server you need to enable the `streaming_archiver`, as already said, 79 | including this line in the server configuration file: 80 | 81 | ``` ini 82 | streaming_archiver = on 83 | ``` 84 | 85 | If you plan to use replication slots (recommended), 86 | another essential option for the setup of the streaming-based 87 | transaction log archiving is the `slot_name` option: 88 | 89 | ``` ini 90 | slot_name = barman 91 | ``` 92 | 93 | This option defines the name of the replication slot that will be 94 | used by Barman. It is mandatory if you want to use replication slots. 95 | 96 | When you configure the replication slot name, you can create a 97 | replication slot for Barman with this command: 98 | 99 | ``` bash 100 | barman@backup$ barman receive-wal --create-slot pg 101 | Creating physical replication slot 'barman' on server 'pg' 102 | Replication slot 'barman' created 103 | ``` 104 | 105 | -------------------------------------------------------------------------------- /sphinx/generate_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 4 | # 5 | # This file is part of Barman. 6 | # 7 | # Barman is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # Barman is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Barman. If not, see . 19 | 20 | BASEDIR=$(cd ${0%/*}; pwd ) 21 | 22 | # modify GEN_MODE. It must be passed like parameter value 23 | GEN_MODE='html' 24 | 25 | function die() 26 | { 27 | echo $@ 28 | exit 1 29 | } 30 | 31 | function usage() 32 | { 33 | echo "Usage: $0 [-h] [-t TARGET] DIR" 34 | echo 35 | echo "use -h for extended help" 36 | echo 37 | exit 1 38 | } 39 | 40 | function showhelp() 41 | { 42 | echo "$0 [-h] [-t TARGET] DIR" 43 | echo 44 | echo "DIR is the source directory of the barman files" 45 | echo 46 | echo " -h Show this help message" 47 | echo " -t TARGET Generate documentation using a specific " 48 | echo " target format (default: HTML)" 49 | echo 50 | echo "List of available target formats:" 51 | echo " html to make standalone HTML files" 52 | echo " dirhtml to make HTML files named index.html in directories" 53 | echo " singlehtml to make a single large HTML file" 54 | echo " pickle to make pickle files" 55 | echo " json to make JSON files" 56 | echo " htmlhelp to make HTML files and a HTML help project" 57 | echo " qthelp to make HTML files and a qthelp project" 58 | echo " devhelp to make HTML files and a Devhelp project" 59 | echo " epub to make an epub" 60 | echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 61 | echo " latexpdf to make LaTeX files and run them through pdflatex" 62 | echo " text to make text files" 63 | echo " man to make manual pages" 64 | echo " texinfo to make Texinfo files" 65 | echo " info to make Texinfo files and run them through makeinfo" 66 | echo " gettext to make PO message catalogs" 67 | echo " changes to make an overview of all changed/added/deprecated items" 68 | echo " linkcheck to check all external links for integrity" 69 | echo " doctest to run all doctests embedded in the documentation (if enabled)" 70 | echo 71 | } 72 | 73 | RED='\033[1;31m' 74 | RSET='\033[0m' 75 | 76 | function red() 77 | { 78 | printf "${RED}${1}${RSET}\n" 79 | } 80 | 81 | 82 | # if -h is the parameter it shows help 83 | # if -t expect for a target 84 | while getopts ht: OPT; 85 | do 86 | case "$OPT" in 87 | t) 88 | GEN_MODE=${OPTARG}; shift 2;; 89 | --) 90 | shift; break;; 91 | h|*) 92 | showhelp; exit 1;; 93 | esac 94 | shift; 95 | done 96 | 97 | if [[ $# -gt 2 ]] 98 | then 99 | showhelp 100 | exit 1 101 | fi 102 | 103 | if [[ $# -eq 0 ]] ; then 104 | BARMAN_DIR=$(cd "$BASEDIR/.."; pwd) 105 | else 106 | BARMAN_DIR=$(cd "$1"; pwd) 107 | fi 108 | 109 | [[ "${BARMAN_DIR}" = "." ]] && die 'Input directory . is not supported!' 110 | [[ ! -d "${BARMAN_DIR}" ]] && die 'Input directory does not exists!' 111 | 112 | export BARMAN_DIR 113 | cd "${BASEDIR}" 114 | 115 | # Cleans the build directory 116 | red "Cleaning the Build directory..." 117 | make clean 118 | 119 | red "Removing all generated files..." 120 | ls "${BASEDIR}"/docs/*.rst | grep -v 'index.rst$' | xargs -trI X rm -f X 121 | 122 | # Generates automatically modules doc 123 | red "Generating documentation from modules..." 124 | sphinx-apidoc -P -e -T -M -o docs "${BARMAN_DIR}" 125 | # Invokes html generation 126 | red "Generating ${GEN_MODE}" 127 | make ${GEN_MODE} 128 | 129 | red "DONE!!" 130 | -------------------------------------------------------------------------------- /rpm/rhel5/python26-dateutil.spec: -------------------------------------------------------------------------------- 1 | # Use Python 2.6 2 | %global pybasever 2.6 3 | %global __python_ver 26 4 | %global __python %{_bindir}/python%{pybasever} 5 | %global __os_install_post %{__multiple_python_os_install_post} 6 | 7 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 8 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 9 | 10 | Name: python%{__python_ver}-dateutil 11 | Version: 1.4.1 12 | Release: 6%{?dist} 13 | Summary: Powerful extensions to the standard datetime module 14 | 15 | Group: Development/Languages 16 | License: Python 17 | URL: http://labix.org/python-dateutil 18 | Source0: http://labix.org/download/python-dateutil/python-dateutil-%{version}.tar.gz 19 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 20 | 21 | # Redirect the exposed parts of the dateutil.zoneinfo API to remove references 22 | # to the embedded copy of zoneinfo-2008e.tar.gz and instead use the system 23 | # data from the "tzdata" package (rhbz#559309): 24 | Patch0: python-dateutil-1.4.1-remove-embedded-timezone-data.patch 25 | 26 | BuildArch: noarch 27 | BuildRequires: python%{__python_ver}-devel,python%{__python_ver}-setuptools 28 | 29 | Requires: tzdata 30 | 31 | %description 32 | The dateutil module provides powerful extensions to the standard datetime 33 | module available in Python 2.3+. 34 | 35 | %prep 36 | %setup -n python-dateutil-%{version} -q 37 | 38 | # Remove embedded copy of timezone data: 39 | %patch0 -p1 40 | rm dateutil/zoneinfo/zoneinfo-2008e.tar.gz 41 | 42 | # Change encoding of NEWS file to UTF-8, preserving timestamp: 43 | iconv -f ISO-8859-1 -t utf8 NEWS > NEWS.utf8 && \ 44 | touch -r NEWS NEWS.utf8 && \ 45 | mv NEWS.utf8 NEWS 46 | 47 | %build 48 | %{__python} setup.py build 49 | 50 | 51 | %install 52 | rm -rf $RPM_BUILD_ROOT 53 | %{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT 54 | 55 | 56 | %clean 57 | rm -rf $RPM_BUILD_ROOT 58 | 59 | %check 60 | %{__python} test.py 61 | 62 | %files 63 | %defattr(-,root,root,-) 64 | %doc example.py LICENSE NEWS README 65 | %{python_sitelib}/dateutil/ 66 | %{python_sitelib}/*.egg-info 67 | 68 | %changelog 69 | * Tue Jul 13 2010 David Malcolm - 1.4.1-6 70 | - remove embedded copy of timezone data, and redirect the dateutil.zoneinfo 71 | API accordingly 72 | Resolves: rhbz#559309 73 | - add a %%check, running the upstream selftest suite 74 | 75 | * Tue Jul 13 2010 David Malcolm - 1.4.1-5 76 | - add requirement on tzdata 77 | Resolves: rhbz#559309 78 | - fix encoding of the NEWS file 79 | 80 | * Mon Nov 30 2009 Dennis Gregorovic - 1.4.1-4.1 81 | - Rebuilt for RHEL 6 82 | 83 | * Sun Jul 26 2009 Fedora Release Engineering - 1.4.1-4 84 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild 85 | 86 | * Thu Feb 26 2009 Fedora Release Engineering - 1.4.1-3 87 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild 88 | 89 | * Fri Feb 20 2009 Jef Spaleta - 1.4.1-2 90 | - small specfile fix 91 | 92 | * Fri Feb 20 2009 Jef Spaleta - 1.4.1-2 93 | - New upstream version 94 | 95 | * Sat Nov 29 2008 Ignacio Vazquez-Abrams - 1.4-3 96 | - Rebuild for Python 2.6 97 | 98 | * Fri Aug 29 2008 Tom "spot" Callaway - 1.4-2 99 | - fix license tag 100 | 101 | * Tue Jul 01 2008 Jef Spaleta 1.4-1 102 | - Latest upstream release 103 | 104 | * Fri Jan 04 2008 Jef Spaleta 1.2-2 105 | - Fix for egg-info file creation 106 | 107 | * Thu Jun 28 2007 Orion Poplawski 1.2-1 108 | - Update to 1.2 109 | 110 | * Mon Dec 11 2006 Jef Spaleta 1.1-5 111 | - Fix python-devel BR, as per discussion in maintainers-list 112 | 113 | * Mon Dec 11 2006 Jef Spaleta 1.1-4 114 | - Release bump for rebuild against python 2.5 in devel tree 115 | 116 | * Wed Jul 26 2006 Orion Poplawski 1.1-3 117 | - Add patch to fix building on x86_64 118 | 119 | * Wed Feb 15 2006 Orion Poplawski 1.1-2 120 | - Rebuild for gcc/glibc changes 121 | 122 | * Thu Dec 22 2005 Orion Poplawski 1.1-1 123 | - Update to 1.1 124 | 125 | * Thu Jul 28 2005 Orion Poplawski 1.0-1 126 | - Update to 1.0 127 | 128 | * Tue Jul 05 2005 Orion Poplawski 0.9-1 129 | - Initial Fedora Extras package 130 | -------------------------------------------------------------------------------- /scripts/gitlog-to-changelog: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Convert git log output to ChangeLog format. 3 | 4 | my $VERSION = '2010-10-28 09:48'; # UTC 5 | # The definition above must lie within the first 8 lines in order 6 | # for the Emacs time-stamp write hook (at end) to update it. 7 | # If you change this file with Emacs, please let the write hook 8 | # do its job. Otherwise, update this string manually. 9 | 10 | # Copyright (C) 2008 Free Software Foundation, Inc. 11 | 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | # Written by Jim Meyering 26 | 27 | use strict; 28 | use warnings; 29 | use Getopt::Long; 30 | use POSIX qw(strftime); 31 | 32 | (my $ME = $0) =~ s|.*/||; 33 | 34 | # use File::Coda; # http://meyering.net/code/Coda/ 35 | END { 36 | defined fileno STDOUT or return; 37 | close STDOUT and return; 38 | warn "$ME: failed to close standard output: $!\n"; 39 | $? ||= 1; 40 | } 41 | 42 | sub usage ($) 43 | { 44 | my ($exit_code) = @_; 45 | my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); 46 | if ($exit_code != 0) 47 | { 48 | print $STREAM "Try `$ME --help' for more information.\n"; 49 | } 50 | else 51 | { 52 | print $STREAM < ChangeLog 68 | 69 | EOF 70 | } 71 | exit $exit_code; 72 | } 73 | 74 | # If the string $S is a well-behaved file name, simply return it. 75 | # If it contains white space, quotes, etc., quote it, and return the new tring. 76 | sub shell_quote($) 77 | { 78 | my ($s) = @_; 79 | if ($s =~ m![^\w+/.,-]!) 80 | { 81 | # Convert each single quote to '\'' 82 | $s =~ s/\'/\'\\\'\'/g; 83 | # Then single quote the string. 84 | $s = "'$s'"; 85 | } 86 | return $s; 87 | } 88 | 89 | sub quoted_cmd(@) 90 | { 91 | return join (' ', map {shell_quote $_} @_); 92 | } 93 | 94 | { 95 | my $since_date = '1970-01-01 UTC'; 96 | GetOptions 97 | ( 98 | help => sub { usage 0 }, 99 | version => sub { print "$ME version $VERSION\n"; exit }, 100 | 'since=s' => \$since_date, 101 | ) or usage 1; 102 | 103 | @ARGV 104 | and (warn "$ME: too many arguments\n"), usage 1; 105 | 106 | my @cmd = (qw (git log --log-size), "--since=$since_date", 107 | '--pretty=format:%at %an <%ae>%n%n%s%n%b%n'); 108 | open PIPE, '-|', @cmd 109 | or die "$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n"; 110 | 111 | my $prev_date_line = ''; 112 | while (1) 113 | { 114 | defined (my $in = ) 115 | or last; 116 | $in =~ /^log size (\d+)$/ 117 | or die "$ME:$.: Invalid line (expected log size):\n$in"; 118 | my $log_nbytes = $1; 119 | 120 | my $log; 121 | my $n_read = read PIPE, $log, $log_nbytes; 122 | $n_read == $log_nbytes 123 | or die "$ME:$.: unexpected EOF\n"; 124 | 125 | my @line = split "\n", $log; 126 | my $author_line = shift @line; 127 | defined $author_line 128 | or die "$ME:$.: unexpected EOF\n"; 129 | $author_line =~ /^(\d+) (.*>)$/ 130 | or die "$ME:$.: Invalid line " 131 | . "(expected date/author/email):\n$author_line\n"; 132 | 133 | my $date_line = sprintf "%s $2\n", strftime ("%F", localtime ($1)); 134 | # If this line would be the same as the previous date/name/email 135 | # line, then arrange not to print it. 136 | if ($date_line ne $prev_date_line) 137 | { 138 | $prev_date_line eq '' 139 | or print "\n"; 140 | print $date_line; 141 | } 142 | $prev_date_line = $date_line; 143 | 144 | # Omit "Signed-off-by..." lines. 145 | @line = grep !/^Signed-off-by: .*>$/, @line; 146 | 147 | # Remove leading and trailing blank lines. 148 | while ($line[0] =~ /^\s*$/) { shift @line; } 149 | while ($line[$#line] =~ /^\s*$/) { pop @line; } 150 | 151 | # Prefix each non-empty line with a TAB. 152 | @line = map { length $_ ? "\t$_" : '' } @line; 153 | 154 | print "\n", join ("\n", @line), "\n"; 155 | 156 | defined ($in = ) 157 | or last; 158 | $in ne "\n" 159 | and die "$ME:$.: unexpected line:\n$in"; 160 | } 161 | 162 | close PIPE 163 | or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n"; 164 | # FIXME-someday: include $PROCESS_STATUS in the diagnostic 165 | } 166 | 167 | # Local Variables: 168 | # indent-tabs-mode: nil 169 | # eval: (add-hook 'write-file-hooks 'time-stamp) 170 | # time-stamp-start: "my $VERSION = '" 171 | # time-stamp-format: "%:y-%02m-%02d %02H:%02M" 172 | # time-stamp-time-zone: "UTC" 173 | # time-stamp-end: "'; # UTC" 174 | # End: 175 | 176 | -------------------------------------------------------------------------------- /rpm/barman.spec: -------------------------------------------------------------------------------- 1 | %if 0%{?rhel} == 7 2 | %global pybasever 2.7 3 | %else 4 | %if 0%{?fedora}>=21 5 | %global pybasever 2.7 6 | %else 7 | %global pybasever 2.6 8 | %endif 9 | %endif 10 | 11 | %if 0%{?rhel} == 5 12 | %global with_python26 1 13 | %endif 14 | 15 | %if 0%{?with_python26} 16 | %global __python_ver python26 17 | %global __python %{_bindir}/python%{pybasever} 18 | %global __os_install_post %{__multiple_python_os_install_post} 19 | %else 20 | %global __python_ver python 21 | %endif 22 | 23 | %global main_version 2.2 24 | # comment out the next line if not a pre-release (use '#%%global ...') 25 | %global extra_version a1 26 | # Usually 1 - unique sequence for all pre-release version 27 | %global package_release 1 28 | 29 | %{!?pybasever: %define pybasever %(%{__python} -c "import sys;print(sys.version[0:3])")} 30 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 31 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 32 | 33 | Summary: Backup and Recovery Manager for PostgreSQL 34 | Name: barman 35 | Version: %{main_version} 36 | Release: %{?extra_version:0.}%{package_release}%{?extra_version:.%{extra_version}}%{?dist} 37 | License: GPLv3 38 | Group: Applications/Databases 39 | Url: http://www.pgbarman.org/ 40 | Source0: %{name}-%{version}%{?extra_version:%{extra_version}}.tar.gz 41 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 42 | BuildArch: noarch 43 | Vendor: 2ndQuadrant Italia Srl 44 | Requires: python-abi = %{pybasever}, %{__python_ver}-psycopg2 >= 2.4.2, %{__python_ver}-argh >= 0.21.2, %{__python_ver}-argcomplete, %{__python_ver}-dateutil 45 | Requires: /usr/sbin/useradd 46 | Requires: rsync >= 3.0.4 47 | Requires: barman-incr >= %{main_version} 48 | 49 | %package incr 50 | Summary: Helper for incremental backup with barman 51 | Requires: python-abi = %{pybasever}, %{__python_ver}-backports-lzma, %{__python_ver}-msgpack >= 0.4.6 52 | %if 0%{?rhel} == 5 53 | Requires: %{__python_ver}-argparse 54 | %endif 55 | Requires: rsync >= 3.0.4 56 | 57 | %description 58 | Barman (Backup and Recovery Manager) is an open-source 59 | administration tool for disaster recovery of PostgreSQL 60 | servers written in Python. 61 | It allows your organisation to perform remote backups of 62 | multiple servers in business critical environments to 63 | reduce risk and help DBAs during the recovery phase. 64 | 65 | Barman is distributed under GNU GPL 3 and maintained 66 | by 2ndQuadrant. 67 | 68 | %description incr 69 | Barman-incr is simple python tool for incremental backup of PostgreSQL (>= 9.3). 70 | 71 | 72 | %prep 73 | %setup -n barman-%{version}%{?extra_version:%{extra_version}} -q 74 | 75 | %build 76 | %{__python} setup.py build 77 | cat > barman.cron << EOF 78 | # m h dom mon dow user command 79 | * * * * * barman [ -x %{_bindir}/barman ] && %{_bindir}/barman -q cron 80 | EOF 81 | cat > barman.logrotate << EOF 82 | /var/log/barman/barman.log { 83 | missingok 84 | notifempty 85 | create 0600 barman barman 86 | } 87 | EOF 88 | 89 | %install 90 | %{__python} setup.py install -O1 --skip-build --root %{buildroot} 91 | mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d 92 | mkdir -p %{buildroot}%{_sysconfdir}/cron.d/ 93 | mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d/ 94 | mkdir -p %{buildroot}%{_sysconfdir}/barman.d/ 95 | mkdir -p %{buildroot}/var/lib/barman 96 | mkdir -p %{buildroot}/var/log/barman 97 | install -pm 644 doc/barman.conf %{buildroot}%{_sysconfdir}/barman.conf 98 | install -pm 644 doc/barman.d/* %{buildroot}%{_sysconfdir}/barman.d/ 99 | install -pm 644 scripts/barman.bash_completion %{buildroot}%{_sysconfdir}/bash_completion.d/barman 100 | install -pm 644 barman.cron %{buildroot}%{_sysconfdir}/cron.d/barman 101 | install -pm 644 barman.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/barman 102 | touch %{buildroot}/var/log/barman/barman.log 103 | mkdir -p %{buildroot}/usr/bin 104 | install -pm 755 bin/barman-incr %{buildroot}/usr/bin/barman-incr 105 | 106 | %clean 107 | rm -rf %{buildroot} 108 | 109 | %files 110 | %defattr(-,root,root) 111 | %doc INSTALL NEWS README.rst 112 | %{python_sitelib}/%{name}-%{version}%{?extra_version:%{extra_version}}-py%{pybasever}.egg-info 113 | %{python_sitelib}/%{name}/ 114 | %{_bindir}/%{name} 115 | %doc %{_mandir}/man1/%{name}.1.gz 116 | %doc %{_mandir}/man5/%{name}.5.gz 117 | %config(noreplace) %{_sysconfdir}/bash_completion.d/ 118 | %config(noreplace) %{_sysconfdir}/%{name}.conf 119 | %config(noreplace) %{_sysconfdir}/cron.d/%{name} 120 | %config(noreplace) %{_sysconfdir}/logrotate.d/%{name} 121 | %config(noreplace) %{_sysconfdir}/barman.d/ 122 | %attr(700,barman,barman) %dir /var/lib/%{name} 123 | %attr(755,barman,barman) %dir /var/log/%{name} 124 | %attr(600,barman,barman) %ghost /var/log/%{name}/%{name}.log 125 | 126 | %files incr 127 | %attr(755,root,root) /usr/bin/barman-incr 128 | 129 | %pre 130 | groupadd -f -r barman >/dev/null 2>&1 || : 131 | useradd -M -n -g barman -r -d /var/lib/barman -s /bin/bash \ 132 | -c "Backup and Recovery Manager for PostgreSQL" barman >/dev/null 2>&1 || : 133 | 134 | %changelog 135 | * Thu Jan 5 2017 - Giulio Calacoci 2.1-1 136 | - New release 2.1-1 137 | 138 | * Tue Dec 27 2016 - Gabriele Bartolini 2.1-0.1.alpha.1 139 | - New release 2.1-0.1.alpha.1 140 | 141 | * Tue Sep 27 2016 - Gabriele Bartolini 2.0-1 142 | - New release 2.0-1 143 | - Trim changelog for releases 1.X 144 | -------------------------------------------------------------------------------- /tests/test_process.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | import errno 19 | import os 20 | 21 | import mock 22 | 23 | from barman.lockfile import ServerWalReceiveLock 24 | from barman.process import ProcessInfo, ProcessManager 25 | from testing_helpers import build_config_from_dicts 26 | 27 | 28 | # noinspection PyMethodMayBeStatic 29 | class TestProcessInfo(object): 30 | """ 31 | ProcessInfo obj tests 32 | """ 33 | 34 | def test_init(self): 35 | """ 36 | Test the init method 37 | """ 38 | pi = ProcessInfo(pid=12345, 39 | server_name='test_server', 40 | task='test_task') 41 | 42 | assert pi.pid == 12345 43 | assert pi.server_name == 'test_server' 44 | assert pi.task == 'test_task' 45 | 46 | 47 | class TestProcessManager(object): 48 | """ 49 | Simple class for testing the ProcessManager obj 50 | """ 51 | 52 | def test_init(self, tmpdir): 53 | """ 54 | Test the init method 55 | """ 56 | # Build a basic configuration 57 | config = build_config_from_dicts({ 58 | 'barman_lock_directory': tmpdir.strpath}) 59 | config.name = 'main' 60 | # Acquire a lock and initialise the ProjectManager. 61 | # Expect the ProjectManager to Retrieve the 62 | # "Running process" identified by the lock 63 | lock = ServerWalReceiveLock(tmpdir.strpath, 'main') 64 | with lock: 65 | pm = ProcessManager(config) 66 | 67 | # Test for the length of the process list 68 | assert len(pm.process_list) == 1 69 | # Test for the server identifier of the process 70 | assert pm.process_list[0].server_name == 'main' 71 | # Test for the task type 72 | assert pm.process_list[0].task == 'receive-wal' 73 | # Read the pid from the lockfile and test id against the ProcessInfo 74 | # contained in the process_list 75 | with open(lock.filename, 'r') as lockfile: 76 | pid = lockfile.read().strip() 77 | assert int(pid) == pm.process_list[0].pid 78 | 79 | # Test lock file parse error. 80 | # Skip the lock and don't raise any exception. 81 | with lock: 82 | with open(lock.filename, 'w') as lockfile: 83 | lockfile.write("invalid") 84 | pm = ProcessManager(config) 85 | assert len(pm.process_list) == 0 86 | 87 | def test_list(self, tmpdir): 88 | """ 89 | Test the list method from the ProjectManager class 90 | """ 91 | config = build_config_from_dicts({ 92 | 'barman_lock_directory': tmpdir.strpath}) 93 | config.name = 'main' 94 | with ServerWalReceiveLock(tmpdir.strpath, 'main'): 95 | pm = ProcessManager(config) 96 | process = pm.list('receive-wal')[0] 97 | 98 | assert process.server_name == 'main' 99 | assert process.task == 'receive-wal' 100 | with open(os.path.join( 101 | tmpdir.strpath, 102 | '.%s-receive-wal.lock' % config.name)) as lockfile: 103 | pid = lockfile.read().strip() 104 | assert int(pid) == process.pid 105 | 106 | @mock.patch('os.kill') 107 | def test_kill(self, kill_mock, tmpdir): 108 | """ 109 | Test the Kill method from the ProjectManager class. 110 | Mocks the os.kill used inside the the kill method 111 | """ 112 | config = build_config_from_dicts({ 113 | 'barman_lock_directory': tmpdir.strpath}) 114 | config.name = 'main' 115 | # Acquire a lock, simulating a running process 116 | with ServerWalReceiveLock(tmpdir.strpath, 'main'): 117 | # Build a ProcessManager and retrieve the receive-wal process 118 | pm = ProcessManager(config) 119 | pi = pm.list('receive-wal')[0] 120 | # Exit at the first invocation of kill (this is a failed kill) 121 | kill_mock.side_effect = OSError(errno.EPERM, '', '') 122 | kill = pm.kill(pi) 123 | # Expect the kill result to be false 124 | assert kill is False 125 | assert kill_mock.call_count == 1 126 | kill_mock.assert_called_with(pi.pid, 2) 127 | 128 | kill_mock.reset_mock() 129 | # Exit at the second invocation of kill (this is a successful kill) 130 | kill_mock.side_effect = [None, OSError(errno.ESRCH, '', '')] 131 | # Expect the kill result to be true 132 | kill = pm.kill(pi) 133 | assert kill 134 | assert kill_mock.call_count == 2 135 | kill_mock.assert_has_calls([mock.call(pi.pid, 2), 136 | mock.call(pi.pid, 0)]) 137 | 138 | kill_mock.reset_mock() 139 | # Check for the retry feature. exit at the second iteration of the 140 | # kill cycle 141 | kill_mock.side_effect = [None, None, OSError(errno.ESRCH, '', '')] 142 | kill = pm.kill(pi) 143 | assert kill 144 | assert kill_mock.call_count == 3 145 | kill_mock.assert_has_calls([mock.call(pi.pid, 2), 146 | mock.call(pi.pid, 0), 147 | mock.call(pi.pid, 0)]) 148 | -------------------------------------------------------------------------------- /doc/manual/43-backup-commands.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Backup commands 4 | 5 | Backup commands are those that works directly on backups already existing in 6 | Barman's backup catalog. 7 | 8 | > **NOTE:** 9 | > Remember a backup ID can be retrieved with `barman list-backup 10 | > ` 11 | 12 | ## Backup ID shortcuts 13 | 14 | Barman allows you to use special keywords to identify a specific backup: 15 | 16 | * `last/latest`: identifies the newest backup in the catalog 17 | * `first/oldest`: identifies the oldest backup in the catalog 18 | 19 | Using those keywords with Barman commands allows you to execute actions 20 | without knowing the exact ID of a backup for a server. 21 | For example we can issue: 22 | 23 | ``` bash 24 | barman delete oldest 25 | ``` 26 | 27 | to remove the oldest backup available in the catalog and reclaim disk space. 28 | 29 | ## `delete` 30 | 31 | You can delete a given backup with: 32 | 33 | ``` bash 34 | barman delete 35 | ``` 36 | 37 | The `delete` command accepts any [shortcut](#shortcuts) to identify backups. 38 | 39 | ## `list-files` 40 | 41 | You can list the files (base backup and required WAL files) for a 42 | given backup with: 43 | 44 | ``` bash 45 | barman list-files [--target TARGET_TYPE] 46 | ``` 47 | 48 | With the `--target TARGET_TYPE` option, it is possible to choose the 49 | content of the list for a given backup. 50 | 51 | Possible values for `TARGET_TYPE` are: 52 | 53 | - `data`: lists the data files 54 | - `standalone`: lists the base backup files, including required WAL 55 | files 56 | - `wal`: lists all WAL files from the beginning of the base backup to 57 | the start of the following one (or until the end of the log) 58 | - `full`: same as `data` + `wal` 59 | 60 | The default value for `TARGET_TYPE` is `standalone`. 61 | 62 | > **IMPORTANT:** 63 | > The `list-files` command facilitates interaction with external 64 | > tools, and can therefore be extremely useful to integrate 65 | > Barman into your archiving procedures. 66 | 67 | ## `recover` 68 | 69 | The `recover` command is used to recover a whole server after 70 | a backup is executed using the `backup` command. 71 | 72 | This is achieved issuing a command like the following: 73 | 74 | ```bash 75 | barman@backup$ barman recover /path/to/recover/dir 76 | ``` 77 | 78 | At the end of the execution of the recovery, the selected backup is recovered 79 | locally and the destination path contains a data directory ready to be used 80 | to start a PostgreSQL instance. 81 | 82 | > **IMPORTANT:** 83 | > Running this command as user `barman`, it will become the database superuser. 84 | 85 | The specific ID of a backup can be retrieved using the [list-backup](#list-backup) 86 | command. 87 | 88 | > **IMPORTANT:** 89 | > Barman does not currently keep track of symbolic links inside PGDATA 90 | > (except for tablespaces inside pg_tblspc). We encourage 91 | > system administrators to keep track of symbolic links and to add them 92 | > to the disaster recovery plans/procedures in case they need to be restored 93 | > in their original location. 94 | 95 | The recovery command has several options that modify the command behavior. 96 | 97 | ### Remote recovery 98 | 99 | Add the `--remote-ssh-command ` option to the invocation 100 | of the recovery command. Doing this will allow Barman to execute 101 | the copy on a remote server, using the provided command to connect 102 | to the remote host. 103 | 104 | > **NOTE:** 105 | > It is advisable to use the `postgres` user to perform 106 | > the recovery on the remote host. 107 | 108 | Known limitations of the remote recovery are: 109 | 110 | * Barman requires at least 4GB of free space in the system temporary directory 111 | unless the [`get-wal`](#get-wal) command is specified 112 | in the `recovery_option` parameter in the Barman configuration. 113 | * The SSH connection between Barman and the remote host **must** use the 114 | public key exchange authentication method 115 | * The remote user **must** be able to create the directory structure 116 | of the backup in the destination directory. 117 | * There must be enough free space on the remote server 118 | to contain the base backup and the WAL files needed for recovery. 119 | 120 | ### Tablespace remapping 121 | 122 | Barman is able to automatically remap one or more tablespaces using 123 | the recover command with the --tablespace option. 124 | The option accepts a pair of values as arguments using the 125 | `NAME:DIRECTORY` format: 126 | 127 | * `NAME` is the identifier of the tablespace 128 | * `DIRECTORY` is the new destination path for the tablespace 129 | 130 | If the destination directory does not exists, 131 | Barman will try to create it (assuming you have the required permissions). 132 | 133 | ### Point in time recovery 134 | 135 | Barman wraps PostgreSQL's Point-in-Time Recovery (PITR), 136 | allowing you to specify a recovery target, either as a timestamp, 137 | as a restore label, or as a transaction ID. 138 | 139 | The recovery target can be specified using one of 140 | three mutually exclusive options: 141 | 142 | * --target-time TARGET_TIME: to specify a timestamp 143 | * --target-xid TARGET_XID: to specify a transaction ID 144 | * --target-name TARGET_NAME: to specify a named restore point 145 | previously created with the pg_create_restore_point(name) 146 | function[^TARGET_NAME] 147 | 148 | [^TARGET_NAME]: 149 | Only available on PostgreSQL 9.1 and above 150 | 151 | You can use the --exclusive option to specify whether to stop immediately 152 | before or immediately after the recovery target. 153 | 154 | Barman allows you to specify a target timeline for recovery, 155 | using the `target-tli` option. The notion of timeline goes beyond the scope of 156 | this document; you can find more details in the PostgreSQL documentation, 157 | as mentioned in the _"Before you start"_ section. 158 | 159 | ## `show-backup` 160 | 161 | You can retrieve all the available information for a particular backup of 162 | a given server with: 163 | 164 | ``` bash 165 | barman show-backup 166 | ``` 167 | 168 | The `show-backup` command accepts any [shortcut](#shortcuts) to identify backups. 169 | -------------------------------------------------------------------------------- /sphinx/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -c . -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ./docs 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -a -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Barman.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Barman.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Barman" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Barman" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /barman/process.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see 17 | 18 | import errno 19 | import logging 20 | import os 21 | import signal 22 | import time 23 | from glob import glob 24 | 25 | from barman import output 26 | from barman.exceptions import LockFileParsingError 27 | from barman.lockfile import ServerWalReceiveLock 28 | 29 | _logger = logging.getLogger(__name__) 30 | 31 | 32 | class ProcessInfo(object): 33 | """ 34 | Barman process representation 35 | """ 36 | 37 | def __init__(self, pid, server_name, task): 38 | """ 39 | This object contains all the information required to identify a 40 | barman process 41 | 42 | :param int pid: Process ID 43 | :param string server_name: Name of the server owning the process 44 | :param string task: Task name (receive-wal, archive-wal...) 45 | """ 46 | 47 | self.pid = pid 48 | self.server_name = server_name 49 | self.task = task 50 | 51 | 52 | class ProcessManager(object): 53 | """ 54 | Class for the management of barman processes owned by a server 55 | """ 56 | 57 | # Map containing the tasks we want to retrieve (and eventually manage) 58 | TASKS = { 59 | 'receive-wal': ServerWalReceiveLock 60 | } 61 | 62 | def __init__(self, config): 63 | """ 64 | Build a ProcessManager for the provided server 65 | 66 | :param config: configuration of the server owning the process manager 67 | """ 68 | self.config = config 69 | self.process_list = [] 70 | # Cycle over the lock files in the lock directory for this server 71 | for path in glob(os.path.join(self.config.barman_lock_directory, 72 | '.%s-*.lock' % self.config.name)): 73 | for task, lock_class in self.TASKS.items(): 74 | # Check the lock_name against the lock class 75 | lock = lock_class.build_if_matches(path) 76 | if lock: 77 | try: 78 | # Use the lock to get the owner pid 79 | pid = lock.get_owner_pid() 80 | except LockFileParsingError: 81 | _logger.warning( 82 | "Skipping the %s process for server %s: " 83 | "Error reading the PID from lock file '%s'", 84 | task, self.config.name, path) 85 | break 86 | # If there is a pid save it in the process list 87 | if pid: 88 | self.process_list.append( 89 | ProcessInfo(pid, config.name, task)) 90 | # In any case, we found a match, so we must stop iterating 91 | # over the task types and handle the the next path 92 | break 93 | 94 | def list(self, task_filter=None): 95 | """ 96 | Returns a list of processes owned by this server 97 | 98 | If no filter is provided, all the processes are returned. 99 | 100 | :param str task_filter: Type of process we want to retrieve 101 | :return list[ProcessInfo]: List of processes for the server 102 | """ 103 | server_tasks = [] 104 | for process in self.process_list: 105 | # Filter the processes if necessary 106 | if task_filter and process.task != task_filter: 107 | continue 108 | server_tasks.append(process) 109 | return server_tasks 110 | 111 | def kill(self, process_info, retries=10): 112 | """ 113 | Kill a process 114 | 115 | Returns True if killed successfully False otherwise 116 | 117 | :param ProcessInfo process_info: representation of the process 118 | we want to kill 119 | :param int retries: number of times the method will check 120 | if the process is still alive 121 | :rtype: bool 122 | """ 123 | # Try to kill the process 124 | try: 125 | _logger.debug("Sending SIGINT to PID %s", process_info.pid) 126 | os.kill(process_info.pid, signal.SIGINT) 127 | _logger.debug("os.kill call succeeded") 128 | except OSError as e: 129 | _logger.debug("os.kill call failed: %s", e) 130 | # The process doesn't exists. It has probably just terminated. 131 | if e.errno == errno.ESRCH: 132 | return True 133 | # Something unexpected has happened 134 | output.error("%s", e) 135 | return False 136 | # Check if the process have been killed. the fastest (and maybe safest) 137 | # way is to send a kill with 0 as signal. 138 | # If the method returns an OSError exceptions, the process have been 139 | # killed successfully, otherwise is still alive. 140 | for counter in range(retries): 141 | try: 142 | _logger.debug("Checking with SIG_DFL if PID %s is still alive", 143 | process_info.pid) 144 | os.kill(process_info.pid, signal.SIG_DFL) 145 | _logger.debug("os.kill call succeeded") 146 | except OSError as e: 147 | _logger.debug("os.kill call failed: %s", e) 148 | # If the process doesn't exists, we are done. 149 | if e.errno == errno.ESRCH: 150 | return True 151 | # Something unexpected has happened 152 | output.error("%s", e) 153 | return False 154 | time.sleep(1) 155 | _logger.debug("The PID %s has not been terminated after %s retries", 156 | process_info.pid, retries) 157 | return False 158 | -------------------------------------------------------------------------------- /rpm/rhel5/python26-psycopg2.spec: -------------------------------------------------------------------------------- 1 | # Use Python 2.6 2 | %global pybasever 2.6 3 | %global __python_ver 26 4 | %global __python %{_bindir}/python%{pybasever} 5 | %global __os_install_post %{__multiple_python_os_install_post} 6 | 7 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 8 | %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} 9 | 10 | %define ZPsycopgDAdir %{_localstatedir}/lib/zope/Products/ZPsycopgDA 11 | 12 | %global pgmajorversion 90 13 | %global pginstdir /usr/pgsql-9.0 14 | %global sname psycopg2 15 | 16 | Summary: A PostgreSQL database adapter for Python 17 | Name: python26-%{sname} 18 | Version: 2.4.5 19 | Release: 1%{?dist} 20 | License: LGPLv3 with exceptions 21 | Group: Applications/Databases 22 | Url: http://www.psycopg.org/psycopg/ 23 | Source0: http://initd.org/psycopg/tarballs/PSYCOPG-2-4/%{sname}-%{version}.tar.gz 24 | Patch0: setup.cfg.patch 25 | BuildRequires: python%{__python_ver}-devel postgresql%{pgmajorversion}-devel 26 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) 27 | Requires: python-abi = %(%{__python} -c "import sys ; print sys.version[:3]") 28 | 29 | %description 30 | psycopg is a PostgreSQL database adapter for the Python programming 31 | language (just like pygresql and popy.) It was written from scratch 32 | with the aim of being very small and fast, and stable as a rock. The 33 | main advantages of psycopg are that it supports the full Python 34 | DBAPI-2.0 and being thread safe at level 2. 35 | 36 | %package doc 37 | Summary: Documentation for psycopg python PostgreSQL database adapter 38 | Group: Documentation 39 | Requires: %{name} = %{version}-%{release} 40 | 41 | %description doc 42 | Documentation and example files for the psycopg python PostgreSQL 43 | database adapter. 44 | 45 | %package test 46 | Summary: Tests for psycopg2 47 | Group: Development/Libraries 48 | Requires: %{name} = %{version}-%{release} 49 | 50 | %description test 51 | Tests for psycopg2. 52 | 53 | %package zope 54 | Summary: Zope Database Adapter ZPsycopgDA 55 | Group: Applications/Databases 56 | Requires: %{name} = %{version}-%{release} zope 57 | 58 | %description zope 59 | Zope Database Adapter for PostgreSQL, called ZPsycopgDA 60 | 61 | %prep 62 | %setup -q -n psycopg2-%{version} 63 | %patch0 -p0 64 | 65 | %build 66 | %{__python} setup.py build 67 | # Fix for wrong-file-end-of-line-encoding problem; upstream also must fix this. 68 | for i in `find doc -iname "*.html"`; do sed -i 's/\r//' $i; done 69 | for i in `find doc -iname "*.css"`; do sed -i 's/\r//' $i; done 70 | 71 | %install 72 | rm -Rf %{buildroot} 73 | mkdir -p %{buildroot}%{python_sitearch}/psycopg2 74 | %{__python} setup.py install --no-compile --root %{buildroot} 75 | 76 | install -d %{buildroot}%{ZPsycopgDAdir} 77 | cp -pr ZPsycopgDA/* %{buildroot}%{ZPsycopgDAdir} 78 | 79 | %clean 80 | rm -rf %{buildroot} 81 | 82 | %files 83 | %defattr(-,root,root) 84 | %doc AUTHORS ChangeLog INSTALL LICENSE README 85 | %dir %{python_sitearch}/psycopg2 86 | %{python_sitearch}/psycopg2/*.py 87 | %{python_sitearch}/psycopg2/*.pyc 88 | %{python_sitearch}/psycopg2/*.so 89 | %{python_sitearch}/psycopg2/*.pyo 90 | %{python_sitearch}/psycopg2-*.egg-info 91 | 92 | %files doc 93 | %defattr(-,root,root) 94 | %doc doc examples/ 95 | 96 | %files test 97 | %defattr(-,root,root) 98 | %{python_sitearch}/%{sname}/tests/* 99 | 100 | %files zope 101 | %defattr(-,root,root) 102 | %dir %{ZPsycopgDAdir} 103 | %{ZPsycopgDAdir}/*.py 104 | %{ZPsycopgDAdir}/*.pyo 105 | %{ZPsycopgDAdir}/*.pyc 106 | %{ZPsycopgDAdir}/dtml/* 107 | %{ZPsycopgDAdir}/icons/* 108 | 109 | %changelog 110 | * Wed May 9 2012 - Marco Neciarini 2.4.5-1 111 | - Update to version 2.4.5 112 | 113 | * Mon Aug 22 2011 Devrim GUNDUZ 2.4.2-1 114 | - Update to 2.4.2 115 | - Add a patch for pg_config path. 116 | - Add new subpackage: test 117 | 118 | * Tue Mar 16 2010 Devrim GUNDUZ 2.0.14-1 119 | - Update to 2.0.14 120 | 121 | * Mon Oct 19 2009 Devrim GUNDUZ 2.0.13-1 122 | - Update to 2.0.13 123 | 124 | * Mon Sep 7 2009 Devrim GUNDUZ 2.0.12-1 125 | - Update to 2.0.12 126 | 127 | * Tue May 26 2009 Devrim GUNDUZ 2.0.11-1 128 | - Update to 2.0.11 129 | 130 | * Fri Apr 24 2009 Devrim GUNDUZ 2.0.10-1 131 | - Update to 2.0.10 132 | 133 | * Thu Mar 2 2009 Devrim GUNDUZ 2.0.9-1 134 | - Update to 2.0.9 135 | 136 | * Wed Apr 30 2008 - Devrim GUNDUZ 2.0.7-1 137 | - Update to 2.0.7 138 | 139 | * Fri Jun 15 2007 - Devrim GUNDUZ 2.0.6-1 140 | - Update to 2.0.6 141 | 142 | * Sun May 06 2007 Thorsten Leemhuis 143 | - rebuilt for RHEL5 final 144 | 145 | * Wed Dec 6 2006 - Devrim GUNDUZ 2.0.5.1-4 146 | - Rebuilt for PostgreSQL 8.2.0 147 | 148 | * Mon Sep 11 2006 - Devrim GUNDUZ 2.0.5.1-3 149 | - Rebuilt 150 | 151 | * Wed Sep 6 2006 - Devrim GUNDUZ 2.0.5.1-2 152 | - Remove ghost'ing, per Python Packaging Guidelines 153 | 154 | * Mon Sep 4 2006 - Devrim GUNDUZ 2.0.5.1-1 155 | - Update to 2.0.5.1 156 | 157 | * Sun Aug 6 2006 - Devrim GUNDUZ 2.0.3-3 158 | - Fixed zope package dependencies and macro definition, per bugzilla review (#199784) 159 | - Fixed zope package directory ownership, per bugzilla review (#199784) 160 | - Fixed cp usage for zope subpackage, per bugzilla review (#199784) 161 | 162 | * Mon Jul 31 2006 - Devrim GUNDUZ 2.0.3-2 163 | - Fixed 64 bit builds 164 | - Fixed license 165 | - Added Zope subpackage 166 | - Fixed typo in doc description 167 | - Added macro for zope subpackage dir 168 | 169 | * Mon Jul 31 2006 - Devrim GUNDUZ 2.0.3-1 170 | - Update to 2.0.3 171 | - Fixed spec file, per bugzilla review (#199784) 172 | 173 | * Sat Jul 22 2006 - Devrim GUNDUZ 2.0.2-3 174 | - Removed python dependency, per bugzilla review. (#199784) 175 | - Changed doc package group, per bugzilla review. (#199784) 176 | - Replaced dos2unix with sed, per guidelines and bugzilla review (#199784) 177 | - Fix changelog dates 178 | 179 | * Sat Jul 21 2006 - Devrim GUNDUZ 2.0.2-2 180 | - Added dos2unix to buildrequires 181 | - removed python related part from package name 182 | 183 | * Fri Jul 20 2006 - Devrim GUNDUZ 2.0.2-1 184 | - Fix rpmlint errors, including dos2unix solution 185 | - Re-engineered spec file 186 | 187 | * Fri Jan 23 2006 - Devrim GUNDUZ 188 | - First 2.0.X build 189 | 190 | * Fri Jan 23 2006 - Devrim GUNDUZ 191 | - Update to 1.2.21 192 | 193 | * Tue Dec 06 2005 - Devrim GUNDUZ 194 | - Initial release for 1.1.20 195 | -------------------------------------------------------------------------------- /barman/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | 19 | class BarmanException(Exception): 20 | """ 21 | The base class of all other barman exceptions 22 | """ 23 | 24 | 25 | class ConfigurationException(BarmanException): 26 | """ 27 | Base exception for all the Configuration errors 28 | """ 29 | 30 | 31 | class CommandException(BarmanException): 32 | """ 33 | Base exception for all the errors related to 34 | the execution of a Command. 35 | """ 36 | 37 | 38 | class CompressionException(BarmanException): 39 | """ 40 | Base exception for all the errors related to 41 | the execution of a compression action. 42 | """ 43 | 44 | 45 | class PostgresException(BarmanException): 46 | """ 47 | Base exception for all the errors related to PostgreSQL. 48 | """ 49 | 50 | 51 | class BackupException(BarmanException): 52 | """ 53 | Base exception for all the errors related to the execution of a backup. 54 | """ 55 | 56 | 57 | class WALFileException(BarmanException): 58 | """ 59 | Base exception for all the errors related to WAL files. 60 | """ 61 | 62 | 63 | class HookScriptException(BarmanException): 64 | """ 65 | Base exception for all the errors related to Hook Script execution. 66 | """ 67 | 68 | 69 | class LockFileException(BarmanException): 70 | """ 71 | Base exception for lock related errors 72 | """ 73 | 74 | 75 | class DuplicateWalFile(WALFileException): 76 | """ 77 | A duplicate WAL file has been found 78 | """ 79 | 80 | 81 | class MatchingDuplicateWalFile(DuplicateWalFile): 82 | """ 83 | A duplicate WAL file has been found, but it's identical to the one we 84 | already have. 85 | """ 86 | 87 | 88 | class SshCommandException(CommandException): 89 | """ 90 | Error parsing ssh_command parameter 91 | """ 92 | 93 | 94 | class UnknownBackupIdException(BackupException): 95 | """ 96 | The searched backup_id doesn't exists 97 | """ 98 | 99 | 100 | class BackupInfoBadInitialisation(BackupException): 101 | """ 102 | Exception for a bad initialization error 103 | """ 104 | 105 | 106 | class CommandFailedException(CommandException): 107 | """ 108 | Exception representing a failed command 109 | """ 110 | 111 | 112 | class CommandMaxRetryExceeded(CommandFailedException): 113 | """ 114 | A command with retry_times > 0 has exceeded the number of available retry 115 | """ 116 | def __init__(self, exc): 117 | """ 118 | :param Exception exc: the last exception raised by the command 119 | """ 120 | self.exc = exc 121 | super(CommandMaxRetryExceeded, self).__init__(*exc.args) 122 | 123 | 124 | class RsyncListFilesFailure(CommandException): 125 | """ 126 | Failure parsing the output of a "rsync --list-only" command 127 | """ 128 | 129 | 130 | class DataTransferFailure(CommandException): 131 | """ 132 | Used to pass failure details from a data transfer Command 133 | """ 134 | 135 | @classmethod 136 | def from_command_error(cls, cmd, e, msg): 137 | """ 138 | This method build a DataTransferFailure exception and report the 139 | provided message to the user (both console and log file) along with 140 | the output of the failed command. 141 | 142 | :param str cmd: The command that failed the transfer 143 | :param CommandFailedException e: The exception we are handling 144 | :param str msg: a descriptive message on what we are trying to do 145 | :return DataTransferFailure: will contain the message provided in msg 146 | """ 147 | details = msg 148 | details += "\n%s error:\n" % cmd 149 | details += e.args[0]['out'] 150 | details += e.args[0]['err'] 151 | return cls(details) 152 | 153 | 154 | class CompressionIncompatibility(CompressionException): 155 | """ 156 | Exception for compression incompatibility 157 | """ 158 | 159 | 160 | class FsOperationFailed(CommandException): 161 | """ 162 | Exception which represents a failed execution of a command on FS 163 | """ 164 | 165 | 166 | class LockFileBusy(LockFileException): 167 | """ 168 | Raised when a lock file is not free 169 | """ 170 | 171 | 172 | class LockFilePermissionDenied(LockFileException): 173 | """ 174 | Raised when a lock file is not accessible 175 | """ 176 | 177 | 178 | class LockFileParsingError(LockFileException): 179 | """ 180 | Raised when the content of the lockfile is unexpected 181 | """ 182 | 183 | 184 | class ConninfoException(ConfigurationException): 185 | """ 186 | Error for missing or failed parsing of the conninfo parameter (DSN) 187 | """ 188 | 189 | 190 | class PostgresConnectionError(PostgresException): 191 | """ 192 | Error connecting to the PostgreSQL server 193 | """ 194 | def __str__(self): 195 | # Returns the first line 196 | if self.args and self.args[0]: 197 | return str(self.args[0]).splitlines()[0].strip() 198 | else: 199 | return '' 200 | 201 | 202 | class PostgresAppNameError(PostgresConnectionError): 203 | """ 204 | Error setting application name with PostgreSQL server 205 | """ 206 | 207 | 208 | class PostgresSuperuserRequired(PostgresException): 209 | """ 210 | Superuser access is required 211 | """ 212 | 213 | 214 | class PostgresIsInRecovery(PostgresException): 215 | """ 216 | PostgreSQL is in recovery, so no write operations are allowed 217 | """ 218 | 219 | 220 | class PostgresUnsupportedFeature(PostgresException): 221 | """ 222 | Unsupported feature 223 | """ 224 | 225 | 226 | class PostgresDuplicateReplicationSlot(PostgresException): 227 | """ 228 | The creation of a physical replication slot failed because 229 | the slot already exists 230 | """ 231 | 232 | 233 | class PostgresReplicationSlotsFull(PostgresException): 234 | """ 235 | The creation of a physical replication slot failed because 236 | the all the replication slots have been taken 237 | """ 238 | 239 | 240 | class PostgresReplicationSlotInUse(PostgresException): 241 | """ 242 | The drop of a physical replication slot failed because 243 | the replication slots is in use 244 | """ 245 | 246 | 247 | class PostgresInvalidReplicationSlot(PostgresException): 248 | """ 249 | Exception representing a failure during the deletion of a non 250 | existent replication slot 251 | """ 252 | 253 | 254 | class TimeoutError(CommandException): 255 | """ 256 | A timeout occurred. 257 | """ 258 | 259 | 260 | class ArchiverFailure(WALFileException): 261 | """ 262 | Exception representing a failure during the execution 263 | of the archive process 264 | """ 265 | 266 | 267 | class BadXlogSegmentName(WALFileException): 268 | """ 269 | Exception for a bad xlog name 270 | """ 271 | 272 | 273 | class BadHistoryFileContents(WALFileException): 274 | """ 275 | Exception for a corrupted history file 276 | """ 277 | 278 | 279 | class AbortedRetryHookScript(HookScriptException): 280 | """ 281 | Exception for handling abort of retry hook scripts 282 | """ 283 | def __init__(self, hook): 284 | """ 285 | Initialise the exception with hook script info 286 | """ 287 | self.hook = hook 288 | 289 | def __str__(self): 290 | """ 291 | String representation 292 | """ 293 | return ("Abort '%s_%s' retry hook script (%s, exit code: %d)" % ( 294 | self.hook.phase, self.hook.name, 295 | self.hook.script, self.hook.exit_status)) 296 | -------------------------------------------------------------------------------- /doc/manual/21-preliminary_steps.en.md: -------------------------------------------------------------------------------- 1 | ## Preliminary steps 2 | 3 | This section contains some preliminary steps that you need to 4 | undertake before setting up your PostgreSQL server in Barman. 5 | 6 | > **IMPORTANT:** 7 | > Before you proceed, it is important that you have made your decision 8 | > in terms of WAL archiving and backup strategies, as outlined in the 9 | > _"Design and architecture"_ section. In particular, you should 10 | > decide which WAL archiving methods to use, as well as the backup 11 | > method. 12 | 13 | ### PostgreSQL connection 14 | 15 | You need to make sure that the `backup` server can connect to 16 | the PostgreSQL server on `pg` as superuser. This operation is mandatory. 17 | 18 | We recommend creating a specific user in PostgreSQL, named `barman`, 19 | as follows: 20 | 21 | ``` bash 22 | postgres@pg$ createuser -s -W barman 23 | ``` 24 | 25 | > **IMPORTANT:** The above command will prompt for a password, 26 | > which you are then advised to add to the `~barman/.pgpass` file 27 | > on the `backup` server. For further information, please refer to 28 | > ["The Password File" section in the PostgreSQL Documentation] [pgpass]. 29 | 30 | This connection is required by Barman in order to coordinate its 31 | activities with the server, as well as for monitoring purposes. 32 | 33 | You can choose your favourite client authentication method among those 34 | offered by PostgreSQL. More information can be found in the 35 | ["Client Authentication" section of the PostgreSQL Documentation] [pghba]. 36 | 37 | Make sure you test the following command before proceeding: 38 | 39 | ``` bash 40 | barman@backup$ psql -c 'SELECT version()' -U barman -h pg postgres 41 | ``` 42 | 43 | Write down the above information (user name, host name and database 44 | name) and keep it for later. You will need it with in the `conninfo` 45 | option for your server configuration, like in this example: 46 | 47 | ``` ini 48 | [pg] 49 | ; ... 50 | conninfo = host=pg user=barman dbname=postgres 51 | ``` 52 | 53 | > **NOTE:** Barman honours the `application_name` connection option 54 | > for PostgreSQL servers 9.0 or higher. 55 | 56 | 57 | ### PostgreSQL WAL archiving and replication 58 | 59 | Before you proceed, you need to properly configure PostgreSQL on `pg` 60 | to accept streaming replication connections from the Barman 61 | server. Please read the following sections in the PostgreSQL 62 | documentation: 63 | 64 | - [Role attributes] [roles] 65 | - [The pg_hba.conf file] [authpghba] 66 | - [Setting up standby servers using streaming replication] [streamprot] 67 | 68 | 69 | One configuration parameter that is crucially important is the 70 | `wal_level` parameter. This parameter must be configured to ensure 71 | that all the useful information necessary for a backup to be coherent 72 | are included in the transaction log file. 73 | 74 | ``` ini 75 | wal_level = 'replica' 76 | ``` 77 | 78 | For PostgreSQL versions older than 9.6, `wal_level` must be set to 79 | `hot_standby`. 80 | 81 | Restart the PostgreSQL server for the configuration to be refreshed. 82 | 83 | 84 | ### PostgreSQL streaming connection 85 | 86 | If you plan to use WAL streaming or streaming backup, you need to 87 | setup a streaming connection. We recommend creating a specific user in 88 | PostgreSQL, named `streaming_barman`, as follows: 89 | 90 | ``` bash 91 | postgres@pg$ createuser -W --replication streaming_barman 92 | ``` 93 | 94 | > **IMPORTANT:** The above command will prompt for a password, 95 | > which you are then advised to add to the `~barman/.pgpass` file 96 | > on the `backup` server. For further information, please refer to 97 | > ["The Password File" section in the PostgreSQL Documentation] [pgpass]. 98 | 99 | You can manually verify that the streaming connection works through 100 | the following command: 101 | 102 | ``` bash 103 | barman@backup$ psql -U streaming_barman -h pg \ 104 | -c "IDENTIFY_SYSTEM" \ 105 | replication=1 106 | ``` 107 | 108 | > **IMPORTANT:** 109 | > Please make sure you are able to connect via streaming replication 110 | > before going any further. 111 | 112 | You also need to configure the `max_wal_senders` parameter in the 113 | PostgreSQL configuration file: 114 | 115 | ``` ini 116 | max_wal_senders = 2 117 | ``` 118 | 119 | This option represents the maximum number of concurrent streaming 120 | connections that the server will be allowed to manage. 121 | 122 | Another important parameter is `max_replication_slots`, which 123 | represents the maximum number of replication slots [^replslot94] 124 | that the server will be allowed to manage. 125 | This parameter is needed if you are planning to 126 | use the streaming connection to receive WAL files over the streaming 127 | connection: 128 | 129 | ``` ini 130 | max_replication_slots = 2 131 | ``` 132 | 133 | [^replslot94]: Replication slots have been introduced in PostgreSQL 9.4. 134 | See section _"WAL Streaming / Replication slots"_ for 135 | details. 136 | 137 | The values proposed for `max_replication_slots` and `max_wal_senders` 138 | must be considered as examples, and the values you will use in your 139 | actual setup must be choosen after a careful evaluation of the 140 | architecture. Please consult the PostgreSQL documentation for 141 | guidelines and clarifications. 142 | 143 | 144 | ### SSH connections 145 | 146 | SSH is a protocol and a set of tools that allows you to open a remote 147 | shell to a remote server and copy files between the server and the local 148 | system. You can find more documentation about SSH usage in the article 149 | ["SSH Essentials"][ssh_essentials] by Digital Ocean. 150 | 151 | SSH key exchange is a very common practice that is used to implement 152 | secure passwordless connections between users on different machines, 153 | and it's needed to use `rsync` for WAL archiving and for backups. 154 | 155 | > **NOTE:** 156 | > This procedure is not needed if you plan to use the streaming 157 | > connection only to archive transaction logs and backup your PostgreSQL 158 | > server. 159 | 160 | [ssh_essentials]: https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys 161 | 162 | #### SSH configuration of postgres user 163 | 164 | Unless you have done it before, you need to create an SSH key for the 165 | PostgreSQL user. Log in as `postgres`, in the `pg` host and type: 166 | 167 | ``` bash 168 | postgres@pg$ ssh-keygen -t rsa 169 | ``` 170 | 171 | As this key must be used to connect from hosts without providing a 172 | password, no passphrase should be entered during the key pair 173 | creation. 174 | 175 | 176 | #### SSH configuration of barman user 177 | 178 | As in the previous paragraph, you need to create an SSH key for the 179 | Barman user. Log in as `barman` in the `backup` host and type: 180 | 181 | ``` bash 182 | barman@backup$ ssh-keygen -t rsa 183 | ``` 184 | 185 | For the same reason, no passphrase should be entered. 186 | 187 | #### From PostgreSQL to Barman 188 | 189 | The SSH connection from the PostgreSQL server to the backup server is 190 | needed to correctly archive WAL files using the `archive_command` 191 | setting. 192 | 193 | To successfully connect from the PostgreSQL server to the backup 194 | server, the PostgreSQL public key has to be configured into the 195 | authorized keys of the backup server for the `barman` user. 196 | 197 | The public key to be authorized is stored inside the `postgres` user 198 | home directory in a file named `.ssh/id_rsa.pub`, and its content 199 | should be included in a file named `.ssh/authorized_keys` inside the 200 | home directory of the `barman` user in the backup server. If the 201 | `authorized_keys` file doesn't exist, create it using `600` as 202 | permissions. 203 | 204 | The following command should succeed without any output if the SSH key 205 | pair exchange has been completed successfully: 206 | 207 | ``` bash 208 | postgres@pg$ ssh barman@backup -C true 209 | ``` 210 | 211 | The value of the `archive_command` configuration parameter will be 212 | discussed in the _"WAL archiving via archive_command section"_. 213 | 214 | 215 | #### From Barman to PostgreSQL 216 | 217 | The SSH connection between the backup server and the PostgreSQL server 218 | is used for the traditional backup over rsync. Just as with the 219 | connection from the PostgreSQL server to the backup server, we should 220 | authorize the public key of the backup server in the PostgreSQL server 221 | for the `postgres` user. 222 | 223 | The content of the file `.ssh/id_rsa.pub` in the `barman` server should 224 | be put in the file named `.ssh/authorized_keys` in the PostgreSQL 225 | server. The permissions of that file should be `600`. 226 | 227 | The following command should succeed without any output if the key 228 | pair exchange has been completed successfully. 229 | 230 | ``` bash 231 | barman@backup$ ssh postgres@pg -C true 232 | ``` 233 | -------------------------------------------------------------------------------- /doc/manual/42-server-commands.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Server commands 4 | 5 | As we said in the previous section, server commands work directly on 6 | a PostgreSQL server or on its area in Barman, and are useful to check 7 | its status, perform maintainance operations, take backups, and 8 | manage the WAL archive. 9 | 10 | ## `archive_wal` 11 | 12 | The `archive_wal` command execute maintainance operations on WAL files 13 | for a given server. This operations include processing of the WAL 14 | files received from the streaming connection or from the 15 | `archive_command` or both. 16 | 17 | > **IMPORTANT:** 18 | > The `archive_wal` command, even if it can be directly invoked, is 19 | > designed to be started from the `cron` general command. 20 | 21 | ## `backup` 22 | 23 | The `backup` command takes a full backup (_base backup_) of a given 24 | server. It has several options that let you override the corresponding 25 | configuration parameter for the new backup. For more information, 26 | consult the manual page. 27 | 28 | You can perform a full backup for a given server with: 29 | 30 | ``` bash 31 | barman backup 32 | ``` 33 | 34 | > **TIP:** 35 | > You can use `barman backup all` to sequentially backup all your 36 | > configured servers. 37 | 38 | 39 | ## `check` 40 | 41 | You can check the connection to a given server and the 42 | configuration coherence with the `check` command: 43 | 44 | ``` bash 45 | barman check 46 | ``` 47 | 48 | > **TIP:** 49 | > You can use `barman check all` to check all your configured servers. 50 | 51 | > **IMPORTANT:** 52 | > The `check` command is probably the most critical feature that 53 | > Barman implements. We recommend to integrate it with your alerting 54 | > and monitoring infrastructure. The `--nagios` option allows you 55 | > to easily create a plugin for Nagios/Icinga. 56 | 57 | ## `get-wal` 58 | 59 | Barman allows users to request any _xlog_ file from its WAL archive 60 | through the `get-wal` command: 61 | 62 | ``` bash 63 | barman get-wal [-o OUTPUT_DIRECTORY] [-j|-x] 64 | ``` 65 | 66 | If the requested WAL file is found in the server archive, the 67 | uncompressed content will be returned to `STDOUT`, unless otherwise 68 | specified. 69 | 70 | The following options are available for the `get-wal` command: 71 | 72 | - `-o` allows users to specify a destination directory where Barman 73 | will deposit the requested WAL file 74 | - `-j` will compress the output using `bzip2` algorithm 75 | - `-x` will compress the output using `gzip` algorithm 76 | - `-p SIZE` peeks from the archive up to WAL files, starting from 77 | the requested file 78 | 79 | It is possible to use `get-wal` during a recovery operation, 80 | transforming the Barman server into a _WAL hub_ for your servers. This 81 | can be automatically achieved by adding the `get-wal` value to the 82 | `recovery_options` global/server configuration option: 83 | 84 | ``` ini 85 | recovery_options = 'get-wal' 86 | ``` 87 | 88 | `recovery_options` is a global/server option that accepts a list of 89 | comma separated values. If the keyword `get-wal` is present during a 90 | recovery operation, Barman will prepare the `recovery.conf` file by 91 | setting the `restore_command` so that `barman get-wal` is used to 92 | fetch the required WAL files. 93 | 94 | This is an example of a `restore_command` for a local recovery: 95 | 96 | ``` ini 97 | restore_command = 'sudo -u barman barman get-wal SERVER %f > %p' 98 | ``` 99 | 100 | Please note that the `get-wal` command should always be invoked as 101 | `barman` user, and that it requires the correct permission to 102 | read the WAL files from the catalog. This is the reason why we are 103 | using `sudo -u barman` in the example. 104 | 105 | Setting `recovery_options` to `get-wal` for a remote recovery will instead 106 | generate a `restore_command` using the `barman-wal-restore` script. 107 | `barman-wal-restore` is a more resilient shell script which manages SSH 108 | connection errors. 109 | 110 | This script has many useful options such as the automatic compression and 111 | decompression of the WAL files and the *peek* feature, which allows you 112 | to retrieve the next WAL files while PostgreSQL is applying one of them. It is 113 | an excellent way to optimise the bandwidth usage between PostgreSQL and 114 | Barman. 115 | 116 | `barman-wal-restore` is available in the `barman-cli` project or package. 117 | 118 | This is an example of a `restore_command` for a remote recovery: 119 | 120 | ``` ini 121 | restore_command = 'barman-wal-restore -U barman backup SERVER %f %p' 122 | ``` 123 | 124 | Since it uses SSH to communicate with the Barman server, SSH key authentication 125 | is required for the `postgres` user to login as `barman` on the backup server. 126 | 127 | > **IMPORTANT:** 128 | > Even though `recovery_options` aims to automate the process, using 129 | > the `get-wal` facility requires manual intervention and proper 130 | > testing. 131 | 132 | ## `list-backup` 133 | 134 | You can list the catalog of available backups for a given server 135 | with: 136 | 137 | ``` bash 138 | barman list-backup 139 | ``` 140 | 141 | > **TIP:** You can request a full list of the backups of all servers 142 | > using `all` as the server name. 143 | 144 | To have a machine-readable output you can use the `--minimal` option. 145 | 146 | ## `rebuild-xlogdb` 147 | 148 | At any time, you can regenerate the content of the WAL archive for a 149 | specific server (or every server, using the `all` shortcut). The WAL 150 | archive is contained in the `xlog.db` file and every server managed by 151 | Barman has its own copy. 152 | 153 | The `xlog.db` file can be rebuilt with the `rebuild-xlogdb` 154 | command. This will scan all the archived WAL files and regenerate the 155 | metadata for the archive. 156 | 157 | For example: 158 | 159 | ``` bash 160 | barman rebuild-xlogdb 161 | ``` 162 | 163 | ## `receive-wal` 164 | 165 | This command manages the `receive-wal` process, which uses the 166 | streaming protocol to receive WAL files from the PostgreSQL streaming 167 | connection. 168 | 169 | ### receive-wal process management 170 | 171 | If the command is run without options, a `receive-wal` process will 172 | be started. This command is based on the `pg_receivexlog` PostgreSQL 173 | command. 174 | 175 | ``` bash 176 | barman receive-wal 177 | ``` 178 | 179 | If the command is run with the `--stop` option, the currently running 180 | `receive-wal` process will be stopped. 181 | 182 | The `receive-wal` process uses a status file to track last written 183 | record of the transaction log. When the status file needs to be 184 | cleaned, the `--reset` option can be used. 185 | 186 | > **IMPORTANT:** If you are not using replication slots, you rely 187 | > on the value of `wal_keep_segments`. Be aware that under high peeks 188 | > of workload on the database, the `receive-wal` process 189 | > might fall behind and go out of sync. As a precautionary measure, 190 | > Barman currently requires that users manually execute the command with the 191 | > `--reset` option, to avoid making wrong assumptions. 192 | 193 | ### Replication slot management 194 | 195 | The `receive-wal` process is also useful to create or drop the 196 | replication slot needed by Barman for its WAL archiving procedure. 197 | 198 | With the `--create-slot` option, the replication slot named after the 199 | `slot_name` configuration option will be created on the PostgreSQL 200 | server. 201 | 202 | With the `--drop-slot`, the previous replication slot will be deleted. 203 | 204 | ## `replication-status` 205 | 206 | The `replication-status` command reports the status of any streaming 207 | client currently attached to the PostgreSQL server, including the 208 | `receive-wal` process of your Barman server (if configured). 209 | 210 | You can execute the command as follows: 211 | 212 | ``` bash 213 | barman replication-status 214 | ``` 215 | 216 | > **TIP:** You can request a full status report of the replica 217 | > for all your servers using `all` as the server name. 218 | 219 | To have a machine-readable output you can use the `--minimal` option. 220 | 221 | ## `show-server` 222 | 223 | You can show the configuration parameters for a given server with: 224 | 225 | ``` bash 226 | barman show-server 227 | ``` 228 | 229 | > **TIP:** you can request a full configuration report using `all` as 230 | > the server name. 231 | 232 | 233 | ## `status` 234 | 235 | The `status` command shows live information and status of a PostgreSQL 236 | server or of all servers if you use `all` as server name. 237 | 238 | ``` bash 239 | barman show-server 240 | ``` 241 | 242 | ## `switch-xlog` 243 | 244 | This command makes the PostgreSQL server switch to another transaction 245 | log file, allowing the current log file to be closed, received and then 246 | archived. 247 | 248 | ``` bash 249 | barman switch-xlog 250 | ``` 251 | 252 | If there has been no transaction activity since the last transaction 253 | log file switch, the switch needs to be forced using the 254 | `--force` option. 255 | 256 | The `--archive` option requests Barman to trigger WAL archiving after 257 | the xlog switch. By default, a 30 seconds timeout is enforced (this 258 | can be changed with `--archive-timeout`). If no WAL file is received, 259 | an error is returned. 260 | -------------------------------------------------------------------------------- /doc/manual/10-design.en.md: -------------------------------------------------------------------------------- 1 | \newpage 2 | 3 | # Design and architecture 4 | 5 | ## Where to install Barman 6 | 7 | One of the foundations of Barman is the ability to operate remotely from the database server, via the network. 8 | 9 | Theoretically, you could have your Barman server located in a data centre in another part of the world, thousands of miles away from your PostgreSQL server. 10 | Realistically, you do not want your Barman server to be too far from your PostgreSQL server, so that both backup and recovery times are kept under control. 11 | 12 | Even though there is no _"one size fits all"_ way to setup Barman, there are a couple of recommendations that we suggest you abide by, in particular: 13 | 14 | - Install Barman on a dedicated server 15 | - Do not share the same storage with your PostgreSQL server 16 | - Integrate Barman with your monitoring infrastructure [^nagios] 17 | - Test everything before you deploy it to production 18 | 19 | [^nagios]: Integration with Nagios/Icinga is straightforward thanks to the `barman check --nagios` command, one of the most important features of Barman and a true lifesaver. 20 | 21 | A reasonable way to start modelling your disaster recovery architecture is to: 22 | 23 | - design a couple of possibile architectures in respect to PostgreSQL and Barman, such as: 24 | 1. same data centre 25 | 2. different data centre in the same metropolitan area 26 | 3. different data centre 27 | - elaborate the pros and the cons of each hypothesis 28 | - evaluate the single points of failure (SPOF) of your system, with cost-benefit analysis 29 | - make your decision and implement the initial solution 30 | 31 | Having said this, a very common setup for Barman is to be installed in the same data centre where your PostgreSQL servers are. In this case, the single point of failure is the data centre. Fortunately, the impact of such a SPOF can be alleviated thanks to a feature called _hook scripts_. Indeed, backups of Barman can be exported on different media, such as _tape_ via `tar`, or locations, like an _S3 bucket_ in the Amazon cloud. 32 | 33 | Remember that no decision is forever. You can start this way and adapt over time to the solution that suits you best. However, try and keep it simple to start with. 34 | 35 | ## One Barman, many PostgreSQL servers 36 | 37 | Another relevant feature that was first introduced by Barman is support for multiple servers. Barman can store backup data coming from multiple PostgreSQL instances, even with different versions, in a centralised way. [^recver] 38 | 39 | [^recver]: The same [requirements for PostgreSQL's PITR][requirements_recovery] apply for recovery, as detailed in the section _"Requirements for recovery"_. 40 | 41 | As a result, you can model complex disaster recovery architectures, forming a "star schema", where PostgreSQL servers rotate around a central Barman server. 42 | 43 | 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. 44 | 45 | From this point forward, for the sake of simplicity, this guide will assume a basic architecture: 46 | 47 | - one PostgreSQL instance (with host name `pg`) 48 | - one backup server with Barman (with host name `backup`) 49 | 50 | ## Streaming backup vs rsync/SSH 51 | 52 | Traditionally, Barman has always operated remotely via SSH, taking advantage of `rsync` for physical backup operations. Version 2.0 introduces native support for PostgreSQL's streaming replication protocol for backup operations, via `pg_basebackup`. [^fmatrix] 53 | 54 | [^fmatrix]: Check in the "Feature matrix" which PostgreSQL versions support streaming replication backups with Barman. 55 | 56 | Choosing one of these two methods is a decision you will need to make. 57 | 58 | On a general basis, starting from Barman 2.0, backup over streaming replication is the recommended setup for PostgreSQL 9.4 or higher. Moreover, if you do not make use of tablespaces, backup over streaming can be used starting from PostgreSQL 9.2. 59 | 60 | > **IMPORTANT:** \newline 61 | > Because Barman transparently makes use of `pg_basebackup`, features such as incremental backup, deduplication, and network compression are currently not available. In this case, bandwidth limitation has some restrictions - compared to the traditional method via `rsync`. 62 | 63 | Traditional backup via `rsync`/SSH is available for all versions of PostgreSQL starting from 8.3, and it is recommended in all cases where `pg_basebackup` limitations occur (for example, a very large database that can benefit from incremental backup and deduplication). 64 | 65 | The reason why we recommend streaming backup is that, based on our experience, it is easier to setup than the traditional one. Also, streaming backup allows you to backup a PostgreSQL server on Windows[^windows], and makes life easier when working with Docker. 66 | 67 | [^windows]: Backup of a PostgreSQL server on Windows is possible, but it is still experimental because it is not yet part of our continuous integration system. See section _"How to setup a Windows based server"_ for details. 68 | 69 | ## Standard archiving, WAL streaming ... or both 70 | 71 | PostgreSQL's Point-In-Time-Recovery requires that transactional logs, also known as _xlog_ or WAL files, are stored alongside of base backups. 72 | 73 | Traditionally, Barman has supported standard WAL file shipping through PostgreSQL's `archive_command` (usually via `rsync`/SSH). With this method, WAL files are archived only when PostgreSQL _switches_ to a new WAL file. To keep it simple, this normally happens every 16MB worth of data changes. 74 | 75 | Barman 1.6.0 introduces streaming of WAL files for PostgreSQL servers 9.2 or higher, as an additional method for transactional log archiving, through `pg_receivexlog`. WAL streaming is able to reduce the risk of data loss, bringing RPO down to _near zero_ values. 76 | 77 | Barman 2.0 introduces support for replication slots with PostgreSQL servers 9.4 or above, therefore allowing WAL streaming-only configurations. Moreover, you can now add Barman as a synchronous WAL receiver in your PostgreSQL 9.5 (or higher) cluster, and achieve **zero data loss** (RPO=0). 78 | 79 | In some cases you have no choice and you are forced to use traditional archiving. In others, you can choose whether to use both or just WAL streaming. 80 | Unless you have strong reasons not to do it, we recommend to use both channels, for maximum reliability and robustness. 81 | 82 | ## Two typical scenarios for backups 83 | 84 | In order to make life easier for you, below we summarise the two most typical scenarios for a given PostgreSQL server in Barman. 85 | 86 | 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 installation. 87 | 88 | As mentioned before, we will only worry about the PostgreSQL server (`pg`) and the Barman server (`backup`). However, in real life, your architecture will most likely contain other technologies such as repmgr, pgBouncer, Nagios/Icinga, and so on. 89 | 90 | ### Scenario 1: Backup via streaming protocol 91 | 92 | If you are using PostgreSQL 9.4 or higher, and your database falls under a general use case scenario, you will likely end up deciding on a streaming backup installation - see figure \ref{scenario1-design} below. 93 | 94 | 95 | ![Streaming-only backup (Scenario 1)\label{scenario1-design}](../images/barman-architecture-scenario1.png){ width=80% } 96 | 97 | In this scenario, you will need to configure: 98 | 99 | 1. a standard connection to PostgreSQL, for management, coordination, and monitoring purposes 100 | 2. a streaming replication connection that will be used by both `pg_basebackup` (for base backup operations) and `pg_receivexlog` (for WAL streaming) 101 | 102 | This setup, in Barman's terminology, is known as **streaming-only** setup, as it does not require any SSH connection for backup and archiving operations. This is particularly suitable and extremely practical for Docker environments. 103 | 104 | However, as mentioned before, you can configure standard archiving as well and implement a more robust architecture - see figure \ref{scenario1b-design} below. 105 | 106 | ![Streaming backup with WAL archiving (Scenario 1b)\label{scenario1b-design}](../images/barman-architecture-scenario1b.png){ width=80% } 107 | 108 | This alternate approach requires: 109 | 110 | - an additional SSH connection that allows the `postgres` user on the PostgreSQL server to connect as `barman` user on the Barman server 111 | - the `archive_command` in PostgreSQL be configured to ship WAL files to Barman 112 | 113 | This architecture is available also to PostgreSQL 9.2/9.3 users that do not use tablespaces. 114 | 115 | 116 | ### Scenario 2: Backup via `rsync`/SSH 117 | 118 | The _traditional_ setup of `rsync` over SSH is the only available option for: 119 | 120 | - PostgreSQL servers version 8.3, 8.4, 9.0 or 9.1 121 | - PostgreSQL servers version 9.2 or 9.3 that are using tablespaces 122 | - incremental backup and deduplication 123 | - network compression during backups 124 | - finer control of bandwidth usage, including on a tablespace basis 125 | 126 | ![Scenario 2 - Backup via rsync/SSH](../images/barman-architecture-scenario2.png){ width=80% } 127 | 128 | In this scenario, you will need to configure: 129 | 130 | 1. a standard connection to PostgreSQL for management, coordination, and monitoring purposes 131 | 2. an SSH connection for base backup operations to be used by `rsync` that allows the `barman` user on the Barman server to connect as `postgres` user on the PostgreSQL server 132 | 3. an SSH connection for WAL archiving to be used by the `archive_command` in PostgreSQL and that allows the `postgres` user on the PostgreSQL server to connect as `barman` user on the Barman server 133 | 134 | Starting from PostgreSQL 9.2, you can add a streaming replication connection that is used for WAL streaming and significantly reduce RPO. This more robust implementation is depicted in figure \ref{scenario2b-design}. 135 | 136 | ![Backup via rsync/SSH with WAL streaming (Scenario 2b)\label{scenario2b-design}](../images/barman-architecture-scenario2b.png){ width=80% } 137 | 138 | 139 | -------------------------------------------------------------------------------- /barman/hooks.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | """ 19 | This module contains the logic to run hook scripts 20 | """ 21 | 22 | import logging 23 | import time 24 | 25 | from barman import version 26 | from barman.command_wrappers import Command 27 | from barman.exceptions import AbortedRetryHookScript, UnknownBackupIdException 28 | 29 | _logger = logging.getLogger(__name__) 30 | 31 | 32 | class HookScriptRunner(object): 33 | def __init__(self, backup_manager, name, phase=None, error=None, 34 | retry=False, **extra_env): 35 | """ 36 | Execute a hook script managing its environment 37 | """ 38 | self.backup_manager = backup_manager 39 | self.name = name 40 | self.extra_env = extra_env 41 | self.phase = phase 42 | self.error = error 43 | self.retry = retry 44 | 45 | self.environment = None 46 | self.exit_status = None 47 | self.exception = None 48 | self.script = None 49 | 50 | self.reset() 51 | 52 | def reset(self): 53 | """ 54 | Reset the status of the class. 55 | """ 56 | self.environment = dict(self.extra_env) 57 | config_file = self.backup_manager.config.config.config_file 58 | self.environment.update({ 59 | 'BARMAN_VERSION': version.__version__, 60 | 'BARMAN_SERVER': self.backup_manager.config.name, 61 | 'BARMAN_CONFIGURATION': config_file, 62 | 'BARMAN_HOOK': self.name, 63 | 'BARMAN_RETRY': str(1 if self.retry else 0), 64 | }) 65 | if self.error: 66 | self.environment['BARMAN_ERROR'] = self.error 67 | if self.phase: 68 | self.environment['BARMAN_PHASE'] = self.phase 69 | script_config_name = "%s_%s" % (self.phase, self.name) 70 | else: 71 | script_config_name = self.name 72 | self.script = getattr(self.backup_manager.config, script_config_name, 73 | None) 74 | self.exit_status = None 75 | self.exception = None 76 | 77 | def env_from_backup_info(self, backup_info): 78 | """ 79 | Prepare the environment for executing a script 80 | 81 | :param BackupInfo backup_info: the backup metadata 82 | """ 83 | try: 84 | previous_backup = self.backup_manager.get_previous_backup( 85 | backup_info.backup_id) 86 | if previous_backup: 87 | previous_backup_id = previous_backup.backup_id 88 | else: 89 | previous_backup_id = '' 90 | except UnknownBackupIdException: 91 | previous_backup_id = '' 92 | self.environment.update({ 93 | 'BARMAN_BACKUP_DIR': backup_info.get_basebackup_directory(), 94 | 'BARMAN_BACKUP_ID': backup_info.backup_id, 95 | 'BARMAN_PREVIOUS_ID': previous_backup_id, 96 | 'BARMAN_STATUS': backup_info.status, 97 | 'BARMAN_ERROR': backup_info.error or '', 98 | }) 99 | 100 | def env_from_wal_info(self, wal_info, full_path=None, error=None): 101 | """ 102 | Prepare the environment for executing a script 103 | 104 | :param WalFileInfo wal_info: the backup metadata 105 | :param str full_path: override wal_info.fullpath() result 106 | :param str|Exception error: An error message in case of failure 107 | """ 108 | self.environment.update({ 109 | 'BARMAN_SEGMENT': wal_info.name, 110 | 'BARMAN_FILE': str(full_path if full_path is not None else 111 | wal_info.fullpath(self.backup_manager.server)), 112 | 'BARMAN_SIZE': str(wal_info.size), 113 | 'BARMAN_TIMESTAMP': str(wal_info.time), 114 | 'BARMAN_COMPRESSION': wal_info.compression or '', 115 | 'BARMAN_ERROR': str(error or '') 116 | }) 117 | 118 | def run(self): 119 | """ 120 | Run a a hook script if configured. 121 | This method must never throw any exception 122 | """ 123 | # noinspection PyBroadException 124 | try: 125 | if self.script: 126 | _logger.debug("Attempt to run %s: %s", self.name, self.script) 127 | cmd = Command( 128 | self.script, 129 | env_append=self.environment, 130 | path=self.backup_manager.server.path, 131 | shell=True, check=False) 132 | self.exit_status = cmd() 133 | if self.exit_status != 0: 134 | details = "%s returned %d\n" \ 135 | "Output details:\n" \ 136 | % (self.script, self.exit_status) 137 | details += cmd.out 138 | details += cmd.err 139 | _logger.warning(details) 140 | else: 141 | _logger.debug("%s returned %d", 142 | self.script, 143 | self.exit_status) 144 | return self.exit_status 145 | except Exception as e: 146 | _logger.exception('Exception running %s', self.name) 147 | self.exception = e 148 | return None 149 | 150 | 151 | class RetryHookScriptRunner(HookScriptRunner): 152 | 153 | """ 154 | A 'retry' hook script is a special kind of hook script that Barman 155 | tries to run indefinitely until it either returns a SUCCESS or 156 | ABORT exit code. 157 | Retry hook scripts are executed immediately before (pre) and after (post) 158 | the command execution. Standard hook scripts are executed immediately 159 | before (pre) and after (post) the retry hook scripts. 160 | """ 161 | 162 | # Failed attempts before sleeping for NAP_TIME seconds 163 | ATTEMPTS_BEFORE_NAP = 5 164 | # Short break after a failure (in seconds) 165 | BREAK_TIME = 3 166 | # Long break (nap, in seconds) after ATTEMPTS_BEFORE_NAP failures 167 | NAP_TIME = 60 168 | # ABORT (and STOP) exit code 169 | EXIT_ABORT_STOP = 63 170 | # ABORT (and CONTINUE) exit code 171 | EXIT_ABORT_CONTINUE = 62 172 | # SUCCESS exit code 173 | EXIT_SUCCESS = 0 174 | 175 | def __init__(self, backup_manager, name, phase=None, error=None, 176 | **extra_env): 177 | super(RetryHookScriptRunner, self).__init__( 178 | backup_manager, name, phase, error, retry=True, **extra_env) 179 | 180 | def run(self): 181 | """ 182 | Run a a 'retry' hook script, if required by configuration. 183 | 184 | Barman will retry to run the script indefinitely until it returns 185 | a EXIT_SUCCESS, or an EXIT_ABORT_CONTINUE, or an EXIT_ABORT_STOP code. 186 | There are BREAK_TIME seconds of sleep between every try. 187 | Every ATTEMPTS_BEFORE_NAP failures, Barman will sleep 188 | for NAP_TIME seconds. 189 | """ 190 | # If there is no script, exit 191 | if self.script is not None: 192 | # Keep track of the number of attempts 193 | attempts = 1 194 | while True: 195 | # Run the script using the standard hook method (inherited) 196 | super(RetryHookScriptRunner, self).run() 197 | 198 | # Run the script until it returns EXIT_ABORT_CONTINUE, 199 | # or an EXIT_ABORT_STOP, or EXIT_SUCCESS 200 | if self.exit_status in (self.EXIT_ABORT_CONTINUE, 201 | self.EXIT_ABORT_STOP, 202 | self.EXIT_SUCCESS): 203 | break 204 | 205 | # Check for the number of attempts 206 | if attempts <= self.ATTEMPTS_BEFORE_NAP: 207 | attempts += 1 208 | # Take a short break 209 | _logger.debug("Retry again in %d seconds", self.BREAK_TIME) 210 | time.sleep(self.BREAK_TIME) 211 | else: 212 | # Reset the attempt number and take a longer nap 213 | _logger.debug("Reached %d failures. Take a nap " 214 | "then retry again in %d seconds", 215 | self.ATTEMPTS_BEFORE_NAP, 216 | self.NAP_TIME) 217 | attempts = 1 218 | time.sleep(self.NAP_TIME) 219 | 220 | # Outside the loop check for the exit code. 221 | if self.exit_status == self.EXIT_ABORT_CONTINUE: 222 | # Warn the user if the script exited with EXIT_ABORT_CONTINUE 223 | # Notify EXIT_ABORT_CONTINUE exit status because success and 224 | # failures are already managed in the superclass run method 225 | _logger.warning("%s was aborted (got exit status %d, " 226 | "Barman resumes)", 227 | self.script, 228 | self.exit_status) 229 | elif self.exit_status == self.EXIT_ABORT_STOP: 230 | # Log the error and raise AbortedRetryHookScript exception 231 | _logger.error("%s was aborted (got exit status %d, " 232 | "Barman requested to stop)", 233 | self.script, 234 | self.exit_status) 235 | raise AbortedRetryHookScript(self) 236 | 237 | return self.exit_status 238 | -------------------------------------------------------------------------------- /tests/test_compressor.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | import base64 19 | import os 20 | 21 | import mock 22 | 23 | from barman.compression import (BZip2Compressor, CommandCompressor, 24 | CompressionManager, CustomCompressor, 25 | GZipCompressor, PyBZip2Compressor, 26 | PyGZipCompressor, identify_compression) 27 | 28 | 29 | # noinspection PyMethodMayBeStatic 30 | class TestCompressionManager(object): 31 | def test_compression_manager_creation(self): 32 | # prepare mock obj 33 | config_mock = mock.Mock() 34 | comp_manager = CompressionManager(config_mock, None) 35 | assert comp_manager 36 | 37 | def test_check_compression_none(self): 38 | # prepare mock obj 39 | config_mock = mock.Mock() 40 | config_mock.compression = "custom" 41 | comp_manager = CompressionManager(config_mock, None) 42 | assert comp_manager.check() is True 43 | 44 | def test_check_with_compression(self): 45 | # prepare mock obj 46 | config_mock = mock.Mock() 47 | comp_manager = CompressionManager(config_mock, None) 48 | assert comp_manager.check('test_compression') is False 49 | 50 | def test_get_compressor_custom(self): 51 | # prepare mock obj 52 | config_mock = mock.Mock() 53 | config_mock.compression = "custom" 54 | config_mock.custom_compression_filter = ( 55 | "test_custom_compression_filter") 56 | config_mock.custom_decompression_filter = ( 57 | "test_custom_decompression_filter") 58 | 59 | # check custom compression method creation 60 | comp_manager = CompressionManager(config_mock, None) 61 | assert comp_manager.get_compressor() is not None 62 | 63 | def test_get_compressor_gzip(self): 64 | # prepare mock obj 65 | config_mock = mock.Mock() 66 | config_mock.compression = "gzip" 67 | 68 | # check custom compression method creation 69 | comp_manager = CompressionManager(config_mock, None) 70 | assert comp_manager.get_compressor() is not None 71 | 72 | def test_get_compressor_bzip2(self): 73 | # prepare mock obj 74 | config_mock = mock.Mock() 75 | config_mock.compression = "bzip2" 76 | 77 | # check custom compression method creation 78 | comp_manager = CompressionManager(config_mock, None) 79 | assert comp_manager.get_compressor() is not None 80 | 81 | def test_get_compressor_invalid(self): 82 | # prepare mock obj 83 | config_mock = mock.Mock() 84 | 85 | # check custom compression method creation 86 | comp_manager = CompressionManager(config_mock, None) 87 | assert comp_manager.get_compressor("test_compression") is None 88 | 89 | 90 | # noinspection PyMethodMayBeStatic 91 | class TestIdentifyCompression(object): 92 | def test_identify_compression(self, tmpdir): 93 | bz2_tmp_file = tmpdir.join("test_file") 94 | # "test" in bz2 compression 95 | bz2_tmp_file.write(base64.b64decode( 96 | b"QlpoOTFBWSZTWczDcdQAAAJBgAAQAgAMACAAIZpoM00Zl4u5IpwoSGZhuOoA"), 97 | mode='wb') 98 | 99 | compression_bz2 = identify_compression(bz2_tmp_file.strpath) 100 | assert compression_bz2 == "bzip2" 101 | 102 | zip_tmp_file = tmpdir.join("test_file") 103 | # "test" in bz2 compression 104 | zip_tmp_file.write(base64.b64decode( 105 | b"H4sIAF0ssFIAAytJLS7hAgDGNbk7BQAAAA=="), 106 | mode='wb') 107 | 108 | # check custom compression method creation 109 | compression_zip = identify_compression(zip_tmp_file.strpath) 110 | assert compression_zip == "gzip" 111 | 112 | 113 | # noinspection PyMethodMayBeStatic 114 | class TestCommandCompressors(object): 115 | 116 | def test_creation(self): 117 | # Prepare mock obj 118 | config_mock = mock.Mock() 119 | 120 | compressor = CommandCompressor(config=config_mock, 121 | compression="dummy_compressor") 122 | 123 | assert compressor is not None 124 | assert compressor.config == config_mock 125 | assert compressor.compression == "dummy_compressor" 126 | 127 | def test_build_command(self): 128 | # prepare mock obj 129 | config_mock = mock.Mock() 130 | 131 | compressor = CommandCompressor(config=config_mock, 132 | compression="dummy_compressor") 133 | 134 | command = compressor._build_command("dummy_command") 135 | 136 | assert command.cmd == 'command(){ dummy_command > "$2" < "$1";}; ' \ 137 | 'command' 138 | 139 | def test_gzip(self, tmpdir): 140 | 141 | config_mock = mock.Mock() 142 | 143 | compressor = GZipCompressor(config=config_mock, compression='gzip') 144 | 145 | src = tmpdir.join('sourcefile') 146 | src.write('content') 147 | 148 | compressor.compress(src.strpath, '%s/zipfile.zip' % tmpdir.strpath) 149 | assert os.path.exists('%s/zipfile.zip' % tmpdir.strpath) 150 | compression_zip = identify_compression('%s/zipfile.zip' % 151 | tmpdir.strpath) 152 | assert compression_zip == "gzip" 153 | 154 | compressor.decompress('%s/zipfile.zip' % tmpdir.strpath, 155 | '%s/zipfile.uncompressed' % tmpdir.strpath) 156 | 157 | f = open('%s/zipfile.uncompressed' % tmpdir.strpath).read() 158 | assert f == 'content' 159 | 160 | def test_bzip2(self, tmpdir): 161 | 162 | config_mock = mock.Mock() 163 | 164 | compressor = BZip2Compressor(config=config_mock, compression='bzip2') 165 | 166 | src = tmpdir.join('sourcefile') 167 | src.write('content') 168 | 169 | compressor.compress(src.strpath, '%s/bzipfile.bz2' % tmpdir.strpath) 170 | assert os.path.exists('%s/bzipfile.bz2' % tmpdir.strpath) 171 | compression_zip = identify_compression('%s/bzipfile.bz2' % 172 | tmpdir.strpath) 173 | assert compression_zip == "bzip2" 174 | 175 | compressor.decompress('%s/bzipfile.bz2' % tmpdir.strpath, 176 | '%s/bzipfile.uncompressed' % tmpdir.strpath) 177 | 178 | f = open('%s/bzipfile.uncompressed' % tmpdir.strpath).read() 179 | assert f == 'content' 180 | 181 | 182 | # noinspection PyMethodMayBeStatic 183 | class TestInternalCompressors(object): 184 | 185 | def test_gzip(self, tmpdir): 186 | 187 | config_mock = mock.Mock() 188 | 189 | compressor = PyGZipCompressor(config=config_mock, compression='pygzip') 190 | 191 | src = tmpdir.join('sourcefile') 192 | src.write('content') 193 | 194 | compressor.compress(src.strpath, '%s/zipfile.zip' % tmpdir.strpath) 195 | assert os.path.exists('%s/zipfile.zip' % tmpdir.strpath) 196 | compression_zip = identify_compression('%s/zipfile.zip' % 197 | tmpdir.strpath) 198 | assert compression_zip == "gzip" 199 | 200 | compressor.decompress('%s/zipfile.zip' % tmpdir.strpath, 201 | '%s/zipfile.uncompressed' % tmpdir.strpath) 202 | 203 | f = open('%s/zipfile.uncompressed' % tmpdir.strpath).read() 204 | assert f == 'content' 205 | 206 | def test_bzip2(self, tmpdir): 207 | 208 | config_mock = mock.Mock() 209 | 210 | compressor = PyBZip2Compressor(config=config_mock, 211 | compression='pybzip2') 212 | 213 | src = tmpdir.join('sourcefile') 214 | src.write('content') 215 | 216 | compressor.compress(src.strpath, '%s/bzipfile.bz2' % tmpdir.strpath) 217 | assert os.path.exists('%s/bzipfile.bz2' % tmpdir.strpath) 218 | compression_zip = identify_compression('%s/bzipfile.bz2' % 219 | tmpdir.strpath) 220 | assert compression_zip == "bzip2" 221 | 222 | compressor.decompress('%s/bzipfile.bz2' % tmpdir.strpath, 223 | '%s/bzipfile.uncompressed' % tmpdir.strpath) 224 | 225 | f = open('%s/bzipfile.uncompressed' % tmpdir.strpath).read() 226 | assert f == 'content' 227 | 228 | 229 | # noinspection PyMethodMayBeStatic 230 | class TestCustomCompressor(object): 231 | def test_custom_compressor_creation(self): 232 | config_mock = mock.Mock() 233 | config_mock.custom_compression_filter = 'dummy_compression_filter' 234 | config_mock.custom_decompression_filter = 'dummy_decompression_filter' 235 | 236 | compressor = CustomCompressor(config=config_mock, 237 | compression="custom") 238 | 239 | assert compressor is not None 240 | assert compressor._compress.cmd == ( 241 | 'command(){ dummy_compression_filter > "$2" < "$1";}; command') 242 | assert compressor._decompress.cmd == ( 243 | 'command(){ dummy_decompression_filter > "$2" < "$1";}; command') 244 | 245 | def test_validate(self): 246 | config_mock = mock.Mock() 247 | config_mock.custom_compression_filter = 'dummy_compression_filter' 248 | config_mock.custom_decompression_filter = 'dummy_decompression_filter' 249 | 250 | compressor = CustomCompressor(config=config_mock, 251 | compression="custom") 252 | 253 | validate = compressor.validate('custom') 254 | 255 | assert validate is None 256 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | import pytest 19 | from mock import Mock 20 | 21 | import barman.config 22 | from barman.cli import get_server, get_server_list, manage_server_command 23 | from barman.server import Server 24 | from testing_helpers import build_config_dictionary, build_config_from_dicts 25 | 26 | 27 | # noinspection PyMethodMayBeStatic 28 | class TestCli(object): 29 | 30 | def test_get_server(self, monkeypatch): 31 | """ 32 | Test the get_server method, providing a basic configuration 33 | 34 | :param monkeypatch monkeypatch: pytest patcher 35 | """ 36 | # Mock the args from argparse 37 | args = Mock() 38 | args.server_name = 'main' 39 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 40 | main_conf={ 41 | 'archiver': 'on', 42 | })) 43 | server_main = get_server(args) 44 | # Expect the server to exists 45 | assert server_main 46 | # Expect the name to be the right one 47 | assert server_main.config.name == 'main' 48 | 49 | def test_get_server_with_conflicts(self, monkeypatch, capsys): 50 | """ 51 | Test get_server method using a configuration containing errors 52 | 53 | :param monkeypatch monkeypatch: pytest patcher 54 | """ 55 | # Mock the args from argparse 56 | args = Mock() 57 | # conflicting directories 58 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 59 | main_conf={ 60 | 'wals_directory': '/some/barman/home/main/wals', 61 | 'basebackups_directory': '/some/barman/home/main/wals', 62 | 'archiver': 'on', 63 | })) 64 | args.server_name = 'main' 65 | with pytest.raises(SystemExit): 66 | get_server(args, True) 67 | out, err = capsys.readouterr() 68 | assert err 69 | assert "ERROR: Conflicting path:" in err 70 | 71 | # conflicting directories with on_error_stop=False 72 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 73 | main_conf={ 74 | 'wals_directory': '/some/barman/home/main/wals', 75 | 'basebackups_directory': '/some/barman/home/main/wals', 76 | 'archiver': 'on', 77 | })) 78 | args.server_name = 'main' 79 | get_server(args, on_error_stop=False) 80 | # In this case the server is returned and a warning message is emitted 81 | out, err = capsys.readouterr() 82 | assert err 83 | assert "ERROR: Conflicting path:" in err 84 | 85 | def test_manage_server_command(self, monkeypatch, capsys): 86 | """ 87 | Test manage_server_command method checking 88 | the various types of error output 89 | 90 | :param monkeypatch monkeypatch: pytest patcher 91 | """ 92 | # Build a server with a config with path conflicts 93 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 94 | main_conf=build_config_dictionary({ 95 | 'wals_directory': '/some/barman/home/main/wals', 96 | 'basebackups_directory': '/some/barman/home/main/wals', 97 | 'archiver': 'on', 98 | }))) 99 | server = Server(barman.__config__.get_server('main')) 100 | # Test a not blocking WARNING message 101 | manage_server_command(server) 102 | out, err = capsys.readouterr() 103 | # Expect an ERROR message because of conflicting paths 104 | assert 'ERROR: Conflicting path' in err 105 | 106 | # Build a server with a config without path conflicts 107 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) 108 | server = Server(barman.__config__.get_server('main')) 109 | # Set the server as not active 110 | server.config.active = False 111 | # Request to treat inactive as errors 112 | to_be_executed = manage_server_command(server, inactive_is_error=True) 113 | out, err = capsys.readouterr() 114 | # Expect a ERROR message because of a not active server 115 | assert 'ERROR: Inactive server' in err 116 | assert not to_be_executed 117 | 118 | # Request to treat inactive as warning 119 | to_be_executed = manage_server_command(server, inactive_is_error=False) 120 | out, err = capsys.readouterr() 121 | # Expect no error whatsoever 122 | assert err == '' 123 | assert not to_be_executed 124 | 125 | def test_get_server_global_error_list(self, monkeypatch, capsys): 126 | """ 127 | Test the management of multiple servers and the 128 | presence of global errors 129 | 130 | :param monkeypatch monkeypatch: pytest patcher 131 | """ 132 | args = Mock() 133 | args.server_name = 'main' 134 | # Build 2 servers with shared path. 135 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 136 | global_conf=None, 137 | main_conf={ 138 | 'basebackups_directory': '/some/barman/home/main/base', 139 | 'incoming_wals_directory': '/some/barman/home/main/incoming', 140 | 'wals_directory': '/some/barman/home/main/wals', 141 | 'backup_directory': '/some/barman/home/main', 142 | 'archiver': 'on', 143 | }, 144 | test_conf={ 145 | 'basebackups_directory': '/some/barman/home/test/wals', 146 | 'incoming_wals_directory': '/some/barman/home/main/incoming', 147 | 'wals_directory': '/some/barman/home/main/wals', 148 | 'backup_directory': '/some/barman/home/main', 149 | 'archiver': 'on', 150 | })) 151 | # Expect a conflict because of the shared paths 152 | with pytest.raises(SystemExit): 153 | get_server(args) 154 | out, err = capsys.readouterr() 155 | # Check for the presence of error messages 156 | assert err 157 | # Check paths in error messages 158 | assert 'Conflicting path: ' \ 159 | 'basebackups_directory=/some/barman/home/main/base' in err 160 | assert 'Conflicting path: ' \ 161 | 'incoming_wals_directory=/some/barman/home/main/incoming' in err 162 | assert 'Conflicting path: ' \ 163 | 'wals_directory=/some/barman/home/main/wals' in err 164 | assert 'Conflicting path: ' \ 165 | 'backup_directory=/some/barman/home/main' in err 166 | 167 | def test_get_server_list(self, monkeypatch, capsys): 168 | """ 169 | Test the get_server_list method 170 | 171 | :param monkeypatch monkeypatch: pytest patcher 172 | """ 173 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) 174 | server_dict = get_server_list() 175 | assert server_dict 176 | # Expect 2 test servers Main and Test 177 | assert len(server_dict) == 2 178 | # Test the method with global errors 179 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 180 | global_conf=None, 181 | main_conf={ 182 | 'basebackups_directory': '/some/barman/home/main/base', 183 | 'incoming_wals_directory': '/some/barman/home/main/incoming', 184 | 'wals_directory': '/some/barman/home/main/wals', 185 | 'backup_directory': '/some/barman/home/main', 186 | 'archiver': 'on', 187 | }, 188 | test_conf={ 189 | 'basebackups_directory': '/some/barman/home/test/wals', 190 | 'incoming_wals_directory': '/some/barman/home/main/incoming', 191 | 'wals_directory': '/some/barman/home/main/wals', 192 | 'backup_directory': '/some/barman/home/main', 193 | 'archiver': 'on', 194 | })) 195 | # Expect the method to fail and exit 196 | with pytest.raises(SystemExit): 197 | get_server_list() 198 | out, err = capsys.readouterr() 199 | # Check for the presence of error messages 200 | assert err 201 | # Check paths in error messages 202 | assert 'Conflicting path: ' \ 203 | 'basebackups_directory=/some/barman/home/main/base' in err 204 | assert 'Conflicting path: ' \ 205 | 'incoming_wals_directory=/some/barman/home/main/incoming' in err 206 | assert 'Conflicting path: ' \ 207 | 'wals_directory=/some/barman/home/main/wals' in err 208 | assert 'Conflicting path: ' \ 209 | 'backup_directory=/some/barman/home/main' in err 210 | 211 | def test_get_server_list_global_error_continue(self, monkeypatch): 212 | """ 213 | Test the population of the list of global errors for diagnostic 214 | purposes (diagnose invocation) 215 | 216 | :param monkeypatch monkeypatch: pytest patcher 217 | """ 218 | monkeypatch.setattr(barman, '__config__', build_config_from_dicts( 219 | global_conf=None, 220 | main_conf={ 221 | 'backup_directory': '/some/barman/home/main', 222 | 'archiver': 'on', 223 | }, 224 | test_conf={ 225 | 'backup_directory': '/some/barman/home/main', 226 | 'archiver': 'on', 227 | })) 228 | server_dict = get_server_list(on_error_stop=False) 229 | global_error_list = barman.__config__.servers_msg_list 230 | # Check for the presence of servers 231 | assert server_dict 232 | # Check for the presence of global errors 233 | assert global_error_list 234 | assert len(global_error_list) == 6 235 | -------------------------------------------------------------------------------- /barman/lockfile.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2016 2ndQuadrant Italia Srl 2 | # 3 | # This file is part of Barman. 4 | # 5 | # Barman is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Barman is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Barman. If not, see . 17 | 18 | """ 19 | This module is the lock manager for Barman 20 | """ 21 | 22 | import errno 23 | import fcntl 24 | import os 25 | import re 26 | 27 | from barman.exceptions import (LockFileBusy, LockFileParsingError, 28 | LockFilePermissionDenied) 29 | 30 | 31 | class LockFile(object): 32 | """ 33 | Ensures that there is only one process which is running against a 34 | specified LockFile. 35 | It supports the Context Manager interface, allowing the use in with 36 | statements. 37 | 38 | with LockFile('file.lock') as locked: 39 | if not locked: 40 | print "failed" 41 | else: 42 | 43 | 44 | You can also use exceptions on failures 45 | 46 | try: 47 | with LockFile('file.lock', True): 48 | 49 | except LockFileBusy, e, file: 50 | print "failed to lock %s" % file 51 | 52 | """ 53 | 54 | LOCK_PATTERN = None 55 | """ 56 | If defined in a subclass, it must be a compiled regular expression 57 | which matches the lock filename. 58 | 59 | It must provide named groups for the constructor parameters which produce 60 | the same lock name. I.e.: 61 | 62 | >>> ServerWalReceiveLock('/tmp', 'server-name').filename 63 | '/tmp/.server-name-receive-wal.lock' 64 | >>> ServerWalReceiveLock.LOCK_PATTERN = re.compile( 65 | r'\.(?P.+)-receive-wal\.lock') 66 | >>> m = ServerWalReceiveLock.LOCK_PATTERN.match( 67 | '.server-name-receive-wal.lock') 68 | >>> ServerWalReceiveLock('/tmp', **(m.groupdict())).filename 69 | '/tmp/.server-name-receive-wal.lock' 70 | 71 | """ 72 | 73 | @classmethod 74 | def build_if_matches(cls, path): 75 | """ 76 | Factory method that creates a lock instance if the path matches 77 | the lock filename created by the actual class 78 | 79 | :param path: the full path of a LockFile 80 | :return: 81 | """ 82 | # If LOCK_PATTERN is not defined always return None 83 | if not cls.LOCK_PATTERN: 84 | return None 85 | # Matches the provided path against LOCK_PATTERN 86 | lock_directory = os.path.abspath(os.path.dirname(path)) 87 | lock_name = os.path.basename(path) 88 | match = cls.LOCK_PATTERN.match(lock_name) 89 | if match: 90 | # Build the lock object for the provided path 91 | return cls(lock_directory, **(match.groupdict())) 92 | return None 93 | 94 | def __init__(self, filename, raise_if_fail=True, wait=False): 95 | self.filename = os.path.abspath(filename) 96 | self.fd = None 97 | self.raise_if_fail = raise_if_fail 98 | self.wait = wait 99 | 100 | def acquire(self, raise_if_fail=None, wait=None): 101 | """ 102 | Creates and holds on to the lock file. 103 | 104 | When raise_if_fail, a LockFileBusy is raised if 105 | the lock is held by someone else and a LockFilePermissionDenied is 106 | raised when the user executing barman have insufficient rights for 107 | the creation of a LockFile. 108 | 109 | Returns True if lock has been successfully acquired, False otherwise. 110 | 111 | :param bool raise_if_fail: If True raise an exception on failure 112 | :param bool wait: If True issue a blocking request 113 | :returns bool: whether the lock has been acquired 114 | """ 115 | if self.fd: 116 | return True 117 | fd = None 118 | # method arguments take precedence on class parameters 119 | raise_if_fail = raise_if_fail \ 120 | if raise_if_fail is not None else self.raise_if_fail 121 | wait = wait if wait is not None else self.wait 122 | try: 123 | # 384 is 0600 in octal, 'rw-------' 124 | fd = os.open(self.filename, os.O_CREAT | os.O_RDWR, 384) 125 | flags = fcntl.LOCK_EX 126 | if not wait: 127 | flags |= fcntl.LOCK_NB 128 | fcntl.flock(fd, flags) 129 | # Once locked, replace the content of the file 130 | os.lseek(fd, 0, os.SEEK_SET) 131 | os.write(fd, ("%s\n" % os.getpid()).encode('ascii')) 132 | # Truncate the file at the current position 133 | os.ftruncate(fd, os.lseek(fd, 0, os.SEEK_CUR)) 134 | self.fd = fd 135 | return True 136 | except (OSError, IOError) as e: 137 | if fd: 138 | os.close(fd) # let's not leak file descriptors 139 | if raise_if_fail: 140 | if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK): 141 | raise LockFileBusy(self.filename) 142 | elif e.errno == errno.EACCES: 143 | raise LockFilePermissionDenied(self.filename) 144 | else: 145 | raise 146 | else: 147 | return False 148 | 149 | def release(self): 150 | """ 151 | Releases the lock. 152 | 153 | If the lock is not held by the current process it does nothing. 154 | """ 155 | if not self.fd: 156 | return 157 | try: 158 | fcntl.flock(self.fd, fcntl.LOCK_UN) 159 | os.close(self.fd) 160 | except (OSError, IOError): 161 | pass 162 | self.fd = None 163 | 164 | def __del__(self): 165 | """ 166 | Avoid stale lock files. 167 | """ 168 | self.release() 169 | 170 | # Contextmanager interface 171 | 172 | def __enter__(self): 173 | return self.acquire() 174 | 175 | def __exit__(self, exception_type, value, traceback): 176 | self.release() 177 | 178 | def get_owner_pid(self): 179 | """ 180 | Test whether a lock is already held by a process. 181 | 182 | Returns the PID of the owner process or None if the lock is available. 183 | 184 | :rtype: int|None 185 | :raises LockFileParsingError: when the lock content is garbled 186 | :raises LockFilePermissionDenied: when the lockfile is not accessible 187 | """ 188 | try: 189 | self.acquire(raise_if_fail=True, wait=False) 190 | except LockFileBusy: 191 | try: 192 | # Read the lock content and parse the PID 193 | # NOTE: We cannot read it in the self.acquire method to avoid 194 | # reading the previous locker PID 195 | with open(self.filename, 'r') as file_object: 196 | return int(file_object.readline().strip()) 197 | except ValueError as e: 198 | # This should not happen 199 | raise LockFileParsingError(e) 200 | # release the lock and return None 201 | self.release() 202 | return None 203 | 204 | 205 | class GlobalCronLock(LockFile): 206 | """ 207 | This lock protects cron from multiple executions. 208 | 209 | Creates a global '.cron.lock' lock file under the given lock_directory. 210 | """ 211 | 212 | def __init__(self, lock_directory): 213 | super(GlobalCronLock, self).__init__( 214 | os.path.join(lock_directory, '.cron.lock'), 215 | raise_if_fail=True) 216 | 217 | 218 | class ServerBackupLock(LockFile): 219 | """ 220 | This lock protects a server from multiple executions of backup command 221 | 222 | Creates a '.-backup.lock' lock file under the given lock_directory 223 | for the named SERVER. 224 | """ 225 | 226 | def __init__(self, lock_directory, server_name): 227 | super(ServerBackupLock, self).__init__( 228 | os.path.join(lock_directory, '.%s-backup.lock' % server_name), 229 | raise_if_fail=True) 230 | 231 | 232 | class ServerCronLock(LockFile): 233 | """ 234 | This lock protects a server from multiple executions of cron command 235 | 236 | Creates a '.-cron.lock' lock file under the given lock_directory 237 | for the named SERVER. 238 | """ 239 | 240 | def __init__(self, lock_directory, server_name): 241 | super(ServerCronLock, self).__init__( 242 | os.path.join(lock_directory, '.%s-cron.lock' % server_name), 243 | raise_if_fail=True, wait=False) 244 | 245 | 246 | class ServerXLOGDBLock(LockFile): 247 | """ 248 | This lock protects a server's xlogdb access 249 | 250 | Creates a '.-xlogdb.lock' lock file under the given lock_directory 251 | for the named SERVER. 252 | """ 253 | 254 | def __init__(self, lock_directory, server_name): 255 | super(ServerXLOGDBLock, self).__init__( 256 | os.path.join(lock_directory, '.%s-xlogdb.lock' % server_name), 257 | raise_if_fail=True, wait=True) 258 | 259 | 260 | class ServerWalArchiveLock(LockFile): 261 | """ 262 | This lock protects a server from multiple executions of wal-archive command 263 | 264 | Creates a '.-archive-wal.lock' lock file under 265 | the given lock_directory for the named SERVER. 266 | """ 267 | 268 | def __init__(self, lock_directory, server_name): 269 | super(ServerWalArchiveLock, self).__init__( 270 | os.path.join(lock_directory, '.%s-archive-wal.lock' % server_name), 271 | raise_if_fail=True, wait=False) 272 | 273 | 274 | class ServerWalReceiveLock(LockFile): 275 | """ 276 | This lock protects a server from multiple executions of receive-wal command 277 | 278 | Creates a '.-receive-wal.lock' lock file under 279 | the given lock_directory for the named SERVER. 280 | """ 281 | # TODO: Implement on the other LockFile subclasses 282 | LOCK_PATTERN = re.compile(r'\.(?P.+)-receive-wal\.lock') 283 | 284 | def __init__(self, lock_directory, server_name): 285 | super(ServerWalReceiveLock, self).__init__( 286 | os.path.join(lock_directory, '.%s-receive-wal.lock' % server_name), 287 | raise_if_fail=True, wait=False) 288 | --------------------------------------------------------------------------------